![](https://forums.duke4.net/public/style_images/cgs/_custom/switch.png)
EDuke32 Scripting "CON coding help"
#1681 Posted 26 September 2015 - 04:15 AM
Firstly I want to create an equivalent of a sector effector to perform various custom trickery. The issue will be if I implement this as a useractor then it's actor code may not run because it is sleeping (statnum = zombie). So, is there a way of making a never-sleeps useractor ?
I notice there are events 'EVENT_GAME' or 'EVENT PREGAME' which fire for each actor per game tic, but it is not clear whether these will still run for zombie actors. If there was an EVENT_TIC (which there isn't) then I guess I could use it to force my custom sprite's statnum back to 1 (awake) and I might be able to infer my hypothetical EVENT_TIC using some logic in EVENT_GAME, but this is all sounding rather wasteful of CPU cycles as well as messy.
Or .. is there another better way to implement this?
Secondly, as part of said trickery, how do I detect when a 'channel' fires (e.g. from switch, touchplate, etc) ? It would be jolly useful if there was a game event that signalled this but I can't see one. For switches I could iterate through all sprites (or a subset based on statnum) looking for appropriately tagged switches and get their state from picnum but that feels like it could add a lot of processor overhead if I did it on every game tic.
Finally it would be nice if my custom sector effector would allow me to utilise the lotag for my own purposes but currently if this is non-zero then my custom sector effector is deleted in game, presumably 'cos the lotag is being interpretted as multiplayer only or something (or is it skill level ? I forget). Whatever is there a way around this behaviour?
[Edit] Ah-ha ! Saving the lotag in a gamevar during eventloadactor and then setting lotag 0 fixes that last issue.
TTFN,
Jon
This post has been edited by The Mechanic: 26 September 2015 - 04:28 AM
#1682 Posted 27 September 2015 - 03:23 AM
This post has been edited by December Man: 27 September 2015 - 03:24 AM
#1683 Posted 27 September 2015 - 06:46 AM
#1684 Posted 27 September 2015 - 09:15 AM
#1685 Posted 30 September 2015 - 07:36 AM
First is that Lizman's Copy size ingame is huge. I know that I gotta put this code, but I don't know where.
{ sizeat 42 40 cstator 257 }
And also them Lizman's copies seem to attack immediately even when the player is not seen.
#1687 Posted 30 September 2015 - 11:05 AM
This post has been edited by Mark.: 30 September 2015 - 11:07 AM
#1688 Posted 30 September 2015 - 01:02 PM
Jenz/Amaka, on 30 September 2015 - 07:36 AM, said:
First is that Lizman's Copy size ingame is huge. I know that I gotta put this code, but I don't know where.
{ sizeat 42 40 cstator 257 }
And also them Lizman's copies seem to attack immediately even when the player is not seen.
That's because some enemies are hard-coded. In other words, part of the code is written directly in the executable.
Add this somewhere in the CON (obviously not using the LIZMAN tile):
appendevent EVENT_LOADACTOR switch sprite[THISACTOR].picnum case LIZMAN case LIZMANSTAYPUT case LIZMANSPITTING case LIZMANJUMP sizeat 40 40 clipdist 80 cstator 257 break endswitch endevent
Find these parts:
actor LIZMANSTAYPUT LIZSTRENGTH ai AILIZGETENEMY cactor LIZMAN enda
actor LIZMANSPITTING LIZSTRENGTH ai AILIZSPIT cactor LIZMAN enda
actor LIZMANJUMP LIZSTRENGTH ai AILIZJUMPENEMY cactor LIZMAN enda
actor LIZMAN LIZSTRENGTH
Replace with:
useractor enemy LIZMANSTAYPUT LIZSTRENGTH ai AILIZGETENEMY cactor LIZMAN enda
useractor enemy LIZMANSPITTING LIZSTRENGTH ai AILIZSPIT cactor LIZMAN enda
useractor enemy LIZMANJUMP LIZSTRENGTH ai AILIZJUMPENEMY cactor LIZMAN enda
useractor enemy LIZMAN LIZSTRENGTH
This post has been edited by Fox: 01 October 2015 - 01:36 AM
#1689 Posted 01 October 2015 - 01:20 AM
Fox, on 30 September 2015 - 01:02 PM, said:
Add this somewhere in the CON (obviously not using the LIZMAN tile):
appendevent EVENT_LOADACTOR switch sprite[THISACTOR].picnum case LIZMAN case LIZMANSTAYPUT case LIZMANSPITTING case LIZMANJUMP sizeat 40 40 clipdist 80 cstator 257 break endswitch
I tried adding that code. I tried at the start of .con, end, different .con, and they all give same errors.
DS_GAME.CON: In event `EVENT_LOADACTOR': DS_GAME.CON:33: error: parameter `ANULLACTION' is undefined. DS_GAME.CON:33: error: expected a keyword but found `0'. Found 0 warning(s), 2 error(s).
#1691 Posted 01 October 2015 - 01:37 AM
action ANULLACTION 0
nvm
This post has been edited by Daedolon: 01 October 2015 - 01:37 AM
#1692 Posted 01 October 2015 - 05:54 AM
Fox, on 01 October 2015 - 01:36 AM, said:
That did it! Many thanks, Fox!
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
#1693 Posted 02 October 2015 - 11:22 AM
Also, if I may, a repeat of previous question - how do I detect an activator firing from within CON code ? Possible ? Not possible ?
TTFN,
Jon
#1694 Posted 02 October 2015 - 01:22 PM
The Mechanic, on 02 October 2015 - 11:22 AM, said:
I'm not entirely sure what you are asking, but you might be saying that when you spawn an enemy, the max number of kills in the map does not get increased. If that's the case, then you can fix that by reading/writing the following:
http://wiki.eduke32....x_actors_killed
The Mechanic, on 02 October 2015 - 11:22 AM, said:
You can try this command:
http://wiki.eduke32....activatormotion
IIRC it only works in certain contexts. I ended up making my own special activators by looping through sprites and changing, checking per-actor gamevars.
#1695 Posted 02 October 2015 - 11:40 PM
Trooper Dan, on 02 October 2015 - 01:22 PM, said:
http://wiki.eduke32....x_actors_killed
D'oh !
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
Anyhow, when I detect a player triggering one of my respawns alls I'll know is the player's THISACTOR value. How would I convert this to the relevent index into the player structures ? Or is the script system smart enough such that getplayer[THISACTOR] will re-interpret THISACTOR for me ? Or should I just ignore multiplayer and use getplayer[0] ? (I don't play multiplayer and I'm sure I read somewhere that current Eduke versions aren't multiplayer anyway?).
Trooper Dan, on 02 October 2015 - 01:22 PM, said:
http://wiki.eduke32....activatormotion
IIRC it only works in certain contexts. I ended up making my own special activators by looping through sprites and changing, checking per-actor gamevars.
I couldn't see how to use checkactivatormotion. At the moment I've implemented what you have done, my own activator system and grouping sprites as a chains of groups of sprites (debugging a linked list of linked lists in a primitive script language and no debugging tools nearly did for what little is left of my sanity!). Unfortunately it does mean I need helper sectors (e.g. a door) to translate a standard activator to jonz system, which is a nuiscence.
Can you provide any further info on the contexts in which Checkactivatormotion works ?
Currently my main game loop looks like this:
gamevar ticky 0 0 gamevar startupdebug 1 0 // Called once per "tic" _per_ _actor_. Not clear if this gets called for actors that the // game has decided are temporarily zombied ? Jonz sprites are not useractors so maybe // will never be zombied ?? onevent EVENT_GAME ifvarn startupdebug 0 { ... dump some debug stuff setvar startupdebug 0 } // Fudge: There is no event that runs once per tick so we need to infer one. // Ticks are roughly in milliseconds. This is NOT accurate for multiplayer // and game should never sync to this for multiplayer. TODO: Use what else? getticks temp1 setvarvar temp2 temp1 subvarvar temp2 ticky ifvarg temp2 33 // Roughly 30 times per second. Ish. { setvarvar ticky temp1 // Process jonz main sprite system // This is more efficient this way otherwise I'd be searching chains of // groups of sprites for every actor on every tick. What I need is an EVENT_GAME // that runs once per game tic but there isn't one ? state process_allsectormonitors state update_sectorchangers //state move_sprite_groups TODO // TODO : revise this if how sounds are played is influenced by THISACTOR state update_jsounds } // These effects may spawn objects so will only work if THISACTOR is correctly set. state update_alljeffects state update_alljrespawns endevent
It has happened this way because I'm not confident about when, or what happens, should my sprites get marked by Eduke as zombied because the player hasn't seen them in a while (however they are _not_ useractors). Also unless I've missed something there is no event that fires once per game tick - plus I dont know the interval of a game tick.
TTFN,
Jon
#1696 Posted 03 October 2015 - 12:22 AM
The Mechanic, on 02 October 2015 - 11:40 PM, said:
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
If you want RESPAWNs to continue working after being activated, use this:
appendevent EVENT_KILLIT ifactor RESPAWN { setvar RETURN -1 setactor[THISACTOR].extra 0 } endevent
The Mechanic, on 02 October 2015 - 11:40 PM, said:
Yes, it will re-interpret THISACTOR. If you use it for getactor, THISACTOR returns the current actor ID, for getplayer it will be the nearest player ID, and for getsector it will be the current actor sector ID.
It's tricky, but in multiplayer you would have to change the value of max_actors_killed for all players...
The Mechanic, on 02 October 2015 - 11:40 PM, said:
[...]
It has happened this way because I'm not confident about when, or what happens, should my sprites get marked by Eduke as zombied because the player hasn't seen them in a while (however they are _not_ useractors). Also unless I've missed something there is no event that fires once per game tick - plus I dont know the interval of a game tick.
TTFN,
Jon
Not sure where you are getting with this. First of all, EVENT_GAME runs every tic for all existing sprites in the map, including sleeping (zombie) actors. So a global gamevar would be overwritten.
If you want to prevent an actor from ever sleeping, I believe this would work:
onevent EVENT_GAME ifactor MYACTOR setactor[THISACTOR].httimetosleep 0 endevent
This post has been edited by Fox: 03 October 2015 - 12:22 AM
#1697 Posted 03 October 2015 - 01:47 AM
Fox, on 03 October 2015 - 12:22 AM, said:
I did enquire about how to achieve what I'm trying to do in previous threads when I was at the planning stage, this so far has been the only way I've been able to move forward.
I have sprites grouped into functional groups as sprites within a group interact with each other, with one sprite within that group acting as a master. When I wrote that piece of code you need to bear in mind that I couldn't get an answer on whether EVENT_GAME would still get called for sleeping sprites so this was the only way I could see to absolutely gaurentee my sprites would get processed. A gaurentee that EVENT_GAME is _always_ called for every sprite will certainly make my life easier.
Fox, on 03 October 2015 - 12:22 AM, said:
appendevent EVENT_KILLIT ifactor RESPAWN { setvar RETURN -1 setactor[THISACTOR].extra 0 } endevent
If a RESPAWN has never respawned during a game then that should be counted as one enemy the player failed to kill. After the first respawn, it does _not_ count as a missed enemy unless it has actually spawned another enemy. I doubt that logic is built into the game.
Hello, what is the actor's 'extra' doing that requires it to be set to 0 ?
Fox, on 03 October 2015 - 12:22 AM, said:
Just to clarify, are you saying that:
getactor[THISACTOR].sectnum temp getsector[temp].somethingorother ....
can actually be done with
getsector[THISACTOR].somethingorother ...
That'd be useful.
Fox, on 03 October 2015 - 12:22 AM, said:
Indeed, I'm hoping that using extspritestat and specifying STAT_PLAYER will iterate through each player, though I'm not sure if the sprite values returned by that function will be valid in accessing the player-specifc sprite vars. Gonna just have to suck it and see.
Fox, on 03 October 2015 - 12:22 AM, said:
This was the vital answer that I hadn't been able to find stated explicitly. When I sketched out the game loop I posted I did not have that as a gaurentee, hence implementing things the way I did.
Fox, on 03 October 2015 - 12:22 AM, said:
onevent EVENT_GAME ifactor MYACTOR setactor[THISACTOR].httimetosleep 0 endevent
Ah, I'd been using this wiki page which didn't mention httimetosleep. After a search, it is listed in this page which shows even more interesting looking stuff. What's going on ? Is the first page a general sprite structure, and the second page adds gamevars that are also applicable to sprites defined as (user)actors? i.e. setactor[THISACTOR].httimetosleep will work for a (user)actor but blow up if I tried to use it on a regular every day decorative sprite ?
TTFN,
Jon
PS: I want 'ifsoundvar' but it doesn't exist. Is there an alternative ? Currently I've a 450 line monster func to attempt this functionality - yeuk! - IIRC, the first time I've used a spreadsheet to generate code !
#1698 Posted 03 October 2015 - 02:14 AM
The Mechanic, on 03 October 2015 - 01:47 AM, said:
I had written a code for that some time ago, as far I remember the results were very precise. I may take a look at it again...
The Mechanic, on 03 October 2015 - 01:47 AM, said:
It's used by the game to make RESPAWNs work. Not my fault.
The Mechanic, on 03 October 2015 - 01:47 AM, said:
getactor[THISACTOR].sectnum temp getsector[temp].somethingorother ....
can actually be done with
getsector[THISACTOR].somethingorother ...
That'd be useful.
Correct.
The Mechanic, on 03 October 2015 - 01:47 AM, said:
In this case, you wouldn't loop through the player actors, but the player IDs.
setvar temp 0 whilevarvarn temp MULTIMODE { getplayer[temp].max_actors_killed temp2 addvar temp2 1 setplayer[temp].max_actors_killed temp2 addvar temp 1 }
The Mechanic, on 03 October 2015 - 01:47 AM, said:
Being even more explicit, note that I said sprites, not actors, because EVENT_GAME also run through decorative sprites or projectiles.
The Mechanic, on 03 October 2015 - 01:47 AM, said:
These pages are redundant. In a website running on a wiki software you define categories for pages, which serve merely for an organizational purpose. However EDukeWiki has its own page for structures, which are preferable.
These structures exist for all sorts of sprites.
The Mechanic, on 03 October 2015 - 01:47 AM, said:
Indeed, that command doesn't appear to exist. Don't forget ifsound is unsynchronized, so be careful!
This post has been edited by Fox: 03 October 2015 - 02:14 AM
#1699 Posted 03 October 2015 - 02:50 AM
#1700 Posted 03 October 2015 - 04:57 AM
Fox, on 03 October 2015 - 02:14 AM, said:
setvar temp 0 whilevarvarn temp MULTIMODE { getplayer[temp].max_actors_killed temp2 addvar temp2 1 setplayer[temp].max_actors_killed temp2 addvar temp 1 }
Ah-ha, so the mysterious MULTIMODE is in fact the number of players. (Does a bit more delving) should that be numplayers as that doesn't include bot players? (for the original purposes of kill count I doubt it makes any difference, but I'm thinking more generally).
Fox, on 03 October 2015 - 02:14 AM, said:
Do you mean unsynchronised between multiple players ? Or something worse ?
The reason I'm using my "ifsoundvar" is only to enable playing one sound effect after another finishes (I've given up doing this with door sectors as duke's door-generated sounds are bloody unpredictable at best), or loop a sound (save building elevator help sectors - that really was a neat trick). I'm not using the end of a sound to do anything more than that so should I get away with it ?
If my object spawns a sound - 71, say - and whilst that is playing some other game event also starts a sound 71 then yes my object will be waiting for the second one to finish, but that is a minor limitation of my system. In practice the sounds spawned by my object are likely to not crop up at the same time elsewhere.
Jblade, on 03 October 2015 - 02:50 AM, said:
By accident yes. (Indeed, 75% of errors I make are 'cos I forget the additioanl 'var' on the end of funcs).
There is 'sound' for playing a fixed sound, 'soundvar' for sounds based on a variable, 'ifsound' to check for a fixed sound and .... (drum roll) ... no fricken 'ifsoundvar'
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
TTFN,
Jon
This post has been edited by The Mechanic: 03 October 2015 - 05:03 AM
#1701 Posted 03 October 2015 - 05:26 AM
This post has been edited by Mark.: 03 October 2015 - 05:57 AM
#1702 Posted 03 October 2015 - 07:29 AM
Mark., on 03 October 2015 - 05:26 AM, said:
Because I'm creating a re-usable library - think extended/improved version of sector effectors and such. The sound system is also a lot more than only stitching sounds together.
I agree if I were only working on a specific map then, yes, simply whip out CoolEdit Pro or Audacity and stitch the necessary sounds together, job done.
TTFN,
Jon
#1703 Posted 03 October 2015 - 07:44 AM
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
#1704 Posted 03 October 2015 - 02:17 PM
The Mechanic, on 03 October 2015 - 04:57 AM, said:
Yeah. It's okay to use ifsound to check if a sound should be played. But, for example, sounds are never played if you have sounds off in the menu, so anything that affects the game would break the sync in multiplayer.
#1705 Posted 05 October 2015 - 10:40 AM
I desperately need an explanation of what is going on with sprite indexes as seen in a CON file and actual sprite numbers I see in mapster and how they might change.
Example: using headspritesect + nextspritesect, during a particular EVENT_LOADACTOR, I'm iterating round some sprites in a sector. In my test map I get three sprites (223,220,208). Fine. I have this:
gamevar myvar -1 2 // Per actor
I use myvar to keep a reference to the next sprite - a linked list. So, 223 has myvar=220, 220 has myvar=208 and 208 has myvar=-1 cos its the last one.
When the game is running, my CON file access sprite 223 only to find it's myvar is now -1 !?!? Wtf !?!? . So, just for a test, I also wrote the myvar values into each sprite's xvel,yvel and zvel (just to be thorough) and used DNDEBUG to dump a map and see what the hell is going on. Well, the three sprites in the sector all have xvel,yvel and zvel as I'd expected - only the the sprite numbers are different - according to mapster, they are sprites 219, 216 and 204. In effect, they've been moved down by 4. I've noticed these sprites get set an "owner", e.g. sprite 219 has an owner of 223 and so forth.
Purely for test purposes I subtracted 4 from the myvar values. As expected I now accessed the correct sprite number - 219 instead or 223 - and (....drum roll...) the sodding value of myvar was still -1
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
I've clearly missed something fundamental - but what ? How _should_ I be keeping a reference to specific sprites ? Could something happen during the game that could cause sprite numbers to re-arrange yet again ? Or can I assume that prior to the first EVENT_GAME sprite data moves around but once the first EVENT_GAME occurs the sprite data finally stays put ?
TTFN,
Jon
#1706 Posted 05 October 2015 - 12:12 PM
Why are you doing the iteration in LOADACTOR?
What's your goal?
Did you remember to use s/getactorvar[actorid].myvar ?
If the sprites are being spawned at any point (beyond initial load) the IDs can definitely change. Nothing to do with CON, it's the engine itself.
#1707 Posted 05 October 2015 - 12:48 PM
Mblackwell, on 05 October 2015 - 12:12 PM, said:
Why are you doing the iteration in LOADACTOR?
What's your goal?
Did you remember to use s/getactorvar[actorid].myvar ?
If the sprites are being spawned at any point (beyond initial load) the IDs can definitely change. Nothing to do with CON, it's the engine itself.
I'm grouping sprites together during initialisation so I can subsequently manipulate them as group of sprites.
As an example, I've a custom "locator" sprite which get grouped together (via hitag) in a user defined order (lotag) in order to define a path, imagine the overhead of sorting that little lot on every game tic. Then there is grouping regular sprites - such as a platform made of regular sprites - which are linked together in a group and follow a path defined by those locators. Pretty much impossible if the sprite indexes keep moving around.
If I can't reliably identify the exact same sprite on different game tics then that pretty much destroys a lot of what I'm wanting to achieve
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
TTFN,
Jon
#1708 Posted 05 October 2015 - 04:23 PM
#1709 Posted 05 October 2015 - 07:08 PM
A couple of better bets might be:
1) Use custom statnums and headspritestat. (This is great for random stuff)
2) A better method still for LOCATOR type things would probably be to create arrays with offsets. To do it of course you'll need to figure out the max/how many points you want in each path. The hitag would be ordered rather than a random unique number. Each mylocator would simply have to insert its sprite id at position mylotag*MAXPOINTS+myhitag in the array. So for 30 separate paths with 30 different points you'd need an array size of 930 (actually you'd get 31 paths I think due to path 0 but I'm not going to do the math atm). Then individual actors just need to traverse their assigned set of mylocators.
#1710 Posted 06 October 2015 - 01:21 AM
Fox, on 05 October 2015 - 04:23 PM, said:
No. The hitag is used as the "channel" that marks an actor as part of that group. The idea was during initialisation this would be used to set up linked list pointers (implemented as per-actor gamevars). Where sorting was needed that was done via lotag. Advantages:
1) After initialisation, lotag and hitag are redundant
2) When I fire an activation (a jonz version at this point in time) I just scoot across the first sprites in the group and flag that they've been activated and need to do something when it is their turn.
3) When moving a group of sprites they absolutely have to move at exactly the same time and not wait for their respective EVENT_GAME calls else they will flicker. A linked list of exactly the ones to move is quick and simple.
All in all a brilliant plan - right up to the point where ID's change
![:D](https://forums.duke4.net/public/style_emoticons/default/sad.gif)
The effects are totally configured via standard mapster, so primarily they need configuring via lotag/hitag, 'extra' if I need a bit more, and so on (I've a csutom mapster with a menu system which will simplify this setup, but the effects will always be configurable via standard mapster). Part of initialisation is to stash these values and if necessary reset them. With very few exceptions, I leave standard sprite array data well alone after initialisation.
Mblackwell, on 05 October 2015 - 07:08 PM, said:
Indeed. Other than borrowing a few flags in cstat (which has some debugging advantages) I'm avoiding reusing standard sprite variables.
Mblackwell, on 05 October 2015 - 07:08 PM, said:
1) Use custom statnums and headspritestat. (This is great for random stuff)
I didn't think I could use statnum (wiki page) as I infered it might change in, or influence, the game operation.
"Unassigned status numbers are reserved for future EDuke32 features. Please ask the developers to allocate an official user statnum range for CON-side features, should this be desired." You start the petition to allocate statnum > 1024 for user defined use whilst I print the campaign t-shirts and mugs
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
Mblackwell, on 05 October 2015 - 07:08 PM, said:
Do you mean that, using my previous example sprites {223,220,208}, their ID's may move but their relative ID's will always be the same e.g. {222,219,207}, or {23,20,08} etc ? Otherwise I don't see how an array will help.
Mblackwell, on 05 October 2015 - 07:08 PM, said:
But the ID changes and its been suggested this isn't just on completion of initialisation but also if during the game something is spawned.
Mblackwell, on 05 October 2015 - 07:08 PM, said:
Again, how do they find their associated locators as the ID's of these locators may change?
AH! (lightbulb finally flickers into life), maybe I've just seen where you were going. Assign each group a unique statnum value and use this as the linking mechanism e.g. sprites with statnum 1025 follow the path of locators statnum 1234. I'll take a peek in the code for the size of statnum - if I'm _real_ lucky I could simply use statnum = 1024 + original hitag value. No need for any extra tables at all. Mblackwell, I owe you one.
![:)](https://forums.duke4.net/public/style_emoticons/default/smile.gif)
Right, off to re-write half me darn code
![:)](https://forums.duke4.net/public/style_emoticons/default/dukecry.gif)
TTFN,
Jon
[Edit] Sprites that are blocking, hitable and have hitag (=>destructable) have their statnums set to 17 so above method for grouping needs to be to iterate all sprites with matching statnums AND all sprites with satnum 17 and matching hitag. Given I'm not interacting with enemies,players,weapons,projectiles and so forth- only inanimate objects - additional checking for statnum 17's is the only extra effort I need. I hope.
This post has been edited by The Mechanic: 06 October 2015 - 02:30 AM