heretic2-sdk/Toolkit/Programming/GameCode/game/g_shrine.c
1999-03-18 00:00:00 +00:00

1944 lines
51 KiB
C

// g_shrine.c
//
// Heretic II - Raven software
//
#include "FX.h"
#include "g_local.h"
#include "g_itemstats.h"
#include "random.h"
#include "vector.h"
#include "p_actions.h"
#include "p_anims.h"
#include "p_main.h"
#include "m_player.h"
#include "p_funcs.h"
#include "cl_strings.h"
// Set up those shrines that are randomly selectable.
char delay_text[] = "shrine respawn delay";
char chaos_text[] = "chaos shrine touch";
char health_text[] = "health shrine touch";
char mana_text[] = "mana shrine touch";
char light_text[] = "light shrine touch";
char lungs_text[] = "lungs shrine touch";
char run_text[] = "run shrine touch";
char staff_text[] = "staff shrine touch";
char powerup_text[] = "powerup shrine touch";
char ghost_text[] = "ghost shrine touch";
char reflect_text[] = "reflect shrine touch";
char armor_gold_text[] = "armor gold shrine touch";
char armor_silver_text[] = "armor silver shrine touch";
void player_shrine_health_effect(edict_t *self);
void player_shrine_armor_silver_effect(edict_t *self);
void player_shrine_armor_gold_effect(edict_t *self);
void player_shrine_lungs_effect(edict_t *self);
void player_shrine_light_effect(edict_t *self);
void player_shrine_staff_effect(edict_t *self);
void player_shrine_mana_effect(edict_t *self);
void player_shrine_ghost_effect(edict_t *self);
void player_shrine_reflect_effect(edict_t *self);
void player_shrine_powerup_effect(edict_t *self);
void player_shrine_speed_effect(edict_t *self);
void shrine_armor_silver_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
void shrine_armor_gold_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
void shrine_random_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
extern gitem_armor_t silver_armor_info;
extern gitem_armor_t gold_armor_info;
#define INVUN_TIME 2.0
// ************************************************************************************************
// PlayerKillShrineFX
// ------------------
// Remove all shrine effects associated with a player. Used when he's turned into a chicken.
// ************************************************************************************************
void PlayerKillShrineFX(edict_t *self)
{
playerinfo_t *playerinfo;
playerinfo=&self->client->playerinfo;
assert(playerinfo);
// --- Remove Reflection
// Remove time on the timer for the reflectivity.
self->client->playerinfo.reflect_timer = level.time - 1.0;
// Turn off the relection at the client effect end through client flags that are passed down.
self->s.renderfx &= ~RF_REFLECTION;
// --- Remove Ghosting.
// Remove time on the timer for the ghosting.
self->client->playerinfo.ghost_timer = level.time - 1.0;
// Turn off the ghosting at the client effect end through client flags that are passed down.
self->s.renderfx &= ~RF_TRANS_GHOST;
// --- Remove the light.
// Remove time on the timer for the light.
self->client->playerinfo.light_timer = level.time - 1.0;
// Turn off the light at the client effect end through client flags that are passed down.
self->s.effects &= ~EF_LIGHT_ENABLED;
// turn off the run shrine should we need to
self->s.effects &= ~EF_SPEED_ACTIVE;
gi.RemoveEffects(&self->s, FX_FOOT_TRAIL);
// Kill any lights that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_PLAYER_TORCH);
// Kill lungs.
self->client->playerinfo.lungs_timer = 0.0;
// Remove Armor.
self->client->playerinfo.pers.armor_count = 0;
// Turn off the armor at the model level.
playerinfo->pers.armortype = ARMOR_NONE;
SetupPlayerinfo_effects(self);
P_PlayerUpdateModelAttributes(&self->client->playerinfo);
WritePlayerinfo_effects(self);
// Remove Staff powerup.
self->client->playerinfo.pers.stafflevel = STAFF_LEVEL_BASIC;
// Remove Weapons powerup.
self->client->playerinfo.powerup_timer = level.time - 1.0;
// Kill any tomes that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_TOME_OF_POWER);
// Turn off the tome at the client effect end through client flags that are passed down.
self->s.effects &= ~EF_POWERUP_ENABLED;
}
// ************************************************************************************************
// PlayerRestartShrineFX
// ---------------------
// This is the routine that re-starts any client effects that need to be running. For instance,
// recovery of a saved game, where for example, the torch is active.
// ************************************************************************************************
void PlayerRestartShrineFX(edict_t *self)
{
// If we have a light, turn it on.
if (self->s.effects & EF_LIGHT_ENABLED)
{
// Kill any lights that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_PLAYER_TORCH);
// Create the light and the tome of power.
gi.CreateEffect(&self->s, FX_PLAYER_TORCH, CEF_OWNERS_ORIGIN, NULL, "");
}
// If we have a powerup, turn it on.
if (self->s.effects & EF_POWERUP_ENABLED)
{
// Kill any lights that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_TOME_OF_POWER);
// Create the light and the tome of power.
gi.CreateEffect(&self->s, FX_TOME_OF_POWER, CEF_OWNERS_ORIGIN, NULL, "");
}
// If we have a powerup, turn it on.
if (self->s.effects & EF_SPEED_ACTIVE)
{
// Kill any lights that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_FOOT_TRAIL);
// Create the light and the tome of power.
gi.CreateEffect(&self->s, FX_FOOT_TRAIL, CEF_OWNERS_ORIGIN, NULL, "");
}
}
// ************************************************************************************************
// G_PlayerActionShrineEffect
// --------------------------
// ************************************************************************************************
void G_PlayerActionShrineEffect(playerinfo_t *playerinfo)
{
edict_t *self;
self=(edict_t *)playerinfo->self;
switch(self->shrine_type)
{
case SHRINE_ARMOR_SILVER:
player_shrine_armor_silver_effect(self);
break;
case SHRINE_ARMOR_GOLD:
player_shrine_armor_gold_effect(self);
break;
case SHRINE_LIGHT:
player_shrine_light_effect(self);
break;
case SHRINE_HEAL:
player_shrine_health_effect(self);
break;
case SHRINE_STAFF:
player_shrine_staff_effect(self);
break;
case SHRINE_LUNGS:
player_shrine_lungs_effect(self);
break;
case SHRINE_GHOST:
player_shrine_ghost_effect(self);
break;
case SHRINE_REFLECT:
player_shrine_reflect_effect(self);
break;
case SHRINE_POWERUP:
player_shrine_powerup_effect(self);
break;
case SHRINE_MANA:
player_shrine_mana_effect(self);
break;
case SHRINE_SPEED:
player_shrine_speed_effect(self);
break;
default:
player_shrine_mana_effect(self);
break;
}
}
// ************************************************************************************************
// PlayerRandomShrineEffect
// ------------------------
// Called from the random Shrine - which one do we want to do?
// ************************************************************************************************
void PlayerRandomShrineEffect(edict_t *self, int value)
{
switch(value)
{
case SHRINE_ARMOR_SILVER:
player_shrine_armor_silver_effect(self);
break;
case SHRINE_ARMOR_GOLD:
player_shrine_armor_gold_effect(self);
break;
case SHRINE_LIGHT:
player_shrine_light_effect(self);
break;
case SHRINE_HEAL:
player_shrine_health_effect(self);
break;
case SHRINE_STAFF:
player_shrine_staff_effect(self);
break;
case SHRINE_LUNGS:
player_shrine_lungs_effect(self);
break;
case SHRINE_GHOST:
player_shrine_ghost_effect(self);
break;
case SHRINE_REFLECT:
player_shrine_reflect_effect(self);
break;
case SHRINE_POWERUP:
player_shrine_powerup_effect(self);
break;
case SHRINE_MANA:
player_shrine_mana_effect(self);
break;
case SHRINE_SPEED:
player_shrine_speed_effect(self);
break;
default:
player_shrine_powerup_effect(self);
break;
}
}
// ************************************************************************************************
// DelayThink
// ----------
// Wait till we can use this shrine again.
// ************************************************************************************************
void DelayThink(edict_t *self)
{
edict_t *dest;
vec3_t offset;
vec3_t offset2;
// Handle changing shrine types in deathmatch.
if (deathmatch->value && (self->oldtouch == shrine_armor_gold_touch))
{
// If we were gold in death match, we won't be again.
self->owner->touch = shrine_armor_silver_touch;
}
else if (deathmatch->value && (self->oldtouch == shrine_armor_silver_touch) && !(irand(0,8)))
{
// 1 in 9 chance in death match an armor shrine turns gold.
self->owner->touch = shrine_armor_gold_touch;
}
else
{
// Restore the touch pad.
self->owner->touch = self->oldtouch;
}
// Make the ball appear in the middle.
// Setup in playerinfo the destination entity of the teleport.
dest = G_Find (NULL, FOFS(targetname), self->owner->target);
if (!dest)
{
#ifdef _DEVEL
gi.dprintf ("Shrine Trigger couldn't find shrine model\n");
#endif
G_SetToFree (self);
return;
}
if (self->owner->touch == shrine_armor_gold_touch)
dest->style = 7;
else
if (self->owner->touch == shrine_armor_silver_touch)
dest->style = 6;
VectorScale(dest->s.angles, ANGLE_TO_RAD, offset);
DirFromAngles(offset, offset2);
dest->PersistantCFX=gi.CreatePersistantEffect(&dest->s,
FX_SHRINE_BALL,
CEF_BROADCAST,
dest->s.origin,
"db",
offset2,
(byte)(dest->style-1));
G_SetToFree (self);
}
// ************************************************************************************************
// deal_with_shrine_node
// ---------------------
// Either kill or set this shrine node to unuseable for a while.
// ************************************************************************************************
void deal_with_shrine_node(edict_t *self)
{
edict_t *delay,*dest;
vec3_t offset,offset2;
int time;
float clients;
// Set up a delay so we can't use this shrine for a while.
if (deathmatch->value || (self->spawnflags & 1))
{
delay = G_Spawn ();
delay->svflags |= SVF_NOCLIENT;
delay->movetype = PHYSICSTYPE_NONE;
delay->solid = SOLID_NOT;
delay->think = DelayThink;
delay->owner = self;
delay->classname = delay_text;
if (deathmatch->value)
// The equation for respawn:
// --The respawn times should be normal for 8 players.
// --For 32 players the respawn should be halved
// --For 2 players the respawn should be doubled.
{
/*
time = SHRINE_DELAY * sqrt((float)game.num_clients/8.0); // This makes it a nice curve. Clever, no?
// Lemme see here: sqrt(2/8) = sqrt(1/4) = 1/2
// sqrt(8/8) = sqrt(1) = 1
// sqrt(32/8) = sqrt(4) = 2
*/
clients=(float)game.num_clients;
if (clients<2.0)
clients=2.0;
time = SHRINE_DELAY * sqrt(2.0/clients); // Spawn more frequently when more players.
// Lemme see here: sqrt(2/2) = sqrt(1) = 1
// sqrt(2/8) = sqrt(1/4) = 1/2
// sqrt(2/32) = sqrt(1/16) = 1/4
}
else
{
time = SHRINE_DELAY;
}
// sanity check
if (time < 5)
time = 5;
delay->nextthink = level.time + time;
delay->oldtouch = self->touch;
gi.linkentity (delay);
}
// Turn off the touch for this shrine.
self->touch = NULL;
// Setup in playerinfo, the destination entity of the teleport.
dest = G_Find (NULL, FOFS(targetname), self->target);
if (!dest)
{
#ifdef _DEVEL
gi.dprintf ("Shrine Trigger couldn't find shrine model\n");
#endif
return;
}
// But kill the shrine ball thats out there for this shrine.
gi.RemoveEffects(&dest->s, FX_SHRINE_BALL);
// Kill the glowing ball in the middle.
if (dest->PersistantCFX)
{
gi.RemovePersistantEffect(dest->PersistantCFX, REMOVE_SHRINE);
dest->PersistantCFX = 0;
}
// Make the shrine ball explode.
VectorScale(dest->s.angles, ANGLE_TO_RAD, offset);
DirFromAngles(offset, offset2);
gi.CreateEffect(&dest->s,FX_SHRINE_BALL_EXPLODE,CEF_OWNERS_ORIGIN,dest->s.origin,"db",offset2,(byte)(dest->style-1));
}
void shrine_restore_player(edict_t *other)
{
// Stop us from being on fire.
if(other->fire_damage_time>level.time)
{
other->fire_damage_time = 0;
// Turn off CFX too.
other->s.effects &= ~EF_ON_FIRE;
}
// Stop bleeding.
other->client->playerinfo.flags &= ~PLAYER_FLAG_BLEED;
// Restore limbs!
// FIXME: maybe do some cool temp effect on these nodes to show they respawned?
ResetPlayerBaseNodes(other);
other->client->playerinfo.flags &= ~PLAYER_FLAG_NO_LARM;
other->client->playerinfo.flags &= ~PLAYER_FLAG_NO_RARM;
}
// ************************************************************************************************
// Health Shrine
// ************************************************************************************************
// Fire off the health shrine effect.
void player_shrine_health_effect(edict_t *self)
{
// Start up the shrine heal effect.
gi.CreateEffect(&self->s, FX_SHRINE_HEALTH, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine4.wav"),1,ATTN_NORM,0);
}
void shrine_heal_core(edict_t *self,edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Give us some health.
if (other->health < (SHRINE_MAX_HEALTH - SHRINE_HEALTH))
other->health += SHRINE_HEALTH;
else if (other->health < SHRINE_MAX_HEALTH)
other->health = SHRINE_MAX_HEALTH;
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// ************************************************************************************************
// shrine_heal_touch
// -----------------
// Fire off a heal effect and give us some health.
// ************************************************************************************************
void shrine_heal_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_heal_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_HEALTH);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_health_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_HEAL;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo,ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_heal (.5 .3 .5) ? PERMANENT
*/
void shrine_heal(edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_HEAL;
ent->classname = health_text;
if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_heal_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity(ent);
}
// ************************************************************************************************
// Silver armor shrine.
// ************************************************************************************************
// Fire off the armor shrine effect.
void player_shrine_armor_silver_effect(edict_t *self)
{
// Start up the shrine armor effect.
gi.CreateEffect(&self->s, FX_SHRINE_ARMOR, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine2.wav"),1,ATTN_NORM,0);
}
void shrine_armor_silver_core(edict_t *self,edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add armor to player.
if ((other->client->playerinfo.pers.armortype == ARMOR_TYPE_GOLD) &&
(other->client->playerinfo.pers.armor_count >= gold_armor_info.max_armor / 2))
other->client->playerinfo.pers.armor_count = gold_armor_info.max_armor;
else
{
other->client->playerinfo.pers.armortype = ARMOR_TYPE_SILVER;
other->client->playerinfo.pers.armor_count = silver_armor_info.max_armor;
}
SetupPlayerinfo_effects(other);
P_PlayerUpdateModelAttributes(&other->client->playerinfo);
WritePlayerinfo_effects(other);
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us some armor.
void shrine_armor_silver_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_armor_silver_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_SILVER);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
if (other->client->playerinfo.pers.armortype == ARMOR_TYPE_SILVER)
player_shrine_armor_silver_effect(other);
else
player_shrine_armor_gold_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_ARMOR_SILVER;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_armor (.5 .3 .5) ? PERMANENT
*/
void shrine_armor (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_ARMOR_SILVER;
ent->classname = armor_silver_text;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_armor_silver_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Armor shrine - gold.
// ************************************************************************************************
// Fire off the gold armor shrine effect.
void player_shrine_armor_gold_effect(edict_t *self)
{
// Start up the shrine armor effect.
gi.CreateEffect(&self->s, FX_SHRINE_ARMOR, CEF_OWNERS_ORIGIN|CEF_FLAG6, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine2.wav"),1,ATTN_NORM,0);
}
void shrine_armor_gold_core(edict_t *self,edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add gold armor to player.
other->client->playerinfo.pers.armortype = ARMOR_TYPE_GOLD;
other->client->playerinfo.pers.armor_count = gold_armor_info.max_armor;
SetupPlayerinfo_effects(other);
P_PlayerUpdateModelAttributes(&other->client->playerinfo);
WritePlayerinfo_effects(other);
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us some armor.
void shrine_armor_gold_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_armor_gold_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_GOLD);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_armor_gold_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_ARMOR_GOLD;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_armor_gold (.5 .3 .5) ? PERMANENT
*/
void shrine_armor_gold (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_ARMOR_GOLD;
ent->classname = armor_gold_text;
// No touch if flags say so.
if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_armor_gold_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Staff powerup shrine.
// ************************************************************************************************
// Fire off the staff shrine effect.
void player_shrine_staff_effect(edict_t *self)
{
int flags = CEF_OWNERS_ORIGIN;
// Start up the shrine staff effect.
if (self->client->playerinfo.pers.stafflevel == STAFF_LEVEL_POWER2)
{
flags |= CEF_FLAG6;
gi.sound(self,CHAN_ITEM,gi.soundindex("weapons/FirewallPowerCast.wav"),1,ATTN_NORM,0);
}
else
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine7.wav"),1,ATTN_NORM,0);
gi.CreateEffect(&self->s, FX_SHRINE_STAFF, flags, NULL, "");
// Do the SHRINE sound.
}
void shrine_staff_core(edict_t *self,edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add onto his staff.
if (other->client->playerinfo.pers.stafflevel < STAFF_LEVEL_MAX-1)
{
other->client->playerinfo.pers.stafflevel++;
SetupPlayerinfo_effects(other);
P_PlayerUpdateModelAttributes(&other->client->playerinfo);
WritePlayerinfo_effects(other);
}
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us a staff powerup.
void shrine_staff_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_staff_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_BLADE);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_staff_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_STAFF;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_staff (.5 .3 .5) ? PERMANENT
*/
void shrine_staff (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_STAFF;
ent->classname = staff_text;
if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_staff_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Lungs Shrine
// ************************************************************************************************
// Fire off the lungs shrine effect.
void player_shrine_lungs_effect(edict_t *self)
{
// Start up the shrine lung effect.
gi.CreateEffect(&self->s, FX_SHRINE_LUNGS, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine9.wav"),1,ATTN_NORM,0);
}
void shrine_lung_core(edict_t *self, edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add some time in on the timer for the lungs.
other->client->playerinfo.lungs_timer = LUNGS_DURATION;
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us lung power.
void shrine_lung_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_lung_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_LUNGS);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_lungs_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_LUNGS;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invulnerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_lung (.5 .3 .5) ? PERMANENT
*/
void shrine_lung (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_LUNGS;
ent->classname = lungs_text;
if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_lung_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Light Shrine
// ************************************************************************************************
// Fire off the shrine light effect .
void player_shrine_light_effect(edict_t *self)
{
assert(self->client);
// Kill any lights that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_PLAYER_TORCH);
// Create the light and the tome of power.
gi.CreateEffect(&self->s, FX_PLAYER_TORCH, CEF_OWNERS_ORIGIN, NULL, "");
// Start up the shrine light effect.
gi.CreateEffect(&self->s, FX_SHRINE_LIGHT, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine8.wav"),1,ATTN_NORM,0);
}
void shrine_light_core(edict_t *self, edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add some time in on the timer for the light.
other->client->playerinfo.light_timer = level.time + LIGHT_DURATION;
// Turn on the light.
other->s.effects |= EF_LIGHT_ENABLED;
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us some light.
void shrine_light_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_light_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_LIGHT);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_light_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_LIGHT;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_light (.5 .3 .5) ? PERMANENT
*/
void shrine_light (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_LIGHT;
ent->classname = light_text;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_light_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Mana Shrine
// ************************************************************************************************
// Fire off the shrine mana effect.
void player_shrine_mana_effect(edict_t *self)
{
// Start up the shrine mana effect.
gi.CreateEffect(&self->s, FX_SHRINE_MANA, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine1.wav"),1,ATTN_NORM,0);
}
void shrine_mana_core(edict_t *self, edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add mana.
other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(P_FindItem("Off-mana"))] = 100;
other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(P_FindItem("Def-mana"))] = 100;
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// We hit the mana shrine pad, give us some manna, do the animation.
void shrine_mana_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_mana_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_MANA);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_mana_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_MANA;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_mana (.5 .3 .5) ? PERMANENT
*/
void shrine_mana (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_MANA;
ent->classname = mana_text;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_mana_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Ghost (invisibilty) shrine.
// ************************************************************************************************
// Fire off the ghost shrine effect.
void player_shrine_ghost_effect(edict_t *self)
{
assert(self->client);
// Start up the shrine ghost effect.
gi.CreateEffect(&self->s, FX_SHRINE_GHOST, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine6.wav"),1,ATTN_NORM,0);
}
void shrine_ghost_core(edict_t *self,edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add some time in on the timer for the ghost effect.
other->client->playerinfo.ghost_timer = level.time + GHOST_DURATION;
// Update the model attributes for ghosting.
SetupPlayerinfo_effects(other);
P_PlayerUpdateModelAttributes(&other->client->playerinfo);
WritePlayerinfo_effects(other);
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us a ghosting for a while powerup.
void shrine_ghost_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_ghost_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_GHOST);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_ghost_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_GHOST;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invulnerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_ghost (.5 .3 .5) ? PERMANENT
*/
void shrine_ghost (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_GHOST;
ent->classname = ghost_text;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_ghost_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Spell reflecting shrine.
// ************************************************************************************************
// Fire off the reflect shrine effect.
void player_shrine_reflect_effect(edict_t *self)
{
assert(self->client);
// Start up the shrine staff effect.
gi.CreateEffect(&self->s, FX_SHRINE_REFLECT, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine3.wav"),1,ATTN_NORM,0);
}
void shrine_reflect_core(edict_t *self,edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add some time in on the timer for the reflectivity.
if (deathmatch->value)
other->client->playerinfo.reflect_timer = level.time + REFLECT_DURATION_DEATHMATCH;
else
other->client->playerinfo.reflect_timer = level.time + REFLECT_DURATION_SINGLE;
// Update the model attributes for the reflection skin.
SetupPlayerinfo_effects(other);
P_PlayerUpdateModelAttributes(&other->client->playerinfo);
WritePlayerinfo_effects(other);
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
// Fire off an effect and give us a reflecting for a while powerup.
void shrine_reflect_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_reflect_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_REFLECT);
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_reflect_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_REFLECT;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_reflect (.5 .3 .5) ? PERMANENT
*/
void shrine_reflect (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_REFLECT;
ent->classname = reflect_text;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_reflect_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Spell powerup Shrine
// ************************************************************************************************
// Fire off the powerup shrine effect.
void player_shrine_powerup_effect(edict_t *self)
{
assert(self->client);
// Kill any tomes that may already be out there for this player.
gi.RemoveEffects(&self->s, FX_TOME_OF_POWER);
// Create the tome of power.
gi.CreateEffect(&self->s, FX_TOME_OF_POWER, CEF_OWNERS_ORIGIN, NULL, "");
// Start up the shrine powerup effect.
gi.CreateEffect(&self->s, FX_SHRINE_POWERUP, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine5.wav"),1,ATTN_NORM,0);
}
// Fire off an effect and give us a powerup for a while.
void shrine_powerup_core (edict_t *self, edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add some time in on the timer for the reflectivity.
other->client->playerinfo.powerup_timer = level.time + POWERUP_DURATION;
// Turn on the light at the client end through client flags that are passed to the client.
other->s.effects |= EF_POWERUP_ENABLED;
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
void shrine_powerup_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_powerup_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_POWERUP);
// If we are in death match, don't make us go through the shrine anim, just/ start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_powerup_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_POWERUP;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_powerup (.5 .3 .5) ? PERMANENT
*/
void shrine_powerup (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_POWERUP;
ent->classname = powerup_text;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_powerup_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Speed Shrine
// ************************************************************************************************
// Fire off the powerup shrine effect.
void player_shrine_speed_effect(edict_t *self)
{
assert(self->client);
// Start up the shrine powerup effect.
gi.CreateEffect(&self->s, FX_SHRINE_SPEED, CEF_OWNERS_ORIGIN, NULL, "");
// Do the SHRINE sound.
gi.sound(self,CHAN_ITEM,gi.soundindex("items/shrine10.wav"),1,ATTN_NORM,0);
}
// Fire off an effect and give us double speed for a while
void shrine_speed_core (edict_t *self, edict_t *other)
{
if (other->deadflag != DEAD_NO)
return;
// If we are a chicken, lets make us a player again. Don't give him anything else.
if (other->flags & FL_CHICKEN)
{
other->morph_timer = level.time - 0.1;
return;
}
// Add some time in on the timer for speeding
other->client->playerinfo.speed_timer = level.time + SPEED_DURATION;
// Turn on the speed at the client level.
other->s.effects |= EF_SPEED_ACTIVE;
// Kill any tomes that may already be out there for this player.
gi.RemoveEffects(&other->s, FX_FOOT_TRAIL);
// Create the tome of power.
gi.CreateEffect(&other->s, FX_FOOT_TRAIL, CEF_OWNERS_ORIGIN, NULL, "");
// restore dismemberment, and stop us being on fire
shrine_restore_player(other);
}
void shrine_speed_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// If we aren't a player, forget it.
if (!other->client)
return;
shrine_speed_core(self,other);
gi.gamemsg_centerprintf(other, GM_S_SPEED);
// If we are in death match, don't make us go through the shrine anim, just/ start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
player_shrine_speed_effect(other);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = SHRINE_SPEED;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invunerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_speed (.5 .3 .5) ? PERMANENT
*/
void shrine_speed (edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_SPEED;
ent->classname = run_text;
if (no_runshrine->value)
return;
if (!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_speed_touch;
if(deathmatch->value && ((int)dmflags->value & DF_SHRINE_CHAOS) && !((int)dmflags->value & DF_NO_SHRINE))
{
ent->shrine_type = SHRINE_RANDOM;
ent->touch = shrine_random_touch;
}
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}
// ************************************************************************************************
// Random shrine.
// ************************************************************************************************
#define POSSIBLE_RANDOM_SHRINES 9
int possible_shrines[POSSIBLE_RANDOM_SHRINES] =
{
SHRINE_MANA,
SHRINE_STAFF,
SHRINE_ARMOR_SILVER,
SHRINE_ARMOR_GOLD,
};
// Fire off an effect and give us a powerup for a while powerup.
void shrine_random_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
int random_shrine_num;
int total_rand_count = 0;
int possible_shrines[10];
// If we aren't a player, forget it!
if (!other->client)
return;
if(other->client->playerinfo.flags&PLAYER_FLAG_BLEED||
other->client->playerinfo.flags&PLAYER_FLAG_NO_LARM||
other->client->playerinfo.flags&PLAYER_FLAG_NO_RARM)
{
// Always heal if they're missing a limb or bleeding to death - should it give full health
// too though?
random_shrine_num = SHRINE_HEAL;
}
else
{
// here's where we make the shrines clever. If we already have a shrine option, lets remove it from
// the possible shrine list
if (other->client->playerinfo.speed_timer < level.time)
{
if (!no_runshrine->value)
{
possible_shrines[total_rand_count] = SHRINE_SPEED;
total_rand_count++;
}
}
if (other->health < SHRINE_MAX_HEALTH)
{
possible_shrines[total_rand_count] = SHRINE_HEAL;
total_rand_count++;
}
if (other->client->playerinfo.powerup_timer < level.time)
{
possible_shrines[total_rand_count] = SHRINE_POWERUP;
total_rand_count++;
}
if (other->client->playerinfo.ghost_timer < level.time)
{
possible_shrines[total_rand_count] = SHRINE_GHOST;
total_rand_count++;
}
if (other->client->playerinfo.reflect_timer < level.time)
{
if (!irand(0,1))
{ // Reflection shrines appear 50% as often as other shrines.
possible_shrines[total_rand_count] = SHRINE_REFLECT;
total_rand_count++;
}
}
if ((other->client->playerinfo.pers.armortype != ARMOR_TYPE_GOLD) ||
(!other->client->playerinfo.pers.armor_count))
{
possible_shrines[total_rand_count] = SHRINE_ARMOR_GOLD;
total_rand_count++;
}
if ((other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(P_FindItem("Off-mana"))] < 100) ||
(other->client->playerinfo.pers.inventory.Items[ITEM_INDEX(P_FindItem("Def-mana"))] < 100))
{
possible_shrines[total_rand_count] = SHRINE_MANA;
total_rand_count++;
}
if (other->client->playerinfo.pers.stafflevel < STAFF_LEVEL_MAX-1)
{
possible_shrines[total_rand_count] = SHRINE_STAFF;
total_rand_count++;
}
if (((other->client->playerinfo.pers.armortype != ARMOR_TYPE_GOLD) &&
(other->client->playerinfo.pers.armortype != ARMOR_TYPE_SILVER)) ||
(!other->client->playerinfo.pers.armor_count))
{
possible_shrines[total_rand_count] = SHRINE_ARMOR_SILVER;
total_rand_count++;
}
// if we have everything, give us a powerup. thats always helpful
if (!total_rand_count)
random_shrine_num = SHRINE_POWERUP;
else
random_shrine_num = possible_shrines[irand(0,total_rand_count)];
}
// Give us whatever we should have from this shrine.
switch(random_shrine_num)
{
case SHRINE_HEAL:
shrine_heal_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_HEALTH);
break;
case SHRINE_ARMOR_SILVER:
shrine_armor_silver_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_SILVER);
break;
case SHRINE_ARMOR_GOLD:
shrine_armor_gold_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_GOLD);
break;
case SHRINE_MANA:
shrine_mana_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_MANA);
break;
case SHRINE_STAFF:
shrine_staff_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_BLADE);
break;
case SHRINE_GHOST:
shrine_ghost_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_GHOST);
break;
case SHRINE_REFLECT:
shrine_reflect_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_REFLECT);
break;
case SHRINE_POWERUP:
shrine_powerup_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_POWERUP);
break;
case SHRINE_SPEED:
shrine_speed_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_SPEED);
break;
default:
shrine_powerup_core(self,other);
gi.gamemsg_centerprintf(other, GM_CS_POWERUP);
break;
}
// If we are in death match, don't make us go through the shrine anim, just start the effect,
// give us whatever, and leave it at that.
if (deathmatch->value || (other->flags & FL_CHICKEN) || (other->client->playerinfo.flags & PLAYER_FLAG_WATER))
{
PlayerRandomShrineEffect(other, random_shrine_num);
}
else
{
// Tell us what sort of shrine we just hit.
other->shrine_type = random_shrine_num;
// Initialise the shrine animation.
P_PlayerAnimSetLowerSeq(&other->client->playerinfo, ASEQ_SHRINE);
// Make us invulnerable for a couple of seconds.
other->client->shrine_framenum = level.time + INVUN_TIME;
}
// Decide whether to delete this shrine or disable it for a while.
deal_with_shrine_node(self);
}
/*QUAKED shrine_random (.5 .3 .5) ? PERMANENT
*/
void shrine_random(edict_t *ent)
{
ent->movetype = PHYSICSTYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
ent->solid = SOLID_TRIGGER;
ent->shrine_type = SHRINE_RANDOM;
ent->classname = chaos_text;
if(!deathmatch->value || (deathmatch->value && !((int)dmflags->value & DF_NO_SHRINE)))
ent->touch = shrine_random_touch;
gi.setmodel(ent, ent->model);
gi.linkentity (ent);
}