It's high time to propose to the community (still active of course!), useful tutorials, in order to add them in the Eduke32 wiki, or simply to help the other creators of mods, TC or simple maps.
Since the creation of my mod (still unfinished but still in the works lol), that is since the year 2017, I took quite a lot of remarks and critics, in order to make me really understand the coding and script.
They weren't wrong of course, the community helped me in their own way. A way to make me progress more without giving up.
Now that I've learned to be autonomous and to manage a lot of things (most of them minor), I managed to make a relatively clean and functional coding.
By looking at a lot of existing mods, I was able to learn more about commands, gamevars and structures in general.
Now that everything is clear, I will start with the first tutorial:
----NEW KEYCARD CREATIONS----
Before presenting the script here, I want to mention the source of the code itself, as well as the credits for the mods used.
(1). the first code concerning new keymaps, comes from the mod "Nuclear Showdown", created by James Stanfield and originally released August 3, 2007.
- the animation was quite slow, very few frames were used and the player was not blocked at all during the animation (no lockplayer).
(2). the second code comes from the mod "Naferia's Reign: Invasion of the Dark Mistress", created by MisfitTech Studios, developers of "The Misfits" and originally released 2007.
- the code is in the end very similar to the final coding, but use a lot of variables and quite complicated structures. Moreover, it was complicated with "EVENT_DISPLAYREST" to correctly associate the color (pal) for the animation.
Conclusion, I merged the two scripts and improved the whole thing so that it is really as faithful as possible to the original animation.
----STEP 01----
We will first add the basic definitions to make a new keycard sprite:
define NEWACCESSCARD 14 // new keycard sprite define NEWACCESSSWITCH1 15 // new access switch #1 define NEWACCESSSWITCH2 17 // new access switch #2 define HANDHOLDINGACCESS2 19 // animation sprite of Duke's hand holding the key card
The definition numbers are an example. Use any empty slots. The examples are of course based on the original sprites: TILES #60, #130-131, #170-171 and #2568.
Then, two actions and the special message for the switchs:
action ACCESSOFF 0 action ACCESSON 0 definequote 130 ^8GREEN ACCESS CARD REQUIRED
The number 130 of the message is also an example.
[^#] can be used to change the color of all of, or just a section of a quote. The # is the palette number intended for use. Example:
definequote ^12PICKED UP A PORTABLE MEDKIT definequote ^16BLUE ^0ACCESS CARD REQUIRED
thank you very much Eduke32 wiki !!!
and finally, the gamevars:
// new access card item vars gamevar access_key1 0 1 gamevar access_quote 0 2 gamevar ckeycard_pal 0 0 gamevar ckeycard_picnum 0 0 gamevar customkeycard_pos 0 0 // new access switchs vars gamevar hitag_saved 0 2 gamevar lotag_saved 0 2 gamevar zero_switch 0 0 // check switch / force fields global vars gamevar access_temp 0 2 gamevar access_temp2 0 2 gamevar access_temp3 0 2 gamevar access_temp4 0 2 // force fields vars (with new switch used) gamevar forcefields_temp 0 2 gamevar forcefields_temp2 0 2 gamevar hitwalls 0 131073 // the wall that gets hit by the hitscan gamevar misc_array -1 131072 gamevar misc_array_amount 0 132098 gamevar misc_array_amount_temp 0 131072 gamevar wall_array 0 10
----STEP 02----
************************
NEW KEYCARD - METHOD #01
************************
Now you will create a new actor for the new keycard like this:
useractor notenemy NEWACCESSCARD fall sizeat 32 32 ifmove RESPAWN_ACTOR_FLAG state respawnit else ifp pshrunk nullop else ifp palive ifpdistl RETRIEVEDISTANCE ifcount 6 ifcanseetarget { ifspritepal 22 { ifvarand access_key1 1 break else { addvar access_key1 1 } redefinequote 43 ^8GREEN ^0ACCESS CARD } quote 43 state getcode } enda
It is from the command "ifspritepal" that it becomes interesting.
The pal 22 used, is of course the used green color of your new keycard and it is identical to pal 11.
The line "ifvarand access_key1 1 break" is identical to the original keycard "ifpinventory GET_ACCESS 0 break" and this indicates that you have the new keycard in your inventory.
The line "addvar access_key1 1" simply indicates the addition of the keycard in the right place. First location value is 1.
And finally, the line "redefinequote 43 ^8GREEN ^0ACCESS CARD" which is an alternative way of displaying the message, while picking up the keycard.
Instead of just having the basic message (number 43), you add one or more additional lines and colors.
IMPORTANT NOTE! If you want to add more pals to your new keycard, do exactly this:
useractor notenemy NEWACCESSCARD fall sizeat 32 32 ifmove RESPAWN_ACTOR_FLAG state respawnit else ifp pshrunk nullop else ifp palive ifpdistl RETRIEVEDISTANCE ifcount 6 ifcanseetarget { ifspritepal 10 { ifvarand access_key1 1 break else { addvar access_key1 1 } redefinequote 43 ^10DARK RED ^0ACCESS CARD } else ifspritepal 22 { ifvarand access_key1 2 break else { addvar access_key1 2 } redefinequote 43 ^8GREEN ^0ACCESS CARD } // else... quote 43 state getcode } enda
the lines "ifvarand / addvar access_key1" are very important! Each time you add a new pal, the number increases according to a specific location:
pal 10 = key1 1
pal 22 = key1 2
pal 15 = key1 4
pal 12 = key1 8
etc...
The first three values are identical to the original card: "https://wiki.eduke32.com/wiki/Got_access"
and the more you add, the more you have to increase by adding the number:
1+0 = 1 (keycard 1)
1+1 = 2 (keycard 2)
2+2 = 4 (keycard 3)
4+4 = 8 (keycard 4)
8+8 = 16 (keycard 5)
etc...
Is it ok for you? Last thing. If you need to reset your inventory or start a new game, add this:
onevent EVENT_RESETINVENTORY // reset the inventory at map start setvar access_key1 0 endevent onevent EVENT_ENTERLEVEL // reset the counters at map start setvar access_key1 0 endevent
And the bonus for cheating:
state allkeys setvar access_key1 1 ends onevent EVENT_ACTIVATECHEAT ife RETURN 1 // CHEAT_STUFF (give all weapons, inventory and keys) { state allkeys } ife RETURN 8 // CHEAT_ITEMS (give all inventory and keys) { state allkeys } ife RETURN 23 // CHEAT_KEYS (give all keys) { state allkeys } endevent
In the code "state allkeys" to simply give the example of a first new keycard with a new single color, the value is 1.
Don't forget to add up all the values concerning the addition of the new colors.
For example, if you have added only three pals (10, 12 and 15), to add it all up is the value of 7:
state allkeys setvar access_key1 7 // 1+2+4 = 7 ends
Add for fun a number of 6 pals and you get the value 63. Have fun with this while respecting the value.
And that's it! End of the second step!
Personal notes: I definitely did not use the code mentioned for the original ACCESSCARD actor, because I don't know if it would have worked or not.
Assuming that with Eduke32 everything is actually possible, it was better to create a new actor for more security.
----STEP 03----
Now that your new keycard is ready, we'll add all the code for the new access card switchs:
state stopsearchsounds stopsound DUKE_SEARCH stopsound DUKE_SEARCH2 ends state newaccessswitch ifaction 0 { action ACCESSOFF } { ifpdistl 1309 { ifp pfacing { ifhitspace { ifcansee { ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 130 } state stopsearchsounds ifaction ACCESSOFF ifspritepal 22 { ifvarand access_key1 1 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 22 setvar customkeycard_pos 20 action ACCESSON } } } } else set access_quote 0 } } } ifaction ACCESSON { ifvare customkeycard_pos 9 { operateactivators lotag_saved THISACTOR operatemasterswitches lotag_saved operaterespawns lotag_saved ifvare hitag_saved 0 soundonce SWITCH_ON else soundoncevar hitag_saved ifspritepal 22 subvar access_key1 1 } } ends
A bit complicated isn't it? Don't panic, I'll explain! First of all, some general information.
The code "state stopsearchsounds" = prevents Duke from using the quotes, during he tries to activate the access card switch.
The lines with the gamevar "access_quote" is "ACCESS CARD REQUIRED" message (quote 130) displayed and will be displayed every time the player presses the space bar on the keyboard only.
The message will not be blocked if you keep pressing the key.
The line "ife access_key1 0" which is immediately followed by the first mentioned line, will prevent the message from activating, during the on-screen keycard animation at the same time.
Then the line from "ifspritepal 22" takes with the braces, a very useful code block to know:
- ifvarand access_key1 1 = is of course the keycard of your inventory, which will be taken into account with the new access card switch of the same pal.
- lockplayer 23 = this stops the player's movement for about 2 seconds.
- setvar ckeycard_picnum HANDHOLDINGACCESS2 = is the first animation image; Duke holding the keycard with his hand.
- setvar ckeycard_pal 22 = this is of course the chosen pal of the image.
- setvar customkeycard_pos 20 = the total number of frames for the animation.
A little further down, you have the last block taken with "ifaction ACCESSON":
The line "ifvare customkeycard_pos 9" corresponds to which frame number of the animation, a door will open, a monster will appear, an elevator will be unlocked, etc...
Change the value 9 by another one (from 1 to 20, total number of images of the animation), will make delayed or precipitated an activation (which would not have too much coherence lol).
This same line is of course associated with the commands "operate" followed by the values lotag / hitag to add as if it were an original switch.
Finally, the last line "ifspritepal 22 subvar access_key1 1" = removes the icon of the key card from the inventory, after the player has used it.
That's it! Now that your new switch is ready, let's we will this to make it really work. First of all, you will add the following code towards the end of this one:
state checkcounterswitch setvar access_temp 0 whilevarn access_temp 16384 { getactor[access_temp].statnum access_temp4 ifvarn access_temp4 1024 { getactor[access_temp].picnum access_temp2 ifvare access_temp2 NEWACCESSSWITCH1 { getactorvar[access_temp].lotag_saved access_temp3 ifvarvare lotag_saved access_temp3 { setactor[access_temp].picnum 16 } } ifvare access_temp2 NEWACCESSSWITCH2 { getactorvar[access_temp].lotag_saved access_temp3 ifvarvare lotag_saved access_temp3 { setactor[access_temp].picnum 18 } } } addvar access_temp 1 } ends
Towards the end of this one =
state newaccessswitch ifaction 0 { action ACCESSOFF } { ifpdistl 1309 { ifp pfacing { ifhitspace { ifcansee { ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 130 } state stopsearchsounds ifaction ACCESSOFF ifspritepal 22 { ifvarand access_key1 1 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 22 setvar customkeycard_pos 20 action ACCESSON } } } } else set access_quote 0 } } } ifaction ACCESSON { ifvare customkeycard_pos 9 { operateactivators lotag_saved THISACTOR operatemasterswitches lotag_saved operaterespawns lotag_saved ifvare hitag_saved 0 soundonce SWITCH_ON else soundoncevar hitag_saved ifspritepal 22 subvar access_key1 1 state checkcounterswitch } } ends
It will be in this part of the code that you will add all your new access card switches.
The lines "ifvare access_temp2" correspond to the picnum of your switch (unactivated) and underneath next to "lotag_saved" you have between braces the line "setactor[access_temp].picnum 16 / 18" which corresponds to your activated switch picnum.
SWITCH ON = picnum NEWACCESSSWITCH1 (tile#15)
SWITCH OFF = picnum tile#16
Now you will add this:
state useswitchcheckwall ifvarn hitwalls -1 { setvar misc_array 214 getactorvar[misc_array].misc_array_amount misc_array_amount_temp // hitwall-overpicnum getwall[hitwalls].overpicnum misc_array_amount_temp setvar misc_array 214 setactorvar[misc_array].misc_array_amount misc_array_amount_temp } ifvare misc_array_amount_temp W_FORCEFIELD setvar forcefields_temp 0 else ifvare misc_array_amount_temp 664 setvar forcefields_temp 0 else ifvare misc_array_amount_temp BIGFORCE setvar forcefields_temp 0 else setvar forcefields_temp 1 ends
Towards the beginning =
state newaccessswitch ifaction 0 { action ACCESSOFF } state useswitchcheckwall { ifpdistl 1309 { ifp pfacing { ifhitspace { ifcansee { ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 130 } state stopsearchsounds ifaction ACCESSOFF ifspritepal 22 { ifvarand access_key1 1 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 22 setvar customkeycard_pos 20 action ACCESSON } } } } else set access_quote 0 } } } ifaction ACCESSON { ifvare customkeycard_pos 9 { operateactivators lotag_saved THISACTOR operatemasterswitches lotag_saved operaterespawns lotag_saved ifvare hitag_saved 0 soundonce SWITCH_ON else soundoncevar hitag_saved ifspritepal 22 subvar access_key1 1 state checkcounterswitch } } ends
This will avoid having to target the wall, rather than the switch sprite (cstat 16 - wall-aligned).
NOTE: this part of the code, as well as the following, both come from the mod "Naferia's Reign: Invasion of the Dark Mistress"
Finally, if you were to disable a force field, add this:
state checkforforcefields setvar access_temp 0 whilevarn access_temp 16383 { ifvarvarl access_temp NUMWALLS getwall[access_temp].lotag access_temp4 ifvarvare access_temp4 lotag_saved { ifvare actorvar[access_temp].wall_array 0 { ifvarvarl access_temp NUMWALLS getwall[access_temp].overpicnum forcefields_temp2 ifvare forcefields_temp2 BIGFORCE { setwall[access_temp].overpicnum 0 setwall[access_temp].cstat 0 setactorvar[access_temp].wall_array 1 } else ifvare forcefields_temp2 W_FORCEFIELD { setwall[access_temp].overpicnum 0 setwall[access_temp].cstat 0 setactorvar[access_temp].wall_array 2 } else ifvare forcefields_temp2 664 { setwall[access_temp].overpicnum 0 setwall[access_temp].cstat 0 setactorvar[access_temp].wall_array 2 } } else ifvare actorvar[access_temp].wall_array 1 { ifvarvarl access_temp NUMWALLS getwall[access_temp].overpicnum forcefields_temp2 ifvare forcefields_temp2 0 { setwall[access_temp].overpicnum BIGFORCE setwall[access_temp].cstat 209 setactorvar[access_temp].wall_array 0 } } else ifvare actorvar[access_temp].wall_array 2 { ifvarvarl access_temp NUMWALLS getwall[access_temp].overpicnum forcefields_temp2 ifvare forcefields_temp2 0 { setwall[access_temp].overpicnum W_FORCEFIELD setwall[access_temp].cstat 209 setactorvar[access_temp].wall_array 0 } } } addvar access_temp 1 ifvarg access_temp 16383 break } ends
Towards the end of this one =
state newaccessswitch ifaction 0 { action ACCESSOFF } state useswitchcheckwall { ifpdistl 1309 { ifp pfacing { ifhitspace { ifcansee { ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 130 } state stopsearchsounds ifaction ACCESSOFF ifspritepal 22 { ifvarand access_key1 1 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 22 setvar customkeycard_pos 20 action ACCESSON } } } } else set access_quote 0 } } } ifaction ACCESSON { ifvare customkeycard_pos 9 { operateactivators lotag_saved THISACTOR operatemasterswitches lotag_saved operaterespawns lotag_saved state checkforforcefields ifvare hitag_saved 0 soundonce SWITCH_ON else soundoncevar hitag_saved ifspritepal 22 subvar access_key1 1 state checkcounterswitch } } ends
Don't forget these extra lines as well:
state newaccessswitch ifaction 0 { action ACCESSOFF } state useswitchcheckwall ifvare forcefields_temp2 0 { ifpdistl 1309 ifvare forcefields_temp 1 { ifp pfacing { ifhitspace { ifcansee { ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 130 } state stopsearchsounds ifaction ACCESSOFF ifspritepal 22 { ifvarand access_key1 1 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 22 setvar customkeycard_pos 20 action ACCESSON } } } } else set access_quote 0 } } } ifaction ACCESSON { ifvare customkeycard_pos 9 { operateactivators lotag_saved THISACTOR operatemasterswitches lotag_saved operaterespawns lotag_saved state checkforforcefields ifvare hitag_saved 0 soundonce SWITCH_ON else soundoncevar hitag_saved ifspritepal 22 subvar access_key1 1 state checkcounterswitch } } ends
That's it! You have a fully functional switch but a few last things are missing. As with your new keycard actor, create two more for your new switches and of course you add the main code after:
useractor notenemy NEWACCESSSWITCH1 state newaccessswitch enda useractor notenemy NEWACCESSSWITCH2 state newaccessswitch enda
Still in your "state newaccessswitch" code exactly as for the example of your new keycard, add the other pal of your new switches like this:
state newaccessswitch ifaction 0 { action ACCESSOFF } state useswitchcheckwall ifvare forcefields_temp2 0 { ifpdistl 1309 ifvare forcefields_temp 1 { ifp pfacing { ifhitspace { ifcansee { state stopsearchsounds ifaction ACCESSOFF ifspritepal 10 { ifvarand access_key1 1 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 10 setvar customkeycard_pos 20 action ACCESSON } ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 131 } } else ifspritepal 22 { ifvarand access_key1 2 { lockplayer 23 setvar ckeycard_picnum HANDHOLDINGACCESS2 setvar ckeycard_pal 22 setvar customkeycard_pos 20 action ACCESSON } ife access_quote 0 ife access_key1 0 { set access_quote 1 quote 130 } } //else... } } else set access_quote 0 } } } ifaction ACCESSON { ifvare customkeycard_pos 9 { operateactivators lotag_saved THISACTOR operatemasterswitches lotag_saved operaterespawns lotag_saved state checkforforcefields ifvare hitag_saved 0 soundonce SWITCH_ON else soundoncevar hitag_saved ifspritepal 10 subvar access_key1 1 else ifspritepal 22 subvar access_key1 2 state checkcounterswitch } } ends
Always the same principle, pal 10 = 1, pal 22 = 2, etc... (= "ifvarand access_key1").
NOTE: did you notice that the lines "ife access_quote 0 ife access_key1 0" and "{ set access_quote 1 quote 130 }" have changed places? Well, that's perfectly normal! If you have more than one pal for your new switch, you have to place the lines just below the block of the chosen pal, as already mentioned in the code. The quote in braces (quote 131) will simply be another name of your choice, such as "DARK RED ACCESS CARD REQUIRED"
And finally, a second line appeared towards the end of the code "ifspritepal 10 subvar access_key1 1 else"
it is of course still the same principle of your multi-colored key card. The icon of the key card will be removed from the screen after the player has used it.
We are coming to the end of this first part of the tutorial...Which is only the FIRST METHOD (yeah, yeah, there is a second) and it will be quite fun.
But before we close this tutorial, we will of course finish it. Yeah, yeah, it wasn't finished lol.
Of course, the code for the key card animation is missing, which really took me HOURS! REAL HOURS to check each positioning (x / y offset) of each image, frame by frame.
I used a second Eduke32 only for testing purposes, I used the command "rotatesprite" I added on a map a keycard and its switch to see the original animation and I paused several times (at the second ready!), to see where I had to place my images and the same process several times until I got a complete and beautiful animation on a total of 20 frames. A MONSTROUS JOB!!!!!
onevent EVENT_DISPLAYSBAR //setvar RETURN -1 // only if you redo the whole HUD switch customkeycard_pos // key card frame animation case 0: break case 1: rotatesprite 166 244 65536 0 2565 0 1 0 0 0 xdim ydim break case 2: rotatesprite 162 228 65536 0 2565 0 1 0 0 0 xdim ydim break case 3: rotatesprite 154 196 65536 0 2565 0 1 0 0 0 xdim ydim break case 4: rotatesprite 152 188 65536 0 2565 0 1 0 0 0 xdim ydim break case 5: rotatesprite 146 164 65536 0 2565 0 1 0 0 0 xdim ydim break case 6: rotatesprite 143 152 65536 0 2564 0 1 0 0 0 xdim ydim break case 7: rotatesprite 143 152 65536 0 2564 0 1 0 0 0 xdim ydim break case 8: rotatesprite 143 152 65536 0 2564 0 1 0 0 0 xdim ydim break case 9: rotatesprite 143 152 65536 0 2564 0 1 0 0 0 xdim ydim break case 10: rotatesprite 143 152 65536 0 2564 0 1 0 0 0 xdim ydim break case 11: rotatesprite 143 152 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 12: rotatesprite 143 152 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 13: rotatesprite 143 152 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 14: case 15: rotatesprite 143 152 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 16: rotatesprite 149 176 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 17: rotatesprite 154 196 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 18: rotatesprite 162 228 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 19: rotatesprite 166 244 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim break case 20: rotatesprite 168 252 65536 0 ckeycard_picnum 0 ckeycard_pal 0 0 0 xdim ydim setplayer[THISACTOR].weapon_pos 30 // weapon properly lowered and raised break endswitch ifvarand access_key1 1 // classic green keycard icon { rotatesprite 255 164 32768 0 60 0 4 545 0 0 xdim ydim rotatesprite 256 163 32768 0 NEWACCESSCARD 0 11 512 0 0 xdim ydim } endevent
It's beautiful, isn't it? I also forgot to tell you to add this to complete the code for your new switches. For the lotag and hitag values to be taken into account, do this in the "LOADACTOR" event:
onevent EVENT_LOADACTOR // lotag/hitag values switch sprite[THISACTOR].picnum case NEWACCESSSWITCH1 // new access card switchs case NEWACCESSSWITCH2 getactor[THISACTOR].lotag lotag_saved setactor[THISACTOR].lotag zero_switch getactor[THISACTOR].hitag hitag_saved setactor[THISACTOR].hitag zero_switch break endswitch endevent
The final touch, add this in the code of APLAYER at the very beginning:
ifvarg customkeycard_pos 0 { setplayer[THISACTOR].kickback_pic 0 subvar customkeycard_pos 1 }
And it's over! Now you're finally ready to add your new keycard and switch sprites into your designs. The sequel for the second method will be coming soon. So be patient!
VIDEO TEST: https://youtu.be/WlWflNyUW_8