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