void deflect_think (edict_t *self) { edict_t *player = G_GetClient(self->enemy); //Find my slot que_t *slot = NULL; slot = que_findtype(self->enemy->curses, NULL, DEFLECT); // Blessing self-terminates if the enemy dies or the duration expires if (!slot || !que_valident(slot)) { if (player && level.time >= self->monsterinfo.selected_time) gi.cprintf(player, PRINT_HIGH, "Deflect has expired\n"); que_removeent(self->enemy->curses, self, true); return; } // warn player that deflect is about to expire // if (player && !(level.framenum % 10) && (level.time >= slot->time - 5)) // gi.cprintf(player, PRINT_HIGH, "Deflect will expire in %.0f seconds\n", slot->time - level.time); //Stick with the target VectorCopy(self->enemy->s.origin, self->s.origin); gi.linkentity(self); DeflectProjectiles(self->enemy, self->random, false); //Next think self->nextthink = level.time + FRAMETIME; }
void Bless_think(edict_t *self) { //Find my slot que_t *slot = NULL; slot = que_findtype(self->enemy->curses, NULL, BLESS); // Blessing self-terminates if the enemy dies or the duration expires if (!slot || !que_valident(slot)) { self->enemy->superspeed = false; que_removeent(self->enemy->curses, self, true); return; } //Stick with the target VectorCopy(self->enemy->s.origin, self->s.origin); gi.linkentity(self); //give them super speed self->enemy->superspeed = true; //Next think self->nextthink = level.time + FRAMETIME; }
void curse_think(edict_t *self) { //Find my curse slot que_t *slot = NULL; slot = que_findtype(self->enemy->curses, NULL, self->atype); // curse self-terminates if the enemy dies or the duration expires if (!slot || !que_valident(slot)) { que_removeent(self->enemy->curses, self, true); return; } CurseEffects(self->enemy, 10, 242); //Stick with the target VectorCopy(self->enemy->s.origin, self->s.origin); gi.linkentity(self); //Next think time self->nextthink = level.time + FRAMETIME; LifeDrain(self);// 3.5 this must be called last, because it may free the curse ent Bleed(self);//4.2 }
void plague_think (edict_t *self) { int dmg; float radius; edict_t *e=NULL; // plague self-terminates if: if (!G_EntIsAlive(self->owner) || !G_EntIsAlive(self->enemy) //someone dies || (self->owner->flags & FL_WORMHOLE) // owner enters a wormhole || (self->owner->client->tball_delay > level.time) //owner tballs away || (self->owner->flags & FL_CHATPROTECT) //3.0 owner is in chatprotect || ((self->owner->myskills.class_num == CLASS_POLTERGEIST) && (!self->owner->mtype) && !PM_PlayerHasMonster(self->owner)) //3.0 poltergeist is in human form || que_findtype(self->enemy->curses, NULL, HEALING) != NULL) //3.0 player is blessed with healing { que_removeent(self->enemy->curses, self, true); return; } VectorCopy(self->enemy->s.origin, self->s.origin); // follow enemy radius = PLAGUE_DEFAULT_RADIUS+PLAGUE_ADDON_RADIUS*self->owner->myskills.abilities[PLAGUE].current_level; if (radius > PLAGUE_MAX_RADIUS) radius = PLAGUE_MAX_RADIUS; // find someone nearby to infect while ((e = findradius(e, self->s.origin, radius)) != NULL) { if (e == self->enemy) continue; if (!G_ValidTarget(self, e, true)) continue; // don't allow more than one curse of the same type if (que_typeexists(e->curses, CURSE_PLAGUE)) continue; // holy water grants temporary immunity to curses if (e->holywaterProtection > level.time) continue; // spawn another plague cloud on this entity PlagueCloud(self->owner, e); } if (level.time > self->wait) { dmg = (float)self->owner->myskills.abilities[PLAGUE].current_level/10 * ((float)self->enemy->max_health/20); if (!self->enemy->client && strcmp(self->enemy->classname, "player_tank") != 0) dmg *= 2; // non-clients take double damage (helps with pvm) if (dmg < 1) dmg = 1; if (dmg > 100) dmg = 100; T_Damage(self->enemy, self->enemy, self->owner, vec3_origin, self->enemy->s.origin, vec3_origin, dmg, 0, DAMAGE_NO_ABILITIES, MOD_PLAGUE); // hurt 'em self->wait = level.time + PLAGUE_DELAY; } self->nextthink = level.time + FRAMETIME; }
void bombperson_think (edict_t *self) { int height, max_height; float bombtime, thinktime; vec3_t start; trace_t tr; // calculate drop rate bombtime = self->delay - 8; // max rate achieved 2 seconds after casting if (bombtime < level.time) bombtime = level.time; thinktime = level.time + 0.25 * ((bombtime + 1) - level.time); // max 1 bomb per 0.25 seconds // bomb self-terminates if the enemy dies or owner teleports away if (!G_EntIsAlive(self->owner) || !G_EntIsAlive(self->enemy) || (level.time > self->delay) || (self->owner->client->tball_delay > level.time)) { //RemoveCurse(self->enemy, self); que_removeent(self->enemy->curses, self, true); return; } VectorCopy(self->enemy->s.origin, self->s.origin); // gi.linkentity(self); /* // if the caster can't see his target, then pause the spell if (!visible(self->orb, self->owner)) { self->nextthink = thinktime; return; } */ // get random drop height max_height = 250 - (20 * self->owner->myskills.abilities[BOMB_SPELL].current_level); if (max_height < 150) max_height = 150; height = GetRandom(50, max_height) + self->enemy->maxs[2]; // drop bombs above target VectorCopy(self->s.origin, start); start[2] += height; tr = gi.trace(self->s.origin, self->mins, self->maxs, start, self->owner, MASK_SHOT); VectorCopy(tr.endpos, start); start[2]--; // spread randomly around target start[0] += (BOMBPERSON_WIDTH/2)*crandom(); start[1] += (BOMBPERSON_WIDTH/2)*crandom(); spawn_grenades(self->owner, start, (0.5+2*random()), self->dmg, 1); self->nextthink = thinktime; }
void salvation_think (edict_t *self) { int radius; edict_t *other=NULL; que_t *slot=NULL; // check status of owner if (!CheckAuraOwner(self, COST_FOR_SALVATION)) { que_removeent(self->owner->auras, self, true); return; } // use cubes if (!(level.framenum % DEFAULT_AURA_FRAMES)) { int cube_cost = DEFAULT_AURA_COST; self->owner->client->pers.inventory[power_cube_index] -= cube_cost; } que_addent(self->owner->auras, self, DEFAULT_AURA_DURATION); // move aura with owner VectorCopy(self->owner->s.origin,self->s.origin); self->nextthink = level.time + FRAMETIME; if (level.framenum % DEFAULT_AURA_SCAN_FRAMES) return; radius = 256; // scan for targets while ((other = findradius (other, self->s.origin, radius)) != NULL) { slot = NULL; if (other == self->owner) continue; if (!G_EntExists(other)) continue; if (other->health < 1) continue; if (OnSameTeam(self->owner, other) < 2) continue; if (!visible(self->owner, other)) continue; slot = que_findtype(other->auras, slot, AURA_SALVATION); if (slot && (slot->ent->owner != self->owner)) continue; que_addent(other->auras, self, DEFAULT_AURA_DURATION); } }
void LifeDrain (edict_t *curse) { int take; edict_t *caster=curse->owner; if (curse->atype != LIFE_DRAIN) return; if (level.time < curse->wait) return; if (!G_ValidTarget(caster, curse->enemy, false)) { // remove the curse if the target dies que_removeent(curse->enemy->curses, curse, true); return; } take = LIFE_DRAIN_HEALTH; // more effective on non-clients (because they have more health) if (!curse->enemy->client) take *= 2; // give caster health if (caster->health < caster->max_health) { caster->health += take; if (caster->health > caster->max_health) caster->health = caster->max_health; } // take it away from curse's target T_Damage(curse->enemy, caster, caster, vec3_origin, vec3_origin, vec3_origin, take, 0, DAMAGE_NO_ABILITIES, MOD_LIFE_DRAIN); curse->wait = level.time + LIFE_DRAIN_UPDATETIME; }
void Bleed (edict_t *curse) { int take; edict_t *caster=curse->owner; if (curse->atype != BLEEDING) return; if (level.time < curse->wait) return; if (!G_ValidTarget(caster, curse->enemy, false)) { // remove the curse if the target dies que_removeent(curse->enemy->curses, curse, true); return; } // 33-99% health taken over duration of curse take = (curse->enemy->max_health * (0.033 * curse->monsterinfo.level)) / curse->monsterinfo.selected_time; //gi.dprintf("target %s take %d health %d/%d level %d time %.1f\n", // curse->enemy->classname, take, curse->enemy->health, curse->enemy->max_health, // curse->monsterinfo.level, curse->monsterinfo.selected_time); // damage limits if (take < 1) take = 1; if (take > 100) take = 100; T_Damage(curse->enemy, caster, caster, vec3_origin, vec3_origin, vec3_origin, take, 0, DAMAGE_NO_ABILITIES, MOD_LIFE_DRAIN); curse->wait = level.time + (GetRandom(3, 10) * FRAMETIME); }
void holyfreeze_think (edict_t *self) { int radius; edict_t *target=NULL, *curse=NULL; que_t *slot; // check status of owner if (!CheckAuraOwner(self, DEFAULT_AURA_COST)) { //gi.dprintf("aura removed itself\n"); que_removeent(self->owner->auras, self, true); return; } // owner has an active aura que_addent(self->owner->auras, self, DEFAULT_AURA_DURATION); // use cubes if (!(level.framenum % DEFAULT_AURA_FRAMES)) { int cube_cost = DEFAULT_AURA_COST; self->owner->client->pers.inventory[power_cube_index] -= cube_cost; } // move aura with owner VectorCopy(self->owner->s.origin,self->s.origin); self->nextthink = level.time + FRAMETIME; if (level.framenum % DEFAULT_AURA_SCAN_FRAMES) return; // scan for targets radius = DEFAULT_AURA_MIN_RADIUS+self->owner->myskills.abilities[HOLY_FREEZE].current_level*DEFAULT_AURA_ADDON_RADIUS; if (radius > DEFAULT_AURA_MAX_RADIUS) radius = DEFAULT_AURA_MAX_RADIUS; while ((target = findradius (target, self->s.origin, radius)) != NULL) { slot = NULL; if (target == self->owner) continue; if (!G_ValidTarget(self->owner, target, true)) continue; // FIXME: make this into a loop search if we plan to allow // more than one curse of the same type slot = que_findtype(target->curses, slot, AURA_HOLYFREEZE); if (slot && (slot->ent->owner != self->owner)) { // gi.dprintf("already slowed by someone else\n"); continue; // already slowed by someone else } if (!slot) // aura doesn't exist in que or timed out { if (random() > 0.5) gi.sound(target, CHAN_ITEM, gi.soundindex("spells/blue1.wav"), 1, ATTN_NORM, 0); else gi.sound(target, CHAN_ITEM, gi.soundindex("spells/blue3.wav"), 1, ATTN_NORM, 0); } que_addent(target->curses, self, DEFAULT_AURA_DURATION); } }
void fire_think (edict_t *self) { edict_t *ed=NULL; qboolean quench = false; int i; int damage; // fire self-terminates if if (!G_EntIsAlive(self->enemy) || !G_EntIsAlive(self->owner)//owner dies || (level.time > self->delay)) // enemy dies //duration expires //|| que_findtype(self->enemy->curses, NULL, HEALING) != NULL) //3.0 when player is blessed with healing { que_removeent(self->enemy->curses, self, true); return; } //3.0 quench the flames if the player is in possesion of a flame stopping item if (!(self->enemy->waterlevel || self->waterlevel)) { for (i = 3; i < MAX_VRXITEMS; ++i) { if (self->enemy->myskills.items[i].itemtype & ITEM_FIRE_RESIST) { quench = true; break; } } } if (self->enemy->waterlevel || self->waterlevel || quench) { //if item and not water stopped the fire if (quench) { //Consume an item charge if (!(self->enemy->myskills.items[i].itemtype & ITEM_UNIQUE)) self->enemy->myskills.items[i].quantity -= 1; if(self->enemy->myskills.items[i].quantity == 0) { int count = 0; gi.cprintf(self->enemy, PRINT_HIGH, "Your burn resistant clothing has been destroyed!\n"); //erase the item V_ItemClear(&self->enemy->myskills.items[i]); //Tell the user if they have any left for (i = 3; i < MAX_VRXITEMS; ++i) if (self->enemy->myskills.items[i].itemtype & ITEM_FIRE_RESIST) count++; if (count) gi.cprintf(self->enemy, PRINT_HIGH, "You have %d left.\n", count); } } //water did it, so play a hissing dound else gi.sound (self->enemy, CHAN_WEAPON, gi.soundindex ("world/airhiss1.wav"), 1, ATTN_NORM, 0); que_removeent(self->enemy->curses, self, true); return; } damage = self->dmg; VectorCopy(self->enemy->s.origin,self->s.origin); if (self->PlasmaDelay < level.time) { T_Damage (self->enemy, self, self->owner, vec3_origin, self->enemy->s.origin, vec3_origin, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_BURN); self->PlasmaDelay = level.time + 1; } self->nextthink = level.time + FRAMETIME; }
void Healing_think(edict_t *self) { //Find my slot que_t *slot = NULL; int heal_amount = HEALING_HEAL_BASE + HEALING_HEAL_BONUS * self->owner->myskills.abilities[HEALING].current_level; float cooldown = 1.0; slot = que_findtype(self->enemy->curses, NULL, HEALING); // Blessing self-terminates if the enemy dies or the duration expires if (!slot || !que_valident(slot)) { que_removeent(self->enemy->curses, self, true); return; } //Stick with the target VectorCopy(self->enemy->s.origin, self->s.origin); gi.linkentity(self); //Next think time self->nextthink = level.time + cooldown; //Heal the target's armor if (!self->enemy->client) { //Check to make sure it's a monster if (!self->enemy->mtype) return; heal_amount = self->enemy->max_health * (0.01 * self->owner->myskills.abilities[HEALING].current_level); // 1% healed per level if (heal_amount > 100) heal_amount = 100; //Heal the momster's health self->enemy->health += heal_amount; if (self->enemy->health > self->enemy->max_health) self->enemy->health = self->enemy->max_health; if (self->enemy->monsterinfo.power_armor_type) { heal_amount = self->enemy->monsterinfo.power_armor_power * (0.01 * self->owner->myskills.abilities[HEALING].current_level); // 1% healed per level if (heal_amount > 100) heal_amount = 100; //Heal the monster's armor self->enemy->monsterinfo.power_armor_power += heal_amount; if (self->enemy->monsterinfo.power_armor_power > self->enemy->monsterinfo.max_armor) self->enemy->monsterinfo.power_armor_power = self->enemy->monsterinfo.max_armor; } } else { if (self->enemy->health < MAX_HEALTH(self->enemy)) { //Heal health self->enemy->health += heal_amount; if (self->enemy->health > MAX_HEALTH(self->enemy)) self->enemy->health = MAX_HEALTH(self->enemy); } if (self->enemy->client->pers.inventory[body_armor_index] < MAX_ARMOR(self->enemy)) { //Heal armor heal_amount *= 0.5; // don't heal as much armor if (heal_amount < 1) heal_amount = 1; self->enemy->client->pers.inventory[body_armor_index] += heal_amount; if (self->enemy->client->pers.inventory[body_armor_index] > MAX_ARMOR(self->enemy)) self->enemy->client->pers.inventory[body_armor_index] = MAX_ARMOR(self->enemy); } } }