void() W_SetCurrentAmmo; /* ALL LIGHTS SHOULD BE 0 1 0 IN COLOR ALL OTHER ITEMS SHOULD BE .8 .3 .4 IN COLOR */ void() SUB_regen = { self.model = self.mdl; // restore original model self.solid = SOLID_TRIGGER; // allow it to be touched again sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); // play respawn sound setorigin (self, self.origin); // Supa pickup glow fix begin if (deathmatch) { if (self.classname == "item_artifact_invulnerability") self.effects = self.effects | EF_RED; if (self.classname == "item_artifact_super_damage") self.effects = self.effects | EF_BLUE; } // Supa pickup glow fix end }; // Supa, Quoth respawning items support // Respawn item like in DM if 'ritem' TRUE, override respawn time with 'respawndelay' if set, inc 'cnt' with each respawn and if 'respawncount' is set we'll remove the item if cnt > respawncount // remember that SUB_Regen is already set on every item that can respawn, all we need to do is give a nextthink time in order to trigger it .float ritem, respawndelay, respawncount; void(entity whatitem, float defaultdelay) CheckItemRespawn = { if (!whatitem.ritem) // respawn item if true, otherwise abort return; whatitem.cnt = whatitem.cnt + 1; // inc before check to account for zero indexing if (whatitem.respawncount ) // limited respawns if (whatitem.respawncount < whatitem.cnt) return; // okay, we're clear to set up a respawn if (whatitem.respawndelay) // custom respawn delay? whatitem.nextthink = time + whatitem.respawndelay; else whatitem.nextthink = time + defaultdelay; }; /*QUAKED noclass (0 0 0) (-8 -8 -8) (8 8 8) prints a warning message when spawned */ void() noclass = { dprint ("noclass spawned at"); dprint (vtos(self.origin)); dprint ("\n"); remove (self); }; void () misc_crystal_think; // gb /* ============ DelaySpawnItem Makes a SPAWNED item ready for pickup on a trigger event ============ */ void() DelaySpawnItem = { self.solid = SOLID_TRIGGER; setmodel (self, self.mdl); setsize (self, self.pos1, self.pos2); if (self.model == "progs/gb_crystal.mdl") // gb, the crystal keyitem { self.think = misc_crystal_think; // do the light show self.nextthink = time + 0.1; self.effects = EF_DIMLIGHT; } if (!(self.spawnflags & 32)) // SILENT, gb sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); self.use = SUB_Null; }; // Supa, restore old hull and lock movement void() RefreshHull = { setsize (self, self.dest, self.dest2); self.movetype = MOVETYPE_NONE; self.velocity = '0 0 0'; }; /* ============ PlaceItem plants the object on the floor ============ */ void() PlaceItem = { local float oldz; if ((self.spawnflags & 128)) //ijed Don't drop spawnflag { self.mdl = self.model; // so it can be restored on respawn self.flags = FL_ITEM; // make extra wide self.solid = SOLID_TRIGGER; self.movetype = MOVETYPE_FLY; self.velocity = '0 0 0'; } else { if (self.classname == "item_health" || self.classname == "item_stimpack" || self.classname == "item_armorshard" || self.classname == "flagbase" ) // Supa, CTF { // hacking around hull issues.. setsize (self, '0 0 0', '0 0 0'); // void hull for now self.think = RefreshHull; self.nextthink = time + 0.2; } self.mdl = self.model; // so it can be restored on respawn self.flags = FL_ITEM; // make extra wide self.solid = SOLID_TRIGGER; self.movetype = MOVETYPE_TOSS; self.velocity = '0 0 0'; setorigin (self, self.origin + '0 0 6'); if (self.model == "progs/gb_crystal.mdl") // energy crystal keyitem? { self.awake = 1; // start bobbing up self.ammo_shells = ceil(random(5)); // hopefully an int between 1 and 5 self.alpha = 0.75; self.effects = EF_DIMLIGHT; self.think = misc_crystal_think; self.nextthink = time + 0.2; } // oldz = self.origin_z; if (!droptofloor()) { print_self ("bonus item", "fell out of level"); remove(self); return; } } if ((self.spawnflags & 64)) // SPAWNED, gb { self.pos1 = self.mins; self.pos2 = self.maxs; if (self.model == "progs/gb_crystal.mdl") { self.think = SUB_Null; // gb, stop the light show self.effects = 0; } self.model = ""; self.solid = SOLID_NOT; self.use = DelaySpawnItem; } }; /* ============ StartItem Sets the clipping size and plants the object on the floor ============ */ void() StartItem = { self.nextthink = time + 0.5; // gb, was 0.2 -- items start after other solids self.think = PlaceItem; }; /* ========================================================================= HEALTH BOX ========================================================================= */ // // T_Heal: add health to an entity, limiting health to max_health // "ignore" will ignore max_health limit // // DRS: Revised Health System stuff. Also note that max_health barrier on megahealth is now // max_health * 2. void (entity e, float healamount, float ignore) T_Heal = { healamount = ceil(healamount); e.health = e.health + healamount; if ((!ignore) && (e.health >= e.max_health)) e.health = e.max_health; if (e.health > rint(e.max_health*2)) e.health = rint(e.max_health*2); // Megahealth = rot down the player's super health if (ignore == 1) { // Supa, no longer needed // e.items = e.items | IT_SUPERHEALTH; if (e.rottime < time) e.rottime = time + 5; } // Supa, check for Rage stop threshold and remove Rage if equal/over it if (e.is_raged) if (e.health >= RAGE_THRESHOLD_STOP) Rage_Toggle(e); }; /*QUAKED item_health (.3 .3 1) (0 0 0) (32 32 32) rotten megahealth Health box. Normally gives 25 points. Rotten box heals 10-20 points, megahealth will add 100 health */ float H_ROTTEN = 1; float H_MEGA = 2; .float healamount, healtype; void() health_touch; void() MHRot = { if(self.health <= self.max_health) { self.items = self.items - (other.items & IT_SUPERHEALTH); return; } self.health = self.health - 1; self.rottime = time + 1; }; void() item_health_go = { self.touch = health_touch; // Supa, set size to item specified value setsize (self, self.dest, self.dest2); StartItem(); }; void() item_health = { // self.touch = health_touch; // Move the origin into the middle of the item for the purpose of // both using this item as a location as well, so that other things // appearing at its location look sensible, and also so that if this // appears at another location, it will position itself sensibly there. // // Simple version of the above: Place it in the editor so that the box // is in the right place, and this line takes care of the rest! self.originhack = '16 16 0'; // Supa, non-BSP models will void this if (self.spawnflags & H_MEGA) //ijed Revised health item for worldtype set models { precache_sound("items/r_item2.wav"); self.noise = "items/r_item2.wav"; self.healamount = 100; self.healtype = 1; if (world.worldtype == 0) { precache_model("progs/health0m.mdl"); //ijed Medievel MegaJar setmodel(self, "progs/health0m.mdl"); // setsize (self, '0 0 0', '32 32 56'); self.dest = '0 0 0'; self.dest2 = '32 32 32'; self.originhack = '0 0 0'; setorigin (self, self.origin + '16 16 0'); // Supa, mangle^Wcorrect the origin for great justice^W^W^Wto account for the original bmodel offset } else if (world.worldtype == 1) { precache_model("maps/b_bh100.bsp"); //ijed runic is original for now setmodel(self, "maps/b_bh100.bsp"); // setsize (self, '0 0 0', '32 32 56'); self.dest = '0 0 0'; self.dest2 = '32 32 32'; } else if (world.worldtype == 2) { precache_model("progs/health2m.mdl"); //ijed Base version finally in setmodel(self, "progs/health2m.mdl"); // setsize (self, '0 0 0', '32 32 56'); self.dest = '0 0 0'; self.dest2 = '32 32 32'; self.originhack = '0 0 0'; setorigin (self, self.origin + '16 16 0'); // Supa, mangle^Wcorrect the origin for great justice^W^W^Wto account for the original bmodel offset } } else { precache_sound("items/r_item1.wav"); self.noise = "items/r_item1.wav"; self.healtype = 0; if (self.spawnflags & H_ROTTEN) self.healamount = floor(random() * 10 + 10); //ijed Randomised rotten health else self.healamount = 25; if (world.worldtype == 0) { precache_model ("progs/health0.mdl"); //ijed medievel health flask setmodel (self, "progs/health0.mdl"); // setsize (self, '0 0 0', '32 32 56'); self.dest = '-16 -16 0'; self.dest2 = '16 16 32'; self.originhack = '0 0 0'; setorigin (self, self.origin + '16 16 0'); } else if (world.worldtype == 1) { precache_model ("progs/health0.mdl"); //ijed Waiting for runic model setmodel (self, "progs/health0.mdl"); // setsize (self, '0 0 0', '32 32 56'); self.dest = '0 0 0'; self.dest2 = '32 32 32'; self.originhack = '0 0 0'; setorigin (self, self.origin + '16 16 0'); } else if (world.worldtype == 2) { precache_model ("progs/health2.mdl"); //ijed Square base health pack setmodel (self, "progs/health2.mdl"); // setsize (self, '0 0 0', '32 32 56'); self.dest = '0 0 0'; self.dest2 = '32 32 32'; self.originhack = '0 0 0'; setorigin (self, self.origin + '16 16 0'); } } self.go = item_health_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_stimpack (.3 .3 1) (-16 -16 0) (16 16 32) */ // DRS: Stimpack. Easy as pie. Mmmm....Pie...*drools* void() item_stimpack = { // self.touch = health_touch; if (world.worldtype == 0) { precache_model ("progs/health0s.mdl"); //ijed Medievel health vial setmodel (self, "progs/health0s.mdl"); // setsize (self, '-16 -16 0', '16 16 56'); } else if (world.worldtype == 1) { precache_model ("progs/health0s.mdl"); //ijed Runic Placeholder setmodel (self, "progs/health0s.mdl"); // setsize (self, '-16 -16 0', '16 16 56'); } else if (world.worldtype == 2) { precache_model ("progs/health2s.mdl"); //ijed Tech Placeholder setmodel (self, "progs/health2s.mdl"); // setsize (self, '-16 -16 0', '16 16 56'); } self.dest = '-16 -16 0'; self.dest2 = '16 16 32'; precache_sound("items/r_item1.wav"); self.noise = "items/r_item1.wav"; self.healamount = 5; // RMQ team vote, was 2 self.healtype = 2; // 2 is no megahealth rot. // Set to 1 if rot desired. Set to 0 to lock to maxheath self.go = item_health_go; if(!CheckGroup()) self.go(); }; void() health_touch = { local float amount; local string s; if (other.classname != "player") return; //dprint(ftos(other.max_health)); ijed Disabled for now because was blocking other messages //dprint(" Max Health\n"); if(self.healtype == 0 && other.health >= other.max_health) return; amount = self.healamount; if (self.healtype > 0) // Megahealth? Ignore max_health... { if (other.health >= rint(other.max_health*2)) return; T_Heal(other, amount, self.healtype); } else T_Heal(other, amount, 0); sprint(other, "You receive "); s = ftos(amount); sprint(other, s); sprint(other, " health\n"); // health touch sound if (self.healtype > 0) // MH sound(other, CHAN_ITEM, self.noise, 1, ATTN_NONE); // gb, was NORM else sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); stuffcmd (other, "bf\n"); self.model = string_null; self.solid = SOLID_NOT; /* // if (deathmatch != 2) // deathmatch 2 is the silly old rules if (deathmatch == 1) { // if (deathmatch) // Supa self.nextthink = time + 20; self.think = SUB_regen; } if (deathmatch == 3) // gb { // if (deathmatch) // Supa self.nextthink = time + 15; self.think = SUB_regen; } */ // Supa, SP respawning items support if (!deathmatch) CheckItemRespawn(self, 20); // Supa, gametype specific respawn times if (gametype) switch (gametype) { case FFA: {self.nextthink = time + 20; } break; case DUEL: {self.nextthink = time + 20; } break; case TDM: {self.nextthink = time + 20; } break; case TDM_FF: {self.nextthink = time + 20; } break; case CTF: {self.nextthink = time + 20; } break; case CTF_FF: {self.nextthink = time + 20; } break; default: { bprint("health_touch: Gametype initialisation failed!\n"); } break; } self.think = SUB_regen; activator = other; SUB_UseTargets(); // fire all targets / killtargets }; /* =============================================================================== ARMOR =============================================================================== */ void() armor_touch; void() shard_touch; void() armor_touch = { local float type, value, bit; if (other.health <= 0) return; if (other.classname != "player") return; if (self.classname == "item_armor1") { type = 0.3; value = 100; bit = IT_ARMOR1; } if (self.classname == "item_armor2") { type = 0.6; value = 150; bit = IT_ARMOR2; } if (self.classname == "item_armorInv") { type = 0.8; value = 200; bit = IT_ARMOR3; } if (other.armortype*other.armorvalue >= type*value) return; other.armortype = type; other.armorvalue = value; other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + bit; self.solid = SOLID_NOT; self.model = string_null; /* if (deathmatch == 1) { self.nextthink = time + 20; self.think = SUB_regen; } if (deathmatch == 3) // gb { self.nextthink = time + 30; self.think = SUB_regen; } */ // Supa, SP respawning items support if (!deathmatch) CheckItemRespawn(self, 30); // Supa, gametype specific respawn times if (gametype) switch (gametype) { case FFA: {self.nextthink = time + 30; } break; case DUEL: {self.nextthink = time + 30; } break; case TDM: {self.nextthink = time + 30; } break; case TDM_FF: {self.nextthink = time + 30; } break; case CTF: {self.nextthink = time + 30; } break; case CTF_FF: {self.nextthink = time + 30; } break; default: { bprint("armor_touch: Gametype initialisation failed!\n"); } break; } self.think = SUB_regen; sprint(other, "You got armor\n"); // armor touch sound sound(other, CHAN_ITEM, "items/armor1.wav", 1, ATTN_NORM); // gb, NONE? stuffcmd (other, "bf\n"); activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() shard_touch = { local float bit; if (other.health <= 0) return; if (other.classname != "player") return; if ((other.items & IT_ARMOR1) || (other.items & IT_ARMOR2) || (other.items & IT_ARMOR3) ) // has armor { // Supa, check bounds, original armourvalue + 25 if (other.items & IT_ARMOR1 && other.armorvalue >= 125) return; if (other.items & IT_ARMOR2 && other.armorvalue >= 175) return; if (other.items & IT_ARMOR3 && other.armorvalue >= 225) return; other.armorvalue = other.armorvalue + 5; // was 2, RMQ team // Supa, now cap armourvalue to bounds if (other.items & IT_ARMOR1 && other.armorvalue >= 125) other.armorvalue = 125; else if (other.items & IT_ARMOR2 && other.armorvalue >= 175) other.armorvalue = 175; else if (other.items & IT_ARMOR3 && other.armorvalue >= 225) other.armorvalue = 225; } else { other.armortype = 0.3; // GA other.armorvalue = 5; // 2 bit = IT_ARMOR1; other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + bit; } self.solid = SOLID_NOT; self.model = string_null; /* if (deathmatch == 1) { self.nextthink = time + 20; self.think = SUB_regen; } if (deathmatch == 3) // gb { self.nextthink = time + 30; self.think = SUB_regen; } */ // Supa, SP respawning items support if (!deathmatch) CheckItemRespawn(self, 30); // Supa, gametype specific respawn times if (gametype) switch (gametype) { case FFA: {self.nextthink = time + 30; } break; case DUEL: {self.nextthink = time + 30; } break; case TDM: {self.nextthink = time + 30; } break; case TDM_FF: {self.nextthink = time + 30; } break; case CTF: {self.nextthink = time + 30; } break; case CTF_FF: {self.nextthink = time + 30; } break; default: { bprint("shard_touch: Gametype initialisation failed!\n"); } break; } // Supa, oh ack oh ack oh ack // the LavaMonitor logic is utterly breaking knight-dropped armour shards because the // various item pickup functions have no way to tell if the item was spawned as a result // of a deathdrop, which would mean the item is set to check for lava Very Often and // thusly has a nextthink of Very Soon which *BREATHE* means that the shard will trigger // a respawn almost immediately, since it still has a nextthink set which was intended for // the LavaMontior!!!1111 *THUNK* if (self.classname != "armorshard") // classname set for Knight deathdrop shards self.think = SUB_regen; sprint(other, "You got armor\n"); // armor touch sound, pickup flash sound(other, CHAN_ITEM, "items/armor1.wav", 1, ATTN_NORM); // gb, NONE? stuffcmd (other, "bf\n"); activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() item_armor_go = { if (self.classname == "item_armorshard") self.touch = shard_touch; else self.touch = armor_touch; setsize (self, '-16 -16 0', '16 16 56'); StartItem (); }; /*QUAKED item_armor1 (0 .5 .8) (-16 -16 0) (16 16 32) */ void() item_armor1 = { precache_model ("progs/armor.mdl"); setmodel (self, "progs/armor.mdl"); self.skin = 0; self.go = item_armor_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_armor2 (0 .5 .8) (-16 -16 0) (16 16 32) */ void() item_armor2 = { precache_model ("progs/armor.mdl"); setmodel (self, "progs/armor.mdl"); self.skin = 1; self.go = item_armor_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_armorInv (0 .5 .8) (-16 -16 0) (16 16 32) */ void() item_armorInv = { precache_model ("progs/armor.mdl"); setmodel (self, "progs/armor.mdl"); self.skin = 2; self.go = item_armor_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_armorshard (0 .5 .8) (-16 -16 0) (16 16 32) */ void() item_armorshard = { if (world.worldtype == 0) //ijed Sets shard model to worldtype model { precache_model ("progs/armorshard0.mdl"); setmodel (self, "progs/armorshard0.mdl"); } else if (world.worldtype == 1) { precache_model ("progs/armorshard1.mdl"); setmodel (self, "progs/armorshard1.mdl"); } else if (world.worldtype == 2) { precache_model ("progs/armorshard2.mdl"); setmodel (self, "progs/armorshard2.mdl"); } // self.touch = shard_touch; // setsize (self, '-16 -16 0', '16 16 56'); // StartItem (); // Supa, store old hull for placeitem self.dest = '-16 -16 0'; self.dest2 = '16 16 56'; self.go = item_armor_go; if(!CheckGroup()) self.go(); }; /* =============================================================================== WEAPONS =============================================================================== */ // LA: use global max ammo constants void() bound_other_ammo = { if (other.ammo_shells > MAX_SHELLS) //ijed Was 100 other.ammo_shells = MAX_SHELLS; if (other.ammo_nails > MAX_NAILS) other.ammo_nails = MAX_NAILS; if (other.ammo_rockets > MAX_ROCKETS) //ijed Was 100 other.ammo_rockets = MAX_ROCKETS; if (other.ammo_cells > MAX_CELLS) other.ammo_cells = MAX_CELLS; }; float(float w) RankForWeapon = { if (self.waterlevel <= 1 && w == IT_RAILGUN) return 1; if (self.waterlevel <= 1 && w == IT_LIGHTNING) return 2; if (w == IT_ROCKET_LAUNCHER) return 3; if (w == IT_SUPER_NAILGUN) return 4; if (w == IT_GRENADE_LAUNCHER) return 5; if (w == IT_SUPER_SHOTGUN) return 6; if (w == IT_NAILGUN) return 7; return 8; }; /* ============= Deathmatch_Weapon Deathmatch weapon change rules for picking up a weapon .float ammo_shells, ammo_nails, ammo_rockets, ammo_cells; ============= */ void(float old, float new) Deathmatch_Weapon = { local float or, nr; // change self.weapon if desired or = RankForWeapon (self.weapon); nr = RankForWeapon (new); if ( nr < or ) self.weapon = new; }; /* ============= weapon_touch ============= */ float() W_BestWeapon; void() weapon_touch = { local float hadammo, best, new, new2, old; local entity stemp; local float leave; if (other.health <= 0) return; if (!(other.flags & FL_CLIENT)) return; // if the player was using his best weapon, change up to the new one if better stemp = self; self = other; best = W_BestWeapon(); self = stemp; // if (deathmatch == 2 || deathmatch == 3 || coop) // gb, deathmatch 3 support // gb, deathmatch 3 support if (gametype == FFA || coop ) leave = 1; else leave = 0; if (self.classname == "weapon_nailgun") { if (leave && (other.items & IT_NAILGUN) ) return; hadammo = other.ammo_nails; new = IT_NAILGUN; other.ammo_nails = other.ammo_nails + 30; } else if (self.classname == "weapon_blaster") // ijed, replaces NG with the Blaster { if (leave && (other.items2 & IT_BLASTER)) return; hadammo = other.ammo_rockets; new = IT_NAILGUN; new2 = IT_BLASTER; other.ammo_cells = other.ammo_cells + 12; } else if (self.classname == "weapon_supernailgun") { if (leave && (other.items & IT_SUPER_NAILGUN) ) return; hadammo = other.ammo_rockets; new = IT_SUPER_NAILGUN; other.ammo_nails = other.ammo_nails + 30; } else if (self.classname == "weapon_impacthammer") // gb, E1 Impact Hammer { if (leave && (other.items2 & IT_IMPACT) ) // ! return; hadammo = other.ammo_rockets; new = IT_SUPER_SHOTGUN; new2 = IT_IMPACT; // !! other.ammo_shells = other.ammo_shells + 5; } else if (self.classname == "weapon_supershotgun") { if (leave) if (other.items & IT_SUPER_SHOTGUN ) if (!(other.items2 & IT_IMPACT) ) // ! if (!(other.items2 & IT_SHREDDER) ) return; hadammo = other.ammo_rockets; new = IT_SUPER_SHOTGUN; other.ammo_shells = other.ammo_shells + 5; } else if (self.classname == "weapon_shredder") // Supa, replaces SSG with the Shredder { if (leave && (other.items2 & IT_SHREDDER)) return; hadammo = other.ammo_rockets; new = IT_SUPER_SHOTGUN; new2 = IT_SHREDDER; other.ammo_shells = other.ammo_shells + 9; } else if (self.classname == "weapon_rocketlauncher") { if (leave && (other.items & IT_ROCKET_LAUNCHER) ) return; hadammo = other.ammo_rockets; new = IT_ROCKET_LAUNCHER; other.ammo_rockets = other.ammo_rockets + 5; } else if (self.classname == "weapon_grenadelauncher") { if (leave && (other.items & IT_GRENADE_LAUNCHER) ) return; hadammo = other.ammo_rockets; new = IT_GRENADE_LAUNCHER; other.ammo_rockets = other.ammo_rockets + 5; } else if (self.classname == "weapon_lightning") { if (leave && (other.items & IT_LIGHTNING) ) return; hadammo = other.ammo_rockets; new = IT_LIGHTNING; other.ammo_cells = other.ammo_cells + 15; } else if (self.classname == "weapon_railgun") { if (leave && (other.items & IT_RAILGUN) ) return; hadammo = other.ammo_rockets; new = IT_RAILGUN; other.ammo_cells = other.ammo_cells + 12; } else if (self.classname == "weapon_axe") // gb, E1 old axe, not chainsaw { if (leave && (other.items2 & IT_OLDAXE) ) // ! return; new = IT_AXE; new2 = IT_OLDAXE; // !! } else if (self.classname == "weapon_chainsaw") { if (leave && (other.items & IT_AXE) && !(other.items2 & IT_OLDAXE) ) // ! return; new = IT_AXE; } else if (self.classname == "weapon_shotgun") { if (leave && (other.items & IT_SHOTGUN) ) return; hadammo = other.ammo_rockets; new = IT_SHOTGUN; other.ammo_shells = other.ammo_shells + 5; } else objerror ("weapon_touch: unknown classname"); sprint (other, "You got the "); sprint (other, self.netname); sprint (other, "\n"); // weapon touch sound if (self.classname == "weapon_axe") // gb sound (other, CHAN_ITEM, "weapons/pkup_axe.wav", 1, ATTN_NORM); // gb, NONE? else if (self.classname == "weapon_chainsaw") // gb sound (other, CHAN_ITEM, "weapons/pkup_saw.wav", 1, ATTN_NORM); // gb, NONE? else sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); // gb, NONE? stuffcmd (other, "bf\n"); bound_other_ammo (); // change to the weapon old = other.items; other.items = other.items | new; // gb, rmq stuff other.items2 = other.items2 | new2; // add weapons from .items2 // gb, need this to ensure chainsaw and oldaxe are mutually exclusive // ! the code gives you the axe once self.items2 & IT_OLDAXE; hence no need to do this the other way around if (self.classname == "weapon_chainsaw" && (other.items2 & IT_OLDAXE)) // picking up chainsaw, AND have oldaxe? other.items2 = other.items2 - IT_OLDAXE; // remove oldaxe if so // gb, same for Impact Hammer and SSG if (self.classname == "weapon_supershotgun") { if (other.items2 & IT_IMPACT) // picking up SSG, AND have Impact? other.items2 -= IT_IMPACT; // remove Impact if so // Supa, removes Shredder on pickup if you had one if (other.items2 & IT_SHREDDER) other.items2 -= IT_SHREDDER; } // Supa, same for the Blaster and Nailgun if (self.classname == "weapon_nailgun" && (other.items2 & IT_BLASTER)) other.items2 -= IT_BLASTER; stemp = self; self = other; // if (!deathmatch) // QIP fix by Maddes - do that in SP, too // self.weapon = new; // else Deathmatch_Weapon (old, new); W_SetCurrentAmmo(); self = stemp; if (leave) { if (self.state == 0) { activator = other; SUB_UseTargets (); self.state = 1; } return; } // remove it in single player, or setup for respawning in deathmatch self.model = string_null; self.solid = SOLID_NOT; /* if (deathmatch == 1) self.nextthink = time + 30; */ // Supa, SP respawning items support if (!deathmatch) CheckItemRespawn(self, 15); // Supa, gametype specific respawn times if (gametype) switch (gametype) { // case FFA: {self.nextthink = time + 15;} break; case DUEL: {self.nextthink = time + 15;} break; case TDM: {self.nextthink = time + 15;} break; case TDM_FF: {self.nextthink = time + 15;} break; case CTF: {self.nextthink = time + 5; } break; case CTF_FF: {self.nextthink = time + 5; } break; default: { bprint("weapon_touch: Gametype initialisation failed!\n"); } break; } self.think = SUB_regen; activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() weapon_go = { self.touch = weapon_touch; setsize (self, '-16 -16 0', '16 16 56'); StartItem (); }; /*QUAKED weapon_axe (0 .5 .8) (-16 -16 0) (16 16 32) */ // gb void() weapon_axe = { precache_model ("progs/g_axe.mdl"); setmodel (self, "progs/g_axe.mdl"); self.weapon = IT_AXE; self.netname = "Axe"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_chainsaw (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_chainsaw = { precache_model ("progs/g_saw.mdl"); setmodel (self, "progs/g_saw.mdl"); self.weapon = IT_AXE; self.netname = "Chainsaw"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_shotgun (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_shotgun = { precache_model ("progs/g_gun.mdl"); setmodel (self, "progs/g_gun.mdl"); self.weapon = IT_SHOTGUN; self.netname = "Shotgun"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_impacthammer (0 .5 .8) (-16 -16 0) (16 16 32) */ // gb void() weapon_impacthammer = { precache_model ("progs/g_shot.mdl"); setmodel (self, "progs/g_shot.mdl"); self.weapon = IT_SUPER_SHOTGUN; self.netname = "Impact Hammer"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_supershotgun (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_supershotgun = { precache_model ("progs/g_shot.mdl"); setmodel (self, "progs/g_shot.mdl"); self.weapon = IT_SUPER_SHOTGUN; self.netname = "Double-barrelled Shotgun"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_shredder (0 .5 .8) (-16 -16 0) (16 16 32) */ // Supa void() weapon_shredder = { precache_model ("progs/g_shredder.mdl"); setmodel (self, "progs/g_shredder.mdl"); self.weapon = IT_SUPER_SHOTGUN; self.netname = "Shredder! Find some meat!"; // 'You got the Shredder! Find some meat!' self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_nailgun (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_nailgun = { precache_model ("progs/g_nail.mdl"); setmodel (self, "progs/g_nail.mdl"); self.weapon = IT_NAILGUN; self.netname = "nailgun"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_blaster (0 .5 .8) (-16 -16 0) (16 16 32) */ // ijed void() weapon_blaster = { precache_model ("progs/g_blaster.mdl"); setmodel (self, "progs/g_blaster.mdl"); self.weapon = IT_NAILGUN; self.netname = "Blaster! Time for searing laser death!"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_supernailgun (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_supernailgun = { precache_model ("progs/g_nail2.mdl"); setmodel (self, "progs/g_nail2.mdl"); self.weapon = IT_SUPER_NAILGUN; self.netname = "Super Nailgun"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_grenadelauncher (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_grenadelauncher = { precache_model ("progs/g_rock.mdl"); setmodel (self, "progs/g_rock.mdl"); self.weapon = 3; self.netname = "Grenade Launcher"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_rocketlauncher (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_rocketlauncher = { precache_model ("progs/g_rock2.mdl"); setmodel (self, "progs/g_rock2.mdl"); self.weapon = 3; self.netname = "Rocket Launcher"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; /*QUAKED weapon_lightning (0 .5 .8) (-16 -16 0) (16 16 32) */ void() weapon_railgun; // Supa, totally-not-a-railgun, doot de doo doo.. void() weapon_lightning = { /* if (mapname == "dm6") // Supa, totally-not-a-railgun, replace LG on DM6 { self.classname = "weapon_railgun"; weapon_railgun(); return; } */ precache_model ("progs/g_light.mdl"); setmodel (self, "progs/g_light.mdl"); self.weapon = 3; self.netname = "Thunderbolt"; self.go = weapon_go; if(!CheckGroup()) self.go(); }; // Supa, totally-not-a-railgun void() weapon_railgun = { precache_model ("progs/g_caut.mdl"); //ijed test version in setmodel (self, "progs/g_caut.mdl"); self.weapon = 3; self.netname = "Cauteriser"; //ijed Well, it is now :) self.go = weapon_go; if(!CheckGroup()) self.go(); }; /* =============================================================================== AMMO =============================================================================== */ // LA: Re-written so that ammo boxes are not removed until fully depleted in SP // Leaving MP behaviour as before, because I think it's more correct there. void() ammo_touch = { local entity stemp; local float best; local float picked; // some ammo was picked up local float remaining; // there is some ammo still in the box if (other.classname != "player") return; if (other.health <= 0) return; // if the player was using his best weapon, change up to the new one if better stemp = self; self = other; best = W_BestWeapon(); self = stemp; picked = remaining = 0; // shells if (self.ammo_shells > 0) { if (other.ammo_shells < MAX_SHELLS) { other.ammo_shells = other.ammo_shells + self.ammo_shells; picked = 1; if (other.ammo_shells > MAX_SHELLS) { self.ammo_shells = other.ammo_shells - MAX_SHELLS; remaining = 1; } } else { remaining = 1; // since player is full, there is obviously some left in the box } } // nails if (self.ammo_nails > 0) { if (other.ammo_nails < MAX_NAILS) { other.ammo_nails = other.ammo_nails + self.ammo_nails; picked = 1; if (other.ammo_nails > MAX_NAILS) { self.ammo_nails = other.ammo_nails - MAX_NAILS; remaining = 1; } } else { remaining = 1; // since player is full... } } // rockets if (self.ammo_rockets > 0) { if (other.ammo_rockets < MAX_ROCKETS) { other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; picked = 1; if (other.ammo_rockets > MAX_ROCKETS) { self.ammo_rockets = other.ammo_rockets - MAX_ROCKETS; remaining = 1; } } else { remaining = 1; // since player is full... } } // cells if (self.ammo_cells > 0) { if (other.ammo_cells < MAX_CELLS) { other.ammo_cells = other.ammo_cells + self.ammo_cells; picked = 1; if (other.ammo_cells > MAX_CELLS) { self.ammo_cells = other.ammo_cells - MAX_CELLS; remaining = 1; } } else { remaining = 1; // since player is full... } } if (!picked) return; // Didn't pick anything up? Then sod off... if (deathmatch) remaining = 0; // in DM, take the whole box anyway bound_other_ammo (); if (remaining) { sprint (other, "You got some "); } else { sprint (other, "You got the "); } sprint (other, self.netname); sprint (other, "\n"); // ammo touch sound sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); // gb, NONE? stuffcmd (other, "bf\n"); // change to a better weapon if appropriate if ( other.weapon == best ) { stemp = self; self = other; self.weapon = W_BestWeapon(); W_SetCurrentAmmo (); self = stemp; } // if changed current ammo, update it stemp = self; self = other; W_SetCurrentAmmo(); self = stemp; if (!remaining) { // remove it in single player, or setup for respawning in deathmatch self.model = string_null; self.solid = SOLID_NOT; /* if (deathmatch == 1) { self.nextthink = time + 30; } else if (deathmatch == 3) { self.nextthink = time + 15; // gb, deathmatch 3 support self.think = SUB_regen; } */ // Supa, SP respawning items support if (!deathmatch) CheckItemRespawn(self, 20); // Supa, gametype specific respawn times if (gametype) switch (gametype) { case FFA: {self.nextthink = time + 20; } break; case DUEL: {self.nextthink = time + 20; } break; case TDM: {self.nextthink = time + 20; } break; case TDM_FF: {self.nextthink = time + 20; } break; case CTF: {self.nextthink = time + 20; } break; case CTF_FF: {self.nextthink = time + 20; } break; default: { bprint("ammo_touch: Gametype initialisation failed!\n"); } break; } self.think = SUB_regen; } activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() ammo_go = { self.touch = ammo_touch; setsize (self, '0 0 0', '32 32 56'); StartItem (); }; float WEAPON_BIG2 = 1; /*QUAKED item_shells (0 .5 .8) (0 0 0) (32 32 32) big */ void() item_shells = { if (self.spawnflags & WEAPON_BIG2) { //precache_model ("maps/b_shell1.bsp"); //setmodel (self, "maps/b_shell1.bsp"); precache_model ("progs/ammo_shells2.mdl"); setmodel (self, "progs/ammo_shells2.mdl"); self.ammo_shells = 30; //ijed was 40 } else { //precache_model ("maps/b_shell0.bsp"); //setmodel (self, "maps/b_shell0.bsp"); //ijed New model precache_model ("progs/ammo_shells1.mdl"); setmodel (self, "progs/ammo_shells1.mdl"); self.ammo_shells = 15; //ijed Was 20 } self.netname = "shells"; // self.originhack = '16 16 0'; self.go = ammo_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_spikes (0 .5 .8) (0 0 0) (32 32 32) big */ void() item_spikes = { if (self.spawnflags & WEAPON_BIG2) { precache_model ("progs/ammo_nails1.mdl"); setmodel (self, "progs/ammo_nails1.mdl"); //precache_model ("maps/b_nail1.bsp"); //setmodel (self, "maps/b_nail1.bsp"); self.ammo_nails = 50; } else { //precache_model ("maps/b_nail0.bsp"); //setmodel (self, "maps/b_nail0.bsp"); //ijed New model precache_model ("progs/ammo_nails1.mdl"); setmodel (self, "progs/ammo_nails1.mdl"); self.ammo_nails = 25; } self.netname = "nails"; // self.originhack = '16 16 0'; self.go = ammo_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_rockets (0 .5 .8) (0 0 0) (32 32 32) big */ void() item_rockets = { if (self.spawnflags & WEAPON_BIG2) { //precache_model ("maps/b_rock1.bsp"); //setmodel (self, "maps/b_rock1.bsp"); precache_model ("progs/ammo_rockets2.mdl"); setmodel (self, "progs/ammo_rockets2.mdl"); self.ammo_rockets = 10; } else { precache_model ("progs/ammo_rockets1.mdl"); setmodel (self, "progs/ammo_rockets1.mdl"); self.ammo_rockets = 5; } self.netname = "rockets"; // self.originhack = '16 16 0'; self.go = ammo_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_cells (0 .5 .8) (0 0 0) (32 32 32) big */ void() item_cells = { if (self.spawnflags & WEAPON_BIG2) { precache_model ("progs/ammo_cells2.mdl"); setmodel (self, "progs/ammo_cells2.mdl"); self.ammo_cells = 12; } else { precache_model ("progs/ammo_cells1.mdl"); setmodel (self, "progs/ammo_cells1.mdl"); self.ammo_cells = 6; } self.netname = "cells"; // self.originhack = '16 16 0'; self.go = ammo_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_weapon (0 .5 .8) (0 0 0) (32 32 32) shotgun rocket spikes big DO NOT USE THIS!!!! IT WILL BE REMOVED! */ // LA: Unfortunately, we have to keep this function for id1 support // which means updating what it drops to the ammo_touch overhaul // we skipped adding it to the randomizer, however, as no-one should be using it any more float WEAPON_SHOTGUN = 1; float WEAPON_ROCKET = 2; float WEAPON_SPIKES = 4; float WEAPON_BIG = 8; void() item_weapon = { self.touch = ammo_touch; if (self.spawnflags & WEAPON_SHOTGUN) { if (self.spawnflags & WEAPON_BIG) { precache_model ("maps/b_shell1.bsp"); setmodel (self, "maps/b_shell1.bsp"); self.ammo_shells = 20; // 40 } else { precache_model ("maps/b_shell0.bsp"); setmodel (self, "maps/b_shell0.bsp"); self.ammo_shells = 10; // 20 } self.netname = "shells"; } if (self.spawnflags & WEAPON_SPIKES) { if (self.spawnflags & WEAPON_BIG) { precache_model ("maps/b_nail1.bsp"); setmodel (self, "maps/b_nail1.bsp"); self.ammo_nails = 50; // 40 } else { precache_model ("maps/b_nail0.bsp"); setmodel (self, "maps/b_nail0.bsp"); self.ammo_nails = 25; // 20 } self.netname = "nails"; // "spikes" } if (self.spawnflags & WEAPON_ROCKET) { if (self.spawnflags & WEAPON_BIG) { precache_model ("maps/b_rock1.bsp"); setmodel (self, "maps/b_rock1.bsp"); self.ammo_rockets = 10; } else { precache_model ("maps/b_rock0.bsp"); setmodel (self, "maps/b_rock0.bsp"); self.ammo_rockets = 5; } self.netname = "rockets"; } setsize (self, '0 0 0', '32 32 56'); StartItem (); }; /* =============================================================================== KEYS =============================================================================== */ float KEY_ITEM1 = 1; float KEY_ITEM2 = 2; float KEY_ITEM3 = 4; float KEY_ITEM4 = 8; void() key_touch = { local entity stemp; local float best; if (other.classname != "player") return; if (other.health <= 0) return; if ((other.items & self.items) || (other.items2 & self.items2)) return; sprint (other, "\bYou got the "); sprint (other, self.netname); sprint (other,"\n"); sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM); stuffcmd (other, "bf\n"); other.items = other.items | self.items; other.items2 = other.items2 | self.items2; if (!coop) { self.solid = SOLID_NOT; self.model = string_null; } activator = other; SUB_UseTargets(); // fire all targets / killtargets }; // DRS void() keyitem_touch = { // Can't take if not a player. if(other.classname != "player") return; if(other.health < 1) // dead players can't take. return; if(other.keyitems & self.keyitems) // can't pick up more than one. return; sprint(other, "\bYou got "); sprint(other, self.netname); sprint(other, "\n"); sound (other, CHAN_ITEM, self.noise, 1, ATTN_NONE); // gb, was NORM stuffcmd (other, "bf\n"); other.keyitems = other.keyitems | self.keyitems; if (self.model == "progs/gb_crystal.mdl") // gb, stop the light show when picked up { self.effects = 0; self.think = SUB_Null; } if (!coop) { self.solid = SOLID_NOT; self.model = string_null; } activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() key_setsounds = { if (world.worldtype == 0) { precache_sound ("misc/medkey.wav"); self.noise = "misc/medkey.wav"; } if (world.worldtype == 1) { precache_sound ("misc/runekey.wav"); self.noise = "misc/runekey.wav"; } if (world.worldtype == 2) { precache_sound2 ("misc/basekey.wav"); self.noise = "misc/basekey.wav"; } }; void() item_key_go = { self.touch = key_touch; key_setsounds(); // Would be faster and smaller to inline this setsize (self, '-16 -16 -24', '16 16 32'); StartItem (); }; /*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) SILVER key In order for keys to work you MUST set your maps worldtype to one of the following: 0: medieval 1: metal 2: base */ void() item_key1 = { if (world.worldtype == 0) { precache_model ("progs/key_med.mdl"); setmodel (self, "progs/key_med.mdl"); self.netname = "silver key"; } else if (world.worldtype == 1) { precache_model ("progs/key_rune.mdl"); setmodel (self, "progs/key_rune.mdl"); self.netname = "silver runekey"; } else if (world.worldtype == 2) { precache_model2 ("progs/key_card.mdl"); setmodel (self, "progs/key_card.mdl"); self.netname = "silver keycard"; } self.skin = 1; //silver key skin // key_setsounds(); // self.touch = key_touch; self.items = IT_KEY1; self.go = item_key_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) GOLD key In order for keys to work you MUST set your maps worldtype to one of the following: 0: medieval 1: metal 2: base */ void() item_key2 = { if (world.worldtype == 0) { precache_model ("progs/key_med.mdl"); setmodel (self, "progs/key_med.mdl"); self.netname = "gold key"; } if (world.worldtype == 1) { precache_model ("progs/key_rune.mdl"); setmodel (self, "progs/key_rune.mdl"); self.netname = "gold runekey"; } if (world.worldtype == 2) { precache_model2 ("progs/key_card.mdl"); setmodel (self, "progs/key_card.mdl"); self.netname = "gold keycard"; } self.skin = 2; //gold key skin // key_setsounds(); // self.touch = key_touch; self.items = IT_KEY2; self.go = item_key_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_key3 (0 .5 .8) (-16 -16 -24) (16 16 32) BRONZE key In order for keys to work you MUST set your maps worldtype to one of the following: 0: medieval 1: metal 2: base */ void() item_key3 = { if (world.worldtype == 0) { precache_model ("progs/key_med.mdl"); setmodel (self, "progs/key_med.mdl"); self.netname = "bronze key"; } if (world.worldtype == 1) { precache_model ("progs/key_rune.mdl"); setmodel (self, "progs/key_rune.mdl"); self.netname = "bronze runekey"; } if (world.worldtype == 2) { precache_model2 ("progs/key_card.mdl"); setmodel (self, "progs/key_card.mdl"); self.netname = "bronze keycard"; } self.skin = 0; //bronze key skin // key_setsounds(); // self.touch = key_touch; self.items2 = IT_KEY3; //items2 -otp self.go = item_key_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_key4 (0 .5 .8) (-16 -16 -24) (16 16 32) PLATINUM key In order for keys to work you MUST set your maps worldtype to one of the following: 0: medieval 1: metal 2: base */ void() item_key4 = { if (world.worldtype == 0) { precache_model ("progs/key_med.mdl"); setmodel (self, "progs/key_med.mdl"); self.netname = "platinum key"; } if (world.worldtype == 1) { precache_model ("progs/key_rune.mdl"); setmodel (self, "progs/key_rune.mdl"); self.netname = "platinum runekey"; } if (world.worldtype == 2) { precache_model2 ("progs/key_card.mdl"); setmodel (self, "progs/key_card.mdl"); self.netname = "platinum keycard"; } self.skin = 3; //platinum key skin // key_setsounds(); // self.touch = key_touch; self.items2 = IT_KEY4; //items2 -otp self.go = item_key_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) KEYITEM_2 KEYITEM_3 KEYITEM_4 x x SILENT SPAWNED DONTDROP NOEASY NOMEDIUM NOHARD NODM User definable extended key. Can use a .mdl or be a brush model (like a func_wall etc). This keyitem''s name must be set in worldspawn (!!!) like this: "keyitem1" "beast key" Set the corresponding spawnflag here (leave blank for keyitem1). Set the same spawnflag on the trigger_lock that expects this keyitem. You can have up to 4 keyitems defined like this. Keys can migrate between levels, so a clever mapper can make secret keys that can unlock an obvious area in a succeeding map. (Just make sure you set the name!) Set "keyitemX_keep" "1" in worldspawn to prevent doors from removing that key from the player's inventory In game, you can see collected keyitems in the inventory (type "inventory" in console). "noise" sound to play on pickup, defaults to misc/medkey.wav "deathtype" name of the .mdl to use, unless this is a brush model "skin" sets the skin if using .mdl file, skin 0 is the first "view_ofs" 'x y z' height adjustment for non-rotational models, try '0 0 24'. "target" as usual */ // DRS // 201012211149EST Supa, fixing alias model key bbox issues // 201101011730EST Supa, fixing the breakage created by the previous fix -_- // LA: Adding randomizer hook. The name of this _go function isn't ideal, but it's the most logical choice // 201109122322EST Supa, implementing item_key-related world.keyitemX_keep flags void() item_customkey_go = { local vector szmin, szmax; local string whatmdl; if (!self.model) // alias model? A bmodel key will already start with .model set { szmin = '-16 -16 -24'; szmax = '16 16 32'; whatmdl = self.deathtype; } else // bmodel key whatmdl = self.model; szmin_z = szmin_z + self.view_ofs_z; szmax_z = szmax_z + self.view_ofs_z; setmodel (self, whatmdl); //ijed Allow selection of frames from map via cnt value if (frame) self.frame = self.frame; if (self.deathtype) // only setsize on alias models, bmodel keys already have absmin/absmax set setsize (self, szmin, szmax); self.touch = keyitem_touch; StartItem (); }; void() item_key = { // no sound? Default to medkey.wav if (!self.noise) self.noise = "misc/medkey.wav"; // precache sounds. if (self.noise) precache_sound2 (self.noise); if (!self.model) // alias model key? { if (!self.deathtype) // default to medeval silver key if no mapper model set. self.deathtype = "progs/w_s_key.mdl"; precache_model (self.deathtype); } // set key and key name if (self.spawnflags & 1) {self.netname = world.keyitem2; self.keyitems = KEY_ITEM2; } else if (self.spawnflags & 2) {self.netname = world.keyitem3; self.keyitems = KEY_ITEM3; } else if (self.spawnflags & 4) {self.netname = world.keyitem4; self.keyitems = KEY_ITEM4; } else {self.netname = world.keyitem1; self.keyitems = KEY_ITEM1; } if (!self.netname) self.netname = "the Mystery Key"; self.go = item_customkey_go; if(!CheckGroup()) self.go(); }; // for worldcraft compat. void() func_key = { item_key(); }; void() showkeyitems = { local string s1, s2, s3, s4, s5, s6, s7; s1 = "\bKey Items\b\n"; if(self.keyitems & KEY_ITEM1) s2 = world.keyitem1; else s2 = "\n"; if(self.keyitems & KEY_ITEM2) s3 = world.keyitem2; else s3 = "\n"; if(self.keyitems & KEY_ITEM3) s4 = world.keyitem3; else s4 = "\n"; if(self.keyitems & KEY_ITEM4) s5 = world.keyitem4; else s5 = "\n"; s6 = ""; s7 = "\n"; frik_big_centerprint(self, s1, s2, s3, s4, s5, s6, s7); }; /* =============================================================================== END OF LEVEL RUNES =============================================================================== */ void() sigil_touch = { local entity stemp; local float best; if (other.classname != "player") return; if (other.health <= 0) return; if (self.spawnflags & 16) return; // set spawnflag 16 for fake rune, wasn't being used for anything else... -rj centerprint (other, "You got the rune!"); sound (other, CHAN_ITEM, self.noise, 1, ATTN_NONE); // gb, was NORM stuffcmd (other, "bf\n"); self.solid = SOLID_NOT; self.model = string_null; serverflags = serverflags | (self.spawnflags & 15); self.classname = ""; // so rune doors won't find it activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() item_sigil_go = { self.touch = sigil_touch; setsize (self, '-16 -16 -24', '16 16 32'); StartItem (); }; /*QUAKED item_sigil (0 .5 .8) (-16 -16 -24) (16 16 32) E1 E2 E3 E4 End of level sigil, pick up to end episode and return to jrstart. */ void() item_sigil = { if (!self.spawnflags) objerror ("no spawnflags"); precache_sound ("misc/runekey.wav"); self.noise = "misc/runekey.wav"; if (self.spawnflags & 1) { precache_model ("progs/end1.mdl"); setmodel (self, "progs/end1.mdl"); } if (self.spawnflags & 2) { precache_model2 ("progs/end2.mdl"); setmodel (self, "progs/end2.mdl"); } if (self.spawnflags & 4) { precache_model2 ("progs/end3.mdl"); setmodel (self, "progs/end3.mdl"); } if (self.spawnflags & 8) { precache_model2 ("progs/end4.mdl"); setmodel (self, "progs/end4.mdl"); } self.go = item_sigil_go; if(!CheckGroup()) self.go(); }; /* =============================================================================== POWERUPS =============================================================================== */ void() powerup_touch; void() powerup_touch = { local entity stemp; local float best; #ifdef HOOK local float leave; // gb // if (deathmatch == 2 || deathmatch == 3 || coop) // gb, deathmatch 3 support if (gametype == FFA || coop ) // gb, deathmatch 3 support leave = 1; else leave = 0; if (leave ) if (other.hook_equip != 0 ) // gb if (self.classname == "item_grappling_hook" ) // Supa, only exit if applicable return; #endif if (other.classname != "player") return; if (other.health <= 0) return; sprint (other, "You got the "); sprint (other, self.netname); sprint (other,"\n"); // Supa, SP respawning items support self.mdl = self.model; self.think = SUB_regen; if (!deathmatch) { local float spawndelay; if (self.classname == "item_artifact_invulnerability" || self.classname == "item_artifact_invisibility" ) spawndelay = 300; else if (self.classname == "item_grappling_hook" ) spawndelay = 30; else spawndelay = 60; CheckItemRespawn(self, spawndelay); } else { if ((self.classname == "item_artifact_invulnerability") || (self.classname == "item_artifact_invisibility")) self.nextthink = time + 60*5; #ifdef HOOK if (self.classname == "item_grappling_hook") { if (leave) self.nextthink = -1; else self.nextthink = time + 30; } #endif else self.nextthink = time + 60; } sound (other, CHAN_VOICE, self.noise, 1, ATTN_NONE); // gb, was NORM stuffcmd (other, "bf\n"); #ifdef HOOK if ( !(leave && self.classname == "item_grappling_hook") ) { #endif self.solid = SOLID_NOT; other.items = other.items | self.items; self.model = string_null; #ifdef HOOK } #endif // do the apropriate action if (self.classname == "item_artifact_envirosuit") { other.rad_time = 1; other.radsuit_finished = time + 30; } if (self.classname == "item_artifact_invulnerability") { // Supa, new pent, turn off rage and regen on pickup if (self.is_raged) Rage_Toggle(self); // other.invincible_time = 1; // other.invincible_finished = time + 30; // Supa, new pent behavior self.effects = self.effects - (self.effects & EF_RED); // gb } if (self.classname == "item_artifact_invisibility") { other.invisible_time = 1; other.invisible_finished = time + 30; } if (self.classname == "item_artifact_super_damage") { other.super_time = 1; if (other.super_damage_finished > time) other.super_damage_finished += 10; // add 10s to the timer if already on a Quad run else other.super_damage_finished = time + 10; // Supa, was 30 self.effects = self.effects - (self.effects & EF_BLUE); // gb } //if (self.classname == "item_artifact_res") //{ //} #ifdef HOOK if (self.classname == "item_grappling_hook") { other.hook_equip = 1; } #endif activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() item_artifact_go = { if (deathmatch) // CRUFT { if (self.classname == "item_artifact_invulnerability") self.effects = self.effects | EF_RED; // gb, powerup glow else if (self.classname == "item_artifact_super_damage") self.effects = self.effects | EF_BLUE; } self.touch = powerup_touch; setsize (self, '-16 -16 -24', '16 16 32'); StartItem (); }; /*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32) Player is invulnerable for 30 seconds */ void() item_artifact_invulnerability = { if (gametype == DUEL) // Supa remove(self); precache_model ("progs/invulner.mdl"); precache_sound ("items/protect.wav"); precache_sound ("items/protect2.wav"); precache_sound ("items/protect3.wav"); self.noise = "items/protect.wav"; setmodel (self, "progs/invulner.mdl"); self.netname = "Pentagram of Protection"; self.items = IT_INVULNERABILITY; // setsize (self, '-16 -16 -24', '16 16 32'); self.go = item_artifact_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_artifact_envirosuit (0 .5 .8) (-16 -16 -24) (16 16 32) Player takes no damage from water or slime for 30 seconds */ void() item_artifact_envirosuit = { precache_model ("progs/suit.mdl"); precache_sound ("items/suit.wav"); precache_sound ("items/suit2.wav"); self.noise = "items/suit.wav"; setmodel (self, "progs/suit.mdl"); self.netname = "Biosuit"; self.items = IT_SUIT; // setsize (self, '-16 -16 -24', '16 16 32'); self.go = item_artifact_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_artifact_invisibility (0 .5 .8) (-16 -16 -24) (16 16 32) Player is invisible for 30 seconds */ void() item_artifact_invisibility = { /* if (mapname == "dm3") // Supa, totally-not-a-railgun, replace ROS on DM3 { self.classname = "weapon_railgun"; weapon_railgun(); return; } */ precache_model ("progs/invisibl.mdl"); precache_sound ("items/inv1.wav"); precache_sound ("items/inv2.wav"); precache_sound ("items/inv3.wav"); self.noise = "items/inv1.wav"; setmodel (self, "progs/invisibl.mdl"); self.netname = "Ring of Shadows"; self.items = IT_INVISIBILITY; // setsize (self, '-16 -16 -24', '16 16 32'); self.go = item_artifact_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_artifact_super_damage (0 .5 .8) (-16 -16 -24) (16 16 32) The next attack from the player will do 4x damage */ void() item_artifact_super_damage = { if (gametype == DUEL) // Supa remove(self); precache_model ("progs/quaddama.mdl"); precache_sound ("items/damage.wav"); precache_sound ("items/damage2.wav"); precache_sound ("items/damage3.wav"); self.noise = "items/damage.wav"; setmodel (self, "progs/quaddama.mdl"); self.netname = "Quad Damage"; self.items = IT_QUAD; // setsize (self, '-16 -16 -24', '16 16 32'); self.go = item_artifact_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_artifact_res (0 .5 .8) (-16 -16 -24) (16 16 32) Goodbye, quicksave */ void() item_artifact_res = { //if (gametype == DUEL || DEATHMATCH) // remove(self); precache_model ("progs/res.mdl"); precache_sound ("items/res.wav"); self.noise = "items/res.wav"; setmodel (self, "progs/res.mdl"); self.netname = "Ward of Rebirth"; self.items = IT_REBIRTH; //self.effects = self.effects | EF_BRIGHTLIGHT; self.go = item_artifact_go; if(!CheckGroup()) self.go(); }; #ifdef HOOK /*QUAKED item_grappling_hook (0 .5 .8) (-16 -16 -24) (16 16 32) Simply gives player the grappling hook. */ void() GrapplePrecaches = // 20120522 Supa, I hate doing the same two things in two different places and you should too { precache_model ("progs/hook.mdl"); precache_model ("progs/chain.mdl"); precache_sound ("shambler/smack.wav"); // precache_sound ("blob/land1.wav"); // precache_sound ("hook/chain1.wav"); // precache_sound ("hook/chain2.wav"); precache_sound ("hook/reelin1.wav"); precache_sound ("hook/reelin2.wav"); precache_sound ("hook/retract1.wav"); precache_sound ("hook/pickup1.wav"); }; void() item_grappling_hook = // gb { GrapplePrecaches(); self.noise = "hook/pickup1.wav"; setmodel (self, "progs/hook.mdl"); self.netname = "Grappling Hook"; // self.items = IT_SUIT; // setsize (self, '-16 -16 -24', '16 16 32'); self.go = item_artifact_go; if(!CheckGroup()) self.go(); }; #endif /* =============================================================================== PLAYER BACKPACKS =============================================================================== */ void() BackpackTouch = { local string s; local float best, old, new; local entity stemp; local float acount; #ifdef HOOK local float hadnohook; #endif if (other.classname != "player") return; if (other.health <= 0) return; acount = 0; sprint (other, "You get "); if (self.items) if ((other.items & self.items) == 0) { acount = 1; sprint (other, "the "); sprint (other, self.netname); } // if the player was using his best weapon, change up to the new one if better stemp = self; self = other; best = W_BestWeapon(); self = stemp; // change weapons other.ammo_shells = other.ammo_shells + self.ammo_shells; other.ammo_nails = other.ammo_nails + self.ammo_nails; other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; other.ammo_cells = other.ammo_cells + self.ammo_cells; #ifdef HOOK if (other.hook_equip == 0) hadnohook = 1; else hadnohook = 0; other.hook_equip = other.hook_equip + self.hook_equip; // gb #endif new = self.items; if (!new) new = other.weapon; old = other.items; other.items = other.items | new; if (self.items2) // Supa, give replacement weapon if present other.items2 = other.items2 | self.items2; bound_other_ammo (); #ifdef HOOK if (self.hook_equip && hadnohook) { if (acount) sprint(other, ", "); acount = 1; sprint(other, "the Grappling Hook"); } #endif if (self.ammo_shells) { if (acount) sprint(other, ", "); acount = 1; s = ftos(self.ammo_shells); sprint (other, s); if (self.ammo_shells == 1) { sprint (other, " shell"); } else { sprint (other, " shells"); } } if (self.ammo_nails) { if (acount) sprint(other, ", "); acount = 1; s = ftos(self.ammo_nails); sprint (other, s); if (self.ammo_nails == 1) { sprint (other, " nail"); } else { sprint (other, " nails"); } } if (self.ammo_rockets) { if (acount) sprint(other, ", "); acount = 1; s = ftos(self.ammo_rockets); sprint (other, s); if (self.ammo_rockets == 1) { sprint (other, " rocket"); } else { sprint (other, " rockets"); } } if (self.ammo_cells) { if (acount) sprint(other, ", "); acount = 1; s = ftos(self.ammo_cells); sprint (other, s); if (self.ammo_cells == 1) { sprint (other, " cell"); } else { sprint (other, " cells"); } } if (self.armorvalue) { local float bit; if (acount) sprint(other, ", "); acount = 1; s = ftos(self.armorvalue); sprint (other, s); sprint (other, " armor"); if ((other.items & IT_ARMOR1) || (other.items & IT_ARMOR2) || (other.items & IT_ARMOR3)) // has armor { other.armorvalue = other.armorvalue + self.armorvalue; } else { other.armortype = 0.3; // GA other.armorvalue = self.armorvalue; bit = IT_ARMOR1; other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + bit; } } if (self.healamount) { if (acount) sprint(other, ", "); acount = 1; s = ftos(self.healamount); sprint (other, s); sprint (other, " health"); // if (other.health >= rint (other.max_health * 2)) // return; if (other.health < rint (other.max_health * 2)) // Supa, immortal spamming backpack of doom bug T_Heal(other, self.healamount, self.healtype); } sprint (other, "\n"); // backpack touch sound sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); // set to NONE like ammo and weapons? stuffcmd (other, "bf\n"); SUB_UseTargets(); // gb, item_backpack should do this when picked up // remove the backpack, change self to the player remove(self); // FIXME: if item_backpack uses this function, then it can't currently respawn! (LA) self = other; // change to the weapon // if (!deathmatch) // QIP // self.weapon = new; // else Deathmatch_Weapon (old, new); W_SetCurrentAmmo (); }; /* =============== DropBackpack =============== */ void() DropBackpack = { local entity item; if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) return; // nothing in it item = spawn(); item.classname = "backpack"; item.origin = self.origin - '0 0 24'; item.items = self.weapon; if (item.items == IT_AXE) item.netname = "Chainsaw"; // gb else if (item.items == IT_SHOTGUN) item.netname = "Shotgun"; else if (item.items == IT_SUPER_SHOTGUN) { // Supa if (self.items2 & IT_SHREDDER) {item.netname = "Shredder! Find some meat!"; item.items2 = IT_SHREDDER; } else item.netname = "Double-barrelled Shotgun"; } else if (item.items == IT_NAILGUN) item.netname = "Nailgun"; else if (item.items == IT_SUPER_NAILGUN) item.netname = "Super Nailgun"; else if (item.items == IT_GRENADE_LAUNCHER) item.netname = "Grenade Launcher"; else if (item.items == IT_ROCKET_LAUNCHER) item.netname = "Rocket Launcher"; else if (item.items == IT_LIGHTNING) item.netname = "Thunderbolt"; else if (item.items == IT_RAILGUN) item.netname = "Cauteriser"; else item.netname = ""; item.ammo_shells = self.ammo_shells; item.ammo_nails = self.ammo_nails; item.ammo_rockets = self.ammo_rockets; item.ammo_cells = self.ammo_cells; #ifdef HOOK item.hook_equip = self.hook_equip; // gb #endif item.velocity_z = 300; item.velocity_x = -100 + (random() * 200); item.velocity_y = -100 + (random() * 200); item.flags = FL_ITEM; item.solid = SOLID_TRIGGER; item.movetype = MOVETYPE_TOSS; setmodel (item, "progs/backpack.mdl"); setsize (item, '-16 -16 0', '16 16 56'); item.touch = BackpackTouch; // item.nextthink = time + 120; // remove after 2 minutes // item.think = SUB_Remove; // Supa, lava burns items away item.cnt = time + 120; // remove after 2 minutes item.nextthink = time + 0.1; item.think = LavaMonitor; }; // LA: Backpacks for mappers to include, by request. void() item_backpack_go = { setmodel (self, "progs/backpack.mdl"); setsize (self, '-16 -16 0', '16 16 56'); self.touch = BackpackTouch; StartItem (); }; /*QUAKED item_backpack (.3 .3 1) (-16 -16 0) (16 16 56) ? ? ? ? ? SILENT SPAWNED FLOATING Backpack full of whatever the mapper desires ammo_shells: Shells ammo_nails: Nails ammo_rockets: Rockets ammo_cells: Cells armorvalue: Armor. Added to current armor class, or Green otherwise. healamount: Health. Will go above maximum health. You can include an item with .items and .netname, but please don't... */ void() item_backpack = { precache_model ("progs/backpack.mdl"); precache_sound ("weapons/lock4.wav"); self.go = item_backpack_go; if(!CheckGroup()) self.go(); }; #ifdef MONSTERS /* =============== DeathDrop =============== */ // Generic death drop function - gb // LA: Largely cleaned up logic void() DeathDrop = { local entity item; local float r; // if (random() > 0.3) // global frequency of death drops // return; // Supa quick fix to avoid spawning unneeded item placeholders if (self.classname == "monster_knight" ) {if (random() > 0.2) return;} //ijed Made this lower because there's more of them else if (self.classname == "monster_hell_knight") {if (random() > 0.3) return;} item = spawn(); // item.origin = self.origin - '0 0 24'; setorigin(item, self.origin); // Supa Armourshard fix // first, decide who drops what if (self.classname == "monster_army") // likes to pack useless equipment { // get dropped item type r = random(); if (r < 0.2) item.classname = "armorpack"; // ammo + 5 armor else if (r < 0.3) item.classname = "healthpack"; // ammo + 5 health else item.classname = "ammopack"; // ammo only // get ammo type and count if (self.spawnflags & 4) self.ammo_nails = ceil(random() * 12) + 3; // NAIL_GRUNT gives 4-15 nails instead else self.ammo_shells = ceil(random() * 3); // 1-3 shells } else if (self.classname == "monster_enforcer") // wears armor, scoffs at health; LA: extra ammo for wargear flags { r = random(); if (r < 0.2) item.classname = "armorpack"; else item.classname = "ammopack"; // get ammo type and count self.ammo_cells = ceil(random() * 3 + 1); // 2-4 cells if (self.spawnflags & 4) self.ammo_cells = self.ammo_cells + 1; // HYPERBLASTER gives +1 cell, for 3-5 total if (self.spawnflags & 8) self.ammo_rockets = ceil(random() * 2); // HUNTERKILLERS means a guaranteed rocket drop, equal chance 1 or 2 else self.ammo_rockets = floor(random() * 2.2); // 0 or 1 rockets, with small (9%) chance of 2 } else if (self.classname == "monster_ogre") // armor? health? HA! { item.classname = "ammopack"; // get ammo type and count if (self.spawnflags & 4) self.ammo_nails = ceil(random() * 11) + 4; // NAIL_OGRE gives 5-15 nails instead else if (self.spawnflags & 16) self.ammo_rockets = ceil(random() * 3 + 1); // ROCKET_OGRE gives 2-4 rockets instead else self.ammo_rockets = ceil(random() * 2); // 1-2 rockets } else if (self.classname == "monster_knight") // backpacks not invented yet { item.classname = "armorshard"; } else if (self.classname == "monster_hell_knight") // same { item.classname = "armorshard"; } // now build the required item // you must precache sounds, models in the monster spawn functions // - except backpack.mdl ijed Going to have the grunts visually carry the backpack as an experiment if (item.classname == "armorshard") // Supa Minor little fix { if (world.worldtype == 0) //ijed Sets shard model to worldtype model, precached inside the knights qc setmodel (item, "progs/armorshard0.mdl"); else if (world.worldtype == 1) setmodel (item, "progs/armorshard1.mdl"); else if (world.worldtype == 2) //ijed Tech armour shards? ~OUM? setmodel (item, "progs/armorshard2.mdl"); setsize (item, '-16 -16 0', '16 16 56'); item.touch = shard_touch; } else if (item.classname == "armorpack") // pack w/ ammo + shard { setmodel (item, "progs/backpack.mdl"); setsize (item, '-16 -16 0', '16 16 56'); item.touch = BackpackTouch; item.ammo_shells = self.ammo_shells; item.ammo_nails = self.ammo_nails; item.ammo_rockets = self.ammo_rockets; item.ammo_cells = self.ammo_cells; item.armorvalue = 5; // 2 } else if (item.classname == "healthpack") { setmodel (item, "progs/backpack.mdl"); setsize (item, '-16 -16 0', '16 16 56'); item.touch = BackpackTouch; item.ammo_shells = self.ammo_shells; item.ammo_nails = self.ammo_nails; item.ammo_rockets = self.ammo_rockets; item.ammo_cells = self.ammo_cells; item.healamount = 5; // 2 item.healtype = 2; } else if (item.classname == "ammopack") // old fashioned { setmodel (item, "progs/backpack.mdl"); setsize (item, '-16 -16 0', '16 16 56'); item.touch = BackpackTouch; item.ammo_shells = self.ammo_shells; item.ammo_nails = self.ammo_nails; item.ammo_rockets = self.ammo_rockets; item.ammo_cells = self.ammo_cells; } // unless keys item.velocity_z = 300; item.velocity_x = -100 + (random() * 200); item.velocity_y = -100 + (random() * 200); item.flags = FL_ITEM; item.solid = SOLID_TRIGGER; // unless keys item.movetype = MOVETYPE_TOSS; // unless keys // item.nextthink = time + 120; // remove after 2 minutes // item.think = SUB_Remove; // Supa, oops, forgot this one.. item.cnt = time + 120; // remove after 2 minutes item.nextthink = time + 0.1; item.think = LavaMonitor; }; #endif /* =============== DropWeapon =============== */ // gb, thanks Shyft, modified void() DropWeapon = { local entity item; item = spawn(); item.origin = self.origin + v_forward*8 + '0 0 32'; item.items = self.weapon; self.items = self.items - self.weapon; // don't be an asshole, give them ammo, too - gb if (item.items == IT_AXE) { item.netname = "Chainsaw"; } else if (item.items == IT_SHOTGUN) { item.netname = "Shotgun"; if (self.ammo_shells > 0) {item.ammo_shells = ceil(self.ammo_shells / 2); self.ammo_shells = floor(self.ammo_shells / 2); } } else if (item.items == IT_SUPER_SHOTGUN) { if (self.items2 & IT_SHREDDER) {item.netname = "Shredder! Find some meat!"; self.items2 -= IT_SHREDDER;} else item.netname = "Double-barrelled Shotgun"; if (self.ammo_shells > 0) {item.ammo_shells = ceil(self.ammo_shells / 2); self.ammo_shells = floor(self.ammo_shells / 2); } } else if (item.items == IT_NAILGUN) { item.netname = "Nailgun"; if (self.ammo_nails > 0) {item.ammo_nails = ceil(self.ammo_nails / 2); self.ammo_nails = floor(self.ammo_nails / 2); } } else if (item.items == IT_SUPER_NAILGUN) { item.netname = "Super Nailgun"; if (self.ammo_nails > 0) {item.ammo_nails = ceil(self.ammo_nails / 2); self.ammo_nails = floor(self.ammo_nails / 2); } } else if (item.items == IT_GRENADE_LAUNCHER) { item.netname = "Grenade Launcher"; if (self.ammo_rockets > 0) {item.ammo_rockets = ceil(self.ammo_rockets / 2); self.ammo_rockets = floor(self.ammo_rockets / 2); } } else if (item.items == IT_ROCKET_LAUNCHER) { item.netname = "Rocket Launcher"; if (self.ammo_rockets > 0) {item.ammo_rockets = self.ammo_rockets; self.ammo_rockets = 0; } } else if (item.items == IT_LIGHTNING) { item.netname = "Thunderbolt"; if (self.ammo_cells > 0) {item.ammo_cells = self.ammo_cells; self.ammo_cells = 0; } } else if (item.items == IT_RAILGUN) { item.netname = "Cauteriser"; if (self.ammo_cells > 0) {item.ammo_cells = self.ammo_cells; self.ammo_cells = 0; } } makevectors (self.v_angle); if (self.v_angle_x) item.velocity = v_forward*600 + v_up*100 + v_right*10; else { item.velocity = aim(self, 10000); item.velocity = item.velocity * 200; item.velocity_z = 200; } item.flags = FL_ITEM; item.solid = SOLID_TRIGGER; item.movetype = MOVETYPE_TOSS; setmodel (item, "progs/backpack.mdl"); setsize (item, '-16 -16 0', '16 16 56'); item.classname = "weaponpack"; // gb, bots and priority ... item.touch = BackpackTouch; // gb self.weapon = W_BestWeapon(); W_SetCurrentAmmo(); // gb sound (self, CHAN_AUTO, "weapons/ax1.wav", 1, ATTN_NORM); }; // Supa, Quad Drop begin void() DroppedQuad_Touch = { local float quadtime; if (other.classname != "player") return; if (other.health <= 0) return; sprint (other, "You got the Quad Damage\n"); // in order to work around the quad accumulation, we'll have to decay quad time remaining over time, even when it hasn't been picked up quadtime = ceil(self.nextthink - time); // remember that next quad spawns at self.nextthink bprint (other.netname); bprint (" picked up a Quad with "); bprint (ftos(quadtime)); bprint (" seconds remaining!\n"); sound (other, CHAN_VOICE, "items/damage.wav", 1, ATTN_NONE); stuffcmd (other, "bf\n"); other.super_time = 1; if (other.super_damage_finished < self.nextthink) // Don't override the timer if they already have a Quad with enough time left other.super_damage_finished = self.nextthink; other.items = other.items | IT_QUAD; self.solid = SOLID_NOT; self.model = string_null; self.think = SUB_Remove; self.nextthink = time; // next frame }; void() DropQuad = { local entity item; item = spawn(); item.classname = "item_artifact_super_damage"; item.origin = self.origin - '0 0 24'; item.velocity_z = 300; item.velocity_x = -100 + (random() * 200); item.velocity_y = -100 + (random() * 200); item.effects = EF_BLUE; item.flags = FL_ITEM; item.solid = SOLID_TRIGGER; item.movetype = MOVETYPE_TOSS; setmodel (item, "progs/quaddama.mdl"); setsize (item, '-16 -16 -24', '16 16 32'); item.touch = DroppedQuad_Touch; item.nextthink = self.super_damage_finished; // make sure the dropped quad dies by the time the next quad spawns item.think = SUB_Remove; bprint(self.netname); bprint(" dropped a Quad with "); bprint(ftos(ceil(item.nextthink - time))); bprint(" seconds remaining!\n"); }; // Quad Drop end /* ========================================================================== CHARMS gb, 20120429 - Charm system ========================================================================== */ void() charm_touch = { local float leave; if (other.health <= 0) return; if (!(other.flags & FL_CLIENT)) return; // if (deathmatch == 2 || deathmatch == 3 || coop) // gb, deathmatch 3 support // gb, deathmatch 3 support if (gametype == FFA || coop ) leave = 1; else leave = 0; if (self.classname == "item_charm_rage") { if (leave && (other.charms & CH_RAGE) ) return; other.charms = other.charms | CH_RAGE; } else if (self.classname == "item_charm_movement") { if (leave && (other.charms & CH_EXT_MOVE) ) return; other.charms = other.charms | CH_EXT_MOVE; } else if (self.classname == "item_charm_absorber") { if (leave && (other.charms & CH_ABSORBER) ) return; other.charms = other.charms | CH_ABSORBER; } else objerror ("charm_touch: unknown classname"); sprint (other, "You got the "); sprint (other, self.netname); sprint (other, "\n"); // charm touch sound sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); // gb, NONE? stuffcmd (other, "bf\n"); if (leave) { if (self.state == 0) { activator = other; SUB_UseTargets (); self.state = 1; } return; } // remove it in single player, or setup for respawning in deathmatch self.model = string_null; self.solid = SOLID_NOT; // Supa, SP respawning items support if (!deathmatch) CheckItemRespawn(self, 15); // Supa, gametype specific respawn times if (gametype) switch (gametype) { // case FFA: {self.nextthink = time + 15;} break; case DUEL: {self.nextthink = time + 15;} break; case TDM: {self.nextthink = time + 15;} break; case TDM_FF: {self.nextthink = time + 15;} break; case CTF: {self.nextthink = time + 5; } break; case CTF_FF: {self.nextthink = time + 5; } break; default: { bprint("charm_touch: Gametype initialisation failed!\n"); } break; } self.think = SUB_regen; activator = other; SUB_UseTargets(); // fire all targets / killtargets }; void() charm_go = { self.touch = charm_touch; setsize (self, '-16 -16 0', '16 16 56'); StartItem (); }; /*QUAKED item_charm_rage (0 .5 .8) (-16 -16 0) (16 16 32) The Rage Charm. Activates Rage ability when collected. (health regen and 2x damage when near death) */ void() item_charm_rage = { precache_model ("progs/h_player.mdl"); setmodel (self, "progs/h_player.mdl"); self.netname = "Charm: \bRage"; self.go = charm_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_charm_movement (0 .5 .8) (-16 -16 0) (16 16 32) The Extended Movement Charm. Activates special moves when collected. (Walljump, dash, pogo, stairglide) */ void() item_charm_movement = { precache_model ("progs/h_player.mdl"); setmodel (self, "progs/h_player.mdl"); self.netname = "Charm: \bExtended Movement"; self.go = charm_go; if(!CheckGroup()) self.go(); }; /*QUAKED item_charm_absorber (0 .5 .8) (-16 -16 0) (16 16 32) The Kinetic Absorber charm. Counteracts fall damage when collected. */ void() item_charm_absorber = { precache_model ("progs/h_player.mdl"); setmodel (self, "progs/h_player.mdl"); self.netname = "Charm: \bKinetic Absorber"; self.go = charm_go; if(!CheckGroup()) self.go(); };