Welcome to peewee's newbie to C programming for quake2 mods tutorial This will be full of typos and bad puncuation, but I will try hard to keep all of the code segments in full context and typo free! this only consists of simple easy commands that programming experts expect you to know already! ***The 1st thing is to do some simple c syntax*** ## declaring variables ## int imanumber; //declares "imanumber" as an integer float ihatedecimals; //declares "ihatedecimals" as a "float" or number with decimals char alphebet; //declares "alphabet" as a single character, like a letter(y) or symbol(&) string sentence; //declares "sentence" as a whole line of characters, like a sentence ## arrays ## char letters[4]; //makes a variable that holds 4 letters int numbers[5]={45,78,90,32,35}; //array of numbers with set values ## variable values ## integer1 = 10; //makes the value into 10 integer1 += 2; //adds 2 to integer1, making it from 10 into 12 integer *= 2 //multiplies integer1 by 2, same idea as "-=" subtracts "/=" divides etc.. string1 = "I'm a sentence!"; // makes string one hole "I'm a sentence!" ## if conditions ## if (variable1 == 5) //if variable1 is equal to 5 then { variable2 = 67; //make variable2 into 67 } if (variable1 < 5) //if variable1 is less than 5 if (variable1 > 5) //if variable1 is grater than 5 if (variable1 <= 5) //if variable1 is less than or equale to 5 if (!(variable1 == 5)) //if "variable1 equals 5" is false if (variable1 < 5 && variable1 is > 2) //if variable1 is less than 5 AND greater than 2 ***I'm now gonna do a small overveiw of what the different files are for: (not very reliable, but can give you some help)*** g_ai.c (controls the monsters) g_chase.c (tells monsters who to folow and when to be alerted) g_cmds.c (tells the game what commands to have and what they do) g_combat.c (movement and stuff) g_func.c (fun one! controls what doors and walls in levels do) g_items.c (tells game what items there are) g_main.c (misc things, not used much) g_misc.c (even more misc things, used a little more) g_monster.c (basicly same as g_chase.c and g_ai.c) g_phys.c (this is what tells quake2 what to do with like dmge and dodging) g_save.c (don't know, think it controls certain menu comands) g_spawn.c (don't known) g_svcmds.c (commands only host uses, like sv_gravity) g_target.c (like g_func.c but more specific) g_trigger.c (ditto) g_turret.c (ditto again) g_utils.c (don't know but it's very usefull) g_weapon.c (tells the game what happens when diff shot types are fired) m_?????.c (g_weapons, p_weapons, and p_client for monsters) p_client.c (too much to say, basicly death message to ammo limits) p_hud.c (the Heads Up Display, this tells quake to display stuff on screen) p_trail.c (don't know, probably like g_chase.c) p_veiw.c (controls color changes and screen moving for diff things) p_weapon.c (is the file that connects g_items.c to g_weapons.c) q_shared.c (ties things together like p_weapons and defines things) g_local.h (ditto) q_shared.h (ditto again) If i didn't know one of these, then u probobly won't use it While i'm explainging actuall code i'll put /* =-= comment =-=*/ for MY comments, more =-='s may be added in accordence to its importance O.K. 1st of all we will start off with changing the amount of ammo that a gun uses: As it looks in g_items.c at the part actually telling u the item is in the game ============================================================= /*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) */ { "weapon_machinegun", /*=-=defines which section in p_weapon.c to use=-=*/ Pickup_Weapon, Use_Weapon, Drop_Weapon, Weapon_Machinegun, "misc/w_pkup.wav", "models/weapons/g_machn/tris.md2", EF_ROTATE, /*=-=here is the weapon that you see in the level when you're going to pick it up=-=*/ "models/weapons/v_machn/tris.md2",/*=-=here is the weapon you see in your vision=-=*/ /* icon */ "w_machinegun", /*=-=now here is that little icon that appears in inventory=-=*/ /* pickup */ "Machinegun", 0, /*=-=-=-=-=-=-= below here the number "1" is what most would believe as what the gun actually uses for ammo, but this is at what the gun switches because it is outa ammo!=-=-=-=-=-=-=*/ 1, "Bullets", /*=-= this is the ammo that it uses, this is usefull if u wanna use diff ammo type look below to the ammo part that looks kinda like this=-=*/ IT_WEAPON|IT_STAY_COOP, WEAP_MACHINEGUN, /*=-=not all tuts have this if not, add it then go to g_local.h and add #define WEAP_??? to the list already there near the top=-=*/ NULL, /*=-=change to 0 if this EXACT line gives u probs at compiling=-=*/ 0, /*=-=don't play wit this=-=*/ /* precache */ "weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav" //don't play with above sounds, it don't work u gotta do it in the g_weapons.c }, ============================================================= ok now if you want to change the ammo you use, u gotta do it in either p_weapons.c or g_weapons.c like for bfg go to p_weapons.c and near the bottom of void weapon_bfg_fire, find ============================================================= ent->client->ps.gunframe++; PlayerNoise(ent, start, PNOISE_WEAPON); /*=-= above 2 lines are just for refernce, don't change them! =-=*/ if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) ) ent->client->pers.inventory[ent->client->ammo_index] -= 50; /*=-=-=-= the 50 right above is the ammo it uses, change that and the one in g_items accordingly =-=-=-=*/ /*=-= DON'T FORGET TO SCROLL UP TO "void NoAmmoWeaponChange" and make the apropriate adjustments like so=-=*/ if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))] /*=-= so far here says to check for any slugs whatsoever =-=*/ && ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] ) { ent->client->newweapon = FindItem ("railgun"); return; } /*=-= say you have the railgun use 3 shells instead of 1 slugs change the 1st line to this =-=*/ if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells")) > 2] /*=-= notice the change in "slugs" to "shells" is all it takes to switch ammo type, also use standard program procedure on the ammochange value.. >2 means 3 and up >=2 means 2 and up and so on... =-=*/ /*=-= you can also add weapons.. notice that rocket launcher is not in the list, this was left out so that you don't blow yourself up if you run out of railgun ammo.. but to add it.. find this section (and order matters from top to bttom)=-=*/ if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))] && ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] ) { ent->client->newweapon = FindItem ("railgun"); return; } /*=-= and add this below it =-=*/ if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("rockets"))] && ent->client->pers.inventory[ITEM_INDEX(FindItem("rocket launcher"))] ) { ent->client->newweapon = FindItem ("rocket launcher"); return; } /*=-= now if you run out of cells or slugs, you'll go straight to rocketlauncher instead of to chaingun =-=*/ ============================================================= //===================================================== //******************* Wow, an update!****************** //Oct. 25, 2002 //===================================================== //**************Sending messages!********************\\ //First now, we'll show how to display a message //I use this mostly to tell you what weapon you're using if I make a //new one //Here's the simple command: gi.cprintf(ent->owner, PRINT_HIGH, "Hello, I'm talking Tina And I want to kill you!\n"); //I'll break it down/ //g.cprint() is the command to say "Hey write this!" //that "ent->owner" is who receives the message. //ent->owner is from g_weapon, I think it was blaster this time. //anyway! You can use other things like "self", "other", or just "ent" //dependiong on what is defined as what. //In g_weapons ent (sometimes "self) is usually the bullet being shot //and ent->owner (self->owner) is usually the person who shot it //other is generally the one you hit. //exceptions include railgun, self->owner is guy who shot it. //tr.ent is the guy you hit //Lastly, in qoutes is your message.. , the "\n" is a carriage return //for practice let's make it taunt someone you hit with blaster //goto g_weapon.c.. under "Blaster_touch" where it says if (other->takedamage) { if (self->spawnflags & 1) mod = MOD_HYPERBLASTER; else mod = MOD_BLASTER; T_Damage (other, self, self->owner, self->velocity,self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod); } // //Now change it to this // if (other->takedamage) { if (self->spawnflags & 1) mod = MOD_HYPERBLASTER; else mod = MOD_BLASTER; T_Damage (other, self, self->owner,self->velocity,self->s.origin,plane->normal,self->dmg, 1,DAMAGE_ENERGY, mod); //pEwE -- added to print message gi.cprintf(other, PRINT_HIGH, "Loser! You got hit with a friggen blaster!\n"); } //great, now you can tick off the poor sucker you just hit with your pea shooter // ---pEwE //*******************damage and weapon speed************* //********damage************ //Here's pretty basic tweaks, very usefull //This is all done in p_weapon.c, makes it easy //Let's start with rocket. Because You're probobly gonna want to up it's dmg //and make it ungodly fast.. I can't believe I'm teaching you how to do it! //anyway! The at the top of "void Weapon_RocketLauncher_Fire (edict_t *ent)" //there are 3 damage variables for rocket: damage, damage_radius, and radius_damage. //damage is what is taken away on a direct hit //radius_damage is mow much a person is hurt by the explosion //damage_radius is how far from the center the radius damage reaches //It's pretty self explainitory, change this: damage = 140 + (int)(random() * 20.0); radius_damage = 150; damage_radius = 150; //Other weapons like machinegun, and railgun, have a "kick" //Kick is how far a person that you shoot will get knocked back //basically same thing, change this: int kick = 2; //*********weapon speeds********** //Here's one I like, I always make guns take longer to shoot.. more fair //Easiest example would probobly be railgun, lets take a look //At the bottom of weach "weaponname_fire" theres a "Weapon_Weaponname" //This is what is actually called by g_items.c, and that calls //the "weaponname_fire" according to what frame the weapon is on void Weapon_Railgun (edict_t *ent) { static int pause_frames[] = {56, 0}; static int fire_frames[] = {4, 0}; Weapon_Generic (ent, 3, 22, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); } //in the "Weapon_Generic" the 2nd number after "ent" is how long firing lasts //railgun goes 22 frames before you can fire again //say you want railgun to shoot faster, you can make it only take 10 frames: Weapon_Generic (ent, 3, 10, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); //This will shoot more than twice as fast //or raise the frames to 40 Weapon_Generic (ent, 3, 40, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); //this will make it almsot twice as slow //the other numbers are different things like, 3 is the frame to start on //where it says "static int fire_frames" is which frame it shoots on //If you make the 1st number above what it fires on, it won't shoot Weapon_Generic (ent, 5, 22, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); //that will skip over firing, and jsut ocntinually do nothing shoot //also you can't change the total time above the pause frames //pause frames are rames between firing //if you make the 2nd number go above the pause frames, fun things happen Weapon_Generic (ent, 5, 57, 56, 61, pause_frames, fire_frames, weapon_railgun_fire); //won't work, it'll do weird things //possibly keep you from switching weapons //more than likely keep you from shooting more than once //definitly mix up the frames, say look like it shoots when it is idleing //Now you know some more basics. I'll update some other time //************************************************************ //***************Hey look, it's another time!***************** //************************************************************ //April 16, 03 - what a freqent updating process! //Well, Blurry asked me about how I put the AOL CD Launcher in pwmod //This is a perfect example to follow the last 2 tuts. //The changes are mostly simple but later made more advanced to fit the mod //The real 1st big change was that I changed the blaster bolt //In g_weapons.c under fire_blaster() it describes the blaster object bolt->solid = SOLID_BBOX; bolt->s.effects |= effect; VectorClear (bolt->mins); VectorClear (bolt->maxs); bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2"); bolt->s.sound = gi.soundindex ("misc/lasfly.wav"); //This is just a small section, but I think you get the idea //You'll notice the line bolt->s.effects |= effect; //this is the partical trail that follows the weapon //For the blaster, it's determined in p_weapon and passed to g_weapon //but you can change it here to say EF_ROCKET //The way a hyperblaster works, the effect is a 0 (nothing) anyway so dont worry //but this line bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2"); //is the bolt model, this is that little yellow spegghetti looking thing the blaster shoots //using your trusty pak extracter (if you dont have one, search for one, or ask me) //you can find a new model to use as the bolt, I used a cd for the aol gun // "models/items/keys/data_cd/tris.md2" is the cd model //One extra effect used is rotating. //Just change the s.effect to "EF_ROTATE" like so bolt->s.effects |= EF_ROTATE; //and your cd now spins //You can expiriment by changeing the effects and models //Look inside q_shared.h and you'll find a big list of effects to use //One last change to the g_weapons is that the bolt needs to bounce //There are a few things you need to change. First, the movetype "fly missle" //is made to die when it hits a wall, so you needed to change bolt->movetype = MOVETYPE_FLYMISSLE; //to bolt->movetype = MOVETYPE_BOUNCE; //This is the movetype that the grenades use to bounce off of walls. //It's rather prmitive as it us, but it works //Personally I used a qdevels tut to create a new movetype for bouncing, but thats later //The last change is the touch. Right now, the bolt will stil hit a wall and die //We need to fix this. //goto blaster_touch() and change { int mod; if (other == self->owner) return; if (surf && (surf->flags & SURF_SKY)) { G_FreeEdict (self); return; } if (self->owner->client) PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); if (other->takedamage) { if (self->spawnflags & 1) mod = MOD_HYPERBLASTER; else mod = MOD_BLASTER; T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod); } else { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BLASTER); gi.WritePosition (self->s.origin); if (!plane) gi.WriteDir (vec3_origin); else gi.WriteDir (plane->normal); gi.multicast (self->s.origin, MULTICAST_PVS); } G_FreeEdict (self); } //to { if (other == self->owner) return; if (self->owner->client) PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); if (other->takedamage) { T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, 0, MOD_HYPERBLASTER); } else { return; } G_FreeEdict (self); } //as it is, this took out the lines to die on walls and to die on skys //now there' 2 small little tweaks you may want to make. //Right now the blaster only shoots at 1000, this is about teh same speed as a grenade launcher //and won't shoot much farther than one //so visit p_weapons.c and take a look at the line under Blaster_Fire() //that says fire_blaster (ent, start, forward, damage, 1000, effect, hyper); //the number 1000 next to damage and effect is the bolts speed //this is what you raise to make the bolt shoot faster and farther //don't raise it above 2000 or below 1 or else the bolt will do insane crazy things //Very last thing is to change the bolts time //Bolts only last in the world a certain time limit, default is 2 seconds //You may want to raise it or lower it depending on how long you want the bolt to bounce //You'll always want a time limit so the game doesnt lag or crash //now go back to g_weapons.c and get back to fire_blaster() bolt->nextthink = level.time + 2; //the + 2 after level.time is how long the bolt stays around //Rasie it or lower it how you see fit. //@@@@@That's it until next time@@@@@ //--------------------------------------------------------------------------------- //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //--------------------------------------------------------------------------------- //Once again, blurry wants a tut, so here's the phoenix rocket. //The biggest thing about the phoenix different from a normal arocket is the use of //new aiming vectors borrowed from the supper shotgun.. //Let's look at the code from supershotgun that does this inside p_weapon.c: v[PITCH] = ent->client->v_angle[PITCH]; v[YAW] = ent->client->v_angle[YAW]; v[ROLL] = ent->client->v_angle[ROLL]; AngleVectors (v, forward, NULL, NULL); fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SUPERSHOTGUN); v[YAW] = ent->client->v_angle[YAW] + 5; AngleVectors (v, forward, NULL, NULL); fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SUPERSHOTGUN); //This little section of code adds to the angle of the shot, PITCH being vertical //and YAW being horizontal. All you have to do is copy this code into another weapon //say blaster (to make it easiest) //goto the: fire_blaster (ent, start, forward, damage, 1000, 0, 0); //line under Blaster_Fire //Now above it add so it looks like this: v[PITCH] = ent->client->v_angle[PITCH]; v[YAW] = ent->client->v_angle[YAW]; v[ROLL] = ent->client->v_angle[ROLL]; AngleVectors (v, forward, NULL, NULL); fire_blaster (ent, start, forward, damage, 1000, 0, 0); //these just tell the game to do default angles. //Now lets shoot one up and to the right of this, make this line underneath v[PITCH] = ent->client->v_angle[PITCH] + 5; v[YAW] = ent->client->v_angle[YAW] + 5; AngleVectors (v, forward, NULL, NULL); fire_blaster (ent, start, forward, damage, 1000, 0, 0); //and then one up and left v[PITCH] = ent->client->v_angle[PITCH] + 5; v[YAW] = ent->client->v_angle[YAW] - 5; AngleVectors (v, forward, NULL, NULL); fire_blaster (ent, start, forward, damage, 1000, 0, 0); //Basically, do this until you have as many shots as you want where you want //Lastly, you'll need to declare an extra variable at the top, so above: vec3_t forward, right; //add: vec3_t v; //and you're done.. run it and have fun