Page 2 of 26

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 05:19
by Krom
@Ben: Please be more specific in error's description. What is exactly happening, do you get an error message, or houses aren't blocked/unlocked?

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 05:31
by Ben
Nothing in the dynamic script is working at all. I am just getting this error:

Image

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 05:45
by Krom
That is because HouseAllow is not a state, it is an action. You need to change it to Actions.HouseAllow(...).

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 06:41
by Lewin
Yeah looks like I didn't write that example script properly, I was doing it in a hurry without checking. Remember it this way:

States are when you query the game without changing anything. For example: "How many warriors does player X have?", "How long has the game been running?", "What type of house is this?"

Actions are when you change something in the game, for example "Add a group of warriors for player X", "Show a message to the player", "Allow the player to build this house".

Events (OnSomething) are when the game lets you know that some event occurred, for example "A house was built", "a unit died", "game tick occurred".

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 13:10
by Ben
Thanks, Krom and Lewin. I'll see if I can get it working now.

And thanks also, Lewin, for your explanation. That helps a bit.

EDIT:

Okay, it is finally recognizing the code, but now it's doing something funky. It is disabling all buildings except the inn, which shouldn't be happening because the inn's ID (27) isn't in my code:
  Code:
procedure OnMissionStart; var I, P: Integer; begin for P := 0 to 5 do if States.PlayerEnabled(P) then begin for I := 0 to 28 do Actions.HouseAllow(P, I, False); Actions.HouseAllow(P, 11, True); Actions.HouseAllow(P, 13, True); end; end; procedure OnHouseBuilt(aHouse: Integer); begin if States.HouseType(aHouse) = 11 then Actions.HouseAllow(States.HouseOwner(aHouse), 13, True); if States.HouseType(aHouse) = 14 then Actions.HouseAllow(States.HouseOwner(aHouse), 9, True); end;
Totally confused... :?

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 14:07
by Lewin
Thanks for reporting, there was a bug in HouseAllow which made it work the opposite way expected. It works as "HouseBlock". So for now if you switch all cases of "True" to "False" it will work :)
But next RC it will be fixed so that HouseAllow(A, B, True) makes the house allowed, and False makes it blocked.

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 15:07
by Ben
I thought that this was what was happening, so I actually tried switching everything to False, but it still didn't work.
I must have overlooked something. I'll go try again.

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 15:26
by Lewin
I thought that this was what was happening, so I actually tried switching everything to False, but it still didn't work.
I must have overlooked something. I'll go try again.
Don't switch everything to false, swap true with false and false with true.
Also note that the example I gave you wasn't complete, you need to customise what happens in OnHouseBuilt so building the school allows the inn, etc. You also need to allow everything when they build the sawmill to make it use the "normal" unlock order after that.

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 16:10
by Ben
Don't switch everything to false, swap true with false and false with true.
Yeah that's what I meant. I figured it out; though, and it is working fine :)
Also note that the example I gave you wasn't complete, you need to customise what happens in OnHouseBuilt so building the school allows the inn, etc. You also need to allow everything when they build the sawmill to make it use the "normal" unlock order after that.
Yeah I did it the hard way: manually doing each unlock. I guess that I wasn't thinking. Oh well. More experience I guess :P

Also, if I just wanted to disable just two buildings, and not, say 9-27, could I just do two IDs instead of a range?

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 16:44
by Lewin
Also, if I just wanted to disable just two buildings, and not, say 9-27, could I just do two IDs instead of a range?
Yes that might be smarter in this case. Just run Actions.HouseAllow twice with fixed IDs (instead of I from the loop), and remove the for loop completely.

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 17:21
by Ben
Thanks again.

Sado and I were trying to figure out if we could use the OnTick even to run after more than just 1 tick. For example, say I wanted a unit to be created after 1000 ticks. How would I do this?

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 21:23
by The Dark Lord
I'm having troubles too. This error occurs: [Error] (8:26): Type mismatch
I'm using the exact same script as before, when it worked just fine. What's changed?
Also, can't it just ignore the scripts that aren't working? Currently nothing works if there's just one tiny mistake; that's pretty annoying, I can't do a thing right now.
  Code:
var Message0Sent: Boolean; Attack1Started, Attack2Started, Attack3Started, Attack4Started, Attack5Started, Attack6Started: Boolean; Attack1Defeated, Attack2Defeated, Attack3Defeated, Attack4Defeated, Attack5Defeated, Attack6Defeated: array [0..3] of Boolean; procedure ShowMsgToPlayers(aMsg: Integer); begin Actions.ShowMsg(0, aMsg); Actions.ShowMsg(1, aMsg); Actions.ShowMsg(2, aMsg); Actions.ShowMsg(3, aMsg); end; procedure CheckAttack1Defeated(aPlayer: Integer); begin if (States.ArmyCount(aPlayer + 4) = 0) and (Attack1Defeated[aPlayer] = false) and (States.GameTime > 2400) then begin Actions.GiveWares(aPlayer, 1, 50); Actions.GiveWares(aPlayer, 2, 15); Actions.GiveWares(aPlayer, 7, 15); Actions.ShowMsg(aPlayer, 2); Attack1Defeated[aPlayer] := True; //Actions.SetOverlayText(0; 1; 2; 3, States.TextFormatted(30, [States.PlayerColorText(aPlayer), States.PlayerName(aPlayer)])); end; end; procedure CheckAttack2Defeated(aPlayer: Integer); begin if (States.ArmyCount(aPlayer + 4) = 0) and (Attack2Defeated[aPlayer] = false) and (States.GameTime > 6600) then begin Actions.GiveWares(aPlayer, 1, 40); Actions.GiveWares(aPlayer, 2, 15); Actions.GiveWares(aPlayer, 7, 15); Actions.ShowMsg(aPlayer, 4); Attack2Defeated[aPlayer] := True; end; end; procedure CheckAttack3Defeated(aPlayer: Integer); begin if (States.ArmyCount(aPlayer + 4) = 0) and (Attack3Defeated[aPlayer] = false) and (States.GameTime > 9600) then begin Actions.GiveWares(aPlayer, 1, 50); Actions.GiveWares(aPlayer, 2, 20); Actions.GiveWares(aPlayer, 7, 20); Actions.ShowMsg(aPlayer, 6); Attack3Defeated[aPlayer] := True; end; end; procedure CheckAttack4Defeated(aPlayer: Integer); begin if (States.ArmyCount(aPlayer + 4) = 0) and (Attack4Defeated[aPlayer] = false) and (States.GameTime > 13800) then begin Actions.GiveWares(aPlayer, 1, 50); Actions.GiveWares(aPlayer, 2, 15); Actions.GiveWares(aPlayer, 7, 10); Actions.ShowMsg(aPlayer, 8); Attack4Defeated[aPlayer] := True; end; end; procedure CheckAttack5Defeated(aPlayer: Integer); begin if (States.ArmyCount(aPlayer + 4) = 0) and (Attack5Defeated[aPlayer] = false) and (States.GameTime > 16800) then begin Actions.GiveWares(aPlayer, 1, 35); Actions.GiveWares(aPlayer, 2, 10); Actions.GiveWares(aPlayer, 7, 5); Actions.GiveWares(aPlayer, 18, 10); Actions.ShowMsg(aPlayer, 10); Attack5Defeated[aPlayer] := True; end; end; procedure CheckAttack6Defeated(aPlayer: Integer); begin if (States.ArmyCount(aPlayer + 4) = 0) and (Attack6Defeated[aPlayer] = false) and (States.GameTime > 19800) then begin Actions.GiveWares(aPlayer, 1, 30); Actions.GiveWares(aPlayer, 7, 10); Actions.ShowMsg(aPlayer, 12); Attack6Defeated[aPlayer] := True; end; end; begin if (States.GameTime = 50) and not Message0Sent then begin ShowMsgToPlayers(0); //Actions.ShowCountdown(0, 2350); //Actions.ShowCountdown(1, 2350); //Actions.ShowCountdown(2, 2350); //Actions.ShowCountdown(3, 2350); Message0Sent := true; end; //attack wave 1 if (States.GameTime = 2400) and not Attack1Started then begin Actions.GiveGroup(4, 14, 68, 78, 5, 15, 1); Actions.GiveGroup(5, 14, 122, 78, 3, 15, 1); Actions.GiveGroup(6, 14, 68, 112, 7, 15, 1); Actions.GiveGroup(7, 14, 122, 112, 1, 15, 1); ShowMsgToPlayers(1); //Actions.ShowCountdown(0, 4200); //Actions.ShowCountdown(1, 4200); //Actions.ShowCountdown(2, 4200); //Actions.ShowCountdown(3, 4200); Attack1Started := true; end; CheckAttack1Defeated(0); CheckAttack1Defeated(1); CheckAttack1Defeated(2); CheckAttack1Defeated(3); //Attack wave 2 if (States.GameTime = 6600) and (Attack2Started = false) then begin Actions.GiveGroup(4, 19, 68, 78, 5, 20, 1); Actions.GiveGroup(5, 19, 122, 78, 3, 20, 1); Actions.GiveGroup(6, 19, 68, 112, 7, 20, 1); Actions.GiveGroup(7, 19, 122, 112, 1, 20, 1); ShowMsgToPlayers(3); //Actions.ShowCountdown(0, 3000); //Actions.ShowCountdown(1, 3000); //Actions.ShowCountdown(2, 3000); //Actions.ShowCountdown(3, 3000); Attack2Started := true; end; CheckAttack2Defeated(0); CheckAttack2Defeated(1); CheckAttack2Defeated(2); CheckAttack2Defeated(3); //Attack wave 3 if (States.GameTime = 9600) and (Attack3Started = false) then begin Actions.GiveGroup(4, 20, 68, 78, 5, 25, 1); Actions.GiveGroup(5, 20, 122, 78, 3, 25, 1); Actions.GiveGroup(6, 20, 68, 112, 7, 25, 1); Actions.GiveGroup(7, 20, 122, 112, 1, 25, 1); ShowMsgToPlayers(5); //Actions.ShowCountdown(0, 3000); //Actions.ShowCountdown(1, 3000); //Actions.ShowCountdown(2, 3000); //Actions.ShowCountdown(3, 3000); Attack3Started := true; end; CheckAttack3Defeated(0); CheckAttack3Defeated(1); CheckAttack3Defeated(2); CheckAttack3Defeated(3); //Attack wave 4 if (States.GameTime = 12600) and (Attack4Started = false) then begin Actions.GiveGroup(4, 14, 68, 78, 5, 60, 5); Actions.GiveGroup(5, 14, 122, 78, 3, 60, 5); Actions.GiveGroup(6, 14, 68, 112, 7, 60, 5); Actions.GiveGroup(7, 14, 122, 112, 1, 60, 5); Actions.GiveGroup(4, 15, 70, 80, 5, 20, 2); Actions.GiveGroup(5, 15, 124, 80, 3, 20, 2); Actions.GiveGroup(6, 15, 70, 114, 7, 20, 2); Actions.GiveGroup(7, 15, 124, 114, 1, 20, 2); ShowMsgToPlayers(7); //Actions.ShowCountdown(0, 3000); //Actions.ShowCountdown(1, 3000); //Actions.ShowCountdown(2, 3000); //Actions.ShowCountdown(3, 3000); Attack4Started := true; end; CheckAttack4Defeated(0); CheckAttack4Defeated(1); CheckAttack4Defeated(2); CheckAttack4Defeated(3); //Attack wave 5 if (States.GameTime = 15600) and (Attack5Started = false) then begin Actions.GiveGroup(4, 21, 68, 78, 5, 20, 1); Actions.GiveGroup(5, 21, 122, 78, 3, 20, 1); Actions.GiveGroup(6, 21, 68, 112, 7, 20, 1); Actions.GiveGroup(7, 21, 122, 112, 1, 20, 1); ShowMsgToPlayers(9); //Actions.ShowCountdown(0, 3000); //Actions.ShowCountdown(1, 3000); //Actions.ShowCountdown(2, 3000); //Actions.ShowCountdown(3, 3000); Attack5Started := true; end; CheckAttack6Defeated(0); CheckAttack6Defeated(1); CheckAttack6Defeated(2); CheckAttack6Defeated(3); //Attack wave 6 if (States.GameTime = 18600) and (Attack6Started = false) then begin Actions.GiveGroup(4, 16, 68, 78, 5, 50, 3); Actions.GiveGroup(5, 16, 122, 78, 3, 50, 3); Actions.GiveGroup(6, 16, 68, 112, 7, 50, 3); Actions.GiveGroup(7, 16, 122, 112, 1, 50, 3); ShowMsgToPlayers(11); //Actions.ShowCountdown(0, 3000); //Actions.ShowCountdown(1, 3000); //Actions.ShowCountdown(2, 3000); //Actions.ShowCountdown(3, 3000); Attack6Started := true; end; CheckAttack6Defeated(0); CheckAttack6Defeated(1); CheckAttack6Defeated(2); CheckAttack6Defeated(3); end.

Re: Dynamic Script Usage

PostPosted: 12 Apr 2013, 22:47
by sado1
Would be nice to actually have a tool that'd check script's integrity without running the map again and again just to see what was the mistake.

Re: Dynamic Script Usage

PostPosted: 13 Apr 2013, 01:05
by Lewin
I'm having troubles too. This error occurs: [Error] (8:26): Type mismatch
I'm using the exact same script as before, when it worked just fine. What's changed?
We changed quite a lot of stuff since you originally wrote that script. In future releases we'll try to keep backwards compatibility better, but you were using an "alpha" version of the scripting demo back then ;) Here's the stuff which affects your script
- The error you got says there's a mistake on line 8 at character 26. You can see that's this: Actions.ShowMsg, the second parameter needs to be a string (text). You can fetch text out of the LIBX files using States.Text(X). So replace "Actions.ShowMsg(0, aMsg);" with "Actions.ShowMsg(0, States.Text(aMsg));" This allows you to combine text more easily, like I did for the overlay in Annie's Hill. There are more cases where you used "Actions.ShowMsg" in the script, so make sure you fix all of them.
- States.ArmyCount was renamed to States.StatArmyCount
- The "begin .... end." at the bottom of the document (the main bit of code that runs every tick) needs to be replaced with "procedure OnTick;
begin
...
end;"
So basically add the procedure line at the top and replace the final "." after the end with a ";". We changed it to work like this to be more consistent (everything happens through events)

When you get an error like "(8:26): Type mismatch", check what commands you use on that line (8) and lookup in the wiki to make sure you are using them correctly (in this case you provided an integer when it expected a string, so that's a type mismatch)

After fixing those 3 things your script runs without errors for me, and shows me a message :)
Also, can't it just ignore the scripts that aren't working? Currently nothing works if there's just one tiny mistake; that's pretty annoying, I can't do a thing right now.
Unfortunately no, that's the way programming usually works. Because that one mistake could cause nothing else to work in the script. The closest thing we could do is remove every line that causes an error (there's a joke Javascript library that does that...) but that wouldn't be very helpful, since often it will just cause more errors and confuse the user when the wrong stuff happens, for example if we removed an if statement that was broken the conditional code would run every time.
Would be nice to actually have a tool that'd check script's integrity without running the map again and again just to see what was the mistake.
Yes it would, I'm planning to write one for the next RC :)


EDIT:
Sado and I were trying to figure out if we could use the OnTick even to run after more than just 1 tick. For example, say I wanted a unit to be created after 1000 ticks. How would I do this?
Your procedure OnTick will be run EVERY tick of the game, 10 times per second for the entire game. If you want a unit to be created after 1000 ticks use this:
  Code:
procedure OnTick; begin if States.GameTime = 1000 then Actions.GiveUnit(...); end;
So every tick the game will check "is this tick 1000"? If yes, it will run the GiveUnit code. If no, it won't do anything in this case. But you could add more stuff into OnTick:
  Code:
procedure OnTick; begin //Every tick we should set the text overlaid on the screen for player 0 Actions.SetOverlayText(0, 'Current tick: '+IntToStr(States.GameTime)); if States.GameTime = 100 then //After 10 seconds begin Actions.ShowMsg(...); //Show a message Actions.GiveWares(...); //Give the player some wares end; if States.GameTime = 1000 then //After 100 seconds Actions.GiveUnit(...); //Give the player a unit end;

Re: Dynamic Script Usage

PostPosted: 13 Apr 2013, 02:03
by Ben
But this only works once. I thought that the OnTick would work as a loop, but with the gametime action, it doesn't work like that. So how do I make this a loop?