Files
2019-12-30 17:23:05 +01:00

3201 lines
77 KiB
Plaintext

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();
};