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); } }
qboolean magmine_findtarget(edict_t *self) { edict_t *other = NULL; while ((other = findclosestradius(other, self->s.origin, self->dmg_radius)) != NULL) { if (!G_ValidTarget(self, other, true)) continue; //if (!BrainValidTarget(self, other)) // continue; self->enemy = other; return true; } return false; }
// search for nearby enemies, return true if one is found // this is to make the medic stop healing if there is a higher priority target // this function is the same as drone_findtarget(), except that it skips the medic check qboolean mymedic_findenemy (edict_t *self) { edict_t *target=NULL; while ((target = findclosestradius (target, self->s.origin, 1024)) != NULL) { if (!G_ValidTarget(self, target, true)) continue; self->enemy = target; drone_wakeallies(self); return true; } return false; }
qboolean myparasite_findtarget (edict_t *self) { edict_t *other=NULL; int para_range = PARASITE_ATTACK_RANGE; while ((other = findclosestradius(other, self->s.origin, para_range)) != NULL) { if (!parasite_cantarget(self, other)) continue; //if (!G_ValidTarget(self, other, true)) // return false; //if (!infov(self, other, 90)) // return false; self->enemy = other; return true; } return false; }
void WaterTotem_think(edict_t *self, edict_t *caster) { edict_t *target = NULL; //Find players in radius and attack them. while ((target = findclosestradius(target, self->s.origin, TOTEM_MAX_RANGE)) != NULL) { // (apple) // Since ice talent and watertotem work concurrently now, // checking for chill_duration will throttle ice talent's refire. if (G_ValidTarget(self, target, true)) { vec3_t normal; int talentLevel; float duration = WATERTOTEM_DURATION_BASE + self->monsterinfo.level * WATERTOTEM_DURATION_MULT; //Get a directional vector from the totem to the target. VectorSubtract(self->s.origin, target->s.origin, normal); //Talent: Ice. Damages players. talentLevel = getTalentLevel(caster, TALENT_ICE); if(talentLevel > 0) { int damage = GetRandom(10, 20) * talentLevel; vec3_t normal; //Damage the target VectorSubtract(target->s.origin, self->s.origin, normal); T_Damage(target, self, self, vec3_origin, self->s.origin, normal, damage, 0, DAMAGE_NO_KNOCKBACK, MOD_WATERTOTEM); } //Chill the target. target->chill_level = self->monsterinfo.level; target->chill_time = level.time + duration; //gi.dprintf("chilled %s for %.1f seconds at level %d\n", target->classname, duration, self->monsterinfo.level); } } //Next think. self->delay = level.time + WATERTOTEM_REFIRE_BASE + WATERTOTEM_REFIRE_MULT * self->monsterinfo.level; }
qboolean station_findtarget (edict_t *self) { edict_t *e=NULL; while ((e = findclosestradius(e, self->s.origin, STATION_TARGET_RADIUS)) != NULL) { if (!ValidStationTarget(self, e)) continue; if (!OnSameTeam(self, e)) { gi.centerprintf(self->creator, "%s is using\nyour supply station!\n", e->client->pers.netname); continue; } self->enemy = e; return true; } self->enemy = NULL; return false; }
qboolean boss_findtarget (edict_t *boss) { edict_t *target = NULL; while ((target = findclosestradius(target, boss->s.origin, BOSS_TARGET_RADIUS)) != NULL) { if (!G_ValidTarget(boss, target, true)) continue; if (!infront(boss, target)) continue; boss->enemy = target; //if (target->client) // gi.dprintf("found %s\n", target->client->pers.netname); //else // gi.dprintf("found target %s\n", target->classname); // gi.sound (boss, CHAN_WEAPON, gi.soundindex ("tank/sight1.wav"), 1, ATTN_NORM, 0); return true; } return false; }
qboolean minisentry_findtarget (edict_t *self) { edict_t *target=NULL; // don't retarget too quickly if (self->last_move_time > level.time) return false; while ((target = findclosestradius (target, self->s.origin, SENTRY_TARGET_RANGE)) != NULL) { if (!G_ValidTarget(self, target, true)) continue; if (!infov(self, target, SENTRY_FOV)) continue; self->enemy = target; self->last_move_time = level.time + 1.0; gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/turrspot.wav"), 1, ATTN_NORM, 0); return true; } return false; }
void Cmd_CorpseExplode(edict_t *ent) { int damage, min_dmg, max_dmg, slvl; float fraction, radius; vec3_t start, end, forward, right, offset; trace_t tr; edict_t *e=NULL; if (debuginfo->value) gi.dprintf("DEBUG: %s just called Cmd_CorpseExplode()\n", ent->client->pers.netname); if(ent->myskills.abilities[CORPSE_EXPLODE].disable) return; if (!G_CanUseAbilities(ent, ent->myskills.abilities[CORPSE_EXPLODE].current_level, COST_FOR_CORPSEEXPLODE)) return; slvl = ent->myskills.abilities[CORPSE_EXPLODE].current_level; radius = CORPSE_EXPLOSION_INITIAL_RADIUS + CORPSE_EXPLOSION_ADDON_RADIUS * slvl; // calculate starting position AngleVectors (ent->client->v_angle, forward, right, NULL); VectorSet(offset, 0, 7, ent->viewheight-8); P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); VectorMA(start, CORPSE_EXPLOSION_MAX_RANGE, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SOLID); while ((e = findclosestradius (e, tr.endpos, CORPSE_EXPLOSION_SEARCH_RADIUS)) != NULL) { if (!G_EntExists(e)) continue; if (e->health > 0) continue; if (e->max_health < 1) continue; // kill the corpse T_Damage(e, e, ent, vec3_origin, e->s.origin, vec3_origin, 10000, 0, DAMAGE_NO_PROTECTION, MOD_CORPSEEXPLODE); // inflict damage fraction = 0.1 * GetRandom(5, 10); damage = fraction * e->max_health; // calculate min/max damage range min_dmg = CORPSE_EXPLOSION_INITIAL_DAMAGE + CORPSE_EXPLOSION_ADDON_DAMAGE * slvl; max_dmg = 5 * min_dmg; if (damage < min_dmg) damage = min_dmg; else if (damage > max_dmg) damage = max_dmg; T_RadiusDamage (e, ent, damage, NULL, radius, MOD_CORPSEEXPLODE); //gi.dprintf("fraction %.1f, damage %d, max_health: %d\n", fraction, damage, e->max_health); //Spells like corpse explode shouldn't display 10000 damage, so show the corpse damage instead ent->client->ps.stats[STAT_ID_DAMAGE] = damage; gi.sound(e, CHAN_ITEM, gi.soundindex("spells/corpseexplodecast.wav"), 1, ATTN_NORM, 0); ent->client->pers.inventory[power_cube_index] -= COST_FOR_CORPSEEXPLODE; ent->client->ability_delay = level.time + DELAY_CORPSEEXPLODE; safe_cprintf(ent, PRINT_HIGH, "Corpse exploded for %d damage!\n", damage); //decino: explosion effect gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_GRENADE_EXPLOSION); gi.WritePosition (e->s.origin); gi.multicast (e->s.origin, MULTICAST_PVS); //decino: shoot 6 gibs that deal damage //az: todo, more copypaste. /*for (i = 0; i < 10; i++) { e->s.angles[YAW] += 36; AngleCheck(&e->s.angles[YAW]); AngleVectors(e->s.angles, forward, NULL, up); fire_gib(ent, e->s.origin, forward, dmg, 0, 1000); }*/ // calling entity made a sound, used to alert monsters ent->lastsound = level.framenum; break; } }
void FireTotem_think(edict_t *self, edict_t *caster) { int talentLevel; float chance; edict_t *target = NULL; //Totem should not work underwater (gee I wonder why). if(!self->waterlevel) { //Talent: Volcanic talentLevel = getTalentLevel(caster, TALENT_VOLCANIC); chance = 0.02 * talentLevel; //Find players in radius and attack them. while ((target = findclosestradius(target, self->s.origin, TOTEM_MAX_RANGE)) != NULL) { if (G_ValidTarget(self, target, true) && (self->s.origin[2]+64>target->s.origin[2])) { vec3_t forward, end; int damage = FIRETOTEM_DAMAGE_BASE + self->monsterinfo.level * FIRETOTEM_DAMAGE_MULT; int count = 10 + self->monsterinfo.level; int speed = 600; float val, dist; qboolean fireball=false; // copy target location G_EntMidPoint(target, end); // calculate distance to target dist = distance(end, self->s.origin); // move our target point based on projectile and enemy velocity VectorMA(end, (float)dist/speed, target->velocity, end); //Talent: Volcanic - chance to shoot a fireball if (talentLevel > 0 && chance > random()) fireball = true; // aim up if (fireball) val = ((dist/2048)*(dist/2048)*2048) + (end[2]-self->s.origin[2]);//4.4 else val = ((dist/512)*(dist/512)*512) + (end[2]-self->s.origin[2]); if (val < 0) val = 0; end[2] += val; // calculate direction vector to target VectorSubtract(end, self->s.origin, forward); VectorNormalize(forward); // don't fire in a perfectly straight line forward[1] += 0.05*crandom(); // spawn flames if (fireball) fire_fireball(self, self->s.origin, forward, 200, 125, 600, 5, 20);//4.4 else ThrowFlame(self, self->s.origin, forward, distance(self->s.origin, target->s.origin), speed, damage, GetRandom(2, 4)); self->lastsound = level.framenum; // refire delay self->delay = level.time + FRAMETIME; } } } }