void magmine_attack(edict_t *self) { int pull; vec3_t start, end, dir; // magmine will not pull a target that is below it // this prevents players from placing magmines to pull a target off their feet if (self->enemy->absmin[2] + 1 < self->absmin[2]) return; G_EntMidPoint(self->enemy, end); G_EntMidPoint(self, start); VectorSubtract(end, start, dir); VectorNormalize(dir); pull = MAGMINE_DEFAULT_PULL + MAGMINE_ADDON_PULL * self->monsterinfo.level; if (self->enemy->groundentity) pull *= 2; // pull them in! T_Damage(self->enemy, self, self, dir, end, vec3_origin, 0, pull, 0, 0); if (level.time > self->delay) { gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/tlaser.wav"), 1, ATTN_IDLE, 0); self->delay = level.time + 2; } }
void mybrain_suxor (edict_t *self) { int damage, range, pull; vec3_t start, v, end; trace_t tr; if (!self->enemy) return; if (!self->enemy->inuse) return; self->lastsound = level.framenum; G_EntMidPoint(self->enemy, start); VectorSubtract(start, self->s.origin, v); self->ideal_yaw = vectoyaw(v); M_ChangeYaw (self); range = VectorLength(v); VectorNormalize(v); VectorMA(self->s.origin, 512, v, end); tr = gi.trace(self->s.origin, NULL, NULL, end, self, MASK_SHOT); if (G_EntExists(tr.ent) && (tr.ent == self->enemy)) { damage = BRAIN_INITIAL_TENTACLE_DMG + BRAIN_ADDON_TENTACLE_DMG*self->monsterinfo.level; pull = BRAIN_INITIAL_PULL + BRAIN_ADDON_PULL*self->monsterinfo.level; if (tr.ent->groundentity) pull *= 2; if (range > 64) T_Damage(tr.ent, self, self, v, tr.endpos, tr.plane.normal, 0, pull, 0, MOD_UNKNOWN); else T_Damage(tr.ent, self, self, v, tr.endpos, tr.plane.normal, damage, pull, 0, MOD_UNKNOWN); } }
void mymedic_cable_attack (edict_t *self) { vec3_t forward, right, start, offset, end; trace_t tr; // need a valid target and activator if (!self || !self->inuse || !self->activator || !self->activator->inuse || !self->enemy || !self->enemy->inuse) return; // make sure target is still in range if (entdist(self, self->enemy) > 256) return; // get muzzle location AngleVectors(self->s.angles, forward, right, NULL); VectorCopy(mymedic_cable_offsets[self->s.frame - FRAME_attack42], offset); G_ProjectSource(self->s.origin, offset, forward, right, start); // get end position //VectorCopy(self->enemy->s.origin, end); //end[2] = self->enemy->absmax[2]-8; G_EntMidPoint(self->enemy, end); tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT); if (tr.ent != self->enemy) return; // cable is blocked // cable effect gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_MEDIC_CABLE_ATTACK); gi.WriteShort (self - g_edicts); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (self->s.origin, MULTICAST_PVS); // the target needs healing if (M_NeedRegen(self->enemy)) { int frames = 6000/(12*self->monsterinfo.level); if (!frames) frames = 1; // remove all curses CurseRemove(self->enemy, 0); //Give them a short period of curse immunity self->enemy->holywaterProtection = level.time + 2.0; //2 seconds immunity // heal them M_Regenerate(self->enemy, frames, 0, 1.0, true, true, false, &self->enemy->monsterinfo.regen_delay2); // hold monsters in-place if (self->enemy->svflags & SVF_MONSTER) self->enemy->holdtime = level.time + 0.2; } // the target is a dead monster and needs resurrection else if (self->enemy->health < 1) { M_Reanimate(self->activator, self->enemy, self->monsterinfo.level, 0.33, false); } }
void myparasite_fire (edict_t *self) { int pull; int damage; int para_range = PARASITE_ATTACK_RANGE; vec3_t v, start, end, forward; trace_t tr; // monitor attack duration if (self->shots >= PARASITE_ATTACK_FRAMES) { self->shots = 0; //self->oldenemy = self->enemy; self->enemy = NULL; self->wait = level.time + PARASITE_REFIRE; return; } damage = PARASITE_INITIAL_DMG+PARASITE_ADDON_DMG*self->myskills.abilities[BLOOD_SUCKER].current_level; // morph mastery increases damage if (self->myskills.abilities[MORPH_MASTERY].current_level > 0) damage *= 1.5; self->lastsound = level.framenum; if (self->shots == 0) gi.sound (self, CHAN_AUTO, gi.soundindex("parasite/paratck3.wav"), 1, ATTN_NORM, 0); // get muzzle position AngleVectors(self->s.angles, forward, NULL, NULL); VectorMA(self->s.origin, self->maxs[1]-8, forward, start); start[2] += 2; // get a valid target if we don't have one already if (!parasite_cantarget(self, self->enemy)) { if (!myparasite_findtarget(self)) { self->enemy = NULL; //gi.dprintf("couldn't find target\n"); } } if (self->enemy) { // lock-on to target //VectorCopy(self->enemy->s.origin, end); G_EntMidPoint(self->enemy, end); // is this a corpse? if (self->enemy->health < 1) end[2] -= 8; // aim towards the ground VectorSubtract(end, start, v); VectorNormalize(v); VectorMA(start, para_range, v, end); } else { AngleVectors(self->client->v_angle, forward, NULL, NULL); // fire straight ahead VectorMA(start, para_range, forward, end); } tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); // make sure we are actually hitting our enemy //if (tr.ent && (tr.ent==self->enemy)) if (G_EntExists(tr.ent) && !OnSameTeam(self, tr.ent)) { pull = PARASITE_KNOCKBACK; if (tr.ent->groundentity) pull *= 2; T_Damage(tr.ent, self, self, v, tr.endpos, tr.plane.normal, damage, pull, DAMAGE_NO_ABILITIES, MOD_PARASITE); if (self->health < self->max_health) { self->health += damage; if (self->health > self->max_health) self->health = self->max_health; } } // make the parasite toungue! gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_PARASITE_ATTACK); gi.WriteShort (self-g_edicts); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (start, MULTICAST_PVS); self->shots++; if (self->shots == PARASITE_ATTACK_FRAMES) gi.sound (self, CHAN_AUTO, gi.soundindex("parasite/paratck4.wav"), 1, ATTN_NORM, 0); }
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; } } } }