Added CL_ShutdownLocal() in cl_main.c.

Changed func_door_secret in missionpack DLL to have the correct die function (door_secret_die) if health is set.
Moved misc, model_*, and target entity code to new source files g_misc_laz.c, g_misc_nm.c, g_model.c, and g_target_laz.c in missionpack DLL.
This commit is contained in:
Knightmare66 2021-02-21 21:01:45 -05:00
parent c9e3575516
commit bcf678286b
19 changed files with 5037 additions and 4890 deletions

View file

@ -2236,6 +2236,90 @@ void CL_InitLocal (void)
}
/*
=================
CL_ShutdownLocal
=================
*/
void CL_ShutdownLocal (void)
{
if (!local_initialized)
return;
Cmd_RemoveCommand ("cmd");
Cmd_RemoveCommand ("pause");
Cmd_RemoveCommand ("pingservers");
Cmd_RemoveCommand ("skins");
Cmd_RemoveCommand ("userinfo");
Cmd_RemoveCommand ("snd_restart");
Cmd_RemoveCommand ("changing");
Cmd_RemoveCommand ("disconnect");
Cmd_RemoveCommand ("record");
Cmd_RemoveCommand ("stop");
Cmd_RemoveCommand ("quit");
Cmd_RemoveCommand ("connect");
Cmd_RemoveCommand ("reconnect");
Cmd_RemoveCommand ("rcon");
// Cmd_RemoveCommand ("packet"); // this is dangerous to leave in
Cmd_RemoveCommand ("setenv");
Cmd_RemoveCommand ("precache");
Cmd_RemoveCommand ("download");
Cmd_RemoveCommand ("writeconfig");
Cmd_RemoveCommand ("aacskey");
// Chat Ignore from R1Q2/Q2Pro
Cmd_RemoveCommand ("ignorenick");
Cmd_RemoveCommand ("unignorenick");
Cmd_RemoveCommand ("ignoretext");
Cmd_RemoveCommand ("unignoretext");
// end R1Q2/Q2Pro Chat Ignore
#ifdef LOC_SUPPORT // Xile/NiceAss LOC
Cmd_RemoveCommand ("loc_add");
Cmd_RemoveCommand ("loc_del");
Cmd_RemoveCommand ("loc_save");
Cmd_RemoveCommand ("loc_help");
#endif // LOC_SUPPORT
Cmd_RemoveCommand ("wave");
Cmd_RemoveCommand ("inven");
Cmd_RemoveCommand ("kill");
Cmd_RemoveCommand ("use");
Cmd_RemoveCommand ("drop");
Cmd_RemoveCommand ("say");
Cmd_RemoveCommand ("say_team");
Cmd_RemoveCommand ("info");
Cmd_RemoveCommand ("prog");
Cmd_RemoveCommand ("give");
Cmd_RemoveCommand ("god");
Cmd_RemoveCommand ("notarget");
Cmd_RemoveCommand ("noclip");
Cmd_RemoveCommand ("invuse");
Cmd_RemoveCommand ("invprev");
Cmd_RemoveCommand ("invnext");
Cmd_RemoveCommand ("invdrop");
Cmd_RemoveCommand ("weapnext");
Cmd_RemoveCommand ("weapprev");
// Chat Ignore from R1Q2/Q2Pro
CL_RemoveAllChatIgnores (&cl_chatNickIgnores);
CL_RemoveAllChatIgnores (&cl_chatTextIgnores);
// end R1Q2/Q2Pro Chat Ignore
local_initialized = false;
}
/*
===============
@ -2896,6 +2980,7 @@ void CL_Shutdown (void)
sec = Sys_Milliseconds();
// end delay
CL_ShutdownLocal (); // added Local shutdown
IN_Shutdown ();
VID_Shutdown();

View file

@ -3499,6 +3499,7 @@ void train_move_children (edict_t *self)
{
VectorAdd (ent->s.angles, ent->org_angles, angles);
G_SetMovedir (angles, ent->movedir);
// Knightmare- these entities need special calculations
if (!strcmp(ent->classname, "monster_turret") || !strcmp(ent->classname, "turret_wall"))
// if ( (ent->class_id == ENTITY_MONSTER_TURRET) || (ent->class_id == ENTITY_TURRET_WALL) )
@ -3776,7 +3777,7 @@ void train_remove_children (edict_t *self)
if (!ent->inuse)
return;
if (!strcmp(ent->movewith, self->targetname))
{ //recursively remove each child's children
{ // recursively remove each child's children
train_remove_children (ent);
G_FreeEdict(ent);
}
@ -4263,7 +4264,7 @@ void train_rotate (edict_t *self)
//gi.bprintf (PRINT_HIGH, "train cy: %i iy: %i ys: %i\n", cur_yaw, idl_yaw, ys);
train_speed = VectorLength (self->enemy->velocity);
if (train_speed == 0) //Don't rotate if we're stopped
if (train_speed == 0) // Don't rotate if we're stopped
VectorClear (self->enemy->avelocity);
self->nextthink = level.time + FRAMETIME;
@ -4362,7 +4363,7 @@ again:
// Set speed before train_next is called
// Knightmare- this is only used for Rogue maps
// train speed changes are handled differently
if ( (ent->speed) && (level.maptype == MAPTYPE_ROGUE))
if ( (ent->speed) && (level.maptype == MAPTYPE_ROGUE) )
{
self->speed = ent->speed;
self->moveinfo.speed = ent->speed;
@ -4422,9 +4423,9 @@ again:
// Rroff rotating
if (self->spawnflags & TRAIN_ROTATE && !(ent->spawnflags & 2))
{
// VectorSubtract (ent->s.origin, self->s.origin, v);
// self->ideal_yaw = vectoyaw(v);
// self->ideal_pitch = vectopitch(v);
// VectorSubtract (ent->s.origin, self->s.origin, v);
// self->ideal_yaw = vectoyaw(v);
// self->ideal_pitch = vectopitch(v);
if (self->spawnflags & TRAIN_ORIGIN) { // Knightmare- func_train_origin support
VectorSubtract(ent->s.origin, self->s.origin, v);
}
@ -4512,8 +4513,8 @@ void train_resume (edict_t *self)
if (self->spawnflags & TRAIN_ROT_CONST)
{
self->avelocity[0] = self->pitch_speed;
self->avelocity[1] = self->yaw_speed;
self->avelocity[2] = self->roll_speed;
self->avelocity[1] = self->yaw_speed;
self->avelocity[2] = self->roll_speed;
}
}
@ -5201,9 +5202,10 @@ void door_secret_done (edict_t *self)
{
if (!(self->targetname) || (self->spawnflags & SECRET_ALWAYS_SHOOT))
{
// Knightmare- setting health to anything other than 0
// makes the die function never get called!
self->health = 0;
// Knightmare- restore user-set health here
// now that the correct die function is set
// self->health = 0;
self->health = self->max_health;
self->takedamage = DAMAGE_YES;
}
self->moveinfo.state = STATE_LOWEST; // Knightmare added
@ -5246,7 +5248,6 @@ void door_secret_blocked (edict_t *self, edict_t *other)
void door_secret_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
// gi.dprintf("door_secret_die\n");
self->takedamage = DAMAGE_NO;
door_secret_use (self, attacker, attacker);
}
@ -5259,15 +5260,15 @@ void SP_func_door_secret (edict_t *ent)
if ( (level.maptype == MAPTYPE_CUSTOM) && (ent->sounds > 4) && (ent->sounds < 100) ) // custom sounds
{
ent->moveinfo.sound_start = gi.soundindex (va("doors/dr%02i_strt.wav", ent->sounds));
ent->moveinfo.sound_middle = gi.soundindex (va("doors/dr%02i_mid.wav", ent->sounds));
ent->moveinfo.sound_end = gi.soundindex (va("doors/dr%02i_end.wav", ent->sounds));
ent->moveinfo.sound_start = gi.soundindex (va("doors/dr%02i_strt.wav", ent->sounds));
ent->moveinfo.sound_middle = gi.soundindex (va("doors/dr%02i_mid.wav", ent->sounds));
ent->moveinfo.sound_end = gi.soundindex (va("doors/dr%02i_end.wav", ent->sounds));
}
else if (ent->sounds != 1)
{
ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
}
else
{
@ -5289,9 +5290,12 @@ void SP_func_door_secret (edict_t *ent)
if (!(ent->targetname) || (ent->spawnflags & SECRET_ALWAYS_SHOOT))
{
// Knightmare- setting health to anything other than 0
// makes the die function never get called!
ent->health = 0;
// Knightmare- we can allow user-set health here
// now that the correct die function is set
// ent->health = 0;
if (!ent->health)
ent->health = 1;
ent->max_health = ent->health;
ent->takedamage = DAMAGE_YES;
ent->die = door_secret_die;
}
@ -5336,7 +5340,8 @@ void SP_func_door_secret (edict_t *ent)
if (ent->health)
{
ent->takedamage = DAMAGE_YES;
ent->die = door_killed;
// ent->die = door_killed;
ent->die = door_secret_die; // Knightmare- this had the wrong die function set!
ent->max_health = ent->health;
}
else if (ent->targetname && ent->message)
@ -6009,7 +6014,7 @@ void swinging_door_killed (edict_t *self, edict_t *inflictor, edict_t *attacker,
ent->nextthink = level.time + ent->moveinfo.wait;
return;
}
check_reverse_rotation(ent,point);
check_reverse_rotation (ent, point);
if (!(ent->flags & FL_TEAMSLAVE))
{
if (ent->moveinfo.sound_start)

View file

@ -1859,6 +1859,65 @@
{"thing_think", (byte *)thing_think},
{"thing_restore_leader", (byte *)thing_restore_leader},
{"SpawnThing", (byte *)SpawnThing},
{"SP_target_locator", (byte *)SP_target_locator},
{"target_locator_init", (byte *)target_locator_init},
{"SP_target_failure", (byte *)SP_target_failure},
{"use_target_failure", (byte *)use_target_failure},
{"target_failure_fade_lights", (byte *)target_failure_fade_lights},
{"target_failure_think", (byte *)target_failure_think},
{"target_failure_player_die", (byte *)target_failure_player_die},
{"target_failure_wipe", (byte *)target_failure_wipe},
{"SP_target_animation", (byte *)SP_target_animation},
{"target_animation_use", (byte *)target_animation_use},
{"target_animate", (byte *)target_animate},
{"SP_target_monitor", (byte *)SP_target_monitor},
{"use_target_monitor", (byte *)use_target_monitor},
{"target_monitor_move", (byte *)target_monitor_move},
{"target_monitor_off", (byte *)target_monitor_off},
{"SP_target_attractor", (byte *)SP_target_attractor},
{"use_target_attractor", (byte *)use_target_attractor},
{"target_attractor_think", (byte *)target_attractor_think},
{"target_attractor_think_single", (byte *)target_attractor_think_single},
{"SP_target_clone", (byte *)SP_target_clone},
{"target_clone_use", (byte *)target_clone_use},
{"clone", (byte *)clone},
{"SP_target_rocks", (byte *)SP_target_rocks},
{"target_rocks_use", (byte *)target_rocks_use},
{"ThrowRock", (byte *)ThrowRock},
{"SP_target_fade", (byte *)SP_target_fade},
{"use_target_fade", (byte *)use_target_fade},
{"SP_target_sky", (byte *)SP_target_sky},
{"target_sky_use", (byte *)target_sky_use},
{"SP_target_skill", (byte *)SP_target_skill},
{"use_target_skill", (byte *)use_target_skill},
{"SP_target_cd", (byte *)SP_target_cd},
{"target_cd_use", (byte *)target_cd_use},
{"SP_target_rotation", (byte *)SP_target_rotation},
{"target_rotation_use", (byte *)target_rotation_use},
{"SP_target_change", (byte *)SP_target_change},
{"target_change_use", (byte *)target_change_use},
{"SP_target_movewith", (byte *)SP_target_movewith},
{"target_movewith_use", (byte *)target_movewith_use},
{"SP_target_effect", (byte *)SP_target_effect},
{"target_effect_think", (byte *)target_effect_think},
{"target_effect_use", (byte *)target_effect_use},
{"target_effect_widowbeam", (byte *)target_effect_widowbeam},
{"target_effect_tunnel_sparks", (byte *)target_effect_tunnel_sparks},
{"target_effect_explosion", (byte *)target_effect_explosion},
{"target_effect_sparks", (byte *)target_effect_sparks},
{"target_effect_lightning", (byte *)target_effect_lightning},
{"target_effect_trail", (byte *)target_effect_trail},
{"target_effect_splash", (byte *)target_effect_splash},
{"target_effect_steam", (byte *)target_effect_steam},
{"target_effect_at", (byte *)target_effect_at},
{"SP_target_global_text", (byte *)SP_target_global_text},
{"target_global_text_use", (byte *)target_global_text_use},
{"SP_target_set_effect", (byte *)SP_target_set_effect},
{"target_set_effect_use", (byte *)target_set_effect_use},
{"SP_target_command", (byte *)SP_target_command},
{"target_command_use", (byte *)target_command_use},
{"SP_target_monsterbattle", (byte *)SP_target_monsterbattle},
{"use_target_monsterbattle", (byte *)use_target_monsterbattle},
{"SP_target_earthquake", (byte *)SP_target_earthquake},
{"target_earthquake_use", (byte *)target_earthquake_use},
{"target_earthquake_think", (byte *)target_earthquake_think},
@ -2111,71 +2170,12 @@
{"trigger_teleport_use", (byte *)trigger_teleport_use},
{"trigger_teleport_touch", (byte *)trigger_teleport_touch},
{"SP_info_teleport_destination", (byte *)SP_info_teleport_destination},
{"SP_target_locator", (byte *)SP_target_locator},
{"target_locator_init", (byte *)target_locator_init},
{"SP_target_failure", (byte *)SP_target_failure},
{"use_target_failure", (byte *)use_target_failure},
{"target_failure_fade_lights", (byte *)target_failure_fade_lights},
{"target_failure_think", (byte *)target_failure_think},
{"target_failure_player_die", (byte *)target_failure_player_die},
{"target_failure_wipe", (byte *)target_failure_wipe},
{"SP_target_animation", (byte *)SP_target_animation},
{"target_animation_use", (byte *)target_animation_use},
{"target_animate", (byte *)target_animate},
{"SP_target_monitor", (byte *)SP_target_monitor},
{"use_target_monitor", (byte *)use_target_monitor},
{"target_monitor_move", (byte *)target_monitor_move},
{"target_monitor_off", (byte *)target_monitor_off},
{"SP_target_attractor", (byte *)SP_target_attractor},
{"use_target_attractor", (byte *)use_target_attractor},
{"target_attractor_think", (byte *)target_attractor_think},
{"target_attractor_think_single", (byte *)target_attractor_think_single},
{"SP_target_clone", (byte *)SP_target_clone},
{"target_clone_use", (byte *)target_clone_use},
{"clone", (byte *)clone},
{"SP_target_rocks", (byte *)SP_target_rocks},
{"target_rocks_use", (byte *)target_rocks_use},
{"ThrowRock", (byte *)ThrowRock},
{"SP_target_fade", (byte *)SP_target_fade},
{"use_target_fade", (byte *)use_target_fade},
{"SP_target_sky", (byte *)SP_target_sky},
{"target_sky_use", (byte *)target_sky_use},
{"SP_target_skill", (byte *)SP_target_skill},
{"use_target_skill", (byte *)use_target_skill},
{"SP_target_cd", (byte *)SP_target_cd},
{"target_cd_use", (byte *)target_cd_use},
{"SP_target_rotation", (byte *)SP_target_rotation},
{"target_rotation_use", (byte *)target_rotation_use},
{"SP_target_change", (byte *)SP_target_change},
{"target_change_use", (byte *)target_change_use},
{"SP_target_movewith", (byte *)SP_target_movewith},
{"target_movewith_use", (byte *)target_movewith_use},
{"SP_target_effect", (byte *)SP_target_effect},
{"target_effect_think", (byte *)target_effect_think},
{"target_effect_use", (byte *)target_effect_use},
{"target_effect_widowbeam", (byte *)target_effect_widowbeam},
{"target_effect_tunnel_sparks", (byte *)target_effect_tunnel_sparks},
{"target_effect_explosion", (byte *)target_effect_explosion},
{"target_effect_sparks", (byte *)target_effect_sparks},
{"target_effect_lightning", (byte *)target_effect_lightning},
{"target_effect_trail", (byte *)target_effect_trail},
{"target_effect_splash", (byte *)target_effect_splash},
{"target_effect_steam", (byte *)target_effect_steam},
{"target_effect_at", (byte *)target_effect_at},
{"SP_target_global_text", (byte *)SP_target_global_text},
{"target_global_text_use", (byte *)target_global_text_use},
{"SP_target_set_effect", (byte *)SP_target_set_effect},
{"target_set_effect_use", (byte *)target_set_effect_use},
{"SP_target_command", (byte *)SP_target_command},
{"target_command_use", (byte *)target_command_use},
{"SP_target_orb", (byte *)SP_target_orb},
{"orb_think", (byte *)orb_think},
{"SP_target_blacklight", (byte *)SP_target_blacklight},
{"blacklight_think", (byte *)blacklight_think},
{"SP_target_killplayers", (byte *)SP_target_killplayers},
{"target_killplayers_use", (byte *)target_killplayers_use},
{"SP_target_monsterbattle", (byte *)SP_target_monsterbattle},
{"use_target_monsterbattle", (byte *)use_target_monsterbattle},
{"SP_target_anger", (byte *)SP_target_anger},
{"target_anger_use", (byte *)target_anger_use},
{"SP_target_steam", (byte *)SP_target_steam},
@ -2292,6 +2292,13 @@
{"M_SetDeath", (byte *)M_SetDeath},
{"FadeDieSink", (byte *)FadeDieSink},
{"FadeSink", (byte *)FadeSink},
{"SP_model_train_origin", (byte *)SP_model_train_origin},
{"SP_model_train", (byte *)SP_model_train},
{"model_train_animator", (byte *)model_train_animator},
{"SP_model_spawn", (byte *)SP_model_spawn},
{"model_die", (byte *)model_die},
{"model_spawn_use", (byte *)model_spawn_use},
{"modelspawn_think", (byte *)modelspawn_think},
{"SP_misc_q1_fireball", (byte *)SP_misc_q1_fireball},
{"q1_fireball_fly", (byte *)q1_fireball_fly},
{"q1_fireball_touch", (byte *)q1_fireball_touch},
@ -2314,6 +2321,14 @@
{"bubble_touch", (byte *)bubble_touch},
{"SP_misc_q1_zombie_crucified", (byte *)SP_misc_q1_zombie_crucified},
{"misc_zombie_crucified_think", (byte *)misc_zombie_crucified_think},
{"SP_monster_coco_monkey", (byte *)SP_monster_coco_monkey},
{"monster_coco_monkey_think", (byte *)monster_coco_monkey_think},
{"SP_light_flame2s", (byte *)SP_light_flame2s},
{"SP_light_flame2", (byte *)SP_light_flame2},
{"SP_light_flame1s", (byte *)SP_light_flame1s},
{"SP_light_flame1", (byte *)SP_light_flame1},
{"light_flame_spawn", (byte *)light_flame_spawn},
{"light_flame_use", (byte *)light_flame_use},
{"PatchDeadSoldier", (byte *)PatchDeadSoldier},
{"SP_target_fountain", (byte *)SP_target_fountain},
{"target_fountain_delayed_use", (byte *)target_fountain_delayed_use},
@ -2332,14 +2347,6 @@
{"SP_misc_light", (byte *)SP_misc_light},
{"misc_light_use", (byte *)misc_light_use},
{"misc_light_think", (byte *)misc_light_think},
{"SP_monster_coco_monkey", (byte *)SP_monster_coco_monkey},
{"monster_coco_monkey_think", (byte *)monster_coco_monkey_think},
{"SP_light_flame2s", (byte *)SP_light_flame2s},
{"SP_light_flame2", (byte *)SP_light_flame2},
{"SP_light_flame1s", (byte *)SP_light_flame1s},
{"SP_light_flame1", (byte *)SP_light_flame1},
{"light_flame_spawn", (byte *)light_flame_spawn},
{"light_flame_use", (byte *)light_flame_use},
{"SP_misc_gekk_writhe", (byte *)SP_misc_gekk_writhe},
{"misc_gekk_writhe_use", (byte *)misc_gekk_writhe_use},
{"misc_gekk_writhe_think", (byte *)misc_gekk_writhe_think},
@ -2488,13 +2495,6 @@
{"VelocityForDamage", (byte *)VelocityForDamage},
{"SP_func_areaportal", (byte *)SP_func_areaportal},
{"Use_Areaportal", (byte *)Use_Areaportal},
{"SP_model_train_origin", (byte *)SP_model_train_origin},
{"SP_model_train", (byte *)SP_model_train},
{"model_train_animator", (byte *)model_train_animator},
{"SP_model_spawn", (byte *)SP_model_spawn},
{"model_die", (byte *)model_die},
{"model_spawn_use", (byte *)model_spawn_use},
{"modelspawn_think", (byte *)modelspawn_think},
{"Cmd_Trigger_f", (byte *)Cmd_Trigger_f},
{"SP_light_flame", (byte *)SP_light_flame},
{"bigflame_think", (byte *)bigflame_think},

View file

@ -176,563 +176,3 @@ void Cmd_Trigger_f (edict_t *ent)
break;
}
}
/*
=============================
Spawning a user defined model
=============================
*/
//ed - added all these spawnflags and stuff
/*QUAKED model_spawn (1 0 0) (-8 -8 -8) (8 8 8) x TOGGLE NOT_IR PLAYER NO_MODEL ANIM_ONCE
Spawns a user defined model, you can specify whether its solid, if so how big the box is, and apply nearly
any effect to the entity.
Spawnflags:
TOGGLE Start active, when triggered become inactive
NOT_IR The model won't be tinted red when the player has IR goggles on
PLAYER Set this if you want to use a player model
NO_MODEL Don't use a model. Usefull for placing particle effects and dynamic lights on their own
ANIM__ONCE Only play the animation once
-----------------------
Key/Value pairs:
"style" Specifies the animation type to use.
0: None (unless startframe and framenumbers are used)
1: ANIM01 - cycle between frames 0 and 1 at 2 hz
2: ANIM23 - cycle between frames 2 and 3 at 2 hz
3: ANIM_ALL - cycle through all frames at 2 hz
4: ANIM_ALLFAST - cycle through all frames at 10 hz
Note: The animation flags override startframe and framenumbers settings you may have enterered. ANIM_ALL and ANIM_ALLFAST don't do what you might think - rather than setting a framerate, these apparently cause the model to cycle through its ENTIRE sequence of animations in 0.5 or 0.1 seconds... which for monster and player models is of course not possible. Looks exceptionally goofy.
"usermodel" The model to load (models/ is already coded)
"startframe" The starting frame : default 0
"framenumbers" The number of frames you want to display after startframe
"skinnum" The skin number to use, default 0
"health" If non-zero and solidstate is 3 or 4 (solid), the entity will be shootable. When destroyed, it blows up with a no-damage explosion.
"solidstate"
1 - not solid at all. These models do not obey any sort of physics. If you place them up in the air or embedded in a wall they will stay there and be perfectly happy about it.
2 - solid. These models will "droptofloor" when spawned. If the health value is set they may be damaged.
3 - solid. Same as above but not affected by gravity. Model will remain in the same location.
4 - not solid but affected by gravity. Model will "droptofloor" when spawned.
NOTE : if you want the model to be solid then you must enter vector values into the following fields :
"bleft" = the point that is at the bottom left of the models bounding box in a model editor
"tright" = the point that is at the top left of the models bounding box in a model editor
"effects"
1: ROTATE Rotate like a weapon
2: GIB
8: BLASTER Yellowish orange glow plus particles
16: ROCKET Rocket trail
32: GRENADE Grenade trail
64: HYPERBLASTER BLASTER w/o the particles
128: BFG Big green ball
256: COLOR_SHELL
512: POWERSCREEN Green power shield
16384: FLIES Ewwww
32768: QUAD Blue shell
65536: PENT Red shell
131072: TELEPORTER Teleporter particles
262144: FLAG1 Red glow
524288: FLAG2 Blue glow
1048576: IONRIPPER
2097152: GREENGIB
4194304: BLUE_HB Blue hyperblaster glow
8388608: SPINNING_LIGHTS Red spinning lights
16777216: PLASMA
33554432: TRAP
67108864: TRACKER
134217728: DOUBLE Yellow shell
268435456: SPHERETRANS Transparent
536870912: TAGTRAIL
1073741824: HALF_DAMAGE
2147483648: TRACKER_TRAIL
"renderfx"
1: MINLIGHT Never completely dark
2: VIEWERMODEL
4: WEAPONMODEL
8: FULLBRIGHT
16: DEPTHHACK
32: TRANSLUCENT Transparent
64: FRAMELERP
128: BEAM
512: GLOW Pulsating glow of normal Q2 pickup items
1024: SHELL_RED
2048: SHELL_GREEN
4096: SHELL_BLUE
32768: IR_VISIBLE
65536: SHELL_DOUBLE
131072: SHELL_HALF_DAMAGE White shell
262144: USE_DISGUISE
"movewith" Targetname of the entity to move with
*/
#define TOGGLE 2
#define NOT_IR 4
#define PLAYER_MODEL 8
#define NO_MODEL 16
#define ANIM_ONCE 32
void model_spawn_use (edict_t *self, edict_t *other, edict_t *activator);
void modelspawn_think (edict_t *self)
{
self->s.frame++;
if (self->s.frame >= self->framenumbers)
{
self->s.frame = self->startframe;
if (self->spawnflags & ANIM_ONCE)
{
model_spawn_use(self,world,world);
return;
}
}
self->nextthink = level.time + FRAMETIME;
gi.linkentity(self);
if (!strcmp(self->classname, "model_train"))
train_move_children (self);
}
void model_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->delay) // we started off
{
self->svflags &= ~SVF_NOCLIENT;
self->delay = 0;
if (self->framenumbers > 1)
{
self->think = modelspawn_think;
self->nextthink = level.time + FRAMETIME;
}
self->s.sound = self->noise_index;
#ifdef LOOP_SOUND_ATTENUATION
self->s.attenuation = self->attenuation;
#endif
}
else // we started active
{
self->svflags |= SVF_NOCLIENT;
self->delay = 1;
self->use = model_spawn_use;
self->think = NULL;
self->nextthink = 0;
self->s.sound = 0;
}
}
void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
if (self->deathtarget)
{
self->target = self->deathtarget;
G_UseTargets (self, attacker);
}
train_kill_children(self);
BecomeExplosion1(self);
}
#define ANIM_MASK (EF_ANIM01|EF_ANIM23|EF_ANIM_ALL|EF_ANIM_ALLFAST)
void SP_model_spawn (edict_t *ent)
{
char modelname[256];
// paranoia check
if ((!ent->usermodel) && (!ent->spawnflags & NO_MODEL) && !(ent->spawnflags & PLAYER_MODEL))
{
gi.dprintf("%s without a model and without NO_MODEL spawnflag at %s\n", ent->classname, vtos(ent->s.origin));
G_FreeEdict(ent);
return;
}
ent->class_id = ENTITY_MODEL_SPAWN;
switch (ent->solidstate)
{
case 1 : ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_NONE; break;
case 2 : ent->solid = SOLID_BBOX; ent->movetype = MOVETYPE_TOSS; break;
case 3 : ent->solid = SOLID_BBOX; ent->movetype = MOVETYPE_NONE; break;
case 4 : ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_TOSS; break;
default: ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_NONE; break;
}
if (ent->solid != SOLID_NOT )
{
if (ent->health > 0)
{
ent->die = model_die;
ent->takedamage = DAMAGE_YES;
}
}
switch (ent->style)
{
case 1 : ent->s.effects |= EF_ANIM01; break;
case 2 : ent->s.effects |= EF_ANIM23; break;
case 3 : ent->s.effects |= EF_ANIM_ALL; break;
case 4 : ent->s.effects |= EF_ANIM_ALLFAST; break;
}
// DWH: Rather than use one value (renderfx) we use the
// actual values for effects and renderfx. All may
// be combined.
ent->s.effects |= ent->effects;
ent->s.renderfx |= ent->renderfx;
if (ent->startframe < 0)
ent->startframe = 0;
if (!ent->framenumbers)
ent->framenumbers = 1;
// Change framenumbers to last frame to play
ent->framenumbers += ent->startframe;
if (!VectorLength(ent->bleft) && ent->solid == SOLID_BBOX)
{
gi.dprintf("%s solid with no bleft vector at %s, using default (-16,-16,-16)\n", ent->classname, vtos(ent->s.origin));
VectorSet(ent->bleft, -16, -16, -16);
}
VectorCopy (ent->bleft, ent->mins);
if (!VectorLength(ent->tright) && ent->solid == SOLID_BBOX)
{
gi.dprintf("%s solid with no tright vector at %, using default (16,16,16)\n", ent->classname, vtos(ent->s.origin));
VectorSet(ent->tright, 16, 16, 16);
}
VectorCopy (ent->tright, ent->maxs);
if (ent->solid != SOLID_NOT)
ent->clipmask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER;
if (ent->spawnflags & NO_MODEL)
{ // For rendering effects to work, we MUST use a model
ent->s.modelindex = gi.modelindex ("sprites/point.sp2");
ent->movetype = MOVETYPE_NOCLIP;
}
else
{
if (ent->spawnflags & PLAYER_MODEL)
{
if (!ent->usermodel || !strlen(ent->usermodel))
ent->s.modelindex = MAX_MODELS-1; //was 255
else
{
if (strstr(ent->usermodel,"tris.md2"))
Com_sprintf(modelname, sizeof(modelname), "players/%s", ent->usermodel);
else
Com_sprintf(modelname, sizeof(modelname), "players/%s/tris.md2", ent->usermodel);
ent->s.modelindex = gi.modelindex(modelname);
}
}
else
{
if (strstr(ent->usermodel,".sp2")) {
// Knightmare- check for "sprites/" already in path
if ( !strncmp(ent->usermodel, "sprites/", 8) )
Com_sprintf(modelname, sizeof(modelname), "%s", ent->usermodel);
else
Com_sprintf(modelname, sizeof(modelname), "sprites/%s", ent->usermodel);
}
else {
// Knightmare- check for "models/" already in path
if ( !strncmp(ent->usermodel, "models/", 7) )
Com_sprintf(modelname, sizeof(modelname), "%s", ent->usermodel);
else
Com_sprintf(modelname, sizeof(modelname), "models/%s", ent->usermodel);
}
ent->s.modelindex = gi.modelindex (modelname);
}
if (ent->startframe < 0)
{
gi.dprintf("model_spawn with startframe less than 0 at %s\n", vtos(ent->s.origin));
ent->startframe = 0;
}
ent->s.frame = ent->startframe;
}
if (st.noise)
ent->noise_index = gi.soundindex (st.noise);
//ent->s.sound = ent->noise_index;
#ifdef LOOP_SOUND_ATTENUATION
ent->s.attenuation = ent->attenuation;
#endif
if (ent->skinnum) // Knightmare- selectable skin
ent->s.skinnum = ent->skinnum;
if (ent->spawnflags & ANIM_ONCE)
ent->spawnflags |= TOGGLE;
if (ent->spawnflags & TOGGLE)
{ // Knightmare- allow starting off (but not for model_train)
if ( (strcmp(ent->classname, "model_train") != 0) && (ent->delay != 0) ) {
ent->delay = 1;
ent->svflags |= SVF_NOCLIENT;
}
else {
ent->delay = 0;
}
ent->use = model_spawn_use;
}
if (!(ent->s.effects & ANIM_MASK) && (ent->framenumbers > 1))
{
ent->think = modelspawn_think;
ent->nextthink = level.time + 2*FRAMETIME;
}
if (ent->spawnflags & NOT_IR)
ent->s.renderfx &= ~RF_IR_VISIBLE;
else
ent->s.renderfx |= RF_IR_VISIBLE;
gi.linkentity (ent);
}
/*QUAKED model_train (1 0 0) (-8 -8 -8) (8 8 8) START_ON TOGGLE BLOCK_STOPS PLAYER NO_MODEL ROTATE ROT_CONST SMOOTH
A moving model. The "team" key allows you to team train entities together.
Spawnflags:
PLAYER Set this if you want to use a player model
NO_MODEL Don't use a model. Usefull for placing particle effects and dynamic lights on their own
SPLINE: If set, the func_train will follow a spline curve between path_corners. What this means is you can create near perfectly smooth curvilinear paths with a handful of path_corners. The train will constantly turn to face the direction it is moving (unless yaw_speed and pitch_speed are negative values). For a couple of examples, see the rottrain and lcraft example maps (available on the downloads page.) The shape of the spline curve is controlled by the location and pitch and yaw angles of the train's path_corners. Train roll angle will vary linearly between path_corner roll angle values (the third component of the angles vector).
-----------------------
Key/Value pairs:
"style" Specifies the animation type to use.
0: None (unless startframe and framenumbers are used)
1: ANIM01 - cycle between frames 0 and 1 at 2 hz
2: ANIM23 - cycle between frames 2 and 3 at 2 hz
3: ANIM_ALL - cycle through all frames at 2 hz
4: ANIM_ALLFAST - cycle through all frames at 10 hz
Note: The animation flags override startframe and framenumbers settings you may have enterered. ANIM_ALL and ANIM_ALLFAST don't do what you might think - rather than setting a framerate, these apparently cause the model to cycle through its ENTIRE sequence of animations in 0.5 or 0.1 seconds... which for monster and player models is of course not possible. Looks exceptionally goofy.
"usermodel" The model to load (models/ is already coded)
"startframe" The starting frame : default 0
"framenumbers" The number of frames you want to display after startframe
"skinnum" The skin number to use, default 0
"health" If non-zero and solidstate is 3 or 4 (solid), the entity will be shootable. When destroyed, it blows up with a no-damage explosion.
"target" first path_corner"
"team" func_train or func_rotating
"solidstate"
1 = Not solid (default)
2 = Bounding box
NOTE : if you want the model to be solid then you must enter vector values into the following fields :
"bleft" = the point that is at the bottom left of the models bounding box in a model editor
"tright" = the point that is at the top left of the models bounding box in a model editor
"speed" How fast the model should move
"accel" Acceleration
"decel" Deceleration
"pitch_speed" (Nose up & Down) in degrees per second (defualt 20)
"yaw_speed" (Side-to-side "wiggle") in degrees per second (default 20)
"roll_speed" (Banking) in degrees per second toward the next path corner's set roll
"dmg" default 2, damage to inflict when blocked
"noise" Sound model makes while moving(path/file.wav)
"effects"
1: ROTATE Rotate like a weapon
2: GIB
8: BLASTER Yellowish orange glow plus particles
16: ROCKET Rocket trail
32: GRENADE Grenade trail
64: HYPERBLASTER BLASTER w/o the particles
128: BFG Big green ball
256: COLOR_SHELL
512: POWERSCREEN Green power shield
16384: FLIES Ewwww
32768: QUAD Blue shell
65536: PENT Red shell
131072: TELEPORTER Teleporter particles
262144: FLAG1 Red glow
524288: FLAG2 Blue glow
1048576: IONRIPPER
2097152: GREENGIB
4194304: BLUE_HB Blue hyperblaster glow
8388608: SPINNING_LIGHTS Red spinning lights
16777216: PLASMA
33554432: TRAP
67108864: TRACKER
134217728: DOUBLE Yellow shell
268435456: SPHERETRANS Transparent
536870912: TAGTRAIL
1073741824: HALF_DAMAGE
2147483648: TRACKER_TRAIL
"renderfx"
1: MINLIGHT Never completely dark
2: VIEWERMODEL
4: WEAPONMODEL
8: FULLBRIGHT
16: DEPTHHACK
32: TRANSLUCENT Transparent
64: FRAMELERP
128: BEAM
512: GLOW Pulsating glow of normal Q2 pickup items
1024: SHELL_RED
2048: SHELL_GREEN
4096: SHELL_BLUE
32768: IR_VISIBLE
65536: SHELL_DOUBLE
131072: SHELL_HALF_DAMAGE White shell
262144: USE_DISGUISE
To have other entities move with the model train, set the door pieces' movewith values to the same as the train's targetname and they will move in
unison, and also still be able to move relative to the train themselves, and can be attached and detached using target_movewith.
NOTE: All the pieces must be created after the model train entity, otherwise they will move ahead of it.
*/
#define MODEL_TRAIN_START_ON 1
#define MODEL_TRAIN_TOGGLE 2
#define MODEL_TRAIN_BLOCK_STOPS 4
#define MODEL_TRAIN_ROTATE 32
#define MODEL_TRAIN_ROT_CONST 64
#define TRAIN_ANIM 32
#define TRAIN_ANIM_FAST 64
#define MODEL_TRAIN_SMOOTH 128
#define TRAIN_ROTATE 8
#define TRAIN_ROT_CONST 16
#define TRAIN_SPLINE 8192
void model_train_animator(edict_t *animator)
{
edict_t *train;
train = animator->owner;
if (!train || !train->inuse)
{
G_FreeEdict(animator);
return;
}
if (Q_stricmp(train->classname, "model_train"))
{
G_FreeEdict(animator);
return;
}
animator->nextthink = level.time + FRAMETIME;
if (VectorLength(train->velocity) == 0)
return;
train->s.frame++;
if (train->s.frame >= train->framenumbers)
train->s.frame = train->startframe;
gi.linkentity(train);
}
void SP_model_train (edict_t *self)
{
SP_model_spawn (self);
self->class_id = ENTITY_MODEL_TRAIN;
// Reset s.sound, which SP_model_spawn may have turned on
self->moveinfo.sound_middle = self->s.sound;
self->s.sound = 0;
if (!self->inuse) return;
// Reset some things from SP_model_spawn
self->delay = 0;
self->think = NULL;
self->nextthink = 0;
self->s.sound = self->noise_index;
if (self->health)
{
self->die = model_die;
self->takedamage = DAMAGE_YES;
}
if (self->framenumbers > self->startframe+1)
{
edict_t *animator;
animator = G_Spawn();
animator->owner = self;
animator->think = model_train_animator;
animator->nextthink = level.time + FRAMETIME;
}
self->s.frame = self->startframe;
self->movetype = MOVETYPE_PUSH;
// Really gross stuff here... translate model_spawn spawnflags
// to func_train spawnflags. PLAYER_MODEL and NO_MODEL have
// already been checked in SP_model_spawn and are never re-used,
// so it's OK to overwrite those.
if (self->spawnflags & MODEL_TRAIN_ROTATE)
{
self->spawnflags &= ~MODEL_TRAIN_ROTATE;
self->spawnflags |= TRAIN_ROTATE;
}
if (self->spawnflags & MODEL_TRAIN_ROT_CONST)
{
self->spawnflags &= ~MODEL_TRAIN_ROT_CONST;
self->spawnflags |= TRAIN_ROT_CONST;
}
//Knightmare- change both rotate flags to spline flag
if ((self->spawnflags & TRAIN_ROTATE) && (self->spawnflags &TRAIN_ROT_CONST))
{
self->spawnflags &= ~TRAIN_ROTATE;
self->spawnflags &= ~TRAIN_ROT_CONST;
self->spawnflags |= TRAIN_SPLINE;
}
if (self->style == 3)
self->spawnflags |= TRAIN_ANIM; // 32
if (self->style == 4)
self->spawnflags |= TRAIN_ANIM_FAST; // 64
// TRAIN_SMOOTH forces trains to go directly to Move_Done from
// Move_Final rather than slowing down (if necessary) for one
// frame.
if (self->spawnflags & MODEL_TRAIN_SMOOTH)
self->smooth_movement = 1;
else
self->smooth_movement = 0;
self->blocked = train_blocked;
if (self->spawnflags & MODEL_TRAIN_BLOCK_STOPS)
self->dmg = 0;
else
{
if (!self->dmg)
self->dmg = 100;
}
if (!self->speed)
self->speed = 100;
// Mappack
if (!self->accel)
self->moveinfo.accel = self->speed;
else
self->moveinfo.accel = self->accel;
if (!self->decel)
self->moveinfo.decel = self->speed;
else
self->moveinfo.decel = self->decel;
self->moveinfo.speed = self->speed;
self->use = train_use;
gi.linkentity (self);
if (self->target)
{
// start trains on the second frame, to make sure their targets have had
// a chance to spawn
self->nextthink = level.time + FRAMETIME;
self->think = func_train_find;
}
else
gi.dprintf ("model_train without a target at %s\n", vtos(self->s.origin));
}
void SP_model_train_origin (edict_t *self)
{
self->spawnflags |= TRAIN_ORIGIN;
SP_model_train (self);
}

View file

@ -4668,964 +4668,3 @@ void SP_misc_gekk_writhe (edict_t *self)
}
/*
=============================================================
Coconut Monkey 3 Flame entities
=============================================================
*/
#define FLAME_START_OFF 1
void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
/*static*/ void light_flame_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->solid == SOLID_NOT)
{
self->svflags &= ~SVF_NOCLIENT;
gi.configstring (CS_LIGHTS+self->style, "m");
self->spawnflags &= ~FLAME_START_OFF;
self->solid = SOLID_TRIGGER;
}
else
{
self->svflags |= SVF_NOCLIENT;
gi.configstring (CS_LIGHTS+self->style, "a");
self->spawnflags |= FLAME_START_OFF;
self->solid = SOLID_NOT;
}
gi.linkentity (self);
}
void light_flame_spawn (edict_t *self)
{
self->s.effects = EF_ANIM_ALLFAST;
self->s.renderfx |= RF_NOSHADOW;
self->movetype = MOVETYPE_NONE;
self->touch = hurt_touch;
if (!self->dmg)
self->dmg = 5;
self->noise_index = gi.soundindex ("world/electro.wav");
if (self->style >= 32)
{
if (self->spawnflags & FLAME_START_OFF)
{
gi.configstring (CS_LIGHTS+self->style, "a");
self->svflags |= SVF_NOCLIENT;
self->solid = SOLID_NOT;
}
else
{
gi.configstring (CS_LIGHTS+self->style, "m");
self->solid = SOLID_TRIGGER;
}
}
self->use = light_flame_use;
gi.linkentity (self);
}
void SP_light_flame1 (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame1.sp2");
VectorSet(self->mins,-48,-48,-32);
VectorSet(self->maxs, 48, 48, 64);
light_flame_spawn (self);
}
void SP_light_flame1s (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame1s.sp2");
VectorSet(self->mins,-16,-16,-16);
VectorSet(self->maxs, 16, 16, 32);
light_flame_spawn (self);
}
void SP_light_flame2 (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame2.sp2");
VectorSet(self->mins,-48,-48,-32);
VectorSet(self->maxs, 48, 48, 64);
light_flame_spawn (self);
}
void SP_light_flame2s (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame2s.sp2");
VectorSet(self->mins,-16,-16,-16);
VectorSet(self->maxs, 16, 16, 32);
light_flame_spawn (self);
}
/*
=============================================================
Coconut Monkey
=============================================================
*/
void monster_coco_monkey_think (edict_t *self)
{
if (++self->s.frame > 19)
self->s.frame = 0;
self->nextthink = level.time + FRAMETIME;
}
void SP_monster_coco_monkey (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->movetype = MOVETYPE_TOSS;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/coco/tris.md2");
self->s.renderfx |= RF_IR_VISIBLE;
VectorSet(self->mins,-16,-16,-40);
VectorSet(self->maxs, 16, 16, 48);
self->s.origin[2] += 10;
self->nextthink = level.time + FRAMETIME;
self->think = monster_coco_monkey_think;
self->common_name = "Coconut Monkey";
self->class_id = ENTITY_MONSTER_COCO_MONKEY;
gi.linkentity (self);
}
/*
=============================================================
Lazarus new entities
=============================================================
*/
void misc_light_think (edict_t *self)
{
if (self->spawnflags & START_OFF)
return;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_FLASHLIGHT);
gi.WritePosition (self->s.origin);
gi.WriteShort (self - g_edicts);
gi.multicast (self->s.origin, MULTICAST_PVS);
self->nextthink = level.time + FRAMETIME;
}
void misc_light_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->spawnflags & START_OFF)
{
self->spawnflags &= ~START_OFF;
self->nextthink = level.time + FRAMETIME;
}
else
self->spawnflags |= START_OFF;
}
void SP_misc_light (edict_t *self)
{
self->class_id = ENTITY_MISC_LIGHT;
self->use = misc_light_use;
if (self->movewith)
self->movetype = MOVETYPE_PUSH;
else
self->movetype = MOVETYPE_NONE;
self->think = misc_light_think;
if (!(self->spawnflags & START_OFF))
self->nextthink = level.time + 2*FRAMETIME;
}
/*
=============================================================
TARGET_PRECIPITATION
=============================================================
*/
#define SF_WEATHER_STARTON 1
#define SF_WEATHER_SPLASH 2
#define SF_WEATHER_GRAVITY_BOUNCE 4
#define SF_WEATHER_FIRE_ONCE 8
#define SF_WEATHER_START_FADE 16
#define STYLE_WEATHER_RAIN 0
#define STYLE_WEATHER_BIGRAIN 1
#define STYLE_WEATHER_SNOW 2
#define STYLE_WEATHER_LEAF 3
#define STYLE_WEATHER_USER 4
void drop_add_to_chain(edict_t *drop)
{
edict_t *owner = drop->owner;
edict_t *parent;
if (!owner || !owner->inuse || !(owner->spawnflags & SF_WEATHER_STARTON))
{
G_FreeEdict(drop);
return;
}
parent = owner;
while (parent->child)
parent = parent->child;
parent->child = drop;
drop->child = NULL;
drop->svflags |= SVF_NOCLIENT;
drop->s.effects &= ~EF_SPHERETRANS;
drop->s.renderfx &= ~RF_TRANSLUCENT;
VectorClear(drop->velocity);
VectorClear(drop->avelocity);
gi.linkentity(drop);
}
void drop_splash(edict_t *drop)
{
vec3_t up = {0,0,1};
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_LASER_SPARKS);
gi.WriteByte (drop->owner->mass2);
gi.WritePosition (drop->s.origin);
gi.WriteDir (up);
gi.WriteByte (drop->owner->sounds);
gi.multicast (drop->s.origin, MULTICAST_PVS);
drop_add_to_chain(drop);
}
void leaf_fade2(edict_t *ent)
{
ent->count++;
if (ent->count == 1)
{
ent->s.effects |= EF_SPHERETRANS;
ent->nextthink=level.time+0.5;
gi.linkentity(ent);
}
else
drop_add_to_chain(ent);
}
void leaf_fade (edict_t *ent)
{
ent->s.renderfx = RF_TRANSLUCENT;
ent->think = leaf_fade2;
ent->nextthink = level.time+0.5;
ent->count = 0;
gi.linkentity(ent);
}
void drop_touch(edict_t *drop, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (drop->owner->spawnflags & SF_WEATHER_START_FADE)
return;
else if (drop->fadeout > 0)
{
if ( (drop->spawnflags & SF_WEATHER_GRAVITY_BOUNCE) && (drop->owner->gravity > 0))
{
drop->movetype = MOVETYPE_DEBRIS;
drop->gravity = drop->owner->gravity;
}
drop->think = leaf_fade;
drop->nextthink = level.time + drop->fadeout;
}
else if (drop->spawnflags & SF_WEATHER_SPLASH)
drop_splash(drop);
else
drop_add_to_chain(drop);
}
void spawn_precipitation(edict_t *self, vec3_t org, vec3_t dir, float speed)
{
edict_t *drop;
if (self->child)
{
// Then we already have a currently unused, invisible drop available
drop = self->child;
self->child = drop->child;
drop->child = NULL;
drop->svflags &= ~SVF_NOCLIENT;
drop->groundentity = NULL;
}
else
{
drop = G_Spawn();
if (self->style == STYLE_WEATHER_BIGRAIN)
drop->s.modelindex = gi.modelindex ("models/objects/drop/heavy.md2");
else if (self->style == STYLE_WEATHER_SNOW)
drop->s.modelindex = gi.modelindex ("models/objects/snow/tris.md2");
else if (self->style == STYLE_WEATHER_LEAF)
{
float r=random();
if (r < 0.33)
drop->s.modelindex = gi.modelindex ("models/objects/leaf1/tris.md2");
else if (r < 0.66)
drop->s.modelindex = gi.modelindex ("models/objects/leaf2/tris.md2");
else
drop->s.modelindex = gi.modelindex ("models/objects/leaf3/tris.md2");
VectorSet(drop->mins,-1,-1,-1);
VectorSet(drop->maxs, 1, 1, 1);
}
else if (self->style == STYLE_WEATHER_USER)
drop->s.modelindex = gi.modelindex(self->usermodel);
else
drop->s.modelindex = gi.modelindex ("models/objects/drop/tris.md2");
drop->classname = "rain drop";
}
if (self->gravity > 0.0f || self->attenuation > 0 )
drop->movetype = MOVETYPE_DEBRIS;
else
drop->movetype = MOVETYPE_RAIN;
drop->touch = drop_touch;
if (self->style == STYLE_WEATHER_USER)
drop->clipmask = MASK_MONSTERSOLID;
else if ((self->fadeout > 0) && (self->gravity == 0.0f))
drop->clipmask = MASK_SOLID | CONTENTS_WATER;
else
drop->clipmask = MASK_MONSTERSOLID | CONTENTS_WATER;
drop->solid = SOLID_BBOX;
drop->svflags = SVF_DEADMONSTER;
VectorSet(drop->mins, -1, -1, -1);
VectorSet(drop->maxs, 1, 1, 1);
if (self->spawnflags & SF_WEATHER_GRAVITY_BOUNCE)
drop->gravity = self->gravity;
else
drop->gravity = 0.0f;
drop->attenuation = self->attenuation;
drop->mass = self->mass;
drop->spawnflags = self->spawnflags;
drop->fadeout = self->fadeout;
drop->owner = self;
VectorCopy (org, drop->s.origin);
vectoangles(dir, drop->s.angles);
drop->s.angles[PITCH] -= 90;
VectorScale (dir, speed, drop->velocity);
if (self->style == STYLE_WEATHER_LEAF)
{
drop->avelocity[PITCH] = crandom() * 360;
drop->avelocity[YAW] = crandom() * 360;
drop->avelocity[ROLL] = crandom() * 360;
}
else if (self->style == STYLE_WEATHER_USER)
{
drop->s.effects = self->effects;
drop->s.renderfx = self->renderfx;
drop->avelocity[PITCH] = crandom() * self->pitch_speed;
drop->avelocity[YAW] = crandom() * self->yaw_speed;
drop->avelocity[ROLL] = crandom() * self->roll_speed;
}
else
{
drop->s.effects |= EF_SPHERETRANS;
drop->avelocity[YAW] = self->yaw_speed;
}
if (self->spawnflags & SF_WEATHER_START_FADE)
{
drop->think = leaf_fade;
drop->nextthink = level.time + self->fadeout;
}
gi.linkentity(drop);
}
void target_precipitation_think (edict_t *self)
{
vec3_t center;
vec3_t org;
int r, i;
float u, v, z;
float temp;
qboolean can_see_me;
self->nextthink = level.time + FRAMETIME;
// Don't start raining until player is in the game. The following
// takes care of both initial map load conditions and restored saved games.
// This is a gross abuse of groundentity_linkcount. Sue me.
if (g_edicts[1].linkcount == self->groundentity_linkcount)
return;
else
self->groundentity_linkcount = g_edicts[1].linkcount;
// Don't spawn drops if player can't see us. This SEEMS like an obvious
// thing to do, but can cause visual problems if mapper isn't careful.
// For example, placing target_precipitation where it isn't in the PVS
// of the player's current position, but the result (rain) IS in the
// PVS. In any case, this step is necessary to prevent overflows when
// player suddenly encounters rain.
can_see_me = false;
for (i=1; i<=game.maxclients && !can_see_me; i++)
{
if (!g_edicts[i].inuse) continue;
if (gi.inPVS(g_edicts[i].s.origin,self->s.origin))
can_see_me = true;
}
if (!can_see_me) return;
// Count is models/second. We accumulate a probability of a model
// falling this frame in ->density. Yeah its a misnomer but density isn't
// used for anything else so it works fine.
temp = 0.1*(self->density + crandom()*self->random);
r = (int)(temp);
if (r > 0)
self->density = self->count + (temp-(float)r)*10;
else
self->density += (temp*10);
if (r < 1) return;
VectorAdd(self->bleft,self->tright,center);
VectorMA(self->s.origin,0.5,center,center);
for (i=0; i<r; i++)
{
u = crandom() * (self->tright[0] - self->bleft[0])/2;
v = crandom() * (self->tright[1] - self->bleft[1])/2;
z = crandom() * (self->tright[2] - self->bleft[2])/2;
VectorCopy(center, org);
org[0] += u;
org[1] += v;
org[2] += z;
spawn_precipitation(self, org, self->movedir, self->speed);
}
}
void target_precipitation_use (edict_t *ent, edict_t *other, edict_t *activator)
{
if (ent->spawnflags & SF_WEATHER_STARTON)
{
// already on; turn it off
ent->nextthink = 0;
ent->spawnflags &= ~SF_WEATHER_STARTON;
if (ent->child)
{
edict_t *child, *parent;
child = ent->child;
ent->child = NULL;
while (child)
{
parent = child;
child = parent->child;
G_FreeEdict(parent);
}
}
}
else
{
ent->density = ent->count;
ent->think = target_precipitation_think;
ent->spawnflags |= SF_WEATHER_STARTON;
ent->think(ent);
}
}
void target_precipitation_delayed_use (edict_t *self)
{
// Since target_precipitation tends to be a processor hog,
// for START_ON we wait until the player has spawned into the
// game to ease the startup burden somewhat
if (g_edicts[1].linkcount)
{
self->think = target_precipitation_think;
self->think(self);
}
else
self->nextthink = level.time + FRAMETIME;
}
void SP_target_precipitation (edict_t *ent)
{
if (deathmatch->value || coop->value)
{
G_FreeEdict(ent);
return;
}
ent->class_id = ENTITY_TARGET_PRECIPITATION;
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
if (ent->spawnflags & SF_WEATHER_STARTON)
{
ent->think = target_precipitation_delayed_use;
ent->nextthink = level.time + 1;
}
if (ent->style == STYLE_WEATHER_USER)
{
char *buffer;
size_t bufSize;
if (!ent->usermodel)
{
gi.dprintf("target_precipitation style=user\nwith no usermodel.\n");
G_FreeEdict(ent);
return;
}
// Knightmare- check for "models/" or "sprites/" already in path
if ( strncmp(ent->usermodel, "models/", 7) && strncmp(ent->usermodel, "sprites/", 8) )
{
bufSize = strlen(ent->usermodel)+10;
buffer = gi.TagMalloc(bufSize, TAG_LEVEL);
if (strstr(ent->usermodel,".sp2"))
Com_sprintf(buffer, bufSize, "sprites/%s", ent->usermodel);
else
Com_sprintf(buffer, bufSize, "models/%s", ent->usermodel);
ent->usermodel = buffer;
}
if (st.gravity)
ent->gravity = atof(st.gravity);
else
ent->gravity = 0.0f;
}
else
{
ent->gravity = 0.0f;
ent->attenuation = 0.0f;
}
// If not rain or "user", turn off splash. Yeah I know goofy mapper
// might WANT splash, but we're enforcing good taste here :)
if (ent->style > STYLE_WEATHER_BIGRAIN && ent->style != STYLE_WEATHER_USER)
ent->spawnflags &= ~SF_WEATHER_SPLASH;
ent->use = target_precipitation_use;
if (!ent->count)
ent->count = 1;
if (!ent->sounds)
ent->sounds = 2; // blue splash
if (!ent->mass2)
ent->mass2 = 8; // 8 particles in splash
if ((ent->style < STYLE_WEATHER_RAIN) || (ent->style > STYLE_WEATHER_USER))
ent->style = STYLE_WEATHER_RAIN; // single rain drop model
if (ent->speed <= 0)
{
switch (ent->style)
{
case STYLE_WEATHER_SNOW: ent->speed = 50; break;
case STYLE_WEATHER_LEAF: ent->speed = 50; break;
default: ent->speed = 300;
}
}
if ((VectorLength(ent->bleft) == 0.) && (VectorLength(ent->tright) == 0.))
{
// Default distribution places raindrops vertically for
// full coverage, to help avoid "lumps"
VectorSet(ent->bleft,-512,-512, -ent->speed*0.05);
VectorSet(ent->tright,512, 512, ent->speed*0.05);
}
if (VectorLength(ent->s.angles) > 0)
G_SetMovedir(ent->s.angles,ent->movedir);
else
VectorSet(ent->movedir,0,0,-1);
ent->density = ent->count;
gi.linkentity (ent);
}
//=============================================================================
// TARGET_FOUNTAIN is identical to TARGET_PRECIPITATION, with these exceptions:
// ALL styles are "user-defined" (no predefined rain, snow, etc.)
// Models are spawned from a point source, and bleft/tright form a box within
// which the target point is found.
//=============================================================================
void target_fountain_think (edict_t *self)
{
vec3_t center;
vec3_t org;
vec3_t dir;
int r, i;
float u, v, z;
float temp;
qboolean can_see_me;
if (!(self->spawnflags & SF_WEATHER_FIRE_ONCE))
self->nextthink = level.time + FRAMETIME;
// Don't start raining until player is in the game. The following
// takes care of both initial map load conditions and restored saved games.
// This is a gross abuse of groundentity_linkcount. Sue me.
if (g_edicts[1].linkcount == self->groundentity_linkcount)
return;
else
self->groundentity_linkcount = g_edicts[1].linkcount;
// Don't spawn drops if player can't see us. This SEEMS like an obvious
// thing to do, but can cause visual problems if mapper isn't careful.
// For example, placing target_precipitation where it isn't in the PVS
// of the player's current position, but the result (rain) IS in the
// PVS. In any case, this step is necessary to prevent overflows when
// player suddenly encounters rain.
can_see_me = false;
for (i=1; i<=game.maxclients && !can_see_me; i++)
{
if (!g_edicts[i].inuse) continue;
if (gi.inPVS(g_edicts[i].s.origin,self->s.origin))
can_see_me = true;
}
if (!can_see_me) return;
// Count is models/second. We accumulate a probability of a model
// falling this frame in ->density. Yeah its a misnomer but density isn't
// used for anything else so it works fine.
temp = 0.1*(self->density + crandom()*self->random);
r = (int)(temp);
if (r > 0)
self->density = self->count;
else
self->density += (temp*10);
if (r < 1) return;
VectorAdd(self->bleft,self->tright,center);
VectorMA(self->s.origin,0.5,center,center);
for (i=0; i<r; i++)
{
u = crandom() * (self->tright[0] - self->bleft[0])/2;
v = crandom() * (self->tright[1] - self->bleft[1])/2;
z = crandom() * (self->tright[2] - self->bleft[2])/2;
VectorCopy(center, org);
org[0] += u;
org[1] += v;
org[2] += z;
VectorSubtract(org,self->s.origin,dir);
VectorNormalize(dir);
spawn_precipitation(self, self->s.origin, dir, self->speed);
}
}
void target_fountain_use (edict_t *ent, edict_t *other, edict_t *activator)
{
if ((ent->spawnflags & SF_WEATHER_STARTON) && !(ent->spawnflags & SF_WEATHER_FIRE_ONCE))
{
// already on; turn it off
ent->nextthink = 0;
ent->spawnflags &= ~SF_WEATHER_STARTON;
if (ent->child)
{
edict_t *child, *parent;
child = ent->child;
ent->child = NULL;
while (child)
{
parent = child;
child = parent->child;
G_FreeEdict(parent);
}
}
}
else
{
ent->density = ent->count;
ent->think = target_fountain_think;
ent->spawnflags |= SF_WEATHER_STARTON;
ent->think(ent);
}
}
void target_fountain_delayed_use (edict_t *self)
{
// Since target_fountain tends to be a processor hog,
// for START_ON we wait until the player has spawned into the
// game to ease the startup burden somewhat
if (g_edicts[1].linkcount)
{
self->think = target_fountain_think;
self->think(self);
}
else
self->nextthink = level.time + FRAMETIME;
}
void SP_target_fountain (edict_t *ent)
{
char *buffer;
size_t bufSize;
if (deathmatch->value || coop->value)
{
G_FreeEdict(ent);
return;
}
ent->class_id = ENTITY_TARGET_FOUNTAIN;
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
if (ent->spawnflags & SF_WEATHER_STARTON)
{
ent->think = target_fountain_delayed_use;
ent->nextthink = level.time + 1;
}
ent->style = STYLE_WEATHER_USER;
if (!ent->usermodel)
{
gi.dprintf("target_fountain with no usermodel.\n");
G_FreeEdict(ent);
return;
}
// Knightmare- check for "models/" or "sprites/" already in path
if ( strncmp(ent->usermodel, "models/", 7) && strncmp(ent->usermodel, "sprites/", 8) )
{
bufSize = strlen(ent->usermodel)+10;
buffer = gi.TagMalloc(bufSize, TAG_LEVEL);
if (strstr(ent->usermodel,".sp2"))
Com_sprintf(buffer, bufSize, "sprites/%s", ent->usermodel);
else
Com_sprintf(buffer, bufSize, "models/%s", ent->usermodel);
ent->usermodel = buffer;
}
if (st.gravity)
ent->gravity = atof(st.gravity);
else
ent->gravity = 0.0f;
ent->use = target_fountain_use;
if (!ent->count)
ent->count = 1;
if (!ent->sounds)
ent->sounds = 2; // blue splash
if (!ent->mass2)
ent->mass2 = 8; // 8 particles in splash
if (ent->speed <= 0)
ent->speed = 300;
if ((VectorLength(ent->bleft) == 0.) && (VectorLength(ent->tright) == 0.))
{
// Default distribution places raindrops vertically for
// full coverage, to help avoid "lumps"
VectorSet(ent->bleft,-32, -32, 64);
VectorSet(ent->tright,32, 32,128);
}
ent->density = ent->count;
gi.linkentity (ent);
}
//
/*=============================================================================
MISC_DEADSOLDIER MODEL PATCH
==============================================================================*/
#define NUM_SKINS 16
#define MAX_SKINNAME 64
#define DEADSOLDIER_MODEL "models/deadbods/dude/tris.md2"
#include "pak.h"
int PatchDeadSoldier (void)
{
cvar_t *gamedir;
char skins[NUM_SKINS][MAX_SKINNAME]; // skin entries
char infilename[MAX_OSPATH];
char outfilename[MAX_OSPATH];
char tempname[MAX_OSPATH];
int j;
// char *p;
FILE *infile;
FILE *outfile;
dmdl_t model; // model header
byte *data; // model data
int datasize; // model data size (bytes)
int newoffset; // model data offset (after skins)
// get game (moddir) name
gamedir = gi.cvar("game", "", 0);
if (!*gamedir->string)
return 0; // we're in baseq2
// Com_sprintf (outfilename, sizeof(outfilename), "%s/%s", gamedir->string,DEADSOLDIER_MODEL);
Com_sprintf (tempname, sizeof(tempname), DEADSOLDIER_MODEL);
SavegameDirRelativePath (tempname, outfilename, sizeof(outfilename));
if (outfile = fopen (outfilename, "rb"))
{
// output file already exists, move along
fclose (outfile);
// gi.dprintf ("PatchDeadSoldier: Could not save %s, file already exists\n", outfilename);
return 0;
}
for (j = 0; j < NUM_SKINS; j++)
memset (skins[j], 0, MAX_SKINNAME);
Com_sprintf (skins[0], sizeof(skins[0]), "models/deadbods/dude/dead1.pcx");
Com_sprintf (skins[1], sizeof(skins[1]), "players/male/cipher.pcx");
Com_sprintf (skins[2], sizeof(skins[2]), "players/male/claymore.pcx");
Com_sprintf (skins[3], sizeof(skins[3]), "players/male/flak.pcx");
Com_sprintf (skins[4], sizeof(skins[4]), "players/male/grunt.pcx");
Com_sprintf (skins[5], sizeof(skins[5]), "players/male/howitzer.pcx");
Com_sprintf (skins[6], sizeof(skins[6]), "players/male/major.pcx");
Com_sprintf (skins[7], sizeof(skins[7]), "players/male/nightops.pcx");
Com_sprintf (skins[8], sizeof(skins[8]), "players/male/pointman.pcx");
Com_sprintf (skins[9], sizeof(skins[9]), "players/male/psycho.pcx");
Com_sprintf (skins[10], sizeof(skins[10]), "players/male/rampage.pcx");
Com_sprintf (skins[11], sizeof(skins[11]), "players/male/razor.pcx");
Com_sprintf (skins[12], sizeof(skins[12]), "players/male/recon.pcx");
Com_sprintf (skins[13], sizeof(skins[13]), "players/male/scout.pcx");
Com_sprintf (skins[14], sizeof(skins[14]), "players/male/sniper.pcx");
Com_sprintf (skins[15], sizeof(skins[15]), "players/male/viper.pcx");
// load original model
Com_sprintf (infilename, sizeof(infilename), "baseq2/%s", DEADSOLDIER_MODEL);
if ( !(infile = fopen (infilename, "rb")) )
{
// If file doesn't exist on user's hard disk, it must be in
// pak0.pak
pak_header_t pakheader;
pak_item_t pakitem;
FILE *fpak;
int k, numitems;
fpak = fopen("baseq2/pak0.pak","rb");
if (!fpak)
{
cvar_t *cddir;
char pakfile[MAX_OSPATH];
cddir = gi.cvar("cddir", "", 0);
Com_sprintf(pakfile, sizeof(pakfile), "%s/baseq2/pak0.pak",cddir->string);
fpak = fopen(pakfile,"rb");
if (!fpak)
{
gi.dprintf("PatchDeadSoldier: Cannot find pak0.pak\n");
return 0;
}
}
fread(&pakheader,1,sizeof(pak_header_t),fpak);
numitems = pakheader.dsize/sizeof(pak_item_t);
fseek(fpak,pakheader.dstart,SEEK_SET);
data = NULL;
for (k=0; k<numitems && !data; k++)
{
fread(&pakitem,1,sizeof(pak_item_t),fpak);
if (!Q_stricmp(pakitem.name,DEADSOLDIER_MODEL))
{
fseek(fpak,pakitem.start,SEEK_SET);
fread(&model, sizeof(dmdl_t), 1, fpak);
datasize = model.ofs_end - model.ofs_skins;
if ( !(data = malloc (datasize)) ) // make sure freed locally
{
fclose(fpak);
gi.dprintf ("PatchDeadSoldier: Could not allocate memory for model\n");
return 0;
}
fread (data, sizeof (byte), datasize, fpak);
}
}
fclose(fpak);
if (!data)
{
gi.dprintf("PatchDeadSoldier: Could not find %s in baseq2/pak0.pak\n",DEADSOLDIER_MODEL);
return 0;
}
}
else
{
fread (&model, sizeof (dmdl_t), 1, infile);
datasize = model.ofs_end - model.ofs_skins;
if ( !(data = malloc (datasize)) ) // make sure freed locally
{
gi.dprintf ("PatchMonsterModel: Could not allocate memory for model\n");
return 0;
}
fread (data, sizeof (byte), datasize, infile);
fclose (infile);
}
// update model info
model.num_skins = NUM_SKINS;
// Already had 1 skin, so new offset doesn't include that one
// newoffset = (model.num_skins-1) * MAX_SKINNAME;
newoffset = model.num_skins * MAX_SKINNAME;
model.ofs_st += newoffset;
model.ofs_tris += newoffset;
model.ofs_frames += newoffset;
model.ofs_glcmds += newoffset;
model.ofs_end += newoffset;
// save new model
/* Com_sprintf (outfilename, sizeof(outfilename), "%s/models", gamedir->string); // make some dirs if needed
_mkdir (outfilename);
Com_strcat (outfilename, sizeof(outfilename), "/deadbods");
_mkdir (outfilename);
Com_strcat (outfilename, sizeof(outfilename), "/dude");
_mkdir (outfilename);
Com_sprintf (outfilename, sizeof(outfilename), "%s/%s", gamedir->string, DEADSOLDIER_MODEL);
p = strstr(outfilename,"/tris.md2");
*p = 0;
_mkdir (outfilename);
Com_sprintf (outfilename, sizeof(outfilename), "%s/%s", gamedir->string, DEADSOLDIER_MODEL);
*/
Com_sprintf (tempname, sizeof(tempname), DEADSOLDIER_MODEL);
SavegameDirRelativePath (tempname, outfilename, sizeof(outfilename));
CreatePath (outfilename);
if ( !(outfile = fopen (outfilename, "wb")) )
{
// file couldn't be created for some other reason
gi.dprintf ("PatchDeadSoldier: Could not save %s\n", outfilename);
free (data);
return 0;
}
fwrite (&model, sizeof (dmdl_t), 1, outfile);
// fwrite (skins, sizeof (char), model.num_skins*MAX_SKINNAME, outfile);
fwrite (skins, sizeof (char), newoffset, outfile);
// data += MAX_SKINNAME;
fwrite (data, sizeof (byte), datasize, outfile);
fclose (outfile);
gi.dprintf ("PatchDeadSoldier: Saved %s\n", outfilename);
free (data); // crashes here
return 1;
}

827
missionpack/g_misc_laz.c Normal file
View file

@ -0,0 +1,827 @@
// g_misc_laz.c
// misc entities for the Lazarus mod
#include "g_local.h"
#define START_OFF 1
/*
=============================================================
Lazarus new entities
=============================================================
*/
void misc_light_think (edict_t *self)
{
if (self->spawnflags & START_OFF)
return;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_FLASHLIGHT);
gi.WritePosition (self->s.origin);
gi.WriteShort (self - g_edicts);
gi.multicast (self->s.origin, MULTICAST_PVS);
self->nextthink = level.time + FRAMETIME;
}
void misc_light_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->spawnflags & START_OFF)
{
self->spawnflags &= ~START_OFF;
self->nextthink = level.time + FRAMETIME;
}
else
self->spawnflags |= START_OFF;
}
void SP_misc_light (edict_t *self)
{
self->class_id = ENTITY_MISC_LIGHT;
self->use = misc_light_use;
if (self->movewith)
self->movetype = MOVETYPE_PUSH;
else
self->movetype = MOVETYPE_NONE;
self->think = misc_light_think;
if (!(self->spawnflags & START_OFF))
self->nextthink = level.time + 2*FRAMETIME;
}
/*
=============================================================
TARGET_PRECIPITATION
=============================================================
*/
#define SF_WEATHER_STARTON 1
#define SF_WEATHER_SPLASH 2
#define SF_WEATHER_GRAVITY_BOUNCE 4
#define SF_WEATHER_FIRE_ONCE 8
#define SF_WEATHER_START_FADE 16
#define STYLE_WEATHER_RAIN 0
#define STYLE_WEATHER_BIGRAIN 1
#define STYLE_WEATHER_SNOW 2
#define STYLE_WEATHER_LEAF 3
#define STYLE_WEATHER_USER 4
void drop_add_to_chain(edict_t *drop)
{
edict_t *owner = drop->owner;
edict_t *parent;
if (!owner || !owner->inuse || !(owner->spawnflags & SF_WEATHER_STARTON))
{
G_FreeEdict(drop);
return;
}
parent = owner;
while (parent->child)
parent = parent->child;
parent->child = drop;
drop->child = NULL;
drop->svflags |= SVF_NOCLIENT;
drop->s.effects &= ~EF_SPHERETRANS;
drop->s.renderfx &= ~RF_TRANSLUCENT;
VectorClear(drop->velocity);
VectorClear(drop->avelocity);
gi.linkentity(drop);
}
void drop_splash(edict_t *drop)
{
vec3_t up = {0,0,1};
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_LASER_SPARKS);
gi.WriteByte (drop->owner->mass2);
gi.WritePosition (drop->s.origin);
gi.WriteDir (up);
gi.WriteByte (drop->owner->sounds);
gi.multicast (drop->s.origin, MULTICAST_PVS);
drop_add_to_chain(drop);
}
void leaf_fade2(edict_t *ent)
{
ent->count++;
if (ent->count == 1)
{
ent->s.effects |= EF_SPHERETRANS;
ent->nextthink=level.time+0.5;
gi.linkentity(ent);
}
else
drop_add_to_chain(ent);
}
void leaf_fade (edict_t *ent)
{
ent->s.renderfx = RF_TRANSLUCENT;
ent->think = leaf_fade2;
ent->nextthink = level.time+0.5;
ent->count = 0;
gi.linkentity(ent);
}
void drop_touch(edict_t *drop, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (drop->owner->spawnflags & SF_WEATHER_START_FADE)
return;
else if (drop->fadeout > 0)
{
if ( (drop->spawnflags & SF_WEATHER_GRAVITY_BOUNCE) && (drop->owner->gravity > 0))
{
drop->movetype = MOVETYPE_DEBRIS;
drop->gravity = drop->owner->gravity;
}
drop->think = leaf_fade;
drop->nextthink = level.time + drop->fadeout;
}
else if (drop->spawnflags & SF_WEATHER_SPLASH)
drop_splash(drop);
else
drop_add_to_chain(drop);
}
void spawn_precipitation(edict_t *self, vec3_t org, vec3_t dir, float speed)
{
edict_t *drop;
if (self->child)
{
// Then we already have a currently unused, invisible drop available
drop = self->child;
self->child = drop->child;
drop->child = NULL;
drop->svflags &= ~SVF_NOCLIENT;
drop->groundentity = NULL;
}
else
{
drop = G_Spawn();
if (self->style == STYLE_WEATHER_BIGRAIN)
drop->s.modelindex = gi.modelindex ("models/objects/drop/heavy.md2");
else if (self->style == STYLE_WEATHER_SNOW)
drop->s.modelindex = gi.modelindex ("models/objects/snow/tris.md2");
else if (self->style == STYLE_WEATHER_LEAF)
{
float r=random();
if (r < 0.33)
drop->s.modelindex = gi.modelindex ("models/objects/leaf1/tris.md2");
else if (r < 0.66)
drop->s.modelindex = gi.modelindex ("models/objects/leaf2/tris.md2");
else
drop->s.modelindex = gi.modelindex ("models/objects/leaf3/tris.md2");
VectorSet(drop->mins,-1,-1,-1);
VectorSet(drop->maxs, 1, 1, 1);
}
else if (self->style == STYLE_WEATHER_USER)
drop->s.modelindex = gi.modelindex(self->usermodel);
else
drop->s.modelindex = gi.modelindex ("models/objects/drop/tris.md2");
drop->classname = "rain drop";
}
if (self->gravity > 0.0f || self->attenuation > 0 )
drop->movetype = MOVETYPE_DEBRIS;
else
drop->movetype = MOVETYPE_RAIN;
drop->touch = drop_touch;
if (self->style == STYLE_WEATHER_USER)
drop->clipmask = MASK_MONSTERSOLID;
else if ((self->fadeout > 0) && (self->gravity == 0.0f))
drop->clipmask = MASK_SOLID | CONTENTS_WATER;
else
drop->clipmask = MASK_MONSTERSOLID | CONTENTS_WATER;
drop->solid = SOLID_BBOX;
drop->svflags = SVF_DEADMONSTER;
VectorSet(drop->mins, -1, -1, -1);
VectorSet(drop->maxs, 1, 1, 1);
if (self->spawnflags & SF_WEATHER_GRAVITY_BOUNCE)
drop->gravity = self->gravity;
else
drop->gravity = 0.0f;
drop->attenuation = self->attenuation;
drop->mass = self->mass;
drop->spawnflags = self->spawnflags;
drop->fadeout = self->fadeout;
drop->owner = self;
VectorCopy (org, drop->s.origin);
vectoangles(dir, drop->s.angles);
drop->s.angles[PITCH] -= 90;
VectorScale (dir, speed, drop->velocity);
if (self->style == STYLE_WEATHER_LEAF)
{
drop->avelocity[PITCH] = crandom() * 360;
drop->avelocity[YAW] = crandom() * 360;
drop->avelocity[ROLL] = crandom() * 360;
}
else if (self->style == STYLE_WEATHER_USER)
{
drop->s.effects = self->effects;
drop->s.renderfx = self->renderfx;
drop->avelocity[PITCH] = crandom() * self->pitch_speed;
drop->avelocity[YAW] = crandom() * self->yaw_speed;
drop->avelocity[ROLL] = crandom() * self->roll_speed;
}
else
{
drop->s.effects |= EF_SPHERETRANS;
drop->avelocity[YAW] = self->yaw_speed;
}
if (self->spawnflags & SF_WEATHER_START_FADE)
{
drop->think = leaf_fade;
drop->nextthink = level.time + self->fadeout;
}
gi.linkentity(drop);
}
void target_precipitation_think (edict_t *self)
{
vec3_t center;
vec3_t org;
int r, i;
float u, v, z;
float temp;
qboolean can_see_me;
self->nextthink = level.time + FRAMETIME;
// Don't start raining until player is in the game. The following
// takes care of both initial map load conditions and restored saved games.
// This is a gross abuse of groundentity_linkcount. Sue me.
if (g_edicts[1].linkcount == self->groundentity_linkcount)
return;
else
self->groundentity_linkcount = g_edicts[1].linkcount;
// Don't spawn drops if player can't see us. This SEEMS like an obvious
// thing to do, but can cause visual problems if mapper isn't careful.
// For example, placing target_precipitation where it isn't in the PVS
// of the player's current position, but the result (rain) IS in the
// PVS. In any case, this step is necessary to prevent overflows when
// player suddenly encounters rain.
can_see_me = false;
for (i=1; i<=game.maxclients && !can_see_me; i++)
{
if (!g_edicts[i].inuse) continue;
if (gi.inPVS(g_edicts[i].s.origin,self->s.origin))
can_see_me = true;
}
if (!can_see_me) return;
// Count is models/second. We accumulate a probability of a model
// falling this frame in ->density. Yeah its a misnomer but density isn't
// used for anything else so it works fine.
temp = 0.1*(self->density + crandom()*self->random);
r = (int)(temp);
if (r > 0)
self->density = self->count + (temp-(float)r)*10;
else
self->density += (temp*10);
if (r < 1) return;
VectorAdd(self->bleft,self->tright,center);
VectorMA(self->s.origin,0.5,center,center);
for (i=0; i<r; i++)
{
u = crandom() * (self->tright[0] - self->bleft[0])/2;
v = crandom() * (self->tright[1] - self->bleft[1])/2;
z = crandom() * (self->tright[2] - self->bleft[2])/2;
VectorCopy(center, org);
org[0] += u;
org[1] += v;
org[2] += z;
spawn_precipitation(self, org, self->movedir, self->speed);
}
}
void target_precipitation_use (edict_t *ent, edict_t *other, edict_t *activator)
{
if (ent->spawnflags & SF_WEATHER_STARTON)
{
// already on; turn it off
ent->nextthink = 0;
ent->spawnflags &= ~SF_WEATHER_STARTON;
if (ent->child)
{
edict_t *child, *parent;
child = ent->child;
ent->child = NULL;
while (child)
{
parent = child;
child = parent->child;
G_FreeEdict(parent);
}
}
}
else
{
ent->density = ent->count;
ent->think = target_precipitation_think;
ent->spawnflags |= SF_WEATHER_STARTON;
ent->think(ent);
}
}
void target_precipitation_delayed_use (edict_t *self)
{
// Since target_precipitation tends to be a processor hog,
// for START_ON we wait until the player has spawned into the
// game to ease the startup burden somewhat
if (g_edicts[1].linkcount)
{
self->think = target_precipitation_think;
self->think(self);
}
else
self->nextthink = level.time + FRAMETIME;
}
void SP_target_precipitation (edict_t *ent)
{
if (deathmatch->value || coop->value)
{
G_FreeEdict(ent);
return;
}
ent->class_id = ENTITY_TARGET_PRECIPITATION;
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
if (ent->spawnflags & SF_WEATHER_STARTON)
{
ent->think = target_precipitation_delayed_use;
ent->nextthink = level.time + 1;
}
if (ent->style == STYLE_WEATHER_USER)
{
char *buffer;
size_t bufSize;
if (!ent->usermodel)
{
gi.dprintf("target_precipitation style=user\nwith no usermodel.\n");
G_FreeEdict(ent);
return;
}
// Knightmare- check for "models/" or "sprites/" already in path
if ( strncmp(ent->usermodel, "models/", 7) && strncmp(ent->usermodel, "sprites/", 8) )
{
bufSize = strlen(ent->usermodel)+10;
buffer = gi.TagMalloc(bufSize, TAG_LEVEL);
if (strstr(ent->usermodel,".sp2"))
Com_sprintf(buffer, bufSize, "sprites/%s", ent->usermodel);
else
Com_sprintf(buffer, bufSize, "models/%s", ent->usermodel);
ent->usermodel = buffer;
}
if (st.gravity)
ent->gravity = atof(st.gravity);
else
ent->gravity = 0.0f;
}
else
{
ent->gravity = 0.0f;
ent->attenuation = 0.0f;
}
// If not rain or "user", turn off splash. Yeah I know goofy mapper
// might WANT splash, but we're enforcing good taste here :)
if (ent->style > STYLE_WEATHER_BIGRAIN && ent->style != STYLE_WEATHER_USER)
ent->spawnflags &= ~SF_WEATHER_SPLASH;
ent->use = target_precipitation_use;
if (!ent->count)
ent->count = 1;
if (!ent->sounds)
ent->sounds = 2; // blue splash
if (!ent->mass2)
ent->mass2 = 8; // 8 particles in splash
if ((ent->style < STYLE_WEATHER_RAIN) || (ent->style > STYLE_WEATHER_USER))
ent->style = STYLE_WEATHER_RAIN; // single rain drop model
if (ent->speed <= 0)
{
switch (ent->style)
{
case STYLE_WEATHER_SNOW: ent->speed = 50; break;
case STYLE_WEATHER_LEAF: ent->speed = 50; break;
default: ent->speed = 300;
}
}
if ((VectorLength(ent->bleft) == 0.) && (VectorLength(ent->tright) == 0.))
{
// Default distribution places raindrops vertically for
// full coverage, to help avoid "lumps"
VectorSet(ent->bleft,-512,-512, -ent->speed*0.05);
VectorSet(ent->tright,512, 512, ent->speed*0.05);
}
if (VectorLength(ent->s.angles) > 0)
G_SetMovedir(ent->s.angles,ent->movedir);
else
VectorSet(ent->movedir,0,0,-1);
ent->density = ent->count;
gi.linkentity (ent);
}
//=============================================================================
// TARGET_FOUNTAIN is identical to TARGET_PRECIPITATION, with these exceptions:
// ALL styles are "user-defined" (no predefined rain, snow, etc.)
// Models are spawned from a point source, and bleft/tright form a box within
// which the target point is found.
//=============================================================================
void target_fountain_think (edict_t *self)
{
vec3_t center;
vec3_t org;
vec3_t dir;
int r, i;
float u, v, z;
float temp;
qboolean can_see_me;
if (!(self->spawnflags & SF_WEATHER_FIRE_ONCE))
self->nextthink = level.time + FRAMETIME;
// Don't start raining until player is in the game. The following
// takes care of both initial map load conditions and restored saved games.
// This is a gross abuse of groundentity_linkcount. Sue me.
if (g_edicts[1].linkcount == self->groundentity_linkcount)
return;
else
self->groundentity_linkcount = g_edicts[1].linkcount;
// Don't spawn drops if player can't see us. This SEEMS like an obvious
// thing to do, but can cause visual problems if mapper isn't careful.
// For example, placing target_precipitation where it isn't in the PVS
// of the player's current position, but the result (rain) IS in the
// PVS. In any case, this step is necessary to prevent overflows when
// player suddenly encounters rain.
can_see_me = false;
for (i=1; i<=game.maxclients && !can_see_me; i++)
{
if (!g_edicts[i].inuse) continue;
if (gi.inPVS(g_edicts[i].s.origin,self->s.origin))
can_see_me = true;
}
if (!can_see_me) return;
// Count is models/second. We accumulate a probability of a model
// falling this frame in ->density. Yeah its a misnomer but density isn't
// used for anything else so it works fine.
temp = 0.1*(self->density + crandom()*self->random);
r = (int)(temp);
if (r > 0)
self->density = self->count;
else
self->density += (temp*10);
if (r < 1) return;
VectorAdd(self->bleft,self->tright,center);
VectorMA(self->s.origin,0.5,center,center);
for (i=0; i<r; i++)
{
u = crandom() * (self->tright[0] - self->bleft[0])/2;
v = crandom() * (self->tright[1] - self->bleft[1])/2;
z = crandom() * (self->tright[2] - self->bleft[2])/2;
VectorCopy(center, org);
org[0] += u;
org[1] += v;
org[2] += z;
VectorSubtract(org,self->s.origin,dir);
VectorNormalize(dir);
spawn_precipitation(self, self->s.origin, dir, self->speed);
}
}
void target_fountain_use (edict_t *ent, edict_t *other, edict_t *activator)
{
if ((ent->spawnflags & SF_WEATHER_STARTON) && !(ent->spawnflags & SF_WEATHER_FIRE_ONCE))
{
// already on; turn it off
ent->nextthink = 0;
ent->spawnflags &= ~SF_WEATHER_STARTON;
if (ent->child)
{
edict_t *child, *parent;
child = ent->child;
ent->child = NULL;
while (child)
{
parent = child;
child = parent->child;
G_FreeEdict(parent);
}
}
}
else
{
ent->density = ent->count;
ent->think = target_fountain_think;
ent->spawnflags |= SF_WEATHER_STARTON;
ent->think(ent);
}
}
void target_fountain_delayed_use (edict_t *self)
{
// Since target_fountain tends to be a processor hog,
// for START_ON we wait until the player has spawned into the
// game to ease the startup burden somewhat
if (g_edicts[1].linkcount)
{
self->think = target_fountain_think;
self->think(self);
}
else
self->nextthink = level.time + FRAMETIME;
}
void SP_target_fountain (edict_t *ent)
{
char *buffer;
size_t bufSize;
if (deathmatch->value || coop->value)
{
G_FreeEdict(ent);
return;
}
ent->class_id = ENTITY_TARGET_FOUNTAIN;
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
if (ent->spawnflags & SF_WEATHER_STARTON)
{
ent->think = target_fountain_delayed_use;
ent->nextthink = level.time + 1;
}
ent->style = STYLE_WEATHER_USER;
if (!ent->usermodel)
{
gi.dprintf("target_fountain with no usermodel.\n");
G_FreeEdict(ent);
return;
}
// Knightmare- check for "models/" or "sprites/" already in path
if ( strncmp(ent->usermodel, "models/", 7) && strncmp(ent->usermodel, "sprites/", 8) )
{
bufSize = strlen(ent->usermodel)+10;
buffer = gi.TagMalloc(bufSize, TAG_LEVEL);
if (strstr(ent->usermodel,".sp2"))
Com_sprintf(buffer, bufSize, "sprites/%s", ent->usermodel);
else
Com_sprintf(buffer, bufSize, "models/%s", ent->usermodel);
ent->usermodel = buffer;
}
if (st.gravity)
ent->gravity = atof(st.gravity);
else
ent->gravity = 0.0f;
ent->use = target_fountain_use;
if (!ent->count)
ent->count = 1;
if (!ent->sounds)
ent->sounds = 2; // blue splash
if (!ent->mass2)
ent->mass2 = 8; // 8 particles in splash
if (ent->speed <= 0)
ent->speed = 300;
if ((VectorLength(ent->bleft) == 0.) && (VectorLength(ent->tright) == 0.))
{
// Default distribution places raindrops vertically for
// full coverage, to help avoid "lumps"
VectorSet(ent->bleft,-32, -32, 64);
VectorSet(ent->tright,32, 32,128);
}
ent->density = ent->count;
gi.linkentity (ent);
}
//
/*=============================================================================
MISC_DEADSOLDIER MODEL PATCH
==============================================================================*/
#define NUM_SKINS 16
#define MAX_SKINNAME 64
#define DEADSOLDIER_MODEL "models/deadbods/dude/tris.md2"
#include "pak.h"
int PatchDeadSoldier (void)
{
cvar_t *gamedir;
char skins[NUM_SKINS][MAX_SKINNAME]; // skin entries
char infilename[MAX_OSPATH];
char outfilename[MAX_OSPATH];
char tempname[MAX_OSPATH];
int j;
// char *p;
FILE *infile;
FILE *outfile;
dmdl_t model; // model header
byte *data; // model data
int datasize; // model data size (bytes)
int newoffset; // model data offset (after skins)
// get game (moddir) name
gamedir = gi.cvar("game", "", 0);
if (!*gamedir->string)
return 0; // we're in baseq2
// Com_sprintf (outfilename, sizeof(outfilename), "%s/%s", gamedir->string,DEADSOLDIER_MODEL);
Com_sprintf (tempname, sizeof(tempname), DEADSOLDIER_MODEL);
SavegameDirRelativePath (tempname, outfilename, sizeof(outfilename));
if (outfile = fopen (outfilename, "rb"))
{
// output file already exists, move along
fclose (outfile);
// gi.dprintf ("PatchDeadSoldier: Could not save %s, file already exists\n", outfilename);
return 0;
}
for (j = 0; j < NUM_SKINS; j++)
memset (skins[j], 0, MAX_SKINNAME);
Com_sprintf (skins[0], sizeof(skins[0]), "models/deadbods/dude/dead1.pcx");
Com_sprintf (skins[1], sizeof(skins[1]), "players/male/cipher.pcx");
Com_sprintf (skins[2], sizeof(skins[2]), "players/male/claymore.pcx");
Com_sprintf (skins[3], sizeof(skins[3]), "players/male/flak.pcx");
Com_sprintf (skins[4], sizeof(skins[4]), "players/male/grunt.pcx");
Com_sprintf (skins[5], sizeof(skins[5]), "players/male/howitzer.pcx");
Com_sprintf (skins[6], sizeof(skins[6]), "players/male/major.pcx");
Com_sprintf (skins[7], sizeof(skins[7]), "players/male/nightops.pcx");
Com_sprintf (skins[8], sizeof(skins[8]), "players/male/pointman.pcx");
Com_sprintf (skins[9], sizeof(skins[9]), "players/male/psycho.pcx");
Com_sprintf (skins[10], sizeof(skins[10]), "players/male/rampage.pcx");
Com_sprintf (skins[11], sizeof(skins[11]), "players/male/razor.pcx");
Com_sprintf (skins[12], sizeof(skins[12]), "players/male/recon.pcx");
Com_sprintf (skins[13], sizeof(skins[13]), "players/male/scout.pcx");
Com_sprintf (skins[14], sizeof(skins[14]), "players/male/sniper.pcx");
Com_sprintf (skins[15], sizeof(skins[15]), "players/male/viper.pcx");
// load original model
Com_sprintf (infilename, sizeof(infilename), "baseq2/%s", DEADSOLDIER_MODEL);
if ( !(infile = fopen (infilename, "rb")) )
{
// If file doesn't exist on user's hard disk, it must be in
// pak0.pak
pak_header_t pakheader;
pak_item_t pakitem;
FILE *fpak;
int k, numitems;
fpak = fopen("baseq2/pak0.pak","rb");
if (!fpak)
{
cvar_t *cddir;
char pakfile[MAX_OSPATH];
cddir = gi.cvar("cddir", "", 0);
Com_sprintf(pakfile, sizeof(pakfile), "%s/baseq2/pak0.pak",cddir->string);
fpak = fopen(pakfile,"rb");
if (!fpak)
{
gi.dprintf("PatchDeadSoldier: Cannot find pak0.pak\n");
return 0;
}
}
fread(&pakheader,1,sizeof(pak_header_t),fpak);
numitems = pakheader.dsize/sizeof(pak_item_t);
fseek(fpak,pakheader.dstart,SEEK_SET);
data = NULL;
for (k=0; k<numitems && !data; k++)
{
fread(&pakitem,1,sizeof(pak_item_t),fpak);
if (!Q_stricmp(pakitem.name,DEADSOLDIER_MODEL))
{
fseek(fpak,pakitem.start,SEEK_SET);
fread(&model, sizeof(dmdl_t), 1, fpak);
datasize = model.ofs_end - model.ofs_skins;
if ( !(data = malloc (datasize)) ) // make sure freed locally
{
fclose(fpak);
gi.dprintf ("PatchDeadSoldier: Could not allocate memory for model\n");
return 0;
}
fread (data, sizeof (byte), datasize, fpak);
}
}
fclose(fpak);
if (!data)
{
gi.dprintf("PatchDeadSoldier: Could not find %s in baseq2/pak0.pak\n",DEADSOLDIER_MODEL);
return 0;
}
}
else
{
fread (&model, sizeof (dmdl_t), 1, infile);
datasize = model.ofs_end - model.ofs_skins;
if ( !(data = malloc (datasize)) ) // make sure freed locally
{
gi.dprintf ("PatchMonsterModel: Could not allocate memory for model\n");
return 0;
}
fread (data, sizeof (byte), datasize, infile);
fclose (infile);
}
// update model info
model.num_skins = NUM_SKINS;
// Already had 1 skin, so new offset doesn't include that one
// newoffset = (model.num_skins-1) * MAX_SKINNAME;
newoffset = model.num_skins * MAX_SKINNAME;
model.ofs_st += newoffset;
model.ofs_tris += newoffset;
model.ofs_frames += newoffset;
model.ofs_glcmds += newoffset;
model.ofs_end += newoffset;
// save new model
/* Com_sprintf (outfilename, sizeof(outfilename), "%s/models", gamedir->string); // make some dirs if needed
_mkdir (outfilename);
Com_strcat (outfilename, sizeof(outfilename), "/deadbods");
_mkdir (outfilename);
Com_strcat (outfilename, sizeof(outfilename), "/dude");
_mkdir (outfilename);
Com_sprintf (outfilename, sizeof(outfilename), "%s/%s", gamedir->string, DEADSOLDIER_MODEL);
p = strstr(outfilename,"/tris.md2");
*p = 0;
_mkdir (outfilename);
Com_sprintf (outfilename, sizeof(outfilename), "%s/%s", gamedir->string, DEADSOLDIER_MODEL);
*/
Com_sprintf (tempname, sizeof(tempname), DEADSOLDIER_MODEL);
SavegameDirRelativePath (tempname, outfilename, sizeof(outfilename));
CreatePath (outfilename);
if ( !(outfile = fopen (outfilename, "wb")) )
{
// file couldn't be created for some other reason
gi.dprintf ("PatchDeadSoldier: Could not save %s\n", outfilename);
free (data);
return 0;
}
fwrite (&model, sizeof (dmdl_t), 1, outfile);
// fwrite (skins, sizeof (char), model.num_skins*MAX_SKINNAME, outfile);
fwrite (skins, sizeof (char), newoffset, outfile);
// data += MAX_SKINNAME;
fwrite (data, sizeof (byte), datasize, outfile);
fclose (outfile);
gi.dprintf ("PatchDeadSoldier: Saved %s\n", outfilename);
free (data); // crashes here
return 1;
}

145
missionpack/g_misc_nm.c Normal file
View file

@ -0,0 +1,145 @@
// g_misc_nm.c
// misc entities for Neil Manke's Q2 maps
#include "g_local.h"
/*
=============================================================
Coconut Monkey 3 Flame entities
=============================================================
*/
#define FLAME_START_OFF 1
void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
void light_flame_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->solid == SOLID_NOT)
{
self->svflags &= ~SVF_NOCLIENT;
gi.configstring (CS_LIGHTS+self->style, "m");
self->spawnflags &= ~FLAME_START_OFF;
self->solid = SOLID_TRIGGER;
}
else
{
self->svflags |= SVF_NOCLIENT;
gi.configstring (CS_LIGHTS+self->style, "a");
self->spawnflags |= FLAME_START_OFF;
self->solid = SOLID_NOT;
}
gi.linkentity (self);
}
void light_flame_spawn (edict_t *self)
{
self->s.effects = EF_ANIM_ALLFAST;
self->s.renderfx |= RF_NOSHADOW;
self->movetype = MOVETYPE_NONE;
self->touch = hurt_touch;
if (!self->dmg)
self->dmg = 5;
self->noise_index = gi.soundindex ("world/electro.wav");
if (self->style >= 32)
{
if (self->spawnflags & FLAME_START_OFF)
{
gi.configstring (CS_LIGHTS+self->style, "a");
self->svflags |= SVF_NOCLIENT;
self->solid = SOLID_NOT;
}
else
{
gi.configstring (CS_LIGHTS+self->style, "m");
self->solid = SOLID_TRIGGER;
}
}
self->use = light_flame_use;
gi.linkentity (self);
}
void SP_light_flame1 (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame1.sp2");
VectorSet(self->mins,-48,-48,-32);
VectorSet(self->maxs, 48, 48, 64);
light_flame_spawn (self);
}
void SP_light_flame1s (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame1s.sp2");
VectorSet(self->mins,-16,-16,-16);
VectorSet(self->maxs, 16, 16, 32);
light_flame_spawn (self);
}
void SP_light_flame2 (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame2.sp2");
VectorSet(self->mins,-48,-48,-32);
VectorSet(self->maxs, 48, 48, 64);
light_flame_spawn (self);
}
void SP_light_flame2s (edict_t *self)
{
self->class_id = ENTITY_LIGHT_FLAME_CM;
self->s.modelindex = gi.modelindex ("sprites/s_flame2s.sp2");
VectorSet(self->mins,-16,-16,-16);
VectorSet(self->maxs, 16, 16, 32);
light_flame_spawn (self);
}
/*
=============================================================
Coconut Monkey
=============================================================
*/
void monster_coco_monkey_think (edict_t *self)
{
if (++self->s.frame > 19)
self->s.frame = 0;
self->nextthink = level.time + FRAMETIME;
}
void SP_monster_coco_monkey (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->movetype = MOVETYPE_TOSS;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex ("models/monsters/coco/tris.md2");
self->s.renderfx |= RF_IR_VISIBLE;
VectorSet(self->mins,-16,-16,-40);
VectorSet(self->maxs, 16, 16, 48);
self->s.origin[2] += 10;
self->nextthink = level.time + FRAMETIME;
self->think = monster_coco_monkey_think;
self->common_name = "Coconut Monkey";
self->class_id = ENTITY_MONSTER_COCO_MONKEY;
gi.linkentity (self);
}

563
missionpack/g_model.c Normal file
View file

@ -0,0 +1,563 @@
// g_model.c
#include "g_local.h"
/*
=============================
Spawning a user defined model
=============================
*/
//ed - added all these spawnflags and stuff
/*QUAKED model_spawn (1 0 0) (-8 -8 -8) (8 8 8) x TOGGLE NOT_IR PLAYER NO_MODEL ANIM_ONCE
Spawns a user defined model, you can specify whether its solid, if so how big the box is, and apply nearly
any effect to the entity.
Spawnflags:
TOGGLE Start active, when triggered become inactive
NOT_IR The model won't be tinted red when the player has IR goggles on
PLAYER Set this if you want to use a player model
NO_MODEL Don't use a model. Usefull for placing particle effects and dynamic lights on their own
ANIM__ONCE Only play the animation once
-----------------------
Key/Value pairs:
"style" Specifies the animation type to use.
0: None (unless startframe and framenumbers are used)
1: ANIM01 - cycle between frames 0 and 1 at 2 hz
2: ANIM23 - cycle between frames 2 and 3 at 2 hz
3: ANIM_ALL - cycle through all frames at 2 hz
4: ANIM_ALLFAST - cycle through all frames at 10 hz
Note: The animation flags override startframe and framenumbers settings you may have enterered. ANIM_ALL and ANIM_ALLFAST don't do what you might think - rather than setting a framerate, these apparently cause the model to cycle through its ENTIRE sequence of animations in 0.5 or 0.1 seconds... which for monster and player models is of course not possible. Looks exceptionally goofy.
"usermodel" The model to load (models/ is already coded)
"startframe" The starting frame : default 0
"framenumbers" The number of frames you want to display after startframe
"skinnum" The skin number to use, default 0
"health" If non-zero and solidstate is 3 or 4 (solid), the entity will be shootable. When destroyed, it blows up with a no-damage explosion.
"solidstate"
1 - not solid at all. These models do not obey any sort of physics. If you place them up in the air or embedded in a wall they will stay there and be perfectly happy about it.
2 - solid. These models will "droptofloor" when spawned. If the health value is set they may be damaged.
3 - solid. Same as above but not affected by gravity. Model will remain in the same location.
4 - not solid but affected by gravity. Model will "droptofloor" when spawned.
NOTE : if you want the model to be solid then you must enter vector values into the following fields :
"bleft" = the point that is at the bottom left of the models bounding box in a model editor
"tright" = the point that is at the top left of the models bounding box in a model editor
"effects"
1: ROTATE Rotate like a weapon
2: GIB
8: BLASTER Yellowish orange glow plus particles
16: ROCKET Rocket trail
32: GRENADE Grenade trail
64: HYPERBLASTER BLASTER w/o the particles
128: BFG Big green ball
256: COLOR_SHELL
512: POWERSCREEN Green power shield
16384: FLIES Ewwww
32768: QUAD Blue shell
65536: PENT Red shell
131072: TELEPORTER Teleporter particles
262144: FLAG1 Red glow
524288: FLAG2 Blue glow
1048576: IONRIPPER
2097152: GREENGIB
4194304: BLUE_HB Blue hyperblaster glow
8388608: SPINNING_LIGHTS Red spinning lights
16777216: PLASMA
33554432: TRAP
67108864: TRACKER
134217728: DOUBLE Yellow shell
268435456: SPHERETRANS Transparent
536870912: TAGTRAIL
1073741824: HALF_DAMAGE
2147483648: TRACKER_TRAIL
"renderfx"
1: MINLIGHT Never completely dark
2: VIEWERMODEL
4: WEAPONMODEL
8: FULLBRIGHT
16: DEPTHHACK
32: TRANSLUCENT Transparent
64: FRAMELERP
128: BEAM
512: GLOW Pulsating glow of normal Q2 pickup items
1024: SHELL_RED
2048: SHELL_GREEN
4096: SHELL_BLUE
32768: IR_VISIBLE
65536: SHELL_DOUBLE
131072: SHELL_HALF_DAMAGE White shell
262144: USE_DISGUISE
"movewith" Targetname of the entity to move with
*/
#define TOGGLE 2
#define NOT_IR 4
#define PLAYER_MODEL 8
#define NO_MODEL 16
#define ANIM_ONCE 32
void model_spawn_use (edict_t *self, edict_t *other, edict_t *activator);
void modelspawn_think (edict_t *self)
{
self->s.frame++;
if (self->s.frame >= self->framenumbers)
{
self->s.frame = self->startframe;
if (self->spawnflags & ANIM_ONCE)
{
model_spawn_use(self,world,world);
return;
}
}
self->nextthink = level.time + FRAMETIME;
gi.linkentity(self);
if (!strcmp(self->classname, "model_train"))
train_move_children (self);
}
void model_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
{
if (self->delay) // we started off
{
self->svflags &= ~SVF_NOCLIENT;
self->delay = 0;
if (self->framenumbers > 1)
{
self->think = modelspawn_think;
self->nextthink = level.time + FRAMETIME;
}
self->s.sound = self->noise_index;
#ifdef LOOP_SOUND_ATTENUATION
self->s.attenuation = self->attenuation;
#endif
}
else // we started active
{
self->svflags |= SVF_NOCLIENT;
self->delay = 1;
self->use = model_spawn_use;
self->think = NULL;
self->nextthink = 0;
self->s.sound = 0;
}
}
void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
if (self->deathtarget)
{
self->target = self->deathtarget;
G_UseTargets (self, attacker);
}
train_kill_children(self);
BecomeExplosion1(self);
}
#define ANIM_MASK (EF_ANIM01|EF_ANIM23|EF_ANIM_ALL|EF_ANIM_ALLFAST)
void SP_model_spawn (edict_t *ent)
{
char modelname[256];
// paranoia check
if ((!ent->usermodel) && (!ent->spawnflags & NO_MODEL) && !(ent->spawnflags & PLAYER_MODEL))
{
gi.dprintf("%s without a model and without NO_MODEL spawnflag at %s\n", ent->classname, vtos(ent->s.origin));
G_FreeEdict(ent);
return;
}
ent->class_id = ENTITY_MODEL_SPAWN;
switch (ent->solidstate)
{
case 1 : ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_NONE; break;
case 2 : ent->solid = SOLID_BBOX; ent->movetype = MOVETYPE_TOSS; break;
case 3 : ent->solid = SOLID_BBOX; ent->movetype = MOVETYPE_NONE; break;
case 4 : ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_TOSS; break;
default: ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_NONE; break;
}
if (ent->solid != SOLID_NOT )
{
if (ent->health > 0)
{
ent->die = model_die;
ent->takedamage = DAMAGE_YES;
}
}
switch (ent->style)
{
case 1 : ent->s.effects |= EF_ANIM01; break;
case 2 : ent->s.effects |= EF_ANIM23; break;
case 3 : ent->s.effects |= EF_ANIM_ALL; break;
case 4 : ent->s.effects |= EF_ANIM_ALLFAST; break;
}
// DWH: Rather than use one value (renderfx) we use the
// actual values for effects and renderfx. All may
// be combined.
ent->s.effects |= ent->effects;
ent->s.renderfx |= ent->renderfx;
if (ent->startframe < 0)
ent->startframe = 0;
if (!ent->framenumbers)
ent->framenumbers = 1;
// Change framenumbers to last frame to play
ent->framenumbers += ent->startframe;
if (!VectorLength(ent->bleft) && ent->solid == SOLID_BBOX)
{
gi.dprintf("%s solid with no bleft vector at %s, using default (-16,-16,-16)\n", ent->classname, vtos(ent->s.origin));
VectorSet(ent->bleft, -16, -16, -16);
}
VectorCopy (ent->bleft, ent->mins);
if (!VectorLength(ent->tright) && ent->solid == SOLID_BBOX)
{
gi.dprintf("%s solid with no tright vector at %, using default (16,16,16)\n", ent->classname, vtos(ent->s.origin));
VectorSet(ent->tright, 16, 16, 16);
}
VectorCopy (ent->tright, ent->maxs);
if (ent->solid != SOLID_NOT)
ent->clipmask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER;
if (ent->spawnflags & NO_MODEL)
{ // For rendering effects to work, we MUST use a model
ent->s.modelindex = gi.modelindex ("sprites/point.sp2");
ent->movetype = MOVETYPE_NOCLIP;
}
else
{
if (ent->spawnflags & PLAYER_MODEL)
{
if (!ent->usermodel || !strlen(ent->usermodel))
ent->s.modelindex = MAX_MODELS-1; //was 255
else
{
if (strstr(ent->usermodel,"tris.md2"))
Com_sprintf(modelname, sizeof(modelname), "players/%s", ent->usermodel);
else
Com_sprintf(modelname, sizeof(modelname), "players/%s/tris.md2", ent->usermodel);
ent->s.modelindex = gi.modelindex(modelname);
}
}
else
{
if (strstr(ent->usermodel,".sp2")) {
// Knightmare- check for "sprites/" already in path
if ( !strncmp(ent->usermodel, "sprites/", 8) )
Com_sprintf(modelname, sizeof(modelname), "%s", ent->usermodel);
else
Com_sprintf(modelname, sizeof(modelname), "sprites/%s", ent->usermodel);
}
else {
// Knightmare- check for "models/" already in path
if ( !strncmp(ent->usermodel, "models/", 7) )
Com_sprintf(modelname, sizeof(modelname), "%s", ent->usermodel);
else
Com_sprintf(modelname, sizeof(modelname), "models/%s", ent->usermodel);
}
ent->s.modelindex = gi.modelindex (modelname);
}
if (ent->startframe < 0)
{
gi.dprintf("model_spawn with startframe less than 0 at %s\n", vtos(ent->s.origin));
ent->startframe = 0;
}
ent->s.frame = ent->startframe;
}
if (st.noise)
ent->noise_index = gi.soundindex (st.noise);
//ent->s.sound = ent->noise_index;
#ifdef LOOP_SOUND_ATTENUATION
ent->s.attenuation = ent->attenuation;
#endif
if (ent->skinnum) // Knightmare- selectable skin
ent->s.skinnum = ent->skinnum;
if (ent->spawnflags & ANIM_ONCE)
ent->spawnflags |= TOGGLE;
if (ent->spawnflags & TOGGLE)
{ // Knightmare- allow starting off (but not for model_train)
if ( (strcmp(ent->classname, "model_train") != 0) && (ent->delay != 0) ) {
ent->delay = 1;
ent->svflags |= SVF_NOCLIENT;
}
else {
ent->delay = 0;
}
ent->use = model_spawn_use;
}
if (!(ent->s.effects & ANIM_MASK) && (ent->framenumbers > 1))
{
ent->think = modelspawn_think;
ent->nextthink = level.time + 2*FRAMETIME;
}
if (ent->spawnflags & NOT_IR)
ent->s.renderfx &= ~RF_IR_VISIBLE;
else
ent->s.renderfx |= RF_IR_VISIBLE;
gi.linkentity (ent);
}
/*QUAKED model_train (1 0 0) (-8 -8 -8) (8 8 8) START_ON TOGGLE BLOCK_STOPS PLAYER NO_MODEL ROTATE ROT_CONST SMOOTH
A moving model. The "team" key allows you to team train entities together.
Spawnflags:
PLAYER Set this if you want to use a player model
NO_MODEL Don't use a model. Usefull for placing particle effects and dynamic lights on their own
SPLINE: If set, the func_train will follow a spline curve between path_corners. What this means is you can create near perfectly smooth curvilinear paths with a handful of path_corners. The train will constantly turn to face the direction it is moving (unless yaw_speed and pitch_speed are negative values). For a couple of examples, see the rottrain and lcraft example maps (available on the downloads page.) The shape of the spline curve is controlled by the location and pitch and yaw angles of the train's path_corners. Train roll angle will vary linearly between path_corner roll angle values (the third component of the angles vector).
-----------------------
Key/Value pairs:
"style" Specifies the animation type to use.
0: None (unless startframe and framenumbers are used)
1: ANIM01 - cycle between frames 0 and 1 at 2 hz
2: ANIM23 - cycle between frames 2 and 3 at 2 hz
3: ANIM_ALL - cycle through all frames at 2 hz
4: ANIM_ALLFAST - cycle through all frames at 10 hz
Note: The animation flags override startframe and framenumbers settings you may have enterered. ANIM_ALL and ANIM_ALLFAST don't do what you might think - rather than setting a framerate, these apparently cause the model to cycle through its ENTIRE sequence of animations in 0.5 or 0.1 seconds... which for monster and player models is of course not possible. Looks exceptionally goofy.
"usermodel" The model to load (models/ is already coded)
"startframe" The starting frame : default 0
"framenumbers" The number of frames you want to display after startframe
"skinnum" The skin number to use, default 0
"health" If non-zero and solidstate is 3 or 4 (solid), the entity will be shootable. When destroyed, it blows up with a no-damage explosion.
"target" first path_corner"
"team" func_train or func_rotating
"solidstate"
1 = Not solid (default)
2 = Bounding box
NOTE : if you want the model to be solid then you must enter vector values into the following fields :
"bleft" = the point that is at the bottom left of the models bounding box in a model editor
"tright" = the point that is at the top left of the models bounding box in a model editor
"speed" How fast the model should move
"accel" Acceleration
"decel" Deceleration
"pitch_speed" (Nose up & Down) in degrees per second (defualt 20)
"yaw_speed" (Side-to-side "wiggle") in degrees per second (default 20)
"roll_speed" (Banking) in degrees per second toward the next path corner's set roll
"dmg" default 2, damage to inflict when blocked
"noise" Sound model makes while moving(path/file.wav)
"effects"
1: ROTATE Rotate like a weapon
2: GIB
8: BLASTER Yellowish orange glow plus particles
16: ROCKET Rocket trail
32: GRENADE Grenade trail
64: HYPERBLASTER BLASTER w/o the particles
128: BFG Big green ball
256: COLOR_SHELL
512: POWERSCREEN Green power shield
16384: FLIES Ewwww
32768: QUAD Blue shell
65536: PENT Red shell
131072: TELEPORTER Teleporter particles
262144: FLAG1 Red glow
524288: FLAG2 Blue glow
1048576: IONRIPPER
2097152: GREENGIB
4194304: BLUE_HB Blue hyperblaster glow
8388608: SPINNING_LIGHTS Red spinning lights
16777216: PLASMA
33554432: TRAP
67108864: TRACKER
134217728: DOUBLE Yellow shell
268435456: SPHERETRANS Transparent
536870912: TAGTRAIL
1073741824: HALF_DAMAGE
2147483648: TRACKER_TRAIL
"renderfx"
1: MINLIGHT Never completely dark
2: VIEWERMODEL
4: WEAPONMODEL
8: FULLBRIGHT
16: DEPTHHACK
32: TRANSLUCENT Transparent
64: FRAMELERP
128: BEAM
512: GLOW Pulsating glow of normal Q2 pickup items
1024: SHELL_RED
2048: SHELL_GREEN
4096: SHELL_BLUE
32768: IR_VISIBLE
65536: SHELL_DOUBLE
131072: SHELL_HALF_DAMAGE White shell
262144: USE_DISGUISE
To have other entities move with the model train, set the door pieces' movewith values to the same as the train's targetname and they will move in
unison, and also still be able to move relative to the train themselves, and can be attached and detached using target_movewith.
NOTE: All the pieces must be created after the model train entity, otherwise they will move ahead of it.
*/
#define MODEL_TRAIN_START_ON 1
#define MODEL_TRAIN_TOGGLE 2
#define MODEL_TRAIN_BLOCK_STOPS 4
#define MODEL_TRAIN_ROTATE 32
#define MODEL_TRAIN_ROT_CONST 64
#define TRAIN_ANIM 32
#define TRAIN_ANIM_FAST 64
#define MODEL_TRAIN_SMOOTH 128
#define TRAIN_ROTATE 8
#define TRAIN_ROT_CONST 16
#define TRAIN_SPLINE 8192
void model_train_animator(edict_t *animator)
{
edict_t *train;
train = animator->owner;
if (!train || !train->inuse)
{
G_FreeEdict(animator);
return;
}
if (Q_stricmp(train->classname, "model_train"))
{
G_FreeEdict(animator);
return;
}
animator->nextthink = level.time + FRAMETIME;
if (VectorLength(train->velocity) == 0)
return;
train->s.frame++;
if (train->s.frame >= train->framenumbers)
train->s.frame = train->startframe;
gi.linkentity(train);
}
void SP_model_train (edict_t *self)
{
SP_model_spawn (self);
self->class_id = ENTITY_MODEL_TRAIN;
// Reset s.sound, which SP_model_spawn may have turned on
self->moveinfo.sound_middle = self->s.sound;
self->s.sound = 0;
if (!self->inuse) return;
// Reset some things from SP_model_spawn
self->delay = 0;
self->think = NULL;
self->nextthink = 0;
self->s.sound = self->noise_index;
if (self->health)
{
self->die = model_die;
self->takedamage = DAMAGE_YES;
}
if (self->framenumbers > self->startframe+1)
{
edict_t *animator;
animator = G_Spawn();
animator->owner = self;
animator->think = model_train_animator;
animator->nextthink = level.time + FRAMETIME;
}
self->s.frame = self->startframe;
self->movetype = MOVETYPE_PUSH;
// Really gross stuff here... translate model_spawn spawnflags
// to func_train spawnflags. PLAYER_MODEL and NO_MODEL have
// already been checked in SP_model_spawn and are never re-used,
// so it's OK to overwrite those.
if (self->spawnflags & MODEL_TRAIN_ROTATE)
{
self->spawnflags &= ~MODEL_TRAIN_ROTATE;
self->spawnflags |= TRAIN_ROTATE;
}
if (self->spawnflags & MODEL_TRAIN_ROT_CONST)
{
self->spawnflags &= ~MODEL_TRAIN_ROT_CONST;
self->spawnflags |= TRAIN_ROT_CONST;
}
//Knightmare- change both rotate flags to spline flag
if ((self->spawnflags & TRAIN_ROTATE) && (self->spawnflags &TRAIN_ROT_CONST))
{
self->spawnflags &= ~TRAIN_ROTATE;
self->spawnflags &= ~TRAIN_ROT_CONST;
self->spawnflags |= TRAIN_SPLINE;
}
if (self->style == 3)
self->spawnflags |= TRAIN_ANIM; // 32
if (self->style == 4)
self->spawnflags |= TRAIN_ANIM_FAST; // 64
// TRAIN_SMOOTH forces trains to go directly to Move_Done from
// Move_Final rather than slowing down (if necessary) for one
// frame.
if (self->spawnflags & MODEL_TRAIN_SMOOTH)
self->smooth_movement = 1;
else
self->smooth_movement = 0;
self->blocked = train_blocked;
if (self->spawnflags & MODEL_TRAIN_BLOCK_STOPS)
self->dmg = 0;
else
{
if (!self->dmg)
self->dmg = 100;
}
if (!self->speed)
self->speed = 100;
// Mappack
if (!self->accel)
self->moveinfo.accel = self->speed;
else
self->moveinfo.accel = self->accel;
if (!self->decel)
self->moveinfo.decel = self->speed;
else
self->moveinfo.decel = self->decel;
self->moveinfo.speed = self->speed;
self->use = train_use;
gi.linkentity (self);
if (self->target)
{
// start trains on the second frame, to make sure their targets have had
// a chance to spawn
self->nextthink = level.time + FRAMETIME;
self->think = func_train_find;
}
else
gi.dprintf ("model_train without a target at %s\n", vtos(self->s.origin));
}
void SP_model_train_origin (edict_t *self)
{
self->spawnflags |= TRAIN_ORIGIN;
SP_model_train (self);
}

File diff suppressed because it is too large Load diff

3176
missionpack/g_target_laz.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -711,7 +711,7 @@ void G_FreeEdict (edict_t *ed)
}*/
if (ed->speaker) // recursively remove train's speaker entity
G_FreeEdict(ed->speaker);
G_FreeEdict (ed->speaker);
// Knightmare- stop target_playback
if (ed->classname && (strlen(ed->classname) > 0) && !strcmp(ed->classname, "target_playback"))

View file

@ -737,7 +737,7 @@ void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int s
VectorScale (aimdir, speed, grenade->velocity);
VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
//Knightmare- add player's base velocity to grenade
// Knightmare- add player's base velocity to grenade
if (add_velocity_throw->value && self->client)
VectorAdd (grenade->velocity, self->velocity, grenade->velocity);
else if (self->groundentity)

View file

@ -363,7 +363,7 @@ void dog_dead (edict_t *self)
M_FlyCheck (self);
// Lazarus monster fade
if(world->effects & FX_WORLDSPAWN_CORPSEFADE)
if (world->effects & FX_WORLDSPAWN_CORPSEFADE)
{
self->think = FadeDieSink;
self->nextthink = level.time+corpse_fadetime->value;
@ -425,7 +425,7 @@ void dog_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage,
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
if(random() < 0.5)
if (random() < 0.5)
self->monsterinfo.currentmove = &dog_move_death1;
else
self->monsterinfo.currentmove = &dog_move_death2;
@ -452,6 +452,9 @@ void SP_monster_dog (edict_t *self)
sound_attack = gi.soundindex ("dog/dattack1.wav");
sound_sight = gi.soundindex ("dog/dsight.wav");
sound_idle = gi.soundindex ("dog/idle.wav");
// precache gibs
gi.modelindex ("mmodels/monsters/dog/h_dog.md2");
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
@ -467,11 +470,11 @@ void SP_monster_dog (edict_t *self)
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 8);
if(!self->health)
if (!self->health)
self->health = 50;
if(!self->gib_health)
if (!self->gib_health)
self->gib_health = -100;
if(!self->mass)
if (!self->mass)
self->mass = 80;
self->pain = dog_pain;

View file

@ -1,5 +1,5 @@
// Generated by ModelEd
// DOG
// Dog
#define FRAME_attack1 0
#define FRAME_attack2 1

View file

@ -1,3 +1,4 @@
// Generated by ModelEd
// FREDDIE
#define FRAME_run1 0

View file

@ -31,25 +31,25 @@
#define FRAME_perch28 27
#define FRAME_perch29 28
#define FRAME_perch30 29
#define FRAME_walk1 30
#define FRAME_walk2 31
#define FRAME_walk3 32
#define FRAME_walk4 33
#define FRAME_walk5 34
#define FRAME_walk6 35
#define FRAME_walk7 36
#define FRAME_walk8 37
#define FRAME_walk9 38
#define FRAME_walk1 30
#define FRAME_walk2 31
#define FRAME_walk3 32
#define FRAME_walk4 33
#define FRAME_walk5 34
#define FRAME_walk6 35
#define FRAME_walk7 36
#define FRAME_walk8 37
#define FRAME_walk9 38
#define FRAME_walk10 39
#define FRAME_soar1 40
#define FRAME_soar2 41
#define FRAME_soar3 42
#define FRAME_soar4 43
#define FRAME_soar5 44
#define FRAME_soar6 45
#define FRAME_soar7 46
#define FRAME_soar8 47
#define FRAME_soar9 48
#define FRAME_soar1 40
#define FRAME_soar2 41
#define FRAME_soar3 42
#define FRAME_soar4 43
#define FRAME_soar5 44
#define FRAME_soar6 45
#define FRAME_soar7 46
#define FRAME_soar8 47
#define FRAME_soar9 48
#define FRAME_soar10 49
#define FRAME_soar11 50
#define FRAME_soar12 51
@ -83,18 +83,18 @@
#define FRAME_soar40 79
#define FRAME_soar41 80
#define FRAME_soar42 81
#define FRAME_pain1 82
#define FRAME_pain2 83
#define FRAME_pain3 84
#define FRAME_pain4 85
#define FRAME_pain1 82
#define FRAME_pain2 83
#define FRAME_pain3 84
#define FRAME_pain4 85
#define FRAME_soarpain1 86
#define FRAME_soarpain2 87
#define FRAME_soarpain3 88
#define FRAME_soarpain4 89
#define FRAME_die1 90
#define FRAME_die2 91
#define FRAME_die3 92
#define FRAME_die4 93
#define FRAME_die1 90
#define FRAME_die2 91
#define FRAME_die3 92
#define FRAME_die4 93
#define FRAME_soardie1 94
#define FRAME_soardie2 95
#define FRAME_soardie3 96
@ -118,74 +118,74 @@
#define FRAME_soardie21 114
#define FRAME_soardie22 115
#define FRAME_soardie23 116
#define FRAME_soardie24 117
#define FRAME_soardie25 118
#define FRAME_soardie26 119
#define FRAME_soardie27 120
#define FRAME_soardie28 121
#define FRAME_soardie29 122
#define FRAME_soardie30 123
#define FRAME_takeoff1 124
#define FRAME_takeoff2 125
#define FRAME_takeoff3 126
#define FRAME_takeoff4 127
#define FRAME_takeoff5 128
#define FRAME_takeoff6 129
#define FRAME_fly1 130
#define FRAME_fly2 131
#define FRAME_fly3 132
#define FRAME_fly4 133
#define FRAME_fly5 134
#define FRAME_melee1 135
#define FRAME_melee2 136
#define FRAME_melee3 137
#define FRAME_melee4 138
#define FRAME_land1 139
#define FRAME_land2 140
#define FRAME_land3 141
#define FRAME_land4 142
#define FRAME_land5 143
#define FRAME_land6 144
#define FRAME_land7 145
#define FRAME_land8 146
#define FRAME_land9 147
#define FRAME_land10 148
#define FRAME_land11 149
#define FRAME_land12 150
#define FRAME_land13 151
#define FRAME_skin 152
#define FRAME_bankR1 153
#define FRAME_bankR2 154
#define FRAME_bankR3 155
#define FRAME_bankR4 156
#define FRAME_bankR5 157
#define FRAME_bankR6 158
#define FRAME_bankR7 159
#define FRAME_bankR8 160
#define FRAME_bankR9 161
#define FRAME_bankR10 162
#define FRAME_bankL1 163
#define FRAME_bankL2 164
#define FRAME_bankL3 165
#define FRAME_bankL4 166
#define FRAME_bankL5 167
#define FRAME_bankL6 168
#define FRAME_bankL7 169
#define FRAME_bankL8 170
#define FRAME_bankL9 171
#define FRAME_bankL10 172
#define FRAME_TEMPLATE1 173
#define FRAME_soardie24 117
#define FRAME_soardie25 118
#define FRAME_soardie26 119
#define FRAME_soardie27 120
#define FRAME_soardie28 121
#define FRAME_soardie29 122
#define FRAME_soardie30 123
#define FRAME_takeoff1 124
#define FRAME_takeoff2 125
#define FRAME_takeoff3 126
#define FRAME_takeoff4 127
#define FRAME_takeoff5 128
#define FRAME_takeoff6 129
#define FRAME_fly1 130
#define FRAME_fly2 131
#define FRAME_fly3 132
#define FRAME_fly4 133
#define FRAME_fly5 134
#define FRAME_melee1 135
#define FRAME_melee2 136
#define FRAME_melee3 137
#define FRAME_melee4 138
#define FRAME_land1 139
#define FRAME_land2 140
#define FRAME_land3 141
#define FRAME_land4 142
#define FRAME_land5 143
#define FRAME_land6 144
#define FRAME_land7 145
#define FRAME_land8 146
#define FRAME_land9 147
#define FRAME_land10 148
#define FRAME_land11 149
#define FRAME_land12 150
#define FRAME_land13 151
#define FRAME_skin 152
#define FRAME_bankR1 153
#define FRAME_bankR2 154
#define FRAME_bankR3 155
#define FRAME_bankR4 156
#define FRAME_bankR5 157
#define FRAME_bankR6 158
#define FRAME_bankR7 159
#define FRAME_bankR8 160
#define FRAME_bankR9 161
#define FRAME_bankR10 162
#define FRAME_bankL1 163
#define FRAME_bankL2 164
#define FRAME_bankL3 165
#define FRAME_bankL4 166
#define FRAME_bankL5 167
#define FRAME_bankL6 168
#define FRAME_bankL7 169
#define FRAME_bankL8 170
#define FRAME_bankL9 171
#define FRAME_bankL10 172
#define FRAME_TEMPLATE1 173
#define FRAME_perchSAFE1 174
#define FRAME_flySAFE1 175
#define FRAME_flySAFE2 176
#define FRAME_flySAFE3 177
#define FRAME_flySAFE4 178
#define FRAME_flySAFE5 179
#define FRAME_flySAFE6 180
#define FRAME_flySAFE7 181
#define FRAME_flySAFE8 182
#define FRAME_flySAFE9 183
#define FRAME_flySAFE10 184
#define FRAME_flySAFE1 175
#define FRAME_flySAFE2 176
#define FRAME_flySAFE3 177
#define FRAME_flySAFE4 178
#define FRAME_flySAFE5 179
#define FRAME_flySAFE6 180
#define FRAME_flySAFE7 181
#define FRAME_flySAFE8 182
#define FRAME_flySAFE9 183
#define FRAME_flySAFE10 184
#define FRAME_takeoffSAFE1 185
#define FRAME_takeoffSAFE2 186
#define FRAME_takeoffSAFE3 187

View file

@ -169,10 +169,22 @@ SOURCE=.\g_misc.c
# End Source File
# Begin Source File
SOURCE=.\g_misc_laz.c
# End Source File
# Begin Source File
SOURCE=.\g_misc_nm.c
# End Source File
# Begin Source File
SOURCE=.\g_misc_q1.c
# End Source File
# Begin Source File
SOURCE=.\g_model.c
# End Source File
# Begin Source File
SOURCE=.\g_monster.c
# End Source File
# Begin Source File
@ -245,6 +257,10 @@ SOURCE=.\g_target.c
# End Source File
# Begin Source File
SOURCE=.\g_target_laz.c
# End Source File
# Begin Source File
SOURCE=.\g_thing.c
# End Source File
# Begin Source File

View file

@ -491,10 +491,22 @@
RelativePath="g_misc.c"
>
</File>
<File
RelativePath=".\g_misc_laz.c"
>
</File>
<File
RelativePath=".\g_misc_nm.c"
>
</File>
<File
RelativePath=".\g_misc_q1.c"
>
</File>
<File
RelativePath=".\g_model.c"
>
</File>
<File
RelativePath="g_monster.c"
>
@ -567,6 +579,10 @@
RelativePath="g_target.c"
>
</File>
<File
RelativePath=".\g_target_laz.c"
>
</File>
<File
RelativePath="g_thing.c"
>

View file

@ -923,7 +923,7 @@ void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
// Knightmare- the missing quadfire sounds
if (ent->client->quadfire_framenum > level.framenum)
gi.sound(ent, CHAN_ITEM, gi.soundindex("items/quadfire3.wav"), 1, ATTN_NORM, 0);
fire (ent, ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK2) );
fire (ent, ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK2));
break;
}
}
@ -1438,7 +1438,7 @@ ROCKET
======================================================================
*/
edict_t *rocket_target(edict_t *self, vec3_t start, vec3_t forward)
edict_t *rocket_target (edict_t *self, vec3_t start, vec3_t forward)
{
float bd, d;
int i;