/* ================================================================ SPLITTER ================================================================ Copyright (C) 1998 by 2015, Inc. All rights reserved. This source is may not be distributed and/or modified without expressly written permission by 2015, Inc. */ #include "g_local.h" #include "actor.h" #include "gibs.h" #include "splitter.h" #include "flamethrower.h" CLASS_DECLARATION( Actor, Splitter, "monster_splitter" ); Event EV_Splitter_SpawnBug( "spawnbug" ); ResponseDef Splitter::Responses[] = { { &EV_Killed, ( Response )Splitter::KilledEvent }, { &EV_Splitter_SpawnBug, ( Response )Splitter::SpawnBugEvent }, { NULL, NULL } }; //////////////////////////////////////////////// // // SpawnBugEvent // //////////////////////////////////////////////// void Splitter::SpawnBugEvent // Spawns a bug actor and throws it from the splitter ( Event *ev ) { Vector pos; char temp[128]; // Make the splitter not-solid, so the bug doesn't get caught in him setSolidType( SOLID_NOT ); // Find the appropriate bone in the splitter for spawning the bug // at (currently disabled since there is not bone) pos = worldorigin; pos.z += 20; // Spawn lots of blood and shit // Well, not shit - not literally, anyhow. //Creategibs arguments: //1 - entity where they are spawned from //2 - damage done which translates to speed to throw them at //3 - maximum size of gibs to be created //4 - number of gibs //5 - optional model to use //From another spot in the code: CreateGibs( this, health, gibsize, numgibs ); CreateGibs( this, -50, 0.8, 5, "gib1.def" ); CreateGibs( this, -200, 0.3, 5, "gib2.def" ); // Clear the spawn args G_InitSpawnArguments(); sprintf( temp, "%f %f %f", (float)pos.x, (float)pos.y, (float)pos.z ); G_SetSpawnArg( "origin", temp ); sprintf( temp, "%f", (float)angles[YAW] ); G_SetSpawnArg( "angle", temp ); G_SetSpawnArg( "model", "bug.def" ); G_SetSpawnArg( "targetname", TargetName() ); // Gives the splitter's targetname to the bug G_SetSpawnArg( "attackmode", "2" ); G_CallSpawn(); // Clear the spawn args G_InitSpawnArguments(); } //////////////////////////////////////////////// // KilledEvent //////////////////////////////////////////////// void Splitter::KilledEvent // Based on Actor::Killed // Since WarT had already altered Actor::Killed, I've put my alterations to that // in #### markings. ( Event *ev ) { const char *name; Entity *ent; int num; Entity *attacker; Entity *inflictor; Vector dir; Event *event; int i; str dname; int meansofdeath; int j; CheckWater(); StopAnimating(); CancelPendingEvents(); // don't allow them to fly, think, or swim anymore flags &= ~( FL_PRETHINK | FL_SWIM | FL_FLY ); deadflag = DEAD_DYING; takedamage = DAMAGE_YES; groundentity = NULL; attacker = ev->GetEntity( 1 ); inflictor = ev->GetEntity( 3 ); meansofdeath = ev->GetInteger( 5 ); // Double all the armor DoubleArmor(); SetVariable( "other", ev->GetEntity( 1 ) ); if ( !DoAction( "killed" ) && actorthread ) { actorthread->ProcessEvent( EV_ScriptThread_End ); } // Turn off dlight and shadow edict->s.renderfx &= ~( RF_DLIGHT|RF_XFLIP ); // // kill the killtargets // // added extended targeting stuff name = KillTarget(); for(j = 0; j < 2; j++) { switch(j) { case 0: name = KillTarget(); break; case 1: name = KillTarget2(); break; } if ( name && strcmp( name, "" ) ) { num = 0; do { num = G_FindTarget( num, name ); if ( !num ) { break; } ent = G_GetEntity( num ); ent->PostEvent( EV_Remove, 0 ); } while ( 1 ); } } // // fire targets // // added extended targeting stuff for(j = 0; j < 4; j++) { switch(j) { case 0: name = Target(); break; case 1: name = Target2(); break; case 2: name = Target3(); break; case 3: name = Target4(); break; } if ( name && strcmp( name, "" ) ) { num = 0; do { num = G_FindTarget( num, name ); if ( !num ) { break; } ent = G_GetEntity( num ); event = new Event( EV_Activate ); event->AddEntity( attacker ); ent->ProcessEvent( event ); } while ( 1 ); } } // // see if we have a kill_thread // if ( kill_thread.length() > 1 ) { ScriptThread * thread; // // create the thread, but don't start it yet // thread = ExecuteThread( kill_thread, false ); if ( thread ) { ProcessScript( thread, NULL ); } else { warning( "Killed", "could not process kill_thread" ); } } if ( DoGib( meansofdeath, inflictor ) ) { deathgib = true; } // skin darkening for death from flames if(inflictor->isSubclassOf(ThrowerFlame)) { edict->s.renderfx |= RF_LIGHTOFFSET; edict->s.lightofs = -127; CancelEventsOfType(EV_Sentient_HurtFlame); edict->s.effects |= EF_FLAMES; } else { // turn off the actor's heat signature edict->s.effects &= ~EF_WARM; } if ( currentWeapon ) { DropWeapon( currentWeapon ); } animOverride = false; // // determine death animation // if ( !strncmp( animname.c_str(), "crouch", 6 ) ) { dname = "crouch_"; } if ( !strncmp( animname.c_str(), "live_split", 10 ) ) { dname = "live_split_"; } else if ( !strncmp( animname.c_str(), "dead", 4 ) ) { dname = "dead_split_"; } else if ( deathgib ) { str location; location = ev->GetString( 4 ); // Check for location first otherwise randomize if ( location == "torso_upper" ) dname += str( "gibdeath_upper" ); else if ( location == "torso_lower" ) dname += str( "gibdeath_lower" ); else if ( strstr( location.c_str(), "leg" ) ) dname += str( "gibdeath_lower" ); else if ( strstr( location.c_str(), "arm" ) ) dname += str( "gibdeath_upper" ); else if ( strstr( location.c_str(), "head" ) ) dname += str( "gibdeath_upper" ); else if ( G_Random() > 0.5 ) dname += str( "gibdeath_upper" ); else dname += str( "gibdeath_lower" ); } else { dname += str( "death_" ) + str( ev->GetString( 4 ) ); } i = gi.Anim_Random( edict->s.modelindex, dname.c_str() ); if ( ( i == -1 ) && !strncmp( animname.c_str(), "crouch", 6 ) ) { dname = "crouch_death"; i = gi.Anim_Random( edict->s.modelindex, dname.c_str() ); } if ( ( i == -1 ) && !strncmp( animname.c_str(), "live_split", 10 ) ) { dname = "live_split_death"; i = gi.Anim_Random( edict->s.modelindex, dname.c_str() ); } if ( ( i == -1 ) && !strncmp( animname.c_str(), "dead", 4 ) ) { dname = "dead_split_death"; i = gi.Anim_Random( edict->s.modelindex, dname.c_str() ); } if ( i == -1 ) { dname = "death"; } if ( ( i != -1 ) && ( !strncmp( dname.c_str(), "gibdeath", 7 ) ) ) { Event *ev1; ev1 = new Event( EV_Gib ); ev1->AddInteger( 1 ); ProcessEvent( ev1 ); } if ( attacker ) { str location; float damage; damage = ev->GetFloat( 2 ); location = ev->GetString( 4 ); event = new Event( EV_GotKill ); event->AddEntity( this ); event->AddInteger( damage ); event->AddEntity( inflictor ); event->AddString( location ); event->AddInteger( meansofdeath ); event->AddInteger( deathgib ); attacker->ProcessEvent( event ); } SetAnim( dname.c_str(), EV_Actor_Dead ); // Call changeanim immediatly since we're no longer calling prethink ChangeAnim(); // // moved this here so guys would not be solid right away // edict->svflags |= SVF_DEADMONSTER; edict->clipmask = MASK_DEADSOLID; angles.x = 0; angles.z = 0; setAngles( angles ); } Splitter::Splitter() { setModel( "splitter.def" ); modelIndex( "bug.def" ); } /**************************************************************************** // for bug Jump2 Class Definition ****************************************************************************/ CLASS_DECLARATION( Jump, Jump2, NULL ); ResponseDef Jump2::Responses[] = { { NULL, NULL } }; void Jump2::Begin ( Actor &self ) { float traveltime; float dist; Vector goaldir,newgoal; if ( anim.length() ) { self.SetAnim( anim ); } // making it jump no more than 500 units goaldir = goal - self.worldorigin; dist = goaldir.length(); if (dist > 500) { goaldir.normalize(); goaldir *= 500; } newgoal = goaldir + self.worldorigin; traveltime = self.JumpTo( newgoal, speed ); endtime = traveltime + level.time; self.last_jump_time = endtime; state = 0; }