void PlagueCloudSpawn (edict_t *ent) { float radius; edict_t *e=NULL; if (ent->myskills.abilities[PLAGUE].disable) return; if (!V_CanUseAbilities(ent, PLAGUE, 0, false)) return; if ((ent->myskills.class_num == CLASS_POLTERGEIST) && !ent->mtype && !PM_PlayerHasMonster(ent)) return; // can't use this in human form radius = PLAGUE_DEFAULT_RADIUS+PLAGUE_ADDON_RADIUS*ent->myskills.abilities[PLAGUE].current_level; if (radius > PLAGUE_MAX_RADIUS) radius = PLAGUE_MAX_RADIUS; // find someone nearby to infect while ((e = findradius(e, ent->s.origin, radius)) != NULL) { if (!G_ValidTarget(ent, e, true)) continue; // if (HasActiveCurse(e, CURSE_PLAGUE)) if (que_typeexists(e->curses, CURSE_PLAGUE)) continue; // holy water grants temporary immunity to curses if (e->holywaterProtection > level.time) continue; PlagueCloud(ent, e); } }
void MindAbsorb(edict_t *ent) { edict_t *target = NULL; int radius; int take; int total; int abilityLevel = ent->myskills.abilities[MIND_ABSORB].current_level; if(ent->myskills.abilities[MIND_ABSORB].disable) return; if (!V_CanUseAbilities(ent, MIND_ABSORB, 0, false)) return; //Cloaking and chat protected players can't steal anything if ((ent->flags & FL_CHATPROTECT) || (ent->svflags & SVF_NOCLIENT)) return; take = MIND_ABSORB_AMOUNT_BASE + (MIND_ABSORB_AMOUNT_BONUS * abilityLevel); radius = MIND_ABSORB_RADIUS_BASE + (MIND_ABSORB_RADIUS_BONUS * abilityLevel); // scan for targets while ((target = findclosestradius(target, ent->s.origin, radius)) != NULL) { if (target == ent) continue; if (!G_ValidTarget(ent, target, true)) continue; total = 0; if (target->client) { if (target->client->pers.inventory[power_cube_index] < take) total += target->client->pers.inventory[power_cube_index]; else total += take; target->client->pers.inventory[power_cube_index] -= total; // a bit of amnesia too target->client->ability_delay = level.time + 0.1 * abilityLevel; } else { if (target->health < take) total += target->health; else total += take; } //Cap cube count to max cubes if (ent->client->pers.inventory[power_cube_index] + total < MAX_POWERCUBES(ent)) ent->client->pers.inventory[power_cube_index] += total; else if (ent->client->pers.inventory[power_cube_index] < MAX_POWERCUBES(ent)) ent->client->pers.inventory[power_cube_index] = MAX_POWERCUBES(ent); // those powercubes hurt! T_Damage(target, ent, ent, vec3_origin, vec3_origin, vec3_origin, total, 0, DAMAGE_NO_ARMOR, MOD_MINDABSORB); } }
void Cmd_WormHole_f (edict_t *ent) { // allow wormhole exit if (ent->flags & FL_WORMHOLE) SpawnWormhole(ent, 0); if (!V_CanUseAbilities(ent, BLACKHOLE, BLACKHOLE_COST, true)) return; if (ent->myskills.abilities[BLACKHOLE].disable) return; SpawnWormhole(ent, 1); }
void Cmd_Decoy_f (edict_t *ent) { if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_Decoy_f()\n", ent->client->pers.netname); if (!V_CanUseAbilities(ent, DECOY, M_DEFAULT_COST, true)) return; if (MirroredEntitiesExist(ent)) { gi.cprintf(ent, PRINT_HIGH, "You already have decoys out!\n"); return; } SpawnDrone(ent, 20, false); }
void Cmd_Curse(edict_t *ent) { int range, radius, talentLevel, cost=CURSE_COST; float duration; edict_t *target = NULL; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_Curse()\n", ent->client->pers.netname); //Talent: Cheaper Curses if ((talentLevel = getTalentLevel(ent, TALENT_CHEAPER_CURSES)) > 0) cost *= 1.0 - 0.1 * talentLevel; if (!V_CanUseAbilities(ent, CURSE, cost, true)) return; range = CURSE_DEFAULT_INITIAL_RANGE + CURSE_DEFAULT_ADDON_RANGE * ent->myskills.abilities[CURSE].current_level; radius = CURSE_DEFAULT_INITIAL_RADIUS + CURSE_DEFAULT_ADDON_RADIUS * ent->myskills.abilities[CURSE].current_level; duration = CURSE_DURATION_BASE + (CURSE_DURATION_BONUS * ent->myskills.abilities[CURSE].current_level); //Talent: Evil curse talentLevel = getTalentLevel(ent, TALENT_EVIL_CURSE); if(talentLevel > 0) duration *= 1.0 + 0.25 * talentLevel; if (duration < 1) duration = 1; CurseRadiusAttack(ent, CURSE, range, radius, duration, true); //Finish casting the spell //ent->client->ability_delay = level.time + CURSE_DELAY; ent->myskills.abilities[CURSE].delay = level.time + CURSE_DELAY; ent->client->pers.inventory[power_cube_index] -= cost; target = curse_Attack(ent, CURSE, radius, duration, true); //Play the spell sound! gi.sound(ent, CHAN_ITEM, gi.soundindex("curses/curse.wav"), 1, ATTN_NORM, 0); }
void Cmd_LowerResist (edict_t *ent) { int range, radius, talentLevel, cost=LOWER_RESIST_COST; float duration; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_LowerResist()\n", ent->client->pers.netname); //Talent: Cheaper Curses if ((talentLevel = getTalentLevel(ent, TALENT_CHEAPER_CURSES)) > 0) cost *= 1.0 - 0.1 * talentLevel; if (!V_CanUseAbilities(ent, LOWER_RESIST, cost, true)) return; range = LOWER_RESIST_INITIAL_RANGE + LOWER_RESIST_ADDON_RANGE * ent->myskills.abilities[LOWER_RESIST].current_level; radius = LOWER_RESIST_INITIAL_RADIUS + LOWER_RESIST_ADDON_RADIUS * ent->myskills.abilities[LOWER_RESIST].current_level; duration = LOWER_RESIST_INITIAL_DURATION + LOWER_RESIST_ADDON_DURATION * ent->myskills.abilities[LOWER_RESIST].current_level; // evil curse talent talentLevel = getTalentLevel(ent, TALENT_EVIL_CURSE); if(talentLevel > 0) duration *= 1.0 + 0.25 * talentLevel; if (duration < 1) duration = 1; CurseRadiusAttack(ent, LOWER_RESIST, range, radius, duration, true); //Finish casting the spell //ent->client->ability_delay = level.time + LOWER_RESIST_DELAY; ent->myskills.abilities[LOWER_RESIST].delay = level.time + LOWER_RESIST_DELAY; ent->client->pers.inventory[power_cube_index] -= cost; //Play the spell sound! gi.sound(ent, CHAN_ITEM, gi.soundindex("curses/lowerresist.wav"), 1, ATTN_NORM, 0); }
void Cmd_PlayerToMedic_f (edict_t *ent) { vec3_t boxmin, boxmax; trace_t tr; int cost = MEDIC_INIT_COST; //Talent: More Ammo int talentLevel = getTalentLevel(ent, TALENT_MORE_AMMO); if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToMedic_f()\n", ent->client->pers.netname); // try to switch back if (ent->mtype || PM_PlayerHasMonster(ent)) { // don't let a player-tank unmorph if they are cocooned if (ent->owner && ent->owner->inuse && ent->owner->movetype == MOVETYPE_NONE) return; if (que_typeexists(ent->curses, 0)) { safe_cprintf(ent, PRINT_HIGH, "You can't morph while cursed!\n"); return; } V_RestoreMorphed(ent, 0); return; } //Talent: Morphing if(getTalentSlot(ent, TALENT_MORPHING) != -1) cost *= 1.0 - 0.25 * getTalentLevel(ent, TALENT_MORPHING); // if (!G_CanUseAbilities(ent, ent->myskills.abilities[MEDIC].current_level, cost)) // return; if (!V_CanUseAbilities(ent, MEDIC, cost, true)) return; if (HasFlag(ent)) { safe_cprintf(ent, PRINT_HIGH, "Can't morph while carrying flag!\n"); return; } // make sure don't get stuck in a wall VectorSet (boxmin, -24, -24, -24); VectorSet (boxmax, 24, 24, 32); tr = gi.trace(ent->s.origin, boxmin, boxmax, ent->s.origin, ent, MASK_SHOT); if (tr.fraction<1) { safe_cprintf(ent, PRINT_HIGH, "Not enough room to morph!\n"); return; } V_ModifyMorphedHealth(ent, MORPH_MEDIC, true); VectorCopy(boxmin, ent->mins); VectorCopy(boxmax, ent->maxs); ent->monsterinfo.attack_finished = level.time + 0.5;// can't attack immediately ent->client->pers.inventory[power_cube_index] -= cost; ent->client->ability_delay = level.time + MEDIC_DELAY; ent->mtype = MORPH_MEDIC; ent->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2"); ent->s.modelindex2 = 0; if (!ent->myskills.administrator) ent->s.skinnum = 0; else ent->s.skinnum = 2; // commander // set maximum hyperblaster ammo ent->myskills.abilities[MEDIC].max_ammo = MEDIC_HB_INITIAL_AMMO+MEDIC_HB_ADDON_AMMO *ent->myskills.abilities[MEDIC].current_level; // Talent: More Ammo // increases ammo 10% per talent level if(talentLevel > 0) ent->myskills.abilities[MEDIC].max_ammo *= 1.0 + 0.1*talentLevel; // give them some starting ammo ent->myskills.abilities[MEDIC].ammo = MEDIC_HB_START_AMMO; ent->client->refire_frames = 0; // reset charged weapon ent->client->weapon_mode = 0; // reset weapon mode lasersight_off(ent); gi.sound (ent, CHAN_WEAPON, gi.soundindex("spells/morph.wav") , 1, ATTN_NORM, 0); }
void Cmd_PlayerToParasite_f (edict_t *ent) { int para_cubecost = PARASITE_INIT_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToParasite_f()\n", ent->client->pers.netname); // try to switch back if (ent->mtype || PM_PlayerHasMonster(ent)) { // don't let a player-tank unmorph if they are cocooned if (ent->owner && ent->owner->inuse && ent->owner->movetype == MOVETYPE_NONE) return; if (que_typeexists(ent->curses, 0)) { gi.cprintf(ent, PRINT_HIGH, "You can't morph while cursed!\n"); return; } V_RestoreMorphed(ent, 0); return; } //Talent: Morphing if(getTalentSlot(ent, TALENT_MORPHING) != -1) para_cubecost *= 1.0 - 0.25 * getTalentLevel(ent, TALENT_MORPHING); // if (!G_CanUseAbilities(ent, ent->myskills.abilities[BLOOD_SUCKER].current_level, para_cubecost)) // return; if (!V_CanUseAbilities(ent, BLOOD_SUCKER, para_cubecost, true)) return; if (HasFlag(ent)) { gi.cprintf(ent, PRINT_HIGH, "Can't morph while carrying flag!\n"); return; } V_ModifyMorphedHealth(ent, M_MYPARASITE, true); ent->wait = level.time + 0.5;// can't attack immediately ent->client->pers.inventory[power_cube_index] -= para_cubecost; ent->client->ability_delay = level.time + PARASITE_DELAY; ent->mtype = M_MYPARASITE; ent->s.modelindex = gi.modelindex ("models/monsters/parasite/tris.md2"); ent->s.modelindex2 = 0; ent->s.skinnum = 0; // decloak ent->svflags &= ~SVF_NOCLIENT; ent->client->cloaking = false; ent->client->cloakable = 0; ent->maxs[2] = 8; ent->viewheight = 0; ent->client->refire_frames = 0; // reset charged weapon ent->client->weapon_mode = 0; // reset weapon mode lasersight_off(ent); gi.sound (ent, CHAN_WEAPON, gi.soundindex("spells/morph.wav") , 1, ATTN_NORM, 0); }
void SpawnTotem(edict_t *ent, int abilityID) { int talentLevel, cost=TOTEM_COST; edict_t *totem; int totemType; vec3_t start;//GHz 4.32 // cost is doubled if you are a flyer or cacodemon below skill level 5 if ((ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) || (ent->mtype == MORPH_CACODEMON && ent->myskills.abilities[CACODEMON].current_level < 5)) cost *= 2; if(!V_CanUseAbilities(ent, abilityID, cost, true)) return; if (ctf->value && abilityID == FIRE_TOTEM && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) { safe_cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); return; } //Determine the totem type. switch(abilityID) { case FIRE_TOTEM: totemType = TOTEM_FIRE; break; case WATER_TOTEM: totemType = TOTEM_WATER; break; case AIR_TOTEM: totemType = TOTEM_AIR; break; case EARTH_TOTEM: totemType = TOTEM_EARTH; break; case DARK_TOTEM: totemType = TOTEM_DARKNESS; break; case NATURE_TOTEM: totemType = TOTEM_NATURE; break; default: return; } //Can't create too many totems. if(ent->totem1) { //Can't have more than one totem without the talent. /*if(getTalentLevel(ent, TALENT_TOTEM) < 1) { safe_cprintf(ent, PRINT_HIGH, "You already have a totem active.\n"); return; } //Can't have more than two totems. else*/ if(ent->totem2) { safe_cprintf(ent, PRINT_HIGH, "You already have two totems active.\n"); return; } //Can't have two totems of opposite alignment. else { int opposite = 0; switch(ent->totem1->mtype) { case TOTEM_FIRE: opposite = TOTEM_WATER; break; case TOTEM_WATER: opposite = TOTEM_FIRE; break; case TOTEM_AIR: opposite = TOTEM_EARTH; break; case TOTEM_EARTH: opposite = TOTEM_AIR; break; case TOTEM_DARKNESS: opposite = TOTEM_NATURE; break; case TOTEM_NATURE: opposite = TOTEM_DARKNESS; break; } if(totemType == opposite) { safe_cprintf(ent, PRINT_HIGH, "You can't create two totems of opposite elemental alignment.\n"); return; } else if(totemType == ent->totem1->mtype) { safe_cprintf(ent, PRINT_HIGH, "You can't create totems of the same type.\n"); return; } } } //Drop a totem. totem = DropTotem(ent); totem->mtype = totemType; totem->monsterinfo.level = ent->myskills.abilities[abilityID].current_level; totem->classname = "totem"; /*totem->owner =*/ totem->activator = ent; totem->think = totem_general_think; totem->touch = totem_touch; totem->nextthink = level.time + FRAMETIME*2; totem->delay = level.time + 0.5; totem->die = totem_die; //TODO: update this with the new model. totem->s.modelindex = gi.modelindex("models/items/mega_h/tris.md2"); //totem->s.angles[ROLL] = 270; VectorSet (totem->mins, -8, -8, -12); VectorSet (totem->maxs, 8, 8, 16); VectorCopy(ent->s.origin, totem->s.origin); totem->health = TOTEM_HEALTH_BASE + TOTEM_HEALTH_MULT * totem->monsterinfo.level; //Talent: Totemic Focus - increases totem health if((talentLevel = getTalentLevel(ent, TALENT_TOTEM)) > 0) totem->health *= 1 + 0.1666 * talentLevel; if (totemType == TOTEM_FIRE) { // fire totem is much tougher totem->health *= 2; // fire totem has a longer delay totem->delay = level.time + 2.0; } totem->max_health = totem->health*2; //Not sure if this stuff is needed (Archer) totem->svflags |= SVF_MONSTER; totem->takedamage = DAMAGE_AIM; totem->clipmask = MASK_MONSTERSOLID; //Back to stuff we need totem->mass = 200; totem->movetype = MOVETYPE_TOSS;//MOVETYPE_WALK; totem->deadflag = DEAD_NO; totem->svflags &= ~SVF_DEADMONSTER; totem->solid = SOLID_BBOX; //Graphical effects //TODO: update this to make it look better. totem->s.effects |= EF_PLASMA | EF_COLOR_SHELL | EF_SPHERETRANS; switch(totemType) { case TOTEM_FIRE: totem->s.effects |= 262144; //red radius light totem->s.renderfx |= RF_SHELL_RED; break; case TOTEM_WATER: totem->s.effects |= 524288; //blue radius light totem->s.renderfx |= RF_SHELL_CYAN; break; case TOTEM_AIR: totem->s.effects |= 64; //bright light radius totem->s.renderfx |= RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN; break; case TOTEM_EARTH: totem->s.renderfx |= RF_SHELL_YELLOW; break; case TOTEM_DARKNESS: totem->s.effects |= 2147483648; //strange darkness effect //totem->s.renderfx |= RF_SHELL_RED | RF_SHELL_BLUE; break; case TOTEM_NATURE: totem->s.effects |= 128; //green radius light totem->s.renderfx |= RF_SHELL_GREEN; break; } //GHz 4.32 if (!G_GetSpawnLocation(ent, 64, totem->mins, totem->maxs, start)) { G_FreeEdict(totem); return; } VectorCopy(start, totem->s.origin); gi.linkentity(totem); //GHz if(!ent->totem1) ent->totem1 = totem; else ent->totem2 = totem; ent->client->pers.inventory[ITEM_INDEX(Fdi_POWERCUBE)] -= cost; // calling entity made a sound, used to alert monsters ent->lastsound = level.framenum; ent->client->ability_delay = level.time + 1.3; }
void Cmd_PlayerToBerserk_f (edict_t *ent) { int cost = BERSERK_COST; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_PlayerToBerserk_f()\n", ent->client->pers.netname); // try to switch back if (ent->mtype || PM_PlayerHasMonster(ent)) { // don't let a player-tank unmorph if they are cocooned if (ent->owner && ent->owner->inuse && ent->owner->movetype == MOVETYPE_NONE) return; if (que_typeexists(ent->curses, 0)) { safe_cprintf(ent, PRINT_HIGH, "You can't morph while cursed!\n"); return; } V_RestoreMorphed(ent, 0); return; } //Talent: Morphing if (vrx_get_talent_slot(ent, TALENT_MORPHING) != -1) cost *= 1.0 - 0.25 * vrx_get_talent_level(ent, TALENT_MORPHING); if (!V_CanUseAbilities(ent, BERSERK, cost, true)) return; if (HasFlag(ent) && !hw->value) { safe_cprintf(ent, PRINT_HIGH, "Can't morph while carrying flag!\n"); return; } V_ModifyMorphedHealth(ent, MORPH_BERSERK, true); ent->monsterinfo.attack_finished = level.time + 0.5;// can't attack immediately ent->client->pers.inventory[power_cube_index] -= cost; ent->client->ability_delay = level.time + BERSERK_DELAY; ent->mtype = MORPH_BERSERK; ent->s.modelindex = gi.modelindex ("models/monsters/berserk/tris.md2"); ent->s.modelindex2 = 0; ent->s.skinnum = 0; // undo crouching / ducked state // try asking their client to get up stuffcmd(ent, "-movedown\n"); // if their client ignores the command, force them up if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { ent->client->ps.pmove.pm_flags &= ~PMF_DUCKED; ent->viewheight = 22; ent->maxs[2] += 28; } ent->client->refire_frames = 0; // reset charged weapon ent->client->weapon_mode = 0; // reset weapon mode ent->client->pers.weapon = NULL; ent->client->ps.gunindex = 0; lasersight_off(ent); gi.sound(ent, CHAN_WEAPON, gi.soundindex("abilities/morph.wav"), 1, ATTN_NORM, 0); }
void Cmd_Bless(edict_t *ent) { int radius; float duration, cooldown; edict_t *target = NULL; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_Bless()\n", ent->client->pers.netname); if(ent->myskills.abilities[BLESS].disable) return; //if (!G_CanUseAbilities(ent, ent->myskills.abilities[BLESS].current_level, BLESS_COST)) // return; if (!V_CanUseAbilities(ent, BLESS, BLESS_COST, true)) return; radius = SHAMAN_CURSE_RADIUS_BASE + (SHAMAN_CURSE_RADIUS_BONUS * ent->myskills.abilities[BLESS].current_level); duration = BLESS_DURATION_BASE + (BLESS_DURATION_BONUS * ent->myskills.abilities[BLESS].current_level); //Blessing self? if (Q_strcasecmp(gi.argv(1), "self") == 0) { if (HasFlag(ent)) { gi.cprintf(ent, PRINT_HIGH, "Can't use this while carrying the flag!\n"); return; } if (!curse_add(ent, ent, BLESS, 0, duration)) { gi.cprintf(ent, PRINT_HIGH, "Unable to bless self.\n"); return; } target = ent; } else { target = curse_Attack(ent, BLESS, radius, duration, false); } if (target != NULL) { que_t *slot = NULL; //Finish casting the spell ent->client->ability_delay = level.time + BLESS_DELAY; ent->client->pers.inventory[power_cube_index] -= BLESS_COST; cooldown = 2.0 * duration; if (cooldown > 10.0) cooldown = 10.0; ent->myskills.abilities[BLESS].delay = level.time + cooldown; //Change the curse think to the bless think slot = que_findtype(target->curses, NULL, BLESS); if (slot) { slot->ent->think = Bless_think; slot->ent->nextthink = level.time + FRAMETIME; } //Notify the target if (target == ent) { gi.cprintf(target, PRINT_HIGH, "YOU HAVE BEEN BLESSED FOR %0.1f seconds!!\n", duration); } else if ((target->client) && !(target->svflags & SVF_MONSTER)) { gi.cprintf(target, PRINT_HIGH, "YOU HAVE BEEN BLESSED FOR %0.1f seconds!!\n", duration); gi.cprintf(ent, PRINT_HIGH, "Blessed %s for %0.1f seconds.\n", target->myskills.player_name, duration); } else { gi.cprintf(ent, PRINT_HIGH, "Blessed %s for %0.1f seconds.\n", target->classname, duration); } //Play the spell sound! gi.sound(target, CHAN_ITEM, gi.soundindex("curses/bless.wav"), 1, ATTN_NORM, 0); } }
void Cmd_Deflect_f(edict_t *ent) { float duration; edict_t *target = ent; // default target is self if (!V_CanUseAbilities(ent, DEFLECT, DEFLECT_COST, true)) return; duration = DEFLECT_INITIAL_DURATION + DEFLECT_ADDON_DURATION * ent->myskills.abilities[DEFLECT].current_level; // bless the tank instead of the noclipped player if (PM_PlayerHasMonster(ent)) target = target->owner; //Blessing self? if (Q_strcasecmp(gi.argv(1), "self") == 0) { if (!curse_add(target, ent, DEFLECT, 0, duration)) { gi.cprintf(ent, PRINT_HIGH, "Unable to bless self.\n"); return; } //target = ent; } else { target = curse_Attack(ent, DEFLECT, 512.0, duration, false); } if (target != NULL) { que_t *slot = NULL; //Finish casting the spell ent->client->ability_delay = level.time + DEFLECT_DELAY; ent->client->pers.inventory[power_cube_index] -= DEFLECT_COST; // ent->myskills.abilities[DEFLECT].delay = level.time + duration + DEFLECT_DELAY; //Change the curse think to the deflect think slot = que_findtype(target->curses, NULL, DEFLECT); if (slot) { slot->ent->think = deflect_think; slot->ent->nextthink = level.time + FRAMETIME; slot->ent->random = DEFLECT_INITIAL_PROJECTILE_CHANCE+DEFLECT_ADDON_HITSCAN_CHANCE*ent->myskills.abilities[DEFLECT].current_level; if (slot->ent->random > DEFLECT_MAX_PROJECTILE_CHANCE) slot->ent->random = DEFLECT_MAX_PROJECTILE_CHANCE; } //Notify the target if (target == ent) { gi.cprintf(target, PRINT_HIGH, "You have been blessed with deflect for %0.1f seconds!\n", duration); } else if ((target->client) && !(target->svflags & SVF_MONSTER)) { gi.cprintf(target, PRINT_HIGH, "You have been blessed with deflect for %0.1f seconds!\n\n", duration); gi.cprintf(ent, PRINT_HIGH, "Blessed %s with deflect for %0.1f seconds.\n", target->myskills.player_name, duration); } else { gi.cprintf(ent, PRINT_HIGH, "Blessed %s with deflect for %0.1f seconds.\n", V_GetMonsterName(target), duration); } //Play the spell sound! gi.sound(target, CHAN_ITEM, gi.soundindex("curses/prayer.wav"), 1, ATTN_NORM, 0); } }