Page 18 of 26

Re: Dynamic Script Usage

PostPosted: 16 Aug 2013, 15:24
by Shadaoe
Another example what dynamic scipting can do! The GIF below shows an accelerated minimap (about 15 minutes). Does anyone notice anything unusual? ;)

Image
Nice work, exploding vagabonds, now this, what's next ? :P

Re: Dynamic Script Usage

PostPosted: 16 Aug 2013, 22:17
by Lewin
QUESTION 1
I'm experimenting with custom sounds now, specifically the PlayWAVAtLocation. It says that only mono sounds are supported. However, stereo works just fine, although it is not projected on the left or right channel. Mono sounds are projected left or right, but they are extremely low in volume. I've tried if the volume parameter (0.0 - 1.0) was maybe to 100 but that doesn't work either. Setting different sample rates (22.500 or 44.100 hertz) or bit depths (8 or 16 bit) has no influence as well.

How can I increase the volume of these mono sounds? Currently they are just not loud enough, so I am forced to use a stereo sound. But then I loose the left-right projection. The sound I have is normalized to about 0.0 dB (maximum volume before clipping).
Only mono sounds can be played at a position on the map, this is an OpenAL limitation, which makes sense when you think about it: if you wanted stereo you could place two sounds next to each other with a small gap (otherwise how does it know how far apart the channels should be?)

The volume gets reduced a bit for sounds that are positioned on the map, because the OpenAL listener is a small distance away from it (non-positional sounds are played right in the listener's ears). But all KaM positional sounds have this limitation and they're loud enough, so maybe you can increase the volume of the WAV further? (there are ways to increase the volume without making clipping sound bad). Take a look at the KaM WAV files and see how they did it (Export Data -> Resources -> Sounds, then look in your export folder)

The volume range you can use at the moment is 0.0 - 1.0. We could increase the upper limit for positional sounds I guess since their volume is reduced. I added it to the suggestions list.
QUESTION 2
Suppose a multiplayer setting of team 1 = player 1-4, and team 2 = player 5-8. If I use FogCoverCircle or FogRevealCircle to change the fog for player 1, and PlayerShareFog(player1, player 2-4) = true (which is the default setting I believe), is the fog for player 2, 3 and 4 automatically updated?
FogCoverCircle and FogRevealCircle will always only effect the specified player. PlayerShareFog only effects things out of your control like units exploring. You can write your own FogRevealCircleForAll if you want to.
QUESTION 3
Posed earlier: is there a way to remove or kill animals?
It should, but it looks like there's a bug causing it not to work at the moment. I'll add it to the bugs list.

Re: Dynamic Script Usage

PostPosted: 17 Aug 2013, 00:11
by Tef
Only mono sounds can be played at a position on the map, this is an OpenAL limitation, which makes sense when you think about it: if you wanted stereo you could place two sounds next to each other with a small gap (otherwise how does it know how far apart the channels should be?)
Here, it plays stereo sounds just fine. They're just always perfectly centered, not panned left or right.
The volume gets reduced a bit for sounds that are positioned on the map, because the OpenAL listener is a small distance away from it (non-positional sounds are played right in the listener's ears). But all KaM positional sounds have this limitation and they're loud enough, so maybe you can increase the volume of the WAV further?
Ok, I did. Left is the dying knight. Right is my sound. My sound is MUCH louder (RMS level is -13.5 dB) than the original dying knight sound (RMS level is -17.5 dB). Visual inspection of both sounds also shows my sound is louder. Both sounds are 22.500 hertz, 8 bit, mono. I checked my script the volume parameter is 1.0. So you would expect it to be clearly audible in the game. However, if I play, my sound is much less loud than the dying knight. I checked if moving the screen to left, right, top, down would help: no result.

Image

Possible conclusions:
- Kam Remake handles custom sounds different than the standard sounds, causing them to loose volume.
- my soundcard is playing games with me.
- I am totally retarded.

Re: Dynamic Script Usage

PostPosted: 17 Aug 2013, 00:25
by Lewin
I just checked the source code, it turns out that death sounds play at volume 4.0 (but the max you can use from the script is 1.0). We'll unlock this for the next release because as you've found positional sounds need to be boosted. Thanks for your help :)

Re: Dynamic Script Usage

PostPosted: 17 Aug 2013, 15:38
by dicsoupcan
I just checked the source code, it turns out that death sounds play at volume 4.0 (but the max you can use from the script is 1.0). We'll unlock this for the next release because as you've found positional sounds need to be boosted. Thanks for your help :)
Maybe it is wise to still set a maximum because otherwise you might end up getting super loud sounds.

Re: Dynamic Script Usage

PostPosted: 17 Aug 2013, 16:11
by pawel95
Maybe it is wise to still set a maximum because otherwise you might end up getting super loud sounds.
Or even troll sounds with like horrible volumne XD Good point.

Re: Dynamic Script Usage

PostPosted: 17 Aug 2013, 16:13
by Krom
We could limit max volume to 4.0 - that's the max we use iirc.

Re: Dynamic Script Usage

PostPosted: 18 Aug 2013, 13:15
by Tef
Is there a way to play the death animation without the sound?

I am now using 'antisound' to achieve a comparable effect, which works pretty well, actually! :D It removes or greatly reduces the sound about 75% of the times. -> I've copied the waveform, inverted it, and I am playing it 4 times to overcome the 4.0 multiplier of original sounds.

Re: Dynamic Script Usage

PostPosted: 18 Aug 2013, 18:04
by Krom
@Tef: Yeah, I think we could add that. Clever solution, btw ;)

Re: Dynamic Script Usage

PostPosted: 19 Aug 2013, 18:48
by Islar
Hi

I think dynamic script is very hard for my to use and i do not understand most thinks. :$

I want to know how i can do this:
A player builds for example a couple of schools on (for my) unknown places. When a school is finished it will get gold. I want to know when a school have more than 4 gold in it.

I think i can use playergetallhouses in some way(?) But more than that i don't understand. :(

Can someone help my with this?

Re: Dynamic Script Usage

PostPosted: 19 Aug 2013, 20:59
by Tef
Hi Islar, I'm not sure in what context you are going to use this. For simplicity, I assume you do this for single player and you are player 1. You want to know things about schools from player 2, 3 and 4. Gold comes into the schools the normal way To make your script easy to read, define some global constants first:
  Code:
const SCHOOL = 13; GOLD = 7; PLAYER_2 = 1; PLAYER_4 = 3;
Now we need to make some sort of thing that checks the schools. We create a new procedure for that. In that procedure we need to ask:
- how many buildings do player 2-4 actually have?
- which of those are schools?
- how much gold does each school have?
- do something if there is more than 4 gold in it
Below is a procedure example that does this.
  Code:
Procedure CheckSchools; var PlayerWalker, HouseArray, HouseWalker, ThisSchool: integer; begin for PlayerWalker := PLAYER_2 to PLAYER_4 do begin // go through player 2, 3 and 4 HouseArray := States.PlayerGetAllHouses(PlayerWalker); // store all the houses of the player into HouseArray for Housewalker := 0 to length(HouseArray) -1) //go through all houses in HouseArray if States.HouseType(HouseArray[HouseWalker]) = SCHOOL then begin // check if the housetype is a school ThisSchool := States.HouseArray[HouseWalker]; //store the school id into ThisSchool. Not necessary btw, you could also put this in the next line directly. if States.HouseResourceAmount(ThisSchool, GOLD) >= 5 then begin // you asked for more than 4, but I made more or equal than 5 of it :-) // FANCY STUFF HERE! end; end; end; end; end;
Finally, you only need to decide how often you want to check the schools and put it into OnTick. In the example below it is once every 2 seconds.
  Code:
Procedure OnTick; begin if States.GameTime mod 20 = 0 then CheckSchools; end;
I haven't tested the code examples above, but that's the general idea. Good luck! Note this is just one possible example!

Re: Dynamic Script Usage

PostPosted: 19 Aug 2013, 23:13
by Tef
Nice work, exploding vagabonds, now this, what's next ? :P
Oh, so much more! (H) (H) (H) This and that are two examples of other (already finished) dynamic scripting stuff :) I hope Ben is starting to get ready because I'm currently putting it al in here!

Re: Dynamic Script Usage

PostPosted: 20 Aug 2013, 12:28
by Tef
2 BUGS:

1- if I put a corn field on some tile, both IsFieldAt and IsWineFieldAt return false
2- if I put a wine field on some tile, both IsFieldAt and IsWineFieldAt return true

Hehe...did you first make IsWineFieldAt and later copied that code for IsFieldAt, Lewin? Guess you forget to update some parameter to make IsFieldAt respond to corn fields instead of winefields, right? ;)

Re: Dynamic Script Usage

PostPosted: 20 Aug 2013, 13:03
by Islar
Hi Islar, I'm not sure in what context you are going to use this. For simplicity, I assume you do this for single player and you are player 1. You want to know things about schools from player 2, 3 and 4. Gold comes into the schools the normal way To make your script easy to read, define some global constants first:
  Code:
const SCHOOL = 13; GOLD = 7; PLAYER_2 = 1; PLAYER_4 = 3;
Now we need to make some sort of thing that checks the schools. We create a new procedure for that. In that procedure we need to ask:
- how many buildings do player 2-4 actually have?
- which of those are schools?
- how much gold does each school have?
- do something if there is more than 4 gold in it
Below is a procedure example that does this.
  Code:
Procedure CheckSchools; var PlayerWalker, HouseArray, HouseWalker, ThisSchool: integer; begin for PlayerWalker := PLAYER_2 to PLAYER_4 do begin // go through player 2, 3 and 4 HouseArray := States.PlayerGetAllHouses(PlayerWalker); // store all the houses of the player into HouseArray for Housewalker := 0 to length(HouseArray) -1) //go through all houses in HouseArray if States.HouseType(HouseArray[HouseWalker]) = SCHOOL then begin // check if the housetype is a school ThisSchool := States.HouseArray[HouseWalker]; //store the school id into ThisSchool. Not necessary btw, you could also put this in the next line directly. if States.HouseResourceAmount(ThisSchool, GOLD) >= 5 then begin // you asked for more than 4, but I made more or equal than 5 of it :-) // FANCY STUFF HERE! end; end; end; end; end;
Finally, you only need to decide how often you want to check the schools and put it into OnTick. In the example below it is once every 2 seconds.
  Code:
Procedure OnTick; begin if States.GameTime mod 20 = 0 then CheckSchools; end;
I haven't tested the code examples above, but that's the general idea. Good luck! Note this is just one possible example!
Hey Tef, I really appreciate you help my with this. I tried this out but i get some Typ mismatch errors. Maybe you know more?

Re: Dynamic Script Usage

PostPosted: 20 Aug 2013, 14:52
by Lewin
2 BUGS:

1- if I put a corn field on some tile, both IsFieldAt and IsWineFieldAt return false
2- if I put a wine field on some tile, both IsFieldAt and IsWineFieldAt return true

Hehe...did you first make IsWineFieldAt and later copied that code for IsFieldAt, Lewin? Guess you forget to update some parameter to make IsFieldAt respond to corn fields instead of winefields, right? ;)
You're quite right, that looks like a copy paste bug. I fixed it, thanks for reporting!