void weapon_supershotgun_fire (gentity_t *ent) { gentity_t *tent; // send shotgun blast tent = G_TempEntity( g_muzzle, EV_SHOTGUN ); VectorScale( forward, 4096, tent->s.origin2 ); SnapVector( tent->s.origin2 ); tent->s.eventParm = rand() & 255; // seed for spread pattern tent->s.otherEntityNum = ent->s.number; ShotgunPattern( tent->s.origin, tent->s.origin2, tent->s.eventParm, ent ); }
/* =============== CalcMuzzlePoint set muzzle location relative to pivoting eye =============== */ void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) { /* LQ3A */ UNREFERENCED_PARAMETER(up); UNREFERENCED_PARAMETER(right); VectorCopy( ent->s.pos.trBase, muzzlePoint ); muzzlePoint[2] += ent->client->ps.viewheight; VectorMA( muzzlePoint, 14, forward, muzzlePoint ); // snap to integer coordinates for more efficient network bandwidth usage SnapVector( muzzlePoint ); }
/* ================= launch_grenade ================= */ gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir ) { gentity_t *bolt; VectorNormalize( dir ); bolt = G_Spawn( ); bolt->classname = "grenade"; bolt->nextthink = level.time + 5000; bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_GRENADE; bolt->s.eFlags = EF_BOUNCE_HALF; bolt->s.generic1 = WPM_PRIMARY; //weaponMode bolt->r.ownerNum = self->s.number; bolt->parent = self; if ( self->client->pers.classSelection != PCL_ALIEN_LEVEL4 ) { bolt->damage = GRENADE_DAMAGE; bolt->splashDamage = GRENADE_DAMAGE; bolt->splashRadius = GRENADE_RANGE; } else { bolt->damage = 300; bolt->splashDamage = 500; bolt->splashRadius = 975; } bolt->methodOfDeath = MOD_GRENADE; bolt->splashMethodOfDeath = MOD_GRENADE; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -3.0f; bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 3.0f; bolt->s.time = level.time; bolt->s.pos.trType = TR_GRAVITY; if ( self->client->pers.classSelection == PCL_ALIEN_LEVEL4 ) { bolt->s.pos.trType = TR_LINEAR_STOP; bolt->s.weapon = WP_LOCKBLOB_LAUNCHER; } bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, GRENADE_SPEED, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin ); return bolt; }
void TieBomberThink( gentity_t *self ) { // NOTE: Lerp2Angles will think this thinkfunc if the model is a misc_model_breakable. Watchout // for that in a script (try to just use ROFF's?). // Stop thinking, you're dead. if ( self->health <= 0 ) { return; } // Needed every think... self->nextthink = level.time + FRAMETIME; gentity_t *player = &g_entities[0]; vec3_t playerDir; float playerDist; //use player eyepoint VectorSubtract( player->currentOrigin, self->currentOrigin, playerDir ); playerDist = VectorNormalize( playerDir ); // Time to attack? if ( player->health > 0 && playerDist < MIN_PLAYER_DIST && self->attackDebounceTime < level.time ) { // Doesn't matter what model gets loaded here, as long as it exists. // It's only used as a point on to which the falling effect for the bomb // can be attached to (kinda inefficient, I know). char name1[200] = "models/players/gonk/model.glm"; gentity_t *bomb = G_CreateObject( self, self->s.pos.trBase, self->s.apos.trBase, 0, 0, TR_GRAVITY, 0 ); bomb->s.modelindex = G_ModelIndex( name1 ); gi.G2API_InitGhoul2Model( bomb->ghoul2, name1, bomb->s.modelindex, NULL_HANDLE, NULL_HANDLE, 0, 0); bomb->s.radius = 50; bomb->s.eFlags |= EF_NODRAW; // Make the bombs go forward in the bombers direction a little. vec3_t fwd, rt; AngleVectors( self->currentAngles, fwd, rt, NULL ); rt[2] -= 0.5f; VectorMA( bomb->s.pos.trBase, -30.0, rt, bomb->s.pos.trBase ); VectorScale( fwd, 300, bomb->s.pos.trDelta ); SnapVector( bomb->s.pos.trDelta ); // save net bandwidth // Start the effect. G_PlayEffect( G_EffectIndex( "ships/tiebomber_bomb_falling" ), bomb->playerModel, gi.G2API_AddBolt( &bomb->ghoul2[0], "model_root" ), bomb->s.number, bomb->currentOrigin, 1000, qtrue ); // Set the tie bomb to have a touch function, so when it hits the ground (or whatever), there's a nice 'boom'. bomb->e_TouchFunc = touchF_TouchTieBomb; self->attackDebounceTime = level.time + 1000; } }
/* ================= fire_grapple ================= */ gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) { gentity_t *hook; //unlagged - grapple int hooktime; //unlagged - grapple VectorNormalize (dir); hook = G_Spawn(); hook->classname = "hook"; hook->nextthink = level.time + 10000; hook->think = Weapon_HookFree; hook->s.eType = ET_MISSILE; hook->r.svFlags = SVF_USE_CURRENT_ORIGIN; hook->s.weapon = WP_GRAPPLING_HOOK; hook->r.ownerNum = self->s.number; hook->methodOfDeath = MOD_GRAPPLE; hook->clipmask = MASK_SHOT; hook->parent = self; hook->target_ent = NULL; //unlagged - grapple // we might want this later hook->s.otherEntityNum = self->s.number; // setting the projectile base time back makes the hook's first // step larger if ( self->client ) { hooktime = self->client->pers.cmd.serverTime + 50; } else { hooktime = level.time - MISSILE_PRESTEP_TIME; } hook->s.pos.trTime = hooktime; //unlagged - grapple hook->s.pos.trType = TR_LINEAR; //unlagged - grapple //hook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame //unlagged - grapple hook->s.otherEntityNum = self->s.number; // use to match beam in client VectorCopy( start, hook->s.pos.trBase ); VectorScale( dir, 800, hook->s.pos.trDelta ); SnapVector( hook->s.pos.trDelta ); // save net bandwidth VectorCopy (start, hook->r.currentOrigin); self->client->hook = hook; return hook; }
//---------------------------------------------------------------- static void turret_fire ( gentity_t *ent, vec3_t start, vec3_t dir ) //---------------------------------------------------------------- { vec3_t org; gentity_t *bolt; if ( (trap_PointContents( start, ent->s.number )&MASK_SHOT) ) { return; } VectorMA( start, -START_DIS, dir, org ); // dumb.... G_PlayEffectID( ent->genericValue13, org, dir ); bolt = G_Spawn(); //use a custom shot effect bolt->s.otherEntityNum2 = ent->genericValue14; //use a custom impact effect bolt->s.emplacedOwner = ent->genericValue15; bolt->classname = "turret_proj"; bolt->nextthink = level.time + 10000; bolt->think = G_FreeEntity; bolt->s.eType = ET_MISSILE; bolt->s.weapon = WP_EMPLACED_GUN; bolt->r.ownerNum = ent->s.number; bolt->damage = ent->damage; bolt->alliedTeam = ent->alliedTeam; bolt->teamnodmg = ent->teamnodmg; //bolt->dflags = DAMAGE_NO_KNOCKBACK;// | DAMAGE_HEAVY_WEAP_CLASS; // Don't push them around, or else we are constantly re-aiming bolt->splashDamage = ent->damage; bolt->splashRadius = 100; bolt->methodOfDeath = MOD_TARGET_LASER; //[BugFix16] bolt->splashMethodOfDeath = MOD_TARGET_LASER; //[/BugFix16] bolt->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; //bolt->trigger_formation = qfalse; // don't draw tail on first frame VectorSet( bolt->r.maxs, 1.5, 1.5, 1.5 ); VectorScale( bolt->r.maxs, -1, bolt->r.mins ); bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time; VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, ent->mass, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin); bolt->parent = ent; }
void shotgunFire( gentity_t *ent ) { gentity_t *tent; // send shotgun blast tent = G_NewTempEntity( muzzle, EV_SHOTGUN ); VectorScale( forward, 4096, tent->s.origin2 ); SnapVector( tent->s.origin2 ); tent->s.eventParm = rand() / ( RAND_MAX / 0x100 + 1 ); // seed for spread pattern tent->s.otherEntityNum = ent->s.number; G_UnlaggedOn( ent, muzzle, SHOTGUN_RANGE ); ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent ); G_UnlaggedOff(); }
/* ================= fire_rocket ================= */ gentity_t *fire_rocket( gentity_t *self, vec3_t start, vec3_t dir ) { gentity_t *bolt; VectorNormalize( dir ); bolt = G_Spawn(); bolt->classname = const_cast<char*>("rocket"); bolt->nextthink = level.time + 20000; // push it out a little bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN | SVF_BROADCAST; //DHM - Nerve :: Use the correct weapon in multiplayer if ( g_gametype.integer == GT_SINGLE_PLAYER ) { bolt->s.weapon = WP_ROCKET_LAUNCHER; } else { bolt->s.weapon = self->s.weapon; } bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = G_GetWeaponDamage( WP_ROCKET_LAUNCHER ); // JPW NERVE bolt->splashDamage = G_GetWeaponDamage( WP_ROCKET_LAUNCHER ); // JPW NERVE // JPW NERVE if ( g_gametype.integer != GT_SINGLE_PLAYER ) { bolt->splashRadius = G_GetWeaponDamage( WP_ROCKET_LAUNCHER ); } else { bolt->splashRadius = 120; } // jpw bolt->methodOfDeath = MOD_ROCKET; bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH; // bolt->clipmask = MASK_SHOT; bolt->clipmask = MASK_MISSILESHOT; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); // JPW NERVE if ( g_gametype.integer != GT_SINGLE_PLAYER ) { VectorScale( dir,2500,bolt->s.pos.trDelta ); } else { VectorScale( dir, 900, bolt->s.pos.trDelta ); } // jpw SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin ); return bolt; }
void shotgunFire( gentity_t *ent ) { gentity_t *tent; // send shotgun blast tent = G_TempEntity( muzzle, EV_SHOTGUN ); VectorScale( forward, 4096, tent->s.origin2 ); SnapVector( tent->s.origin2 ); tent->s.eventParm = rand() & 255; // seed for spread pattern tent->s.otherEntityNum = ent->s.number; G_UnlaggedOn( muzzle, 8192 * 16 ); ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent ); G_UnlaggedOff(); }
static int _vec3_snap(lua_State *L) { luavec3_t a; _et_gentity_setluavec3(L, &a); lua_pop(L, 1); SnapVector(a); _et_gentity_getluavec3(L, a); G_LuaSetVec3Class(L); return 1; }
gentity_t * plant_mine(gentity_t *self, vec3_t start, vec3_t dir) { gentity_t *bolt; VectorNormalize(dir); bolt = G_Spawn(); bolt->classname = "mine"; bolt->nextthink = level.time + 2000; bolt->think = G_minethink; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_MINE; bolt->s.eFlags = EF_BOUNCE_HALF; bolt->s.generic1 = WPM_PRIMARY; //weaponMode bolt->r.ownerNum = self->s.number; bolt->parent = self; if(g_survival.integer) { bolt->damage = MINE_DAMAGE; bolt->splashDamage = MINE_DAMAGE; } else { bolt->damage = (1.25 * MINE_DAMAGE); bolt->splashDamage = (1.25 * MINE_DAMAGE); } bolt->splashRadius = MINE_RANGE; bolt->methodOfDeath = MOD_MINE; bolt->splashMethodOfDeath = MOD_MINE; bolt->clipmask = MASK_DEADSOLID; bolt->target_ent = NULL; bolt->r.mins[0] = bolt->r.mins[1] = -5.0f; bolt->r.mins[2] = 0.0f; bolt->r.maxs[0] = bolt->r.maxs[1] = 5.0f; bolt->r.maxs[2] = 2.0f; bolt->s.time = level.time; bolt->biteam = bolt->s.modelindex2 = BIT_HUMANS; bolt->use = G_itemUse; bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, GRENADE_SPEED/3, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin ); return bolt; }
gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up ) { gentity_t *bolt; vec3_t dir; vec3_t end; float r, u, scale; bolt = G_Spawn(); bolt->classname = const_cast<char*>("nail"); bolt->nextthink = level.time + 10000; bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; // bolt->s.weapon = WP_NAILGUN; bolt->s.weapon = WP_VENOM_FULL; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = G_GetWeaponDamage( WP_VENOM_FULL ); // bolt->methodOfDeath = MOD_NAIL; bolt->methodOfDeath = MOD_VENOM_FULL; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time; VectorCopy( start, bolt->s.pos.trBase ); r = random() * M_PI * 2.0f; u = c::sin( r ) * crandom() * NAILGUN_SPREAD * 16; r = c::cos( r ) * crandom() * NAILGUN_SPREAD * 16; VectorMA( start, 8192 * 16, forward, end ); VectorMA( end, r, right, end ); VectorMA( end, u, up, end ); VectorSubtract( end, start, dir ); VectorNormalize( dir ); // JPW NERVE if ( g_gametype.integer == GT_SINGLE_PLAYER ) { scale = 555 + random() * 1800; } else { scale = 1200 + random() * 2500; } // jpw VectorScale( dir, scale, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); VectorCopy( start, bolt->r.currentOrigin ); return bolt; }
static void FireShotgun( gentity_t *self ) { gentity_t *tent; // instead of an EV_WEAPON_HIT_* event, send this so client can generate the same spread pattern tent = G_NewTempEntity( muzzle, EV_SHOTGUN ); VectorScale( forward, 4096, tent->s.origin2 ); SnapVector( tent->s.origin2 ); tent->s.eventParm = rand() / ( RAND_MAX / 0x100 + 1 ); // seed for spread pattern tent->s.otherEntityNum = self->s.number; // caclulate the pattern and do the damage G_UnlaggedOn( self, muzzle, SHOTGUN_RANGE ); ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, self ); G_UnlaggedOff(); }
//---------------------------------------------------------------- static void turret_fire ( gentity_t *ent, vec3_t start, vec3_t dir ) //---------------------------------------------------------------- { vec3_t org; gentity_t *bolt; if ( (trap_PointContents( start, ent->s.number )&MASK_SHOT) ) { return; } VectorMA( start, -START_DIS, dir, org ); // dumb.... G_PlayEffectID( ent->genericValue13, org, dir ); bolt = G_Spawn(); //use a custom shot effect bolt->s.otherEntityNum2 = ent->genericValue14; //use a custom impact effect bolt->s.emplacedOwner = ent->genericValue15; bolt->classname = "turret_proj"; bolt->nextthink = level.time + 10000; bolt->think = G_FreeEntity; bolt->s.eType = ET_MISSILE; bolt->s.weapon = WP_EMPLACED_GUN; bolt->r.ownerNum = ent->s.number; bolt->damage = ent->damage; bolt->alliedTeam = ent->alliedTeam; bolt->teamnodmg = ent->teamnodmg; bolt->splashDamage = ent->damage; bolt->splashRadius = 100; bolt->methodOfDeath = MOD_TARGET_LASER; bolt->splashMethodOfDeath = MOD_TARGET_LASER; bolt->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; VectorSet( bolt->r.maxs, 1.5, 1.5, 1.5 ); VectorScale( bolt->r.maxs, -1, bolt->r.mins ); bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time; VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, ent->mass, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin); bolt->parent = ent; }
static gentity_t *FireLcannonHelper( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius, int speed ) { // TODO: Tidy up this and lcannonFire gentity_t *m; int nextthink; float charge; // explode in front of player when overcharged if ( damage == LCANNON_DAMAGE ) { nextthink = level.time; } else { nextthink = level.time + 10000; } if ( self->s.generic1 == WPM_PRIMARY ) { m = G_SpawnMissile( MIS_LCANNON, self, start, dir, NULL, G_ExplodeMissile, nextthink ); // some values are set in the code m->damage = damage; m->splashDamage = damage / 2; m->splashRadius = radius; VectorScale( dir, speed, m->s.pos.trDelta ); SnapVector( m->s.pos.trDelta ); // save net bandwidth // pass the missile charge through charge = ( float )( damage - LCANNON_SECONDARY_DAMAGE ) / LCANNON_DAMAGE; m->s.torsoAnim = charge * 255; if ( m->s.torsoAnim < 0 ) { m->s.torsoAnim = 0; } } else { m = G_SpawnMissile( MIS_LCANNON2, self, start, dir, NULL, G_ExplodeMissile, nextthink ); } return m; }
gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up ) { gentity_t *bolt; vec3_t dir; vec3_t end; float r, u, scale; bolt = G_Spawn(); bolt->classname = "nail"; bolt->nextthink = level.time + 10000; bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_NAILGUN; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = 20; bolt->methodOfDeath = MOD_NAIL; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time; VectorCopy( start, bolt->s.pos.trBase ); r = random() * M_PI * 2.0f; u = sin(r) * crandom() * NAILGUN_SPREAD * 16; r = cos(r) * crandom() * NAILGUN_SPREAD * 16; VectorMA( start, 8192 * 16, forward, end); VectorMA (end, r, right, end); VectorMA (end, u, up, end); VectorSubtract( end, start, dir ); VectorNormalize( dir ); scale = 555 + random() * 1800; VectorScale( dir, scale, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); VectorCopy( start, bolt->r.currentOrigin ); if ( self->player ) { bolt->s.team = self->player->sess.sessionTeam; } else { bolt->s.team = TEAM_FREE; } return bolt; }
/* ================= fire_railsphere ================= */ gentity_t *fire_railsphere(gentity_t * self, vec3_t start, vec3_t dir) { gentity_t *bolt; vec3_t mins = { -16, -16, -16 }; vec3_t maxs = { 16, 16, 16 }; VectorNormalize(dir); bolt = G_Spawn(); bolt->classname = "rocket"; bolt->nextthink = level.time + 15000; // bolt->think = RailSphereDamage; // bolt->think = G_ExplodeMissile; bolt->think = G_FreeEntity; // FIXME bolt->s.eType = ET_PROJECTILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_RAILGUN; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = 75; bolt->splashDamage = 50; bolt->splashRadius = 120; bolt->methodOfDeath = MOD_RAILGUN_SPLASH; bolt->splashMethodOfDeath = MOD_RAILGUN_SPLASH; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; // make the sphere shootable bolt->r.contents = CONTENTS_SHOOTABLE; VectorCopy(mins, bolt->r.mins); VectorCopy(maxs, bolt->r.maxs); bolt->takedamage = qtrue; bolt->health = 25; bolt->die = RailSphere_Die; bolt->s.pos.trType = TR_LINEAR; VectorScale(dir, 400, bolt->s.pos.trDelta); bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy(start, bolt->s.pos.trBase); SnapVector(bolt->s.pos.trDelta); // save net bandwidth VectorCopy(start, bolt->r.currentOrigin); return bolt; }
void DropPortalSource(gentity_t * player) { gentity_t *ent; gentity_t *destination; vec3_t snapped; // create the portal source ent = G_Spawn(); ent->s.modelindex = G_ModelIndex("models/powerups/teleporter/tele_enter.md3"); VectorCopy(player->s.pos.trBase, snapped); SnapVector(snapped); G_SetOrigin(ent, snapped); VectorCopy(player->r.mins, ent->r.mins); VectorCopy(player->r.maxs, ent->r.maxs); ent->classname = "hi_portal source"; ent->s.pos.trType = TR_STATIONARY; ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER; ent->takedamage = qtrue; ent->health = 200; ent->die = PortalDie; trap_LinkEntity(ent); ent->count = player->client->portalID; player->client->portalID = 0; // ent->spawnflags = player->client->ps.persistant[PERS_TEAM]; ent->nextthink = level.time + 1000; ent->think = PortalEnable; // find the destination destination = NULL; while((destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL) { if(destination->count == ent->count) { VectorCopy(destination->s.pos.trBase, ent->pos1); break; } } }
gentity_t *fire_gravnail(gentity_t * self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up) { gentity_t *bolt; vec3_t dir; vec3_t end; float r, u, scale; bolt = G_Spawn(); bolt->classname = "nail"; bolt->nextthink = level.time + 500; bolt->think = G_FreeEntity; bolt->s.eType = ET_PROJECTILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_FLAK_CANNON; // bolt->s.eFlags = EF_BOUNCE_HALF; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = 20; bolt->methodOfDeath = MOD_NAIL; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; // bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trAcceleration = g_gravity.value; bolt->s.pos.trTime = level.time; VectorCopy(start, bolt->s.pos.trBase); r = random() * M_PI * 2.0f; u = sin(r) * crandom() * NAILGUN_SPREAD * 16; r = cos(r) * crandom() * NAILGUN_SPREAD * 16; VectorMA(start, 8192 * 16, forward, end); VectorMA(end, r, right, end); VectorMA(end, u, up, end); VectorSubtract(end, start, dir); VectorNormalize(dir); scale = 555 + random() * 1800; VectorScale(dir, scale, bolt->s.pos.trDelta); SnapVector(bolt->s.pos.trDelta); VectorCopy(start, bolt->r.currentOrigin); return bolt; }
/* ================ G_Bounce ================ */ static void G_Bounce( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; float minNormal; bool invert = false; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta ); if( ent->s.eType == ET_BUILDABLE ) { minNormal = BG_FindMinNormalForBuildable( ent->s.modelindex ); invert = BG_FindInvertNormalForBuildable( ent->s.modelindex ); } else minNormal = 0.707f; // cut the velocity to keep from bouncing forever if( ( trace->plane.normal[ 2 ] >= minNormal || ( invert && trace->plane.normal[ 2 ] <= -minNormal ) ) && trace->entityNum == ENTITYNUM_WORLD ) VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta ); else VectorScale( ent->s.pos.trDelta, 0.3f, ent->s.pos.trDelta ); if( VectorLength( ent->s.pos.trDelta ) < 10 ) { VectorMA( trace->endpos, 0.5, trace->plane.normal, trace->endpos ); // make sure it is off ground SnapVector( trace->endpos ); G_SetOrigin( ent, trace->endpos ); ent->s.groundEntityNum = trace->entityNum; VectorCopy( trace->plane.normal, ent->s.origin2 ); VectorSet( ent->s.pos.trDelta, 0.0f, 0.0f, 0.0f ); return; } VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin); ent->s.pos.trTime = level.time; }
static void RocketThink( gentity_t *self ) { vec3_t currentDir, targetDir, newDir, rotAxis; float rotAngle; if ( level.time > self->timestamp ) { self->think = G_ExplodeMissile; self->nextthink = level.time; return; } self->nextthink = level.time + ROCKET_TURN_PERIOD; // Calculate current and target direction. VectorNormalize2( self->s.pos.trDelta, currentDir ); VectorSubtract( self->target->r.currentOrigin, self->r.currentOrigin, targetDir ); VectorNormalize( targetDir ); // Don't turn anymore after the target was passed. if ( DotProduct( currentDir, targetDir ) < 0 ) { return; } // Calculate new direction. Use a fixed turning angle. CrossProduct( currentDir, targetDir, rotAxis ); rotAngle = RAD2DEG( acos( DotProduct( currentDir, targetDir ) ) ); RotatePointAroundVector( newDir, rotAxis, currentDir, Math::Clamp( rotAngle, -ROCKET_TURN_ANGLE, ROCKET_TURN_ANGLE ) ); // Check if new direction is safe. Turn anyway if old direction is unsafe, too. if ( !G_RocketpodSafeShot( ENTITYNUM_NONE, self->r.currentOrigin, newDir ) && G_RocketpodSafeShot( ENTITYNUM_NONE, self->r.currentOrigin, currentDir ) ) { return; } // Update trajectory. VectorScale( newDir, BG_Missile( self->s.modelindex )->speed, self->s.pos.trDelta ); SnapVector( self->s.pos.trDelta ); VectorCopy( self->r.currentOrigin, self->s.pos.trBase ); // TODO: Snap this, too? self->s.pos.trTime = level.time; }
/* ======================================================================================================================================= G_TempEntity Spawns an event entity that will be auto-removed. The origin will be snapped to save net bandwidth, so care must be taken if the origin is right on a surface (snap towards start vector first). ======================================================================================================================================= */ gentity_t *G_TempEntity(vec3_t origin, int event) { gentity_t *e; vec3_t snapped; e = G_Spawn(); e->s.eType = ET_EVENTS + event; e->classname = "tempEntity"; e->eventTime = level.time; e->freeAfterEvent = qtrue; VectorCopy(origin, snapped); SnapVector(snapped); // save network bandwidth G_SetOrigin(e, snapped); // find cluster for PVS trap_LinkEntity(e); return e; }
/* ================ Modified by Elder dropWeapon XRAY FMJ ================ */ gentity_t *dropWeapon(gentity_t * ent, gitem_t * item, float angle, int xr_flags) { vec3_t velocity; vec3_t angles; vec3_t origin; //int throwheight; vec3_t mins, maxs; trace_t tr; VectorCopy(ent->s.pos.trBase, origin); VectorCopy(ent->s.apos.trBase, angles); angles[YAW] += angle; angles[PITCH] = -55; // always at a 55 degree above horizontal angle AngleVectors(angles, velocity, NULL, NULL); // set aiming directions //AngleVectors (ent->client->ps.viewangles, velocity, NULL, NULL); //Elder: don't toss from the head, but from the "waist" origin[2] += 10; // (ent->client->ps.viewheight / 2); VectorMA(origin, 5, velocity, origin); // 14 34 10 // Set temporary bounding box for trace VectorSet(mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS); VectorSet(maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS); // NiceAss: Check if the new location starts in a solid. // FIXME: Use trap_point or whatever? trap_Trace(&tr, origin, mins, maxs, origin, ent->s.number, MASK_SOLID); if (tr.startsolid == qtrue) VectorMA(origin, -7, velocity, origin); // -5 won't work (hint: it should work). Only -7 or less will.. // snap to integer coordinates for more efficient network bandwidth usage SnapVector(origin); // less vertical velocity //velocity[2] += 0.2f; //velocity[2] = 20; VectorNormalize(velocity); VectorScale(velocity, 5, velocity); return LaunchItem(item, origin, velocity, xr_flags); }
/* ============ G_StoreHistory Keep track of where the client's been ============ */ void G_StoreHistory( gentity_t *ent ) { int head, frametime; frametime = level.time - level.previousTime; ent->client->historyHead++; if ( ent->client->historyHead >= NUM_CLIENT_HISTORY ) { ent->client->historyHead = 0; } head = ent->client->historyHead; // store all the collision-detection info and the time VectorCopy( ent->r.mins, ent->client->history[head].mins ); VectorCopy( ent->r.maxs, ent->client->history[head].maxs ); VectorCopy( ent->s.pos.trBase, ent->client->history[head].currentOrigin ); SnapVector( ent->client->history[head].currentOrigin ); ent->client->history[head].leveltime = level.time; }
/* ================= fire_prox ================= */ gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t dir ) { gentity_t *bolt; VectorNormalize (dir); bolt = G_Spawn(); bolt->classname = "prox mine"; bolt->nextthink = level.time + 3000; bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_PROX_LAUNCHER; bolt->s.eFlags = 0; bolt->r.ownerNum = self->s.number; //unlagged - projectile nudge // we'll need this for nudging projectiles later bolt->s.otherEntityNum = self->s.number; //unlagged - projectile nudge bolt->parent = self; bolt->damage = 0; bolt->splashDamage = 100; bolt->splashRadius = 150; bolt->methodOfDeath = MOD_PROXIMITY_MINE; bolt->splashMethodOfDeath = MOD_PROXIMITY_MINE; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; // count is used to check if the prox mine left the player bbox // if count == 1 then the prox mine left the player bbox and can attack to it bolt->count = 0; //FIXME: we prolly wanna abuse another field bolt->s.generic1 = self->client->sess.sessionTeam; bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, 700, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->r.currentOrigin); return bolt; }
/* ================ G_ExplodeMissile Explode a missile without an impact ================ */ void G_ExplodeMissile( gentity_t *ent ) { vec3_t dir; vec3_t origin; BG_EvaluateTrajectory( &ent->s.pos, level.time, origin ); SnapVector( origin ); G_SetOrigin( ent, origin ); // we don't have a valid direction, so just point straight up dir[0] = dir[1] = 0; dir[2] = 1; ent->s.eType = ET_GENERAL; G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) ); ent->freeAfterEvent = qtrue; ent->takedamage = qfalse; // splash damage if ( ent->splashDamage ) { //NOTE: vehicle missiles don't have an ent->parent set, so check that here and set it if ( ent->s.eType == ET_MISSILE//missile && (ent->s.eFlags&EF_JETPACK_ACTIVE)//vehicle missile && ent->r.ownerNum < MAX_CLIENTS )//valid client owner {//set my parent to my owner for purposes of damage credit... ent->parent = &g_entities[ent->r.ownerNum]; } if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, ent, ent->splashMethodOfDeath ) ) { if (ent->parent) { g_entities[ent->parent->s.number].client->accuracy_hits++; } else if (ent->activator) { g_entities[ent->activator->s.number].client->accuracy_hits++; } } } trap_LinkEntity( ent ); }
/* ================ DropWeapon RPG-X Marcin 03/12/2008 ================ */ gentity_t *DropWeapon( gentity_t *ent, gitem_t *item, float angle, int flags, char *txt ) { vec3_t velocity; vec3_t origin; VectorCopy( ent->s.pos.trBase, origin ); // set aiming directions AngleVectors (ent->client->ps.viewangles, velocity, NULL, NULL); origin[2] += ent->client->ps.viewheight + 10; VectorMA( origin, 14, velocity, origin ); // snap to integer coordinates for more efficient network bandwidth usage SnapVector( origin ); // extra vertical velocity velocity[2] += 0.2; VectorNormalize( velocity ); return LaunchItem( item, ent, origin, velocity, flags, txt ); }
/* ================ AHive_ReturnToHive Adjust the trajectory to point towards the hive ================ */ void AHive_ReturnToHive( gentity_t *self ) { vec3_t dir; trace_t tr; if( !self->parent ) { G_Printf( S_COLOR_YELLOW "WARNING: AHive_ReturnToHive called with no self->parent\n" ); return; } trap_UnlinkEntity( self->parent ); trap_Trace( &tr, self->r.currentOrigin, self->r.mins, self->r.maxs, self->parent->r.currentOrigin, self->r.ownerNum, self->clipmask ); trap_LinkEntity( self->parent ); if( tr.fraction < 1.0f ) { //if can't see hive then disperse VectorCopy( self->r.currentOrigin, self->s.pos.trBase ); self->s.pos.trType = TR_STATIONARY; self->s.pos.trTime = level.time; self->think = G_ExplodeMissile; self->nextthink = level.time + 2000; self->parent->active = qfalse; //allow the parent to start again } else { VectorSubtract( self->parent->r.currentOrigin, self->r.currentOrigin, dir ); VectorNormalize( dir ); //change direction towards the hive VectorScale( dir, HIVE_SPEED, self->s.pos.trDelta ); SnapVector( self->s.pos.trDelta ); // save net bandwidth VectorCopy( self->r.currentOrigin, self->s.pos.trBase ); self->s.pos.trTime = level.time; self->think = G_ExplodeMissile; self->nextthink = level.time + 15000; } }
gentity_t *fire_molotov (gentity_t *self, vec3_t start, vec3_t dir, int speed) { gentity_t *bolt; VectorNormalize (dir); bolt = G_Spawn(); bolt->classname = "molotov"; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->r.svFlags |= SVF_BROADCAST; bolt->s.weapon = WP_MOLOTOV; bolt->r.ownerNum = self->s.number; //unlagged - projectile nudge // we'll need this for nudging projectiles later bolt->s.otherEntityNum = self->s.number; //unlagged - projectile nudge bolt->parent = self; bolt->damage = 7; bolt->splashDamage = 0; bolt->splashRadius = 0; bolt->methodOfDeath = MOD_MOLOTOV; bolt->splashMethodOfDeath = MOD_MOLOTOV; bolt->clipmask = MASK_SHOT; bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trTime = level.time + MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, speed, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->r.currentOrigin); if(self->client){ if(self->client->ps.stats[STAT_WP_MODE] < 0) bolt->s.apos.trDelta[0] = self->client->ps.stats[STAT_WP_MODE]; else bolt->s.apos.trDelta[0] = 0; } return bolt; }
/* ============== fire_mortar dir is a non-normalized direction/power vector ============== */ gentity_t *fire_mortar( gentity_t *self, vec3_t start, vec3_t dir ) { gentity_t *bolt; // VectorNormalize (dir); if ( self->spawnflags ) { gentity_t *tent; tent = G_TempEntity( self->s.pos.trBase, EV_MORTAREFX ); tent->s.density = self->spawnflags; // send smoke and muzzle flash flags VectorCopy( self->s.pos.trBase, tent->s.origin ); VectorCopy( self->s.apos.trBase, tent->s.angles ); } bolt = G_Spawn(); bolt->classname = const_cast<char*>("mortar"); bolt->nextthink = level.time + 20000; // push it out a little bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN | SVF_BROADCAST; // broadcast sound. not multiplayer friendly, but for mortars it should be okay // bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_MORTAR; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = G_GetWeaponDamage( WP_MORTAR ); // JPW NERVE bolt->splashDamage = G_GetWeaponDamage( WP_MORTAR ); // JPW NERVE bolt->splashRadius = 120; bolt->methodOfDeath = MOD_MORTAR; bolt->splashMethodOfDeath = MOD_MORTAR_SPLASH; bolt->clipmask = MASK_MISSILESHOT; bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); // VectorScale( dir, 900, bolt->s.pos.trDelta ); VectorCopy( dir, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin ); return bolt; }