Пример #1
0
/*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 );
}
Пример #2
0
/*QUAKED func_rotating (0 .5 .8) ? START_ON - X_AXIS Y_AXIS
You need to have an origin brush as part of this entity.  The center of that brush will be
the point around which it is rotated. It will rotate around the Z axis by default.  You can
check either the X_AXIS or Y_AXIS box to change that.

"model2"	.md3 model to also draw
"speed"		determines how fast it moves; default value is 100.
"dmg"		damage to inflict when blocked (2 default)
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_rotating (gentity_t *ent) {
	if ( !ent->speed ) {
		ent->speed = 100;
	}

	// set the axis of rotation
	ent->s.apos.trType = TR_LINEAR;
	if ( ent->spawnflags & 4 ) {
		ent->s.apos.trDelta[2] = ent->speed;
	} else if ( ent->spawnflags & 8 ) {
		ent->s.apos.trDelta[0] = ent->speed;
	} else {
		ent->s.apos.trDelta[1] = ent->speed;
	}

	if (!ent->damage) {
		ent->damage = 2;
	}

	trap_SetBrushModel( ent, ent->model );
	InitMover( ent );

	VectorCopy( ent->s.origin, ent->s.pos.trBase );
	VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );
	VectorCopy( ent->s.apos.trBase, ent->r.currentAngles );

	trap_LinkEntity( ent );
}
Пример #3
0
/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
Normally bobs on the Z axis
"model2"	.md3 model to also draw
"height"	amplitude of bob (32 default)
"speed"		seconds to complete a bob cycle (4 default)
"phase"		the 0.0 to 1.0 offset in the cycle to start at
"dmg"		damage to inflict when blocked (2 default)
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_bobbing (gentity_t *ent) {
	float		height;
	float		phase;

	G_SpawnFloat( "speed", "4", &ent->speed );
	G_SpawnFloat( "height", "32", &height );
	G_SpawnInt( "dmg", "2", &ent->damage );
	G_SpawnFloat( "phase", "0", &phase );

	trap_SetBrushModel( ent, ent->model );
	InitMover( ent );

	VectorCopy( ent->s.origin, ent->s.pos.trBase );
	VectorCopy( ent->s.origin, ent->r.currentOrigin );

	ent->s.pos.trDuration = ent->speed * 1000;
	ent->s.pos.trTime = ent->s.pos.trDuration * phase;
	ent->s.pos.trType = TR_SINE;

	// set the axis of bobbing
	if ( ent->spawnflags & 1 ) {
		ent->s.pos.trDelta[0] = height;
	} else if ( ent->spawnflags & 2 ) {
		ent->s.pos.trDelta[1] = height;
	} else {
		ent->s.pos.trDelta[2] = height;
	}
}
Пример #4
0
/*QUAKED func_pendulum (0 .5 .8) ?
You need to have an origin brush as part of this entity.
Pendulums always swing north / south on unrotated models.  Add an angles field to the model to allow rotation in other directions.
Pendulum frequency is a physical constant based on the length of the beam and gravity.
"model2"	.md3 model to also draw
"speed"		the number of degrees each way the pendulum swings, (30 default)
"phase"		the 0.0 to 1.0 offset in the cycle to start at
"dmg"		damage to inflict when blocked (2 default)
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_pendulum(gentity_t *ent) {
	float		freq;
	float		length;
	float		phase;
	float		speed;

	G_SpawnFloat( "speed", "30", &speed );
	G_SpawnInt( "dmg", "2", &ent->damage );
	G_SpawnFloat( "phase", "0", &phase );

	trap_SetBrushModel( ent, ent->model );

	// find pendulum length
	length = fabs( ent->r.mins[2] );
	if ( length < 8 ) {
		length = 8;
	}

	freq = 1 / ( M_PI * 2 ) * sqrt( g_gravity.value / ( 3 * length ) );

	ent->s.pos.trDuration = ( 1000 / freq );

	InitMover( ent );

	VectorCopy( ent->s.origin, ent->s.pos.trBase );
	VectorCopy( ent->s.origin, ent->r.currentOrigin );

	VectorCopy( ent->s.angles, ent->s.apos.trBase );

	ent->s.apos.trDuration = 1000 / freq;
	ent->s.apos.trTime = ent->s.apos.trDuration * phase;
	ent->s.apos.trType = TR_SINE;
	ent->s.apos.trDelta[2] = speed;
}
Пример #5
0
/*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
A train is a mover that moves between path_corner target points.
Trains MUST HAVE AN ORIGIN BRUSH.
The train spawns at the first target it is pointing at.
"model2"	.md3 model to also draw
"speed"		default 100
"dmg"		default	2
"noise"		looping sound to play when the train is in motion
"target"	next path corner
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_train (gentity_t *self) {
	VectorClear (self->s.angles);

	if (self->spawnflags & TRAIN_BLOCK_STOPS) {
		self->damage = 0;
	} else {
		if (!self->damage) {
			self->damage = 2;
		}
	}

	if ( !self->speed ) {
		self->speed = 100;
	}

	if ( !self->target ) {
		G_Printf ("func_train without a target at %s\n", vtos(self->r.absmin));
		G_FreeEntity( self );
		return;
	}

	trap_SetBrushModel( self, self->model );
	InitMover( self );

	self->reached = Reached_Train;

	// start trains on the second frame, to make sure their targets have had
	// a chance to spawn
	self->nextthink = level.time + FRAMETIME;
	self->think = Think_SetupTrainTargets;
}
Пример #6
0
/**
QUAKED func_static (0 .5 .8) ?
A bmodel that just sits there, doing nothing.  Can be used for conditional walls and models.
"model2"	.md3 model to also draw
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_static(gentity_t *ent)
{
	trap_SetBrushModel(ent, ent->model);
	InitMover(ent);
	VectorCopy(ent->s.origin, ent->s.pos.trBase);
	VectorCopy(ent->s.origin, ent->r.currentOrigin);
}
Пример #7
0
void SP_func_wall( gentity_t *ent ) {


  // Make it appear as the brush
	trap_SetBrushModel( ent, ent->model );
	ent->s.eType = ET_WALL;
	trap_LinkEntity (ent);
}
Пример #8
0
/*
=================
SP_func_fakebrush
-----------------
Jaybird
Added for fake brush compatibility with ETPro
=================
*/
void SP_func_fakebrush (gentity_t *ent)
{
	// Set the brush (will automatically set up ef_fakebmodel)
	trap_SetBrushModel( ent, ent->model );

	// Link it
	trap_LinkEntity( ent );
}
Пример #9
0
void InitTrigger( gentity_t *self ) {
	if (!VectorCompare (self->s.angles, vec3_origin))
		G_SetMovedir (self->s.angles, self->movedir);

	trap_SetBrushModel( self, self->model );
	self->r.contents = CONTENTS_TRIGGER;		// replaces the -1 from trap_SetBrushModel
	self->r.svFlags = SVF_NOCLIENT;
}
Пример #10
0
void SP_truck_cam( gentity_t *self ) {
	int mass;

	VectorClear( self->s.angles );

	if ( !self->speed ) {
		self->speed = 100;
	}

	if ( !self->target ) {
		G_Printf( "truck_cam without a target at %s\n", vtos( self->r.absmin ) );
		G_FreeEntity( self );
		return;
	}

	trap_SetBrushModel( self, self->model );

	if ( G_SpawnInt( "mass", "20", &mass ) ) {
		self->count = mass;
	} else {
		self->count = 20;
	}

	InitTramcar( self );

	self->nextthink = level.time + ( FRAMETIME / 2 );

	self->think = Think_SetupTrainTargets;

	self->touch = truck_cam_touch;

	self->s.loopSound = 0;
	self->props_frame_state = 0;

	self->clipmask = CONTENTS_SOLID;

	// G_SetOrigin (self, self->s.origin);
	// G_SetAngle (self, self->s.angles);

	self->reached = Reached_Tramcar;

	self->s.density = 6;

	//start_drive_grind_gears
	truck_sound = G_SoundIndex( "sound/vehicles/start_drive_grind_gears_01_11k.wav" );
	// truck_sound = G_SoundIndex ( "sound/vehicles/tankmove1.wav" );

	truck_idle_snd = G_SoundIndex( "sound/vehicles/truckidle.wav" );
	truck_gear1_snd = G_SoundIndex( "sound/vehicles/truckgear1.wav" );
	truck_gear2_snd = G_SoundIndex( "sound/vehicles/truckgear2.wav" );
	truck_gear3_snd = G_SoundIndex( "sound/vehicles/truckgear3.wav" );
	truck_reverse_snd = G_SoundIndex( "sound/vehicles/truckreverse.wav" );
	truck_moving_snd = G_SoundIndex( "sound/vehicles/truckmoving.wav" );
	truck_breaking_snd = G_SoundIndex( "sound/vehicles/truckbreaking.wav" );
	truck_bouncy1_snd = G_SoundIndex( "sound/vehicles/truckbouncy1.wav" );
	truck_bouncy2_snd = G_SoundIndex( "sound/vehicles/truckbouncy2.wav" );
	truck_bouncy3_snd = G_SoundIndex( "sound/vehicles/truckbouncy3.wav" );
}
Пример #11
0
/**
 * \brief Inits a trigger entity.
 *
 * Initializes trigger entities.
 *
 * @param self the trigger entity
 */
void InitTrigger( gentity_t *self ) {
	if (!VectorCompare (self->s.angles, vec3_origin))
		G_SetMovedir (self->s.angles, self->movedir);

	if(!self->tmpEntity) /* for spawnTent command */
		trap_SetBrushModel( self, self->model );
	self->r.contents = CONTENTS_TRIGGER;		/* replaces the -1 from trap_SetBrushModel */
	self->r.svFlags = SVF_NOCLIENT;
}
Пример #12
0
/*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);
}
Пример #13
0
//the same as InitTrigger
void InitBrushSensor( gentity_t *self )
{
	if ( !VectorCompare( self->s.angles, vec3_origin ) )
	{
		G_SetMovedir( self->s.angles, self->movedir );
	}

	trap_SetBrushModel( self, self->model );
	self->r.contents = CONTENTS_SENSOR; // replaces the -1 from trap_SetBrushModel
	self->r.svFlags = SVF_NOCLIENT;
	trap_LinkEntity( self );
}
Пример #14
0
void InitTrigger(gentity_t *self) {
	if (!VectorCompare(self->s.angles, vec3_origin)) {
		G_SetMovedir(self->s.angles, self->movedir);
	}

	// Nico, fix against error: SV_SetBrushModel: NULL
	if (self->model) {
		trap_SetBrushModel(self, self->model);
	}

	self->r.contents = CONTENTS_TRIGGER;        // replaces the -1 from trap_SetBrushModel
	self->r.svFlags  = SVF_NOCLIENT;
}
Пример #15
0
void SP_func_breakable( gentity_t *ent ) {
	 int health;
	 trap_SetBrushModel( ent, ent->model );
	 G_SpawnInt( "health", "0", &health );
	 if( health <= 0 )
		 health = 5;
 	 ent->health = health;
	 ent->takedamage = qtrue;
	 ent->s.eType = ET_BREAKABLE;
	 if ( ent->model2 ) {
		 ent->s.modelindex2 = G_ModelIndex( ent->model2 );
	 }
	 trap_LinkEntity (ent);
 }
Пример #16
0
/*QUAKED bot_landmine_area (0.5 0.7 0.3) ? AXIS_ONLY ALLIED_ONLY
Bots will attempt to place landmines in this area.

  "count" - number of landmines to place in this area. Defaults to 2.
  "targetname" - used only to set bot goal-state from within scripting
*/
void SP_bot_landmine_area( gentity_t *ent ) {
	char *spawnString;

	G_SpawnString( "count", "2", &spawnString );
	ent->count = atoi( spawnString );

	trap_SetBrushModel( ent, ent->model );

	ent->r.contents = 0;        // replaces the -1 from trap_SetBrushModel
	ent->r.svFlags = SVF_NOCLIENT;
	ent->s.eType = ET_LANDMINE_HINT;

	trap_LinkEntity( ent );
}
Пример #17
0
void InitTrigger(gentity_t * self)
{
	if(!VectorCompare(self->s.angles, vec3_origin))
		G_SetMovedir(self->s.angles, self->movedir);

	if(strstr(self->model, ".ase") || strstr(self->model, ".lwo") || strstr(self->model, ".prt"))
	{
		// don't set brush model
	}
	else
	{
		trap_SetBrushModel(self, self->model);
	}
	
	self->r.contents = CONTENTS_TRIGGER;	// replaces the -1 from trap_SetBrushModel
	self->r.svFlags = SVF_NOCLIENT;
}
Пример #18
0
/**
QUAKED func_button (0 .5 .8) ?
When a button is touched, it moves some distance in the direction of its angle, triggers all of its targets, waits some time, then returns to its original position where it can be triggered again.

"model2"	.md3 model to also draw
"angle"		determines the opening direction
"target"	all entities with a matching targetname will be used
"speed"		override the default 40 speed
"wait"		override the default 1 second wait (-1 = never return)
"lip"		override the default 4 pixel lip remaining at end of move
"health"	if set, the button must be killed instead of touched
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_button(gentity_t *ent)
{
	vec3_t		abs_movedir;
	float		distance;
	vec3_t		size;
	float		lip;

	ent->sound1to2 = G_SoundIndex("sound/movers/switches/butn2.wav");

	if (!ent->speed) {
		ent->speed = 40;
	}

	if (!ent->wait) {
		ent->wait = 1;
	}
	ent->wait *= 1000;

	// first position
	VectorCopy(ent->s.origin, ent->pos1);

	// calculate second position
	trap_SetBrushModel(ent, ent->model);

	G_SpawnFloat("lip", "4", &lip);

	G_SetMovedir(ent->s.angles, ent->movedir);
	abs_movedir[0] = fabs(ent->movedir[0]);
	abs_movedir[1] = fabs(ent->movedir[1]);
	abs_movedir[2] = fabs(ent->movedir[2]);
	VectorSubtract(ent->r.maxs, ent->r.mins, size);
	distance = abs_movedir[0] * size[0] + abs_movedir[1] * size[1] + abs_movedir[2] * size[2] - lip;
	VectorMA(ent->pos1, distance, ent->movedir, ent->pos2);

	if (ent->health) {
		// shootable button
		ent->takedamage = qtrue;
	} else {
		// touchable button
		ent->touch = Touch_Button;
	}

	InitMover(ent);
}
Пример #19
0
/**
QUAKED func_plat (0 .5 .8) ?
Plats are always drawn in the extended position so they will light correctly.

"lip"		default 8, protrusion above rest position
"height"	total height of movement, defaults to model height
"speed"		overrides default 200.
"dmg"		overrides default 2
"model2"	.md3 model to also draw
"color"		constantLight color
"light"		constantLight radius
*/
void SP_func_plat(gentity_t *ent)
{
	float		lip, height;

	ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/plats/pt1_strt.wav");
	ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/plats/pt1_end.wav");

	VectorClear (ent->s.angles);

	G_SpawnFloat("speed", "200", &ent->speed);
	G_SpawnInt("dmg", "2", &ent->damage);
	G_SpawnFloat("wait", "1", &ent->wait);
	G_SpawnFloat("lip", "8", &lip);

	ent->wait = 1000;

	// create second position
	trap_SetBrushModel(ent, ent->model);

	if (!G_SpawnFloat("height", "0", &height)) {
		height = (ent->r.maxs[2] - ent->r.mins[2]) - lip;
	}

	// pos1 is the rest (bottom) position, pos2 is the top
	VectorCopy(ent->s.origin, ent->pos2);
	VectorCopy(ent->pos2, ent->pos1);
	ent->pos1[2] -= height;

	InitMover(ent);

	// touch function keeps the plat from returning while
	// a live player is standing on it
	ent->touch = Touch_Plat;

	ent->blocked = Blocked_Door;

	ent->parent = ent;	// so it can be treated as a door

	// spawn the trigger if one hasn't been custom made
	if (!ent->targetname) {
		SpawnPlatTrigger(ent);
	}
}
Пример #20
0
void InitTrigger(gentity_t *self)
{
	if (!VectorCompare(self->s.angles, vec3_origin))
	{
		G_SetMovedir(self->s.angles, self->movedir);
	}

	if (self->model)
	{
		trap_SetBrushModel(self, self->model);
	}
	else
	{
		// empty models for ETPro mapscripting
		G_DPrintf("^6InitTrigger: trap_SetBrushModel(NULL) skipped for scriptName %s\n", self->scriptName);
	}

	self->r.contents = CONTENTS_TRIGGER;        // replaces the -1 from trap_SetBrushModel
	self->r.svFlags  = SVF_NOCLIENT;
}
Пример #21
0
/*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;
}
Пример #22
0
/*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER
TOGGLE		wait in both the start and end states for a trigger event.
START_OPEN	the door to moves to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
NOMONSTER	monsters will not trigger this door

"model2"	.md3 model to also draw
"angle"		determines the opening direction
"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
"speed"		movement speed (100 default)
"wait"		wait before returning (3 default, -1 = never return)
"lip"		lip remaining at end of move (8 default)
"dmg"		damage to inflict when blocked (2 default)
"color"		constantLight color
"light"		constantLight radius
"health"	if set, the door must be shot open
*/
void SP_func_door (gentity_t *ent) {
	vec3_t	abs_movedir;
	float	distance;
	vec3_t	size;
	float	lip;

	ent->sound1to2 = ent->sound2to1 = G_SoundIndex("sound/movers/doors/dr1_strt.wav");
	ent->soundPos1 = ent->soundPos2 = G_SoundIndex("sound/movers/doors/dr1_end.wav");

	ent->blocked = Blocked_Door;

	// default speed of 400
	if (!ent->speed)
		ent->speed = 400;

	// default wait of 2 seconds
	if (!ent->wait)
		ent->wait = 2;
	ent->wait *= 1000;

	// default lip of 8 units
	G_SpawnFloat( "lip", "8", &lip );

	// default damage of 2 points
	G_SpawnInt( "dmg", "2", &ent->damage );

	// first position at start
	VectorCopy( ent->s.origin, ent->pos1 );

	// calculate second position
	trap_SetBrushModel( ent, ent->model );
	G_SetMovedir (ent->s.angles, ent->movedir);
	abs_movedir[0] = fabs(ent->movedir[0]);
	abs_movedir[1] = fabs(ent->movedir[1]);
	abs_movedir[2] = fabs(ent->movedir[2]);
	VectorSubtract( ent->r.maxs, ent->r.mins, size );
	distance = DotProduct( abs_movedir, size ) - lip;
	VectorMA( ent->pos1, distance, ent->movedir, ent->pos2 );

	// if "start_open", reverse position 1 and 2
	if ( ent->spawnflags & 1 ) {
		vec3_t	temp;

		VectorCopy( ent->pos2, temp );
		VectorCopy( ent->s.origin, ent->pos2 );
		VectorCopy( temp, ent->pos1 );
	}

	InitMover( ent );

	ent->nextthink = level.time + FRAMETIME;

	if ( ! (ent->flags & FL_TEAMSLAVE ) ) {
		int health;

		G_SpawnInt( "health", "0", &health );
		if ( health ) {
			ent->takedamage = qtrue;
		}
		if ( ent->targetname || health ) {
			// non touch/shoot doors
			ent->think = Think_MatchTeam;
		} else {
			ent->think = Think_SpawnNewDoorTrigger;
		}
	}


}
Пример #23
0
/*QUAKED func_tramcar (0 .5 .8) ? START_ON TOGGLE - LEADER
health value of 999 will designate the piece as non damageable

The leader of the tramcar group must have the leader flag set or
you'll end up with co-planer poly heaven. When the health of the Leader
of the team hits zero it will unlink and the team will become visible

A tramcar is a mover that moves between path_corner target points.
all tramcar parts MUST HAVE AN ORIGIN BRUSH. (this is true for all parts)

The tramcar spawns at the first target it is pointing at.

If you are going to have enemies ride the tramcar it must be placed in its ending
position when you bsp the map you can the start it by targeting the desired path_corner

"model2"	.md3 model to also draw
"speed"		default 100
"dmg"		default	2
"noise"		looping sound to play when the train is in motion
"target"	next path corner
"color"		constantLight color
"light"		constantLight radius

"type" type of debris ("glass", "wood", "metal", "gibs") default is "wood"
"mass" defaults to 75.  This determines how much debris is emitted when it explodes.  You get one large chunk per 100 of mass (up to 8) and one small chunk per 25 of mass (up to 16).  So 800 gives the most.
*/
void SP_func_tramcar( gentity_t *self ) {

	int mass;
	char    *type;
	char    *s;
	char buffer[MAX_QPATH];

	VectorClear( self->s.angles );

	//if (self->spawnflags & TRAMCAR_BLOCK_STOPS) {
	//	self->damage = 0;
	//	self->s.eFlags |= EF_MOVER_STOP;
	//}
	//else {
	if ( !self->damage ) {
		self->damage = 100;
	}
	//}

	if ( !self->speed ) {
		self->speed = 100;
	}

	if ( !self->target ) {
		G_Printf( "func_tramcar without a target at %s\n", vtos( self->r.absmin ) );
		G_FreeEntity( self );
		return;
	}

	if ( self->spawnflags & TRAMCAR_LEADER ) {
		if ( !self->health ) {
			self->health = 50;
		}

		self->takedamage = qtrue;
		self->die = Tramcar_die;

		if ( self->health < 999 ) {
			self->isProp = qtrue;
		}
	}

	trap_SetBrushModel( self, self->model );

	if ( G_SpawnInt( "mass", "75", &mass ) ) {
		self->count = mass;
	} else {
		self->count = 75;
	}

	G_SpawnString( "type", "wood", &type );
	if ( !Q_stricmp( type,"wood" ) ) {
		self->key = 0;
	} else if ( !Q_stricmp( type,"glass" ) )   {
		self->key = 1;
	} else if ( !Q_stricmp( type,"metal" ) )                                                            {
		self->key = 2;
	} else if ( !Q_stricmp( type,"gibs" ) )                                                                                                                     {
		self->key = 3;
	}

	if ( G_SpawnString( "noise", "NOSOUND", &s ) ) {
		if ( Q_stricmp( s, "nosound" ) ) {
			Q_strncpyz( buffer, s, sizeof( buffer ) );
			self->s.dl_intensity = G_SoundIndex( buffer );
		}
	} else {
		switch ( self->key )
		{
		case 0:     // "wood"
			self->s.dl_intensity = G_SoundIndex( "sound/world/boardbreak.wav" );
			break;
		case 1:     // "glass"
			self->s.dl_intensity = G_SoundIndex( "sound/world/glassbreak.wav" );
			break;
		case 2:     // "metal"
			self->s.dl_intensity = G_SoundIndex( "sound/world/metalbreak.wav" );
			break;
		case 3:     // "gibs"
			self->s.dl_intensity = G_SoundIndex( "sound/player/gibsplit1.wav" );
			break;
		}
	}

	self->s.density = self->count;  // pass the "mass" to the client

	InitTramcar( self );

	self->reached = Reached_Tramcar;

	self->nextthink = level.time + ( FRAMETIME / 2 );

	self->think = Think_SetupTrainTargets;

	self->blocked = Blocked_Tramcar;

	if ( self->spawnflags & TRAMCAR_TOGGLE ) {
		self->use = TramCarUse;
	}

}