Release date: 12/27/1996 12:55 --- CON Editing FAQ --- version 2.0 by Joris B. Weimar -------------------------------------------------------------------------- INDEX -------------------------------------------------------------------------- 1) Information 1.1 Who wrote this FAQ and some general info 1.2 Where did the author get the information? 1.3 What's new? 2) CON building blocks 2.1 What's a state? 2.2 What's an action? 2.3 What's an ai? 2.4 What's an actor? 2.5 What's an useractor? 2.6 What is an 'if' construction? 2.7 The complete primitive list 2.8 Predefined states 2.9 Known .CON bugs 3) Examples 3.1 Example 1: Make the atomic health sprite pulsating 3.2 Example 2: Make your own Duke Bot 4) General CON overview 4.1 DEFS.CON 4.2 USER.CON 4.3 GAME.CON 5) Appendix 5.1 What I would like to know 5.2 Contributers/Thank you's 5.3 Update and info 5.4 Where to get this FAQ -------------------------------------------------------------------------- 1.1 Who wrote this FAQ and some general info -------------------------------------------------------------------------- This FAQ was written by Joris Weimar also known as 'antiwin'. I'm a huge fan of Duke Nukem and until recently I didn't do anything with the CON files other then change some simple values such as MAXPLAYERHEALTH etc. After some of the primitives you will notice a sign like this "[PP]". This will mean the primitive or functionallity is only available in Plutonium Pak. PP is short for Plutonium Pak (do'h!). I must admit that I'm don't know everything on .CON hacking but I know when *I* knew nothing about it I wanted to get every information I could. So here it is. Whenever I searched the net for a CON FAQ I _always_ got the same FAQ. I hope this FAQ will go furhter into subjects that that FAQ (you surely now which FAQ I'm reffering to) brought up. I'm asking you friendly to keep the name of this FAQ 'CONEDIT.FAQ' or 'CONEDIT.ZIP' when zipped. This to eliminate confusion. If you have any questions, tips, corrections or comments about this FAQ you can reach me via e-mail at antiwin@worldonline.nl. You can also call me at +31 (0)70 3520655. -------------------------------------------------------------------------- 1.2 Were did the author get the information? -------------------------------------------------------------------------- Well, I _did_ learn something from the FAQ by Ben Cantrick. But most of the stuff I found out by myself by just trying, trying and trying. I re- wrote the entire code for the pigcop. It's still buggy and there are still some things that I don't comprehense. But he sure has gotten tougher. You'll find an PigCop-to-Duke example in this FAQ. Ok, now lets get on with the good stuff. -------------------------------------------------------------------------- 1.3 What's new? -------------------------------------------------------------------------- * version 0.1á - First release. * version 0.2 - Changed the index - Added some more primitives * version 0.3 - Expanded the PigCop example - Fixed some misspellings :-) * version 0.4 - Expanded the PigCop example - Added 'Contributor/Thank you's' part - Added 'Where to get this FAQ' part * version 0.5 - Added 'Predefined states' part - Removed those 'line-drawing' chars for Windows compatiblity * version 0.6 - Changed pigcop into duke :-) - Fixed several code pigs * version 0.7 - Removed pigcop example - Started a new more simpler example * version 0.8 - Update the new example - Rename keywords to primitives - Added 5 new primitives - Documented a few unknown primitives * version 0.9 - 1.1 - never released * version 2.0 - New example - Added new Plutonium Pak primitives -------------------------------------------------------------------------- 2.1 What's a state? -------------------------------------------------------------------------- A state is a subroutine. Whenever you call a state he executes that function and return to where you called it. Example: state saysecretplace // Start a state definition quote 9 // Some code ends // End of state (return to caller) This is a state (subroutine). Whenever you call it it executes the code contained in it. In this example that would be the command 'quote' which prints a text on screen. 9 is the defined in USER.CON (definequote) as "A SECRET PLACE!". Now we must call it from somewhere: state saysecretplace // execute the state, thus printing "A SECRET PLACE!" You can call a state from within a state like this: state test2 // State test2 definition quote 9 ends // End of state state test1 // State test2 definition state test2 // Call the test2 state ends // End of state Now to print the quote on screen do this: state test1 or ofcourse this (this does it directly while the above example first calles another state): state test2 Now he will print "A SECRET PLACE!". You may think to yourself: "hmmm... I can understand this but where do I put it in the .CON". Well, I'll get to that later. -------------------------------------------------------------------------- 2.2 What's an action? -------------------------------------------------------------------------- An action is used to give a group of sprites a name. Usually this group of sprites is animated. The structure of the action command is: action <name> <startframenum> <numframes> <type> <incvalue> <delay> <name> = This can be any string up to 64 characters long. <startframenum> = starting frame number. Note: this number is rela- tive to the main sprite of the actor. If you want the pigcop to look like the atomic health you need to give the starting frame a number of -1900 since the pigcop main character is 2000 and the atomic health is 100 <numframes> = Number of frames in action group. <type> = This value determines wether the picture is onesided (looks the same no matter what angle you see it from) or 3D. When 3D every sprite will contain actually 5 sprites. One seen from upfront, one from the back, one sideways and two from resp. 45 degr. and 135 degr. The other three angles are created from the other sprites by flipping the x-coordinates. Give <type> a value of 1 to make it onesided. 5 makes it 3D. I don't know if there are any other legal values but I wouldn't bet on it. One possible value could be 8 though. I'm not sure, but when this value is used I guess the expects there to be 8 sprites for each frame (45,90,135degr etc.) <incvalue> = This is the incrementing value. Negative values are allowed. <delay> = This determines how long each frame lasts. Bigger values lets the frame take longer. Example: action ATOMIC 0 15 1 1 10 Ok, this _is_ still kind of complex but you'll get to use this stuff in a minute. -------------------------------------------------------------------------- 2.3 What's an ai? -------------------------------------------------------------------------- An ai is some sort of definition of a state of an actor. Here's the struc- ture: ai <ainame> <action> <speed> <aitype> <ainame> = Just a string to identify it for later use. <action> = action group id. This is the group of frames the actor will cycle through as he is using this ai function. <speed> = Rate of movement of character when using this ai function. It seems that <speed> must be a value defined by move (move WALKSPEED 100). Negative values are allowed. <aitype> = Determines type of ai. The ai types are already programmed in the game so you can't change these. Some of the legal types are: seekplayer: The actor will walk up to the _nearest_ player. fleeenemy: The actor will run away from a player. faceplayer: The actor will point his crosshair at you thus facing you. faceplayersmart: The actor will point his crosshair a little bit next to you in the direction that you're heading. Kind of smart, isn't it. dodgebullet: Evasion manouvre. randomangle: Change actors direction to a random angle when it hits the wall. Or walk up to the player when actor is being shot at. You can more than one ai at the same time by listing them: randomangle dodgebullet etc. When you want the actor to use an ai function do it like this: ai <name> where <name> is the same as <ainame> explained above. -------------------------------------------------------------------------- 2.4 What's an actor? -------------------------------------------------------------------------- Everything that has vertices (drawn in build) is _not_ an actor. So walls, floors, elevators, doors are _not_ actors. Every sprite has the potential of being an actor. Some examples are: Duke, Pigcop, Medicalkit, Health, RPG sprite etc... The structure of the actor command is: actor <initialspritenum> <strength> <action> <speed> <aifunction> <initialspritenum> = This number is the tile number (as in build, editart) from which all actions that this actor can do are relative. For a PIGCOP this value is PIGCOP which is defined (in USER.CON) to be 2000. If you look in build at location 2000 you'll see the PIGCOP character. <strength> = This value tells the game how much damage it can take. If you give this parameter a value of 0 the actor can not be destroyed (bummer). <action> = The action number refers to an action group as de- scribed above. Regarding to monsters this is usally some kind of initial action group. He is just standing and doing nothing. <speed> = Speed is the rate of movement this character has, if the character doesn't move give this a value of 0 or don't give this value at all. <aifunction> = His initial ai routine. With monsters this is usually a still standing monster waiting for someone to discover him. You can read the defenition of ai in the section above. The actor code is the main code of a character. It's structure goes like this: actor ... (describer above) // The code contained hereign is the main code of the character. Each time // (frame) this code gets called! enda // End of Actor As I heard from "StratonAce" we can not add new actors. We can replace other actors by removing the old code and placing in our. "StratonAce" also informed me that this restriction is possibly removed with the upcoming Plutonium Pak version of Duke (1.4) -------------------------------------------------------------------------- 2.5 What's an useractor? [PP] -------------------------------------------------------------------------- The useractor command is new to PP. It allows people to create their own actors in PP without having to replace old ones. It's almost exactly the same as a conventional actor with a few exeptions. For example, enemies created with the useractor command will not shoot straight and their size might not always be proportional (like the bug in BUILD). The structure of the actor command is: useractor <type> <initialspritenum> <strength> <action> <speed> <aifunction> <type> = This tells PP the type of actor you want to create. The legal values are 'enemystayput', 'enemy' and 'notenemy'. Explenations follow: enemy = The actor's code will not be executed until approximatly 1 second after the player has spotted the actor. notenemy = The actor's code will not be executed until the player has spotted the actor. enemystayput = The actor's code will not be executed until approximatly 1 second after the player has spotted the actor AND the actor's code will not be executed if the player is not in sight. <initialspritenum> = This number is the tile number (as in build, editart) from which all actions that this actor can do are relative. For a PIGCOP this value is PIGCOP which is defined (in USER.CON) to be 2000. If you look in build at location 2000 you'll see the PIGCOP character. <strength> = This value tells the game how much damage it can take. If you give this parameter a value of 0 the actor can not be destroyed (bummer). <action> = The action number refers to an action group as de- scribed above. Regarding to monsters this is usally some kind of initial action group. He is just standing and doing nothing. <speed> = Speed is the rate of movement this character has, if the character doesn't move give this a value of 0 or don't give this value at all. <aifunction> = His initial ai routine. With monsters this is usually -------------------------------------------------------------------------- 2.6 What's an 'if' construction? -------------------------------------------------------------------------- Okay, this is really the power of any programming language. In many occasions you want to execute some code (listed below, 2.6) IF some- thing is true, or IF something is false. You also want something ELSE to be executed if the condition is false: IF I AM HUNGRY EAT A SANDWICH ELSE WaiT UNTIL LATER Well, now to get a bit more in Dukes direction, this is some code of my new Pig Cop. He fires a SHRINKER, but only when you're not on ste- roids because when you use steroids you won't shrink (you knew that, right?): ifp ponsteroids shoot SHOTGUN else shoot SHRINKER in PSEUDO code that is: if duke is on steroids shoot him with the shotgun or else shoot him with the shrinker If you didn't know the 'ifp ponsteroids' and 'shoot' command yet, don't worry. They are all listed below. Ofcourse you may want to execute MORE than one function. Then you'll have to use the braces '{' and '}'. ifp ponsteroids { shoot SHOTGUN sound SHOTGUN_FIRE } else { shoot SHRINKER sound SHRINKER_FIRE } You see that all the code between the two braces is considered as ONE function. -------------------------------------------------------------------------- 2.7 The complete primitive list -------------------------------------------------------------------------- Now, you're wondering, what kind of code can I put in these actors and STATEs. Well, you already saw one of them: QUOTE. That's ofcourse not enough to create a character like for example a PigCop. Ok, here are the most important functions: // = Everything on the line after the '//' will be ignored. /* ... */ = Everything between the '/*' and the '*/' will be ignored. action <actiongroup> = Assign sprite animation group to current actor. See definition above. actor ... = See definition above. addammo <weapon> <amount> = Add the given number of ammo to the player. He does not get the weapon if he hasn't got it. The legal values are describer in USER.CON addphealth <amount> = Add the value <amount> to the players health. When playing with more than one player I suspect the closest one will be effected. This goes for all player related functions. addinventory <item> <amnt> = Add <amount> to the item <item>. The legal values for <item> can be seen with the 'ifpinventory' function. ai <name> = Let current actor use the ai function <name> from now on. addstrength = Adds strength to the current actor. addweapon <weap> <ammo> = Gives nearest duke weapon <weap> with an initial amount of ammo equal to <ammo>. Legal weapons are: - HANDBOMB_WEAPON - RPG_WEAPON - SHOTGUN_WEAPON - PISTOL_WEAPON - TRIPBOMB_WEAPON - CHAINGUN_WEAPON - SHRINKER_WEAPON - FREEZE_WEAPON - DEVISTATOR_WEAPON break = Immediatly leave a STATE or actor. clipdist <value> = I have no idea ;) count <num> = Sets the counter to <num>. I believe the game gives every actor its own counter since this function could heavily mess up the timer of other actors cactor <actor> = Call the code of the actor identified by <actor> cstat <mask> = With this function you can do some nice tricks. This is used to change some actor settings for the current actor. Some of the legal values are: 1 = Make sprite blockable ("B" in BUILD) 2 = make actor 'see-through'. 4 = flip sprite around x-axis. 8 = flip sprite around y-axis. 16 = Draw him as wall texture (vert. flat) 32 = Draw him as floor texture (hor. flat) 64 = Make sprite one sided. 128 = Half submerged. 256 = Make sprite solid ("H" in BUILD) 32768 = Invisible To use more than one setting add the values together (264 = solid+upsidedown, 256+8). cstator <mask> = Same as cstat, but it keeps doesn't reset all the previous settings. It just adds the ones you specify. A bit like the 'or' in several programming languages. debris <actiongrp> <amount> = Causes debris to fly all over the place. <actiongrp> is the sprite animation used for the debris. Legal values seem to be 'SCRAP1' and 'SCRAP2'. The higher the amount the more debris. 2 seems to be a reasonable value. But it's up to you. debug <value> = Prints a <value> on screen. This value will be printed in the ULGY standard font and duke will not try to save the background. I don't now what forms <value> can take. define <string> <value> = Defines a value as a string. This way you can use the string instead of the number (easier to remember). The Duke3D compiler will replace every occurance of <string> with <value> definequote <value> <string> = Binds a string to a number. The string can now be displayed by using the 'quote' primitive. defineskillname <value> <s> = Defines the string 's' associated with the difficulty level 'value'. 0 is easy and 3 is hard. [PP] definelevelname <ep> <lev> <mapname> <par time> <3drealms> = Defines a level where the episode number is 'ep' the level number if 'lev' the mapname is 'mapname' the partime is 'par time' and 3drealms' time is '3drealms'. definesound <value> <filename> <begin pitch> <end pitch> <priority> <flags> <volume> = Binds the sound file 'filename' to 'value' and tells the game the sound may be pitched from 'begin pitch' to 'end pitch'. The sound priority is 'priority' and the type of sound is defined in 'flags'. Volume is the volume adjustment. definevolumename <ep> <name> = Defines title for each episode. 'ep' is the episode number and 'name' is the name it will get. [PP] enda = End of actor code marker. endofgame <number> = Ends the game. I'm not sure what <number> means but 52 is used to end level 3 (BOSS2). ends = End of state code marker. fall = Let the current actor fall until it hits a surface. gamestartup ... = This is the main function which 'starts' the game. It gets all the hardcoded values passed as parameters. The values it gets passed can not be changed during gameplay. getlastpal = Sets the palette of the current actor back to the color before the last change. guts <actiongrp> <amount> = Same as debris but then for bodyparts. Legal values for <actiongrp> seem to be: - JIBS(1 to 5) - HEADJIB/LEGJIB/ARMJIB (trooper parts) - LIZMANARM1/LIZMANLEG1 (lizman parts) - DUKETORSO/DUKELEG/DUKEGUN (duke parts) <amount> determines the amount of guts to fly. globalsound = Play sound that can be heard everywhere in the map. hitradius <c> <1> <2> <3> <4>= Make an explosion (not the actual animation but just the damage). <c> is the radius. <4> is how much damage is done in first quarter of circle seen from inside to outside. <3> is how much damage is done in second quarter of circle etc. ifactornotstayput = (not sure) Test if the current actor already 'activated', where 'activated' means spotted by a player or he has spotted the player. It seems that an actors code isn't executed at all until one of the above events occur. You can notice this in the game. If you create a map where an actor (ie. health) is lifted into the sky, he doens't fall down to the ground until you spot it! ifactor <actorid> = Checks if current actor was called with cactor by <actorid> ifaction <actionnum> = Test if the current actor is executing the giving <actionnum>. <actionnum> is defined by the action primitive, remember? ifactioncount <number> = Tests if the actors has display <number> frames since the last call to resetactioncount ifai <ainame> = Tests if the current actor is using the ai function <ainame> which was defined with the 'ai' primitive. ifangdiffl <angle> = If the angle between the current actor and duke is less than <angle> it returns true. 360 degrees is 2048. ifangdiffg <angle> = If the angle between the current actor and duke is less than <angle> it returns false. 360 degrees is 2048. ifawayfromwall = Returns false when actor is on a wall-line. This would be a line that can be seen in BUILD.EXE. I don't know the actual use for this. ifbulletnear = Tests if a bullet is near the current actor. This is a nice one because you can use it like this: ifbulletnear ai AIRUNAWAYFROMBULLET Okay, maybe you don't understand this yet, but I'll explain it later. For now, let's say this code means: If there is a bullet nearby then go into another ai function that makes the actor runaway with high speed (fleeenemy aifunction). ifcansee = Tests if the current actor can see duke. It also seems to have another function. It seems as if you need to call this function to give an actor a new position to walk to when using the seekenemy and some other ai functions. If you don't call this when using that ai function he will just walk up to your previous position and just stop there! ifcanseetarget = Tests if the current actor can see duke. I'm not about this one though. ifcanshoottarget = Tests if the current actor can shoot his target. I don't know what 'can shoot' means. ifceilingdistg <num> = Tests if the distance to the ceiling is greater than <num> ifceilingdistl <num> = Tests if the distance to the ceiling is less than <num> ifcount <num> = Tests if the number of frame (I don't actually know how long a frame takes) is reached. These are not action frames so they are not limited to one actor. See it as some sort of global counter. ifdead = Checks if actor has no health left. Good thing to call after he has been hit with a weapon. If he was and he's dead you need to remove the actor from the map (killit). iffloordistg <num> = Same as 'ifceilingdistg' but now for the floor. iffloordistl <num> = Same as 'ifceilingdistl' but now for the floor. ifgotweaponce <num> = Seems to test if a player has a particular weapon. The weapon tested would be the current actor. This code would logicaly only appear in weapon actors such as RPGSPRITE. I'm not sure what the <num>'s use is. The values passed in the real CONs where 0 and 1. (?) ifhitspace = Checks if duke is hitting the spacebar. ifhitweapon = Tests if the current actor has been hit by a weapon. Use 'ifwasweapon' to check which weapon it was. ifgapzl <num> = Tests if the distance between the floor and the ceiling at the actor's location is less than <num>. ifinspace = Checks if current player is in space. 'space' means when the floor/ceiling is parralaxed and the texture is one of the space-textures. ifinwater = Tests if the current actor is in the water. ifinouterspace = Tests if the current actor is in outer space? ifonwater = Same as 'ininwater', but then for 'on' the water. ifmove <name> = Tests if variable <name> is greater than 0. (not sure) ifnosounds = Tests if a sound is playing. ifnotmoving = Tests if the current actor is moving. Not sure about this one. ifspawnedby <actor> = Checks if the actor who spawned the current actor is equal to <actor> ifspritepal <num> = Tests if the palette of the current actor is equal to <num> ifsquished = Tests if the current actor has been squished. ifoutside = Tests if player is outside. A player is outside when he is in a room with parralaxing on! ifp <type> = Tests if the player (when I say player I always mean Duke, but you knew that, right?) is doing <type> where type can be: pstanding = Duke is standing pwalking = Duke is walking prunning = Duke is running pducking = Duke is ducking pfalling = Duke is falling pjumping = Duke is jumping phigher = Duke is higher than the cur. actor? pwalkingback = Duke is walking backwards prunningback = Duke is running backwards pkicking = Duke is kicking (ass) pshrunk = Duke is a smurf (shrunken) pjetpack = Duke is flying (jetpack) ponsteroids = Duke is using his steroids ponground = Duke has his both feet on the ground palive = Duke hasn't died yet pdead = Duke has been exterminated pfacing = Duke is facing the current actor You can test for more things at the same time. 'ifp prunning pwalking' returns true when either of the two is true. ifpdistl <number> = Tests if the players (nearest player) distance if less than <number>. 1024 appears to be the largest grid in BUILD. ifpdistg <number> = Same as ifpdistl but he now tests if the distance is greater. ifphealthl <num> = Tests if the players health is less than <number>. ifphealthg <num> = Tests if the players health is greater than <number>. ifpinventory <item> <amount> = Tests if the nearest player has less than <amount> left of item <item> where item can be: - GET_STEROIDS - GET_HEATS - GET_BOOTS - GET_SHIELD - GET_SCUBA - GET_HOLODUKE - GET_JETPACK - GET_FIRSTAID - GET_ACCESS (when using this the amount seems to be a bitlist of cards we have 0 = no cards 1 = blue card etc...) ifrespawn = Tests if the monster-respawn-mode is on. If so, the actor needs to respawn after RESPAWN TIME. ifrnd <num> = This is a randomize function. <num> is the chance you give it to be true. If <num> is 256 it wil be always true and 128 50% of the times. If you want less chance than 1/256 you need to use two ifrnd's like this: ifrnd 1 ifrnd 128 // This code gets executed 1/512. ifsquished = Tests if the current actor has been squished (shrunken and stepped on). ifstrength <num> = Tests if current actor has <num> strength left. ifwasweapon = Tests what weapon the actor has been hit by. include <filename> = Includes <filename> in the compiling process. killit = Removes the current actor from the map. The won't be called anymore. lotsofglass <amount> = Animate glass that breaks as if a window has broken. <amount> determines the ehhh... amount of glass. 30 seems to be a reasonable value. mail = Spawn some mail? mikesnd = Plays the microphone sound... money <num> = Spawns <num> dollar bills. move <name> <v1> <v2> = Give <name> a value of <v1> and a optional value of <v2>. When the variable is used to define the speed of an actor the second variable is used for vertical speed. This way you can simulate a character to use a jetpack. I've also seen <v1> and <v2> to be given ai function. What the meaning of that is I'm not entirely sure. If you change the velocity of an actor during it's code it will automaticly update. music <ep> <m1> <m2> ... = Defines MIDI music for each episode where 'ep' is the episode number and m1, m2 etc. are the individual music files for each level. nullop = nullop equals '{ }'. Now you can say: ifspritepal 1 nullop else { quote 1 } instead of ifspritepal 1 { } else { quote 1 } operate = Let's the current actor operate. If a door is nearby the door will open. This is a nice function for a clever actor. This actor could open a door where you fled through. You would have something like this in your main code: ifrnd 1 operate You _don't_ want to operate every time because the second time you operate the door closes again. palfrom <begin> <end> <del> = Change palette to color <begin> and then to <end> and then back to normal again (I think?). 0 or 32 = Green 16 = Red paper = Spawn some paper? pstomp = Player will look down and step on the near actor (if one is near) pkick = Player will kick. Good to call from an actor who has been frozen. First do: 'ifp pfacing' then 'ifpdistl FROZENQUICKKICKDIST' then 'pkick'. quote <num> = Print quote <num> on screen. All quotes are defined in USER.CON. resetactioncount = This resets the counter that counts how many frames of the current actor have been exectuted. The speed of actioncount is determined by the <delay> parameter in the action structure. resetcount = This resets the global count. This is the counter that is not bound to a given actor but count at the same rate for every actor I believe the counter increments every 3/100th of a second. resetplayer = Resets the player in a multiplayer game and places him at one of the APLAYER locations. respawnhitag = This code seems to spawn the actors that need to be spawned when the current actor dies. An example of this would be the dancing girls in the bar in E1L2. shoot <weapon> = Let's the current actor shoot with <weapon>. Legal values for weapons are defined in USER.CON. The direction in which the actor shoots is de- termined by the AI function of the actor. If it is 'faceplayer' he will obviously shoot at the player. But if you have 'seekplayer' as AI function the actor may be heading to the player but since he doesn't go straight to him he can easily miss. Some of the weapons are (these names are also used for ifwasweapon): SHRINKSPARK, SHOTGUN, RPG, CHAINGUN, FREEZEBLAST, KNEE, SPIT, FIRELASTER, HEAVYHBOMB, BOUNCEMINE, MORTER, DEVISTATORBLAST and TRIPBOMB. sizeat <x> <y> = Makes the current actor <x> times smaller in x-direction and <y> times smaller in y-direction. The difference between sizeat and sizeto is that sizeat makes the change immediatly while sizeto resizes the actor graduatly. sizeto <x> <y> = Makes the current actor <x> times smaller in x-direction and <y> times smaller in y-direction. sleeptime <time> = Makes the current actor sleep for <time> counts? sound <soundnum> = Play a sound. The soundnumbers are defined in USER.CON. soundonce <soundnum> = I think when using this sound, it will not be activated again until it is finished. spawn <actor> = Bring a new actor into the map defined by <actor> There seems to be once special <actor> (there may be more) which has a unique effect on the current actor. When you spawn 'FRAMEEFFECT1' the current actor while blur. This effect can be seen when an actor is shrinking or a player is on steroids. spritepal <num> = Changes palette number of sprite. Legal values are: 1 = Blue 4 = Dark 6 = Night vision Green 7 = Yellow (sort of) 8 = Green 10 = Red 19 = Red as a tomato 22 = Almost normal state <statename> = Enter a state named <statename> and return from it. If this line is put out of any actor or state code it is interpreted as a state definition. stopsound <sound> = Stops to play the sound 'sound'. Good for ending long sound effects when they have no use anymore. strength <num> = This function changes the strength of the current actor in <num> tossweapon = Let's duke spawn his currently selected weapon with a 50% chance. This code gets called when Duke dies. wackplayer = Tilt the screen. As if you're struck by lightning. -------------------------------------------------------------------------- 2.8 Predefined states -------------------------------------------------------------------------- Here's a list of states that are already defined in GAME.CON. You can ofcourse alter these but here's a list of some of them (call these state like this: 'state <name>') : - genericshrunkcode Shrink actor and stomp if within correct distance - blimbhitstate Make explosion. Spawn debris, kill actor and some other stuff... - rats Generate some rats. - headhitstate Gets called when player is being hurt bad. - burningstate Lites the current actor on fire. - steamcode Update steam sprite (subtract health from player who is near etc.) - burningbarrelcode Code for a burning barral (duh!) - get_code Gets an item and prepares it for respawn if neccesary. - randgetweapsnds Plays a random sound when called such as 'Groovy' or 'Come get some' etc. - getweaponcode Gets the current weapon and prepares it for respawn if neccesary. - respawnit Respawns the item in multiplayer game. - firestate Updates flames and checks if duke is burning himself etc. - jib_sounds Plays one of those nice sound like 'What a mess' or 'Let god sort them out'. - standard_jibs Spawns some random bodyparts. - femcode Takes care of the females in duke. Kill them or let them show their boobs. - killme Lets woman say "kiiillll meeee...." when duke hits space near her. - tipme Lets duke give woman a dollar bill and say 'Wanna dance' or 'Shake it baby'. - troop_body_jibs Spawns some trooper body parts. - liz_body_jibs Spawns some lizard body parts. - delete_enemy Deletes the current actor (removes it from the map). - standard_pjibs Spawns some duke body parts. Ok, that's it for now. -------------------------------------------------------------------------- 2.9 Known .CON bugs -------------------------------------------------------------------------- I added this section since I discovered a bug. I'll bet there will be more. bug 1: This 'if' construction... ifcansee ifai AIDUKEWANTTOSTOMP { } else ai AIDUKEWANTTOSTOMP ...should be equal to... ifcansee { ifai AIDUKEWANTTOSTOMP { } else ai AIDUKEWANTTOSTOMP } ... but it isn't. In the first case the 'else' part always gets executed. _Huge_ bug. I don't know if it's a bug or not but it sure is strange. When you give a character like a pigcop a huge amount of strength like 4500 then he will move like thunder when you hit him with a RPG. -------------------------------------------------------------------------- 3.1 Example 2: Make the atomic health sprite pulsating -------------------------------------------------------------------------- Okay, we're gonna make the atomice health sprite pulsate between visibility and invisibility graduatly. Ought to look pretty cool! (under construction... sorry) -------------------------------------------------------------------------- 3.2 Example 2: Make your own Duke Bot -------------------------------------------------------------------------- The example in the last couple of versions of this FAQ was getting a little complex for some of you guys. It even had some huge bugs in it. But here's a new example and I'm keeping it as clear as possible. We're gonna try to create a new Duke character. This character will eventually do the following: - when at a distance he will either fire some rockets or run up to you - when near he will shoot a shrinker ray at you - when you're shrunken he'll stomp you - when you shrink him he will shrink when you freeze him he will freeze when you kill him he will die - when he's hit he'll yell or shoot an RPG :-) - when you shoot at him he will flee Ok, but how would we go about this. First we need to replace a character with our new character. I think our PIGCOP will do fine. Now remove all the PigCop code. These are the lines 'action APIGWALK ...' to the line just before 'action ABOSS1WALK ...'. I also recommend creating a one roomed sector with just one pigcop in it so you can check the code out easy. Whenever you see this: '*CHECK*' you can check the code out in your map. First we're gonna define the basics of our character. We need to set up an action group of Duke standing: action DUKESTAND -595 1 5 1 1 Since the PIGCOP standing sprite is tile number 2030 and the Duke standing sprite is 1405. We need to use -595 since all the sprites must be relative to 2000 (PIGCOP). And we need the main actor code ofcourse: define DUKESTRENGTH 200 actor PIGCOP DUKESTRENGTH DUKESTAND faceplayer // Drop the character until it hits a surface. fall enda *CHECK* Now we want him to go look for us so we'll have to define a sprite group (action) of duke running. action DUKERUN -575 4 5 1 10 and a speed at which he runs: move DUKERUNSPEED 240 And NOW we need to define ourselfs an AI function of a duke how is looking for us: ai AIDUKESEEKPLAYER DUKERUN DUKERUNSPEED seekplayer Now we need to add the following code to the actor code (right after 'fall') // Are we still standing? ifaction DUKESTAND // Yep, so now start looking for player ai AIDUKESEEKPLAYER *CHECK* Now duke runs, but strangly enough not to you. That's because we need to call the ifcansee { } function? to update dukes vision. You can place the ifcansee { } right after the fall line in the actor code and then check again. Remove this code afterwards however since we don't need it to be _there_. Now we're gonna create a state (put this, like actions, ai's and move's outside the actor code)... state dukeseekplayer ends ... with no code in it yet. This state needs to be called whenever we are in the seeking ai. So put this in the actor code _after_ the 'ai AIDUKE SEEKPLAYER' line: ifai AIDUKESEEKPLAYER state dukeseekplayer So now if we are in the seekplayer ai the dukeseekplayer will be called! Now we're gonna add the following: if dukes near the player he'll start to fire shrinker rays. Put this code into the dukeseekplayer state: // Can we see the player ifcansee { // Is player near? ifpdistl 5000 // Can we shoot the target? ifcanshoottarget // Go into shooting ai ai AIDUKESHOOTFROMCLOSE } So you'll see we'll have to define a new AI function AIDUKESHOOTFROMCLOSE. ai AIDUKESHOOTFROMCLOSE DUKERUN DUKERUNSPEED faceplayer And we'll need to add this part to the actor code after the 'state dukeseek...' line: ifai AIDUKESHOOTFROMCLOSE state dukeseekplayer So you see that we use the same state when he shooting. Obviously we need something in the dukeseekplayer state to identify wether duke is seeking or shooting. Add this before the 'ifcansee' line in the duke seekplayer state: // Are we shooting? ifai AIDUKESHOOTFROMCLOSE { // Can we see him? ifcansee { // Is he still close? ifpdistl 6000 { // Can we shoot our target? ifcanshoottarget // Only shoot every 10 counts ifcount 10 { resetcount shoot SHRINKER sound SHRINKER_FIRE } } else // No we are not close anymore so seek him. ai AIDUKESEEKPLAYER } else // We can't see him anymore so seek him. ai AIDUKESEEKPLAYER // We don't want to rest of the state to be executed so // directly return break } *CHECK* Wooow. We got ourselfs a mad duke running after us shooting shrinker rays. Isn't that great. But hey, when we're shrunken he keeps shooting at us? Ok, lets fix that. We want duke to go into another ai function when he has shrunken us. ai AIDUKEWANTTOSTOMP DUKERUN DUKERUNSPEED seekplayer Now add this code to the main actor code right before the 'ifai AIDUKESEEKPLAYER' line: ifp pshrunk { // Are we already wanting to stomp? ifai AIDUKEWANTTOSTOMP { } else // No so do it. ai AIDUKEWANTTOSTOMP } and add the following after the 'ifai AIDUKESHOOTFROMCLOSE state dukeseekplayer' line: ifai AIDUKEWANTTOSTOMP { // If he's already dead we've got nothing to do. ifp pdead { } else state dukewanttostomp } Now we're gonna define the state: state dukewanttostomp // Is he still shrunken? ifp pshrunk { // Can we see him? ifcansee { // Is he near enough to stomp? ifpdistl SQUISHABLEDISTANCE { // Kill him by subtracting 400 health (ought to be enough) addphealth -400 // A nice sound sound SQUISHED // Some flying body parts state standard_pjibs state standard_pjibs // Yet another nice sound sound DUKE_KILLED4 } } } // He is not shrunken anymore else ai AIDUKESEEKPLAYER ends Ok, only this time, and this time only, I'll give you all we got now: // -------------- define DUKESTRENGTH 200 action DUKESTAND -595 1 5 1 1 action DUKERUN -575 4 5 1 10 move DUKERUNSPEED 240 ai AIDUKESEEKPLAYER DUKERUN DUKERUNSPEED seekplayer ai AIDUKESHOOTFROMCLOSE DUKERUN DUKERUNSPEED faceplayer ai AIDUKEWANTTOSTOMP DUKERUN DUKERUNSPEED seekplayer state dukeseekplayer ifai AIDUKESHOOTFROMCLOSE { ifcansee { ifpdistl 6000 { ifcanshoottarget ifcount 10 { resetcount shoot SHRINKER sound SHRINKER_FIRE } } else ai AIDUKESEEKPLAYER } else ai AIDUKESEEKPLAYER break } ifcansee { ifpdistl 5000 ifcanshoottarget ai AIDUKESHOOTFROMCLOSE } ends state dukewanttostomp ifp pshrunk { ifcansee { ifpdistl SQUISHABLEDISTANCE { addphealth -400 sound SQUISHED state standard_pjibs state standard_pjibs sound DUKE_KILLED4 } } } else ai AIDUKESEEKPLAYER ends actor PIGCOP MAXPLAYERHEALTH DUKESTAND faceplayer fall ifaction DUKESTAND ai AIDUKESEEKPLAYER ifp pshrunk { ifai AIDUKEWANTTOSTOMP { } else ai AIDUKEWANTTOSTOMP } ifai AIDUKESEEKPLAYER state dukeseekplayer ifai AIDUKESHOOTFROMCLOSE state dukeseekplayer ifai AIDUKEWANTTOSTOMP { ifp pdead { } else state dukewanttostomp } enda // -------------- *CHECK* Well, he shoots and he kills. That's my kind of duke. Now, we're gonna add the part were he shoots rockets from a distance. Yeah! Ok, this code needs to be put in the dukeseekplayer state. In this state we test if the distance is near (ifpdistl 5000). If it's true (he IS near) then - if we can shoot the target - we go into the AIDUKESHOOTCLOSE ai function. What we need to do is add an else like this: The code was: ifcansee { ifpdistl 5000 ifcanshoottarget ai AIDUKESHOOTFROMCLOSE } the code gets to be: ifcansee { ifpdistl 5000 { ifcanshoottarget ai AIDUKESHOOTFROMCLOSE } else { // Once in a while ifrnd 1 { // start shooting rockets ai AIDUKESHOOTROCKET break } } } Yep. A new ai function: move DUKESLOWSPEED 50 action DUKECRAWL -509 3 5 1 30 ai AIDUKESHOOTROCKET DUKECRAWL DUKESLOWSPEED faceplayer And now add this code after the 'ifai AIDUKESHOOTFROMCLOSE state dukeseekplayer' line: ifai AIDUKESHOOTROCKET state dukeshootrocket Now we'll define the state: state dukeshootrocket // Can we see duke? ifcansee { // Is he still far away? ifpdistg 8000 { // Can we shoot the target? ifcanshoottarget { // Only shoot once in the 20 counts ifcount 20 { // Start counting all over again. resetcount shoot RPG sound RPG_SHOOT } } } // No he's getting closer else ai AIDUKESEEKPLAYER } // Can't see him anymore so go find him. else ai AIDUKESEEKPLAYER ends Wooow. When at a distance, if some cases he will start shooting RPG's. What a guy! Now we're gonna teach him to dodge bullets when they're near. So yet another ai function: ai AIDUKEDODGEBULLET DUKECRAWL DUKERUN fleeenemy Put this is the main actor code before 'ifp pshrunk': // Is a bullet nearby? ifbulletnear // Yep, so evade it. ai AIDUKEDODGEBULLET And put this also in the actor code but after 'state dukeshootrocket': // If evasion ai is active ifai AIDUKEDOGDEBULLET { // Are we done (use evasion for 5 counts, ought to be enough) ifcount 5 { // We're done. So go back to seekplayer ai AIDUKESEEKPLAYER // Reset counter resetcount // We're done. break } } Wow. He evades rockets and stuff. Groovy. Ok, now we have given him a chance to survive so we're gonna write to stuff that gets executed when he is hurt and/or killed. First we need to define an ai and an action group of duke getting hurt! action DUKEPAIN -489 1 1 1 10 // DUKESTOPPED = 0 move DUKESTOPPED ai AIDUKEBEINGHURT DUKEPAIN DUKESTOPPED faceplayer Now add this code to the main actor code right before the 'ifbulletnear' code: ifai AIDUKEBEINGHURT { state dukebeinghurt break } ifhitweapon { ai AIDUKEBEINGHURT break } Now here's the dukebeinghurt state: state dukebeinghurt ifdead { // Play nice sound sound SQUISHED // Play a death sound ifrnd 128 sound DUKE_KILLED4 else sound DUKE_DEAD // Some body parts state standard_pjibs state standard_pjibs killit } else { // No he wasn't dead yet so play a randomly chosen // hurt sound. ifrnd 64 sound DUKE_LONGTERM_PAIN2 else ifrnd 64 sound DUKE_LONGTERM_PAIN3 else ifrnd 64 sound DUKE_LONGTERM_PAIN4 else ifrnd 64 sound DUKE_LONGTERM_PAIN5 } // After two frames go back to seeking mode again. ifactioncount 2 ai AIDUKESEEKPLAYER ends Ok, if duke gets shot with a gun he also explodes. So what? The dying animation doesn't work because this is _actually_ a pigcop. And pigcops die differently. Sorry. Now you can kill him easily by just shooting at him. I want him to - sometimes - shoot back with a RPG if he is being hit. This needs to be done in the hurt part where all the ifrnd 64's are. The code now is: else { // No he wasn't dead yet so play a randomly chosen // hurt sound. ifrnd 64 sound DUKE_LONGTERM_PAIN2 else ifrnd 64 sound DUKE_LONGTERM_PAIN3 else ifrnd 64 sound DUKE_LONGTERM_PAIN4 else ifrnd 64 sound DUKE_LONGTERM_PAIN5 } and the code gets to be: { // No he wasn't dead yet so play a randomly chosen // hurt sound. ifrnd 64 sound DUKE_LONGTERM_PAIN2 else ifrnd 64 sound DUKE_LONGTERM_PAIN3 else ifrnd 64 sound DUKE_LONGTERM_PAIN4 else ifrnd 64 sound DUKE_LONGTERM_PAIN5 // 25% chance he shoots when being hurt ifrnd 64 { // Only shoot every 3 counts. ifcount 3 { resetcount shoot RPG sound RPG_SHOOT } } } Ok, now we only need two things until we're done. The possibility to shrink him and the possibility to freeze him. You're on your own from now on... ... so figure this out yourself. Check the code of other actors to see how it's done. If you still have any questions you can always mail me at antiwin@worldonline.nl -------------------------------------------------------------------------- 4.1 DEFS.CON (overview) -------------------------------------------------------------------------- DEFS.CON is the CON file in which all defines are done. This way you can name a tile or sound by name instead of number. It is included by GAME.CON -------------------------------------------------------------------------- 4.2 USER.CON (overview) -------------------------------------------------------------------------- In USER.CON all sorts of defines are done. All levels and sounds are defined here. Also other game effects like respawning time etc. are declared here. It is included by GAME.CON -------------------------------------------------------------------------- 4.3 GAME.CON (overview) -------------------------------------------------------------------------- This is the main CON file. It gets compiled first. It includes DEFS.CON and USER.CON first. In this CON file all the actor code is located. You could put actor code in the USER.CON but it looks better if you keep it all in GAME.CON. -------------------------------------------------------------------------- 5.1 What *I* would like to know -------------------------------------------------------------------------- Here's a list of things I would like to know. So if you do, _please_ mail me. - Is there someone who would like to help me maintain this FAQ? Knowledge of CON hacking is required ofcourse. - Why is 'ifcansee' needed to let seekplayer and other ai function work properly? - Explenation of some of the ai functions. - What does ifnotmoving do in fact? Is this neccesary due to a bug in the ai functions? -------------------------------------------------------------------------- 5.2 Contributers/Thank you's -------------------------------------------------------------------------- I want to thank: - Reptile ( reptile@ <http://> ) - Linkers ( linkers@, <http://> ) for introducing me to Duke Nukem 3D as it is the funest game I've ever seen (yeah, that also means more fun than Quake!). -------------------------------------------------------------------------- 5.3 Update and info -------------------------------------------------------------------------- An update of this FAQ will come within a week of release. I hope all of you guys will send me lots of mail within that week, so I can make the FAQ better. Also, I want to say, that even if it sounds that I know every- thing, I know I don't. Please don't blame me for saying things that are incorrect. The right thing to do is to mail me and correct me. It will be corrected in the FAQ right away. Also there are some things, I'd like to know more about. So if you have any info and CON hacking, don't hesitate to mail me at antiwin@worldonline.nl -------------------------------------------------------------------------- 5.4 Where to get this FAQ -------------------------------------------------------------------------- I hope you can soon download this FAQ from many Duke 3D sites. An update of this FAQ is posted _at least_ once a week in the following newsgroups: alt.games alt.games.apogee alt.games.duke3d