12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019 |
- //NPC_stats.cpp
- // leave this line at the top for all NPC_xxxx.cpp files...
- #include "g_headers.h"
- #include "b_local.h"
- #include "b_public.h"
- #include "anims.h"
- #include "wp_saber.h"
- #include "g_Vehicles.h"
- #if !defined(RUFL_HSTRING_INC)
- #include "..\Rufl\hstring.h"
- #endif
- #include "..\Ratl\string_vs.h"
- #include "..\Rufl\hstring.h"
- #include "..\Ratl\vector_vs.h"
- extern void WP_RemoveSaber( gentity_t *ent, int saberNum );
- extern qboolean NPCsPrecached;
- extern vec3_t playerMins;
- extern vec3_t playerMaxs;
- extern stringID_table_t WPTable[];
- #define MAX_MODELS_PER_LEVEL 40
- #ifdef _XBOX
- using dllNamespace::hstring;
- #endif
- hstring modelsAlreadyDone[MAX_MODELS_PER_LEVEL];
- stringID_table_t animEventTypeTable[] =
- {
- ENUM2STRING(AEV_SOUND), //# animID AEV_SOUND framenum soundpath randomlow randomhi chancetoplay
- ENUM2STRING(AEV_FOOTSTEP), //# animID AEV_FOOTSTEP framenum footstepType
- ENUM2STRING(AEV_EFFECT), //# animID AEV_EFFECT framenum effectpath boltName
- ENUM2STRING(AEV_FIRE), //# animID AEV_FIRE framenum altfire chancetofire
- ENUM2STRING(AEV_MOVE), //# animID AEV_MOVE framenum forwardpush rightpush uppush
- ENUM2STRING(AEV_SOUNDCHAN), //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay
- //must be terminated
- NULL,-1
- };
- stringID_table_t footstepTypeTable[] =
- {
- ENUM2STRING(FOOTSTEP_R),
- ENUM2STRING(FOOTSTEP_L),
- ENUM2STRING(FOOTSTEP_HEAVY_R),
- ENUM2STRING(FOOTSTEP_HEAVY_L),
- //must be terminated
- NULL,-1
- };
- stringID_table_t FPTable[] =
- {
- ENUM2STRING(FP_HEAL),
- ENUM2STRING(FP_LEVITATION),
- ENUM2STRING(FP_SPEED),
- ENUM2STRING(FP_PUSH),
- ENUM2STRING(FP_PULL),
- ENUM2STRING(FP_TELEPATHY),
- ENUM2STRING(FP_GRIP),
- ENUM2STRING(FP_LIGHTNING),
- ENUM2STRING(FP_SABERTHROW),
- ENUM2STRING(FP_SABER_DEFENSE),
- ENUM2STRING(FP_SABER_OFFENSE),
- //new Jedi Academy powers
- ENUM2STRING(FP_RAGE),
- ENUM2STRING(FP_PROTECT),
- ENUM2STRING(FP_ABSORB),
- ENUM2STRING(FP_DRAIN),
- ENUM2STRING(FP_SEE),
- "", -1
- };
- stringID_table_t TeamTable[] =
- {
- "free", TEAM_FREE, // caution, some code checks a team_t via "if (!team_t_varname)" so I guess this should stay as entry 0, great or what? -slc
- ENUM2STRING(TEAM_FREE), // caution, some code checks a team_t via "if (!team_t_varname)" so I guess this should stay as entry 0, great or what? -slc
- "player", TEAM_PLAYER,
- ENUM2STRING(TEAM_PLAYER),
- "enemy", TEAM_ENEMY,
- ENUM2STRING(TEAM_ENEMY),
- "neutral", TEAM_NEUTRAL, // most droids are team_neutral, there are some exceptions like Probe,Seeker,Interrogator
- ENUM2STRING(TEAM_NEUTRAL), // most droids are team_neutral, there are some exceptions like Probe,Seeker,Interrogator
- "", -1
- };
- // this list was made using the model directories, this MUST be in the same order as the CLASS_ enum in teams.h
- stringID_table_t ClassTable[] =
- {
- ENUM2STRING(CLASS_NONE), // hopefully this will never be used by an npc), just covering all bases
- ENUM2STRING(CLASS_ATST), // technically droid...
- ENUM2STRING(CLASS_BARTENDER),
- ENUM2STRING(CLASS_BESPIN_COP),
- ENUM2STRING(CLASS_CLAW),
- ENUM2STRING(CLASS_COMMANDO),
- ENUM2STRING(CLASS_DESANN),
- ENUM2STRING(CLASS_FISH),
- ENUM2STRING(CLASS_FLIER2),
- ENUM2STRING(CLASS_GALAK),
- ENUM2STRING(CLASS_GLIDER),
- ENUM2STRING(CLASS_GONK), // droid
- ENUM2STRING(CLASS_GRAN),
- ENUM2STRING(CLASS_HOWLER),
- ENUM2STRING(CLASS_RANCOR),
- ENUM2STRING(CLASS_SAND_CREATURE),
- ENUM2STRING(CLASS_WAMPA),
- ENUM2STRING(CLASS_IMPERIAL),
- ENUM2STRING(CLASS_IMPWORKER),
- ENUM2STRING(CLASS_INTERROGATOR), // droid
- ENUM2STRING(CLASS_JAN),
- ENUM2STRING(CLASS_JEDI),
- ENUM2STRING(CLASS_KYLE),
- ENUM2STRING(CLASS_LANDO),
- ENUM2STRING(CLASS_LIZARD),
- ENUM2STRING(CLASS_LUKE),
- ENUM2STRING(CLASS_MARK1), // droid
- ENUM2STRING(CLASS_MARK2), // droid
- ENUM2STRING(CLASS_GALAKMECH), // droid
- ENUM2STRING(CLASS_MINEMONSTER),
- ENUM2STRING(CLASS_MONMOTHA),
- ENUM2STRING(CLASS_MORGANKATARN),
- ENUM2STRING(CLASS_MOUSE), // droid
- ENUM2STRING(CLASS_MURJJ),
- ENUM2STRING(CLASS_PRISONER),
- ENUM2STRING(CLASS_PROBE), // droid
- ENUM2STRING(CLASS_PROTOCOL), // droid
- ENUM2STRING(CLASS_R2D2), // droid
- ENUM2STRING(CLASS_R5D2), // droid
- ENUM2STRING(CLASS_REBEL),
- ENUM2STRING(CLASS_REBORN),
- ENUM2STRING(CLASS_REELO),
- ENUM2STRING(CLASS_REMOTE),
- ENUM2STRING(CLASS_RODIAN),
- ENUM2STRING(CLASS_SEEKER), // droid
- ENUM2STRING(CLASS_SENTRY),
- ENUM2STRING(CLASS_SHADOWTROOPER),
- ENUM2STRING(CLASS_SABOTEUR),
- ENUM2STRING(CLASS_STORMTROOPER),
- ENUM2STRING(CLASS_SWAMP),
- ENUM2STRING(CLASS_SWAMPTROOPER),
- ENUM2STRING(CLASS_NOGHRI),
- ENUM2STRING(CLASS_TAVION),
- ENUM2STRING(CLASS_ALORA),
- ENUM2STRING(CLASS_TRANDOSHAN),
- ENUM2STRING(CLASS_UGNAUGHT),
- ENUM2STRING(CLASS_JAWA),
- ENUM2STRING(CLASS_WEEQUAY),
- ENUM2STRING(CLASS_TUSKEN),
- ENUM2STRING(CLASS_BOBAFETT),
- ENUM2STRING(CLASS_ROCKETTROOPER),
- ENUM2STRING(CLASS_SABER_DROID),
- ENUM2STRING(CLASS_PLAYER),
- ENUM2STRING(CLASS_ASSASSIN_DROID),
- ENUM2STRING(CLASS_HAZARD_TROOPER),
- ENUM2STRING(CLASS_VEHICLE),
- "", -1
- };
- /*
- NPC_ReactionTime
- */
- //FIXME use grandom in here
- int NPC_ReactionTime ( void )
- {
- return 200 * ( 6 - NPCInfo->stats.reactions );
- }
- //
- // parse support routines
- //
- qboolean G_ParseLiteral( const char **data, const char *string )
- {
- const char *token;
- token = COM_ParseExt( data, qtrue );
- if ( token[0] == 0 )
- {
- gi.Printf( "unexpected EOF\n" );
- return qtrue;
- }
- if ( Q_stricmp( token, string ) )
- {
- gi.Printf( "required string '%s' missing\n", string );
- return qtrue;
- }
- return qfalse;
- }
- //
- // NPC parameters file : ext_data/NPCs/*.npc*
- //
- #define MAX_NPC_DATA_SIZE 0x20000
- char NPCParms[MAX_NPC_DATA_SIZE];
- /*
- static rank_t TranslateRankName( const char *name )
- Should be used to determine pip bolt-ons
- */
- static rank_t TranslateRankName( const char *name )
- {
- if ( !Q_stricmp( name, "civilian" ) )
- {
- return RANK_CIVILIAN;
- }
- if ( !Q_stricmp( name, "crewman" ) )
- {
- return RANK_CREWMAN;
- }
-
- if ( !Q_stricmp( name, "ensign" ) )
- {
- return RANK_ENSIGN;
- }
-
- if ( !Q_stricmp( name, "ltjg" ) )
- {
- return RANK_LT_JG;
- }
-
- if ( !Q_stricmp( name, "lt" ) )
- {
- return RANK_LT;
- }
-
- if ( !Q_stricmp( name, "ltcomm" ) )
- {
- return RANK_LT_COMM;
- }
-
- if ( !Q_stricmp( name, "commander" ) )
- {
- return RANK_COMMANDER;
- }
-
- if ( !Q_stricmp( name, "captain" ) )
- {
- return RANK_CAPTAIN;
- }
- return RANK_CIVILIAN;
- }
- #ifdef _XBOX
- extern saber_colors_t TranslateSaberColor( const char *name );
- #else
- saber_colors_t TranslateSaberColor( const char *name )
- {
- if ( !Q_stricmp( name, "red" ) )
- {
- return SABER_RED;
- }
- if ( !Q_stricmp( name, "orange" ) )
- {
- return SABER_ORANGE;
- }
- if ( !Q_stricmp( name, "yellow" ) )
- {
- return SABER_YELLOW;
- }
- if ( !Q_stricmp( name, "green" ) )
- {
- return SABER_GREEN;
- }
- if ( !Q_stricmp( name, "blue" ) )
- {
- return SABER_BLUE;
- }
- if ( !Q_stricmp( name, "purple" ) )
- {
- return SABER_PURPLE;
- }
- if ( !Q_stricmp( name, "random" ) )
- {
- return ((saber_colors_t)(Q_irand( SABER_ORANGE, SABER_PURPLE )));
- }
- return SABER_BLUE;
- }
- #endif
- /* static int MethodNameToNumber( const char *name ) {
- if ( !Q_stricmp( name, "EXPONENTIAL" ) ) {
- return METHOD_EXPONENTIAL;
- }
- if ( !Q_stricmp( name, "LINEAR" ) ) {
- return METHOD_LINEAR;
- }
- if ( !Q_stricmp( name, "LOGRITHMIC" ) ) {
- return METHOD_LOGRITHMIC;
- }
- if ( !Q_stricmp( name, "ALWAYS" ) ) {
- return METHOD_ALWAYS;
- }
- if ( !Q_stricmp( name, "NEVER" ) ) {
- return METHOD_NEVER;
- }
- return -1;
- }
- static int ItemNameToNumber( const char *name, int itemType ) {
- // int n;
- for ( n = 0; n < bg_numItems; n++ ) {
- if ( bg_itemlist[n].type != itemType ) {
- continue;
- }
- if ( Q_stricmp( bg_itemlist[n].classname, name ) == 0 ) {
- return bg_itemlist[n].tag;
- }
- }
- return -1;
- }
- */
- static int MoveTypeNameToEnum( const char *name )
- {
- if(!Q_stricmp("runjump", name))
- {
- return MT_RUNJUMP;
- }
- else if(!Q_stricmp("walk", name))
- {
- return MT_WALK;
- }
- else if(!Q_stricmp("flyswim", name))
- {
- return MT_FLYSWIM;
- }
- else if(!Q_stricmp("static", name))
- {
- return MT_STATIC;
- }
- return MT_STATIC;
- }
- extern void CG_RegisterClientRenderInfo(clientInfo_t *ci, renderInfo_t *ri);
- extern void CG_RegisterClientModels (int entityNum);
- extern void CG_RegisterNPCCustomSounds( clientInfo_t *ci );
- //extern void CG_RegisterNPCEffects( team_t team );
- //#define CONVENIENT_ANIMATION_FILE_DEBUG_THING
- #ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
- void SpewDebugStuffToFile(animation_t *bgGlobalAnimations)
- {
- char BGPAFtext[40000];
- fileHandle_t f;
- int i = 0;
- gi.FS_FOpenFile("file_of_debug_stuff_SP.txt", &f, FS_WRITE);
- if (!f)
- {
- return;
- }
- BGPAFtext[0] = 0;
- while (i < MAX_ANIMATIONS)
- {
- strcat(BGPAFtext, va("%i %i\n", i, bgGlobalAnimations[i].frameLerp));
- i++;
- }
- gi.FS_Write(BGPAFtext, strlen(BGPAFtext), f);
- gi.FS_FCloseFile(f);
- }
- #endif
- int CG_CheckAnimFrameForEventType( animevent_t *animEvents, int keyFrame, animEventType_t eventType, unsigned short modelIndex )
- {
- for ( int i = 0; i < MAX_ANIM_EVENTS; i++ )
- {
- if ( animEvents[i].keyFrame == keyFrame )
- {//there is an animevent on this frame already
- if ( animEvents[i].eventType == eventType )
- {//and it is of the same type
- if ( animEvents[i].modelOnly == modelIndex )
- {//and it is for the same model
- return i;
- }
- }
- }
- }
- //nope
- return -1;
- }
- /*
- ======================
- ParseAnimationEvtBlock
- ======================
- */
- static void ParseAnimationEvtBlock(int glaIndex, unsigned short modelIndex, const char* aeb_filename, animevent_t *animEvents, animation_t *animations, unsigned char &lastAnimEvent, const char **text_p, bool bIsFrameSkipped)
- {
- const char *token;
- int num, n, animNum, keyFrame, lowestVal, highestVal, curAnimEvent = 0;
- animEventType_t eventType;
- char stringData[MAX_QPATH];
- // get past starting bracket
- while(1)
- {
- token = COM_Parse( text_p );
- if ( !Q_stricmp( token, "{" ) )
- {
- break;
- }
- }
- //NOTE: instead of a blind increment, increase the index
- // this way if we have an event on an anim that already
- // has an event of that type, it stomps it
- // read information for each frame
- while ( 1 )
- {
- if ( lastAnimEvent >= MAX_ANIM_EVENTS )
- {
- CG_Error( "ParseAnimationEvtBlock: number events in file %s > MAX_ANIM_EVENTS(%i)", aeb_filename, MAX_ANIM_EVENTS );
- }
- // Get base frame of sequence
- token = COM_Parse( text_p );
- if ( !token || !token[0])
- {
- break;
- }
- if ( !Q_stricmp( token, "}" ) ) // At end of block
- {
- break;
- }
- //Compare to same table as animations used
- // so we don't have to use actual numbers for animation first frames,
- // just need offsets.
- //This way when animation numbers change, this table won't have to be updated,
- // at least not much.
- animNum = GetIDForString(animTable, token);
- if(animNum == -1)
- {//Unrecognized ANIM ENUM name,
- Com_Printf(S_COLOR_YELLOW"WARNING: Unknown ANIM %s in file %s\n", token, aeb_filename );
- //skip this entry
- SkipRestOfLine( text_p );
- continue;
- }
- if ( animations[animNum].numFrames == 0 )
- {//we don't use this anim
- #ifndef FINAL_BUILD
- Com_Printf(S_COLOR_YELLOW"WARNING: %s: anim %s not used by this model\n", aeb_filename, token);
- #endif
- //skip this entry
- SkipRestOfLine( text_p );
- continue;
- }
- token = COM_Parse( text_p );
- eventType = (animEventType_t)GetIDForString(animEventTypeTable, token);
- if ( eventType == AEV_NONE || eventType == -1 )
- {//Unrecognized ANIM EVENT TYPE
- Com_Printf(S_COLOR_RED"ERROR: Unknown EVENT %s in animEvent file %s\n", token, aeb_filename );
- continue;
- }
- // Get offset to frame within sequence
- token = COM_Parse( text_p );
- if ( !token )
- {
- break;
- }
- keyFrame = atoi( token );
- if ( bIsFrameSkipped &&
- (animations[animNum].numFrames>1) // important, else frame 1 gets divided down and becomes frame 0. Carcass & Assimilate also work this way
- )
- {
- keyFrame /= 2; // if we ever use any other value in frame-skipping we'll have to figure out some way of reading it, since it's not stored anywhere
- }
- if(keyFrame >= animations[animNum].numFrames)
- {
- Com_Printf(S_COLOR_YELLOW"WARNING: Event out of range on %s in %s\n", GetStringForID(animTable,animNum), aeb_filename );
- assert(keyFrame < animations[animNum].numFrames);
- keyFrame = animations[animNum].numFrames-1; //clamp it
- }
- //set our start frame
- keyFrame += animations[animNum].firstFrame;
- //see if this frame already has an event of this type on it, if so, overwrite it
- curAnimEvent = CG_CheckAnimFrameForEventType( animEvents, keyFrame, eventType, modelIndex );
- if ( curAnimEvent == -1 )
- {//this anim frame doesn't already have an event of this type on it
- curAnimEvent = lastAnimEvent;
- }
- //now that we know which event index we're going to plug the data into, start doing it
- animEvents[curAnimEvent].eventType = eventType;
- assert(keyFrame >= 0 && keyFrame < 65535); //
- animEvents[curAnimEvent].keyFrame = keyFrame;
- animEvents[curAnimEvent].glaIndex = glaIndex;
- animEvents[curAnimEvent].modelOnly = modelIndex;
- int tempVal;
- //now read out the proper data based on the type
- switch ( animEvents[curAnimEvent].eventType )
- {
- case AEV_SOUNDCHAN: //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay
- token = COM_Parse( text_p );
- if ( !token )
- {
- break;
- }
- if ( stricmp( token, "CHAN_VOICE_ATTEN" ) == 0 )
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_VOICE_ATTEN;
- }
- else if ( stricmp( token, "CHAN_VOICE_GLOBAL" ) == 0 )
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_VOICE_GLOBAL;
- }
- else if ( stricmp( token, "CHAN_ANNOUNCER" ) == 0 )
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_ANNOUNCER;
- }
- else if ( stricmp( token, "CHAN_BODY" ) == 0 )
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_BODY;
- }
- else if ( stricmp( token, "CHAN_WEAPON" ) == 0 )
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_WEAPON;
- }
- else if ( stricmp( token, "CHAN_VOICE" ) == 0 )
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_VOICE;
- }
- else
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_AUTO;
- }
- //fall through to normal sound
- case AEV_SOUND: //# animID AEV_SOUND framenum soundpath randomlow randomhi chancetoplay
- //get soundstring
- token = COM_Parse( text_p );
- if ( !token )
- {
- break;
- }
- strcpy(stringData, token);
- //get lowest value
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- lowestVal = atoi( token );
- //get highest value
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- highestVal = atoi( token );
- //Now precache all the sounds
- //NOTE: If we can be assured sequential handles, we can store the first sound index and count
- // unfortunately, if these sounds were previously registered, we cannot be guaranteed sequential indices. Thus an array
- if(lowestVal && highestVal)
- {
- assert(highestVal - lowestVal < MAX_RANDOM_ANIM_SOUNDS);
- for ( n = lowestVal, num = AED_SOUNDINDEX_START; n <= highestVal && num <= AED_SOUNDINDEX_END; n++, num++ )
- {
- animEvents[curAnimEvent].eventData[num] = G_SoundIndex( va( stringData, n ) );//cgi_S_RegisterSound
- }
- animEvents[curAnimEvent].eventData[AED_SOUND_NUMRANDOMSNDS] = num - 1;
- }
- else
- {
- animEvents[curAnimEvent].eventData[AED_SOUNDINDEX_START] = G_SoundIndex( stringData );//cgi_S_RegisterSound
- #if 0 //#ifndef FINAL_BUILD (only meaningfull if using S_RegisterSound
- if ( !animEvents[curAnimEvent].eventData[AED_SOUNDINDEX_START] )
- {//couldn't register it - file not found
- Com_Printf( S_COLOR_RED "ParseAnimationSndBlock: sound %s does not exist (%s)!\n", stringData, *aeb_filename );
- }
- #endif
- animEvents[curAnimEvent].eventData[AED_SOUND_NUMRANDOMSNDS] = 0;
- }
- //get probability
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY] = atoi( token );
- break;
- case AEV_FOOTSTEP: //# animID AEV_FOOTSTEP framenum footstepType
- //get footstep type
- token = COM_Parse( text_p );
- if ( !token )
- {
- break;
- }
- animEvents[curAnimEvent].eventData[AED_FOOTSTEP_TYPE] = GetIDForString(footstepTypeTable, token);
- //get probability
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- animEvents[curAnimEvent].eventData[AED_FOOTSTEP_PROBABILITY] = atoi( token );
- break;
- case AEV_EFFECT: //# animID AEV_EFFECT framenum effectpath boltName
- //get effect index
- token = COM_Parse( text_p );
- if ( !token )
- {
- break;
- }
- if ( token[0] && Q_stricmp( "special", token ) == 0 )
- {//special hard-coded effects
- //let cgame know it's not a real effect
- animEvents[curAnimEvent].eventData[AED_EFFECTINDEX] = -1;
- //get the name of it
- token = COM_Parse( text_p );
- animEvents[curAnimEvent].stringData = G_NewString( token );
- }
- else
- {//regular effect
- tempVal = G_EffectIndex(token);
- assert(tempVal > -32767 && tempVal < 32767);
- animEvents[curAnimEvent].eventData[AED_EFFECTINDEX] = tempVal;
- //get bolt index
- token = COM_Parse( text_p );
- if ( !token )
- {
- break;
- }
- if ( Q_stricmp( "none", token ) != 0 && Q_stricmp( "NULL", token ) != 0 )
- {//actually are specifying a bolt to use
- animEvents[curAnimEvent].stringData = G_NewString( token );
- }
- }
- //NOTE: this string will later be used to add a bolt and store the index, as below:
- //animEvent->eventData[AED_BOLTINDEX] = gi.G2API_AddBolt( ¢->gent->ghoul2[cent->gent->playerModel], animEvent->stringData );
- //get probability
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- animEvents[curAnimEvent].eventData[AED_EFFECT_PROBABILITY] = atoi( token );
- break;
- case AEV_FIRE: //# animID AEV_FIRE framenum altfire chancetofire
- //get altfire
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- animEvents[curAnimEvent].eventData[AED_FIRE_ALT] = atoi( token );
- //get probability
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- animEvents[curAnimEvent].eventData[AED_FIRE_PROBABILITY] = atoi( token );
- break;
- case AEV_MOVE: //# animID AEV_MOVE framenum forwardpush rightpush uppush
- //get forward push
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- tempVal = atoi(token);
- assert(tempVal > -32767 && tempVal < 32767);
- animEvents[curAnimEvent].eventData[AED_MOVE_FWD] = tempVal;
- //get right push
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- tempVal = atoi(token);
- assert(tempVal > -32767 && tempVal < 32767);
- animEvents[curAnimEvent].eventData[AED_MOVE_RT] = tempVal;
- //get upwards push
- token = COM_Parse( text_p );
- if ( !token )
- {//WARNING! BAD TABLE!
- break;
- }
- tempVal = atoi(token);
- assert(tempVal > -32767 && tempVal < 32767);
- animEvents[curAnimEvent].eventData[AED_MOVE_UP] = tempVal;
- break;
- default: //unknown?
- SkipRestOfLine( text_p );
- continue;
- break;
- }
- if ( curAnimEvent == lastAnimEvent )
- {
- lastAnimEvent++;
- }
- }
- }
- /*
- ======================
- G_ParseAnimationEvtFile
- Read a configuration file containing animation events
- models/players/kyle/animevents.cfg, etc
- This file's presence is not required
- ======================
- */
- static
- void G_ParseAnimationEvtFile(int glaIndex, const char* eventsDirectory, int fileIndex, int iRealGLAIndex = -1, bool modelSpecific = false)
- {
- int len;
- const char* token;
- char text[80000];
- const char* text_p = text;
- fileHandle_t f;
- char eventsPath[MAX_QPATH];
- int modelIndex = 0;
- assert(fileIndex>=0 && fileIndex<MAX_ANIM_FILES);
- const char *psAnimFileInternalName = (iRealGLAIndex == -1 ? NULL : gi.G2API_GetAnimFileInternalNameIndex( iRealGLAIndex ));
- // bool bIsFrameSkipped = (psAnimFileInternalName && strlen(psAnimFileInternalName)>5 && !stricmp(&psAnimFileInternalName[strlen(psAnimFileInternalName)-5],"_skip"));
- bool bIsFrameSkipped = false;
- if( (psAnimFileInternalName && strstr(psAnimFileInternalName, "_humanoid")) ||
- strstr(eventsDirectory, "rancor") )
- bIsFrameSkipped = true;
- // Open The File, Make Sure It Is Safe
- //-------------------------------------
- Com_sprintf(eventsPath, MAX_QPATH, "models/players/%s/animevents.cfg", eventsDirectory);
- len = cgi_FS_FOpenFile(eventsPath, &f, FS_READ);
- if ( len <= 0 )
- {//no file
- return;
- }
- if ( len >= sizeof( text ) - 1 )
- {
- CG_Printf( "File %s too long\n", eventsPath );
- return;
- }
- // Read It To The Buffer, Close The File
- //---------------------------------------
- cgi_FS_Read( text, len, f );
- text[len] = 0;
- cgi_FS_FCloseFile( f );
- // Get The Pointers To The Anim Event Arrays
- //-------------------------------------------
- animFileSet_t& afileset = level.knownAnimFileSets[fileIndex];
- animevent_t *legsAnimEvents = afileset.legsAnimEvents;
- animevent_t *torsoAnimEvents = afileset.torsoAnimEvents;
- animation_t *animations = afileset.animations;
- if (modelSpecific)
- {
- hstring modelName(eventsDirectory);
- modelIndex = modelName.handle();
- }
- // read information for batches of sounds (UPPER or LOWER)
- while ( 1 )
- {
- // Get base frame of sequence
- token = COM_Parse( &text_p );
- if ( !token || !token[0] )
- {
- break;
- }
- //these stomp anything set in the include file (if it's an event of the same type on the same frame)!
- if ( !Q_stricmp(token,"UPPEREVENTS") ) // A batch of upper events
- {
- ParseAnimationEvtBlock(glaIndex, modelIndex, eventsPath, torsoAnimEvents, animations, afileset.torsoAnimEventCount, &text_p, bIsFrameSkipped);
- }
- else if ( !Q_stricmp(token,"LOWEREVENTS") ) // A batch of lower events
- {
- ParseAnimationEvtBlock(glaIndex, modelIndex, eventsPath, legsAnimEvents, animations, afileset.legsAnimEventCount, &text_p, bIsFrameSkipped);
- }
- }
- }
- /*
- ======================
- G_ParseAnimationFile
- Read a configuration file containing animation coutns and rates
- models/players/visor/animation.cfg, etc
- ======================
- */
- qboolean G_ParseAnimationFile(int glaIndex, const char *skeletonName, int fileIndex)
- {
- char text[80000];
- int len = 0;
- const char *token = 0;
- float fps = 0;
- const char* text_p = text;
- int animNum = 0;
- animation_t* animations = level.knownAnimFileSets[fileIndex].animations;
- char skeletonPath[MAX_QPATH];
- // Read In The File To The Text Buffer, Make Sure Everything Is Safe To Continue
- //-------------------------------------------------------------------------------
- Com_sprintf(skeletonPath, MAX_QPATH, "models/players/%s/%s.cfg", skeletonName, skeletonName);
- len = gi.RE_GetAnimationCFG(skeletonPath, text, sizeof(text));
- if ( len <= 0 )
- {
- Com_sprintf(skeletonPath, MAX_QPATH, "models/players/%s/animation.cfg", skeletonName);
- len = gi.RE_GetAnimationCFG(skeletonPath, text, sizeof(text));
- if ( len <= 0 )
- {
- return qfalse;
- }
- }
- if ( len >= sizeof( text ) - 1 )
- {
- G_Error( "G_ParseAnimationFile: File %s too long\n (%d > %d)", skeletonName, len, sizeof( text ) - 1);
- return qfalse;
- }
- // Read In Each Token
- //--------------------
- while(1)
- {
- token = COM_Parse( &text_p );
- // If No Token, We've Reached The End Of The File
- //------------------------------------------------
- if ( !token || !token[0])
- {
- break;
- }
- // Get The Anim Number Converted From The First Token
- //----------------------------------------------------
- animNum = GetIDForString(animTable, token);
- if(animNum == -1)
- {
- #ifndef FINAL_BUILD
- if (strcmp(token,"ROOT"))
- {
- Com_Printf(S_COLOR_RED"WARNING: Unknown token %s in %s\n", token, skeletonPath);
- }
- #endif
- //unrecognized animation so skip to end of line,
- while (token[0])
- {
- token = COM_ParseExt( &text_p, qfalse ); //returns empty string when next token is EOL
- }
- continue;
- }
- // GLAIndex
- //----------
- animations[animNum].glaIndex = glaIndex; // Passed Into This Func
- // First Frame
- //-------------
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- assert(atoi(token) >= 0 && atoi(token) < 65536);
- animations[animNum].firstFrame = atoi( token );
- // Num Frames
- //------------
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- assert(atoi(token) >= 0 && atoi(token) < 65536);
- animations[animNum].numFrames = atoi( token );
- // Loop Frames
- //-------------
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- assert(atoi(token) >= -1 && atoi(token) < 128);
- animations[animNum].loopFrames = atoi( token );
- // FPS
- //-----
- token = COM_Parse( &text_p );
- if ( !token )
- {
- break;
- }
- fps = atof( token );
- if ( fps == 0 )
- {
- fps = 1;//Don't allow divide by zero error
- }
- // Calculate Frame Lerp
- //----------------------
- int lerp;
- if ( fps < 0 )
- {//backwards
- lerp = floor(1000.0f / fps);
- assert(lerp > -32767 && lerp < 32767);
- animations[animNum].frameLerp = lerp;
- assert(animations[animNum].frameLerp <= 1);
- }
- else
- {
- lerp = ceil(1000.0f / fps);
- assert(lerp > -32767 && lerp < 32767);
- animations[animNum].frameLerp = lerp;
- assert(animations[animNum].frameLerp >= 1);
- }
- /* lerp = ceil(1000.0f / Q_fabs(fps));
- assert(lerp > -32767 && lerp < 32767);
- animations[animNum].initialLerp = lerp;
- */
- }
- #ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
- if (strstr(af_filename, "humanoid"))
- {
- SpewDebugStuffToFile(animations);
- }
- #endif
- return qtrue;
- }
- ////////////////////////////////////////////////////////////////////////
- // G_ParseAnimFileSet
- //
- // This function is responsible for building the animation file and
- // the animation event file.
- //
- ////////////////////////////////////////////////////////////////////////
- int G_ParseAnimFileSet(const char *skeletonName, const char *modelName=0)
- {
- int fileIndex=0;
- // Try To Find An Existing Skeleton File For This Animation Set
- //--------------------------------------------------------------
- for (fileIndex=0; fileIndex<level.numKnownAnimFileSets; fileIndex++)
- {
- if (Q_stricmp(level.knownAnimFileSets[fileIndex].filename, skeletonName)==0)
- {
- break;
- }
- }
- // Ok, We Don't Already Have One, So Time To Create A New One And Initialize It
- //------------------------------------------------------------------------------
- if (fileIndex>=level.numKnownAnimFileSets)
- {
- if (level.numKnownAnimFileSets==MAX_ANIM_FILES)
- {
- G_Error( "G_ParseAnimFileSet: MAX_ANIM_FILES" );
- return -1;
- }
- // Allocate A new File Set, And Get Some Shortcut Pointers
- //---------------------------------------------------------
- fileIndex = level.numKnownAnimFileSets;
- level.numKnownAnimFileSets++;
- strcpy(level.knownAnimFileSets[fileIndex].filename, skeletonName);
- level.knownAnimFileSets[fileIndex].torsoAnimEventCount = 0;
- level.knownAnimFileSets[fileIndex].legsAnimEventCount = 0;
- animation_t* animations = level.knownAnimFileSets[fileIndex].animations;
- animevent_t* legsAnimEvents = level.knownAnimFileSets[fileIndex].legsAnimEvents;
- animevent_t* torsoAnimEvents = level.knownAnimFileSets[fileIndex].torsoAnimEvents;
- int i, j;
- // Initialize The Frames Information
- //-----------------------------------
- for(i=0; i<MAX_ANIMATIONS; i++)
- {
- animations[i].firstFrame = 0;
- animations[i].numFrames = 0;
- animations[i].loopFrames = -1;
- animations[i].frameLerp = 100;
- // animations[i].initialLerp = 100;
- animations[i].glaIndex = 0;
- }
- // Initialize Animation Event Array
- //----------------------------------
- for(i=0; i<MAX_ANIM_EVENTS; i++)
- {
- torsoAnimEvents[i].eventType = AEV_NONE; //Type of event
- legsAnimEvents[i].eventType = AEV_NONE;
- torsoAnimEvents[i].keyFrame = (unsigned short)-1; //65535 should never be a valid frame... :)
- legsAnimEvents[i].keyFrame = (unsigned short)-1; //Frame to play event on
- torsoAnimEvents[i].stringData = NULL; //we allow storage of one string, temporarily (in case we have to look up an index later,
- legsAnimEvents[i].stringData = NULL; //then make sure to set stringData to NULL so we only do the look-up once)
- torsoAnimEvents[i].modelOnly = 0;
- legsAnimEvents[i].modelOnly = 0;
- torsoAnimEvents[i].glaIndex = 0;
- legsAnimEvents[i].glaIndex = 0;
-
- for (j=0; j<AED_ARRAY_SIZE; j++) //Unique IDs, can be soundIndex of sound file to play OR effect index or footstep type, etc.
- {
- torsoAnimEvents[i].eventData[j] = -1;
- legsAnimEvents[i].eventData[j] = -1;
- }
- }
- // Get The Cinematic GLA Name
- //----------------------------
- if (stricmp(skeletonName, "_humanoid")==0)
- {
- const char* mapName = strrchr( level.mapname, '/' );
- if (mapName)
- {
- mapName++;
- }
- else
- {
- mapName = level.mapname;
- }
- char skeletonMapName[MAX_QPATH];
- Com_sprintf(skeletonMapName, MAX_QPATH, "_humanoid_%s", mapName);
- const int normalGLAIndex = gi.G2API_PrecacheGhoul2Model("models/players/_humanoid/_humanoid.gla");//double check this always comes first!
- // Make Sure To Precache The GLAs (both regular and cinematic), And Remember Their Indicies
- //------------------------------------------------------------------------------------------
- G_ParseAnimationFile(0, skeletonName, fileIndex);
- G_ParseAnimationEvtFile(0, skeletonName, fileIndex, normalGLAIndex, false/*flag for model specific*/);
- const int cineGLAIndex = gi.G2API_PrecacheGhoul2Model( va("models/players/%s/%s.gla", skeletonMapName, skeletonMapName));
- if (cineGLAIndex)
- {
- assert(cineGLAIndex == normalGLAIndex+1);
- if (cineGLAIndex != normalGLAIndex+1)
- {
- Com_Error(ERR_DROP,"Cinematic GLA was not loaded after the normal GLA. Cannot continue safely.");
- }
- G_ParseAnimationFile(1, skeletonMapName, fileIndex);
- G_ParseAnimationEvtFile(1, skeletonMapName, fileIndex, cineGLAIndex, false/*flag for model specific*/);
- }
- }
- else
- {
- // non-humanoid...
- //
- // Make Sure To Precache The GLAs (both regular and cinematic), And Remember Their Indicies
- //------------------------------------------------------------------------------------------
- G_ParseAnimationFile(0, skeletonName, fileIndex);
- G_ParseAnimationEvtFile(0, skeletonName, fileIndex);
- }
- }
- // Tack Any Additional Per Model Events
- //--------------------------------------
- if (modelName)
- {
- // Quick Search To See If We've Already Loaded This Model
- //--------------------------------------------------------
- int curModel=0;
- hstring curModelName(modelName);
- while (curModel<MAX_MODELS_PER_LEVEL && !modelsAlreadyDone[curModel].empty())
- {
- if (modelsAlreadyDone[curModel]==curModelName)
- {
- return fileIndex;
- }
- curModel++;
- }
- if (curModel == MAX_MODELS_PER_LEVEL)
- {
- Com_Error(ERR_DROP, "About to overflow modelsAlreadyDone, increase MAX_MODELS_PER_LEVEL\n");
- }
- // Nope, Ok, Record The Model As Found And Parse It's Event File
- //---------------------------------------------------------------
- modelsAlreadyDone[curModel]=curModelName;
- // Only Do The Event File If The Model Is Not The Same As The Skeleton
- //---------------------------------------------------------------------
- if (stricmp(skeletonName, modelName)!=0)
- {
- const int iGLAIndexToCheckForSkip = (stricmp(skeletonName, "_humanoid")?-1:gi.G2API_PrecacheGhoul2Model("models/players/_humanoid/_humanoid.gla")); // ;-)
- G_ParseAnimationEvtFile(0, modelName, fileIndex, iGLAIndexToCheckForSkip, true);
- }
- }
- return fileIndex;
- }
- #ifdef _XBOX
- // Utility to wipe the modelsAlreadyDone array, as it is never cleared
- void ClearModelsAlreadyDone(void)
- {
- memset(modelsAlreadyDone, 0, sizeof(modelsAlreadyDone));
- }
- #endif
- extern cvar_t *g_char_model;
- void G_LoadAnimFileSet( gentity_t *ent, const char *pModelName )
- {
- //load its animation config
- char animName[MAX_QPATH];
- char *GLAName, *modelName;
- char *slash = NULL;
- char *strippedName;
-
- if ( ent->playerModel == -1 )
- {
- return;
- }
- if ( Q_stricmp( "player", pModelName ) == 0 )
- {//model is actually stored on console
- modelName = g_char_model->string;
- }
- else
- {
- modelName = (char *)pModelName;
- }
- //get the location of the animation.cfg
- GLAName = gi.G2API_GetGLAName( &ent->ghoul2[ent->playerModel] );
- //now load and parse the animation.cfg, animevents.cfg and set the animFileIndex
- if ( !GLAName)
- {
- Com_Printf( S_COLOR_RED"Failed find animation file name models/players/%s\n", modelName );
- strippedName="_humanoid"; //take a guess, maybe it's right?
- }
- else
- {
- Q_strncpyz( animName, GLAName, sizeof( animName ), qtrue );
- slash = strrchr( animName, '/' );
- if ( slash )
- {
- *slash = 0;
- }
- strippedName = COM_SkipPath( animName );
- }
- //now load and parse the animation.cfg, animevents.cfg and set the animFileIndex
- ent->client->clientInfo.animFileIndex = G_ParseAnimFileSet(strippedName, modelName);
- if (ent->client->clientInfo.animFileIndex<0)
- {
- Com_Printf( S_COLOR_RED"Failed to load animation file set models/players/%s/animation.cfg\n", modelName );
- #ifndef FINAL_BUILD
- Com_Error(ERR_FATAL, "Failed to load animation file set models/players/%s/animation.cfg\n", modelName);
- #endif
- }
- }
- void NPC_PrecacheAnimationCFG( const char *NPC_type )
- {
- char filename[MAX_QPATH];
- const char *token;
- const char *value;
- const char *p;
- if ( !Q_stricmp( "random", NPC_type ) )
- {//sorry, can't precache a random just yet
- return;
- }
- p = NPCParms;
- COM_BeginParseSession();
- // look for the right NPC
- while ( p )
- {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 )
- return;
- if ( !Q_stricmp( token, NPC_type ) )
- {
- break;
- }
- SkipBracedSection( &p );
- }
- if ( !p )
- {
- return;
- }
- if ( G_ParseLiteral( &p, "{" ) )
- {
- return;
- }
- // parse the NPC info block
- while ( 1 )
- {
- token = COM_ParseExt( &p, qtrue );
- if ( !token[0] )
- {
- gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPC_type );
- return;
- }
- if ( !Q_stricmp( token, "}" ) )
- {
- break;
- }
- // legsmodel
- if ( !Q_stricmp( token, "legsmodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- //must copy data out of this pointer into a different part of memory because the funcs we're about to call will call COM_ParseExt
- Q_strncpyz( filename, value, sizeof( filename ), qtrue );
- G_ParseAnimFileSet( filename );
- return;
- }
- // playerModel
- if ( !Q_stricmp( token, "playerModel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- char animName[MAX_QPATH];
- char *GLAName;
- char *slash = NULL;
- char *strippedName;
- int handle = gi.G2API_PrecacheGhoul2Model( va( "models/players/%s/model.glm", value ) );
- if ( handle > 0 )//FIXME: isn't 0 a valid handle?
- {
- GLAName = gi.G2API_GetAnimFileNameIndex( handle );
- if ( GLAName )
- {
- Q_strncpyz( animName, GLAName, sizeof( animName ), qtrue );
- slash = strrchr( animName, '/' );
- if ( slash )
- {
- *slash = 0;
- }
- strippedName = COM_SkipPath( animName );
- //must copy data out of this pointer into a different part of memory because the funcs we're about to call will call COM_ParseExt
- Q_strncpyz( filename, value, sizeof( filename ), qtrue );
- G_ParseAnimFileSet(strippedName, filename);
- return;
- }
- }
- }
- }
- }
- extern int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type );
- void NPC_PrecacheWeapons( team_t playerTeam, int spawnflags, char *NPCtype )
- {
- int weapons = NPC_WeaponsForTeam( playerTeam, spawnflags, NPCtype );
- gitem_t *item;
- for ( int curWeap = WP_SABER; curWeap < WP_NUM_WEAPONS; curWeap++ )
- {
- if ( (weapons & ( 1 << curWeap )) )
- {
- item = FindItemForWeapon( ((weapon_t)(curWeap)) ); //precache the weapon
- CG_RegisterItemSounds( (item-bg_itemlist) );
- CG_RegisterItemVisuals( (item-bg_itemlist) );
- //precache the in-hand/in-world ghoul2 weapon model
- char weaponModel[64];
-
- strcpy (weaponModel, weaponData[curWeap].weaponMdl);
- if (char *spot = strstr(weaponModel, ".md3") ) {
- *spot = 0;
- spot = strstr(weaponModel, "_w");//i'm using the in view weapon array instead of scanning the item list, so put the _w back on
- if (!spot) {
- strcat (weaponModel, "_w");
- }
- strcat (weaponModel, ".glm"); //and change to ghoul2
- }
- gi.G2API_PrecacheGhoul2Model( weaponModel ); // correct way is item->world_model
- }
- }
- }
- /*
- void NPC_PrecacheByClassName ( char *NPCName )
- This runs all the class specific precache functions
- */
- extern void NPC_ShadowTrooper_Precache( void );
- extern void NPC_Gonk_Precache( void );
- extern void NPC_Mouse_Precache( void );
- extern void NPC_Seeker_Precache( void );
- extern void NPC_Remote_Precache( void );
- extern void NPC_R2D2_Precache(void);
- extern void NPC_R5D2_Precache(void);
- extern void NPC_Probe_Precache(void);
- extern void NPC_Interrogator_Precache(gentity_t *self);
- extern void NPC_MineMonster_Precache( void );
- extern void NPC_Howler_Precache( void );
- extern void NPC_Rancor_Precache( void );
- extern void NPC_MutantRancor_Precache( void );
- extern void NPC_Wampa_Precache( void );
- extern void NPC_ATST_Precache(void);
- extern void NPC_Sentry_Precache(void);
- extern void NPC_Mark1_Precache(void);
- extern void NPC_Mark2_Precache(void);
- extern void NPC_Protocol_Precache( void );
- extern void Boba_Precache( void );
- extern void RT_Precache( void );
- extern void SandCreature_Precache( void );
- extern void NPC_TavionScepter_Precache( void );
- extern void NPC_TavionSithSword_Precache( void );
- extern void NPC_Rosh_Dark_Precache( void );
- extern void NPC_Tusken_Precache( void );
- extern void NPC_Saboteur_Precache( void );
- extern void NPC_CultistDestroyer_Precache( void );
- void NPC_Jawa_Precache( void )
- {
- for ( int i = 1; i < 7; i++ )
- {
- G_SoundIndex( va( "sound/chars/jawa/misc/chatter%d.wav", i ) );
- }
- G_SoundIndex( "sound/chars/jawa/misc/ooh-tee-nee.wav" );
- }
- void NPC_PrecacheByClassName( const char* type )
- {
- if (!type || !type[0])
- {
- return;
- }
- if ( !Q_stricmp( "gonk", type))
- {
- NPC_Gonk_Precache();
- }
- else if ( !Q_stricmp( "mouse", type))
- {
- NPC_Mouse_Precache();
- }
- else if ( !Q_stricmpn( "r2d2", type, 4))
- {
- NPC_R2D2_Precache();
- }
- else if ( !Q_stricmp( "atst", type))
- {
- NPC_ATST_Precache();
- }
- else if ( !Q_stricmpn( "r5d2", type, 4))
- {
- NPC_R5D2_Precache();
- }
- else if ( !Q_stricmp( "mark1", type))
- {
- NPC_Mark1_Precache();
- }
- else if ( !Q_stricmp( "mark2", type))
- {
- NPC_Mark2_Precache();
- }
- else if ( !Q_stricmp( "interrogator", type))
- {
- NPC_Interrogator_Precache(NULL);
- }
- else if ( !Q_stricmp( "probe", type))
- {
- NPC_Probe_Precache();
- }
- else if ( !Q_stricmp( "seeker", type))
- {
- NPC_Seeker_Precache();
- }
- else if ( !Q_stricmpn( "remote", type, 6))
- {
- NPC_Remote_Precache();
- }
- else if ( !Q_stricmpn( "shadowtrooper", type, 13 ) )
- {
- NPC_ShadowTrooper_Precache();
- }
- else if ( !Q_stricmp( "minemonster", type ))
- {
- NPC_MineMonster_Precache();
- }
- else if ( !Q_stricmp( "howler", type ))
- {
- NPC_Howler_Precache();
- }
- else if ( !Q_stricmp( "rancor", type ))
- {
- NPC_Rancor_Precache();
- }
- else if ( !Q_stricmp( "mutant_rancor", type ))
- {
- NPC_Rancor_Precache();
- NPC_MutantRancor_Precache();
- }
- else if ( !Q_stricmp( "wampa", type ))
- {
- NPC_Wampa_Precache();
- }
- else if ( !Q_stricmp( "sand_creature", type ))
- {
- SandCreature_Precache();
- }
- else if ( !Q_stricmp( "sentry", type ))
- {
- NPC_Sentry_Precache();
- }
- else if ( !Q_stricmp( "protocol", type ))
- {
- NPC_Protocol_Precache();
- }
- else if ( !Q_stricmp( "boba_fett", type ))
- {
- Boba_Precache();
- }
- else if ( !Q_stricmp( "rockettrooper2", type ))
- {
- RT_Precache();
- }
- else if ( !Q_stricmp( "rockettrooper2Officer", type ))
- {
- RT_Precache();
- }
- else if ( !Q_stricmp( "tavion_scepter", type ))
- {
- NPC_TavionScepter_Precache();
- }
- else if ( !Q_stricmp( "tavion_sith_sword", type ))
- {
- NPC_TavionSithSword_Precache();
- }
- else if ( !Q_stricmp( "rosh_dark", type ) )
- {
- NPC_Rosh_Dark_Precache();
- }
- else if ( !Q_stricmpn( "tusken", type, 6 ) )
- {
- NPC_Tusken_Precache();
- }
- else if ( !Q_stricmpn( "saboteur", type, 8 ) )
- {
- NPC_Saboteur_Precache();
- }
- else if ( !Q_stricmp( "cultist_destroyer", type ) )
- {
- NPC_CultistDestroyer_Precache();
- }
- else if ( !Q_stricmpn( "jawa", type, 4 ) )
- {
- NPC_Jawa_Precache();
- }
- }
- /*
- void NPC_Precache ( char *NPCName )
- Precaches NPC skins, tgas and md3s.
- */
- void NPC_Precache ( gentity_t *spawner )
- {
- clientInfo_t ci={0};
- renderInfo_t ri={0};
- team_t playerTeam = TEAM_FREE;
- const char *token;
- const char *value;
- const char *p;
- char *patch;
- char sound[MAX_QPATH];
- qboolean md3Model = qfalse;
- char playerModel[MAX_QPATH] = { 0 };
- char customSkin[MAX_QPATH];
- if ( !Q_stricmp( "random", spawner->NPC_type ) )
- {//sorry, can't precache a random just yet
- return;
- }
- strcpy(customSkin,"default");
- p = NPCParms;
- COM_BeginParseSession();
- // look for the right NPC
- while ( p )
- {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 )
- return;
- if ( !Q_stricmp( token, spawner->NPC_type ) )
- {
- break;
- }
- SkipBracedSection( &p );
- }
- if ( !p )
- {
- return;
- }
- if ( G_ParseLiteral( &p, "{" ) )
- {
- return;
- }
- // parse the NPC info block
- while ( 1 )
- {
- token = COM_ParseExt( &p, qtrue );
- if ( !token[0] )
- {
- gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", spawner->NPC_type );
- return;
- }
- if ( !Q_stricmp( token, "}" ) )
- {
- break;
- }
- // headmodel
- if ( !Q_stricmp( token, "headmodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if(!Q_stricmp("none", value))
- {
- }
- else
- {
- Q_strncpyz( ri.headModelName, value, sizeof(ri.headModelName), qtrue);
- }
- md3Model = qtrue;
- continue;
- }
-
- // torsomodel
- if ( !Q_stricmp( token, "torsomodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if(!Q_stricmp("none", value))
- {
- }
- else
- {
- Q_strncpyz( ri.torsoModelName, value, sizeof(ri.torsoModelName), qtrue);
- }
- md3Model = qtrue;
- continue;
- }
- // legsmodel
- if ( !Q_stricmp( token, "legsmodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- Q_strncpyz( ri.legsModelName, value, sizeof(ri.legsModelName), qtrue);
- md3Model = qtrue;
- continue;
- }
- // playerModel
- if ( !Q_stricmp( token, "playerModel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- Q_strncpyz( playerModel, value, sizeof(playerModel), qtrue);
- md3Model = qfalse;
- continue;
- }
- // customSkin
- if ( !Q_stricmp( token, "customSkin" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- Q_strncpyz( customSkin, value, sizeof(customSkin), qtrue);
- continue;
- }
- // playerTeam
- if ( !Q_stricmp( token, "playerTeam" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- playerTeam = (team_t)GetIDForString( TeamTable, token );
- continue;
- }
-
- // snd
- if ( !Q_stricmp( token, "snd" ) ) {
- if ( COM_ParseString( &p, &value ) ) {
- continue;
- }
- if ( !(spawner->svFlags&SVF_NO_BASIC_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci.customBasicSoundDir = G_NewString( sound );
- }
- continue;
- }
- // sndcombat
- if ( !Q_stricmp( token, "sndcombat" ) ) {
- if ( COM_ParseString( &p, &value ) ) {
- continue;
- }
- if ( !(spawner->svFlags&SVF_NO_COMBAT_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci.customCombatSoundDir = G_NewString( sound );
- }
- continue;
- }
-
- // sndextra
- if ( !Q_stricmp( token, "sndextra" ) ) {
- if ( COM_ParseString( &p, &value ) ) {
- continue;
- }
- if ( !(spawner->svFlags&SVF_NO_EXTRA_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci.customExtraSoundDir = G_NewString( sound );
- }
- continue;
- }
- // sndjedi
- if ( !Q_stricmp( token, "sndjedi" ) ) {
- if ( COM_ParseString( &p, &value ) ) {
- continue;
- }
- if ( !(spawner->svFlags&SVF_NO_EXTRA_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci.customJediSoundDir = G_NewString( sound );
- }
- continue;
- }
- //cache weapons
- if ( !Q_stricmp( token, "weapon" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- int weap = GetIDForString( WPTable, value );
- if ( weap >= WP_NONE && weap < WP_NUM_WEAPONS )
- {
- if ( weap > WP_NONE )
- {
- RegisterItem( FindItemForWeapon( (weapon_t)(weap) ) ); //precache the weapon
- }
- }
- continue;
- }
- //cache sabers
- //saber name
- if ( !Q_stricmp( token, "saber" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- char *saberName = G_NewString( value );
- saberInfo_t saber;
- WP_SaberParseParms( saberName, &saber );
- if ( saber.model && saber.model[0] )
- {
- G_ModelIndex( saber.model );
- }
- if ( saber.skin && saber.skin[0] )
- {
- gi.RE_RegisterSkin( saber.skin );
- G_SkinIndex( saber.skin );
- }
- continue;
- }
-
- //second saber name
- if ( !Q_stricmp( token, "saber2" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- char *saberName = G_NewString( value );
- saberInfo_t saber;
- WP_SaberParseParms( saberName, &saber );
- if ( saber.model && saber.model[0] )
- {
- G_ModelIndex( saber.model );
- }
- if ( saber.skin && saber.skin[0] )
- {
- gi.RE_RegisterSkin( saber.skin );
- G_SkinIndex( saber.skin );
- }
- continue;
- }
- }
- if ( md3Model )
- {
- CG_RegisterClientRenderInfo( &ci, &ri );
- }
- else
- {
- char skinName[MAX_QPATH];
- //precache ghoul2 model
- gi.G2API_PrecacheGhoul2Model( va( "models/players/%s/model.glm", playerModel ) );
- //precache skin
- if (strchr(customSkin, '|'))
- {//three part skin
- Com_sprintf( skinName, sizeof( skinName ), "models/players/%s/|%s", playerModel, customSkin );
- }
- else
- {//standard skin
- Com_sprintf( skinName, sizeof( skinName ), "models/players/%s/model_%s.skin", playerModel, customSkin );
- }
- // lets see if it's out there
- gi.RE_RegisterSkin( skinName );
- }
- //precache this NPC's possible weapons
- NPC_PrecacheWeapons( playerTeam, spawner->spawnflags, spawner->NPC_type );
- // Anything else special about them
- NPC_PrecacheByClassName( spawner->NPC_type );
- CG_RegisterNPCCustomSounds( &ci );
- //CG_RegisterNPCEffects( playerTeam );
- //FIXME: Look for a "sounds" directory and precache death, pain, alert sounds
- }
- void NPC_BuildRandom( gentity_t *NPC )
- {
- }
- extern void G_MatchPlayerWeapon( gentity_t *ent );
- extern void G_InitPlayerFromCvars( gentity_t *ent );
- extern void G_SetG2PlayerModel( gentity_t * const ent, const char *modelName, const char *customSkin, const char *surfOff, const char *surfOn );
- qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC )
- {
- const char *token;
- const char *value;
- const char *p;
- int n;
- float f;
- char *patch;
- char sound[MAX_QPATH];
- char playerModel[MAX_QPATH];
- char customSkin[MAX_QPATH];
- clientInfo_t *ci = &NPC->client->clientInfo;
- renderInfo_t *ri = &NPC->client->renderInfo;
- gNPCstats_t *stats = NULL;
- qboolean md3Model = qtrue;
- char surfOff[1024]={0};
- char surfOn[1024]={0};
- qboolean parsingPlayer = qfalse;
- strcpy(customSkin,"default");
- if ( !NPCName || !NPCName[0])
- {
- NPCName = "Player";
- }
- if ( !NPC->s.number && NPC->client != NULL )
- {//player, only want certain data
- parsingPlayer = qtrue;
- }
- if ( NPC->NPC )
- {
- stats = &NPC->NPC->stats;
- /*
- NPC->NPC->allWeaponOrder[0] = WP_BRYAR_PISTOL;
- NPC->NPC->allWeaponOrder[1] = WP_SABER;
- NPC->NPC->allWeaponOrder[2] = WP_IMOD;
- NPC->NPC->allWeaponOrder[3] = WP_SCAVENGER_RIFLE;
- NPC->NPC->allWeaponOrder[4] = WP_TRICORDER;
- NPC->NPC->allWeaponOrder[6] = WP_NONE;
- NPC->NPC->allWeaponOrder[6] = WP_NONE;
- NPC->NPC->allWeaponOrder[7] = WP_NONE;
- */
- // fill in defaults
- stats->sex = SEX_MALE;
- stats->aggression = 3;
- stats->aim = 3;
- stats->earshot = 1024;
- stats->evasion = 3;
- stats->hfov = 90;
- stats->intelligence = 3;
- stats->move = 3;
- stats->reactions = 3;
- stats->vfov = 60;
- stats->vigilance = 0.1f;
- stats->visrange = 1024;
- if (g_entities[ENTITYNUM_WORLD].max_health && stats->visrange>g_entities[ENTITYNUM_WORLD].max_health)
- {
- stats->visrange = g_entities[ENTITYNUM_WORLD].max_health;
- }
- stats->health = 0;
- stats->yawSpeed = 90;
- stats->walkSpeed = 90;
- stats->runSpeed = 300;
- stats->acceleration = 15;//Increase/descrease speed this much per frame (20fps)
- }
- else
- {
- stats = NULL;
- }
- Q_strncpyz( ci->name, NPCName, sizeof( ci->name ) );
-
- NPC->playerModel = -1;
-
- //Set defaults
- //FIXME: should probably put default torso and head models, but what about enemies
- //that don't have any- like Stasis?
- //Q_strncpyz( ri->headModelName, DEFAULT_HEADMODEL, sizeof(ri->headModelName), qtrue);
- //Q_strncpyz( ri->torsoModelName, DEFAULT_TORSOMODEL, sizeof(ri->torsoModelName), qtrue);
- //Q_strncpyz( ri->legsModelName, DEFAULT_LEGSMODEL, sizeof(ri->legsModelName), qtrue);
- ri->headModelName[0] = 0;
- ri->torsoModelName[0]= 0;
- ri->legsModelName[0] =0;
- ri->headYawRangeLeft = 80;
- ri->headYawRangeRight = 80;
- ri->headPitchRangeUp = 45;
- ri->headPitchRangeDown = 45;
- ri->torsoYawRangeLeft = 60;
- ri->torsoYawRangeRight = 60;
- ri->torsoPitchRangeUp = 30;
- ri->torsoPitchRangeDown = 50;
- VectorCopy(playerMins, NPC->mins);
- VectorCopy(playerMaxs, NPC->maxs);
- NPC->client->crouchheight = CROUCH_MAXS_2;
- NPC->client->standheight = DEFAULT_MAXS_2;
- NPC->client->moveType = MT_RUNJUMP;
- NPC->client->dismemberProbHead = 100;
- NPC->client->dismemberProbArms = 100;
- NPC->client->dismemberProbHands = 100;
- NPC->client->dismemberProbWaist = 100;
- NPC->client->dismemberProbLegs = 100;
- NPC->s.modelScale[0] = NPC->s.modelScale[1] = NPC->s.modelScale[2] = 1.0f;
- *(int*)ri->customRGBA=-1;
- if ( !Q_stricmp( "random", NPCName ) )
- {//Randomly assemble an NPC
- NPC_BuildRandom( NPC );
- }
- else
- {
- p = NPCParms;
- COM_BeginParseSession();
- // look for the right NPC
- while ( p )
- {
- token = COM_ParseExt( &p, qtrue );
- if ( token[0] == 0 )
- {
- return qfalse;
- }
- if ( !Q_stricmp( token, NPCName ) )
- {
- break;
- }
- SkipBracedSection( &p );
- }
- if ( !p )
- {
- return qfalse;
- }
- if ( G_ParseLiteral( &p, "{" ) )
- {
- return qfalse;
- }
-
- // parse the NPC info block
- while ( 1 )
- {
- token = COM_ParseExt( &p, qtrue );
- if ( !token[0] )
- {
- gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPCName );
- return qfalse;
- }
- if ( !Q_stricmp( token, "}" ) )
- {
- break;
- }
- //===MODEL PROPERTIES===========================================================
- // custom color
- if ( !Q_stricmp( token, "customRGBA" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
-
- if ( !Q_stricmp( value, "random") )
- {
- ri->customRGBA[0]=Q_irand(0,255);
- ri->customRGBA[1]=Q_irand(0,255);
- ri->customRGBA[2]=Q_irand(0,255);
- ri->customRGBA[3]=255;
- }
- else if ( !Q_stricmp( value, "random1") )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,5))
- {
- default:
- case 0:
- ri->customRGBA[0]=127;
- ri->customRGBA[1]=153;
- ri->customRGBA[2]=255;
- break;
- case 1:
- ri->customRGBA[0]=177;
- ri->customRGBA[1]=29;
- ri->customRGBA[2]=13;
- break;
- case 2:
- ri->customRGBA[0]=47;
- ri->customRGBA[1]=90;
- ri->customRGBA[2]=40;
- break;
- case 3:
- ri->customRGBA[0]=181;
- ri->customRGBA[1]=207;
- ri->customRGBA[2]=255;
- break;
- case 4:
- ri->customRGBA[0]=138;
- ri->customRGBA[1]=83;
- ri->customRGBA[2]=0;
- break;
- case 5:
- ri->customRGBA[0]=254;
- ri->customRGBA[1]=199;
- ri->customRGBA[2]=14;
- break;
- }
- }
- else if ( !Q_stricmp( value, "jedi_hf" ) )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,7))
- {
- default:
- case 0://red1
- ri->customRGBA[0]=165;
- ri->customRGBA[1]=48;
- ri->customRGBA[2]=21;
- break;
- case 1://yellow1
- ri->customRGBA[0]=254;
- ri->customRGBA[1]=230;
- ri->customRGBA[2]=132;
- break;
- case 2://bluegray
- ri->customRGBA[0]=181;
- ri->customRGBA[1]=207;
- ri->customRGBA[2]=255;
- break;
- case 3://pink
- ri->customRGBA[0]=233;
- ri->customRGBA[1]=183;
- ri->customRGBA[2]=208;
- break;
- case 4://lt blue
- ri->customRGBA[0]=161;
- ri->customRGBA[1]=226;
- ri->customRGBA[2]=240;
- break;
- case 5://blue
- ri->customRGBA[0]=101;
- ri->customRGBA[1]=159;
- ri->customRGBA[2]=255;
- break;
- case 6://orange
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=157;
- ri->customRGBA[2]=114;
- break;
- case 7://violet
- ri->customRGBA[0]=216;
- ri->customRGBA[1]=160;
- ri->customRGBA[2]=255;
- break;
- }
- }
- else if ( !Q_stricmp( value, "jedi_hm" ) )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,7))
- {
- default:
- case 0://yellow
- ri->customRGBA[0]=252;
- ri->customRGBA[1]=243;
- ri->customRGBA[2]=180;
- break;
- case 1://blue
- ri->customRGBA[0]=69;
- ri->customRGBA[1]=109;
- ri->customRGBA[2]=255;
- break;
- case 2://gold
- ri->customRGBA[0]=254;
- ri->customRGBA[1]=197;
- ri->customRGBA[2]=73;
- break;
- case 3://orange
- ri->customRGBA[0]=178;
- ri->customRGBA[1]=78;
- ri->customRGBA[2]=18;
- break;
- case 4://bluegreen
- ri->customRGBA[0]=112;
- ri->customRGBA[1]=153;
- ri->customRGBA[2]=161;
- break;
- case 5://blue2
- ri->customRGBA[0]=123;
- ri->customRGBA[1]=182;
- ri->customRGBA[2]=255;
- break;
- case 6://green2
- ri->customRGBA[0]=0;
- ri->customRGBA[1]=88;
- ri->customRGBA[2]=105;
- break;
- case 7://violet
- ri->customRGBA[0]=138;
- ri->customRGBA[1]=0;
- ri->customRGBA[2]=0;
- break;
- }
- }
- else if ( !Q_stricmp( value, "jedi_kdm" ) )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,8))
- {
- default:
- case 0://blue
- ri->customRGBA[0]=85;
- ri->customRGBA[1]=120;
- ri->customRGBA[2]=255;
- break;
- case 1://violet
- ri->customRGBA[0]=173;
- ri->customRGBA[1]=142;
- ri->customRGBA[2]=219;
- break;
- case 2://brown1
- ri->customRGBA[0]=254;
- ri->customRGBA[1]=197;
- ri->customRGBA[2]=73;
- break;
- case 3://orange
- ri->customRGBA[0]=138;
- ri->customRGBA[1]=83;
- ri->customRGBA[2]=0;
- break;
- case 4://gold
- ri->customRGBA[0]=254;
- ri->customRGBA[1]=199;
- ri->customRGBA[2]=14;
- break;
- case 5://blue2
- ri->customRGBA[0]=68;
- ri->customRGBA[1]=194;
- ri->customRGBA[2]=217;
- break;
- case 6://red1
- ri->customRGBA[0]=170;
- ri->customRGBA[1]=3;
- ri->customRGBA[2]=30;
- break;
- case 7://yellow1
- ri->customRGBA[0]=225;
- ri->customRGBA[1]=226;
- ri->customRGBA[2]=144;
- break;
- case 8://violet2
- ri->customRGBA[0]=167;
- ri->customRGBA[1]=202;
- ri->customRGBA[2]=255;
- break;
- }
- }
- else if ( !Q_stricmp( value, "jedi_rm" ) )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,8))
- {
- default:
- case 0://blue
- ri->customRGBA[0]=127;
- ri->customRGBA[1]=153;
- ri->customRGBA[2]=255;
- break;
- case 1://green1
- ri->customRGBA[0]=208;
- ri->customRGBA[1]=249;
- ri->customRGBA[2]=85;
- break;
- case 2://blue2
- ri->customRGBA[0]=181;
- ri->customRGBA[1]=207;
- ri->customRGBA[2]=255;
- break;
- case 3://gold
- ri->customRGBA[0]=138;
- ri->customRGBA[1]=83;
- ri->customRGBA[2]=0;
- break;
- case 4://gold
- ri->customRGBA[0]=224;
- ri->customRGBA[1]=171;
- ri->customRGBA[2]=44;
- break;
- case 5://green2
- ri->customRGBA[0]=49;
- ri->customRGBA[1]=155;
- ri->customRGBA[2]=131;
- break;
- case 6://red1
- ri->customRGBA[0]=163;
- ri->customRGBA[1]=79;
- ri->customRGBA[2]=17;
- break;
- case 7://violet2
- ri->customRGBA[0]=148;
- ri->customRGBA[1]=104;
- ri->customRGBA[2]=228;
- break;
- case 8://green3
- ri->customRGBA[0]=138;
- ri->customRGBA[1]=136;
- ri->customRGBA[2]=0;
- break;
- }
- }
- else if ( !Q_stricmp( value, "jedi_tf" ) )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,5))
- {
- default:
- case 0://green1
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=235;
- ri->customRGBA[2]=100;
- break;
- case 1://blue1
- ri->customRGBA[0]=62;
- ri->customRGBA[1]=155;
- ri->customRGBA[2]=255;
- break;
- case 2://red1
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=110;
- ri->customRGBA[2]=120;
- break;
- case 3://purple
- ri->customRGBA[0]=180;
- ri->customRGBA[1]=150;
- ri->customRGBA[2]=255;
- break;
- case 4://flesh
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=200;
- ri->customRGBA[2]=212;
- break;
- case 5://base
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=255;
- ri->customRGBA[2]=255;
- break;
- }
- }
- else if ( !Q_stricmp( value, "jedi_zf" ) )
- {
- ri->customRGBA[3]=255;
- switch (Q_irand(0,7))
- {
- default:
- case 0://red1
- ri->customRGBA[0]=204;
- ri->customRGBA[1]=19;
- ri->customRGBA[2]=21;
- break;
- case 1://orange1
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=107;
- ri->customRGBA[2]=40;
- break;
- case 2://pink1
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=148;
- ri->customRGBA[2]=155;
- break;
- case 3://gold
- ri->customRGBA[0]=255;
- ri->customRGBA[1]=164;
- ri->customRGBA[2]=59;
- break;
- case 4://violet1
- ri->customRGBA[0]=216;
- ri->customRGBA[1]=160;
- ri->customRGBA[2]=255;
- break;
- case 5://blue1
- ri->customRGBA[0]=101;
- ri->customRGBA[1]=159;
- ri->customRGBA[2]=255;
- break;
- case 6://blue2
- ri->customRGBA[0]=161;
- ri->customRGBA[1]=226;
- ri->customRGBA[2]=240;
- break;
- case 7://blue3
- ri->customRGBA[0]=37;
- ri->customRGBA[1]=155;
- ri->customRGBA[2]=181;
- break;
- }
- }
- else
- {
- ri->customRGBA[0]=atoi(value);
-
- if ( COM_ParseInt( &p, &n ) )
- {
- continue;
- }
- ri->customRGBA[1]=n;
-
- if ( COM_ParseInt( &p, &n ) )
- {
- continue;
- }
- ri->customRGBA[2]=n;
-
- if ( COM_ParseInt( &p, &n ) )
- {
- continue;
- }
- ri->customRGBA[3]=n;
- }
- continue;
- }
- // headmodel
- if ( !Q_stricmp( token, "headmodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if(!Q_stricmp("none", value))
- {
- ri->headModelName[0] = NULL;
- //Zero the head clamp range so the torso & legs don't lag behind
- ri->headYawRangeLeft =
- ri->headYawRangeRight =
- ri->headPitchRangeUp =
- ri->headPitchRangeDown = 0;
- }
- else
- {
- Q_strncpyz( ri->headModelName, value, sizeof(ri->headModelName), qtrue);
- }
- continue;
- }
-
- // torsomodel
- if ( !Q_stricmp( token, "torsomodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if(!Q_stricmp("none", value))
- {
- ri->torsoModelName[0] = NULL;
- //Zero the torso clamp range so the legs don't lag behind
- ri->torsoYawRangeLeft =
- ri->torsoYawRangeRight =
- ri->torsoPitchRangeUp =
- ri->torsoPitchRangeDown = 0;
- }
- else
- {
- Q_strncpyz( ri->torsoModelName, value, sizeof(ri->torsoModelName), qtrue);
- }
- continue;
- }
- // legsmodel
- if ( !Q_stricmp( token, "legsmodel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- Q_strncpyz( ri->legsModelName, value, sizeof(ri->legsModelName), qtrue);
- //Need to do this here to get the right index
- ci->animFileIndex = G_ParseAnimFileSet(ri->legsModelName);
- continue;
- }
- // playerModel
- if ( !Q_stricmp( token, "playerModel" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- Q_strncpyz( playerModel, value, sizeof(playerModel), qtrue);
- md3Model = qfalse;
- continue;
- }
-
- // customSkin
- if ( !Q_stricmp( token, "customSkin" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- Q_strncpyz( customSkin, value, sizeof(customSkin), qtrue);
- continue;
- }
- // surfOff
- if ( !Q_stricmp( token, "surfOff" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( surfOff[0] )
- {
- strncat( (char *)surfOff, ",", sizeof(surfOff) );
- strncat( (char *)surfOff, value, sizeof(surfOff) );
- }
- else
- {
- Q_strncpyz( surfOff, value, sizeof(surfOff), qtrue);
- }
- continue;
- }
-
- // surfOn
- if ( !Q_stricmp( token, "surfOn" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( surfOn[0] )
- {
- strncat( (char *)surfOn, ",", sizeof(surfOn) );
- strncat( (char *)surfOn, value, sizeof(surfOn) );
- }
- else
- {
- Q_strncpyz( surfOn, value, sizeof(surfOn), qtrue);
- }
- continue;
- }
-
- //headYawRangeLeft
- if ( !Q_stricmp( token, "headYawRangeLeft" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->headYawRangeLeft = n;
- continue;
- }
- //headYawRangeRight
- if ( !Q_stricmp( token, "headYawRangeRight" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->headYawRangeRight = n;
- continue;
- }
- //headPitchRangeUp
- if ( !Q_stricmp( token, "headPitchRangeUp" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->headPitchRangeUp = n;
- continue;
- }
-
- //headPitchRangeDown
- if ( !Q_stricmp( token, "headPitchRangeDown" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->headPitchRangeDown = n;
- continue;
- }
- //torsoYawRangeLeft
- if ( !Q_stricmp( token, "torsoYawRangeLeft" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->torsoYawRangeLeft = n;
- continue;
- }
- //torsoYawRangeRight
- if ( !Q_stricmp( token, "torsoYawRangeRight" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->torsoYawRangeRight = n;
- continue;
- }
- //torsoPitchRangeUp
- if ( !Q_stricmp( token, "torsoPitchRangeUp" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->torsoPitchRangeUp = n;
- continue;
- }
- //torsoPitchRangeDown
- if ( !Q_stricmp( token, "torsoPitchRangeDown" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- ri->torsoPitchRangeDown = n;
- continue;
- }
- // Uniform XYZ scale
- if ( !Q_stricmp( token, "scale" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if (n != 100)
- {
- NPC->s.modelScale[0] = NPC->s.modelScale[1] = NPC->s.modelScale[2] = n/100.0f;
- }
- continue;
- }
- //X scale
- if ( !Q_stricmp( token, "scaleX" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if (n != 100)
- {
- NPC->s.modelScale[0] = n/100.0f;
- }
- continue;
- }
- //Y scale
- if ( !Q_stricmp( token, "scaleY" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if (n != 100)
- {
- NPC->s.modelScale[1] = n/100.0f;
- }
- continue;
- }
- //Z scale
- if ( !Q_stricmp( token, "scaleZ" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if (n != 100)
- {
- NPC->s.modelScale[2] = n/100.0f;
- }
- continue;
- }
- //===AI STATS=====================================================================
- if ( !parsingPlayer )
- {
- // aggression
- if ( !Q_stricmp( token, "aggression" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 5 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->aggression = n;
- }
- continue;
- }
- // aim
- if ( !Q_stricmp( token, "aim" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 5 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->aim = n;
- }
- continue;
- }
- // earshot
- if ( !Q_stricmp( token, "earshot" ) ) {
- if ( COM_ParseFloat( &p, &f ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( f < 0.0f )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->earshot = f;
- }
- continue;
- }
- // evasion
- if ( !Q_stricmp( token, "evasion" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 5 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->evasion = n;
- }
- continue;
- }
- // hfov
- if ( !Q_stricmp( token, "hfov" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 180 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->hfov = n;// / 2; //FIXME: Why was this being done?!
- }
- continue;
- }
- // intelligence
- if ( !Q_stricmp( token, "intelligence" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 5 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->intelligence = n;
- }
- continue;
- }
-
- // move
- if ( !Q_stricmp( token, "move" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 5 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->move = n;
- }
- continue;
- }
- // reactions
- if ( !Q_stricmp( token, "reactions" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 1 || n > 5 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->reactions = n;
- }
- continue;
- }
- // shootDistance
- if ( !Q_stricmp( token, "shootDistance" ) ) {
- if ( COM_ParseFloat( &p, &f ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( f < 0.0f )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->shootDistance = f;
- }
- continue;
- }
- // vfov
- if ( !Q_stricmp( token, "vfov" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 2 || n > 360 ) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->vfov = n / 2;
- }
- continue;
- }
- // vigilance
- if ( !Q_stricmp( token, "vigilance" ) ) {
- if ( COM_ParseFloat( &p, &f ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( f < 0.0f )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->vigilance = f;
- }
- continue;
- }
- // visrange
- if ( !Q_stricmp( token, "visrange" ) ) {
- if ( COM_ParseFloat( &p, &f ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( f < 0.0f )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->visrange = f;
- if (g_entities[ENTITYNUM_WORLD].max_health && stats->visrange>g_entities[ENTITYNUM_WORLD].max_health)
- {
- stats->visrange = g_entities[ENTITYNUM_WORLD].max_health;
- }
- }
- continue;
- }
- // race
- // if ( !Q_stricmp( token, "race" ) )
- // {
- // if ( COM_ParseString( &p, &value ) )
- // {
- // continue;
- // }
- // NPC->client->race = TranslateRaceName(value);
- // continue;
- // }
- // rank
- if ( !Q_stricmp( token, "rank" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->NPC->rank = TranslateRankName(value);
- }
- continue;
- }
- }
- // health
- if ( !Q_stricmp( token, "health" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->health = n;
- }
- else if ( parsingPlayer )
- {
- NPC->client->ps.stats[STAT_MAX_HEALTH] = NPC->client->pers.maxHealth = NPC->max_health = n;
- }
- continue;
- }
- // fullName
- if ( !Q_stricmp( token, "fullName" ) )
- {
- #ifndef FINAL_BUILD
- gi.Printf( S_COLOR_YELLOW"WARNING: fullname ignored in NPC '%s'\n", NPCName );
- #endif
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- continue;
- }
- // playerTeam
- if ( !Q_stricmp( token, "playerTeam" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- NPC->client->playerTeam = (team_t)GetIDForString( TeamTable, value );
- continue;
- }
- // enemyTeam
- if ( !Q_stricmp( token, "enemyTeam" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- NPC->client->enemyTeam = (team_t)GetIDForString( TeamTable, value );
- continue;
- }
- // class
- if ( !Q_stricmp( token, "class" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- NPC->client->NPC_class = (class_t)GetIDForString( ClassTable, value );
- // No md3's for vehicles.
- if ( NPC->client->NPC_class == CLASS_VEHICLE )
- {
- if ( !NPC->m_pVehicle )
- {//you didn't spawn this guy right!
- Com_Printf ( S_COLOR_RED "ERROR: Tried to spawn a vehicle NPC (%s) without using NPC_Vehicle or 'NPC spawn vehicle <vehiclename>'!!! Bad, bad, bad! Shame on you!\n", NPCName );
- return qfalse;
- }
- md3Model = qfalse;
- }
- continue;
- }
- // dismemberment probability for head
- if ( !Q_stricmp( token, "dismemberProbHead" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->client->dismemberProbHead = n;
- }
- continue;
- }
- // dismemberment probability for arms
- if ( !Q_stricmp( token, "dismemberProbArms" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->client->dismemberProbArms = n;
- }
- continue;
- }
- // dismemberment probability for hands
- if ( !Q_stricmp( token, "dismemberProbHands" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->client->dismemberProbHands = n;
- }
- continue;
- }
- // dismemberment probability for waist
- if ( !Q_stricmp( token, "dismemberProbWaist" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->client->dismemberProbWaist = n;
- }
- continue;
- }
- // dismemberment probability for legs
- if ( !Q_stricmp( token, "dismemberProbLegs" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->client->dismemberProbLegs = n;
- }
- continue;
- }
- //===MOVEMENT STATS============================================================
-
- if ( !Q_stricmp( token, "width" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- continue;
- }
- NPC->mins[0] = NPC->mins[1] = -n;
- NPC->maxs[0] = NPC->maxs[1] = n;
- continue;
- }
- if ( !Q_stricmp( token, "height" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- continue;
- }
- if ( NPC->client->NPC_class == CLASS_VEHICLE
- && NPC->m_pVehicle
- && NPC->m_pVehicle->m_pVehicleInfo
- && NPC->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
- {//a flying vehicle's origin must be centered in bbox
- NPC->maxs[2] = NPC->client->standheight = (n/2.0f);
- NPC->mins[2] = -NPC->maxs[2];
- NPC->s.origin[2] += (DEFAULT_MINS_2-NPC->mins[2])+0.125f;
- VectorCopy(NPC->s.origin, NPC->client->ps.origin);
- VectorCopy(NPC->s.origin, NPC->currentOrigin);
- G_SetOrigin( NPC, NPC->s.origin );
- gi.linkentity(NPC);
- }
- else
- {
- NPC->mins[2] = DEFAULT_MINS_2;//Cannot change
- NPC->maxs[2] = NPC->client->standheight = n + DEFAULT_MINS_2;
- }
- NPC->s.radius = n;
- continue;
- }
- if ( !Q_stricmp( token, "crouchheight" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- continue;
- }
- NPC->client->crouchheight = n + DEFAULT_MINS_2;
- continue;
- }
- if ( !parsingPlayer )
- {
- if ( !Q_stricmp( token, "movetype" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- NPC->client->moveType = (movetype_t)MoveTypeNameToEnum(value);
- continue;
- }
-
- // yawSpeed
- if ( !Q_stricmp( token, "yawSpeed" ) ) {
- if ( COM_ParseInt( &p, &n ) ) {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n <= 0) {
- gi.Printf( "bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->yawSpeed = ((float)(n));
- }
- continue;
- }
- // walkSpeed
- if ( !Q_stricmp( token, "walkSpeed" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->walkSpeed = n;
- }
- continue;
- }
-
- //runSpeed
- if ( !Q_stricmp( token, "runSpeed" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->runSpeed = n;
- }
- continue;
- }
- //acceleration
- if ( !Q_stricmp( token, "acceleration" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < 0 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- stats->acceleration = n;
- }
- continue;
- }
- //sex
- if ( !Q_stricmp( token, "sex" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( value[0] == 'm' )
- {//male
- stats->sex = SEX_MALE;
- }
- else if ( value[0] == 'n' )
- {//neutral
- stats->sex = SEX_NEUTRAL;
- }
- else if ( value[0] == 'a' )
- {//asexual?
- stats->sex = SEX_NEUTRAL;
- }
- else if ( value[0] == 'f' )
- {//female
- stats->sex = SEX_FEMALE;
- }
- else if ( value[0] == 's' )
- {//shemale?
- stats->sex = SEX_SHEMALE;
- }
- else if ( value[0] == 'h' )
- {//hermaphrodite?
- stats->sex = SEX_SHEMALE;
- }
- else if ( value[0] == 't' )
- {//transsexual/transvestite?
- stats->sex = SEX_SHEMALE;
- }
- continue;
- }
- //===MISC===============================================================================
- // default behavior
- if ( !Q_stricmp( token, "behavior" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( n < BS_DEFAULT || n >= NUM_BSTATES )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
- continue;
- }
- if ( NPC->NPC )
- {
- NPC->NPC->defaultBehavior = (bState_t)(n);
- }
- continue;
- }
- }
- // snd
- if ( !Q_stricmp( token, "snd" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( !(NPC->svFlags&SVF_NO_BASIC_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci->customBasicSoundDir = G_NewString( sound );
- }
- continue;
- }
- // sndcombat
- if ( !Q_stricmp( token, "sndcombat" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( !(NPC->svFlags&SVF_NO_COMBAT_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci->customCombatSoundDir = G_NewString( sound );
- }
- continue;
- }
-
- // sndextra
- if ( !Q_stricmp( token, "sndextra" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( !(NPC->svFlags&SVF_NO_EXTRA_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci->customExtraSoundDir = G_NewString( sound );
- }
- continue;
- }
- // sndjedi
- if ( !Q_stricmp( token, "sndjedi" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( !(NPC->svFlags&SVF_NO_EXTRA_SOUNDS) )
- {
- //FIXME: store this in some sound field or parse in the soundTable like the animTable...
- Q_strncpyz( sound, value, sizeof( sound ) );
- patch = strstr( sound, "/" );
- if ( patch )
- {
- *patch = 0;
- }
- ci->customJediSoundDir = G_NewString( sound );
- }
- continue;
- }
- //New NPC/jedi stats:
- //starting weapon
- if ( !Q_stricmp( token, "weapon" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- //FIXME: need to precache the weapon, too? (in above func)
- int weap = GetIDForString( WPTable, value );
- if ( weap >= WP_NONE && weap < WP_NUM_WEAPONS )
- {
- NPC->client->ps.weapon = weap;
- NPC->client->ps.stats[STAT_WEAPONS] |= ( 1 << weap );
- if ( weap > WP_NONE )
- {
- RegisterItem( FindItemForWeapon( (weapon_t)(weap) ) ); //precache the weapon
- NPC->client->ps.ammo[weaponData[weap].ammoIndex] = ammoData[weaponData[weap].ammoIndex].max;
- }
- }
- continue;
- }
-
- if ( !parsingPlayer )
- {
- //altFire
- if ( !Q_stricmp( token, "altFire" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- if ( NPC->NPC )
- {
- if ( n != 0 )
- {
- NPC->NPC->scriptFlags |= SCF_ALT_FIRE;
- }
- }
- continue;
- }
- //Other unique behaviors/numbers that are currently hardcoded?
- }
- //force powers
- int fp = GetIDForString( FPTable, token );
- if ( fp >= FP_FIRST && fp < NUM_FORCE_POWERS )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- //FIXME: need to precache the fx, too? (in above func)
- //cap
- if ( n > 5 )
- {
- n = 5;
- }
- else if ( n < 0 )
- {
- n = 0;
- }
- if ( n )
- {//set
- NPC->client->ps.forcePowersKnown |= ( 1 << fp );
- }
- else
- {//clear
- NPC->client->ps.forcePowersKnown &= ~( 1 << fp );
- }
- NPC->client->ps.forcePowerLevel[fp] = n;
- continue;
- }
- //max force power
- if ( !Q_stricmp( token, "forcePowerMax" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- NPC->client->ps.forcePowerMax = n;
- continue;
- }
- //force regen rate - default is 100ms
- if ( !Q_stricmp( token, "forceRegenRate" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- NPC->client->ps.forcePowerRegenRate = n;
- continue;
- }
- //force regen amount - default is 1 (points per second)
- if ( !Q_stricmp( token, "forceRegenAmount" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- NPC->client->ps.forcePowerRegenAmount = n;
- continue;
- }
- //have a sabers.cfg and just name your saber in your NPCs.cfg/ICARUS script
- //saber name
- if ( !Q_stricmp( token, "saber" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- char *saberName = G_NewString( value );
- WP_SaberParseParms( saberName, &NPC->client->ps.saber[0] );
- //if it requires a specific style, make sure we know how to use it
- if ( NPC->client->ps.saber[0].style )
- {
- NPC->client->ps.saberStylesKnown |= (1<<NPC->client->ps.saber[0].style);
- }
- continue;
- }
-
- //second saber name
- if ( !Q_stricmp( token, "saber2" ) )
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- if ( !NPC->client->ps.saber[0].twoHanded )
- {//can't use a second saber if first one is a two-handed saber...?
- char *saberName = G_NewString( value );
- WP_SaberParseParms( saberName, &NPC->client->ps.saber[1] );
- if ( NPC->client->ps.saber[1].style )
- {
- NPC->client->ps.saberStylesKnown |= (1<<NPC->client->ps.saber[1].style);
- }
- if ( NPC->client->ps.saber[1].twoHanded )
- {//tsk tsk, can't use a twoHanded saber as second saber
- WP_RemoveSaber( NPC, 1 );
- }
- else
- {
- NPC->client->ps.dualSabers = qtrue;
- }
- }
- continue;
- }
- // saberColor
- if ( !Q_stricmpn( token, "saberColor", 10) )
- {
- if ( !NPC->client )
- {
- continue;
- }
- if (strlen(token)==10)
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- saber_colors_t color = TranslateSaberColor( value );
- for ( n = 0; n < MAX_BLADES; n++ )
- {
- NPC->client->ps.saber[0].blade[n].color = color;
- }
- }
- else if (strlen(token)==11)
- {
- int index = atoi(&token[10])-1;
- if (index > 7 || index < 1 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, NPCName );
- continue;
- }
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- NPC->client->ps.saber[0].blade[index].color = TranslateSaberColor( value );
- }
- else
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, NPCName );
- }
- continue;
- }
- if ( !Q_stricmpn( token, "saber2Color", 11 ) )
- {
- if ( !NPC->client )
- {
- continue;
- }
- if (strlen(token)==11)
- {
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- saber_colors_t color = TranslateSaberColor( value );
- for ( n = 0; n < MAX_BLADES; n++ )
- {
- NPC->client->ps.saber[1].blade[n].color = color;
- }
- }
- else if (strlen(token)==12)
- {
- n = atoi(&token[11])-1;
- if (n > 7 || n < 1 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saber2Color '%s' in %s\n", token, NPCName );
- continue;
- }
- if ( COM_ParseString( &p, &value ) )
- {
- continue;
- }
- NPC->client->ps.saber[1].blade[n].color = TranslateSaberColor( value );
- }
- else
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saber2Color '%s' in %s\n", token, NPCName );
- }
- continue;
- }
- //saber length
- if ( !Q_stricmpn( token, "saberLength", 11) )
- {
- if (strlen(token)==11)
- {
- n = -1;
- }
- else if (strlen(token)==12)
- {
- n = atoi(&token[11])-1;
- if (n > 7 || n < 1 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, NPCName );
- continue;
- }
- }
- else
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, NPCName );
- continue;
- }
- if ( COM_ParseFloat( &p, &f ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- //cap
- if ( f < 4.0f )
- {
- f = 4.0f;
- }
- if (n == -1)//do them all
- {
- for ( n = 0; n < MAX_BLADES; n++ )
- {
- NPC->client->ps.saber[0].blade[n].lengthMax = f;
- }
- }
- else //just one
- {
- NPC->client->ps.saber[0].blade[n].lengthMax = f;
- }
- continue;
- }
- if ( !Q_stricmpn( token, "saber2Length", 12) )
- {
- if (strlen(token)==12)
- {
- n = -1;
- }
- else if (strlen(token)==13)
- {
- n = atoi(&token[12])-1;
- if (n > 7 || n < 1 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saber2Length '%s' in %s\n", token, NPCName );
- continue;
- }
- }
- else
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saber2Length '%s' in %s\n", token, NPCName );
- continue;
- }
- if ( COM_ParseFloat( &p, &f ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- //cap
- if ( f < 4.0f )
- {
- f = 4.0f;
- }
- if (n == -1)//do them all
- {
- for ( n = 0; n < MAX_BLADES; n++ )
- {
- NPC->client->ps.saber[1].blade[n].lengthMax = f;
- }
- }
- else //just one
- {
- NPC->client->ps.saber[1].blade[n].lengthMax = f;
- }
- continue;
- }
- //saber radius
- if ( !Q_stricmpn( token, "saberRadius", 11 ) )
- {
- if (strlen(token)==11)
- {
- n = -1;
- }
- else if (strlen(token)==12)
- {
- n = atoi(&token[11])-1;
- if (n > 7 || n < 1 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, NPCName );
- continue;
- }
- }
- else
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, NPCName );
- continue;
- }
-
- if ( COM_ParseFloat( &p, &f ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- //cap
- if ( f < 0.25f )
- {
- f = 0.25f;
- }
- if (n==-1)
- {//NOTE: this fills in the rest of the blades with the same length by default
- for ( n = 0; n < MAX_BLADES; n++ )
- {
- NPC->client->ps.saber[0].blade[n].radius = f;
- }
- }
- else
- {
- NPC->client->ps.saber[0].blade[n].radius = f;
- }
- continue;
- }
- if ( !Q_stricmpn( token, "saber2Radius", 12 ) )
- {
- if (strlen(token)==12)
- {
- n = -1;
- }
- else if (strlen(token)==13)
- {
- n = atoi(&token[12])-1;
- if (n > 7 || n < 1 )
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saber2Radius '%s' in %s\n", token, NPCName );
- continue;
- }
- }
- else
- {
- gi.Printf( S_COLOR_YELLOW"WARNING: bad saber2Radius '%s' in %s\n", token, NPCName );
- continue;
- }
- if ( COM_ParseFloat( &p, &f ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- //cap
- if ( f < 0.25f )
- {
- f = 0.25f;
- }
- if (n==-1)
- {//NOTE: this fills in the rest of the blades with the same length by default
- for ( n = 0; n < MAX_BLADES; n++ )
- {
- NPC->client->ps.saber[1].blade[n].radius = f;
- }
- }
- else
- {
- NPC->client->ps.saber[1].blade[n].radius = f;
- }
- continue;
- }
- //ADD:
- //saber sounds (on, off, loop)
- //loop sound (like Vader's breathing or droid bleeps, etc.)
- //starting saber style
- if ( !Q_stricmp( token, "saberStyle" ) )
- {
- if ( COM_ParseInt( &p, &n ) )
- {
- SkipRestOfLine( &p );
- continue;
- }
- //cap
- if ( n > SS_STAFF )
- {
- n = SS_STAFF;
- }
- else if ( n < SS_FAST )
- {
- n = SS_FAST;
- }
- if ( n )
- {//set
- NPC->client->ps.saberStylesKnown |= ( 1 << n );
- }
- else
- {//clear
- NPC->client->ps.saberStylesKnown &= ~( 1 << n );
- }
- NPC->client->ps.saberAnimLevel = n;
- if ( parsingPlayer )
- {
- cg.saberAnimLevelPending = n;
- }
- continue;
- }
- if ( !parsingPlayer )
- {
- gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, NPCName );
- }
- SkipRestOfLine( &p );
- }
- }
- ci->infoValid = qfalse;
- /*
- Ghoul2 Insert Start
- */
- if ( !md3Model )
- {
- NPC->weaponModel[0] = -1;
- if ( Q_stricmp( "player", playerModel ) == 0 )
- {//set the model from the console cvars
- G_InitPlayerFromCvars( NPC );
- //now set the weapon, etc.
- G_MatchPlayerWeapon( NPC );
- //NPC->NPC->aiFlags |= NPCAI_MATCHPLAYERWEAPON;//FIXME: may not always want this
- }
- else
- {//do a normal model load
- // If this is a vehicle, set the model name from the vehicle type array.
- if ( NPC->client->NPC_class == CLASS_VEHICLE )
- {
- int iVehIndex = BG_VehicleGetIndex( NPC->NPC_type );
- strcpy(customSkin, "default"); // Ignore any custom skin that may have come from the NPC File
- Q_strncpyz( playerModel, g_vehicleInfo[iVehIndex].model, sizeof(playerModel), qtrue);
- if ( g_vehicleInfo[iVehIndex].skin && g_vehicleInfo[iVehIndex].skin[0] )
- {
- bool forceSkin = false;
- // Iterate Over All Possible Skins
- //---------------------------------
- ratl::vector_vs<hstring, 15> skinarray;
- ratl::string_vs<256> skins(g_vehicleInfo[iVehIndex].skin);
- for (ratl::string_vs<256>::tokenizer i = skins.begin("|"); i!=skins.end(); i++)
- {
- if (NPC->soundSet && NPC->soundSet[0] && Q_stricmp(*i, NPC->soundSet)==0)
- {
- forceSkin = true;
- }
- skinarray.push_back(*i);
- }
- // Soundset Is The Designer Set Way To Supply A Skin
- //---------------------------------------------------
- if (forceSkin)
- {
- Q_strncpyz( customSkin, NPC->soundSet, sizeof(customSkin), qtrue);
- }
- // Otherwise Choose A Random Skin
- //--------------------------------
- else
- {
- if (NPC->soundSet && NPC->soundSet[0])
- {
- gi.Printf(S_COLOR_RED"WARNING: Unable to use skin (%s)", NPC->soundSet);
- }
- Q_strncpyz( customSkin, *skinarray[Q_irand(0, skinarray.size()-1)], sizeof(customSkin), qtrue);
- }
- if (NPC->soundSet && gi.bIsFromZone(NPC->soundSet, TAG_G_ALLOC)) {
- gi.Free(NPC->soundSet);
- }
- NPC->soundSet = 0; // clear the pointer
- }
- }
- G_SetG2PlayerModel( NPC, playerModel, customSkin, surfOff, surfOn );
- }
- }
- /*
- Ghoul2 Insert End
- */
- if( NPCsPrecached )
- {//Spawning in after initial precache, our models are precached, we just need to set our clientInfo
- CG_RegisterClientModels( NPC->s.number );
- CG_RegisterNPCCustomSounds( ci );
- //CG_RegisterNPCEffects( NPC->client->playerTeam );
- }
- return qtrue;
- }
- void NPC_LoadParms( void )
- {
- int len, totallen, npcExtFNLen, fileCnt, i;
- char *buffer, *holdChar, *marker;
- char npcExtensionListBuf[2048]; // The list of file names read in
- //gi.Printf( "Parsing ext_data/npcs/*.npc definitions\n" );
- //set where to store the first one
- totallen = 0;
- marker = NPCParms;
- marker[0] = '\0';
- //now load in the .npc definitions
- fileCnt = gi.FS_GetFileList("ext_data/npcs", ".npc", npcExtensionListBuf, sizeof(npcExtensionListBuf) );
- holdChar = npcExtensionListBuf;
- for ( i = 0; i < fileCnt; i++, holdChar += npcExtFNLen + 1 )
- {
- npcExtFNLen = strlen( holdChar );
- //gi.Printf( "Parsing %s\n", holdChar );
- len = gi.FS_ReadFile( va( "ext_data/npcs/%s", holdChar), (void **) &buffer );
- if ( len == -1 )
- {
- gi.Printf( "NPC_LoadParms: error reading file %s\n", holdChar );
- }
- else
- {
- if ( totallen && *(marker-1) == '}' )
- {//don't let previous file end on a } because that must be a stand-alone token
- strcat( marker, " " );
- totallen++;
- marker++;
- }
- len = COM_Compress( buffer );
- if ( totallen + len >= MAX_NPC_DATA_SIZE ) {
- G_Error( "NPC_LoadParms: ran out of space before reading %s\n(you must make the .npc files smaller)", holdChar );
- }
- strcat( marker, buffer );
- gi.FS_FreeFile( buffer );
- totallen += len;
- marker += len;
- }
- }
- }
|