void SP_camera_cam( gentity_t *ent ) { Init_Camera( ent ); ent->r.svFlags = SVF_USE_CURRENT_ORIGIN; ent->s.eType = ET_MOVER; G_SetOrigin( ent, ent->s.origin ); G_SetAngle( ent, ent->s.angles ); ent->reached = Reached_Tramcar; ent->nextthink = level.time + ( FRAMETIME / 2 ); ent->think = camera_cam_firstthink; ent->use = camera_cam_use; if ( ent->spawnflags & 1 ) { // On gentity_t *delayOn; delayOn = G_Spawn(); delayOn->think = delayOnthink; delayOn->nextthink = level.time + 1000; delayOn->melee = ent; trap_LinkEntity( delayOn ); } }
/*QUAKED script_mover (0.5 0.25 1.0) ? TRIGGERSPAWN SOLID EXPLOSIVEDAMAGEONLY Scripted brush entity. A simplified means of moving brushes around based on events. "modelscale" - Scale multiplier (defaults to 1, and scales uniformly) "modelscale_vec" - Set scale per-axis. Overrides "modelscale", so if you have both the "modelscale" is ignored "model2" optional md3 to draw over the solid clip brush "scriptname" name used for scripting purposes (like aiName in AI scripting) "health" optionally make this entity damagable */ void SP_script_mover( gentity_t *ent ) { float scale[3] = {1,1,1}; vec3_t scalevec; if ( !ent->model ) { G_Error( "script_model_med must have a \"model\"\n" ); } if ( !ent->scriptName ) { G_Error( "script_model_med must have a \"scriptname\"\n" ); } ent->blocked = script_mover_blocked; // first position at start VectorCopy( ent->s.origin, ent->pos1 ); // VectorCopy( ent->r.currentOrigin, ent->pos1 ); VectorCopy( ent->pos1, ent->pos2 ); // don't go anywhere just yet trap_SetBrushModel( ent, ent->model ); InitMover( ent ); ent->reached = NULL; if ( ent->spawnflags & 1 ) { ent->use = script_mover_use; trap_UnlinkEntity( ent ); // make sure it's not visible return; } G_SetAngle( ent, ent->s.angles ); G_SpawnInt( "health", "0", &ent->health ); if ( ent->health ) { ent->takedamage = qtrue; } ent->die = script_mover_die; ent->pain = script_mover_pain; // look for general scaling if ( G_SpawnFloat( "modelscale", "1", &scale[0] ) ) { scale[2] = scale[1] = scale[0]; } // look for axis specific scaling if ( G_SpawnVector( "modelscale_vec", "1 1 1", &scalevec[0] ) ) { VectorCopy( scalevec, scale ); } if ( scale[0] != 1 || scale[1] != 1 || scale[2] != 1 ) { // ent->s.eType = ET_MOVERSCALED; ent->s.density = ET_MOVERSCALED; // scale is stored in 'angles2' VectorCopy( scale, ent->s.angles2 ); } script_mover_spawn( ent ); }
/*QUAKED team_WOLF_checkpoint (.9 .3 .9) (-16 -16 0) (16 16 128) SPAWNPOINT CP_HOLD AXIS_ONLY ALLIED_ONLY This is the flagpole players touch in Capture and Hold game scenarios. It will call specific trigger funtions in the map script for this object. When allies capture, it will call "allied_capture". When axis capture, it will call "axis_capture". // JPW NERVE if spawnpoint flag is set, think will turn on spawnpoints (specified as targets) // for capture team and turn *off* targeted spawnpoints for opposing team */ void SP_team_WOLF_checkpoint(gentity_t *ent) { char *capture_sound; if (!ent->scriptName) { G_Error("team_WOLF_checkpoint must have a \"scriptname\"\n"); } // Make sure the ET_TRAP entity type stays valid ent->s.eType = ET_TRAP; // Model is user assignable, but it will always try and use the animations for flagpole.md3 if (ent->model) { ent->s.modelindex = G_ModelIndex(ent->model); } else { ent->s.modelindex = G_ModelIndex("models/multiplayer/flagpole/flagpole.md3"); } G_SpawnString("noise", "sound/movers/doors/door6_open.wav", &capture_sound); ent->soundPos1 = G_SoundIndex(capture_sound); ent->clipmask = CONTENTS_SOLID; ent->r.contents = CONTENTS_SOLID; VectorSet(ent->r.mins, -8, -8, 0); VectorSet(ent->r.maxs, 8, 8, 128); G_SetOrigin(ent, ent->s.origin); G_SetAngle(ent, ent->s.angles); // s.frame is the animation number ent->s.frame = WCP_ANIM_NOFLAG; // s.teamNum is which set of animations to use ( only 1 right now ) ent->s.teamNum = 1; // Used later to set animations (and delay between captures) ent->nextthink = 0; // Used to time how long it must be "held" to switch ent->health = -1; ent->count2 = -1; // 'count' signifies which team holds the checkpoint ent->count = -1; // JPW NERVE if (ent->spawnflags & SPAWNPOINT) { ent->touch = checkpoint_spawntouch; } else { if (ent->spawnflags & CP_HOLD) { ent->use = checkpoint_use; } else { ent->touch = checkpoint_touch; } } // jpw trap_LinkEntity(ent); }
gentity_t *LaunchBinocs( gitem_t *item, vec3_t origin, vec3_t velocity, int ownerNum ) { gentity_t *dropped; trace_t tr; vec3_t vec, temp; int i; dropped = G_Spawn(); dropped->s.eType = ET_ITEM; dropped->s.modelindex = item - bg_itemlist; // store item number in modelindex dropped->s.otherEntityNum2 = 1; // DHM - Nerve :: this is taking modelindex2's place for a dropped item dropped->classname = item->classname; dropped->item = item; VectorSet( dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS); //----(SA) so items sit on the ground VectorSet( dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS ); //----(SA) so items sit on the ground dropped->r.contents = CONTENTS_TRIGGER|CONTENTS_ITEM; dropped->clipmask = CONTENTS_SOLID | CONTENTS_MISSILECLIP; // NERVE - SMF - fix for items falling through grates dropped->touch = Touch_Item_Auto; trap_Trace( &tr, origin, dropped->r.mins, dropped->r.maxs, origin, ownerNum, MASK_SOLID ); if ( tr.startsolid ) { VectorSubtract( g_entities[ownerNum].s.origin, origin, temp ); VectorNormalize( temp ); for ( i=16; i<=48; i+=16 ) { VectorScale( temp, i, vec ); VectorAdd( origin, vec, origin ); trap_Trace( &tr, origin, dropped->r.mins, dropped->r.maxs, origin, ownerNum, MASK_SOLID ); if ( !tr.startsolid ) break; } } G_SetOrigin( dropped, origin ); dropped->s.pos.trType = TR_GRAVITY; dropped->s.pos.trTime = level.time; velocity[0] = crandom(); velocity[1] = crandom(); velocity[2] = 0; VectorScale(velocity, 100, velocity); velocity[2] = 150; VectorCopy( velocity, dropped->s.pos.trDelta ); // ydnar: set yaw to parent angles temp[ PITCH ] = 0; temp[ YAW ] = g_entities[ ownerNum ].s.apos.trBase[ YAW ]; temp[ ROLL ] = 0; G_SetAngle( dropped, temp ); dropped->s.eFlags |= EF_BOUNCE_HALF; dropped->think = G_FreeEntity; dropped->nextthink = level.time + 30000; dropped->flags = FL_DROPPED_ITEM; trap_LinkEntity (dropped); return dropped; }
/*QUAKED alarm_box (1 0 1) START_ON You need to have an origin brush as part of this entity current alarm box model is (8 x 16 x 28) "health" - defaults to 10 "dmg" - damage and radius value when it dies "noise" - the sound to play over the system (this would be the siren sound) START_ON means the button is pushed in, any dlights are cycling, and alarms are sounding "team" key/value is valid for teamed alarm boxes teamed alarm_boxes work in tandem (switches/lights syncronize) target a box to dlights to have them activate/deactivate with the system (use a stylestring that matches the cycletime for the alarmbox sound) alarm sound locations are also placed in the dlights, so wherever you place an attached dlight, you will hear the alarm model: the model used is "models/mapobjects/electronics/alarmbox.md3" place the origin at the center of your trigger box */ void SP_alarm_box(gentity_t *ent) { char *s; if(!ent->model) { G_Printf(S_COLOR_RED "alarm_box with NULL model\n"); return; } // model trap_SetBrushModel(ent, ent->model); ent->s.modelindex2 = G_ModelIndex("models/mapobjects/electronics/alarmbox.md3"); // sound if(G_SpawnString("noise", "0", &s)) { ent->soundLoop = G_SoundIndex(s); } // activation sound ent->soundPos3 = G_SoundIndex("sound/world/alarmswitch.wav"); // death sound ent->sound1to2 = G_SoundIndex("sound/world/alarmdeath.wav"); G_SetOrigin(ent, ent->s.origin); G_SetAngle(ent, ent->s.angles); if(!ent->health) { ent->health = 10; } if(ent->spawnflags & 1) { ent->s.frame = 1; } else { ent->s.frame = 0; } ent->active = qtrue; ent->s.eType = ET_ALARMBOX; ent->takedamage = qtrue; ent->die = alarmbox_die; ent->use = alarmbox_use; ent->think = alarmbox_finishspawning; ent->nextthink = level.time + FRAMETIME; trap_LinkEntity(ent); }
/*QUAKED misc_cabinet_supply (.5 .5 .5) (-20 -20 0) (20 20 60) */ void SP_misc_cabinet_supply( gentity_t* self ) { VectorSet (self->r.mins, -20, -20, 0); VectorSet (self->r.maxs, 20, 20, 60); G_SetOrigin (self, self->s.origin); G_SetAngle (self, self->s.angles); self->s.eType = ET_CABINET_A; self->clipmask = CONTENTS_SOLID; self->r.contents = CONTENTS_SOLID; trap_LinkEntity( self ); }
void camera_cam_firstthink( gentity_t *ent ) { gentity_t *target = NULL; vec3_t dang; vec3_t vec; if ( ent->track ) { target = G_Find( NULL, FOFS( targetname ), ent->track ); } if ( target ) { VectorSubtract( target->s.origin, ent->r.currentOrigin, vec ); vectoangles( vec, dang ); G_SetAngle( ent, dang ); } if ( ent->target ) { ent->nextthink = level.time + ( FRAMETIME / 2 ); ent->think = Think_SetupTrainTargets; } }
/* ================ G_BounceItem ================ */ void G_BounceItem( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity, qfalse, ent->s.effect2Time ); dot = DotProduct( velocity, trace->plane.normal ); VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta ); // cut the velocity to keep from bouncing forever VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta ); // check for stop if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) { if (g_flushItems.integer) { vectoangles( trace->plane.normal, ent->s.angles ); ent->s.angles[0] += 90; if (ent->s.angles[0] > 0.0 && ent->s.angles[0] < 50.0) { // avoid freaky medpacks G_SetAngle( ent, ent->s.angles); trace->endpos[2] -= (tan(DEG2RAD(ent->s.angles[0])) * ITEM_RADIUS); } else { trace->endpos[2] += 1.0; // make sure it is off ground } } else { trace->endpos[2] += 1.0; // make sure it is off ground } SnapVector( trace->endpos ); G_SetOrigin( ent, trace->endpos ); ent->s.groundEntityNum = trace->entityNum; return; } VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin); VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; }
// Zero: drops a powerup // ent is the entity that is dropping the powerup // touch is called when pwup is touched. gentity_t *DropPowerup( gentity_t *ent, gitem_t *item, void (*touch)(gentity_t *self, gentity_t *other, trace_t *trace), qboolean gravity ) { gentity_t *powerup = NULL; if(!item) { return NULL; } powerup = G_Spawn(); powerup->s.eType = ET_ITEM; powerup->s.modelindex = item - bg_itemlist; powerup->s.otherEntityNum2 = 1; powerup->classname = item->classname; powerup->item = item; if(gravity) { powerup->s.pos.trType = TR_GRAVITY; } VectorSet( powerup->r.mins, -POWERUP_ITEM_RADIUS, -POWERUP_ITEM_RADIUS, 0 ); //----(SA) so items sit on the ground VectorSet( powerup->r.maxs, POWERUP_ITEM_RADIUS, POWERUP_ITEM_RADIUS, 2*POWERUP_ITEM_RADIUS ); //----(SA) so items sit on the ground powerup->r.contents = CONTENTS_TRIGGER | CONTENTS_ITEM; powerup->clipmask = CONTENTS_SOLID | CONTENTS_MISSILECLIP; powerup->touch = touch; powerup->think = dummythink; powerup->nextthink = 100; G_SetOrigin(powerup, ent->r.currentOrigin); G_SetAngle(powerup, ent->r.currentAngles); powerup->parent = ent; trap_LinkEntity(powerup); return powerup; }
/*QUAKED script_mover (0.5 0.25 1.0) ? TRIGGERSPAWN SOLID EXPLOSIVEDAMAGEONLY RESURECTABLE COMPASS ALLIED AXIS MOUNTED_GUN Scripted brush entity. A simplified means of moving brushes around based on events. "modelscale" - Scale multiplier (defaults to 1, and scales uniformly) "modelscale_vec" - Set scale per-axis. Overrides "modelscale", so if you have both the "modelscale" is ignored "model2" optional md3 to draw over the solid clip brush "scriptname" name used for scripting purposes (like aiName in AI scripting) "health" optionally make this entity damagable "description" used with health, if the entity is damagable, it draws a healthbar with this description above it. */ void SP_script_mover(gentity_t *ent) { float scale[3] = { 1, 1, 1 }; vec3_t scalevec; char *modelname; char *tagent; char *s; if (!ent->model) { G_Error("script_mover must have a \"model\"\n"); } if (!ent->scriptName) { G_Error("script_mover must have a \"scriptname\"\n"); } ent->blocked = script_mover_blocked; // first position at start VectorCopy(ent->s.origin, ent->pos1); VectorCopy(ent->pos1, ent->pos2); // don't go anywhere just yet trap_SetBrushModel(ent, ent->model); InitMover(ent); ent->reached = NULL; ent->s.animMovetype = 0; ent->s.density = 0; if (ent->spawnflags & 256) { ent->s.density |= 2; } if (ent->spawnflags & 8) { ent->use = script_mover_use; } if (ent->spawnflags & 16) { ent->s.time2 = 1; } else { ent->s.time2 = 0; } if (ent->spawnflags & 32) { ent->s.teamNum = TEAM_ALLIES; } else if (ent->spawnflags & 64) { ent->s.teamNum = TEAM_AXIS; } else { ent->s.teamNum = TEAM_FREE; } if (ent->spawnflags & 1) { ent->use = script_mover_use; trap_UnlinkEntity(ent); // make sure it's not visible return; } G_SetAngle(ent, ent->s.angles); G_SpawnInt("health", "0", &ent->health); if (ent->health) { ent->takedamage = qtrue; ent->count = ent->health; // client needs to know about it as well ent->s.effect1Time = ent->count; ent->s.dl_intensity = 255; if (G_SpawnString("description", "", &s)) { char cs[MAX_INFO_STRING]; trap_GetConfigstring(CS_SCRIPT_MOVER_NAMES, cs, sizeof (cs)); Info_SetValueForKey(cs, va("%d", (int)(ent - g_entities)), s); trap_SetConfigstring(CS_SCRIPT_MOVER_NAMES, cs); } } else { ent->count = 0; } ent->die = script_mover_die; // look for general scaling if (G_SpawnFloat("modelscale", "1", &scale[0])) { scale[2] = scale[1] = scale[0]; } if (G_SpawnString("model2", "", &modelname)) { char tagname[MAX_QPATH]; COM_StripExtension(modelname, tagname); Q_strcat(tagname, MAX_QPATH, ".tag"); ent->tagNumber = trap_LoadTag(tagname); } // look for axis specific scaling if (G_SpawnVector("modelscale_vec", "1 1 1", &scalevec[0])) { VectorCopy(scalevec, scale); } if (scale[0] != 1 || scale[1] != 1 || scale[2] != 1) { ent->s.density |= 1; // scale is stored in 'angles2' VectorCopy(scale, ent->s.angles2); } if (ent->spawnflags & 128) { ent->s.density |= 4; ent->waterlevel = 0; if (G_SpawnString("gun", "", &modelname) && !Q_stricmp(modelname, "browning")) { ent->s.density |= 8; } G_SpawnString("tagent", "", &tagent); Q_strncpyz(ent->tagBuffer, tagent, 16); ent->s.powerups = -1; } ent->think = script_mover_spawn; ent->nextthink = level.time + FRAMETIME; }
/* ================ FinishSpawningItem Traces down to find where an item should rest, instead of letting them free fall from their spawn points ================ */ void FinishSpawningItem( gentity_t *ent ) { trace_t tr; vec3_t dest; vec3_t maxs; if ( ent->spawnflags & 1 ) { // suspended VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS ); VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS ); VectorCopy( ent->r.maxs, maxs ); } else { // Rafael // had to modify this so that items would spawn in shelves VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, 0 ); VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS ); VectorCopy( ent->r.maxs, maxs ); maxs[2] /= 2; } ent->r.contents = CONTENTS_TRIGGER | CONTENTS_ITEM; ent->touch = Touch_Item_Auto; ent->s.eType = ET_ITEM; ent->s.modelindex = ent->item - bg_itemlist; // store item number in modelindex ent->s.otherEntityNum2 = 0; // DHM - Nerve :: takes modelindex2's place in signaling a dropped item //----(SA) we don't use this (yet, anyway) so I'm taking it so you can specify a model for treasure items and clipboards // ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item if ( ent->model ) { ent->s.modelindex2 = G_ModelIndex( ent->model ); } // if clipboard, add the menu name string to the client's configstrings if ( ent->item->giType == IT_CLIPBOARD ) { if ( !ent->message ) { ent->s.density = G_FindConfigstringIndex( "clip_test", CS_CLIPBOARDS, MAX_CLIPBOARD_CONFIGSTRINGS, qtrue ); } else { ent->s.density = G_FindConfigstringIndex( ent->message, CS_CLIPBOARDS, MAX_CLIPBOARD_CONFIGSTRINGS, qtrue ); } ent->touch = Touch_Item; // no auto-pickup, only activate } else if ( ent->item->giType == IT_HOLDABLE ) { if ( ent->item->giTag >= HI_BOOK1 && ent->item->giTag <= HI_BOOK3 ) { G_FindConfigstringIndex( va( "hbook%d", ent->item->giTag - HI_BOOK1 ), CS_CLIPBOARDS, MAX_CLIPBOARD_CONFIGSTRINGS, qtrue ); } ent->touch = Touch_Item; // no auto-pickup, only activate } //----(SA) added if ( ent->item->giType == IT_TREASURE ) { ent->touch = Touch_Item; // no auto-pickup, only activate } //----(SA) end // using an item causes it to respawn ent->use = Use_Item; //----(SA) moved this up so it happens for suspended items too (and made it a function) G_SetAngle( ent, ent->s.angles ); if ( ent->spawnflags & 1 ) { // suspended G_SetOrigin( ent, ent->s.origin ); } else { VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 ); trap_Trace( &tr, ent->s.origin, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID ); if ( tr.startsolid ) { vec3_t temp; VectorCopy( ent->s.origin, temp ); temp[2] -= ITEM_RADIUS; VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 ); trap_Trace( &tr, temp, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID ); } #if 0 // drop to floor VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 ); trap_Trace( &tr, ent->s.origin, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID ); #endif if ( tr.startsolid ) { G_Printf( "FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos( ent->s.origin ) ); G_FreeEntity( ent ); return; } // allow to ride movers ent->s.groundEntityNum = tr.entityNum; G_SetOrigin( ent, tr.endpos ); } if ( ent->spawnflags & 2 ) { // spin ent->s.eFlags |= EF_SPINNING; } // team slaves and targeted items aren't present at start if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) { ent->flags |= FL_NODRAW; //ent->s.eFlags |= EF_NODRAW; ent->r.contents = 0; return; } // health/ammo can potentially be multi-stage (multiple use) if ( ent->item->giType == IT_HEALTH || ent->item->giType == IT_AMMO || ent->item->giType == IT_POWERUP ) { int i; // having alternate models defined in bg_misc.c for a health or ammo item specify it as "multi-stage" // TTimo left-hand operand of comma expression has no effect // initial line: for(i=0;i<4,ent->item->world_model[i];i++) {} for ( i = 0; i < 4 && ent->item->world_model[i] ; i++ ) {} ent->s.density = i - 1; // store number of stages in 'density' for client (most will have '1') } // powerups don't spawn in for a while if ( ent->item->giType == IT_POWERUP && g_gametype.integer != GT_SINGLE_PLAYER ) { float respawn; respawn = 45 + crandom() * 15; ent->flags |= FL_NODRAW; //ent->s.eFlags |= EF_NODRAW; ent->r.contents = 0; ent->nextthink = level.time + respawn * 1000; ent->think = RespawnItem; return; } trap_LinkEntity( ent ); }
/* ================ LaunchItem Spawns an item and tosses it forward ================ */ gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity, int ownerNum ) { gentity_t *dropped; trace_t tr; vec3_t vec, temp; int i; dropped = G_Spawn(); dropped->s.eType = ET_ITEM; dropped->s.modelindex = item - bg_itemlist; // store item number in modelindex dropped->s.otherEntityNum2 = 1; // DHM - Nerve :: this is taking modelindex2's place for a dropped item dropped->classname = item->classname; dropped->item = item; VectorSet( dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, 0 ); //----(SA) so items sit on the ground VectorSet( dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, 2*ITEM_RADIUS ); //----(SA) so items sit on the ground dropped->r.contents = CONTENTS_TRIGGER|CONTENTS_ITEM; dropped->clipmask = CONTENTS_SOLID | CONTENTS_MISSILECLIP; // NERVE - SMF - fix for items falling through grates dropped->touch = Touch_Item_Auto; trap_Trace( &tr, origin, dropped->r.mins, dropped->r.maxs, origin, ownerNum, MASK_SOLID ); if ( tr.startsolid ) { VectorSubtract( g_entities[ownerNum].s.origin, origin, temp ); VectorNormalize( temp ); for ( i=16; i<=48; i+=16 ) { VectorScale( temp, i, vec ); VectorAdd( origin, vec, origin ); trap_Trace( &tr, origin, dropped->r.mins, dropped->r.maxs, origin, ownerNum, MASK_SOLID ); if ( !tr.startsolid ) break; } } G_SetOrigin( dropped, origin ); dropped->s.pos.trType = TR_GRAVITY; dropped->s.pos.trTime = level.time; VectorCopy( velocity, dropped->s.pos.trDelta ); // ydnar: set yaw to parent angles temp[ PITCH ] = 0; temp[ YAW ] = g_entities[ ownerNum ].s.apos.trBase[ YAW ]; temp[ ROLL ] = 0; G_SetAngle( dropped, temp ); dropped->s.eFlags |= EF_BOUNCE_HALF; if (item->giType == IT_TEAM) { // Special case for CTF flags gentity_t* flag = &g_entities[ g_entities[ownerNum].client->flagParent ]; dropped->s.otherEntityNum = g_entities[ownerNum].client->flagParent; // store the entitynum of our original flag spawner dropped->s.density = 1; dropped->think = Team_DroppedFlagThink; dropped->nextthink = level.time + 30000; if( level.gameManager ) { G_Script_ScriptEvent( level.gameManager, "trigger", flag->item->giTag == PW_REDFLAG ? "allied_object_dropped" : "axis_object_dropped" ); } G_Script_ScriptEvent( flag, "trigger", "dropped" ); } else { // auto-remove after 30 seconds dropped->think = G_FreeEntity; dropped->nextthink = level.time + 30000; } dropped->flags = FL_DROPPED_ITEM; trap_LinkEntity (dropped); return dropped; }
/** * @brief Traces down to find where an item should rest, instead of letting them * free fall from their spawn points. */ void FinishSpawningItem(gentity_t *ent) { trace_t tr; vec3_t dest; vec3_t maxs; if (ent->spawnflags & 1) // suspended { VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS); VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS); VectorCopy(ent->r.maxs, maxs); } else { // had to modify this so that items would spawn in shelves VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, 0); VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS); VectorCopy(ent->r.maxs, maxs); maxs[2] /= 2; } ent->r.contents = CONTENTS_TRIGGER | CONTENTS_ITEM; ent->touch = Touch_Item_Auto; ent->s.eType = ET_ITEM; ent->s.modelindex = ent->item - bg_itemlist; // store item number in modelindex ent->s.otherEntityNum2 = 0; // takes modelindex2's place in signaling a dropped item // we don't use this (yet, anyway) so I'm taking it so you can specify a model for treasure items and clipboards //ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item if (ent->model) { ent->s.modelindex2 = G_ModelIndex(ent->model); } // using an item causes it to respawn ent->use = Use_Item; // moved this up so it happens for suspended items too (and made it a function) G_SetAngle(ent, ent->s.angles); if (ent->spawnflags & 1) // suspended { G_SetOrigin(ent, ent->s.origin); } else { VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096); trap_Trace(&tr, ent->s.origin, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID); if (tr.startsolid) { vec3_t temp; VectorCopy(ent->s.origin, temp); temp[2] -= ITEM_RADIUS; VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096); trap_Trace(&tr, temp, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID); } if (tr.startsolid) { G_Printf("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin)); G_FreeEntity(ent); return; } // allow to ride movers ent->s.groundEntityNum = tr.entityNum; G_SetOrigin(ent, tr.endpos); } if (ent->spawnflags & 2) // spin { ent->s.eFlags |= EF_SPINNING; } // team slaves and targeted items aren't present at start if ((ent->flags & FL_TEAMSLAVE) || ent->targetname) { ent->flags |= FL_NODRAW; //ent->s.eFlags |= EF_NODRAW; ent->r.contents = 0; return; } // health/ammo can potentially be multi-stage (multiple use) if (ent->item->giType == IT_HEALTH || ent->item->giType == IT_AMMO) { int i; // having alternate models defined in bg_misc.c for a health or ammo item specify it as "multi-stage" // - left-hand operand of comma expression has no effect // initial line: for(i=0;i<4,ent->item->world_model[i];i++) {} for (i = 0; i < 4 && ent->item->world_model[i] ; i++) { } ent->s.density = i - 1; // store number of stages in 'density' for client (most will have '1') } trap_LinkEntity(ent); }
void SP_props_me109( gentity_t *ent ) { VectorSet( ent->r.mins, -128, -128, -128 ); VectorSet( ent->r.maxs, 128, 128, 128 ); ent->clipmask = CONTENTS_SOLID; ent->r.contents = CONTENTS_SOLID; ent->r.svFlags = SVF_USE_CURRENT_ORIGIN; ent->s.eType = ET_MOVER; ent->isProp = qtrue; ent->s.modelindex = G_ModelIndex( "models/mapobjects/vehicles/m109.md3" ); if ( !ent->health ) { ent->health = 500; } ent->takedamage = qtrue; ent->die = props_me109_die; ent->pain = props_me109_pain; ent->reached = Reached_Tramcar; ent->nextthink = level.time + ( FRAMETIME / 2 ); ent->think = Think_SetupAirplaneWaypoints; ent->use = PlaneUse; if ( !( ent->speed ) ) { ent->speed = 1000; } G_SetOrigin( ent, ent->s.origin ); G_SetAngle( ent, ent->s.angles ); if ( ent->spawnflags & 4 ) { ent->s.density = 7; } trap_LinkEntity( ent ); fploop_snd = G_SoundIndex( "sound/fighterplane/fploop.wav" ); fpchoke_snd = G_SoundIndex( "sound/fighterplane/fpchoke.wav" ); fpattack_snd = G_SoundIndex( "sound/weapons/mg42/37mm.wav" ); fpexpdebris_snd = G_SoundIndex( "sound/fighterplane/fpexpdebris.wav" ); fpflyby1_snd = G_SoundIndex( "sound/fighterplane/fpflyby1.wav" ); fpflyby2_snd = G_SoundIndex( "sound/fighterplane/fpflyby2.wav" ); fpidle_snd = G_SoundIndex( "sound/fighterplane/fpidle.wav" ); fpstartup_snd = G_SoundIndex( "sound/fighterplane/fpstartup.wav" ); fuse_part = G_ModelIndex( "models/mapobjects/vehicles/m109debris_a.md3" ); wing_part = G_ModelIndex( "models/mapobjects/vehicles/m109debris_b.md3" ); tail_part = G_ModelIndex( "models/mapobjects/vehicles/m109debris_c.md3" ); nose_part = G_ModelIndex( "models/mapobjects/vehicles/m109debris_d.md3" ); crash_part = G_ModelIndex( "models/mapobjects/vehicles/m109crash.md3" ); InitPlaneSpeaker( ent ); }