game-source/klik/mapents/mapents_powerup.qc

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