Page 16 of 26

Re: Dynamic Script Usage

PostPosted: 06 Jul 2013, 02:12
by Tef
What do you mean States.UnitPositionX and States.UnitPositionY are nasty for the Remake? They should just be simple commands that tell you where the unit is. Or did you mean UnitAt is nasty?
For example, I had this script that decreased the hunger level as a function of their movements, so much moving units get hungry more quickly than units that stand still. This implies looping through all units, store their x,y and compare and update this regularly. However, with the mentioned 2400 units and a check every 4 seconds this is unbearable. I've tried to find out what is actually so CPU-intensive; I've found that things like adding some hunger to 2400 units is much less CPU-intensive than, for example, querying a position of a unit. So, thats what I meant with 'nasty' :wink:
a) Use UnitAt to scan each tile in the area.
b) Scan through GetAllUnits and check their positions.
As told, I tried both. In the current form in my script they are both causing lags when upscaled, so I need to do smart stuff. I already have lots of 'continue' and 'break' in my loops to avoid any calculations whereas possible, but that is not sufficient so far. PlayerGetAllGroups is unsufficient, as I need citizens to be detected as well.
It is also possible to spread out processing of a) over multiple ticks. You can use tricks like processing every 2nd row of the map (e.g. Y=2,4,6 one tick, then Y=1,3,5 next tick).
I will probably do something like this. Did already tricks like this to this script that puts back the fog of war at places where units haven't been for a while. Initially VERY cpu intensive for big maps, because it needs to figure out which places of the map haven't been within the 'seeing' range of units for some period of time. I got it more efficient in three ways: 1) reducing the interval to perform calculations, 2) calculate just a part of the map each time, 3) reducing the calculations with a factor 16 by 'translating' the unit / fog data onto a virtual twodimensional array which is 4x4 as small as the map, and treating it as if it contains actual fog of war data.

For the detection of units, I am now thinking about this:
- every large interval, loop through all units and calculate any units that might come within proximity soon (like 20x20 tiles maybe) and store those into a private array for this detector
- in short intervals, only loop through the private detector array, and the first unit which is within circular range...well has a problem :mrgreen:

Re: Dynamic Script Usage

PostPosted: 06 Jul 2013, 02:39
by Lewin
What do you mean States.UnitPositionX and States.UnitPositionY are nasty for the Remake? They should just be simple commands that tell you where the unit is. Or did you mean UnitAt is nasty?
For example, I had this script that decreased the hunger level as a function of their movements, so much moving units get hungry more quickly than units that stand still. This implies looping through all units, store their x,y and compare and update this regularly. However, with the mentioned 2400 units and a check every 4 seconds this is unbearable. I've tried to find out what is actually so CPU-intensive; I've found that things like adding some hunger to 2400 units is much less CPU-intensive than, for example, querying a position of a unit. So, thats what I meant with 'nasty' :wink:
Querying the position should take about the same amount of time as adding hunger, but if you are doing both, and storing the position, and comparing it to what it was last time, that's a lot more processing that simply adding hunger. But in general UnitHungerSet and UnitPositionX (or Y) should take about the same amount of time to run.
For the detection of units, I am now thinking about this:
- every large interval, loop through all units and calculate any units that might come within proximity soon (like 20x20 tiles maybe) and store those into a private array for this detector
- in short intervals, only loop through the private detector array, and the first unit which is within circular range...well has a problem :mrgreen:
That might work, although you might find it lags on the large update intervals. You really want to spread things out between ticks, just doing a major update every 10 seconds and a minor update every second doesn't solve the problem because the game will still lag every 10 seconds (and any lag is bad). You want to design it to do a small amount of the processing every tick, by e.g. processing rows of the area in turns (so if you have a 20x20 area, on the first tick process rows 1 and 11, then 2 and 12, 3 and 13, etc. Here's an example:
  Code:
for Y :=1 to Height do if (States.GameTime+Y) mod 10 = 0 then for X := 1 to Width do //Your progressing for tile X,Y goes here
If you run that code every tick it will cycle through every row (after 10 ticks it will have progressed all rows). That is what you should be aiming for, don't do massive amounts of processing on any one tick, but instead use every tick to do a small amount of processing.

Re: Dynamic Script Usage

PostPosted: 08 Jul 2013, 16:42
by Islar
Hi

I have a question. I want to give a player a group every minute. But i want this only when the tiles are not occupied. I test it with one tile but it didn't work how i want. The first group appeared, then i get a message and then a new group appeared but i don't get a message. When those first two groups appeared nothing else happened. When i send only the second group away no more groups appeared. But if i send only the first group away more groups appeared after some time. When i send the first group away a message showed directly.

Now i want to ask what the propper way is to make this.
This is my script of the map.
  Code:
var Sword: Integer; PlacedSword: Boolean; Procedure OnMissionStart; begin PlacedSword := False; end; Procedure OnTick; begin if (States.GameTime mod 600 = 0) and not (States.PlayerDefeated (0)) and not PlacedSword then begin PlacedSword := True; Sword := States.GroupAt (4, 5); Actions.GiveGroup (0, 16, 4, 5, 4, 9, 3); end; begin if Sword = States.GroupAt (4, 5) then Exit; if PlacedSword then begin PlacedSword := False Actions.ShowMsg (0, 'Hello') end; end; end;

Re: Dynamic Script Usage

PostPosted: 09 Jul 2013, 02:58
by Lewin
Why do you have that "begin..end" block with nothing before it? (above the line "if Sword = States.GroupAt (4, 5) then") It would run exactly the same if you deleted the "begin" and "end" lines. Maybe that's not what you wanted?

I don't understand what the variable Sword and PlacedSword are supposed to do. Maybe you could write some comments in your code?

Re: Dynamic Script Usage

PostPosted: 11 Jul 2013, 14:24
by Islar
How can i make a delay in script? I want when enemy groups died, destroy a house and put a new house right there with script. I think this can't at the same time. :?
Would someone tell my how to make a delay?

Re: Dynamic Script Usage

PostPosted: 11 Jul 2013, 14:42
by Tef
No you cannot do it immediately at the same time, that's correct. What I do personally is defining a global variable like TimeOfHouseDestruction and set this to zero. When the house is destroyed (you can use OnHouseDestroyed) you should store the GameTime in that variable. Now you only have to create a script within OnTick that says something like this: when (GameTime > (TimeOfHouseDestruction + DelayTime)) and (TimeOfHouseDestruction <> 0) then... You can define any DelayTime or just use 0 if it should be the first new tick after destruction. Don't forget to set TimeOfHouseDestruction to 0 in that script, otherwise it will repeat that action every tick after house destruction.

Off course, this is one possibility, but this is roughly how I do it. Good luck!

Re: Dynamic Script Usage

PostPosted: 11 Jul 2013, 15:48
by Islar
I have now this but the actions do not trigger.
  Code:
var TimeOfHouseDestruction, GameTime, DelayTime: Integer; procedure OnMissionStart; begin GameTime := States.GameTime; DelayTime := 10; TimeOfHouseDestruction := 0; end; procedure OnTick; Begin If (GameTime > (TimeOfHouseDestruction + DelayTime)) and (TimeOfHouseDestruction <> 0) then begin TimeOfHouseDestruction := 0; Actions.GiveHouse (0, 11, 43, 44); Actions.ShowMsg (0, 'Test') end; end; procedure OnHouseDestroyed (aHouseID: Integer; aDestroyerIndex: Integer); begin If States.HouseDestroyed (Store2) then begin TimeOfHouseDestruction := States.GameTime; end; end;
Could you tell my were i misunderstood you :|

Re: Dynamic Script Usage

PostPosted: 11 Jul 2013, 17:03
by Tef
You say: If States.HouseDestroyed (Store2) but I don't see you defining Store2 somewhere. So, define Store2 by saying Store2 := States.HouseAt(x,y) for example. Also, when that storehouse is destroyed, the OnHouseDestroyed event is triggered automatically with its parameters aHouseID and aDestroyerIndex known, so you can say: if aHouseID = Store2 instead of if States.HouseDestroyed (Store2). And you should use States.GameTime instead of GameTime. Also store States.GameTime into your variable upon house destruction.

* EDIT: Islar's script has been fixed.

Re: Dynamic Script Usage

PostPosted: 11 Jul 2013, 23:57
by Lewin
There are other problems with your script Islar, you only set the variable "GameTime" during OnMissionStart, so for the entire mission it will be equal to 0 (so the script would be the same if you replaced GameTime with 0). Why do you need that global variable? Just use States.GameTime instead.

Actually, at the moment I think you can destroy houses and rebuild them instantly, but this could change in the future because it could be a source of errors if the house is not ready to be destroyed. Units are not killed instantly, they take 1 tick before they start dying.

Re: Dynamic Script Usage

PostPosted: 19 Jul 2013, 16:46
by Duke Valennius
Hello, is there a way to find out if player has permanently left multiplayer game? (lost connection - reconnect doesn't count)
It seems that PlayerEnabled and PlayerDefeated both return as if he was still playing. (enabled and not defeated)
I'm sorry if I missed something in reference.

Re: Dynamic Script Usage

PostPosted: 19 Jul 2013, 19:26
by Lewin
Hello, is there a way to find out if player has permanently left multiplayer game? (lost connection - reconnect doesn't count)
It seems that PlayerEnabled and PlayerDefeated both return as if he was still playing. (enabled and not defeated)
I'm sorry if I missed something in reference.
No, you can't tell that from the script. Players leaving is not something that affects the game play, (e.g. it's not recorded in replays) so the script must not have access to it. Currently the players keep working as if nothing happened even if their owner has left the game.

What did you want to use it for?

Re: Dynamic Script Usage

PostPosted: 20 Jul 2013, 07:35
by Duke Valennius
Hello, is there a way to find out if player has permanently left multiplayer game? (lost connection - reconnect doesn't count)
It seems that PlayerEnabled and PlayerDefeated both return as if he was still playing. (enabled and not defeated)
I'm sorry if I missed something in reference.
No, you can't tell that from the script. Players leaving is not something that affects the game play, (e.g. it's not recorded in replays) so the script must not have access to it. Currently the players keep working as if nothing happened even if their owner has left the game.

What did you want to use it for?
I constantly resupply players with weapons and recruits, with same amount going for each team (so that if there is 1 player in team A, and 4 players in team B, both teams receive same amounts). If player is defeated, everything goes well. However, if he disconnects, weapons are still given to him, and his team is in disadvantage. If he could be proclaimed defeated when he disconnects, it would work fine.
I guess it is same problem as in regular multiplayer games, but it would be nice to solve it.

Re: Dynamic Script Usage

PostPosted: 20 Jul 2013, 07:52
by Lewin
I constantly resupply players with weapons and recruits, with same amount going for each team (so that if there is 1 player in team A, and 4 players in team B, both teams receive same amounts). If player is defeated, everything goes well. However, if he disconnects, weapons are still given to him, and his team is in disadvantage. If he could be proclaimed defeated when he disconnects, it would work fine.
I guess it is same problem as in regular multiplayer games, but it would be nice to solve it.
We are planning to count players who have quit (or the host chose to continue playing without them when they disconnect) as defeated, it's been on the todo list for a while. That should solve it for you :)

Re: Dynamic Script Usage

PostPosted: 05 Aug 2013, 22:20
by Tef
Bug? -> It seems impossible to add a tree to a woodcutter's through Actions.HouseAddWaresTo().

Re: Dynamic Script Usage

PostPosted: 06 Aug 2013, 04:52
by Ben
That's because you cannot place a "product" in a building. You can only place the raw material. For example, you can only place pigs in butchers, and not sausages ;)

Why? I have no idea. Maybe it will be fixed one day :)