Page 1 of 1

Fog of War

PostPosted: 22 Sep 2014, 12:08
by Esthlos
I remember this being discussed somewhere in the forum, but with the Search function I can't seem to be able to find a dedicated topic, so...

Now, if I remember correctly, there have been attempts at creating this using Dynamic Scripts, but as far as I know they failed - I have no idea why.
I wanted to try too, and got this... it's on "Across the desert", but the script should be versatile enough to work even if copy-pasted on another map.

It seems to be working, but I don't really know which problems to look for...

EDIT: Doesn't work for location 5... investigating.

Re: Fog of War

PostPosted: 22 Sep 2014, 14:52
by Esthlos
Weird, removing the check States.PlayerEnabled from OnTick fixed location 5.
I'm pretty sure I was enabled, though. :?

Re: Fog of War

PostPosted: 22 Sep 2014, 14:54
by Lewin
Firstly, nice work on the script :)
Weird, removing the check States.PlayerEnabled from OnTick fixed location 5.
I'm pretty sure I was enabled, though. :?
That was a typo. You used "P" instead of "I":
if States.PlayerEnabled(P) = TRUE then
In a more powerful compiler it would have given you a warning about P being uninitialized.
*sigh* if only "var aaaAllies: array[0..99] of Boolean;" worked...
It works for me... The only limitation is that you can't set it with:
  Code:
aaaAllies := [FALSE, FALSE, FALSE, ...]
However, global variables are initialised to 0 or FALSE by default anyway, so this is not necessary ;) Even if it was necessary, using a for-loop to set every element to FALSE is very simple.

Also, why not use a 2D array? It will make your code neater since you wouldn't have to use that 10*P+U complication.
  Code:
var aaaAllies: array[0..7] of array[0..7] of Boolean; //And your main loop becomes: for P1 := 0 to 7 do for P2 := 0 to 7 do if aaaAllies[P1][P2] = TRUE then begin
You might find that performance struggles when players have large villages with 100s of units. You could improve performance by processing each player on a different tick (spreading out the load). Replace the outer loop from above (for P1 := 0 to 7 do) with:
P1 := States.GameTime mod 8; //P1 will cycle from 0..7 every 8 ticks

After seeing your script I added a command States.LocationCount which returns the number of locations on the map (even if no player is using them). This should help you because instead of writing:
for P1 := 0 to 7 do
you can write:
for P1 := 0 to States.LocationCount-1 do

Re: Fog of War

PostPosted: 22 Sep 2014, 15:31
by Esthlos
Thank you!
Weird, removing the check States.PlayerEnabled from OnTick fixed location 5.
I'm pretty sure I was enabled, though. :?
That was a typo. You used "P" instead of "I":
:O :$

EDIT: Oooops another typo (pretty much :P ), taking it down.
EDIT2: Fixed... I forgot the -1; it worked anyway because there is a check and the number I was using (as a placeholder) is high enough, but still...

Re: Fog of War

PostPosted: 22 Sep 2014, 17:22
by sado1
I made the previous script, but abandoned it when I saw how little is needed to make FPS go really bad when playing it with others. You can find my script in my maps topic, I think. If you think your script doesn't have performance problems, try it on a fight map with lots of troops, preferably Ambushed. Make sure you test it with more players, eventually you'll find out how bad the performance is for some. Unless something changed and/or your code is different. How does it work? Since I'm at work atm I can't check it out myself.

Re: Fog of War

PostPosted: 22 Sep 2014, 17:29
by Esthlos
I made the previous script, but abandoned it when I saw how little is needed to make FPS go really bad when playing it with others. You can find my script in my maps topic, I think. If you think your script doesn't have performance problems, try it on a fight map with lots of troops, preferably Ambushed. Make sure you test it with more players, eventually you'll find out how bad the performance is for some. Unless something changed and/or your code is different. How does it work? Since I'm at work atm I can't check it out myself.
Found (the link was in your own megathread :P ): viewtopic.php?f=24&t=1655

Looks extremely similar in the way it works... thus this probably suffers from the same problems as yours. :(

Re: Fog of War

PostPosted: 23 Sep 2014, 20:16
by Esthlos
I've been thinking about how to improve the script's performance...
The only solution I've been able to come up with is to spread more the load over Ticks, by dividing the map in 4 zones and "treating" them in different Ticks.

I've tried it in a 1v1 over LAN with 4 AIs enabled in Ambush, but I'm not sure whether there has actually been an improvement or not...

Which function of those used in OnTick is the "heaviest"?

Re: Fog of War

PostPosted: 23 Sep 2014, 20:37
by dicsoupcan
i got no idea about scripting and stuff, but i do happen to know that testing with ai's takes les of a load in games then testing using actual players. if you want some testers just ask, i am sure people are willing to help test.

Re: Fog of War

PostPosted: 24 Sep 2014, 01:50
by Lewin
Because fog is shared between players on the same team you actually only need to run the outer loop once per team, which could help you with performance (and make updates faster) when there are teams. Creating or resizing dynamic arrays/strings is not very efficient, so it's a bad idea to define aaaLimit in OnTick (make it a static array[0..3] of record, set in OnMissionStart).

The slowest part is probably FogRevealCircle because it's used so many times. Iterating through every unit is slow when there are lots of units, but probably unavoidable. Using quadrants is a good idea.

Re: Fog of War

PostPosted: 26 Sep 2014, 13:54
by Esthlos
Because fog is shared between players on the same team you actually only need to run the outer loop once per team, which could help you with performance (and make updates faster) when there are teams. Creating or resizing dynamic arrays/strings is not very efficient, so it's a bad idea to define aaaLimit in OnTick (make it a static array[0..3] of record, set in OnMissionStart).

The slowest part is probably FogRevealCircle because it's used so many times. Iterating through every unit is slow when there are lots of units, but probably unavoidable. Using quadrants is a good idea.
In both the attached files, aaaLimit is now defined once in OnMissionStart (it is now a 2d array, so that the various values can be called directly with the quadrant number; I've googled "record", but I didn't really understand why it would be better than integers in this case :? ). Thank you!

I've attached both a version where the outer loop is team-based and one in which the outer loop is player-based... I'm not really sure whether it is better FPS-wise to have it team-based, but it may be that I didn't write this well.

P.S. Defining a static one dimensional "array[0..3] of Integer" still doesn't work for me... the script is ok according to the validator and the game starts, but the values can't be set, changed, or saved (not sure which one - I only know that every time I tried, the script behaved as if the various values of the array never got set) :(
P.P.S. Two dimensional arrays instead seem to be working fine either way...
i got no idea about scripting and stuff,
Neither do I, what little I know comes directly from Lewin (in the form of links, wiki, tips and suggestions) :P
In any case, thanks for the offer. :D

Re: Fog of War

PostPosted: 27 Sep 2014, 07:02
by Lewin
In both the attached files, aaaLimit is now defined once in OnMissionStart (it is now a 2d array, so that the various values can be called directly with the quadrant number; I've googled "record", but I didn't really understand why it would be better than integers in this case :? ). Thank you!
It makes your code 100x more readable if you use a record rather than an array. You can replace this:
  Code:
var aaaLimit: array[0..3] of array of Integer; //Map quadrant - 0 MinX, 1 MinY, 2 MaxX, 3 MaxY, 4 MultX, 5 MultY, 6 HouseX, 7 HouseY, 8 UnitX, 9 UnitY
with this:
  Code:
var aaaLimit: array[0..3] of record MinX, MinY, MaxX, MaxY: Integer; HouseX, HouseY, UnitX, UnitY: Integer; end;
And instead of obscure code full of magic numbers like this:
  Code:
Actions.FogCoverRect(aaaSquads[U][P], aaaLimit[aaaQuad][0], aaaLimit[aaaQuad][1], aaaLimit[aaaQuad][2], aaaLimit[aaaQuad][3]);
You get much more readable code like this:
  Code:
Actions.FogCoverRect(aaaSquads[U][P], aaaLimit[aaaQuad].MinX, aaaLimit[aaaQuad].MinY, aaaLimit[aaaQuad].MaxX, aaaLimit[aaaQuad].MaxY);
You can't set the record in a single line of code like you do with the array, but 200 lines of readable code is better than 100 lines of unreadable code ;)

Re: Fog of War

PostPosted: 27 Sep 2014, 10:14
by Esthlos
Managed to test both versions (team-based and player-based) of Ambushed - FoW in a 1v1 over LAN, with exactly the same settings both times (x3 speed, 4 AIs, 3v3, one human player in each team, fixed locations).
The weaker of the two machines got:
stable 8 FPS in the player-based version at the start of the game, not camera nor units moved yet for any of the involved players
(became 9 FPS when I moved the Knights around to check if the script was working)

stable 20 FPS in the team-based version at the start of the game, not camera nor units moved yet for any of the involved players
(became 25 FPS when I moved the Knights around to check if the script was working)

So, it seems that there actually is an improvement. Quite a big one, too. :O
It makes your code 100x more readable if you use a record rather than an array.
Oh. That makes sense. :D
You can't set the record in a single line of code like you do with the array, but 200 lines of readable code is better than 100 lines of unreadable code ;)
Can't I keep the 2d array, keep the code that sets it, then code a single line and have LibreOffice Calc use it to write a loop that copies these values onto the array of record? :P :mrgreen: (H) :wink:

Re: Fog of War

PostPosted: 27 Sep 2014, 17:26
by Esthlos
Updated the team-based version of the script to use the new functions of the Release Candidate 3... now the script truly can be copy-pasted in any map and work immediately.

Also, I got over my laziness and properly wrote the lines to define the array of Record... :P

(Actually, I got Libreoffice to do it for me) :P

Re: Fog of War

PostPosted: 04 Oct 2014, 13:11
by Esthlos
Used SetLength here too :P :mrgreen: