mirror of
https://git.code.sf.net/p/quake/game-source
synced 2024-11-29 15:12:00 +00:00
549 lines
13 KiB
C++
549 lines
13 KiB
C++
#include "common.qh"
|
|
#include "mapents_util.qh"
|
|
#include "items.qh"
|
|
#include "weapon.qh"
|
|
#include "act.qh"
|
|
#include "misc.qh"
|
|
#include "mdl_player.qh"
|
|
#include "mdl_eyes.qh"
|
|
|
|
#include "override.qh"
|
|
#include "damage.qh"
|
|
|
|
#include "equip.qh"
|
|
|
|
#include "mapents_powerup.qh"
|
|
|
|
/* FIXME: These don't handle powerups that grant stuff others grant. */
|
|
float(entity powerup) powerup_check_remove = {
|
|
if ((self.itemfield_1 & powerup.itemfield_1) != powerup.itemfield_1)
|
|
return TRUE;
|
|
if ((self.itemfield_2 & powerup.itemfield_2) != powerup.itemfield_2)
|
|
return TRUE;
|
|
if ((self.itemfield_3 & powerup.itemfield_3) != powerup.itemfield_3)
|
|
return TRUE;
|
|
if ((self.itemfield_4 & powerup.itemfield_4) != powerup.itemfield_4)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
};
|
|
|
|
void(entity powerup) powerup_remove = {
|
|
self.itemfield_1 -= (self.itemfield_1 & powerup.itemfield_1);
|
|
self.itemfield_2 -= (self.itemfield_2 & powerup.itemfield_2);
|
|
self.itemfield_3 -= (self.itemfield_3 & powerup.itemfield_3);
|
|
self.itemfield_4 -= (self.itemfield_4 & powerup.itemfield_4);
|
|
|
|
self.items -= (self.items & powerup.items);
|
|
self.effects -= (self.effects & powerup.effects);
|
|
|
|
override_destroy(self, powerup);
|
|
};
|
|
|
|
float() _powerup_takeitem = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if ((powerup.itemfield_1 & other.itemfield_1)
|
|
|| (powerup.itemfield_2 & other.itemfield_2)
|
|
|| (powerup.itemfield_3 & other.itemfield_3)
|
|
|| (powerup.itemfield_4 & other.itemfield_4)) {
|
|
if ((time+other.attack_finished) > powerup.attack_finished) {
|
|
/* Act like we don't have it, to renew.. */
|
|
powerup_remove(powerup);
|
|
}
|
|
}
|
|
|
|
if (powerup.th_takeitem)
|
|
return powerup.th_takeitem();
|
|
return FALSE;
|
|
};
|
|
|
|
void() _powerup_prethink = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (powerup_check_remove(powerup))
|
|
powerup_remove(powerup);
|
|
|
|
if (powerup.prethink)
|
|
powerup.prethink();
|
|
};
|
|
|
|
void() _powerup_think = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (time > powerup.attack_finished) {
|
|
powerup_remove(powerup);
|
|
} else if (time >= powerup.air_finished) {
|
|
if (is_cl(self))
|
|
stuffcmd(self, "bf\n");
|
|
|
|
if (powerup.noise) {
|
|
sound(self, CHAN_AUTO, powerup.noise, 1, ATTN_NORM);
|
|
powerup.noise = NIL;
|
|
}
|
|
|
|
powerup.air_finished += 1;
|
|
}
|
|
|
|
if (powerup.actthink)
|
|
powerup.actthink();
|
|
};
|
|
|
|
void() _powerup_postthink = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
self.items |= powerup.items;
|
|
self.effects |= powerup.effects;
|
|
|
|
if (powerup.postthink)
|
|
powerup.postthink();
|
|
};
|
|
|
|
// ===================================================================== //
|
|
|
|
float(float dmg) _suit_takedamage = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (dmg < DAMAGE_SHOULDDIE && self.dmg_inflictor == world) {
|
|
/* Magic formula */
|
|
dmg -= 20*frametime;
|
|
dmg /= 30*frametime;
|
|
|
|
if (dmg <= 0) {
|
|
override_halt();
|
|
deathmsg_nodisplay();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (powerup.th_takedamage)
|
|
return powerup.th_takedamage(dmg);
|
|
return FALSE;
|
|
};
|
|
|
|
void() _suit_prethink = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (powerup_check_remove(powerup)) {
|
|
powerup_remove(powerup);
|
|
} else {
|
|
self.air_finished = time + 12;
|
|
}
|
|
|
|
if (powerup.prethink)
|
|
powerup.prethink();
|
|
};
|
|
|
|
#define STR_EQUIPID_SUIT "Environmental Suit"
|
|
void() _suit_activate = {
|
|
local entity powerup;
|
|
|
|
powerup = override_create(other, "OVERRIDE_SUIT", OVERPRIO_SUIT);
|
|
powerup.th_takeitem = _powerup_takeitem;
|
|
powerup.th_takedamage = _suit_takedamage;
|
|
powerup.prethink = _suit_prethink;
|
|
powerup.actthink = _powerup_think;
|
|
powerup.postthink = _powerup_postthink;
|
|
override_finalize(powerup);
|
|
|
|
equip_grant(powerup, EQUIPID_SUIT);
|
|
powerup.items = IT_SUIT;
|
|
powerup.attack_finished = time + self.attack_finished;
|
|
|
|
powerup.noise = "items/suit2.wav";
|
|
powerup.air_finished = powerup.attack_finished - 3;
|
|
};
|
|
/*QUAKED item_artifact_envirosuit (0 .5 .8) (-16 -16 -24) (16 16 32)
|
|
Player takes no damage from water or slime
|
|
*/
|
|
void() item_artifact_envirosuit = {
|
|
self.netname = STR_EQUIPID_SUIT;
|
|
if (!self.model) self.model = "progs/suit.mdl";
|
|
if (!self.noise2) self.noise2 = "items/suit.wav";
|
|
if (!self.attack_finished) self.attack_finished = 30;
|
|
if (!self.mins && !self.maxs) {
|
|
self.mins = '-16 -16 -24';
|
|
self.maxs = '16 16 32';
|
|
}
|
|
if (!self.wait && !self.delay) {
|
|
self.wait = 55;
|
|
self.delay = 10;
|
|
}
|
|
|
|
precache_sound("items/suit2.wav");
|
|
|
|
equip_grant(self, EQUIPID_SUIT);
|
|
self.th_activate = _suit_activate;
|
|
|
|
item_generic();
|
|
};
|
|
|
|
// ===================================================================== //
|
|
|
|
void() item_artifact_super_damage;
|
|
void() _quad_die = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if ((powerup.attack_finished - time) >= 4) {
|
|
local entity oldself;
|
|
|
|
oldself = self;
|
|
|
|
self = spawn("ITEM_ARTIFACT_SUPER_DAMAGE");
|
|
self.origin = center(oldself);
|
|
|
|
self.movetype = MOVETYPE_TOSS;
|
|
self.velocity_x = crandom()*200;
|
|
self.velocity_y = crandom()*200;
|
|
self.velocity_z = 320;
|
|
|
|
self.wait = -1;
|
|
self.attack_finished = powerup.attack_finished - time;
|
|
|
|
self.think = SUB_remove;
|
|
self.nextthink = time + 20 + random()*10;
|
|
|
|
item_artifact_super_damage();
|
|
|
|
bprint(PRINT_HIGH, name(oldself), " dropped a Quad with ", ftos(floor(self.attack_finished)), " seconds remaining.\n");
|
|
|
|
self = oldself;
|
|
}
|
|
|
|
if (powerup.th_die)
|
|
powerup.th_die();
|
|
};
|
|
|
|
void(entity missile) _quad_attack = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (time >= powerup.pain_finished) {
|
|
sound(self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
|
|
powerup.pain_finished = time + 1;
|
|
}
|
|
|
|
missile.dmg *= 4;
|
|
missile.mass *= 4;
|
|
|
|
if (powerup.th_attack)
|
|
powerup.th_attack(missile);
|
|
};
|
|
|
|
#define STR_EQUIPID_QUAD "Quad Damage"
|
|
void() _quad_activate = {
|
|
local entity powerup;
|
|
|
|
powerup = override_create(other, "OVERRIDE_QUAD", OVERPRIO_QUAD);
|
|
powerup.th_takeitem = _powerup_takeitem;
|
|
powerup.th_attack = _quad_attack;
|
|
powerup.th_die = _quad_die;
|
|
powerup.prethink = _powerup_prethink;
|
|
powerup.actthink = _powerup_think;
|
|
powerup.postthink = _powerup_postthink;
|
|
override_finalize(powerup);
|
|
|
|
equip_grant(powerup, EQUIPID_QUAD);
|
|
powerup.items = IT_QUAD;
|
|
powerup.effects = EF_BLUE;
|
|
powerup.attack_finished = time + self.attack_finished;
|
|
|
|
powerup.noise = "items/damage2.wav";
|
|
powerup.air_finished = powerup.attack_finished - 3;
|
|
};
|
|
/*QUAKED item_artifact_super_damage (0 .5 .8) (-16 -16 -24) (16 16 32)
|
|
Attacks from the player will do 4x damage
|
|
*/
|
|
void() item_artifact_super_damage = {
|
|
self.netname = STR_EQUIPID_QUAD;
|
|
if (!self.model) self.model = "progs/quaddama.mdl";
|
|
if (!self.noise2) self.noise2 = "items/damage.wav";
|
|
if (!self.mins && !self.maxs) {
|
|
self.mins = '-16 -16 -24';
|
|
self.maxs = '16 16 32';
|
|
}
|
|
if (!self.attack_finished) self.attack_finished = 30;
|
|
if (!self.wait && !self.delay) {
|
|
self.wait = 55;
|
|
self.delay = 10;
|
|
}
|
|
if (!self.effects) self.effects = EF_BLUE;
|
|
|
|
if (sv_spawning) {
|
|
precache_sound("items/damage3.wav");
|
|
precache_sound("items/damage2.wav");
|
|
}
|
|
|
|
equip_grant(self, EQUIPID_QUAD);
|
|
self.th_activate = _quad_activate;
|
|
|
|
item_generic();
|
|
};
|
|
|
|
// ===================================================================== //
|
|
|
|
float(float dmg) _pentagram_takedamage = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (dmg == DAMAGE_MUSTDIE)
|
|
return powerup.th_takedamage(dmg);
|
|
|
|
if (dmg == DAMAGE_SHOULDDIE) {
|
|
if (self.dmg_attacker == self)
|
|
return powerup.th_takedamage(dmg);
|
|
|
|
local entity oldattacker, oldinflictor;
|
|
local float damaged;
|
|
|
|
oldattacker = self.dmg_attacker;
|
|
oldinflictor = self.dmg_inflictor;
|
|
|
|
damaged = damage(self.dmg_attacker, self, self.dmg_inflictor, dmg, self.deathmsg);
|
|
|
|
other = self.dmg_attacker = oldattacker;
|
|
oldinflictor = self.dmg_inflictor;
|
|
|
|
if (!damaged)
|
|
return powerup.th_takedamage(dmg);
|
|
}
|
|
|
|
damage_push(dmg);
|
|
damage_armor(dmg);
|
|
self.dmg_save = 0; // Avoid flashy stuff
|
|
|
|
if (time >= powerup.pain_finished) {
|
|
sound(self, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
|
|
powerup.pain_finished = time + 1.0;
|
|
}
|
|
|
|
deathmsg_nodisplay();
|
|
|
|
override_halt();
|
|
return FALSE;
|
|
};
|
|
|
|
#define STR_EQUIPID_PENTAGRAM "Pentagram of Protection"
|
|
void() _pentagram_activate = {
|
|
local entity powerup;
|
|
|
|
powerup = override_create(other, "OVERRIDE_PENTAGRAM", OVERPRIO_PENTAGRAM);
|
|
powerup.th_takeitem = _powerup_takeitem;
|
|
powerup.th_takedamage = _pentagram_takedamage;
|
|
powerup.prethink = _powerup_prethink;
|
|
powerup.actthink = _powerup_think;
|
|
powerup.postthink = _powerup_postthink;
|
|
override_finalize(powerup);
|
|
|
|
equip_grant(powerup, EQUIPID_PENTAGRAM);
|
|
powerup.items = IT_INVULNERABILITY;
|
|
powerup.effects = EF_RED;
|
|
powerup.attack_finished = time + self.attack_finished;
|
|
|
|
powerup.noise = "items/protect2.wav";
|
|
powerup.air_finished = powerup.attack_finished - 3;
|
|
};
|
|
/*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32)
|
|
Player is invulnerable
|
|
*/
|
|
void() item_artifact_invulnerability = {
|
|
self.netname = STR_EQUIPID_PENTAGRAM;
|
|
if (!self.model) self.model = "progs/invulner.mdl";
|
|
if (!self.noise2) self.noise2 = "items/protect.wav";
|
|
if (!self.mins && !self.maxs) {
|
|
self.mins = '-16 -16 -24';
|
|
self.maxs = '16 16 32';
|
|
}
|
|
if (!self.attack_finished) self.attack_finished = 30;
|
|
if (!self.wait && !self.delay) {
|
|
self.wait = 60;
|
|
self.delay = 10;
|
|
}
|
|
if (!self.effects) self.effects = EF_RED;
|
|
|
|
precache_sound("items/protect3.wav");
|
|
precache_sound("items/protect2.wav");
|
|
|
|
equip_grant(self, EQUIPID_PENTAGRAM);
|
|
self.th_activate = _pentagram_activate;
|
|
|
|
item_generic();
|
|
};
|
|
|
|
// ===================================================================== //
|
|
|
|
void() _ring_prethink = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (powerup_check_remove(powerup)) {
|
|
mdl_setup_player();
|
|
powerup_remove(powerup);
|
|
}
|
|
|
|
if (powerup.prethink)
|
|
powerup.prethink();
|
|
};
|
|
|
|
void() _ring_think = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (time > powerup.pain_finished) {
|
|
sound(self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
|
|
powerup.pain_finished = time + 1 + (random() * 3);
|
|
}
|
|
|
|
if (time > powerup.attack_finished) {
|
|
mdl_setup_player();
|
|
powerup_remove(powerup);
|
|
} else if (time >= powerup.air_finished) {
|
|
if (is_cl(self))
|
|
stuffcmd(self, "bf\n");
|
|
|
|
if (powerup.noise) {
|
|
sound(self, CHAN_AUTO, powerup.noise, 1, ATTN_NORM);
|
|
powerup.noise = NIL;
|
|
}
|
|
|
|
powerup.air_finished += 1;
|
|
}
|
|
|
|
if (powerup.actthink)
|
|
powerup.actthink();
|
|
};
|
|
|
|
#define STR_EQUIPID_RING "Ring of Shadows"
|
|
void() _ring_activate = {
|
|
local entity powerup, oldself;
|
|
|
|
powerup = override_create(other, "OVERRIDE_RING", OVERPRIO_RING);
|
|
powerup.th_takeitem = _powerup_takeitem;
|
|
powerup.prethink = _ring_prethink;
|
|
powerup.actthink = _ring_think;
|
|
powerup.postthink = _powerup_postthink;
|
|
override_finalize(powerup);
|
|
|
|
equip_grant(powerup, EQUIPID_RING);
|
|
powerup.items = IT_INVISIBILITY;
|
|
powerup.attack_finished = time + self.attack_finished;
|
|
|
|
powerup.noise = "items/inv2.wav";
|
|
powerup.air_finished = powerup.attack_finished - 3;
|
|
|
|
oldself = self;
|
|
self = other;
|
|
mdl_setup_eyes();
|
|
self = oldself;
|
|
};
|
|
/*QUAKED item_artifact_invisibility (0 .5 .8) (-16 -16 -24) (16 16 32)
|
|
Player is eyes model
|
|
*/
|
|
void() item_artifact_invisibility = {
|
|
self.netname = STR_EQUIPID_RING;
|
|
if (!self.model) self.model = "progs/invisibl.mdl";
|
|
if (!self.noise2) self.noise2 = "items/inv1.wav";
|
|
if (!self.mins && !self.maxs) {
|
|
self.mins = '-16 -16 -24';
|
|
self.maxs = '16 16 32';
|
|
}
|
|
if (!self.attack_finished) self.attack_finished = 30;
|
|
if (!self.wait && !self.delay) {
|
|
self.wait = 60;
|
|
self.delay = 10;
|
|
}
|
|
|
|
precache_sound("items/inv3.wav");
|
|
precache_sound("items/inv2.wav");
|
|
|
|
equip_grant(self, EQUIPID_RING);
|
|
self.th_activate = _ring_activate;
|
|
|
|
item_generic();
|
|
};
|
|
|
|
// ===================================================================== //
|
|
|
|
float() _megahealth_takeitem = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if ((powerup.itemfield_1 & other.itemfield_1)
|
|
|| (powerup.itemfield_2 & other.itemfield_2)
|
|
|| (powerup.itemfield_3 & other.itemfield_3)
|
|
|| (powerup.itemfield_4 & other.itemfield_4)) {
|
|
if (self.health < (self.max_health*2.5)) {
|
|
/* Act like we don't have it, to renew.. */
|
|
powerup_remove(powerup);
|
|
}
|
|
}
|
|
|
|
if (powerup.th_takeitem)
|
|
return powerup.th_takeitem();
|
|
return FALSE;
|
|
};
|
|
|
|
void() _megahealth_think = {
|
|
local entity powerup;
|
|
powerup = override_findself();
|
|
|
|
if (self.health <= self.max_health) {
|
|
powerup_remove(powerup);
|
|
} else if (time >= powerup.attack_finished) {
|
|
self.health -= 0.1;
|
|
if (self.health <= self.max_health) {
|
|
self.health = self.max_health;
|
|
powerup_remove(powerup);
|
|
}
|
|
}
|
|
|
|
if (powerup.actthink)
|
|
powerup.actthink();
|
|
};
|
|
|
|
#define STR_EQUIPID_MEGAHEALTH "Megahealth"
|
|
void() _megahealth_activate = {
|
|
local entity powerup;
|
|
|
|
powerup = override_create(other, "OVERRIDE_MEGAHEALTH", OVERPRIO_MEGAHEALTH);
|
|
powerup.th_takeitem = _megahealth_takeitem;
|
|
powerup.prethink = _powerup_prethink;
|
|
powerup.actthink = _megahealth_think;
|
|
powerup.postthink = _powerup_postthink;
|
|
override_finalize(powerup);
|
|
|
|
equip_grant(powerup, EQUIPID_MEGAHEALTH);
|
|
powerup.attack_finished = time + 3;
|
|
|
|
other.health += self.attack_finished;
|
|
if (other.health > (other.max_health*2.5))
|
|
other.health = other.max_health*2.5;
|
|
};
|
|
/*
|
|
*/
|
|
void() item_megahealth = {
|
|
if (!self.model) self.model = "maps/b_bh100.bsp";
|
|
if (!self.noise2) self.noise2 = "items/r_item2.wav";
|
|
if (!self.mins && !self.maxs) {
|
|
self.mins = '0 0 0';
|
|
self.maxs = '32 32 56';
|
|
}
|
|
if (!self.wait && !self.delay) {
|
|
self.wait = 30;
|
|
self.delay = 40;
|
|
}
|
|
|
|
if (!self.attack_finished) self.attack_finished = 100;
|
|
|
|
equip_grant(self, EQUIPID_MEGAHEALTH);
|
|
self.th_activate = _megahealth_activate;
|
|
|
|
item_generic();
|
|
};
|