void boss_locktarget (edict_t *self, int flash_number, vec3_t forward, vec3_t start) { int i; vec3_t v; if (self->owner->client->weapon_mode) // secondary attack { VectorCopy(self->enemy->s.origin, v); v[2]-=100; // aim at floor VectorSubtract(v, self->s.origin, forward); } else { MonsterAim(self, -1, TANK_ROCKET_SPEED, true, flash_number, forward, start); } VectorNormalize(forward); vectoangles(forward, forward); ValidateAngles(forward); // set view angles to target for (i = 0 ; i < 3 ; i++) self->owner->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(forward[i]-self->owner->client->resp.cmd_angles[i]); VectorCopy(forward, self->owner->client->ps.viewangles); VectorCopy(forward, self->owner->client->v_angle); }
void BombArea (edict_t *ent, float skill_mult, float cost_mult) { vec3_t angles, offset; vec3_t forward, right, start, end; trace_t tr; edict_t *bomb; int cost=COST_FOR_BOMB*cost_mult; #ifdef OLD_NOLAG_STYLE // 3.5 don't allow bomb area to prevent lag if (nolag->value) { safe_cprintf(ent, PRINT_HIGH, "Bomb area is temporarily disabled to prevent lag.\n"); return; } #endif 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, 8192, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SOLID); // make sure this is a floor vectoangles(tr.plane.normal, angles); ValidateAngles(angles); if (angles[PITCH] == FLOOR_PITCH) { VectorCopy(tr.endpos, start); VectorCopy(tr.endpos, end); end[2] += BOMBAREA_FLOOR_HEIGHT; tr = gi.trace(start, NULL, NULL, end, ent, MASK_SOLID); } else if (angles[PITCH] != CEILING_PITCH) { safe_cprintf(ent, PRINT_HIGH, "You must look at a ceiling or floor to cast this spell.\n"); return; } bomb = G_Spawn(); bomb->solid = SOLID_NOT; bomb->svflags |= SVF_NOCLIENT; VectorClear(bomb->velocity); VectorClear(bomb->mins); VectorClear(bomb->maxs); bomb->owner = ent; bomb->delay = level.time + BOMBAREA_DURATION + BOMBAREA_STARTUP_DELAY; bomb->nextthink = level.time + BOMBAREA_STARTUP_DELAY; bomb->dmg = 50 + 10*ent->myskills.abilities[BOMB_SPELL].current_level*skill_mult; bomb->think = bombarea_think; VectorCopy(tr.endpos, bomb->s.origin); VectorCopy(tr.endpos, bomb->s.old_origin); VectorCopy(angles, bomb->s.angles); gi.linkentity(bomb); gi.sound(bomb, CHAN_WEAPON, gi.soundindex("abilities/meteorlaunch_short.wav"), 1, ATTN_NORM, 0); ent->client->pers.inventory[power_cube_index] -= cost; ent->client->ability_delay = level.time + (DELAY_BOMB * cost_mult); }
void BuildSupplyStation (edict_t *ent, int cost, float skill_mult, float delay_mult) { vec3_t angles, forward, end; edict_t *station; trace_t tr; station = G_Spawn(); station->creator = ent; station->think = supplystation_think; station->nextthink = level.time + STATION_BUILD_TIME * delay_mult; station->s.modelindex = gi.modelindex ("models/objects/dmspot/tris.md2"); station->s.effects |= EF_PLASMA; station->s.renderfx |= RF_IR_VISIBLE; station->solid = SOLID_BBOX; station->movetype = MOVETYPE_TOSS; station->clipmask = MASK_MONSTERSOLID; station->mass = 500; station->mtype = SUPPLY_STATION; station->classname = "supplystation"; station->takedamage = DAMAGE_YES; station->health = 1000; station->monsterinfo.level = ent->myskills.abilities[SUPPLY_STATION].current_level * skill_mult; station->touch = V_Touch; station->die = supplystation_die; VectorSet(station->mins, -32, -32, -24); VectorSet(station->maxs, 32, 32, -16); station->s.skinnum = 1; // starting position for station AngleVectors (ent->client->v_angle, forward, NULL, NULL); VectorMA(ent->s.origin, 128, forward, end); tr = gi.trace(ent->s.origin, NULL, NULL, end, ent, MASK_SOLID); VectorCopy(tr.endpos, end); vectoangles(tr.plane.normal, angles); ValidateAngles(angles); // player is aiming at the ground if ((tr.fraction != 1.0) && (tr.endpos[2] < ent->s.origin[2]) && (angles[PITCH] == 270)) end[2] += abs(station->mins[2])+1; // make sure station doesn't spawn in a solid tr = gi.trace(end, station->mins, station->maxs, end, NULL, MASK_SHOT); if (tr.contents & MASK_SHOT) { safe_cprintf (ent, PRINT_HIGH, "Can't build supply station there.\n"); G_FreeEdict(station); return; } VectorCopy(tr.endpos, station->s.origin); gi.linkentity(station); ent->supplystation = station; ent->client->ability_delay = level.time + STATION_DELAY * delay_mult; ent->client->pers.inventory[power_cube_index] -= cost; ent->holdtime = level.time + STATION_BUILD_TIME * delay_mult; gi.sound(station, CHAN_ITEM, gi.soundindex("weapons/repair.wav"), 1, ATTN_NORM, 0); }
void minisentry_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { V_Touch(self, other, plane, surf); //4.2 if this is a player-monster (morph), then we should be looking at the client/player if (PM_MonsterHasPilot(other)) other = other->activator; if (other && other->inuse && (other == self->creator) && (level.time > self->random)) { safe_cprintf(self->creator, PRINT_HIGH, "Rotating sentry gun 45 degrees.\n"); VectorCopy(self->move_angles, self->s.angles); // reset angles to default self->s.angles[YAW]+=45; ValidateAngles(self->s.angles); VectorCopy(self->s.angles, self->move_angles); // update default angles self->random = level.time + 1; self->nextthink = level.time + 2; } }
void minisentry_lockon (edict_t *self) { float max, temp; vec3_t angles, v; // curse causes minisentry to fail to lock-on to enemy if ((que_typeexists(self->curses, CURSE)) && random() <= 0.8) return; temp = self->yaw_speed; self->yaw_speed *= 3; VectorSubtract(self->enemy->s.origin, self->s.origin, v); vectoangles(v, angles); self->ideal_yaw = vectoyaw(v); M_ChangeYaw(self); self->yaw_speed = temp; // restore original yaw speed self->s.angles[PITCH] = angles[PITCH]; ValidateAngles(self->s.angles); // maximum pitch is 65 degrees in either direction if (self->enemy->s.origin[2] > self->s.origin[2]) // if the enemy is above { if (self->owner && self->owner->style == SENTRY_FLIPPED) max = 340; // allow 20 degrees up else max = 315; // allow 45 degrees up if (self->s.angles[PITCH] < max) self->s.angles[PITCH] = max; } else { if (self->owner && self->owner->style == SENTRY_FLIPPED) max = 45; // allow 45 degrees down else max = 20; // allow 20 degrees down if (self->s.angles[PITCH] > max) self->s.angles[PITCH] = max; } }
void P_FollowWall (edict_t *ent) { int turns=0, num=90; vec3_t forward, right, start, end; vec3_t offset, angles; trace_t tr; 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, 8192, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SOLID); VectorCopy(tr.endpos, end); vectoangles(tr.plane.normal, angles); ValidateAngles(angles); VectorCopy(tr.endpos, start); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (ent->s.origin); gi.WritePosition (tr.endpos); gi.multicast (ent->s.origin, MULTICAST_PHS); while (turns < 10) { angles[YAW] += num; forward[0] = cos(DEG2RAD(angles[YAW])); forward[1] = sin(DEG2RAD(angles[YAW])); forward[2] = 0; VectorMA(start, 8192, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SOLID); if (tr.startsolid || tr.allsolid) { num = -90; gi.dprintf("fail\n"); continue; } gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (start, MULTICAST_PHS); VectorCopy(tr.endpos, start); vectoangles(tr.plane.normal, angles); ValidateAngles(angles); turns++; //gi.dprintf("turn %d %d degrees\n", turns, (int)angles[YAW]); } /* while (1) { angles[YAW] += num; forward[0] = cos(DEG2RAD(angles[YAW])); forward[1] = sin(DEG2RAD(angles[YAW])); forward[2] = 0; VectorMA(start, 48, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SOLID); if (tr.fraction < 1) { if (num == -180) break; num = -180; continue; } gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (start, MULTICAST_PHS); break; } */ }
/* =============== M_walkmove =============== */ qboolean M_walkmove (edict_t *ent, float yaw, float dist) { float original_yaw=yaw;//GHz vec3_t move; if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) return false; yaw = yaw*M_PI*2 / 360; move[0] = cos(yaw)*dist; move[1] = sin(yaw)*dist; move[2] = 0; if (IsABoss(ent) || ent->mtype == P_TANK) { //return M_Move(ent, move, true); if (!M_Move(ent, move, true)) { float angle1, angle2, delta1, delta2, cl_yaw, ideal_yaw, mult; vec3_t start, end, angles, right; trace_t tr; // get monster angles AngleVectors(ent->s.angles, NULL, right, NULL); //vectoangles(forward, forward); vectoangles(right, right); // get client yaw (FIXME: use mons yaw instead?) cl_yaw = ent->s.angles[YAW]; AngleCheck(&cl_yaw); // trace from monster to wall VectorCopy(ent->s.origin, start); VectorMA(start, 64, move, end); tr = gi.trace(start, ent->mins, ent->maxs, end, ent, MASK_SHOT); // get monster angles in relation to wall VectorCopy(tr.plane.normal, angles); vectoangles(angles, angles); // monster is moving sideways, so use sideways vector instead if ((int)original_yaw==(int)right[YAW]) { cl_yaw = right[YAW]; AngleCheck(&cl_yaw); } // delta between monster yaw and wall yaw should be no more than 90 degrees // else, turn wall angles around 180 degrees if (fabs(cl_yaw-angles[YAW]) > 90) angles[YAW]+=180; ValidateAngles(angles); // possible escape angle 1 angle1 = angles[YAW]+90; AngleCheck(&angle1); delta1 = fabs(angle1-cl_yaw); // possible escape angle 2 angle2 = angles[YAW]-90; AngleCheck(&angle2); delta2 = fabs(angle2-cl_yaw); // take the shorter route if (delta1 > delta2) { ideal_yaw = angle2; mult = 1.0-delta2/90.0; } else { ideal_yaw = angle1; mult = 1.0-delta1/90.0; } // go full speed if we are turned at least half way towards ideal yaw if (mult >= 0.5) mult = 1.0; // modify speed dist*=mult; // recalculate with new heading yaw = ideal_yaw*M_PI*2 / 360; move[0] = cos(yaw)*dist; move[1] = sin(yaw)*dist; move[2] = 0; //gi.dprintf("can't walk wall@%.1f you@%.1f ideal@%.1f\n", angles[YAW], cl_yaw, ideal_yaw); return M_Move(ent, move, true); } return true; } else if (level.time > ent->holdtime) // stay in-place for medic healing return SV_movestep(ent, move, true); else return false; }