12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352 |
- //b_spawn.cpp
- //added by MCG
- // leave this line at the top for all NPC_xxxx.cpp files...
- #include "g_headers.h"
- #include "Q3_Interface.h"
- #include "b_local.h"
- #include "anims.h"
- #include "g_functions.h"
- #include "wp_saber.h"
- #include "g_vehicles.h"
- extern qboolean G_CheckInSolid (gentity_t *self, qboolean fix);
- extern void ClientUserinfoChanged( int clientNum );
- extern qboolean SpotWouldTelefrag2( gentity_t *mover, vec3_t dest );
- extern void Jedi_Cloak( gentity_t *self );
- extern void Saboteur_Cloak( gentity_t *self );
- //extern void FX_BorgTeleport( vec3_t org );
- extern void G_MatchPlayerWeapon( gentity_t *ent );
- extern void Q3_SetParm (int entID, int parmNum, const char *parmValue);
- //extern void CG_ShimmeryThing_Spawner( vec3_t start, vec3_t end, float radius, qboolean taper, int duration );
- //extern void NPC_StasisSpawnEffect( gentity_t *ent );
- extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
- extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
- extern int WP_SaberInitBladeData( gentity_t *ent );
- extern void ST_ClearTimers( gentity_t *ent );
- extern void Jedi_ClearTimers( gentity_t *ent );
- extern void Howler_ClearTimers( gentity_t *self );
- #define NSF_DROP_TO_FLOOR 16
- //void HirogenAlpha_Precache( void );
- /*
- -------------------------
- NPC_PainFunc
- -------------------------
- */
- painFunc_t NPC_PainFunc( gentity_t *ent )
- {
- painFunc_t func;
- if ( ent->client->ps.weapon == WP_SABER )
- {
- func = painF_NPC_Jedi_Pain;
- }
- else
- {
- // team no longer indicates race/species, use NPC_class to determine different npc types
- /*
- switch ( ent->client->playerTeam )
- {
- default:
- func = painF_NPC_Pain;
- break;
- }
- */
- switch( ent->client->NPC_class )
- {
- // troopers get special pain
- case CLASS_SABOTEUR:
- case CLASS_STORMTROOPER:
- case CLASS_SWAMPTROOPER:
- case CLASS_NOGHRI:
- func = painF_NPC_ST_Pain;
- break;
- case CLASS_SEEKER:
- func = painF_NPC_Seeker_Pain;
- break;
- case CLASS_REMOTE:
- func = painF_NPC_Remote_Pain;
- break;
- case CLASS_MINEMONSTER:
- func = painF_NPC_MineMonster_Pain;
- break;
- case CLASS_HOWLER:
- func = painF_NPC_Howler_Pain;
- break;
- case CLASS_RANCOR:
- func = painF_NPC_Rancor_Pain;
- break;
- case CLASS_WAMPA:
- func = painF_NPC_Wampa_Pain;
- break;
- case CLASS_SAND_CREATURE:
- func = painF_NPC_SandCreature_Pain;
- break;
- // all other droids, did I miss any?
- case CLASS_GONK:
- case CLASS_R2D2:
- case CLASS_R5D2:
- case CLASS_MOUSE:
- case CLASS_PROTOCOL:
- case CLASS_INTERROGATOR:
- func = painF_NPC_Droid_Pain;
- break;
- case CLASS_PROBE:
- func = painF_NPC_Probe_Pain;
- break;
- case CLASS_SENTRY:
- func = painF_NPC_Sentry_Pain;
- break;
- case CLASS_MARK1:
- func = painF_NPC_Mark1_Pain;
- break;
- case CLASS_MARK2:
- func = painF_NPC_Mark2_Pain;
- break;
- case CLASS_ATST:
- func = painF_NPC_ATST_Pain;
- break;
- case CLASS_GALAKMECH:
- func = painF_NPC_GM_Pain;
- break;
- // everyone else gets the normal pain func
- default:
- func = painF_NPC_Pain;
- break;
- }
- }
- return func;
- }
- /*
- -------------------------
- NPC_TouchFunc
- -------------------------
- */
- touchFunc_t NPC_TouchFunc( gentity_t *ent )
- {
- return touchF_NPC_Touch;
- }
- /*
- -------------------------
- NPC_SetMiscDefaultData
- -------------------------
- */
- void G_ClassSetDontFlee( gentity_t *self )
- {
- if ( !self || !self->client || !self->NPC )
- {
- return;
- }
- switch ( self->client->NPC_class )
- {
- case CLASS_ATST:
- case CLASS_CLAW:
- case CLASS_DESANN:
- case CLASS_FISH:
- case CLASS_FLIER2:
- case CLASS_GALAK:
- case CLASS_GLIDER:
- case CLASS_RANCOR:
- case CLASS_SAND_CREATURE:
- case CLASS_INTERROGATOR: // droid
- case CLASS_JAN:
- case CLASS_JEDI:
- case CLASS_KYLE:
- case CLASS_LANDO:
- case CLASS_LIZARD:
- case CLASS_LUKE:
- case CLASS_MARK1: // droid
- case CLASS_MARK2: // droid
- case CLASS_GALAKMECH: // droid
- case CLASS_MONMOTHA:
- case CLASS_MORGANKATARN:
- case CLASS_MURJJ:
- case CLASS_PROBE: // droid
- case CLASS_REBORN:
- case CLASS_REELO:
- case CLASS_REMOTE:
- case CLASS_SEEKER: // droid
- case CLASS_SENTRY:
- case CLASS_SHADOWTROOPER:
- case CLASS_SWAMP:
- case CLASS_TAVION:
- case CLASS_ALORA:
- case CLASS_BOBAFETT:
- case CLASS_SABER_DROID:
- case CLASS_ASSASSIN_DROID:
- case CLASS_PLAYER:
- case CLASS_VEHICLE:
- self->NPC->scriptFlags |= SCF_DONT_FLEE;
- break;
- }
- if ( (self->NPC->aiFlags&NPCAI_BOSS_CHARACTER) )
- {
- self->NPC->scriptFlags |= SCF_DONT_FLEE;
- }
- if ( (self->NPC->aiFlags&NPCAI_SUBBOSS_CHARACTER) )
- {
- self->NPC->scriptFlags |= SCF_DONT_FLEE;
- }
- if ( (self->NPC->aiFlags&NPCAI_ROSH) )
- {
- self->NPC->scriptFlags |= SCF_DONT_FLEE;
- }
- if ( (self->NPC->aiFlags&NPCAI_HEAL_ROSH) )
- {
- self->NPC->scriptFlags |= SCF_DONT_FLEE;
- }
- }
- extern void Vehicle_Register(gentity_t *ent);
- extern void RT_FlyStart( gentity_t *self );
- extern void SandCreature_ClearTimers( gentity_t *ent );
- void NPC_SetMiscDefaultData( gentity_t *ent )
- {
- if ( ent->spawnflags & SFB_CINEMATIC )
- {//if a cinematic guy, default us to wait bState
- ent->NPC->behaviorState = BS_CINEMATIC;
- }
- if ( ent->client->NPC_class == CLASS_RANCOR )
- {
- if ( Q_stricmp( "mutant_rancor", ent->NPC_type ) == 0 )
- {
- ent->spawnflags |= 1;//just so I know it's a mutant rancor as opposed to a normal one
- ent->NPC->aiFlags |= NPCAI_NAV_THROUGH_BREAKABLES;
- ent->mass = 2000;
- }
- else
- {
- ent->NPC->aiFlags |= NPCAI_NAV_THROUGH_BREAKABLES;
- ent->mass = 1000;
- }
- ent->flags |= FL_NO_KNOCKBACK;
- }
- else if ( ent->client->NPC_class == CLASS_SAND_CREATURE )
- {//???
- ent->clipmask = CONTENTS_SOLID|CONTENTS_MONSTERCLIP;//it can go through others
- ent->contents = 0;//can't be hit?
- ent->takedamage = qfalse;//can't be killed
- ent->flags |= FL_NO_KNOCKBACK;
- SandCreature_ClearTimers( ent );
- }
- else if ( ent->client->NPC_class == CLASS_BOBAFETT )
- {//set some stuff, precache
- ent->client->ps.forcePowersKnown |= ( 1 << FP_LEVITATION );
- ent->client->ps.forcePowerLevel[FP_LEVITATION] = FORCE_LEVEL_3;
- ent->client->ps.forcePower = 100;
- ent->NPC->scriptFlags |= (SCF_NAV_CAN_FLY|SCF_FLY_WITH_JET|SCF_NAV_CAN_JUMP);
- NPC->flags |= FL_UNDYING; // Can't Kill Boba
- }
- else if ( ent->client->NPC_class == CLASS_ROCKETTROOPER )
- {//set some stuff, precache
- ent->client->ps.forcePowersKnown |= ( 1 << FP_LEVITATION );
- ent->client->ps.forcePowerLevel[FP_LEVITATION] = FORCE_LEVEL_3;
- ent->client->ps.forcePower = 100;
- ent->NPC->scriptFlags |= (SCF_NAV_CAN_FLY|SCF_FLY_WITH_JET|SCF_NAV_CAN_JUMP);//no groups, no combat points!
- if ( Q_stricmp( "rockettrooper2Officer", ent->NPC_type ) == 0 )
- {//start in the air, use spotlight
- //ent->NPC->scriptFlags |= SCF_NO_GROUPS;
- ent->NPC->scriptFlags &= ~SCF_FLY_WITH_JET;
- RT_FlyStart( ent );
- NPC_SetMoveGoal( ent, ent->currentOrigin, 16, qfalse, -1, NULL );
- VectorCopy( ent->currentOrigin, ent->pos1 );
- }
- if ( (ent->spawnflags&2) )
- {//spotlight
- ent->client->ps.eFlags |= EF_SPOTLIGHT;
- }
- }
- else if (ent->client->NPC_class == CLASS_SABER_DROID)
- {
- ent->flags |= FL_NO_KNOCKBACK;
- }
- else if ( ent->client->NPC_class == CLASS_SABOTEUR )
- {//can cloak
- ent->NPC->aiFlags |= NPCAI_SHIELDS;//give them the ability to cloak
- if ( (ent->spawnflags&16) )
- {//start cloaked
- Saboteur_Cloak( ent );
- }
- }
- else if ( ent->client->NPC_class == CLASS_ASSASSIN_DROID )
- {
- ent->client->ps.stats[STAT_ARMOR] = 250; // start with full armor
- if (ent->s.weapon==WP_BLASTER)
- {
- ent->NPC->scriptFlags |= SCF_ALT_FIRE;
- }
- ent->flags |= (FL_NO_KNOCKBACK);
- }
- if (ent->spawnflags&4096)
- {
- ent->NPC->scriptFlags |= SCF_NO_GROUPS;//don't use combat points or group AI
- }
- if ( Q_stricmp( "DKothos", ent->NPC_type ) == 0
- || Q_stricmp( "VKothos", ent->NPC_type ) == 0 )
- {
- ent->NPC->scriptFlags |= SCF_DONT_FIRE;
- ent->NPC->aiFlags |= NPCAI_HEAL_ROSH;
- ent->count = 100;
- }
- else if ( Q_stricmp( "rosh_dark", ent->NPC_type ) == 0 )
- {
- ent->NPC->aiFlags |= NPCAI_ROSH;
- }
- if ( Q_stricmpn( ent->NPC_type, "hazardtrooper", 13 ) == 0 )
- {//hazard trooper
- ent->NPC->scriptFlags |= SCF_NO_GROUPS;//don't use combat points or group AI
- ent->flags |= (FL_SHIELDED|FL_NO_KNOCKBACK);//low-level shots bounce off, no knockback
- }
- if ( !Q_stricmp( "Yoda", ent->NPC_type ) )
- {//FIXME: extern this into NPC.cfg?
- ent->NPC->scriptFlags |= SCF_NO_FORCE;//force powers don't work on him
- ent->NPC->aiFlags |= NPCAI_BOSS_CHARACTER;
- }
- if ( !Q_stricmp( "emperor", ent->NPC_type )
- || !Q_stricmp( "cultist_grip", ent->NPC_type )
- || !Q_stricmp( "cultist_drain", ent->NPC_type )
- || !Q_stricmp( "cultist_lightning", ent->NPC_type ))
- {//FIXME: extern this into NPC.cfg?
- ent->NPC->scriptFlags |= SCF_DONT_FIRE;//so he uses only force powers
- }
- if (!Q_stricmp( "Rax", ent->NPC_type ) )
- {
- ent->NPC->scriptFlags |= SCF_DONT_FLEE;
- }
- if ( !Q_stricmp( "cultist_destroyer", ent->NPC_type ) )
- {
- ent->splashDamage = 1000;
- ent->splashRadius = 384;
- //FIXME: precache these!
- ent->fxID = G_EffectIndex( "force/destruction_exp" );
- ent->NPC->scriptFlags |= (SCF_DONT_FLEE|SCF_IGNORE_ALERTS);
- ent->NPC->ignorePain = qtrue;
- }
- if ( Q_stricmp( "chewie", ent->NPC_type ) )
- {
- //in case chewie ever loses his gun...
- ent->NPC->aiFlags |= NPCAI_HEAVY_MELEE;
- }
- //==================
- if ( ent->client->ps.saber[0].type != SABER_NONE
- && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )
- {//if I'm equipped with a saber, initialize it (them)
- ent->client->ps.SaberDeactivate();
- ent->client->ps.SetSaberLength( 0 );
- WP_SaberInitBladeData( ent );
- if ( ent->client->ps.weapon == WP_SABER )
- {//this is our current weapon, add the models now
- WP_SaberAddG2SaberModels( ent );
- }
- Jedi_ClearTimers( ent );
- }
- if ( ent->client->ps.forcePowersKnown != 0 )
- {
- WP_InitForcePowers( ent );
- if (ent->client->ps.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0)
- {
- ent->NPC->scriptFlags |= SCF_NAV_CAN_JUMP; // anyone who has any force jump can jump
- }
- }
- if ( ent->client->NPC_class == CLASS_HOWLER )
- {
- Howler_ClearTimers( ent );
- ent->NPC->scriptFlags |= SCF_NO_FALLTODEATH;
- ent->flags |= FL_NO_IMPACT_DMG;
- ent->NPC->scriptFlags |= SCF_NAV_CAN_JUMP; // These jokers can jump
- }
- if ( ent->client->NPC_class == CLASS_DESANN
- || ent->client->NPC_class == CLASS_TAVION
- || ent->client->NPC_class == CLASS_LUKE
- || ent->client->NPC_class == CLASS_KYLE
- || Q_stricmp("tavion_scepter", ent->NPC_type ) == 0
- || Q_stricmp("alora_dual", ent->NPC_type ) == 0 )
- {
- ent->NPC->aiFlags |= NPCAI_BOSS_CHARACTER;
- }
- else if ( Q_stricmp( "alora", ent->NPC_type ) == 0
- || Q_stricmp( "rosh_dark", ent->NPC_type ) == 0 )
- {
- ent->NPC->aiFlags |= NPCAI_SUBBOSS_CHARACTER;
- }
- if ( ent->client->NPC_class == CLASS_TUSKEN )
- {
- if ( g_spskill->integer > 1 )
- {//on hard, tusken raiders are faster than you
- ent->NPC->stats.runSpeed = 280;
- ent->NPC->stats.walkSpeed = 65;
- }
- }
- //***I'm not sure whether I should leave this as a TEAM_ switch, I think NPC_class may be more appropriate - dmv
- switch(ent->client->playerTeam)
- {
- case TEAM_PLAYER:
- //ent->flags |= FL_NO_KNOCKBACK;
- if ( ent->client->NPC_class == CLASS_SEEKER )
- {
- ent->NPC->defaultBehavior = BS_DEFAULT;
- ent->client->ps.gravity = 0;
- ent->svFlags |= SVF_CUSTOM_GRAVITY;
- ent->client->moveType = MT_FLYSWIM;
- ent->count = 30; // SEEKER shot ammo count
- return;
- }
- else if ( ent->client->NPC_class == CLASS_JEDI
- || ent->client->NPC_class == CLASS_KYLE
- || ent->client->NPC_class == CLASS_LUKE )
- {//good jedi
- ent->client->enemyTeam = TEAM_ENEMY;
- if ( ent->spawnflags & JSF_AMBUSH )
- {//ambusher
- ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS;
- ent->client->noclip = true;//hang
- }
- }
- else
- {
- if (ent->client->ps.weapon != WP_NONE
- && ent->client->ps.weapon != WP_SABER //sabers done above
- && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves
- {
- G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 );
- }
- switch ( ent->client->ps.weapon )
- {
- case WP_BRYAR_PISTOL://FIXME: new weapon: imp blaster pistol
- case WP_BLASTER_PISTOL:
- case WP_DISRUPTOR:
- case WP_BOWCASTER:
- case WP_REPEATER:
- case WP_DEMP2:
- case WP_FLECHETTE:
- case WP_ROCKET_LAUNCHER:
- case WP_CONCUSSION:
- default:
- break;
- case WP_THERMAL:
- case WP_BLASTER:
- //FIXME: health in NPCs.cfg, and not all blaster users are stormtroopers
- //ent->health = 25;
- //FIXME: not necc. a ST
- ST_ClearTimers( ent );
- if ( ent->NPC->rank >= RANK_LT || ent->client->ps.weapon == WP_THERMAL )
- {//officers, grenade-throwers use alt-fire
- //ent->health = 50;
- //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
- }
- break;
- }
- }
- if ( ent->client->NPC_class == CLASS_PLAYER
- || ent->client->NPC_class == CLASS_VEHICLE
- || (ent->spawnflags & SFB_CINEMATIC) )
- {
- ent->NPC->defaultBehavior = BS_CINEMATIC;
- }
- else
- {
- ent->NPC->defaultBehavior = BS_FOLLOW_LEADER;
- ent->client->leader = &g_entities[0];//player
- }
- break;
- case TEAM_NEUTRAL:
- if ( Q_stricmp( ent->NPC_type, "gonk" ) == 0 )
- {
- // I guess we generically make them player usable
- ent->svFlags |= SVF_PLAYER_USABLE;
- // Not even sure if we want to give different levels of batteries? ...Or even that these are the values we'd want to use.
- switch ( g_spskill->integer )
- {
- case 0: // EASY
- ent->client->ps.batteryCharge = MAX_BATTERIES * 0.8f;
- break;
- case 1: // MEDIUM
- ent->client->ps.batteryCharge = MAX_BATTERIES * 0.75f;
- break;
- default :
- case 2: // HARD
- ent->client->ps.batteryCharge = MAX_BATTERIES * 0.5f;
- break;
- }
- }
- break;
- case TEAM_ENEMY:
- {
- ent->NPC->defaultBehavior = BS_DEFAULT;
- if ( ent->client->NPC_class == CLASS_SHADOWTROOPER
- && Q_stricmpn("shadowtrooper", ent->NPC_type, 13 ) == 0 )
- {//FIXME: a spawnflag?
- Jedi_Cloak( ent );
- }
- if( ent->client->NPC_class == CLASS_TAVION ||
- ent->client->NPC_class == CLASS_ALORA ||
- (ent->client->NPC_class == CLASS_REBORN && ent->client->ps.weapon == WP_SABER) ||
- ent->client->NPC_class == CLASS_DESANN ||
- ent->client->NPC_class == CLASS_SHADOWTROOPER )
- {
- ent->client->enemyTeam = TEAM_PLAYER;
- if ( ent->spawnflags & JSF_AMBUSH )
- {//ambusher
- ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS;
- ent->client->noclip = true;//hang
- }
- }
- else if( ent->client->NPC_class == CLASS_PROBE || ent->client->NPC_class == CLASS_REMOTE ||
- ent->client->NPC_class == CLASS_INTERROGATOR || ent->client->NPC_class == CLASS_SENTRY)
- {
- ent->NPC->defaultBehavior = BS_DEFAULT;
- ent->client->ps.gravity = 0;
- ent->svFlags |= SVF_CUSTOM_GRAVITY;
- ent->client->moveType = MT_FLYSWIM;
- }
- else
- {
- if ( ent->client->ps.weapon != WP_NONE
- && ent->client->ps.weapon != WP_SABER//sabers done above
- && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves
- {
- G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 );
- }
- switch ( ent->client->ps.weapon )
- {
- case WP_BRYAR_PISTOL:
- break;
- case WP_BLASTER_PISTOL:
- NPCInfo->scriptFlags |= SCF_PILOT;
- if ( ent->client->NPC_class == CLASS_REBORN
- && ent->NPC->rank >= RANK_LT_COMM
- && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves
- {//dual blaster pistols, so add the left-hand one, too
- G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handLBolt, 1 );
- }
- break;
- case WP_DISRUPTOR:
- //Sniper
- //ent->NPC->scriptFlags |= SCF_ALT_FIRE;//FIXME: use primary fire sometimes? Up close? Different class of NPC?
- break;
- case WP_BOWCASTER:
- NPCInfo->scriptFlags |= SCF_PILOT;
- break;
- case WP_REPEATER:
- NPCInfo->scriptFlags |= SCF_PILOT;
- //machine-gunner
- break;
- case WP_DEMP2:
- break;
- case WP_FLECHETTE:
- NPCInfo->scriptFlags |= SCF_PILOT;
- //shotgunner
- if ( !Q_stricmp( "stofficeralt", ent->NPC_type ) )
- {
- //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
- }
- break;
- case WP_ROCKET_LAUNCHER:
- break;
- case WP_CONCUSSION:
- break;
- case WP_THERMAL:
- //Gran, use main, bouncy fire
- // ent->NPC->scriptFlags |= SCF_ALT_FIRE;
- break;
- case WP_MELEE:
- break;
- case WP_NOGHRI_STICK:
- break;
- default:
- case WP_BLASTER:
- //FIXME: health in NPCs.cfg, and not all blaster users are stormtroopers
- //FIXME: not necc. a ST
- NPCInfo->scriptFlags |= SCF_PILOT;
- ST_ClearTimers( ent );
- if ( ent->NPC->rank >= RANK_COMMANDER )
- {//commanders use alt-fire
- //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
- }
- if ( !Q_stricmp( "rodian2", ent->NPC_type ) )
- {
- //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
- }
- break;
- }
- }
- }
- break;
- default:
- ent->NPC->defaultBehavior = BS_DEFAULT;
- if ( ent->client->ps.weapon != WP_NONE
- && ent->client->ps.weapon != WP_MELEE
- && ent->client->ps.weapon != WP_SABER//sabers done above
- && (!(ent->NPC->aiFlags&NPCAI_MATCHPLAYERWEAPON)||!ent->weaponModel[0]) )//they do this themselves
- {
- G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 );
- }
- break;
- }
- if ( ent->client->NPC_class == CLASS_ATST || ent->client->NPC_class == CLASS_MARK1 ) // chris/steve/kevin requested that the mark1 be shielded also
- {
- ent->flags |= (FL_SHIELDED|FL_NO_KNOCKBACK);
- }
- // Set CAN FLY Flag for Navigation On The Following Classes
- //----------------------------------------------------------
- if (ent->client->NPC_class==CLASS_PROBE ||
- ent->client->NPC_class==CLASS_REMOTE ||
- ent->client->NPC_class==CLASS_SEEKER ||
- ent->client->NPC_class==CLASS_SENTRY ||
- ent->client->NPC_class==CLASS_GLIDER ||
- ent->client->NPC_class==CLASS_IMPWORKER ||
- ent->client->NPC_class==CLASS_BOBAFETT ||
- ent->client->NPC_class==CLASS_ROCKETTROOPER
- )
- {
- ent->NPC->scriptFlags |= SCF_NAV_CAN_FLY;
- }
- if (ent->client->NPC_class==CLASS_VEHICLE)
- {
- Vehicle_Register(ent);
- }
- if ( ent->client->ps.stats[STAT_WEAPONS]&(1<<WP_SCEPTER) )
- {
- if ( !ent->weaponModel[1] )
- {//we have the scepter, so put it in our left hand if we don't already have a second weapon
- G_CreateG2AttachedWeaponModel( ent, weaponData[WP_SCEPTER].weaponMdl, ent->handLBolt, 1 );
- }
- ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->weaponModel[1]], "*flash");
- }
- if ( ent->client->ps.saber[0].type == SABER_SITH_SWORD )
- {
- ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->weaponModel[0]], "*flash");
- G_PlayEffect( G_EffectIndex( "scepter/sword.efx" ), ent->weaponModel[0], ent->genericBolt1, ent->s.number, ent->currentOrigin, qtrue, qtrue );
- //how many times can she recharge?
- ent->count = g_spskill->integer*2;
- //To make sure she can do it at least once
- ent->flags |= FL_UNDYING;
- }
- if ( ent->client->ps.weapon == WP_NOGHRI_STICK
- && ent->weaponModel[0] )
- {
- ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->weaponModel[0]], "*flash");
- }
- G_ClassSetDontFlee( ent );
- }
- /*
- -------------------------
- NPC_WeaponsForTeam
- -------------------------
- */
- int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type )
- {
- //*** not sure how to handle this, should I pass in class instead of team and go from there? - dmv
- switch(team)
- {
- // no longer exists
- // case TEAM_BORG:
- // break;
- // case TEAM_HIROGEN:
- // if( Q_stricmp( "hirogenalpha", NPC_type ) == 0 )
- // return ( 1 << WP_BLASTER);
- //Falls through
- // case TEAM_KLINGON:
- //NOTENOTE: Falls through
- // case TEAM_IMPERIAL:
- case TEAM_ENEMY:
- if ( Q_stricmp( "tavion", NPC_type ) == 0 ||
- Q_stricmpn( "reborn", NPC_type, 6 ) == 0 ||
- Q_stricmp( "desann", NPC_type ) == 0 ||
- Q_stricmpn( "shadowtrooper", NPC_type, 13 ) == 0 )
- return ( 1 << WP_SABER);
- // return ( 1 << WP_IMPERIAL_BLADE);
- //NOTENOTE: Falls through if not a knife user
- // case TEAM_SCAVENGERS:
- // case TEAM_MALON:
- //FIXME: default weapon in npc config?
- if ( Q_stricmpn( "stofficer", NPC_type, 9 ) == 0 )
- {
- return ( 1 << WP_FLECHETTE);
- }
- if ( Q_stricmp( "stcommander", NPC_type ) == 0 )
- {
- return ( 1 << WP_REPEATER);
- }
- if ( Q_stricmp( "swamptrooper", NPC_type ) == 0 )
- {
- return ( 1 << WP_FLECHETTE);
- }
- if ( Q_stricmp( "swamptrooper2", NPC_type ) == 0 )
- {
- return ( 1 << WP_REPEATER);
- }
- if ( Q_stricmp( "rockettrooper", NPC_type ) == 0 )
- {
- return ( 1 << WP_ROCKET_LAUNCHER);
- }
- if ( Q_stricmpn( "shadowtrooper", NPC_type, 13 ) == 0 )
- {
- return ( 1 << WP_SABER);//|( 1 << WP_RAPID_CONCUSSION)?
- }
- if ( Q_stricmp( "imperial", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER_PISTOL);
- }
- if ( Q_stricmpn( "impworker", NPC_type, 9 ) == 0 )
- {
- return ( 1 << WP_BLASTER_PISTOL);
- }
- if ( Q_stricmp( "stormpilot", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER_PISTOL);
- }
- if ( Q_stricmp( "galak", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER);
- }
- if ( Q_stricmp( "galak_mech", NPC_type ) == 0 )
- {
- return ( 1 << WP_REPEATER);
- }
- if ( Q_stricmpn( "ugnaught", NPC_type, 8 ) == 0 )
- {
- return WP_NONE;
- }
- if ( Q_stricmp( "granshooter", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER);
- }
- if ( Q_stricmp( "granboxer", NPC_type ) == 0 )
- {
- return ( 1 << WP_MELEE);
- }
- if ( Q_stricmpn( "gran", NPC_type, 4 ) == 0 )
- {
- return (( 1 << WP_THERMAL)|( 1 << WP_MELEE));
- }
- if ( Q_stricmp( "rodian", NPC_type ) == 0 )
- {
- return ( 1 << WP_DISRUPTOR);
- }
- if ( Q_stricmp( "rodian2", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER);
- }
- if (( Q_stricmp( "interrogator",NPC_type) == 0) || ( Q_stricmp( "sentry",NPC_type) == 0) || (Q_stricmpn( "protocol",NPC_type,8) == 0) )
- {
- return WP_NONE;
- }
- if ( Q_stricmpn( "weequay", NPC_type, 7 ) == 0 )
- {
- return ( 1 << WP_BOWCASTER);//|( 1 << WP_STAFF )(FIXME: new weap?)
- }
- if ( Q_stricmp( "impofficer", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER);
- }
- if ( Q_stricmp( "impcommander", NPC_type ) == 0 )
- {
- return ( 1 << WP_BLASTER);
- }
- if (( Q_stricmp( "probe", NPC_type ) == 0 ) || ( Q_stricmp( "seeker", NPC_type ) == 0 ))
- {
- return ( 1 << WP_BOT_LASER);
- }
- if ( Q_stricmpn( "remote", NPC_type, 6 ) == 0 )
- {
- return ( 1 << WP_BOT_LASER );
- }
- if ( Q_stricmp( "trandoshan", NPC_type ) == 0 )
- {
- return (1<<WP_REPEATER);
- }
- if ( Q_stricmp( "atst", NPC_type ) == 0 )
- {
- return (( 1 << WP_ATST_MAIN)|( 1 << WP_ATST_SIDE));
- }
- if ( Q_stricmp( "mark1", NPC_type ) == 0 )
- {
- return ( 1 << WP_BOT_LASER);
- }
- if ( Q_stricmp( "mark2", NPC_type ) == 0 )
- {
- return ( 1 << WP_BOT_LASER);
- }
- if ( Q_stricmp( "minemonster", NPC_type ) == 0 )
- {
- return (( 1 << WP_MELEE));
- }
- if ( Q_stricmp( "howler", NPC_type ) == 0 )
- {
- return (( 1 << WP_MELEE));
- }
- //Stormtroopers, etc.
- return ( 1 << WP_BLASTER);
- break;
- case TEAM_PLAYER:
-
- // if(spawnflags & SFB_TRICORDER)
- // return ( 1 << WP_TRICORDER);
-
- if(spawnflags & SFB_RIFLEMAN)
- return ( 1 << WP_REPEATER);
-
- if(spawnflags & SFB_PHASER)
- return ( 1 << WP_BLASTER_PISTOL);
- if ( Q_stricmpn( "jedi", NPC_type, 4 ) == 0 || Q_stricmp( "luke", NPC_type ) == 0 )
- return ( 1 << WP_SABER);
- if ( Q_stricmpn( "prisoner", NPC_type, 8 ) == 0
- || Q_stricmpn( "elder", NPC_type, 5 ) == 0 )
- {
- return WP_NONE;
- }
- if ( Q_stricmpn( "bespincop", NPC_type, 9 ) == 0 )
- {
- return ( 1 << WP_BLASTER_PISTOL);
- }
- if ( Q_stricmp( "MonMothma", NPC_type ) == 0 )
- {
- return WP_NONE;
- }
- //rebel
- return ( 1 << WP_BLASTER);
- break;
- case TEAM_NEUTRAL:
- if ( Q_stricmp( "mark1", NPC_type ) == 0 )
- {
- return WP_NONE;
- }
- if ( Q_stricmp( "mark2", NPC_type ) == 0 )
- {
- return WP_NONE;
- }
- if ( Q_stricmpn( "ugnaught", NPC_type, 8 ) == 0 )
- {
- return WP_NONE;
- }
- if ( Q_stricmp( "bartender", NPC_type ) == 0 )
- {
- return WP_NONE;
- }
- if ( Q_stricmp( "morgankatarn", NPC_type ) == 0 )
- {
- return WP_NONE;
- }
-
- break;
- // these no longer exist
- // case TEAM_FORGE:
- // return ( 1 << WP_MELEE);
- // break;
- // case TEAM_STASIS:
- // return ( 1 << WP_MELEE);
- // break;
- // case TEAM_PARASITE:
- // break;
- // case TEAM_8472:
- // break;
- default:
- break;
- }
- return WP_NONE;
- }
- extern void ChangeWeapon( gentity_t *ent, int newWeapon );
- /*
- -------------------------
- NPC_SetWeapons
- -------------------------
- */
- void NPC_SetWeapons( gentity_t *ent )
- {
- int bestWeap = WP_NONE;
- int weapons = NPC_WeaponsForTeam( ent->client->playerTeam, ent->spawnflags, ent->NPC_type );
- ent->client->ps.stats[STAT_WEAPONS] = 0;
- for ( int curWeap = WP_SABER; curWeap < WP_NUM_WEAPONS; curWeap++ )
- {
- if ( (weapons & ( 1 << curWeap )) )
- {
- ent->client->ps.stats[STAT_WEAPONS] |= ( 1 << curWeap );
- RegisterItem( FindItemForWeapon( (weapon_t)(curWeap) ) ); //precache the weapon
- ent->NPC->currentAmmo = ent->client->ps.ammo[weaponData[curWeap].ammoIndex] = 100;//FIXME: max ammo
- if ( bestWeap == WP_SABER )
- {
- // still want to register other weapons -- force saber to be best weap
- continue;
- }
- if ( curWeap == WP_MELEE )
- {
- if ( bestWeap == WP_NONE )
- {// We'll only consider giving Melee since we haven't found anything better yet.
- bestWeap = curWeap;
- }
- }
- else if ( curWeap > bestWeap || bestWeap == WP_MELEE )
- {
- // This will never override saber as best weap. Also will override WP_MELEE if something better comes later in the list
- bestWeap = curWeap;
- }
- }
- }
- ent->client->ps.weapon = bestWeap;
- }
- /*
- -------------------------
- NPC_SpawnEffect
- NOTE: Make sure any effects called here have their models, tga's and sounds precached in
- CG_RegisterNPCEffects in cg_player.cpp
- -------------------------
- */
- static void NPC_SpawnEffect (gentity_t *ent)
- {
- }
- //--------------------------------------------------------------
- // NPC_SetFX_SpawnStates
- //
- // Set up any special parms for spawn effects
- //--------------------------------------------------------------
- void NPC_SetFX_SpawnStates( gentity_t *ent )
- {
- ent->client->ps.gravity = g_gravity->value;
- }
- //--------------------------------------------------------------
- extern qboolean stop_icarus;
- void NPC_Begin (gentity_t *ent)
- {
- vec3_t spawn_origin, spawn_angles;
- gclient_t *client;
- usercmd_t ucmd;
- gentity_t *spawnPoint = NULL;
- memset( &ucmd, 0, sizeof( ucmd ) );
- if ( !(ent->spawnflags & SFB_NOTSOLID) )
- {//No NPCs should telefrag
- if ( Q_stricmp( ent->NPC_type, "nullDriver") == 0 )
- {//FIXME: should be a better way to check this
- }
- else if( SpotWouldTelefrag( ent, TEAM_FREE ) )//(team_t)(ent->client->playerTeam)
- {
- if ( ent->wait < 0 )
- {//remove yourself
- Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "NPC %s could not spawn, firing target3 (%s) and removing self\n", ent->targetname, ent->target3 );
- //Fire off our target3
- G_UseTargets2( ent, ent, ent->target3 );
- //Kill us
- ent->e_ThinkFunc = thinkF_G_FreeEntity;
- ent->nextthink = level.time + 100;
- }
- else
- {
- Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "NPC %s at (%5.0f %5.0f %5.0f) couldn't spawn, waiting %4.2f secs to try again\n",
- ent->targetname, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2], ent->wait/1000.0f );
- ent->e_ThinkFunc = thinkF_NPC_Begin;
- ent->nextthink = level.time + ent->wait;//try again in half a second
- }
- return;
- }
- }
- //Spawn effect
- NPC_SpawnEffect( ent );
- VectorCopy( ent->client->ps.origin, spawn_origin);
- VectorCopy( ent->s.angles, spawn_angles);
- spawn_angles[YAW] = ent->NPC->desiredYaw;
- client = ent->client;
- // increment the spawncount so the client will detect the respawn
- client->ps.persistant[PERS_SPAWN_COUNT]++;
- client->airOutTime = level.time + 12000;
- client->ps.clientNum = ent->s.number;
- // clear entity values
- if ( ent->health ) // Was health supplied in map
- {
- ent->max_health = client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = ent->health;
- }
- else if ( ent->NPC->stats.health ) // Was health supplied in NPC.cfg?
- {
-
- if ( ent->client->NPC_class != CLASS_REBORN
- && ent->client->NPC_class != CLASS_SHADOWTROOPER
- //&& ent->client->NPC_class != CLASS_TAVION
- //&& ent->client->NPC_class != CLASS_DESANN
- && ent->client->NPC_class != CLASS_JEDI )
- {// up everyone except jedi
- if ( !Q_stricmp("tavion_sith_sword", ent->NPC_type )
- || !Q_stricmp("tavion_scepter", ent->NPC_type )
- || !Q_stricmp("kyle_boss", ent->NPC_type )
- || !Q_stricmp("alora_dual", ent->NPC_type )
- || !Q_stricmp("alora_boss", ent->NPC_type ) )
- {//bosses are a bit different
- ent->NPC->stats.health = ceil((float)ent->NPC->stats.health*0.75f + ((float)ent->NPC->stats.health/4.0f*g_spskill->value)); // 75% on easy, 100% on medium, 125% on hard
- }
- else
- {
- ent->NPC->stats.health += ent->NPC->stats.health/4 * g_spskill->integer; // 100% on easy, 125% on medium, 150% on hard
- }
- }
-
- ent->max_health = client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = ent->NPC->stats.health;
- }
- else
- {
- ent->max_health = client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = 100;
- }
- if ( !Q_stricmp( "rodian", ent->NPC_type ) )
- {//sniper
- //NOTE: this will get overridden by any aim settings in their spawnscripts
- switch ( g_spskill->integer )
- {
- case 0:
- ent->NPC->stats.aim = 1;
- break;
- case 1:
- ent->NPC->stats.aim = Q_irand( 2, 3 );
- break;
- case 2:
- ent->NPC->stats.aim = Q_irand( 3, 4 );
- break;
- }
- }
- else if ( ent->client->NPC_class == CLASS_STORMTROOPER
- || ent->client->NPC_class == CLASS_SWAMPTROOPER
- || ent->client->NPC_class == CLASS_IMPWORKER
- || !Q_stricmp( "rodian2", ent->NPC_type ) )
- {//tweak yawspeed for these NPCs based on difficulty
- switch ( g_spskill->integer )
- {
- case 0:
- ent->NPC->stats.yawSpeed *= 0.75f;
- if ( ent->client->NPC_class == CLASS_IMPWORKER )
- {
- ent->NPC->stats.aim -= Q_irand( 3, 6 );
- }
- break;
- case 1:
- if ( ent->client->NPC_class == CLASS_IMPWORKER )
- {
- ent->NPC->stats.aim -= Q_irand( 2, 4 );
- }
- break;
- case 2:
- ent->NPC->stats.yawSpeed *= 1.5f;
- if ( ent->client->NPC_class == CLASS_IMPWORKER )
- {
- ent->NPC->stats.aim -= Q_irand( 0, 2 );
- }
- break;
- }
- }
- else if ( ent->client->NPC_class == CLASS_REBORN
- || ent->client->NPC_class == CLASS_SHADOWTROOPER )
- {
- switch ( g_spskill->integer )
- {
- case 1:
- ent->NPC->stats.yawSpeed *= 1.25f;
- break;
- case 2:
- ent->NPC->stats.yawSpeed *= 1.5f;
- break;
- }
- }
- ent->s.groundEntityNum = ENTITYNUM_NONE;
- ent->mass = 10;
- ent->takedamage = qtrue;
- /*ent->inuse = qtrue;
- SetInUse(ent);
- ent->m_iIcarusID = -1; // ICARUS_INVALID
- */
- assert(ent->inuse);
- assert(ent->m_iIcarusID==IIcarusInterface::ICARUS_INVALID);
- // CRITICAL NOTE! This was already done somewhere else and it was overwriting the previous value!!!
- if ( !ent->classname || Q_stricmp( ent->classname, "noclass" ) == 0 )
- ent->classname = "NPC";
- // if ( ent->client->race == RACE_HOLOGRAM )
- // {//can shoot through holograms, but not walk through them
- // ent->contents = CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_ITEM;//contents_corspe to make them show up in ID and use traces
- // ent->clipmask = MASK_NPCSOLID;
- // } else
- if(!(ent->spawnflags & SFB_NOTSOLID))
- {
- ent->contents = CONTENTS_BODY;
- ent->clipmask = MASK_NPCSOLID;
- }
- else
- {
- ent->contents = 0;
- ent->clipmask = MASK_NPCSOLID&~CONTENTS_BODY;
- }
- if(!ent->client->moveType)//Static?
- {
- ent->client->moveType = MT_RUNJUMP;
- }
- ent->e_DieFunc = dieF_player_die;
- ent->waterlevel = 0;
- ent->watertype = 0;
-
- //visible to player and NPCs
- if ( ent->client->NPC_class != CLASS_R2D2 &&
- ent->client->NPC_class != CLASS_R5D2 &&
- ent->client->NPC_class != CLASS_MOUSE &&
- ent->client->NPC_class != CLASS_GONK &&
- ent->client->NPC_class != CLASS_PROTOCOL )
- {
- ent->flags &= ~FL_NOTARGET;
- }
- ent->s.eFlags &= ~EF_NODRAW;
- NPC_SetFX_SpawnStates( ent );
-
- client->ps.friction = 6;
- if ( ent->client->ps.weapon == WP_NONE )
- {//not set by the NPCs.cfg
- NPC_SetWeapons(ent);
- }
- //select the weapon
- ent->NPC->currentAmmo = ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex];
- ent->client->ps.weaponstate = WEAPON_IDLE;
- ChangeWeapon( ent, ent->client->ps.weapon );
- VectorCopy( spawn_origin, client->ps.origin );
- // the respawned flag will be cleared after the attack and jump keys come up
- client->ps.pm_flags |= PMF_RESPAWNED;
- // clear entity state values
- ent->s.eType = ET_PLAYER;
- // ent->s.skinNum = ent - g_entities - 1; // used as index to get custom models
- VectorCopy (spawn_origin, ent->s.origin);
- // ent->s.origin[2] += 1; // make sure off ground
- SetClientViewAngle( ent, spawn_angles );
- client->renderInfo.lookTarget = ENTITYNUM_NONE;
- //clear IK grabbing stuff
- client->ps.heldClient = client->ps.heldByClient = ENTITYNUM_NONE;
- if(!(ent->spawnflags & 64))
- {
- if ( Q_stricmp( ent->NPC_type, "nullDriver") == 0 )
- {//FIXME: should be a better way to check this
- }
- else
- {
- G_KillBox( ent );
- }
- gi.linkentity (ent);
- }
- // don't allow full run speed for a bit
- client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
- client->ps.pm_time = 100;
- client->respawnTime = level.time;
- client->latched_buttons = 0;
- if ( ent->client->NPC_class != CLASS_VEHICLE )
- {
- // set default animations
- NPC_SetAnim( ent, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_NORMAL );
- }
- if( spawnPoint )
- {
- // fire the targets of the spawn point
- G_UseTargets( spawnPoint, ent );
- }
- //ICARUS include
- // NOTE! Does this need to be called here? It seems to be getting called twice...
- // Once before the level starts, then once again when the entity is spawned!
- Quake3Game()->InitEntity( ent );
- //==NPC initialization
- SetNPCGlobals( ent );
- ent->enemy = NPCInfo->eventualGoal;
- NPCInfo->timeOfDeath = 0;
- NPCInfo->shotTime = 0;
- NPC_ClearGoal();
- NPC_ChangeWeapon( ent->client->ps.weapon );
- //==Final NPC initialization
- ent->e_PainFunc = NPC_PainFunc( ent ); //painF_NPC_Pain;
- ent->e_TouchFunc = NPC_TouchFunc( ent ); //touchF_NPC_Touch;
- // ent->NPC->side = 1;
- ent->client->ps.ping = ent->NPC->stats.reactions * 50;
- //MCG - Begin: NPC hacks
- //FIXME: Set the team correctly
- ent->client->ps.persistant[PERS_TEAM] = ent->client->playerTeam;
- ent->e_UseFunc = useF_NPC_Use;
- ent->e_ThinkFunc = thinkF_NPC_Think;
- ent->nextthink = level.time + FRAMETIME + Q_irand(0, 100);
- NPC_SetMiscDefaultData( ent );
- if ( ent->health <= 0 )
- {
- //ORIGINAL ID: health will count down towards max_health
- ent->health = client->ps.stats[STAT_HEALTH] = ent->max_health;
- }
- else
- {
- client->ps.stats[STAT_HEALTH] = ent->max_health = ent->health;
- }
- ChangeWeapon( ent, ent->client->ps.weapon );//yes, again... sigh
- if ( !(ent->spawnflags & SFB_STARTINSOLID) )
- {//Not okay to start in solid
- G_CheckInSolid( ent, qtrue );
- }
- VectorClear( ent->NPC->lastClearOrigin );
- //Run a script if you have one assigned to you
- if ( G_ActivateBehavior( ent, BSET_SPAWN ) )
- {
- if( ent->m_iIcarusID != IIcarusInterface::ICARUS_INVALID/*ent->taskManager*/ && !stop_icarus )
- {
- IIcarusInterface::GetIcarus()->Update( ent->m_iIcarusID );
- }
- }
- VectorCopy( ent->currentOrigin, ent->client->renderInfo.eyePoint );
- // run a client frame to drop exactly to the floor,
- // initialize animations and other things
- memset( &ucmd, 0, sizeof( ucmd ) );
- _VectorCopy( client->pers.cmd_angles, ucmd.angles );
-
- ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
- if ( ent->NPC->aiFlags & NPCAI_MATCHPLAYERWEAPON )
- {
- G_MatchPlayerWeapon( ent );
- }
- ClientThink( ent->s.number, &ucmd );
- gi.linkentity( ent );
- if ( ent->client->playerTeam == TEAM_ENEMY || ent->client->playerTeam == TEAM_FREE )
- {//valid enemy spawned
- if ( !(ent->spawnflags&SFB_CINEMATIC) && ent->NPC->behaviorState != BS_CINEMATIC )
- {//not a cinematic enemy
- if ( g_entities[0].client )
- {
- g_entities[0].client->sess.missionStats.enemiesSpawned++;
- }
- }
- }
- }
- /*
- -------------------------
- NPC_StasisSpawn_Go
- -------------------------
- */
- /*
- qboolean NPC_StasisSpawn_Go( gentity_t *ent )
- {
- //Setup an owner pointer if we need it
- if VALIDSTRING( ent->ownername )
- {
- ent->owner = G_Find( NULL, FOFS( targetname ), ent->ownername );
-
- if ( ( ent->owner ) && ( ent->owner->health <= 0 ) )
- {//our spawner thing is broken
- if ( ent->target2 && ent->target2[0] )
- {
- //Fire off our target2
- G_UseTargets2( ent, ent, ent->target2 );
- //Kill us
- ent->e_ThinkFunc = thinkF_G_FreeEntity;
- ent->nextthink = level.time + 100;
- }
- else
- {
- //Try to spawn again in one second
- ent->e_ThinkFunc = thinkF_NPC_Spawn_Go;
- ent->nextthink = level.time + 1000;
- }
- return qfalse;
- }
- }
- //Test for an entity blocking the spawn
- trace_t tr;
- gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, MASK_NPCSOLID );
- //Can't have anything in the way
- if ( tr.allsolid || tr.startsolid )
- {
- ent->nextthink = level.time + 1000;
- return qfalse;
- }
- return qtrue;
- }
- */
- void NPC_DefaultScriptFlags( gentity_t *ent )
- {
- if ( !ent || !ent->NPC )
- {
- return;
- }
- //Set up default script flags
- ent->NPC->scriptFlags = (SCF_CHASE_ENEMIES|SCF_LOOK_FOR_ENEMIES);
- }
- #define MAX_SAFESPAWN_ENTS 4
- bool NPC_SafeSpawn( gentity_t *ent, float safeRadius )
- {
- gentity_t *radiusEnts[ MAX_SAFESPAWN_ENTS ];
- vec3_t safeMins, safeMaxs;
- float distance = 999999;
- int numEnts = 0;
- float safeRadiusSquared = safeRadius*safeRadius;
- if (!ent)
- {
- return false;
- }
- //Setup the bbox to search in
- for ( int i = 0; i < 3; i++ )
- {
- safeMins[i] = ent->currentOrigin[i] - safeRadius;
- safeMaxs[i] = ent->currentOrigin[i] + safeRadius;
- }
- //Get a number of entities in a given space
- numEnts = gi.EntitiesInBox( safeMins, safeMaxs, radiusEnts, MAX_SAFESPAWN_ENTS );
- for ( i = 0; i < numEnts; i++ )
- {
- //Don't consider self
- if ( radiusEnts[i] == ent )
- continue;
- if (radiusEnts[i]->NPC && (radiusEnts[i]->health == 0))
- {
- // ignore dead guys
- continue;
- }
- distance = DistanceSquared( ent->currentOrigin, radiusEnts[i]->currentOrigin );
- //Found one too close to us
- if ( distance < safeRadiusSquared )
- {
- return false;
- }
- }
- return true;
- }
- /*
- -------------------------
- NPC_Spawn_Go
- -------------------------
- */
- gentity_t *NPC_Spawn_Do( gentity_t *ent, qboolean fullSpawnNow )
- {
- gentity_t *newent;
- int index;
- vec3_t saveOrg;
- /* //Do extra code for stasis spawners
- if ( Q_stricmp( ent->classname, "NPC_Stasis" ) == 0 )
- {
- if ( NPC_StasisSpawn_Go( ent ) == qfalse )
- return;
- }
- */
- // 4/18/03 kef -- don't let guys spawn into other guys
- if (ent->spawnflags & 4096)
- {
- if (!NPC_SafeSpawn(ent, 64))
- {
- return NULL;
- }
- }
- //Test for drop to floor
- if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
- {
- trace_t tr;
- vec3_t bottom;
- VectorCopy( ent->currentOrigin, saveOrg );
- VectorCopy( ent->currentOrigin, bottom );
- bottom[2] = MIN_WORLD_COORD;
- gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, bottom, ent->s.number, MASK_NPCSOLID );
- if ( !tr.allsolid && !tr.startsolid && tr.fraction < 1.0 )
- {
- G_SetOrigin( ent, tr.endpos );
- }
- }
- //Check the spawner's count
- if( ent->count != -1 )
- {
- ent->count--;
-
- if( ent->count <= 0 )
- {
- ent->e_UseFunc = useF_NULL;//never again
- //will be removed below
- }
- }
- newent = G_Spawn();
- if ( newent == NULL )
- {
- gi.Printf ( S_COLOR_RED"ERROR: NPC G_Spawn failed\n" );
-
- if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
- {
- G_SetOrigin( ent, saveOrg );
- }
- return NULL;
- }
- newent->client = (gclient_s *)gi.Malloc(sizeof(gclient_s), TAG_G_ALLOC, qtrue);
-
- newent->svFlags |= SVF_NPC;
- if ( ent->NPC_type == NULL )
- {
- ent->NPC_type = "random";
- newent->NPC_type = "random";
- }
- else
- {
- newent->NPC_type = strlwr( G_NewString( ent->NPC_type ) ); //get my own copy so i can free it when i die
- }
- newent->NPC = (gNPC_t*) gi.Malloc(sizeof(gNPC_t), TAG_G_ALLOC, qtrue);
- newent->NPC->tempGoal = G_Spawn();
-
- newent->NPC->tempGoal->classname = "NPC_goal";
- newent->NPC->tempGoal->owner = newent;
- newent->NPC->tempGoal->svFlags |= SVF_NOCLIENT;
- //==NPC_Connect( newent, net_name );===================================
- if ( ent->svFlags & SVF_NO_BASIC_SOUNDS )
- {
- newent->svFlags |= SVF_NO_BASIC_SOUNDS;
- }
- if ( ent->svFlags & SVF_NO_COMBAT_SOUNDS )
- {
- newent->svFlags |= SVF_NO_COMBAT_SOUNDS;
- }
- if ( ent->svFlags & SVF_NO_EXTRA_SOUNDS )
- {
- newent->svFlags |= SVF_NO_EXTRA_SOUNDS;
- }
-
- if ( ent->message )
- {//has a key
- newent->message = G_NewString(ent->message);//copy the key name
- newent->flags |= FL_NO_KNOCKBACK;//don't fall off ledges
- }
- // If this is a vehicle we need to see what kind it is so we properlly allocate it.
- if ( Q_stricmp( ent->classname, "NPC_Vehicle" ) == 0 )
- {
- // Get the vehicle entry index.
- int iVehIndex = BG_VehicleGetIndex( newent->NPC_type );
- if ( iVehIndex == -1 )
- {
- Com_Printf( S_COLOR_RED"ERROR: Attempting to Spawn an unrecognized Vehicle! - %s\n", newent->NPC_type );
- G_FreeEntity( newent );
- if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
- {
- G_SetOrigin( ent, saveOrg );
- }
- return NULL;
- }
- newent->soundSet = G_NewString(ent->soundSet);//get my own copy so i can free it when i die
- // NOTE: If you change/add any of these, update NPC_Spawn_f for the new vehicle you
- // want to be able to spawn in manually.
- // See what kind of vehicle this is and allocate it properly.
- switch( g_vehicleInfo[iVehIndex].type )
- {
- case VH_ANIMAL:
- // Create the animal (making sure all it's data is initialized).
- G_CreateAnimalNPC( &newent->m_pVehicle, newent->NPC_type );
- break;
- case VH_SPEEDER:
- // Create the speeder (making sure all it's data is initialized).
- G_CreateSpeederNPC( &newent->m_pVehicle, newent->NPC_type );
- break;
- case VH_FIGHTER:
- // Create the fighter (making sure all it's data is initialized).
- G_CreateFighterNPC( &newent->m_pVehicle, newent->NPC_type );
- break;
- case VH_WALKER:
- // Create the animal (making sure all it's data is initialized).
- G_CreateWalkerNPC( &newent->m_pVehicle, newent->NPC_type );
- break;
- default:
- Com_Printf( S_COLOR_RED"ERROR: Attempting to Spawn an unrecognized Vehicle Type! - %s\n", newent->NPC_type );
- G_FreeEntity( newent );
- if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
- {
- G_SetOrigin( ent, saveOrg );
- }
- return NULL;
- }
- //grab this from the spawner
- if ( (ent->spawnflags&1) )
- {//wants to explode when not in vis of player
- newent->endFrame = ent->endFrame;
- }
- // Setup the vehicle.
- newent->m_pVehicle->m_pParentEntity = newent;
- newent->m_pVehicle->m_pVehicleInfo->Initialize( newent->m_pVehicle );
- newent->client->NPC_class = CLASS_VEHICLE;
- }
- else
- {
- newent->client->ps.weapon = WP_NONE;//init for later check in NPC_Begin
- }
- newent->classname = "NPC";
- VectorCopy(ent->s.origin, newent->s.origin);
- VectorCopy(ent->s.origin, newent->client->ps.origin);
- VectorCopy(ent->s.origin, newent->currentOrigin);
- G_SetOrigin(newent, ent->s.origin);//just to be sure!
- //NOTE: on vehicles, anything in the .npc file will STOMP data on the NPC that's set by the vehicle
- if ( !NPC_ParseParms( ent->NPC_type, newent ) )
- {
- gi.Printf ( S_COLOR_RED "ERROR: Couldn't spawn NPC %s\n", ent->NPC_type );
- G_FreeEntity( newent );
- if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
- {
- G_SetOrigin( ent, saveOrg );
- }
- return NULL;
- }
- if ( ent->NPC_type )
- {
- if ( !Q_stricmp( ent->NPC_type, "player" ) )
- {// Or check NPC_type against player's NPC_type?
- newent->NPC->aiFlags |= NPCAI_MATCHPLAYERWEAPON;
- }
- else if ( !Q_stricmp( ent->NPC_type, "test" ) )
- {
- int n;
- for ( n = 0; n < 1 ; n++)
- {
- if ( !(g_entities[n].svFlags & SVF_NPC) && g_entities[n].client)
- {
- VectorCopy(g_entities[n].s.origin, newent->s.origin);
- newent->client->playerTeam = g_entities[n].client->playerTeam;
- break;
- }
- }
- newent->NPC->defaultBehavior = newent->NPC->behaviorState = BS_WAIT;
- // newent->svFlags |= SVF_NOPUSH;
- }
- }
- //=====================================================================
- //set the info we want
- newent->health = ent->health;
- newent->wait = ent->wait;
- //copy strings so we can safely free them
- newent->script_targetname = G_NewString(ent->NPC_targetname);
- newent->targetname = G_NewString(ent->NPC_targetname);
- newent->target = G_NewString(ent->NPC_target);//death
- newent->target2 = G_NewString(ent->target2);//knocked out death
- newent->target3 = G_NewString(ent->target3);//???
- newent->target4 = G_NewString(ent->target4);//ffire death
- newent->paintarget = G_NewString(ent->paintarget);
- newent->opentarget = G_NewString(ent->opentarget);
- newent->radius = ent->radius;
- newent->NPC->eventualGoal = ent->enemy;
-
- for( index = BSET_FIRST; index < NUM_BSETS; index++)
- {
- if ( ent->behaviorSet[index] )
- {
- newent->behaviorSet[index] = ent->behaviorSet[index];
- }
- }
-
- VectorCopy(ent->s.angles, newent->s.angles);
- VectorCopy(ent->s.angles, newent->currentAngles);
- VectorCopy(ent->s.angles, newent->client->ps.viewangles);
- newent->NPC->desiredYaw =ent->s.angles[YAW];
-
- //gi.linkentity(newent); //check: don't need this here?
- newent->spawnflags = ent->spawnflags;
- //==New stuff=====================================================================
- newent->s.eType = ET_PLAYER;
-
- //FIXME: Call CopyParms
- if ( ent->parms )
- {
- for ( int parmNum = 0; parmNum < MAX_PARMS; parmNum++ )
- {
- if ( ent->parms->parm[parmNum] && ent->parms->parm[parmNum][0] )
- {
- Q3_SetParm( newent->s.number, parmNum, ent->parms->parm[parmNum] );
- }
- }
- }
- //FIXME: copy cameraGroup, store mine in message or other string field
- //set origin
- newent->s.pos.trType = TR_INTERPOLATE;
- newent->s.pos.trTime = level.time;
- VectorCopy( newent->currentOrigin, newent->s.pos.trBase );
- VectorClear( newent->s.pos.trDelta );
- newent->s.pos.trDuration = 0;
- //set angles
- newent->s.apos.trType = TR_INTERPOLATE;
- newent->s.apos.trTime = level.time;
- VectorCopy( newent->currentOrigin, newent->s.apos.trBase );
- VectorClear( newent->s.apos.trDelta );
- newent->s.apos.trDuration = 0;
-
- newent->NPC->combatPoint = -1;
- newent->NPC->aiFlags |= ent->bounceCount;//ai flags
- newent->flags |= FL_NOTARGET;//So he's ignored until he's fully spawned
- newent->s.eFlags |= EF_NODRAW;//So he's ignored until he's fully spawned
- if ( fullSpawnNow )
- {
- newent->owner = ent->owner;
- }
- else
- {
- newent->e_ThinkFunc = thinkF_NPC_Begin;
- newent->nextthink = level.time + FRAMETIME;
- }
- NPC_DefaultScriptFlags( newent );
- gi.linkentity (newent);
- if(ent->e_UseFunc == useF_NULL)
- {
- if( ent->target )
- {//use any target we're pointed at
- G_UseTargets ( ent, ent );
- }
- if(ent->closetarget)
- {//last guy should fire this target when he dies
- if (newent->target)
- {//zap
- gi.Free(newent->target);
- }
- newent->target = G_NewString(ent->closetarget);
- }
- G_FreeEntity( ent );//bye!
- }
- else if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
- {
- G_SetOrigin( ent, saveOrg );
- }
- if ( fullSpawnNow )
- {
- NPC_Begin( newent );
- }
- return newent;
- }
- void NPC_Spawn_Go( gentity_t *ent )
- {
- NPC_Spawn_Do( ent, qfalse );
- }
- /*
- -------------------------
- NPC_StasisSpawnEffect
- -------------------------
- */
- /*
- void NPC_StasisSpawnEffect( gentity_t *ent )
- {
- vec3_t start, end, forward;
- qboolean taper;
- //Floor or wall?
- if ( ent->spawnflags & 1 )
- {
- AngleVectors( ent->s.angles, forward, NULL, NULL );
- VectorMA( ent->currentOrigin, 24, forward, end );
- VectorMA( ent->currentOrigin, -20, forward, start );
-
- start[2] += 64;
-
- taper = qtrue;
- }
- else
- {
- VectorCopy( ent->currentOrigin, start );
- VectorCopy( start, end );
- end[2] += 48;
- taper = qfalse;
- }
- //Add the effect
- // CG_ShimmeryThing_Spawner( start, end, 32, qtrue, 1000 );
- }
- */
- /*
- -------------------------
- NPC_ShySpawn
- -------------------------
- */
- #define SHY_THINK_TIME 1000
- #define SHY_SPAWN_DISTANCE 128
- #define SHY_SPAWN_DISTANCE_SQR ( SHY_SPAWN_DISTANCE * SHY_SPAWN_DISTANCE )
- void NPC_ShySpawn( gentity_t *ent )
- {
- ent->nextthink = level.time + SHY_THINK_TIME;
- ent->e_ThinkFunc = thinkF_NPC_ShySpawn;
- if ( DistanceSquared( g_entities[0].currentOrigin, ent->currentOrigin ) <= SHY_SPAWN_DISTANCE_SQR )
- return;
- if ( (InFOV( ent, &g_entities[0], 80, 64 )) ) // FIXME: hardcoded fov
- if ( (NPC_ClearLOS( &g_entities[0], ent->currentOrigin )) )
- return;
- // 4/18/03 kef -- don't let guys spawn into other guys
- if (ent->spawnflags & 4096)
- {
- if (!NPC_SafeSpawn(ent, 64))
- {
- return;
- }
- }
- ent->e_ThinkFunc = thinkF_NULL;
- ent->nextthink = 0;
- NPC_Spawn_Go( ent );
- }
- /*
- -------------------------
- NPC_Spawn
- -------------------------
- */
- void NPC_Spawn ( gentity_t *ent, gentity_t *other, gentity_t *activator )
- {
- //delay before spawning NPC
- if (other->spawnflags&32)
- {
- ent->enemy = activator;
- }
- if( ent->delay )
- {
- /* //Stasis does an extra step
- if ( Q_stricmp( ent->classname, "NPC_Stasis" ) == 0 )
- {
- if ( NPC_StasisSpawn_Go( ent ) == qfalse )
- return;
- }
- */
- if ( ent->spawnflags & 2048 ) // SHY
- ent->e_ThinkFunc = thinkF_NPC_ShySpawn;
- else
- ent->e_ThinkFunc = thinkF_NPC_Spawn_Go;
- ent->nextthink = level.time + ent->delay;
- }
- else
- {
- if ( ent->spawnflags & 2048 ) // SHY
- NPC_ShySpawn( ent );
- else
- NPC_Spawn_Go( ent );
- }
- }
- /*QUAKED NPC_spawner (1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY SAFE
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- SAFE - Won't spawn if an entity is within 64 units
- NPC_type - name of NPC (in npcs.cfg) to spawn in
- targetname - name this NPC goes by for targetting
- target - NPC will fire this when it spawns it's last NPC (should this be when the last NPC it spawned dies?)
- target2 - Fired by stasis spawners when they try to spawn while their spawner model is broken
- target3 - Fired by spawner if they try to spawn and are blocked and have a wait < 0 (removes them)
- If targeted, will only spawn a NPC when triggered
- count - how many NPCs to spawn (only if targetted) default = 1
- delay - how long to wait to spawn after used
- wait - if trying to spawn and blocked, how many seconds to wait before trying again (default = 0.5, < 0 = never try again and fire target2)
- NPC_targetname - NPC's targetname AND script_targetname
- NPC_target - NPC's target to fire when killed
- NPC_target2 - NPC's target to fire when knocked out
- NPC_target4 - NPC's target to fire when killed by friendly fire
- NPC_type - type of NPC ("Borg" (default), "Xian", etc)
- health - starting health (default = 100)
- "noBasicSounds" - set to 1 to prevent loading and usage of basic sounds (pain, death, etc)
- "noCombatSounds" - set to 1 to prevent loading and usage of combat sounds (anger, victory, etc.)
- "noExtraSounds" - set to 1 to prevent loading and usage of "extra" sounds (chasing the enemy - detecting them, flanking them... also jedi combat sounds)
- spawnscript - default script to run once spawned (none by default)
- usescript - default script to run when used (none by default)
- awakescript - default script to run once awoken (none by default)
- angerscript - default script to run once angered (none by default)
- painscript - default script to run when hit (none by default)
- fleescript - default script to run when hit and below 50% health (none by default)
- deathscript - default script to run when killed (none by default)
- These strings can be used to activate behaviors instead of scripts - these are checked
- first and so no scripts should be names with these names:
- default - 0: whatever
- idle - 1: Stand around, do abolutely nothing
- roam - 2: Roam around, collect stuff
- walk - 3: Crouch-Walk toward their goals
- run - 4: Run toward their goals
- standshoot - 5: Stay in one spot and shoot- duck when neccesary
- standguard - 6: Wait around for an enemy
- patrol - 7: Follow a path, looking for enemies
- huntkill - 8: Track down enemies and kill them
- evade - 9: Run from enemies
- evadeshoot - 10: Run from enemies, shoot them if they hit you
- runshoot - 11: Run to your goal and shoot enemy when possible
- defend - 12: Defend an entity or spot?
- snipe - 13: Stay hidden, shoot enemy only when have perfect shot and back turned
- combat - 14: Attack, evade, use cover, move about, etc. Full combat AI - id NPC code
- medic - 15: Go for lowest health buddy, hide and heal him.
- takecover - 16: Find nearest cover from enemies
- getammo - 17: Go get some ammo
- advancefight - 18: Go somewhere and fight along the way
- face - 19: turn until facing desired angles
- wait - 20: do nothing
- formation - 21: Maintain a formation
- crouch - 22: Crouch-walk toward their goals
- delay - after spawned or triggered, how many seconds to wait to spawn the NPC
- */
- //void NPC_PrecacheModels ( char *NPCName );
- extern qboolean spawning; // the G_Spawn*() functions are valid (only turned on during one function)
- extern void NPC_PrecacheByClassName(const char*);
- void SP_NPC_spawner( gentity_t *self)
- {
- extern void NPC_PrecacheAnimationCFG( const char *NPC_type );
- float fDelay;
- //register/precache the models needed for this NPC, not anymore
- //self->classname = "NPC_spawner";
- if(!self->count)
- {
- self->count = 1;
- }
- //NOTE: bounceCount is transferred to the spawned NPC's NPC->aiFlags
- self->bounceCount = 0;
- {
- static int garbage;
- //Stop loading of certain extra sounds
- if ( G_SpawnInt( "noBasicSounds", "0", &garbage ) )
- {
- self->svFlags |= SVF_NO_BASIC_SOUNDS;
- }
- if ( G_SpawnInt( "noCombatSounds", "0", &garbage ) )
- {
- self->svFlags |= SVF_NO_COMBAT_SOUNDS;
- }
- if ( G_SpawnInt( "noExtraSounds", "0", &garbage ) )
- {
- self->svFlags |= SVF_NO_EXTRA_SOUNDS;
- }
- if ( G_SpawnInt( "nodelay", "0", &garbage ) )
- {
- self->bounceCount |= NPCAI_NO_JEDI_DELAY;
- }
- }
- if ( !self->wait )
- {
- self->wait = 500;
- }
- else
- {
- self->wait *= 1000;//1 = 1 msec, 1000 = 1 sec
- }
- G_SpawnFloat( "delay", "0", &fDelay );
- if ( fDelay )
- {
- self->delay = ceil(1000.0f*fDelay);//1 = 1 msec, 1000 = 1 sec
- }
- if ( self->delay > 0 )
- {
- self->svFlags |= SVF_NPC_PRECACHE;
- }
- //We have to load the animation.cfg now because spawnscripts are going to want to set anims and we need to know their length and if they're valid
- NPC_PrecacheAnimationCFG( self->NPC_type );
- if ( self->targetname )
- {//Wait for triggering
- self->e_UseFunc = useF_NPC_Spawn;
- self->svFlags |= SVF_NPC_PRECACHE;//FIXME: precache my weapons somehow?
- //NPC_PrecacheModels( self->NPC_type );
- }
- else
- {
- //NOTE: auto-spawners never check for shy spawning
- if ( spawning )
- {//in entity spawn stage - map starting up
- self->e_ThinkFunc = thinkF_NPC_Spawn_Go;
- self->nextthink = level.time + START_TIME_REMOVE_ENTS + 50;
- }
- else
- {//else spawn right now
- NPC_Spawn( self, self, self );
- }
- }
- if (!(self->svFlags&SVF_NPC_PRECACHE))
- {
- NPC_PrecacheByClassName(self->NPC_type);
- }
- //FIXME: store cameraGroup somewhere else and apply to spawned NPCs' cameraGroup
- //Or just don't include NPC_spawners in cameraGroupings
- if ( self->message )
- {//may drop a key, precache the key model and pickup sound
- G_SoundIndex( "sound/weapons/key_pkup.wav" );
- if ( !Q_stricmp( "goodie", self->message ) )
- {
- RegisterItem( FindItemForInventory( INV_GOODIE_KEY ) );
- }
- else
- {
- RegisterItem( FindItemForInventory( INV_SECURITY_KEY ) );
- }
- }
- }
- //=============================================================================================
- //VEHICLES
- //=============================================================================================
- /*QUAKED NPC_Vehicle (1 0 0) (-16 -16 -24) (16 16 32) NO_VIS_DIE x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY SAFE
- set NPC_type to vehicle name in vehicles.dat
- NO_VIS_DIE - die after certain amount of time of not having a LOS to the Player (default time is 10 seconds, change by setting "noVisTime")
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- SAFE - Won't spawn if an entity is within 64 units
- "noVisTime" - how long to wait after spawning/last being seen by the player beforw blowing ourselves up (default is 10 seconds)
- "skin" - which skin to set "red" for example - If no skin it is random
- */
- void NPC_VehicleSpawnUse( gentity_t *self, gentity_t *other, gentity_t *activator )
- {
- G_VehicleSpawn( self );
- }
- void SP_NPC_Vehicle( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- self->NPC_type = "swoop";
- }
- if ( !self->classname )
- {
- self->classname = "NPC_Vehicle";
- }
- G_SetOrigin( self, self->s.origin );
- G_SetAngles( self, self->s.angles );
- G_SpawnString("skin", "", &self->soundSet);
- //grab this from the spawner
- if ( (self->spawnflags&1) )
- {//wants to explode when not in vis of player
- if ( !self->endFrame )
- {
- self->endFrame = NO_PILOT_DIE_TIME;
- }
- }
- if ( self->targetname )
- {
- self->svFlags |= SVF_NPC_PRECACHE; // Precache The Bike when all other npcs are precached
- self->e_UseFunc = useF_NPC_VehicleSpawnUse;
- //we're not spawning until later, so precache us now
- BG_VehicleGetIndex( self->NPC_type );
- }
- else
- {
- G_VehicleSpawn( self );
- }
- }
- //=============================================================================================
- //CHARACTERS
- //=============================================================================================
- /*QUAKED NPC_Player (1 0 0) (-16 -16 -24) (16 16 32) x RIFLEMAN PHASER TRICORDER DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Player( gentity_t *self)
- {
- self->NPC_type = "Player";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Kyle (1 0 0) (-16 -16 -24) (16 16 32) BOSS x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- BOSS - Uses Boss AI
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Kyle( gentity_t *self)
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "Kyle_boss";
- }
- else
- {
- self->NPC_type = "Kyle";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Lando(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Lando( gentity_t *self)
- {
- self->NPC_type = "Lando";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Jan(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Jan( gentity_t *self)
- {
- self->NPC_type = "Jan";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Luke(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Luke( gentity_t *self)
- {
- self->NPC_type = "Luke";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_MonMothma(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_MonMothma( gentity_t *self)
- {
- self->NPC_type = "MonMothma";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Rosh_Penin (1 0 0) (-16 -16 -24) (16 16 32) DARKSIDE NOFORCE x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- Good Rosh
- DARKSIDE - Evil Rosh
- NOFORCE - Can't jump, starts with no saber
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Rosh_Penin( gentity_t *self)
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "rosh_dark";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "rosh_penin_noforce";
- }
- else
- {
- self->NPC_type = "rosh_penin";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Tavion (1 0 0) (-16 -16 -24) (16 16 32) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Tavion( gentity_t *self)
- {
- self->NPC_type = "Tavion";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Tavion_New (1 0 0) (-16 -16 -24) (16 16 32) SCEPTER SITH_SWORD x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Has a red lightsaber and force powers, uses her saber style from JK2
- SCEPTER - Has a red lightsaber and force powers, Ragnos' Scepter in left hand, uses dual saber style and occasionally attacks with Scepter
- SITH_SWORD - Has Ragnos' Sith Sword in right hand and force powers, uses strong style
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Tavion_New( gentity_t *self)
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "tavion_scepter";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "tavion_sith_sword";
- }
- else
- {
- self->NPC_type = "tavion_new";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Alora (1 0 0) (-16 -16 -24) (16 16 32) DUAL x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Lightsaber and level 2 force powers, 300 health
- DUAL - Dual sabers and level 3 force powers, 500 health
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Alora( gentity_t *self)
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "alora_dual";
- }
- else
- {
- self->NPC_type = "alora";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Reelo(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Reelo( gentity_t *self)
- {
- self->NPC_type = "Reelo";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Galak(1 0 0) (-16 -16 -24) (16 16 40) MECH x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- MECH - will be the armored Galak
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Galak( gentity_t *self)
- {
- }
- /*QUAKED NPC_Desann(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Desann( gentity_t *self)
- {
- self->NPC_type = "Desann";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Rax(1 0 0) (-16 -16 -24) (16 16 40) FUN x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- FUN - Makes him magically the funnest thing ever in any game ever made. (actually does nothing, it'll just be fun by the power of suggestion).
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Rax( gentity_t *self )
- {
- self->NPC_type = "Rax";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_BobaFett(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_BobaFett( gentity_t *self )
- {
- self->NPC_type = "Boba_Fett";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Ragnos(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Ragnos( gentity_t *self )
- {
- self->NPC_type = "Ragnos";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Lannik_Racto(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Lannik_Racto( gentity_t *self )
- {
- self->NPC_type = "lannik_racto";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Kothos(1 0 0) (-16 -16 -24) (16 16 40) VIL x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- VIL - spawns Vil Kothos instead of Dasariah (can anyone tell them apart anyway...?)
- Force only... will (eventually) be set up to re-inforce their leader (use SET_LEADER) by healing them, recharging them, keeping the player away, etc.
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Kothos( gentity_t *self )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "VKothos";
- }
- else
- {
- self->NPC_type = "DKothos";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Chewbacca(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Chewbacca( gentity_t *self )
- {
- self->NPC_type = "Chewie";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Bartender(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Bartender( gentity_t *self)
- {
- self->NPC_type = "Bartender";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_MorganKatarn(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_MorganKatarn( gentity_t *self)
- {
- self->NPC_type = "MorganKatarn";
- SP_NPC_spawner( self );
- }
- //=============================================================================================
- //ALLIES
- //=============================================================================================
- /*QUAKED NPC_Jedi(1 0 0) (-16 -16 -24) (16 16 40) TRAINER MASTER RANDOM x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- TRAINER - Special Jedi- instructor
- MASTER - Special Jedi- master
- RANDOM - creates a random Jedi student using the available player models/skins (excludes the current model of the player)
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Ally Jedi NPC Buddy - tags along with player
- */
- static char *randomJedis[] = {
- "jedi_hf1",
- "jedi_rm1",
- "jedi_zf1",
- "jedi_hm1",
- "jedi_tf1",
- "jedi_kdm1",
- };
- extern cvar_t *g_char_model;
- void SP_NPC_Jedi( gentity_t *self)
- {
- if(!self->NPC_type)
- {
- if ( self->spawnflags & 4 ) // Random jedi student
- {
- static unsigned long jediSequence = 0;
- int myIdx;
- for (myIdx = 0; myIdx < 6; ++myIdx)
- if (strstr(randomJedis[myIdx], g_char_model->string))
- break;
- // Sanity check, if player doesn't have a jedi_xx model right now:
- if (myIdx == 6)
- myIdx = 0;
- // Get one of the three after ours:
- int idx = (myIdx + (jediSequence % 3) + 1) % 6;
- jediSequence++;
- self->NPC_type = randomJedis[idx];
- }
- else if ( self->spawnflags & 2 )
- {
- self->NPC_type = "jedimaster";
- }
- else if ( self->spawnflags & 1 )
- {
- self->NPC_type = "jeditrainer";
- }
- else
- {
- /*
- if ( !Q_irand( 0, 2 ) )
- {
- self->NPC_type = "JediF";
- }
- else
- */if ( Q_irand( 0, 1 ) )
- {
- self->NPC_type = "Jedi";
- }
- else
- {
- self->NPC_type = "Jedi2";
- }
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Prisoner(1 0 0) (-16 -16 -24) (16 16 40) ELDER x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Prisoner( gentity_t *self)
- {
- if(!self->NPC_type)
- {
- if ( (self->spawnflags&1) )
- {
- if ( Q_irand( 0, 1 ) )
- {
- self->NPC_type = "elder";
- }
- else
- {
- self->NPC_type = "elder2";
- }
- }
- else
- {
- if ( Q_irand( 0, 1 ) )
- {
- self->NPC_type = "Prisoner";
- }
- else
- {
- self->NPC_type = "Prisoner2";
- }
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Merchant(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Merchant( gentity_t *self)
- {
- self->NPC_type = "merchant";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Rebel(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Rebel( gentity_t *self)
- {
- if(!self->NPC_type)
- {
- self->NPC_type = "Rebel";
- }
- SP_NPC_spawner( self );
- }
- //=============================================================================================
- //ENEMIES
- //=============================================================================================
- /*QUAKED NPC_Human_Merc(1 0 0) (-16 -16 -24) (16 16 40) BOWCASTER REPEATER FLECHETTE CONCUSSION DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- 100 health, blaster rifle
- BOWCASTER - Starts with a Bowcaster
- REPEATER - Starts with a Repeater
- FLECHETTE - Starts with a Flechette gun
- CONCUSSION - Starts with a Concussion Rifle
- If you want them to start with any other kind of weapon, make a spawnscript for them that sets their weapon.
- "message" - turns on his key surface. This is the name of the key you get when you walk over his body. This must match the "message" field of the func_security_panel you want this key to open. Set to "goodie" to have him carrying a goodie key that player can use to operate doors with "GOODIE" spawnflag. NOTE: this overrides all the weapon spawnflags
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Human_Merc( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( self->message )
- {
- self->NPC_type = "human_merc_key";
- }
- else if ( (self->spawnflags&1) )
- {
- self->NPC_type = "human_merc_bow";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "human_merc_rep";
- }
- else if ( (self->spawnflags&4) )
- {
- self->NPC_type = "human_merc_flc";
- }
- else if ( (self->spawnflags&8) )
- {
- self->NPC_type = "human_merc_cnc";
- }
- else
- {
- self->NPC_type = "human_merc";
- }
- }
- SP_NPC_spawner( self );
- }
- //TROOPERS=============================================================================
- /*QUAKED NPC_Stormtrooper(1 0 0) (-16 -16 -24) (16 16 40) OFFICER COMMANDER ALTOFFICER ROCKET DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY COMMANDO
- 30 health, blaster
- OFFICER - 60 health, flechette
- COMMANDER - 60 health, heavy repeater
- ALTOFFICER - 60 health, alt-fire flechette (grenades)
- ROCKET - 60 health, rocket launcher
- COMMANDO - Causes character to use Hazard Trooper (move in formation AI)
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Stormtrooper( gentity_t *self)
- {
- if ( self->spawnflags & 8 )
- {//rocketer
- self->NPC_type = "rockettrooper";
- }
- else if ( self->spawnflags & 4 )
- {//alt-officer
- self->NPC_type = "stofficeralt";
- }
- else if ( self->spawnflags & 2 )
- {//commander
- self->NPC_type = "stcommander";
- }
- else if ( self->spawnflags & 1 )
- {//officer
- self->NPC_type = "stofficer";
- }
- else
- {//regular trooper
- if ( Q_irand( 0, 1 ) )
- {
- self->NPC_type = "StormTrooper";
- }
- else
- {
- self->NPC_type = "StormTrooper2";
- }
- }
- SP_NPC_spawner( self );
- }
- void SP_NPC_StormtrooperOfficer( gentity_t *self)
- {
- self->spawnflags |= 1;
- SP_NPC_Stormtrooper( self );
- }
- /*QUAKED NPC_Snowtrooper(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- 30 health, blaster
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Snowtrooper( gentity_t *self)
- {
- self->NPC_type = "snowtrooper";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Tie_Pilot(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- 30 health, blaster
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Tie_Pilot( gentity_t *self)
- {
- self->NPC_type = "stormpilot";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_RocketTrooper(1 0 0) (-16 -16 -24) (16 16 40) OFFICER SPOTLIGHT x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- 200 health, flies, rockets
- OFFICER - starts flying, uses concussion rifle instead of rockets
- SPOTLIGHT - uses a shoulder-mounted spotlight
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_RocketTrooper( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "rockettrooper2Officer";
- }
- else
- {
- self->NPC_type = "rockettrooper2";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_HazardTrooper(1 0 0) (-16 -16 -24) (16 16 40) OFFICER CONCUSSION x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- 250 health, repeater
- OFFICER - 400 health, flechette
- CONCUSSION - 400 health, concussion rifle
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_HazardTrooper( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "hazardtrooperofficer";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "hazardtrooperconcussion";
- }
- else
- {
- self->NPC_type = "hazardtrooper";
- }
- }
- SP_NPC_spawner( self );
- }
- //OTHERS=============================================================================
- /*QUAKED NPC_Ugnaught(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Ugnaught( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( Q_irand( 0, 1 ) )
- {
- self->NPC_type = "Ugnaught";
- }
- else
- {
- self->NPC_type = "Ugnaught2";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Jawa(1 0 0) (-16 -16 -24) (16 16 40) ARMED x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- ARMED - starts with the Jawa gun in-hand
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Jawa( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "jawa_armed";
- }
- else
- {
- self->NPC_type = "jawa";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Gran(1 0 0) (-16 -16 -24) (16 16 40) SHOOTER BOXER x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- Uses grenade
- SHOOTER - uses blaster instead of
- BOXER - uses fists only
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Gran( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( self->spawnflags & 1 )
- {
- self->NPC_type = "granshooter";
- }
- else if ( self->spawnflags & 2 )
- {
- self->NPC_type = "granboxer";
- }
- else
- {
- if ( Q_irand( 0, 1 ) )
- {
- self->NPC_type = "gran";
- }
- else
- {
- self->NPC_type = "gran2";
- }
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Rodian(1 0 0) (-16 -16 -24) (16 16 40) BLASTER NO_HIDE x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- BLASTER uses a blaster instead of sniper rifle, different skin
- NO_HIDE (only applicable with snipers) does not duck and hide between shots
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Rodian( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( self->spawnflags&1 )
- {
- self->NPC_type = "rodian2";
- }
- else
- {
- self->NPC_type = "rodian";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Weequay(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Weequay( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- switch ( Q_irand( 0, 3 ) )
- {
- case 0:
- self->NPC_type = "Weequay";
- break;
- case 1:
- self->NPC_type = "Weequay2";
- break;
- case 2:
- self->NPC_type = "Weequay3";
- break;
- case 3:
- self->NPC_type = "Weequay4";
- break;
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Trandoshan(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Trandoshan( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- self->NPC_type = "Trandoshan";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Tusken(1 0 0) (-16 -16 -24) (16 16 40) SNIPER x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Tusken( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "tuskensniper";
- }
- else
- {
- self->NPC_type = "tusken";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Noghri(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Noghri( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- self->NPC_type = "noghri";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_SwampTrooper(1 0 0) (-16 -16 -24) (16 16 40) REPEATER x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- REPEATER - Swaptrooper who uses the repeater
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_SwampTrooper( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( self->spawnflags & 1 )
- {
- self->NPC_type = "SwampTrooper2";
- }
- else
- {
- self->NPC_type = "SwampTrooper";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Imperial(1 0 0) (-16 -16 -24) (16 16 40) OFFICER COMMANDER x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- Greyshirt grunt, uses blaster pistol, 20 health.
- OFFICER - Brownshirt Officer, uses blaster rifle, 40 health
- COMMANDER - Blackshirt Commander, uses rapid-fire blaster rifle, 80 healt
- "message" - if a COMMANDER, turns on his key surface. This is the name of the key you get when you walk over his body. This must match the "message" field of the func_security_panel you want this key to open. Set to "goodie" to have him carrying a goodie key that player can use to operate doors with "GOODIE" spawnflag.
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Imperial( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( self->spawnflags & 1 )
- {
- self->NPC_type = "ImpOfficer";
- }
- else if ( self->spawnflags & 2 )
- {
- self->NPC_type = "ImpCommander";
- }
- else
- {
- self->NPC_type = "Imperial";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_ImpWorker(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_ImpWorker( gentity_t *self)
- {
- self->NPC_type = "ImpWorker";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_BespinCop(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_BespinCop( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( !Q_irand( 0, 1 ) )
- {
- self->NPC_type = "BespinCop";
- }
- else
- {
- self->NPC_type = "BespinCop2";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Reborn(1 0 0) (-16 -16 -24) (16 16 40) FORCE FENCER ACROBAT BOSS CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Default Reborn is A poor lightsaber fighter, acrobatic and uses no force powers. 40 health.
- FORCE - Uses force powers but is not the best lightsaber fighter and not acrobatic. 75 health.
- FENCER - A good lightsaber fighter, but not acrobatic and uses no force powers. 100 health.
- ACROBAT - quite acrobatic, but not the best lightsaber fighter and uses no force powers. 100 health.
- BOSS - quite acrobatic, good lightsaber fighter and uses force powers. 150 health.
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Reborn not stand around and taunt the player before attacking
- */
- void SP_NPC_Reborn( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( self->spawnflags & 1 )
- {
- self->NPC_type = "rebornforceuser";
- }
- else if ( self->spawnflags & 2 )
- {
- self->NPC_type = "rebornfencer";
- }
- else if ( self->spawnflags & 4 )
- {
- self->NPC_type = "rebornacrobat";
- }
- else if ( self->spawnflags & 8 )
- {
- self->NPC_type = "rebornboss";
- }
- else
- {
- self->NPC_type = "reborn";
- }
- }
-
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Reborn_New(1 0 0) (-16 -16 -24) (16 16 40) DUAL STAFF WEAK MASTER CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Reborn is an excellent lightsaber fighter, acrobatic and uses force powers. Full-length red saber, 200 health.
- DUAL - Use 2 shorter sabers
- STAFF - Uses a saber staff
- WEAK - Is a bit less tough
- MASTER - Is SUPER tough
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Reborn not stand around and taunt the player before attacking
- */
- void SP_NPC_Reborn_New( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&8) )
- {//tougher guys
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "RebornMasterDual";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "RebornMasterStaff";
- }
- else
- {
- self->NPC_type = "RebornMaster";
- }
- }
- else if ( (self->spawnflags&4) )
- {//weaker guys
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "reborn_dual2";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "reborn_staff2";
- }
- else
- {
- self->NPC_type = "reborn_new2";
- }
- }
- else
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "reborn_dual";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "reborn_staff";
- }
- else
- {
- self->NPC_type = "reborn_new";
- }
- }
- }
-
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Cultist_Saber(1 0 0) (-16 -16 -24) (16 16 40) MED STRONG ALL THROW CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Uses a saber and no force powers. 100 health.
- default fencer uses fast style - weak, but can attack rapidly. Good defense.
- MED - Uses medium style - average speed and attack strength, average defense.
- STRONG - Uses strong style, slower than others, but can do a lot of damage with one blow. Weak defense.
- ALL - Knows all 3 styles, switches between them, good defense.
- THROW - can throw their saber (level 2) - reduces their defense some (can use this spawnflag alone or in combination with any *one* of the previous 3 spawnflags)
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Cultist not stand around and taunt the player before attacking
- */
- void SP_NPC_Cultist_Saber( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_med_throw";
- }
- else
- {
- self->NPC_type = "cultist_saber_med";
- }
- }
- else if ( (self->spawnflags&2) )
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_strong_throw";
- }
- else
- {
- self->NPC_type = "cultist_saber_strong";
- }
- }
- else if ( (self->spawnflags&2) )
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_all_throw";
- }
- else
- {
- self->NPC_type = "cultist_saber_all";
- }
- }
- else
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_throw";
- }
- else
- {
- self->NPC_type = "cultist_saber";
- }
- }
- }
-
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Cultist_Saber_Powers(1 0 0) (-16 -16 -24) (16 16 40) MED STRONG ALL THROW CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Uses a saber and has a couple low-level powers. 150 health.
- default fencer uses fast style - weak, but can attack rapidly. Good defense.
- MED - Uses medium style - average speed and attack strength, average defense.
- STRONG - Uses strong style, slower than others, but can do a lot of damage with one blow. Weak defense.
- ALL - Knows all 3 styles, switches between them, good defense.
- THROW - can throw their saber (level 2) - reduces their defense some (can use this spawnflag alone or in combination with any *one* of the previous 3 spawnflags)
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Cultist not stand around and taunt the player before attacking
- */
- void SP_NPC_Cultist_Saber_Powers( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_med_throw2";
- }
- else
- {
- self->NPC_type = "cultist_saber_med2";
- }
- }
- else if ( (self->spawnflags&2) )
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_strong_throw2";
- }
- else
- {
- self->NPC_type = "cultist_saber_strong2";
- }
- }
- else if ( (self->spawnflags&2) )
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_all_throw2";
- }
- else
- {
- self->NPC_type = "cultist_saber_all2";
- }
- }
- else
- {
- if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_saber_throw";
- }
- else
- {
- self->NPC_type = "cultist_saber2";
- }
- }
- }
-
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Cultist(1 0 0) (-16 -16 -24) (16 16 40) SABER GRIP LIGHTNING DRAIN CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Cultist uses a blaster and force powers. 40 health.
- SABER - Uses a saber and no force powers
- GRIP - Uses no weapon and grip, push and pull
- LIGHTNING - Uses no weapon and lightning and push
- DRAIN - Uses no weapons and drain and push
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Cultist not stand around and taunt the player before attacking
- */
- void SP_NPC_Cultist( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = NULL;
- self->spawnflags = 0;//fast, no throw
- switch ( Q_irand( 0, 2 ) )
- {
- case 0://medium
- self->spawnflags |= 1;
- break;
- case 1://strong
- self->spawnflags |= 2;
- break;
- case 2://all
- self->spawnflags |= 4;
- break;
- }
- if ( Q_irand( 0, 1 ) )
- {//throw
- self->spawnflags |= 8;
- }
- SP_NPC_Cultist_Saber( self );
- return;
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "cultist_grip";
- }
- else if ( (self->spawnflags&4) )
- {
- self->NPC_type = "cultist_lightning";
- }
- else if ( (self->spawnflags&8) )
- {
- self->NPC_type = "cultist_drain";
- }
- else
- {
- self->NPC_type = "cultist";
- }
- }
-
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Cultist_Commando(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Cultist uses dual blaster pistols and force powers. 40 health.
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Cultist not stand around and taunt the player before attacking
- */
- void SP_NPC_Cultist_Commando( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- self->NPC_type = "cultistcommando";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Cultist_Destroyer(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- Cultist has no weapons, runs up to you chanting & building up a Force Destruction blast - when gets to you, screams & explodes
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Cultist_Destroyer( gentity_t *self)
- {
- self->NPC_type = "cultist_destroyer";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_ShadowTrooper(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
- CEILING - Sticks to the ceiling until he sees an enemy or takes pain
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- nodelay - set to "1" to make the Cultist not stand around and taunt the player before attacking
- */
- void SP_NPC_ShadowTrooper( gentity_t *self)
- {
- if(!self->NPC_type)
- {
- if ( !Q_irand( 0, 1 ) )
- {
- self->NPC_type = "ShadowTrooper";
- }
- else
- {
- self->NPC_type = "ShadowTrooper2";
- }
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Saboteur(1 0 0) (-16 -16 -24) (16 16 40) SNIPER PISTOL x x CLOAKED CINEMATIC NOTSOLID STARTINSOLID SHY
- Has a blaster rifle, can cloak and roll
- SNIPER - Has a sniper rifle, no acrobatics, but can dodge
- PISTOL - Just has a pistol, can roll
- COMMANDO - Has 2 pistols and can roll & dodge
- CLOAKED - Starts cloaked
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Saboteur( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "saboteursniper";
- }
- else if ( (self->spawnflags&2) )
- {
- self->NPC_type = "saboteurpistol";
- }
- else if ( (self->spawnflags&4) )
- {
- self->NPC_type = "saboteurcommando";
- }
- else
- {
- self->NPC_type = "saboteur";
- }
- }
- SP_NPC_spawner( self );
- }
- //=============================================================================================
- //MONSTERS
- //=============================================================================================
- /*QUAKED NPC_Monster_Murjj (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Murjj( gentity_t *self)
- {
- self->NPC_type = "Murjj";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Swamp (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Swamp( gentity_t *self)
- {
- self->NPC_type = "Swamp";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Howler (1 0 0) (-16 -16 -24) (16 16 8) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Howler( gentity_t *self)
- {
- self->NPC_type = "howler";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Rancor (1 0 0) (-30 -30 -24) (30 30 136) MUTANT FASTKILL x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- 2000 health, picks people up and eats them
- MUTANT - Bigger, meaner, nastier, Frencher. Breath attack, pound attack.
- FASTKILL - Kills NPCs faster
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Rancor( gentity_t *self)
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "mutant_rancor";
- }
- else
- {
- self->NPC_type = "rancor";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Mutant_Rancor (1 0 0) (-60 -60 -24) (60 60 360) x FASTKILL x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- Bigger, meaner, nastier, Frencher. Breath attack, pound attack.
- FASTKILL - Kills NPCs faster
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Mutant_Rancor( gentity_t *self)
- {
- self->NPC_type = "mutant_rancor";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Wampa (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Wampa( gentity_t *self)
- {
- self->NPC_type = "wampa";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_MineMonster (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_MineMonster( gentity_t *self)
- {
- self->NPC_type = "minemonster";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Claw (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Claw( gentity_t *self)
- {
- self->NPC_type = "Claw";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Glider (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Glider( gentity_t *self)
- {
- self->NPC_type = "Glider";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Flier2 (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Flier2( gentity_t *self)
- {
- self->NPC_type = "Flier2";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Lizard (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Lizard( gentity_t *self)
- {
- self->NPC_type = "Lizard";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Fish (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Monster_Fish( gentity_t *self)
- {
- self->NPC_type = "Fish";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Monster_Sand_Creature (1 0 0) (-24 -24 -24) (24 24 0) FAST x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- turfrange - if set, they will not go beyond this dist from their spawn position
- */
- void SP_NPC_Monster_Sand_Creature( gentity_t *self)
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "sand_creature_fast";
- }
- else
- {
- self->NPC_type = "sand_creature";
- }
- SP_NPC_spawner( self );
- }
- //=============================================================================================
- //DROIDS
- //=============================================================================================
- /*QUAKED NPC_Droid_Interrogator (1 0 0) (-12 -12 -24) (12 12 0) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Droid_Interrogator( gentity_t *self)
- {
- self->NPC_type = "interrogator";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Probe (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Imperial Probe Droid - the multilegged floating droid that Han and Chewie shot on the ice planet Hoth
- */
- void SP_NPC_Droid_Probe( gentity_t *self)
- {
- self->NPC_type = "probe";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Mark1 (1 0 0) (-36 -36 -24) (36 36 80) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Big walking droid
- */
- void SP_NPC_Droid_Mark1( gentity_t *self)
- {
- self->NPC_type = "mark1";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Mark2 (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Small rolling droid with one gun.
- */
- void SP_NPC_Droid_Mark2( gentity_t *self)
- {
- self->NPC_type = "mark2";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_ATST (1 0 0) (-40 -40 -24) (40 40 248) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Droid_ATST( gentity_t *self)
- {
- self->NPC_type = "atst";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Remote (1 0 0) (-4 -4 -24) (4 4 8) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Remote Droid - the floating round droid used by Obi Wan to train Luke about the force while on the Millenium Falcon.
- */
- void SP_NPC_Droid_Remote( gentity_t *self)
- {
- self->NPC_type = "remote_sp";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Seeker (1 0 0) (-4 -4 -24) (4 4 8) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Seeker Droid - floating round droids that shadow troopers spawn
- */
- void SP_NPC_Droid_Seeker( gentity_t *self)
- {
- self->NPC_type = "seeker";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Sentry (1 0 0) (-24 -24 -24) (24 24 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Sentry Droid - Large, armored floating Imperial droids with 3 forward-facing gun turrets
- */
- void SP_NPC_Droid_Sentry( gentity_t *self)
- {
- self->NPC_type = "sentry";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Gonk (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Gonk Droid - the droid that looks like a walking ice machine. Was in the Jawa land crawler, walking around talking to itself.
- NOTARGET by default
- */
- void SP_NPC_Droid_Gonk( gentity_t *self)
- {
- self->NPC_type = "gonk";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Mouse (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- Mouse Droid - small, box shaped droid, first seen on the Death Star. Chewie yelled at it and it backed up and ran away.
- NOTARGET by default
- */
- void SP_NPC_Droid_Mouse( gentity_t *self)
- {
- self->NPC_type = "mouse";
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_R2D2 (1 0 0) (-12 -12 -24) (12 12 40) IMPERIAL x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- R2D2 Droid - you probably know this one already.
- NOTARGET by default
- */
- void SP_NPC_Droid_R2D2( gentity_t *self)
- {
- if ( self->spawnflags&1 )
- {//imperial skin
- self->NPC_type = "r2d2_imp";
- }
- else
- {
- self->NPC_type = "r2d2";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_R5D2 (1 0 0) (-12 -12 -24) (12 12 40) IMPERIAL ALWAYSDIE x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- ALWAYSDIE - won't go into spinning zombie AI when at low health.
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- R5D2 Droid - the droid originally chosen by Uncle Owen until it blew a bad motivator, and they took R2D2 instead.
- NOTARGET by default
- */
- void SP_NPC_Droid_R5D2( gentity_t *self)
- {
- if ( self->spawnflags&1 )
- {//imperial skin
- self->NPC_type = "r5d2_imp";
- }
- else
- {
- self->NPC_type = "r5d2";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Protocol (1 0 0) (-12 -12 -24) (12 12 40) IMPERIAL x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- NOTARGET by default
- */
- void SP_NPC_Droid_Protocol( gentity_t *self)
- {
- if ( self->spawnflags&1 )
- {//imperial skin
- self->NPC_type = "protocol_imp";
- }
- else
- {
- self->NPC_type = "protocol";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Assassin (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Droid_Assassin( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- self->NPC_type = "assassin_droid";
- }
- SP_NPC_spawner( self );
- }
- /*QUAKED NPC_Droid_Saber (1 0 0) (-12 -12 -24) (12 12 40) TRAINING x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
- DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
- CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
- NOTSOLID - Starts not solid
- STARTINSOLID - Don't try to fix if spawn in solid
- SHY - Spawner is shy
- */
- void SP_NPC_Droid_Saber( gentity_t *self)
- {
- if ( !self->NPC_type )
- {
- if ( (self->spawnflags&1) )
- {
- self->NPC_type = "saber_droid_training";
- }
- else
- {
- self->NPC_type = "saber_droid";
- }
- }
- SP_NPC_spawner( self );
- }
- //NPC console commands
- /*
- NPC_Spawn_f
- */
- static void NPC_Spawn_f(void)
- {
- gentity_t *NPCspawner = G_Spawn();
- vec3_t forward, end;
- trace_t trace;
- qboolean isVehicle = qfalse;
-
- if(!NPCspawner)
- {
- gi.Printf( S_COLOR_RED"NPC_Spawn Error: Out of entities!\n" );
- return;
- }
- NPCspawner->e_ThinkFunc = thinkF_G_FreeEntity;
- NPCspawner->nextthink = level.time + FRAMETIME;
-
- char *npc_type = gi.argv( 2 );
- if (!npc_type )
- {
- gi.Printf( S_COLOR_RED"Error, expected:\n NPC spawn [NPC type (from NCPCs.cfg)]\n" );
- return;
- }
- if ( !Q_stricmp( "vehicle", npc_type ) )
- {//spawning a vehicle
- isVehicle = qtrue;
- npc_type = gi.argv( 3 );
- if (!npc_type )
- {
- gi.Printf( S_COLOR_RED"Error, expected:\n NPC spawn vehicle [NPC type (from NCPCs.cfg)]\n" );
- return;
- }
- }
- //Spawn it at spot of first player
- //FIXME: will gib them!
- AngleVectors(g_entities[0].client->ps.viewangles, forward, NULL, NULL);
- VectorNormalize(forward);
- VectorMA(g_entities[0].currentOrigin, 64, forward, end);
- gi.trace(&trace, g_entities[0].currentOrigin, NULL, NULL, end, 0, MASK_SOLID);
- VectorCopy(trace.endpos, end);
- end[2] -= 24;
- gi.trace(&trace, trace.endpos, NULL, NULL, end, 0, MASK_SOLID);
- VectorCopy(trace.endpos, end);
- end[2] += 24;
- G_SetOrigin(NPCspawner, end);
- VectorCopy(NPCspawner->currentOrigin, NPCspawner->s.origin);
- //set the yaw so that they face away from player
- NPCspawner->s.angles[1] = g_entities[0].client->ps.viewangles[1];
- gi.linkentity(NPCspawner);
- NPCspawner->NPC_type = strlwr( G_NewString( npc_type ) );
- NPCspawner->NPC_targetname = G_NewString(gi.argv( 3 ));
- NPCspawner->count = 1;
- NPCspawner->delay = 0;
- NPCspawner->wait = 500;
- //NPCspawner->spawnflags |= SFB_NOTSOLID;
- //NPCspawner->playerTeam = TEAM_FREE;
- //NPCspawner->behaviorSet[BSET_SPAWN] = "common/guard";
- if ( isVehicle )
- {//must let NPC spawn func know this is a vehicle we're trying to spawn
- NPCspawner->classname = "NPC_Vehicle";
- }
- NPC_PrecacheByClassName(NPCspawner->NPC_type);
- if ( !Q_stricmp( "kyle_boss", NPCspawner->NPC_type ))
- {//bah
- NPCspawner->spawnflags |= 1;
- }
- if ( !Q_stricmp( "key", NPCspawner->NPC_type ))
- {//bah
- NPCspawner->message = "key";
- NPCspawner->NPC_type = "imperial";
- }
- if ( !Q_stricmp( "jedi_random", NPCspawner->NPC_type ) )
- {//special case, for testing
- NPCspawner->NPC_type = NULL;
- NPCspawner->spawnflags |= 4;
- SP_NPC_Jedi( NPCspawner );
- }
- else
- {
- NPC_Spawn( NPCspawner, NPCspawner, NPCspawner );
- }
- }
- /*
- NPC_Kill_f
- */
- void NPC_Kill_f( void )
- {
- int n;
- gentity_t *player;
- char *name;
- team_t killTeam = TEAM_FREE;
- qboolean killNonSF = qfalse;
- name = gi.argv( 2 );
- if ( !*name || !name[0] )
- {
- gi.Printf( S_COLOR_RED"Error, Expected:\n");
- gi.Printf( S_COLOR_RED"NPC kill '[NPC targetname]' - kills NPCs with certain targetname\n" );
- gi.Printf( S_COLOR_RED"or\n" );
- gi.Printf( S_COLOR_RED"NPC kill 'all' - kills all NPCs\n" );
- gi.Printf( S_COLOR_RED"or\n" );
- gi.Printf( S_COLOR_RED"NPC team '[teamname]' - kills all NPCs of a certain team ('nonally' is all but your allies)\n" );
- return;
- }
- if ( Q_stricmp( "team", name ) == 0 )
- {
- name = gi.argv( 3 );
- if ( !*name || !name[0] )
- {
- gi.Printf( S_COLOR_RED"NPC_Kill Error: 'npc kill team' requires a team name!\n" );
- gi.Printf( S_COLOR_RED"Valid team names are:\n");
- for ( n = (TEAM_FREE + 1); n < TEAM_NUM_TEAMS; n++ )
- {
- gi.Printf( S_COLOR_RED"%s\n", GetStringForID( TeamTable, n ) );
- }
- gi.Printf( S_COLOR_RED"nonally - kills all but your teammates\n" );
- return;
- }
- if ( Q_stricmp( "nonally", name ) == 0 )
- {
- killNonSF = qtrue;
- }
- else
- {
- killTeam = (team_t)GetIDForString( TeamTable, name );
- if ( killTeam == -1 )
- {
- gi.Printf( S_COLOR_RED"NPC_Kill Error: team '%s' not recognized\n", name );
- gi.Printf( S_COLOR_RED"Valid team names are:\n");
- for ( n = (TEAM_FREE + 1); n < TEAM_NUM_TEAMS; n++ )
- {
- gi.Printf( S_COLOR_RED"%s\n", GetStringForID( TeamTable, n ) );
- }
- gi.Printf( S_COLOR_RED"nonally - kills all but your teammates\n" );
- return;
- }
- }
- }
- for ( n = 1; n < ENTITYNUM_MAX_NORMAL; n++)
- {
- player = &g_entities[n];
- if (!player->inuse) {
- continue;
- }
- if ( killNonSF )
- {
- if ( player )
- {
- if ( player->client )
- {
- if ( player->client->playerTeam != TEAM_PLAYER )
- {
- gi.Printf( S_COLOR_GREEN"Killing NPC %s named %s\n", player->NPC_type, player->targetname );
- /*
- if ( (player->flags&FL_UNDYING) )
- {
- G_Damage( player, NULL, NULL, NULL, NULL, player->health+10000, 0, MOD_UNKNOWN );
- }
- else
- */
- {
- player->health = 0;
- GEntity_DieFunc(player, player, player, player->max_health, MOD_UNKNOWN);
- }
- }
- }
- else if ( player->NPC_type && player->classname && player->classname[0] && Q_stricmp( "NPC_starfleet", player->classname ) != 0 )
- {//A spawner, remove it
- gi.Printf( S_COLOR_GREEN"Removing NPC spawner %s with NPC named %s\n", player->NPC_type, player->NPC_targetname );
- G_FreeEntity( player );
- //FIXME: G_UseTargets2(player, player, player->NPC_target & player->target);?
- }
- }
- }
- else if ( player && player->NPC && player->client )
- {
- if ( killTeam != TEAM_FREE )
- {
- if ( player->client->playerTeam == killTeam )
- {
- gi.Printf( S_COLOR_GREEN"Killing NPC %s named %s\n", player->NPC_type, player->targetname );
- /*
- if ( (player->flags&FL_UNDYING) )
- {
- G_Damage( player, NULL, NULL, NULL, NULL, player->health+10000, 0, MOD_UNKNOWN );
- }
- else
- */
- {
- player->health = 0;
- GEntity_DieFunc(player, player, player, player->max_health, MOD_UNKNOWN);
- }
- }
- }
- else if( (player->targetname && Q_stricmp( name, player->targetname ) == 0)
- || Q_stricmp( name, "all" ) == 0 )
- {
- gi.Printf( S_COLOR_GREEN"Killing NPC %s named %s\n", player->NPC_type, player->targetname );
- player->client->ps.stats[STAT_HEALTH] = 0;
- /*
- if ( (player->flags&FL_UNDYING) )
- {
- G_Damage( player, NULL, NULL, NULL, NULL, player->health+10000, 0, MOD_UNKNOWN );
- }
- else
- */
- {
- player->health = 0;
- GEntity_DieFunc(player, player, player, 100, MOD_UNKNOWN);
- }
- }
- }
- else if ( player && (player->svFlags&SVF_NPC_PRECACHE) )
- {//a spawner
- if( (player->targetname && Q_stricmp( name, player->targetname ) == 0)
- || Q_stricmp( name, "all" ) == 0 )
- {
- gi.Printf( S_COLOR_GREEN"Removing NPC spawner %s named %s\n", player->NPC_type, player->targetname );
- G_FreeEntity( player );
- }
- }
- }
- }
- void NPC_PrintScore( gentity_t *ent )
- {
- gi.Printf( "%s: %d\n", ent->targetname, ent->client->ps.persistant[PERS_SCORE] );
- }
- /*
- Svcmd_NPC_f
- parse and dispatch bot commands
- */
- qboolean showBBoxes = qfalse;
- void Svcmd_NPC_f( void )
- {
- char *cmd;
- cmd = gi.argv( 1 );
- if ( !*cmd )
- {
- gi.Printf( "Valid NPC commands are:\n" );
- gi.Printf( " spawn [NPC type (from *.npc files)]\n" );
- gi.Printf( " spawn vehicle [NPC type (from *.npc files, only for NPCs that are CLASS_VEHICLE and have a .veh file)]\n" );
- gi.Printf( " kill [NPC targetname] or [all(kills all NPCs)] or 'team [teamname]'\n" );
- gi.Printf( " showbounds (draws exact bounding boxes of NPCs)\n" );
- gi.Printf( " score [NPC targetname] (prints number of kills per NPC)\n" );
- }
- else if ( Q_stricmp( cmd, "spawn" ) == 0 )
- {
- NPC_Spawn_f();
- }
- else if ( Q_stricmp( cmd, "kill" ) == 0 )
- {
- NPC_Kill_f();
- }
- else if ( Q_stricmp( cmd, "showbounds" ) == 0 )
- {//Toggle on and off
- showBBoxes = showBBoxes ? qfalse : qtrue;
- }
- else if ( Q_stricmp ( cmd, "score" ) == 0 )
- {
- char *cmd2 = gi.argv(2);
- gentity_t *ent = NULL;
- if ( !cmd2 || !cmd2[0] )
- {//Show the score for all NPCs
- gi.Printf( "SCORE LIST:\n" );
- for ( int i = 0; i < ENTITYNUM_WORLD; i++ )
- {
- ent = &g_entities[i];
- if ( !ent || !ent->client )
- {
- continue;
- }
- NPC_PrintScore( ent );
- }
- }
- else
- {
- if ( (ent = G_Find( NULL, FOFS(targetname), cmd2 )) != NULL && ent->client )
- {
- NPC_PrintScore( ent );
- }
- else
- {
- gi.Printf( "ERROR: NPC score - no such NPC %s\n", cmd2 );
- }
- }
- }
- }
|