Starting some scripting, looking for some commands

Discussions about Coding and Scripting
Marscaleb
Average
Posts: 48
Joined: Tue Jun 07, 2016 6:50 am

Starting some scripting, looking for some commands

Post by Marscaleb »

I've written scripts before, and I've even written in UnrealScript before. But I've never done any scripts in UT99 before, so I don't really know how this game handles a lot of its, well, everything.

So I'm looking for some help getting started.
I already know the basics of writing code, but I don't know what existing functions I can call, nor what existing methods I have to conform to.
When looking through the documentation and tutorials I have found through this site, I have been unable to find anything that gets into the real meat of scripting for Unreal; just basic beginner stuff of writing code in general and compiling. Nothing that can explain to me how to do anything specific. I'm hoping someone here can fill in the gaps, or at least show me how to find out these things on my own.

Right now what I'm looking to do is to modify a mutator someone made to add in some features that I am looking for. Conceptually, this isn't hard, but I have no clue what functions I need to call.

The first thing I need to do is cause the mutator to spawn some bots (under certain conditions) and then remove those bots (under certain conditions). I know this is possible because I can see other mutators that do it, but I can't see the code they used.

The next thing I need to do is display some text on the HUD. Not the message that goes to the log, but text displayed prominently in the center of the screen, like when you make a double-kill.

I'm also curious if it is possible to have code that responds to player input and displays text before the player is spawned into the game, in those first few seconds when a match "exists" and everyone is in spectator mode and no one has spawned yet. If so I would like to add the capacity for players to preemptively set how they spawn in connection with this mutator.

And the last thing I would want to do is call a function or two if the player remains dead for too long.

I could guess how to set this stuff up, but code doesn't work on guesses or people describing the gist of what they want; code needs to be exact.
I feel really silly asking for this stuff, because anyone who could tell me how to do any of this could also just write the code themselves easier than it could be explained. But unless I can find some examples of what I am looking for and/or a complete and searchable documentation on the scripting API, then the only resource I have is to ask.
schwap
Novice
Posts: 20
Joined: Thu Aug 25, 2016 1:06 am

Re: Starting some scripting, looking for some commands

Post by schwap »

I recommend you to join the Discord server and ask for help in the #uscript room.

Just to mention, yes - all these things are possible.
User avatar
OjitroC
Godlike
Posts: 3605
Joined: Sat Sep 12, 2015 8:46 pm

Re: Starting some scripting, looking for some commands

Post by OjitroC »

Marscaleb wrote: The first thing I need to do is cause the mutator to spawn some bots (under certain conditions) and then remove those bots (under certain conditions). I know this is possible because I can see other mutators that do it, but I can't see the code they used.
Not quite sure what you mean when you say you can't see the code - the code of the mutator you link to can be exported by UEd or UTPT - here it is

Code: Select all

class MyBots extends Mutator;

var int BotNum;
var bool bInit;
var bool bBotsKicked;

function PostBeginPlay()
{
    if (!bInit)
    {
        bInit = true;
        BotNum = DeathMatchPlus(Level.Game).MinPlayers - 1;
        SetTimer(5, true);
        bBotsKicked = false;
    }
}

function Timer()
{
    local int i;

    if (Level.Game.NumPlayers == 1 && DeathMatchPlus(Level.Game).NumBots == 0 && bBotsKicked && BotNum > 0)
    {
       for (i=0; i<BotNum; i++)
       {
            Level.Game.ForceAddBot();
       }
       bBotsKicked = false;
    }
}

function ModifyPlayer( Pawn Other )
{
    Super.ModifyPlayer( Other );

    if (Level.Game.NumPlayers > 1)
    {
       if (DeathMatchPlus(Level.Game).NumBots > 0)
       {
          KickBots();
          bBotsKicked = true;
       }
    }
}

function KickBots()
{
    local int i, j;

    j = DeathMatchPlus(Level.Game).NumBots;

    for (i=0; i<j; i++)
    {
        RemoveBot();
    }
}

function bool RemoveBot()
{
    local Bot DumbBot;
    local Pawn P, OtherPawn;
    local actor A;

    for (P = Level.PawnList; P != None; P = P.NextPawn)
    {
        if (Bot(P) != None)       // get Bot with least score
           if (DumbBot == None || P.PlayerReplicationInfo.Score < DumbBot.PlayerReplicationInfo.Score)
               DumbBot = Bot(P);
    }

    if (DumbBot != None)
    {
        DumbBot.Destroy();
        DeathMatchPlus(Level.Game).MinPlayers -= 1;
        return true;
    }

    return false;
}
If this gives you what you want, why not run this mutator alongside the SpecStart mutator?
MrLoathsome
Inhuman
Posts: 958
Joined: Wed Mar 31, 2010 9:02 pm
Personal rank: I am quite rank.
Location: MrLoathsome fell out of the world!

Re: Starting some scripting, looking for some commands

Post by MrLoathsome »

OjitroC wrote:If this gives you what you want, why not run this mutator alongside the SpecStart mutator?
This would be the best way to handle what you want to do. With a separate mutator to manage the number of bots in the
match.
The way I had to write the SpecStart, pretty much excludes doing any of that sort of thing with the SpecStart source.

Attempt some various configs with some of those other mutators, and see if you can get things working the way you want.

In the event that you cant, writing a new mutator to manage bots that accounts for SpecStart running is the way to go.

If you want/need the number of bots added to factor in how many players are playing AND how many are still in SpecStart
spectating mode, I attempted to write it in a way that other mutators could check that. (*Not tested...)
I don't think you will need to make your new mutator dependent upon Specstart either. (No need in EditPackages for this check.)

Your check would look something like this:

Code: Select all

if (TournamentPlayer(A).SSCheck != None)  (*  Player A is still in SpecStart mode... Do whatever... *)
Note!!! You will want to have your new mutator to have a delay at startup, that is longer than whatever the current amount of time
it is taking for SpecStart to get fully initialized and get the SSCheck actor spawned and attached to the new players as they join.
To avoid your mutator falsely detecting that the player has joined the game BEFORE SpecStart has actually even kicked in and spawned
the players SSCheck actor.

Can't state an exact number for the length of that delay, as it will vary depending upon the values you are using in the SpecStart config
to get the thing to work with your gametype.

Also, look at using commands ClientMessage and BroadcastMessage in your mutators ModifyPlayer code for sending custom text strings.
blarg
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Starting some scripting, looking for some commands

Post by sektor2111 »

Marscaleb wrote:I've written scripts before, and I've even written in UnrealScript before. But I've never done any scripts in UT99 before, ...
I'm confused.
This -vv-

Code: Select all

if (TournamentPlayer(A).SSCheck != None)
TournamentPlayer probably doesn't include any sort of "SSCheck" property or variable if I well recall... Or I might be wrong...

The topic's personal opinion:
If you cannot write a simple thing - a mutator for scoring something or such a simple feature, this task requires some advanced knowledge and some small experience with UScript... This takes time, looking at mutators, learning, compiling, testing, else result is None. Actually you cannot start coding with advanced things unless you want to have a default failure...

Just my two cents.
MrLoathsome
Inhuman
Posts: 958
Joined: Wed Mar 31, 2010 9:02 pm
Personal rank: I am quite rank.
Location: MrLoathsome fell out of the world!

Re: Starting some scripting, looking for some commands

Post by MrLoathsome »

sektor2111 wrote:I'm confused.
This -vv-

Code: Select all

if (TournamentPlayer(A).SSCheck != None)
TournamentPlayer probably doesn't include any sort of "SSCheck" property or variable if I well recall... Or I might be wrong...
Well that example is sort of psuedo-code.
Been about 10 months now since I actually messed with any UScript... :sad2:

Obviously TournamentPlayer has no SSCheck property or value by default.

Point is that when a player has joined the server and is in SpecStart v3.0 spectating mode, they will have an SSCheck actor
assigned/attached to them when they enter the server. When they actually leave the spectating mode(s) and join the game, the SSCheck
actor assigned to that player will be destroyed.

In the event that something like my above check does not work, you could have your custom mutator do a foreach actors check
on class SpecStart.SSCheck and then determine which players are still in SpecStart mode by checking SSCheck.Owner. (I think... :what: )
This method would of course require you to have SpecStart v3.0 as an EditPackage.

I do agree with sektor2111 suggestion that you should examine the default scripts some, looking specifically at the gametype sources that
handle the adding/removing of both bots and players into the matches.
Would also recommend exporting and looking at the source scripts for the various other mutators out there that are doing similar things.

The SpecStart v3.0 source is probably NOT a good thing to be looking at while reviewing code to prepare yourself for making your first
mutator. Not saying it is all "advanced' or anything like that, its just that I had to do a lot of unconventional and convoluted things
to make it work the way it does with all the games and gametypes it does. And there are no comments at all. :omfg: :pfff:

THAT BEING SAID....

It might even be possible to have the SpecStart mutator itself modify the game settings for Min/MaxPlayers and add or remove a bot, but
that would require some actual testing to be sure. (Probably a lot...)
You would want to remove your bot or bot(s) at the point in the SSCheck class right before it destroys itself and the player actually joins the match.
Would probably also need to add some code to have it add the bot or bot(s) back into the game when players leave the server.


Note, this is all just guessing off the top of my head. I would have to try some things out and see what happens to be sure.
Quite possible that would not work at all... :ironic2: :noidea
Most likely you would have to add a bunch of checks for gametype, if it is a team game, etc etc. Would need to be carefully done
to avoid breaking things. If you do attempt to make your own custom version of SpecStart, change the name of the class to avoid
any future mismatch nightmares.

Good luck. Keep us posted on any progress, or if you come up with any specific questions.
8)
blarg
Marscaleb
Average
Posts: 48
Joined: Tue Jun 07, 2016 6:50 am

Re: Starting some scripting, looking for some commands

Post by Marscaleb »

The reason I can't use that mutator alongside this one is because it doesn't work in the way I need; I used it as an example because it does something that I do need. It does spawn and remove bots, but just not under the terms and conditions I will need.

Thank you all for the information; I'll take a look at this hopefully tonight, and hopefully the next time I have a question it will be something more specific.
Marscaleb
Average
Posts: 48
Joined: Tue Jun 07, 2016 6:50 am

Re: Starting some scripting, looking for some commands

Post by Marscaleb »

Okay, a couple specific questions I have.

#1
Looking at the MyBots mutator, we have this code for when it removes a bot from play:

Code: Select all

if (DumbBot != None)
    {
        DumbBot.Destroy();
        DeathMatchPlus(Level.Game).MinPlayers -= 1;
        return true;
    }
The Destroy command actually removes the bot from play. But what is the MinPlayers -= 1 for?
If I am reading this code right, that is a variable for the actual gametype, the one set by the server. (It certainly isn't a variable created within the script.) So I am left to wonder why this is being called.
I would venture a guess that this is a necessary cleanup after using Destroy to remove the bot, but I do not understand why. Does Level.Game.ForceAddBot() increase that counter, but there is no ForceRemoveBot function that handles the other end of it?

#2
When exactly is "PostBeginPlay()" called? I was going to guess that it is after the match has begun (players spawned and whatnot) but looking at some mutators suggests this is called at the beginning of a match BEFORE anyone is spawned, when everyone is still flying around in spectator mode.
Also I see everyone adding an "initialized" check to this function to make sure it doesn't get called twice. What conditions are calling that function multiple times? And I've seen one that also calls the Super.PostBeginPlay(), but the other mutators I've looked at do not. Is there anything in the Super.PostBeginPlay that does anything?

#3
What conditions call the function"ModifyPlayer(Pawn Other)"? Apparently it at least gets called when someone joins a game, but I don't know if/when other times it may be called.

#4
So I'm guessing the function "SetTimer(5, true);" calls the function "Timer()" after a set amount of time. (Correct me if I'm wrong.) What is the "true" flag for? I would guess the "5" is the time interval in seconds, and looking at some other mutators that call this function, I would assume it takes a float value but Unreal Script doesn't care if you say "5" or "5.0". (Correct me if I'm wrong.)

#5
What function will draw text on the HUD? (Not just send text the the log.) I don't have any mutators that do this, and don't know where to go looking to find the code.

#6
What function(s) will generate a random number, and what format/range will it come out as?
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Starting some scripting, looking for some commands

Post by Barbie »

Marscaleb wrote:When exactly is "PostBeginPlay()" called?
I recommend some reading here: wiki.beyondunreal: What happens when an Actor is spawned.
Marscaleb wrote:Is there anything in the Super.PostBeginPlay that does anything?
Just walk up in the object hierarchy tree to see what parent objects do in that function.
I recommend downloading or extracting all script sources from UT. (For a better understanding I created a directory tree corresponding to the object hierarchy and put the UC script files there (see pic):
SourceTree.jpg
I use a text search program to find all occurrences of a function or variable.)
Marscaleb wrote:"SetTimer(5, true);" [...] What is the "true" flag for?
Again see Wiki.
Marscaleb wrote:What function(s) will generate a random number
Ahem, wiki with keywords rand and frand? ;o)
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Starting some scripting, looking for some commands

Post by sektor2111 »

Marscaleb wrote:The Destroy command actually removes the bot from play. But what is the MinPlayers -= 1 for?
EXPORT BOTPACK and everything and just read the damn codes. Right here mutator is decreasing number of MinPlayers value for NOT SPAWNING another Bot when actually mutator has removed one - LOGIC. The best of logic would be to check if MinPlayers is not being set to 0 by a genius admin or such for preventing going under 0 value... :loool:
Marscaleb wrote:When exactly is "PostBeginPlay()" called?
It's automated - USE LOG LINES for tests inside functions but not after any return found - if exist.

Code: Select all

log("This is something called.");
Marscaleb wrote:Super.PostBeginPlay that does anything?
No, is not, is coder's fart used to do multiple calls to nothing...
Marscaleb wrote:What conditions call the function"ModifyPlayer(Pawn Other)"?
Read Engine - GameInfo.uc - AGAIN export stupid scripts from Editor. This will have a call when match is being started and/or a player respawns post killed.
Marscaleb wrote:So I'm guessing the function "SetTimer(5, true);" calls the function "Timer()" after a set amount of time. (Correct me if I'm wrong.) What is the "true" flag for? I would guess the "5" is the time interval in seconds, and looking at some other mutators that call this function, I would assume it takes a float value but Unreal Script doesn't care if you say "5" or "5.0". (Correct me if I'm wrong.)
Again - USE LOG lines for tests and figuring things - guessing doesn't help at all.
Marscaleb wrote:What function will draw text on the HUD? (Not just send text the the log.) I don't have any mutators that do this, and don't know where to go looking to find the code.
Postrender ? See Mutator.uc from Engine, HUD, ChallengeHUD, etc. - again Export all scripts...
Marscaleb wrote:What function(s) will generate a random number, and what format/range will it come out as?
Export Scripts and look into Object.uc - probably you need RandRange or Rand or FRand.

Aside for clarifications Wiki is in charge - if plonkers did not ruin it.
Marscaleb
Average
Posts: 48
Joined: Tue Jun 07, 2016 6:50 am

Re: Starting some scripting, looking for some commands

Post by Marscaleb »

Thank you for the information! Working on stuff now...

Two more quick questions.
Is there a function that gets called when the match actually starts (ie when the players spawn and the game clock actually starts counting down)?
And two... I've added a message function to PostBeginPlay but I never see this thing called more than once. Does it? Can it? All the mutators I see add init variables to make sure it doesn't get called twice, but I don't see that happening...
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Starting some scripting, looking for some commands

Post by sektor2111 »

Marscaleb wrote:Is there a function that gets called when the match actually starts (ie when the players spawn and the game clock actually starts counting down)?
There is a solution which I learned by myself in how to capture game-start in mutators. It is used Modifyplayer. In that moment when game starts, variable from "DMplus" bstartmatch or such is true, when that thing is true you can setup your own variable bMatchIsStarted = True if is False in ModifyPlayer as first line - of course you have to declare your variable first.

Code: Select all

class Something expands mutator;

var bool bMatchIsStarted;
....
As long as your variable went true, this means the match is running, is being started - yes, this is not explained in any Tutorial - we can debate these "outsiders" here if you need some info about whatever custom methods. By default bool variables are False but you can set this False as a safety right in PostBeginPlay.
Marscaleb wrote: I've added a message function to PostBeginPlay but I never see this thing called more than once. Does it? Can it? All the mutators I see add init variables to make sure it doesn't get called twice, but I don't see that happening...
PostBeginPlay is called once automated. Whatever you need to have a repeated execution it will need other calls, more or less scheduled: Tick, Timer, State code.
Keep in mind that some mutators can force a second call to an outsider tool and that's why the most of coders were made sure to prevent a duplicate execution - in some mods this might not be a good thing. Your mutator probably is not calling itself but can be stupidly called by others from chain and you need to guard your code somehow. To light you up, mutator which you described does a call to DeathMatchplus forcing a "push" code which is not done by DeathMatchplus itself in that moment. This way works Bot too if you check some CTF DOM AS etc codes. So to speak you might have a function in mutator never called but, you can call it using a Server Actor unseen, this is how UScript works - as a good point from me.
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Starting some scripting, looking for some commands

Post by Barbie »

Marscaleb wrote:I've added a message function to PostBeginPlay but I never see this thing called more than once. Does it? Can it?
PostBeginPlay() is an init function in a way. Such an init function - not only PostBeginPlay() - can be called multiple times, by error, dumbness or whatever. If that function does not change the system's state if it is called multiple times, a check for multiple calls is not needed. Example:

Code: Select all

Function Init() {
	MyValue = 3; // call this n times - nothing changes
}
If the system's state changes with every function call, the coder have to decide whether multiple execution is useful or not and may take actions to avoid it. Example:

Code: Select all

Function Init() {
	Spawn(Class'InitHelper'); // after each call one instance more will exist
	MyValue = MyValue * 2; // double your money on each call
}
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
Marscaleb
Average
Posts: 48
Joined: Tue Jun 07, 2016 6:50 am

Re: Starting some scripting, looking for some commands

Post by Marscaleb »

sektor2111 wrote:
Marscaleb wrote:Is there a function that gets called when the match actually starts (ie when the players spawn and the game clock actually starts counting down)?
There is a solution which I learned by myself in how to capture game-start in mutators. It is used Modifyplayer. In that moment when game starts, variable from "DMplus" bstartmatch or such is true, when that thing is true you can setup your own variable bMatchIsStarted = True if is False in ModifyPlayer as first line - of course you have to declare your variable first.
Dang. ModifyPlayer isn't accessible through Actor, so I can't go that route to add such functionality to the SSCheck class in this mutator.
Edit: Oh wait, this class is already running some inits that get called when the match starts. Never mind.
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Starting some scripting, looking for some commands

Post by sektor2111 »

ModifyPlayer is resident in Mutator not Actor.
Also Modifyplayer can be used itself to do checks because it works when player spawns... that's why here you can attach an actor to player and making sure to not already have one owned, unless you want a stacking actors loading Level and doing funky things... and ModifyPlayer doesn't need to get multiple calls forced, it is called automatically when it needs...
Post Reply