123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- // leave this line at the top for all g_xxxx.cpp files...
- #include "g_headers.h"
- #include "g_local.h"
- #include "g_functions.h"
- #include "bg_public.h"
- extern cvar_t *g_spskill;
- //
- // Helper functions
- //
- //------------------------------------------------------------
- void SetMiscModelModels( char *modelNameString, gentity_t *ent, qboolean damage_model )
- {
- char damageModel[MAX_QPATH];
- char chunkModel[MAX_QPATH];
- int len;
- //Main model
- ent->s.modelindex = G_ModelIndex( modelNameString );
- if ( damage_model )
- {
- len = strlen( modelNameString ) - 4; // extract the extension
- //Dead/damaged model
- strncpy( damageModel, modelNameString, len );
- damageModel[len] = 0;
- strncpy( chunkModel, damageModel, sizeof(chunkModel));
- strcat( damageModel, "_d1.md3" );
- ent->s.modelindex2 = G_ModelIndex( damageModel );
- ent->spawnflags |= 4; // deadsolid
- //Chunk model
- strcat( chunkModel, "_c1.md3" );
- ent->s.modelindex3 = G_ModelIndex( chunkModel );
- }
- }
- //------------------------------------------------------------
- void SetMiscModelDefaults( gentity_t *ent, useFunc_t use_func, char *material, int solid_mask,int animFlag,
- qboolean take_damage, qboolean damage_model = qfalse )
- {
- // Apply damage and chunk models if they exist
- SetMiscModelModels( ent->model, ent, damage_model );
- ent->s.eFlags = animFlag;
- ent->svFlags |= SVF_PLAYER_USABLE;
- ent->contents = solid_mask;
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
- gi.linkentity (ent);
- // Set a generic use function
-
- ent->e_UseFunc = use_func;
- /* if (use_func == useF_health_use)
- {
- G_SoundIndex("sound/player/suithealth.wav");
- }
- else if (use_func == useF_ammo_use )
- {
- G_SoundIndex("sound/player/suitenergy.wav");
- }
- */
- G_SpawnInt( "material", material, (int *)&ent->material );
-
- if (ent->health)
- {
- ent->max_health = ent->health;
- ent->takedamage = take_damage;
- ent->e_PainFunc = painF_misc_model_breakable_pain;
- ent->e_DieFunc = dieF_misc_model_breakable_die;
- }
- }
- void HealthStationSettings(gentity_t *ent)
- {
- G_SpawnInt( "count", "0", &ent->count );
- if (!ent->count)
- {
- switch (g_spskill->integer)
- {
- case 0: // EASY
- ent->count = 100;
- break;
- case 1: // MEDIUM
- ent->count = 75;
- break;
- default :
- case 2: // HARD
- ent->count = 50;
- break;
- }
- }
- }
- void CrystalAmmoSettings(gentity_t *ent)
- {
- G_SpawnInt( "count", "0", &ent->count );
- if (!ent->count)
- {
- switch (g_spskill->integer)
- {
- case 0: // EASY
- ent->count = 75;
- break;
- case 1: // MEDIUM
- ent->count = 75;
- break;
- default :
- case 2: // HARD
- ent->count = 75;
- break;
- }
- }
- }
- //------------------------------------------------------------
- //------------------------------------------------------------
- /*QUAKED misc_model_ghoul (1 0 0) (-16 -16 -37) (16 16 32)
- "model" arbitrary .glm file to display
- "health" - how much health the model has - default 60 (zero makes non-breakable)
- */
- //------------------------------------------------------------
- #include "anims.h"
- extern int G_ParseAnimFileSet( const char *skeletonName, const char *modelName=0);
- int temp_animFileIndex;
- void set_MiscAnim( gentity_t *ent)
- {
- animation_t *animations = level.knownAnimFileSets[temp_animFileIndex].animations;
- if (ent->playerModel & 1)
- {
- int anim = BOTH_STAND3;
- float animSpeed = 50.0f / animations[anim].frameLerp;
- // yes, its the same animation, so work out where we are in the leg anim, and blend us
- gi.G2API_SetBoneAnim(&ent->ghoul2[0], "model_root", animations[anim].firstFrame,
- (animations[anim].numFrames -1 )+ animations[anim].firstFrame,
- BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND , animSpeed, (cg.time?cg.time:level.time), -1, 350);
- }
- else
- {
- int anim = BOTH_PAIN3;
- float animSpeed = 50.0f / animations[anim].frameLerp;
- gi.G2API_SetBoneAnim(&ent->ghoul2[0], "model_root", animations[anim].firstFrame,
- (animations[anim].numFrames -1 )+ animations[anim].firstFrame,
- BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND, animSpeed, (cg.time?cg.time:level.time), -1, 350);
- }
- ent->nextthink = level.time + 900;
- ent->playerModel++;
- }
- void SP_misc_model_ghoul( gentity_t *ent )
- {
- #if 1
- ent->s.modelindex = G_ModelIndex( ent->model );
- gi.G2API_InitGhoul2Model(ent->ghoul2, ent->model, ent->s.modelindex);
- ent->s.radius = 50;
- #else
- char name1[200] = "models/players/kyle/model.glm";
- ent->s.modelindex = G_ModelIndex( name1 );
- gi.G2API_InitGhoul2Model(ent->ghoul2, name1, ent->s.modelindex);
- ent->s.radius = 150;
- // we found the model ok - load it's animation config
- temp_animFileIndex = G_ParseAnimFileSet("_humanoid", "kyle");
- if ( temp_animFileIndex<0 )
- {
- Com_Printf( S_COLOR_RED"Failed to load animation file set models/players/jedi/animation.cfg\n");
- }
-
- ent->s.angles[0] = 0;
- ent->s.angles[1] = 90;
- ent->s.angles[2] = 0;
- ent->s.origin[2] = 20;
- ent->s.origin[1] = 80;
- // ent->s.modelScale[0] = ent->s.modelScale[1] = ent->s.modelScale[2] = 0.8f;
- VectorSet (ent->mins, -16, -16, -37);
- VectorSet (ent->maxs, 16, 16, 32);
- //#if _DEBUG
- //loadsavecrash
- // VectorCopy(ent->mins, ent->s.mins);
- // VectorCopy(ent->maxs, ent->s.maxs);
- //#endif
- ent->contents = CONTENTS_BODY;
- ent->clipmask = MASK_NPCSOLID;
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
- ent->health = 1000;
- // ent->s.modelindex = G_ModelIndex( "models/weapons2/blaster_r/g2blaster_w.glm" );
- // gi.G2API_InitGhoul2Model(ent->ghoul2, "models/weapons2/blaster_r/g2blaster_w.glm", ent->s.modelindex);
- // gi.G2API_AddBolt(&ent->ghoul2[0], "*weapon");
- // gi.G2API_AttachG2Model(&ent->ghoul2[1],&ent->ghoul2[0], 0, 0);
- gi.linkentity (ent);
- animation_t *animations = level.knownAnimFileSets[temp_animFileIndex].animations;
- int anim = BOTH_STAND3;
- float animSpeed = 50.0f / animations[anim].frameLerp;
- gi.G2API_SetBoneAnim(&ent->ghoul2[0], "model_root", animations[anim].firstFrame,
- (animations[anim].numFrames -1 )+ animations[anim].firstFrame,
- BONE_ANIM_OVERRIDE_FREEZE , animSpeed, cg.time);
- // int test = gi.G2API_GetSurfaceRenderStatus(&ent->ghoul2[0], "l_hand");
- // gi.G2API_SetSurfaceOnOff(&ent->ghoul2[0], "l_arm",0x00000100);
- // test = gi.G2API_GetSurfaceRenderStatus(&ent->ghoul2[0], "l_hand");
- // gi.G2API_SetNewOrigin(&ent->ghoul2[0], gi.G2API_AddBolt(&ent->ghoul2[0], "rhang_tag_bone"));
- // ent->s.apos.trDelta[1] = 10;
- // ent->s.apos.trType = TR_LINEAR;
- ent->nextthink = level.time + 1000;
- ent->e_ThinkFunc = thinkF_set_MiscAnim;
- #endif
- }
- #define RACK_BLASTER 1
- #define RACK_REPEATER 2
- #define RACK_ROCKET 4
- /*QUAKED misc_model_gun_rack (1 0 0.25) (-14 -14 -4) (14 14 30) BLASTER REPEATER ROCKET
- model="models/map_objects/kejim/weaponsrack.md3"
- NOTE: can mix and match these spawnflags to get multi-weapon racks. If only one type is checked the rack will be full of those weapons
- BLASTER - Puts one or more blaster guns on the rack.
- REPEATER - Puts one or more repeater guns on the rack.
- ROCKET - Puts one or more rocket launchers on the rack.
- */
- void GunRackAddItem( gitem_t *gun, vec3_t org, vec3_t angs, float ffwd, float fright, float fup )
- {
- vec3_t fwd, right;
- gentity_t *it_ent = G_Spawn();
- qboolean rotate = qtrue;
- AngleVectors( angs, fwd, right, NULL );
- if ( it_ent && gun )
- {
- // FIXME: scaling the ammo will probably need to be tweaked to a reasonable amount...adjust as needed
- // Set base ammo per type
- if ( gun->giType == IT_WEAPON )
- {
- it_ent->spawnflags |= 16;// VERTICAL
- switch( gun->giTag )
- {
- case WP_BLASTER:
- it_ent->count = 15;
- break;
- case WP_REPEATER:
- it_ent->count = 100;
- break;
- case WP_ROCKET_LAUNCHER:
- it_ent->count = 4;
- break;
- }
- }
- else
- {
- rotate = qfalse;
- // must deliberately make it small, or else the objects will spawn inside of each other.
- VectorSet( it_ent->maxs, 6.75f, 6.75f, 6.75f );
- VectorScale( it_ent->maxs, -1, it_ent->mins );
- }
- it_ent->spawnflags |= 1;// ITMSF_SUSPEND
- it_ent->classname = G_NewString(gun->classname); //copy it so it can be freed safely
- G_SpawnItem( it_ent, gun );
- // FinishSpawningItem handles everything, so clear the thinkFunc that was set in G_SpawnItem
- FinishSpawningItem( it_ent );
- if ( gun->giType == IT_AMMO )
- {
- if ( gun->giTag == AMMO_BLASTER ) // I guess this just has to use different logic??
- {
- if ( g_spskill->integer >= 2 )
- {
- it_ent->count += 10; // give more on higher difficulty because there will be more/harder enemies?
- }
- }
- else
- {
- // scale ammo based on skill
- switch ( g_spskill->integer )
- {
- case 0: // do default
- break;
- case 1:
- it_ent->count *= 0.75f;
- break;
- case 2:
- it_ent->count *= 0.5f;
- break;
- }
- }
- }
- it_ent->nextthink = 0;
- VectorCopy( org, it_ent->s.origin );
- VectorMA( it_ent->s.origin, fright, right, it_ent->s.origin );
- VectorMA( it_ent->s.origin, ffwd, fwd, it_ent->s.origin );
- it_ent->s.origin[2] += fup;
- VectorCopy( angs, it_ent->s.angles );
- // by doing this, we can force the amount of ammo we desire onto the weapon for when it gets picked-up
- it_ent->flags |= ( FL_DROPPED_ITEM | FL_FORCE_PULLABLE_ONLY );
- it_ent->physicsBounce = 0.1f;
- for ( int t = 0; t < 3; t++ )
- {
- if ( rotate )
- {
- if ( t == YAW )
- {
- it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + 180 + crandom() * 14 );
- }
- else
- {
- it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + crandom() * 4 );
- }
- }
- else
- {
- if ( t == YAW )
- {
- it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + 90 + crandom() * 4 );
- }
- }
- }
- G_SetAngles( it_ent, it_ent->s.angles );
- G_SetOrigin( it_ent, it_ent->s.origin );
- gi.linkentity( it_ent );
- }
- }
- //---------------------------------------------
- void SP_misc_model_gun_rack( gentity_t *ent )
- {
- gitem_t *blaster = NULL, *repeater = NULL, *rocket = NULL;
- int ct = 0;
- float ofz[3];
- gitem_t *itemList[3];
- // If BLASTER is checked...or nothing is checked then we'll do blasters
- if (( ent->spawnflags & RACK_BLASTER ) || !(ent->spawnflags & ( RACK_BLASTER | RACK_REPEATER | RACK_ROCKET )))
- {
- blaster = FindItemForWeapon( WP_BLASTER );
- }
- if (( ent->spawnflags & RACK_REPEATER ))
- {
- repeater = FindItemForWeapon( WP_REPEATER );
- }
- if (( ent->spawnflags & RACK_ROCKET ))
- {
- rocket = FindItemForWeapon( WP_ROCKET_LAUNCHER );
- }
- //---------weapon types
- if ( blaster )
- {
- ofz[ct] = 23.0f;
- itemList[ct++] = blaster;
- }
- if ( repeater )
- {
- ofz[ct] = 24.5f;
- itemList[ct++] = repeater;
- }
- if ( rocket )
- {
- ofz[ct] = 25.5f;
- itemList[ct++] = rocket;
- }
- if ( ct ) //..should always have at least one item on their, but just being safe
- {
- for ( ; ct < 3 ; ct++ )
- {
- ofz[ct] = ofz[0];
- itemList[ct] = itemList[0]; // first weapon ALWAYS propagates to fill up the shelf
- }
- }
- // now actually add the items to the shelf...validate that we have a list to add
- if ( ct )
- {
- for ( int i = 0; i < ct; i++ )
- {
- GunRackAddItem( itemList[i], ent->s.origin, ent->s.angles, crandom() * 2, ( i - 1 ) * 9 + crandom() * 2, ofz[i] );
- }
- }
- ent->s.modelindex = G_ModelIndex( "models/map_objects/kejim/weaponsrack.md3" );
- G_SetOrigin( ent, ent->s.origin );
- G_SetAngles( ent, ent->s.angles );
- ent->contents = CONTENTS_SOLID;
- gi.linkentity( ent );
- }
- #define RACK_METAL_BOLTS 2
- #define RACK_ROCKETS 4
- #define RACK_WEAPONS 8
- #define RACK_HEALTH 16
- #define RACK_PWR_CELL 32
- #define RACK_NO_FILL 64
- /*QUAKED misc_model_ammo_rack (1 0 0.25) (-14 -14 -4) (14 14 30) BLASTER METAL_BOLTS ROCKETS WEAPON HEALTH PWR_CELL NO_FILL
- model="models/map_objects/kejim/weaponsrung.md3"
- NOTE: can mix and match these spawnflags to get multi-ammo racks. If only one type is checked the rack will be full of that ammo. Only three ammo packs max can be displayed.
- BLASTER - Adds one or more ammo packs that are compatible with Blasters and the Bryar pistol.
- METAL_BOLTS - Adds one or more metal bolt ammo packs that are compatible with the heavy repeater and the flechette gun
- ROCKETS - Puts one or more rocket packs on a rack.
- WEAPON - adds a weapon matching a selected ammo type to the rack.
- HEALTH - adds a health pack to the top shelf of the ammo rack
- PWR_CELL - Adds one or more power cell packs that are compatible with the Disuptor, bowcaster, and demp2
- NO_FILL - Only puts selected ammo on the rack, it never fills up all three slots if only one or two items were checked
- */
- extern gitem_t *FindItemForAmmo( ammo_t ammo );
- //---------------------------------------------
- void SP_misc_model_ammo_rack( gentity_t *ent )
- {
- // If BLASTER is checked...or nothing is checked then we'll do blasters
- if (( ent->spawnflags & RACK_BLASTER ) || !(ent->spawnflags & ( RACK_BLASTER | RACK_METAL_BOLTS | RACK_ROCKETS | RACK_PWR_CELL )))
- {
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- RegisterItem( FindItemForWeapon( WP_BLASTER ));
- }
- RegisterItem( FindItemForAmmo( AMMO_BLASTER ));
- }
- if (( ent->spawnflags & RACK_METAL_BOLTS ))
- {
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- RegisterItem( FindItemForWeapon( WP_REPEATER ));
- }
- RegisterItem( FindItemForAmmo( AMMO_METAL_BOLTS ));
- }
- if (( ent->spawnflags & RACK_ROCKETS ))
- {
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER ));
- }
- RegisterItem( FindItemForAmmo( AMMO_ROCKETS ));
- }
- if (( ent->spawnflags & RACK_PWR_CELL ))
- {
- RegisterItem( FindItemForAmmo( AMMO_POWERCELL ));
- }
- if (( ent->spawnflags & RACK_HEALTH ))
- {
- RegisterItem( FindItem( "item_medpak_instant" ));
- }
- ent->e_ThinkFunc = thinkF_spawn_rack_goods;
- ent->nextthink = level.time + 100;
- G_SetOrigin( ent, ent->s.origin );
- G_SetAngles( ent, ent->s.angles );
- ent->contents = CONTENTS_SHOTCLIP|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//CONTENTS_SOLID;//so use traces can go through them
- gi.linkentity( ent );
- }
- // AMMO RACK!!
- void spawn_rack_goods( gentity_t *ent )
- {
- float v_off = 0;
- gitem_t *blaster = NULL, *metal_bolts = NULL, *rockets = NULL, *it = NULL;
- gitem_t *am_blaster = NULL, *am_metal_bolts = NULL, *am_rockets = NULL, *am_pwr_cell = NULL;
- gitem_t *health = NULL;
- int pos = 0, ct = 0;
- gitem_t *itemList[4]; // allocating 4, but we only use 3. done so I don't have to validate that the array isn't full before I add another
- gi.unlinkentity( ent );
- // If BLASTER is checked...or nothing is checked then we'll do blasters
- if (( ent->spawnflags & RACK_BLASTER ) || !(ent->spawnflags & ( RACK_BLASTER | RACK_METAL_BOLTS | RACK_ROCKETS | RACK_PWR_CELL )))
- {
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- blaster = FindItemForWeapon( WP_BLASTER );
- }
- am_blaster = FindItemForAmmo( AMMO_BLASTER );
- }
- if (( ent->spawnflags & RACK_METAL_BOLTS ))
- {
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- metal_bolts = FindItemForWeapon( WP_REPEATER );
- }
- am_metal_bolts = FindItemForAmmo( AMMO_METAL_BOLTS );
- }
- if (( ent->spawnflags & RACK_ROCKETS ))
- {
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- rockets = FindItemForWeapon( WP_ROCKET_LAUNCHER );
- }
- am_rockets = FindItemForAmmo( AMMO_ROCKETS );
- }
- if (( ent->spawnflags & RACK_PWR_CELL ))
- {
- am_pwr_cell = FindItemForAmmo( AMMO_POWERCELL );
- }
- if (( ent->spawnflags & RACK_HEALTH ))
- {
- health = FindItem( "item_medpak_instant" );
- RegisterItem( health );
- }
- //---------Ammo types
- if ( am_blaster )
- {
- itemList[ct++] = am_blaster;
- }
- if ( am_metal_bolts )
- {
- itemList[ct++] = am_metal_bolts;
- }
- if ( am_pwr_cell )
- {
- itemList[ct++] = am_pwr_cell;
- }
- if ( am_rockets )
- {
- itemList[ct++] = am_rockets;
- }
- if ( !(ent->spawnflags & RACK_NO_FILL) && ct ) //double negative..should always have at least one item on there, but just being safe
- {
- for ( ; ct < 3 ; ct++ )
- {
- itemList[ct] = itemList[0]; // first item ALWAYS propagates to fill up the shelf
- }
- }
- // now actually add the items to the shelf...validate that we have a list to add
- if ( ct )
- {
- for ( int i = 0; i < ct; i++ )
- {
- GunRackAddItem( itemList[i], ent->s.origin, ent->s.angles, crandom() * 0.5f, (i-1)* 8, 7.0f );
- }
- }
- // -----Weapon option
- if ( ent->spawnflags & RACK_WEAPONS )
- {
- if ( !(ent->spawnflags & ( RACK_BLASTER | RACK_METAL_BOLTS | RACK_ROCKETS | RACK_PWR_CELL )))
- {
- // nothing was selected, so we assume blaster pack
- it = blaster;
- }
- else
- {
- // if weapon is checked...and so are one or more ammo types, then pick a random weapon to display..always give weaker weapons first
- if ( blaster )
- {
- it = blaster;
- v_off = 25.5f;
- }
- else if ( metal_bolts )
- {
- it = metal_bolts;
- v_off = 27.0f;
- }
- else if ( rockets )
- {
- it = rockets;
- v_off = 28.0f;
- }
- }
- if ( it )
- {
- // since we may have to put up a health pack on the shelf, we should know where we randomly put
- // the gun so we don't put the pack on the same spot..so pick either the left or right side
- pos = ( random() > .5 ) ? -1 : 1;
- GunRackAddItem( it, ent->s.origin, ent->s.angles, crandom() * 2, ( random() * 6 + 4 ) * pos, v_off );
- }
- }
- // ------Medpack
- if (( ent->spawnflags & RACK_HEALTH ) && health )
- {
- if ( !pos )
- {
- // we haven't picked a side already...
- pos = ( random() > .5 ) ? -1 : 1;
- }
- else
- {
- // switch to the opposite side
- pos *= -1;
- }
- GunRackAddItem( health, ent->s.origin, ent->s.angles, crandom() * 0.5f, ( random() * 4 + 4 ) * pos, 24 );
- }
- ent->s.modelindex = G_ModelIndex( "models/map_objects/kejim/weaponsrung.md3" );
- G_SetOrigin( ent, ent->s.origin );
- G_SetAngles( ent, ent->s.angles );
- gi.linkentity( ent );
- }
- #define DROP_MEDPACK 1
- #define DROP_SHIELDS 2
- #define DROP_BACTA 4
- #define DROP_BATTERIES 8
- /*QUAKED misc_model_cargo_small (1 0 0.25) (-14 -14 -4) (14 14 30) MEDPACK SHIELDS BACTA BATTERIES
- model="models/map_objects/kejim/cargo_small.md3"
- Cargo crate that can only be destroyed by heavy class weapons ( turrets, emplaced guns, at-st ) Can spawn useful things when it breaks
- MEDPACK - instant use medpacks
- SHIELDS - instant shields
- BACTA - bacta tanks
- BATTERIES -
- "health" - how much damage to take before blowing up ( default 25 )
- "splashRadius" - damage range when it explodes ( default 96 )
- "splashDamage" - damage to do within explode range ( default 1 )
- */
- extern gentity_t *LaunchItem( gitem_t *item, const vec3_t origin, const vec3_t velocity, char *target );
- void misc_model_cargo_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod, int dFlags, int hitLoc )
- {
- int flags;
- vec3_t org, temp;
- gitem_t *health = NULL, *shields = NULL, *bacta = NULL, *batteries = NULL;
- // copy these for later
- flags = self->spawnflags;
- VectorCopy( self->currentOrigin, org );
- // we already had spawn flags, but we don't care what they were...we just need to set up the flags we want for misc_model_breakable_die
- self->spawnflags = 8; // NO_DMODEL
- // pass through to get the effects and such
- misc_model_breakable_die( self, inflictor, attacker, damage, mod );
- // now that the model is broken, we can safely spawn these in it's place without them being in solid
- temp[2] = org[2] + 16;
- // annoying, but spawn each thing in its own little quadrant so that they don't end up on top of each other
- if (( flags & DROP_MEDPACK ))
- {
- health = FindItem( "item_medpak_instant" );
- if ( health )
- {
- temp[0] = org[0] + crandom() * 8 + 16;
- temp[1] = org[1] + crandom() * 8 + 16;
- LaunchItem( health, temp, vec3_origin, NULL );
- }
- }
- if (( flags & DROP_SHIELDS ))
- {
- shields = FindItem( "item_shield_sm_instant" );
- if ( shields )
- {
- temp[0] = org[0] + crandom() * 8 - 16;
- temp[1] = org[1] + crandom() * 8 + 16;
- LaunchItem( shields, temp, vec3_origin, NULL );
- }
- }
- if (( flags & DROP_BACTA ))
- {
- bacta = FindItem( "item_bacta" );
- if ( bacta )
- {
- temp[0] = org[0] + crandom() * 8 - 16;
- temp[1] = org[1] + crandom() * 8 - 16;
- LaunchItem( bacta, temp, vec3_origin, NULL );
- }
- }
- if (( flags & DROP_BATTERIES ))
- {
- batteries = FindItem( "item_battery" );
- if ( batteries )
- {
- temp[0] = org[0] + crandom() * 8 + 16;
- temp[1] = org[1] + crandom() * 8 - 16;
- LaunchItem( batteries, temp, vec3_origin, NULL );
- }
- }
- }
- //---------------------------------------------
- void SP_misc_model_cargo_small( gentity_t *ent )
- {
- G_SpawnInt( "splashRadius", "96", &ent->splashRadius );
- G_SpawnInt( "splashDamage", "1", &ent->splashDamage );
- if (( ent->spawnflags & DROP_MEDPACK ))
- {
- RegisterItem( FindItem( "item_medpak_instant" ));
- }
- if (( ent->spawnflags & DROP_SHIELDS ))
- {
- RegisterItem( FindItem( "item_shield_sm_instant" ));
- }
- if (( ent->spawnflags & DROP_BACTA ))
- {
- // RegisterItem( FindItem( "item_bacta" ));
- }
- if (( ent->spawnflags & DROP_BATTERIES ))
- {
- RegisterItem( FindItem( "item_battery" ));
- }
- G_SpawnInt( "health", "25", &ent->health );
- SetMiscModelDefaults( ent, useF_NULL, "11", CONTENTS_SOLID|CONTENTS_OPAQUE|CONTENTS_BODY|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP, NULL, qtrue, NULL );
- ent->s.modelindex2 = G_ModelIndex("/models/map_objects/kejim/cargo_small.md3"); // Precache model
- // we only take damage from a heavy weapon class missile
- ent->flags |= FL_DMG_BY_HEAVY_WEAP_ONLY;
- ent->e_DieFunc = dieF_misc_model_cargo_die;
- ent->radius = 1.5f; // scale number of chunks spawned
- }
|