Battlezone Universe

Battlezone Universe => Battlezone 2 => Maps and Modding => Topic started by: Avatar on January 21, 2008, 07:56:56 PM

Title: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 21, 2008, 07:56:56 PM
I personally think the Scriptor and/or DLL creation could use their own sub-boards.  I know there's been a lot of help given here and there, but it would be nice to have it all in one place.

Anyway, as a contribution to anyone wanting to learn more about the phenomenally easy to use DLL Scriptor by BS-er, here's some code that reads the difficulty level the Player has selected in the Options/Play screen and runs different code depending on that choice.  This is something I'd been trying to figure out for some time and am now incorporating into BZClassic to make the 'Hard' setting take you beyond the original BZ1 missions.

To read the Difficulty setting:

IFaceGetInt,"options.instant.int1"   //reads the difficulty they chose
  StoreResult,Difficulty                  //stores the result in the variable "Difficulty"

  Add,Difficulty,0                         //The Scriptor can't compare two values directly (no "if A = B")
  IfEQ,0,EASY                             //"Easy" reads as zero, if Difficulty + 0 = 0 Goto EASY
  IfEQ,1,MEDIUM                         //"Medium" reads as one, if Difficulty + 0 = 1 Goto MEDIUM
  IfEQ,2,HARD                             //"Hard" reads as two, if Difficulty + 0 = 2 Goto HARD

EASY:       //Go here if they chose '0' or 'Easy'.
  //place your code here, like this line that makes a Warrior
   createp,warrior1,"fvtank",5,"spawnpoint1"
             
  GoTo,ENDDIFFICULTY     //When done with your code jump over the rest

MEDIUM:    //Go here if they chose '1' or 'Medium'
  //again, your code for medium goes here, like making TWO Warriors
  createp,warrior1,"fvtank",5,"spawnpoint1"
  createp,warrior2,"fvtank",5,"spawnpoint2"

  GoTo,ENDDIFFICULTY    //Again, you have to jump over the rest when done

HARD:
  //your code for hard goes here, like making THREE Warriors
  createp,warrior1,"fvtank",5,"spawnpoint1"
  createp,warrior2,"fvtank",5,"spawnpoint2"
  createp,warrior3,"fvtank",5,"spawnpoint3"

ENDDIFFICULTY:    //and here we are, all done.


Now, if all you were doing was making warriors you can condense it all down:

IFaceGetInt,"options.instant.int1"   //reads the difficulty they chose
  StoreResult,Difficulty                  //stores the result in the variable "Difficulty"

  Add,Difficulty,0                         //The Scriptor can't compare two values directly (no "if A = B")
  IfEQ,0,EASY                             //"Easy" reads as zero, if Difficulty + 0 = 0 Goto EASY
  IfEQ,1,MEDIUM                         //"Medium" reads as one, if Difficulty + 0 = 1 Goto MEDIUM
  IfEQ,2,HARD                             //"Hard" reads as two, if Difficulty + 0 = 2 Goto HARD

HARD:   //'hard' will make three warriors
  createp,warrior3,"fvtank",5,"spawnpoint3"
MEDIUM: //'medium' will make two warriors
  createp,warrior2,"fvtank",5,"spawnpoint2"
EASY:  //'easy' will make one warrior
  createp,warrior1,"fvtank",5,"spawnpoint1"

//and here we are, all done.


Keep in mind that the DLL is run progressively, and the setting read at the time that the code is run.  That means with this code they can play on 'Hard' until they cry, and then drop down to 'Easy' to get through the tough part, going back to 'Hard' again to say they made it to the end on 'Hard'...   :)

-Av-


Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 21, 2008, 08:25:15 PM
Or in my Python scriptor:
# Direct code:
difficulty = IFace_GetInteger("options.instant.int1")
if difficulty==0:
    # Do easy
elif difficulty==1
    # Do medium
elif difficulty==2
    # Do Hard

# Could also define these somewhere in the main script area:
Easy = 0
Medium = 1
Hard = 2

# So you can do this instead (more readable):
difficulty = IFace_GetInteger("options.instant.int1")
if difficulty is Easy: # Could still do difficulty==EASY is so inclined, but this is more readable and appropriate for this case
    # Do easy
elif difficulty is Medium
    # Do medium
elif difficulty is Hard
    # Do Hard


Or in C++:
const int difficulty = IFace_GetInteger("options.instant.int1")
if(difficulty==0)
{
    // Do Easy
}
else if(difficulty==1)
{
    // Do Medium
}
else if(difficulty==2)
{
    // Do Hard
}

// Or to be more readable, put this somewhere in a main section or header or what-not (and yes, for any of you real programmers, I would normally put constants, in both C++ and Python all in caps, but this is easier to look at for non-programmers):
const int Easy = 0;
const int Medium = 1;
const int Hard = 2;

// Then this:
const int difficulty = IFace_GetInteger("options.instant.int1")
if(difficulty==Easy)
{
    // Do Easy
}
else if(difficulty==Medium)
{
    // Do Medium
}
else if(difficulty==Hard)
{
    // Do Hard
}
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Lizard on January 21, 2008, 08:38:20 PM
this is another thread that could do with being stickied , but we have so many stickies up there already I'm a bit reluctant to add another one .......
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 21, 2008, 09:30:00 PM
Should probably add it to a Wiki, this is not really the kind of stuff to belong in a forum post. :)
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 21, 2008, 10:54:27 PM
First off, I don't mean any slight to your Scriptor OM, it's just the BSer was there first and his is a bit more english-intuitive, or at least IMHO easier for a non-programmer to pick up and do something with.  It's also very well documented and Sonic has made a ton of examples available to boot.

So not to leave you out in the cold here, and it's excellent that you post a 'translation' to both your Python and VC++.  Makes this sort of a 'Rosetta Stone' for scripting...  :)

As to a Wiki that would be cool.  I'd love to see examples of code posted, as well as some place people could post code they need help with OR just questions and such.

-Av-
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Sonic on January 21, 2008, 11:47:15 PM
I'll pass the thought of having a DLL Scriptor Forum to CmptrWz. I would say thought it won't happen till the site is moved to the new server.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Red Devil on January 22, 2008, 12:05:45 AM
 I say bite the bullet and learn C++.  Well worth it.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Sonic on January 22, 2008, 12:54:19 AM
Quote from: Red Devil on January 22, 2008, 12:05:45 AM
I say bite the bullet and learn C++.  Well worth it.

I dunno, C++ works great for things like MPIs, but the DLL Scriptor provides lineage which is great for story based missions. I find it alot easier to write a single player mission in the scriptor when I'm worried about having the player do x than y than z than to write a C++ DLL. I find it easier in C++ however to do things like do x every 10 minutes, check y every run, suprise the player when z happens.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: bigbadbogie on January 22, 2008, 01:09:15 AM
without the dll scriptor i bet that many mods would never have been made - fleshstorm and FE would be pipedreams

i looked at some c++ coding a while ago and vowed to never, ever learn how to do that - because my life would vanish
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Nielk1 on January 22, 2008, 03:12:48 AM
Personaly that C++ looks more at home to me...
It could use adding to the BZU wiki (whereever it is). My BZWIKI is not so technicly minded ATM, it is more conserned about story (that and I'm moving sites). :roll:
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 22, 2008, 05:03:40 AM
Let's see, with my python version (mostly going to Sonic there), mine has linearity (you can even Sleep(time) and it will pause that tasklet, can make it very linear, not to mention tasklets are vastly useful in simplifying *so* much code).  The code tends to be a great deal shorter then BS-er's scriptor and C++ (while being more readable in my opinion, I can give examples if you give me large swathes of scriptor code for me to convert :) ).

And doing things every so often, in my scriptor is like this:

    def DoEveryTenMinutes():
        while True:
            AddToMessagesBox("This is sent once every ten minutes"
            Sleep(10*60*10) # 10 ticks in a second, 60 seconds in a minute, for 10 minutes, could just write 6000, I could even make conversions functions so you could write something like:   Sleep(MinutesToTicks(10))

    def RunEveryTick()
        while True:
            AddToMessagesBox("This will spam your message box every single tick (ten times a second)")
            Sleep()

    # This decorator does not exist, but I could make it in, oh, a few seconds...
    @RunWhenIsBuilt(ODF="UberTank", Team=HumanTeam)
    def UberTankBuiltByHumans(uberTank):
        while uberTank: # While uberTank is alive in other words), could also do while uberTank.IsAlive():
            BuildObject("UberTankKiller", ComputerTeam, UberTankKillerSpawnPoint).Attack(uberTank, 1000) # Focusing on killing the ubertank, at the expense of all else
            Sleep(10*60) # Wait 60 seconds, then retest if uberTank is alive, if so, it will build another killer, if not, then the killers will be idle and soon be picked up by the idle dispatcher, would also be simple to keep a list of them and send them off to do something else once the uberTank is dead)

    @RunWhenPlayerDies(Team=HumanTeam)
    def PlayerDied(player):
        FailMission(100, "PlayerDiedLostMessage.txt")

    @RunWhenIsDestroyed(ODF="UberTank", Team=HumanTeam)
    def UberTankDied(uberTank):
        FailMission(100, "UberTankDiedLostMessage.txt")

    @RunWhenIsDestroyed(ODF="AiRecy", Team=ComputerTeam)
    def ComputerRecyclerDied(recy):
        SucceedMission(100, "ComputerKilledWinMessage.txt")

    def SomethingLinearForPlayerToDo():
        player = GetLocalPlayer()
        uberTankFactory = GetUberTankFactory()

        AddObjective("Goto Uber-Tank Factory", WHITE)
        SetObjectiveOn(uberTankFactory)
        while not player.IsWithin(uberTankFactory, 50):
            Sleep()

        ClearObjectives()
        AddObjective("Goto Uber-Tank Factory", GREEN)
        AddObjective("Slaughter the enemy before they slaughter your Uber-Tank", WHITE)

        SetBestGroup(BuildObject("UberTank", HumanTeam, uberTankFactory))

        AddToMessagesBox("Computer: GAGH, I WILL KILL YOU FOR THAT!", RGB(255, 64, 64))


And yes, those decorated functions (when something dies and so forth, I really should make those, would be easy, and it is powerful as seen... hmm... next version perhaps) can be turned on or off at will, but they are on by default. and not all parameters are necessary, for example if Team is omitted then it will be called anytime anyone builds/kills one, regardless of Team, and could be other options too.

How would something like this work in the scriptor, I know it would be pretty simple too for 'some' of those functions, and in C++ pretty much all of that is... well... impossible as is, would need a lot of code to set things up and so forth, or make real threads with locks.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Red Devil on January 22, 2008, 05:26:36 AM
 You slay me, dude.  I can see you and Nathan and Ken sitting on the back porch in your old age enjoying a good sherry reminiscing about the classes you've built and the bad pointers you found.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 22, 2008, 06:04:49 AM
Programming is life. :)
Literally though, you should hear me when someone asks what I have been up to coding recently (usually they are relatively new around me and just know I 'program', but do not know how involved I get), I will start and go for hours if I am not stopped, talking about implementation details I discovered were useful, little bugs I ran into, etc... etc...  I am not normally asked again. :p
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: bigbadbogie on January 22, 2008, 06:13:59 AM
Quote from: OvermindDL1 on January 22, 2008, 06:04:49 AM
Programming is life. :)

no - programming is death  :evil:
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 22, 2008, 06:38:19 AM
Only for those that cannot program. :P
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: bigbadbogie on January 22, 2008, 07:53:17 AM
true  8-)
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Sonic on January 22, 2008, 02:12:16 PM
I figured yours also had a linear style, but I simply choose to stay on topic with DLL Scriptor since its the one I've used for 4 mods and several FE missions.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 22, 2008, 06:30:51 PM
I am still interested in the scriptor equivalent of what I posted.  I could do the C++ equiv but it would be rather nasty for some of those.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 22, 2008, 07:36:54 PM
I can do some off the top of my head, but I'm at work and can't make sure it's 100% true code:

[text]
spammessage1,"This is sent once every ten minutes."
spammessage2,"This will spam your message box every single tick (ten times a second)"

routine, everyten,1,true
Startover:
   wait,600  //60seconds per minute * 10 minutes
   display,spammessage1
   Jumpto,Startover

routine, everytick,1,true
Startover:
  display,spammessage2
  Jumpto,Startover

routine,killubertank,1,true
checkagain:
  getbylabel,"unnamed_ubertank1",ubertank
  isaround,ubertank
  ifeq,false,checkagain
  getteam,ubertank
  ifNE,1,checkagain
  createp,"ivutankkill",uberkiller,2
  attack,ubertank,uberkiller,5000
  wait,60
  jumpto,checkagain
 
routine,checkplayer,1,true
checkagain:
  getplayer,theplayer
  isaround, theplayer
  ifeq,true,checkagain
  fail,youdied.des,10

routine,checkubertank,1,true
checkagain:
  getbylabel,"unnamed_ubertank1",ubertank
  isaround,ubertank
  ifeq,true,checkagain
  fail,uberdied.des,10

routine,checkenemyrec,1,true
checkagain:
  getbyTS,1,1,enemyrec
  isaround,enemyrec
  ifeq,true,checkagain
  win,"youkilledem.des",10


routine,playertask,1,true
  getbylabel,"unnamed_ubertankfactory1",enemyfactory
  display,"go to the enemy factory",white
  beaconon,enemyfactory
checkagain:
  getplayer,theplayer
  distobject,theplayer,enemyfactory
  ifGT,50,checkagain
  clear
  display,"go to the enemy factory",green
  display,"Slaughter the enemy before they slaughter your Uber-Tank!",white
 

and, I'm not sure what the last few lines of your code do, OM, but it would be easy enough to watch for the ubertankfactory to die...

I can ready youre code easily enough OM, and would gladly use it, but it would take some good documentation before I felt comfortable doing so.  As it is I can fumble my way through Scriptor code, even at work, with minimal errors, even though it's been some months since I last did a lot of code.

***

Where the Scriptor fall short is in comparisons, conditional loops, arrays, and I have trouble assigning proper labels to units that are created ingame.

For instance, it would be great to be able to make an array of all of the enemy Scavs created during the game and loop through them easily to check their distance from your base.  You can do this in the Scriptor but it's not very intuitive, or efficient, and it's hard to shuffle the groups down, and and and...   the code GSH gave me to do it in VC++ for MP is small and elegant, where the Scriptor equivalent fills a page and a half...

Anyway, I'd gladly go with your Scriptor but you're going to have to bite the bullet and make some sort of help file outlining how it all works.   :)

-Av-
 
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: bigbadbogie on January 22, 2008, 09:20:55 PM
which are you using for bzc av??
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 22, 2008, 09:34:45 PM
On things like "routine, everytick,1,true", shouldn't that 1 actually be equal to the number of commands in the routine to be fully synced, because like that it will only execute one command a tick, instead of the whole loop every tick, thus meaning it will actually only print once every 2 to 3 ticks?  The others have the same issue.

And yea the last few lines:

        # This will create an "UberTank.odf" unit for the human at the location of the
        #  uberTankFactory, then give it a group so the human can control it
        SetBestGroup(BuildObject("UberTank", HumanTeam, uberTankFactory))

        # The above line could be written like this too if you needed to do more with it...
        uberTank = BuildObject("UberTank", HumanTeam, uberTankFactory)
        SetBestGroup(uberTank)

        # This just displays a message in the message box, so probably something
        #  like display,spammessage3 if spammessage3 is set to the message.
        #  Does the scriptor support colorizing the message box text, because that
        #  is what that RGB does, just a lightish red is what I had it do.
        AddToMessagesBox("Computer: GAGH, I WILL KILL YOU FOR THAT!", RGB(255, 64, 64))



To do something like looping over a list of enemy scavs, you could do something like this (with example):
class EnemyScavDistanceWatcher():
    def __init__(self):
        self.__enemyScavs = [] # Two underscores in front of a variable name makes it private, like the private keyword in C++

    @RunWhenIsBuilt(GOClass=("CLASS_SCAVENGER", "CLASS_SCAVENGERH"), NotTeam=HumanTeam)
    def NonHumanScavCreated(self, scav):
        self.__enemyScavs.append(scav)

    @RunWhenIsDestroyed(GOClass=("CLASS_SCAVENGER", "CLASS_SCAVENGERH"), NotTeam=HumanTeam)
    def NonHumanScavDestroyed(self, scav):
        self.__enemyScavs.remove(scav)

    def GetClosestAIScavAndDistance(self, from):
        closest = None
        dist = 2**30
        for scav in self.__enemyScavs:
            d = scav.GetDistance(from)
            if d<dist:
                dist = d
                closest = scav
        return (closest, dist)



# Then from your mission class, just inherit from this as well, you could just
#  put it inside the class directly and save a little bit of code, but this way is
#  reusable across projects and so forth :)
class MyMission(BZ2Mission, EnemyScavDistanceWatcher):
    # etc... and other things...

    # This is just some function that checks to see if the nearest scav is within
    #  a certain distance of the main base, and if so permenently marks it on the
    #  hud for the player to attack
    def WatchForEnemyScavsAndMark(self):
        humanBase = GetHumanMainBuilding()
        while humanBase:
            scav, dist = self.GetClosestAIScavAndDistance(humanBase)
            if dist<200.0:
                scav.SetObjectiveOn()
                Sleep(10*30) # Wait one-half minute before marking again...
            else:
                Sleep(10) # Test once a second


And yea, I know, need to create documentation...
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 22, 2008, 09:44:52 PM
I had the scripts done using BSer's Scriptor before OM's came out...  I've got a LOT of time and effort into the missions and starting over with a new utility, no matter how much more powerful, isn't going to happen...

To me the main attraction of OM's version is MP support.  To have something like the Scriptor, that will do MP capable scripts so we can make online co-op missions (like DuneCommand's), would be a dream...

SO...  when BZC is out and the stock missions in the can I might turn to OM's Scriptor to do the Ancients Campaign.  It would be cool if they could all be played out as MPI's, as that means a more realistic level of difficulty.

***

The 'wait,600' will make it wait 600 seconds, and yes maybe there'll be 1/10th of a second between the end of the wait and the printout, but I'd call it close enough.  :)

The other only actually has one command, the print command.  The label doesn't take a tick, the jump might but it doesn't seem that it does, as it just sets the next run point, so you get one line printed each 1/10th of a second.

I've never worried about time and the number of lines run, as "wait,30" seems to wait for 30 seconds to me.  Maybe it's off by a second or two in some scripts but I've never really timed it that closely.  (If the Golem comes and eats me at roughly the time I told it to I'm happy...).

-Av-
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Warfreak on January 22, 2008, 11:12:36 PM
I can barely find the right link to OM's Scriptor.............. (yes,very sad)....................

To BBB..........
Those who are programatically (yes, play on words i suppose) illiterate will suffer in this age of time.......... I am among that group........so dont be like me....... :-D
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 23, 2008, 01:21:22 AM
Actually my experience is that there's a divide forming.

There are those who understand how and why a program works, and while they know the code ins and outs they often aren't even that good at using the program.  Technically brilliant they often aren't the best source for info on making the program useful in real life situations.

Then there are those who don't have a clue as to what's under the hood, but can be absolute adepts at using it.  The whole thing is magic to them, but they can make it dance and sing.

There are few who bridge the gap nowadays.  We're becoming Morlock and Eloi right before our eyes...

-Av-

Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: bigbadbogie on January 23, 2008, 02:53:13 AM
exactly av -- i am the second class you mentioned - as are most modders

BSer bridges the gap - he made the dll scriptor and several FE missions
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 23, 2008, 05:03:41 AM
I worked a tiny bit on the documentation (a tiny bit meaning almost 50 functions and so forth, just a drop in the huge amount there is).  I also, really need to get a new version out, the new one has more capabilities, which are always a good thing. :)
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Nielk1 on January 23, 2008, 06:17:35 PM
If I ever make missions, I wont be able to beat them... I am one of those good at modding bad at playing. Then again, I don't give myself enough credit.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 23, 2008, 09:41:26 PM
The mark of a good mission is that it won't play exactly the same each time, so if they catch you napping you're toast even if you were the one making the script.  There should be an ebb and flow, a mix of tactics and styles, and a touch of randomness to make it fun.

:)

-Av-
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: bigbadbogie on January 23, 2008, 11:11:49 PM
Then you are going to love qf mod
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Sonic on January 24, 2008, 02:51:36 AM
Quote from: Avatar on January 23, 2008, 09:41:26 PM
The mark of a good mission is that it won't play exactly the same each time, so if they catch you napping you're toast even if you were the one making the script.  There should be an ebb and flow, a mix of tactics and styles, and a touch of randomness to make it fun.

:)

-Av-

My MPI DLL takes randomness into account which can be damn evil. The Reinforcements routine will randomly spit things out at a random point. The evil of it is its called at a fix time variable, called when the AI's Anti-Siege is called and when the AI's Recycler has taking moderate damage. The results one time was we have 4 Siege Tanks show up from all directions smashing down our defenses, which included Rave Titans mind you.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Nielk1 on January 24, 2008, 06:15:42 AM
Quote from: Avatar on January 23, 2008, 09:41:26 PM
The mark of a good mission is that it won't play exactly the same each time, so if they catch you napping you're toast even if you were the one making the script.  There should be an ebb and flow, a mix of tactics and styles, and a touch of randomness to make it fun.

:)

-Av-

I take it we are randomizing with the computer clock miliseconds as the seed?
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: OvermindDL1 on January 24, 2008, 08:56:30 AM
BZ2 supplies a couple random functions that are synced across the network (assuming they are called an equal number of times of course), probably that.
Title: Re: The Scriptor, Mission Difficulty, and you...
Post by: Avatar on January 24, 2008, 10:56:27 AM
Um...  remember, it's me...  the storyteller.  I'm not talking about MP, I'm talking about SP/IA.

I'd need either serious DLL help or OM's Scriptor for MP missions as I wouldn't even know where to start right now.  The only way the BZC MP DLL worked at all was with a ton of hand holding by OM and GSH, I couldn't have done it properly on my own.

-Av-