123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253 |
- //**************************************************************************
- //**
- //** p_inter.c : Heretic 2 : Raven Software, Corp.
- //**
- //** $RCSfile: p_inter.c,v $
- //** $Revision: 1.145 $
- //** $Date: 96/01/16 10:35:33 $
- //** $Author: bgokey $
- //**
- //**************************************************************************
- #include "h2def.h"
- #include "p_local.h"
- #include "soundst.h"
- #define BONUSADD 6
- int ArmorIncrement[NUMCLASSES][NUMARMOR] =
- {
- { 25*FRACUNIT, 20*FRACUNIT, 15*FRACUNIT, 5*FRACUNIT },
- { 10*FRACUNIT, 25*FRACUNIT, 5*FRACUNIT, 20*FRACUNIT },
- { 5*FRACUNIT, 15*FRACUNIT, 10*FRACUNIT, 25*FRACUNIT },
- { 0, 0, 0, 0 }
- };
- int AutoArmorSave[NUMCLASSES] = { 15*FRACUNIT, 10*FRACUNIT, 5*FRACUNIT, 0 };
- char *TextKeyMessages[] =
- {
- TXT_KEY_STEEL,
- TXT_KEY_CAVE,
- TXT_KEY_AXE,
- TXT_KEY_FIRE,
- TXT_KEY_EMERALD,
- TXT_KEY_DUNGEON,
- TXT_KEY_SILVER,
- TXT_KEY_RUSTED,
- TXT_KEY_HORN,
- TXT_KEY_SWAMP,
- TXT_KEY_CASTLE
- };
- static void SetDormantArtifact(mobj_t *arti);
- static void TryPickupArtifact(player_t *player, artitype_t artifactType,
- mobj_t *artifact);
- static void TryPickupWeapon(player_t *player, pclass_t weaponClass,
- weapontype_t weaponType, mobj_t *weapon, char *message);
- static void TryPickupWeaponPiece(player_t *player, pclass_t matchClass,
- int pieceValue, mobj_t *pieceMobj);
- #ifdef __NeXT__
- extern void strupr(char *s);
- #endif
- //--------------------------------------------------------------------------
- //
- // PROC P_SetMessage
- //
- //--------------------------------------------------------------------------
- void P_SetMessage(player_t *player, char *message, boolean ultmsg)
- {
- extern boolean messageson;
-
- if((player->ultimateMessage || !messageson) && !ultmsg)
- {
- return;
- }
- if(strlen(message) > 79)
- {
- memcpy(player->message, message, 80);
- player->message[80] = 0;
- }
- else
- {
- strcpy(player->message, message);
- }
- strupr(player->message);
- player->messageTics = MESSAGETICS;
- player->yellowMessage = false;
- if(ultmsg)
- {
- player->ultimateMessage = true;
- }
- if(player == &players[consoleplayer])
- {
- BorderTopRefresh = true;
- }
- }
- //==========================================================================
- //
- // P_SetYellowMessage
- //
- //==========================================================================
- void P_SetYellowMessage(player_t *player, char *message, boolean ultmsg)
- {
- extern boolean messageson;
-
- if((player->ultimateMessage || !messageson) && !ultmsg)
- {
- return;
- }
- if(strlen(message) > 79)
- {
- memcpy(player->message, message, 80);
- player->message[80] = 0;
- }
- else
- {
- strcpy(player->message, message);
- }
- player->messageTics = 5*MESSAGETICS; // Bold messages last longer
- player->yellowMessage = true;
- if(ultmsg)
- {
- player->ultimateMessage = true;
- }
- if(player == &players[consoleplayer])
- {
- BorderTopRefresh = true;
- }
- }
- //==========================================================================
- //
- // P_ClearMessage
- //
- //==========================================================================
- void P_ClearMessage(player_t *player)
- {
- player->messageTics = 0;
- if(player == &players[consoleplayer])
- {
- BorderTopRefresh = true;
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_HideSpecialThing
- //
- //----------------------------------------------------------------------------
- void P_HideSpecialThing(mobj_t *thing)
- {
- thing->flags &= ~MF_SPECIAL;
- thing->flags2 |= MF2_DONTDRAW;
- P_SetMobjState(thing, S_HIDESPECIAL1);
- }
- //--------------------------------------------------------------------------
- //
- // FUNC P_GiveMana
- //
- // Returns true if the player accepted the mana, false if it was
- // refused (player has MAX_MANA).
- //
- //--------------------------------------------------------------------------
- boolean P_GiveMana(player_t *player, manatype_t mana, int count)
- {
- int prevMana;
- //weapontype_t changeWeapon;
- if(mana == MANA_NONE || mana == MANA_BOTH)
- {
- return(false);
- }
- if(mana < 0 || mana > NUMMANA)
- {
- I_Error("P_GiveMana: bad type %i", mana);
- }
- if(player->mana[mana] == MAX_MANA)
- {
- return(false);
- }
- if(gameskill == sk_baby || gameskill == sk_nightmare)
- { // extra mana in baby mode and nightmare mode
- count += count>>1;
- }
- prevMana = player->mana[mana];
- player->mana[mana] += count;
- if(player->mana[mana] > MAX_MANA)
- {
- player->mana[mana] = MAX_MANA;
- }
- if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
- && mana == MANA_1 && prevMana <= 0)
- {
- P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
- }
- return(true);
- }
- //==========================================================================
- //
- // TryPickupWeapon
- //
- //==========================================================================
- static void TryPickupWeapon(player_t *player, pclass_t weaponClass,
- weapontype_t weaponType, mobj_t *weapon, char *message)
- {
- boolean remove;
- boolean gaveMana;
- boolean gaveWeapon;
- remove = true;
- if(player->class != weaponClass)
- { // Wrong class, but try to pick up for mana
- if(netgame && !deathmatch)
- { // Can't pick up weapons for other classes in coop netplay
- return;
- }
- if(weaponType == WP_SECOND)
- {
- if(!P_GiveMana(player, MANA_1, 25))
- {
- return;
- }
- }
- else
- {
- if(!P_GiveMana(player, MANA_2, 25))
- {
- return;
- }
- }
- }
- else if(netgame && !deathmatch)
- { // Cooperative net-game
- if(player->weaponowned[weaponType])
- {
- return;
- }
- player->weaponowned[weaponType] = true;
- if(weaponType == WP_SECOND)
- {
- P_GiveMana(player, MANA_1, 25);
- }
- else
- {
- P_GiveMana(player, MANA_2, 25);
- }
- player->pendingweapon = weaponType;
- remove = false;
- }
- else
- { // Deathmatch or single player game
- if(weaponType == WP_SECOND)
- {
- gaveMana = P_GiveMana(player, MANA_1, 25);
- }
- else
- {
- gaveMana = P_GiveMana(player, MANA_2, 25);
- }
- if(player->weaponowned[weaponType])
- {
- gaveWeapon = false;
- }
- else
- {
- gaveWeapon = true;
- player->weaponowned[weaponType] = true;
- if(weaponType > player->readyweapon)
- { // Only switch to more powerful weapons
- player->pendingweapon = weaponType;
- }
- }
- if(!(gaveWeapon || gaveMana))
- { // Player didn't need the weapon or any mana
- return;
- }
- }
- P_SetMessage(player, message, false);
- if(weapon->special)
- {
- P_ExecuteLineSpecial(weapon->special, weapon->args,
- NULL, 0, player->mo);
- weapon->special = 0;
- }
- if(remove)
- {
- if(deathmatch && !(weapon->flags2&MF2_DROPPED))
- {
- P_HideSpecialThing(weapon);
- }
- else
- {
- P_RemoveMobj(weapon);
- }
- }
- player->bonuscount += BONUSADD;
- if(player == &players[consoleplayer])
- {
- S_StartSound(NULL, SFX_PICKUP_WEAPON);
- SB_PaletteFlash(false);
- }
- }
- //--------------------------------------------------------------------------
- //
- // FUNC P_GiveWeapon
- //
- // Returns true if the weapon or its mana was accepted.
- //
- //--------------------------------------------------------------------------
- /*
- boolean P_GiveWeapon(player_t *player, pclass_t class, weapontype_t weapon)
- {
- boolean gaveMana;
- boolean gaveWeapon;
- if(player->class != class)
- { // player cannot use this weapon, take it anyway, and get mana
- if(netgame && !deathmatch)
- { // Can't pick up weapons for other classes in coop netplay
- return false;
- }
- if(weapon == WP_SECOND)
- {
- return P_GiveMana(player, MANA_1, 25);
- }
- else
- {
- return P_GiveMana(player, MANA_2, 25);
- }
- }
- if(netgame && !deathmatch)
- { // Cooperative net-game
- if(player->weaponowned[weapon])
- {
- return(false);
- }
- player->bonuscount += BONUSADD;
- player->weaponowned[weapon] = true;
- if(weapon == WP_SECOND)
- {
- P_GiveMana(player, MANA_1, 25);
- }
- else
- {
- P_GiveMana(player, MANA_2, 25);
- }
- player->pendingweapon = weapon;
- if(player == &players[consoleplayer])
- {
- S_StartSound(NULL, SFX_PICKUP_WEAPON);
- }
- return(false);
- }
- if(weapon == WP_SECOND)
- {
- gaveMana = P_GiveMana(player, MANA_1, 25);
- }
- else
- {
- gaveMana = P_GiveMana(player, MANA_2, 25);
- }
- if(player->weaponowned[weapon])
- {
- gaveWeapon = false;
- }
- else
- {
- gaveWeapon = true;
- player->weaponowned[weapon] = true;
- if(weapon > player->readyweapon)
- { // Only switch to more powerful weapons
- player->pendingweapon = weapon;
- }
- }
- return(gaveWeapon || gaveMana);
- }
- */
- //===========================================================================
- //
- // P_GiveWeaponPiece
- //
- //===========================================================================
- /*
- boolean P_GiveWeaponPiece(player_t *player, pclass_t class, int piece)
- {
- P_GiveMana(player, MANA_1, 20);
- P_GiveMana(player, MANA_2, 20);
- if(player->class != class)
- {
- return true;
- }
- else if(player->pieces&piece)
- { // player already has that weapon piece
- return true;
- }
- player->pieces |= piece;
- if(player->pieces == 7)
- { // player has built the fourth weapon!
- P_GiveWeapon(player, class, WP_FOURTH);
- S_StartSound(player->mo, SFX_WEAPON_BUILD);
- }
- return true;
- }
- */
- //==========================================================================
- //
- // TryPickupWeaponPiece
- //
- //==========================================================================
- static void TryPickupWeaponPiece(player_t *player, pclass_t matchClass,
- int pieceValue, mobj_t *pieceMobj)
- {
- boolean remove;
- boolean checkAssembled;
- boolean gaveWeapon;
- int gaveMana;
- static char *fourthWeaponText[] =
- {
- TXT_WEAPON_F4,
- TXT_WEAPON_C4,
- TXT_WEAPON_M4
- };
- static char *weaponPieceText[] =
- {
- TXT_QUIETUS_PIECE,
- TXT_WRAITHVERGE_PIECE,
- TXT_BLOODSCOURGE_PIECE
- };
- static int pieceValueTrans[] =
- {
- 0, // 0: never
- WPIECE1|WPIECE2|WPIECE3, // WPIECE1 (1)
- WPIECE2|WPIECE3, // WPIECE2 (2)
- 0, // 3: never
- WPIECE3 // WPIECE3 (4)
- };
- remove = true;
- checkAssembled = true;
- gaveWeapon = false;
- if(player->class != matchClass)
- { // Wrong class, but try to pick up for mana
- if(netgame && !deathmatch)
- { // Can't pick up wrong-class weapons in coop netplay
- return;
- }
- checkAssembled = false;
- gaveMana = P_GiveMana(player, MANA_1, 20)+
- P_GiveMana(player, MANA_2, 20);
- if(!gaveMana)
- { // Didn't need the mana, so don't pick it up
- return;
- }
- }
- else if(netgame && !deathmatch)
- { // Cooperative net-game
- if(player->pieces&pieceValue)
- { // Already has the piece
- return;
- }
- pieceValue = pieceValueTrans[pieceValue];
- P_GiveMana(player, MANA_1, 20);
- P_GiveMana(player, MANA_2, 20);
- remove = false;
- }
- else
- { // Deathmatch or single player game
- gaveMana = P_GiveMana(player, MANA_1, 20)+
- P_GiveMana(player, MANA_2, 20);
- if(player->pieces&pieceValue)
- { // Already has the piece, check if mana needed
- if(!gaveMana)
- { // Didn't need the mana, so don't pick it up
- return;
- }
- checkAssembled = false;
- }
- }
- // Pick up the weapon piece
- if(pieceMobj->special)
- {
- P_ExecuteLineSpecial(pieceMobj->special, pieceMobj->args,
- NULL, 0, player->mo);
- pieceMobj->special = 0;
- }
- if(remove)
- {
- if(deathmatch && !(pieceMobj->flags2&MF2_DROPPED))
- {
- P_HideSpecialThing(pieceMobj);
- }
- else
- {
- P_RemoveMobj(pieceMobj);
- }
- }
- player->bonuscount += BONUSADD;
- if(player == &players[consoleplayer])
- {
- SB_PaletteFlash(false);
- }
- // Check if fourth weapon assembled
- if(checkAssembled)
- {
- player->pieces |= pieceValue;
- if(player->pieces == (WPIECE1|WPIECE2|WPIECE3))
- {
- gaveWeapon = true;
- player->weaponowned[WP_FOURTH] = true;
- player->pendingweapon = WP_FOURTH;
- }
- }
- if(gaveWeapon)
- {
- P_SetMessage(player, fourthWeaponText[matchClass], false);
- // Play the build-sound full volume for all players
- S_StartSound(NULL, SFX_WEAPON_BUILD);
- }
- else
- {
- P_SetMessage(player, weaponPieceText[matchClass], false);
- if(player == &players[consoleplayer])
- {
- S_StartSound(NULL, SFX_PICKUP_WEAPON);
- }
- }
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_GiveBody
- //
- // Returns false if the body isn't needed at all.
- //
- //---------------------------------------------------------------------------
- boolean P_GiveBody(player_t *player, int num)
- {
- int max;
- max = MAXHEALTH;
- if(player->morphTics)
- {
- max = MAXMORPHHEALTH;
- }
- if(player->health >= max)
- {
- return(false);
- }
- player->health += num;
- if(player->health > max)
- {
- player->health = max;
- }
- player->mo->health = player->health;
- return(true);
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_GiveArmor
- //
- // Returns false if the armor is worse than the current armor.
- //
- //---------------------------------------------------------------------------
- boolean P_GiveArmor(player_t *player, armortype_t armortype, int amount)
- {
- int hits;
- int totalArmor;
- extern int ArmorMax[NUMCLASSES];
- if(amount == -1)
- {
- hits = ArmorIncrement[player->class][armortype];
- if(player->armorpoints[armortype] >= hits)
- {
- return false;
- }
- else
- {
- player->armorpoints[armortype] = hits;
- }
- }
- else
- {
- hits = amount*5*FRACUNIT;
- totalArmor = player->armorpoints[ARMOR_ARMOR]
- +player->armorpoints[ARMOR_SHIELD]
- +player->armorpoints[ARMOR_HELMET]
- +player->armorpoints[ARMOR_AMULET]
- +AutoArmorSave[player->class];
- if(totalArmor < ArmorMax[player->class]*5*FRACUNIT)
- {
- player->armorpoints[armortype] += hits;
- }
- else
- {
- return false;
- }
- }
- return true;
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_GiveKey
- //
- //---------------------------------------------------------------------------
- int P_GiveKey(player_t *player, keytype_t key)
- {
- if(player->keys&(1<<key))
- {
- return false;
- }
- player->bonuscount += BONUSADD;
- player->keys |= 1<<key;
- return true;
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_GivePower
- //
- // Returns true if power accepted.
- //
- //---------------------------------------------------------------------------
- boolean P_GivePower(player_t *player, powertype_t power)
- {
- if(power == pw_invulnerability)
- {
- if(player->powers[power] > BLINKTHRESHOLD)
- { // Already have it
- return(false);
- }
- player->powers[power] = INVULNTICS;
- player->mo->flags2 |= MF2_INVULNERABLE;
- if(player->class == PCLASS_MAGE)
- {
- player->mo->flags2 |= MF2_REFLECTIVE;
- }
- return(true);
- }
- if(power == pw_flight)
- {
- if(player->powers[power] > BLINKTHRESHOLD)
- { // Already have it
- return(false);
- }
- player->powers[power] = FLIGHTTICS;
- player->mo->flags2 |= MF2_FLY;
- player->mo->flags |= MF_NOGRAVITY;
- if(player->mo->z <= player->mo->floorz)
- {
- player->flyheight = 10; // thrust the player in the air a bit
- }
- return(true);
- }
- if(power == pw_infrared)
- {
- if(player->powers[power] > BLINKTHRESHOLD)
- { // Already have it
- return(false);
- }
- player->powers[power] = INFRATICS;
- return(true);
- }
- if(power == pw_speed)
- {
- if(player->powers[power] > BLINKTHRESHOLD)
- { // Already have it
- return(false);
- }
- player->powers[power] = SPEEDTICS;
- return(true);
- }
- if(power == pw_minotaur)
- {
- // Doesn't matter if already have power, renew ticker
- player->powers[power] = MAULATORTICS;
- return(true);
- }
- /*
- if(power == pw_ironfeet)
- {
- player->powers[power] = IRONTICS;
- return(true);
- }
- if(power == pw_strength)
- {
- P_GiveBody(player, 100);
- player->powers[power] = 1;
- return(true);
- }
- */
- if(player->powers[power])
- {
- return(false); // already got it
- }
- player->powers[power] = 1;
- return(true);
- }
- //==========================================================================
- //
- // TryPickupArtifact
- //
- //==========================================================================
- static void TryPickupArtifact(player_t *player, artitype_t artifactType,
- mobj_t *artifact)
- {
- static char *artifactMessages[NUMARTIFACTS] =
- {
- NULL,
- TXT_ARTIINVULNERABILITY,
- TXT_ARTIHEALTH,
- TXT_ARTISUPERHEALTH,
- TXT_ARTIHEALINGRADIUS,
- TXT_ARTISUMMON,
- TXT_ARTITORCH,
- TXT_ARTIEGG,
- TXT_ARTIFLY,
- TXT_ARTIBLASTRADIUS,
- TXT_ARTIPOISONBAG,
- TXT_ARTITELEPORTOTHER,
- TXT_ARTISPEED,
- TXT_ARTIBOOSTMANA,
- TXT_ARTIBOOSTARMOR,
- TXT_ARTITELEPORT,
- TXT_ARTIPUZZSKULL,
- TXT_ARTIPUZZGEMBIG,
- TXT_ARTIPUZZGEMRED,
- TXT_ARTIPUZZGEMGREEN1,
- TXT_ARTIPUZZGEMGREEN2,
- TXT_ARTIPUZZGEMBLUE1,
- TXT_ARTIPUZZGEMBLUE2,
- TXT_ARTIPUZZBOOK1,
- TXT_ARTIPUZZBOOK2,
- TXT_ARTIPUZZSKULL2,
- TXT_ARTIPUZZFWEAPON,
- TXT_ARTIPUZZCWEAPON,
- TXT_ARTIPUZZMWEAPON,
- TXT_ARTIPUZZGEAR, // All gear pickups use the same text
- TXT_ARTIPUZZGEAR,
- TXT_ARTIPUZZGEAR,
- TXT_ARTIPUZZGEAR
- };
- if(P_GiveArtifact(player, artifactType, artifact))
- {
- if(artifact->special)
- {
- P_ExecuteLineSpecial(artifact->special, artifact->args,
- NULL, 0, NULL);
- artifact->special = 0;
- }
- player->bonuscount += BONUSADD;
- if(artifactType < arti_firstpuzzitem)
- {
- SetDormantArtifact(artifact);
- S_StartSound(artifact, SFX_PICKUP_ARTIFACT);
- P_SetMessage(player, artifactMessages[artifactType], false);
- }
- else
- { // Puzzle item
- S_StartSound(NULL, SFX_PICKUP_ITEM);
- P_SetMessage(player, artifactMessages[artifactType], true);
- if(!netgame || deathmatch)
- { // Remove puzzle items if not cooperative netplay
- P_RemoveMobj(artifact);
- }
- }
- }
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_GiveArtifact
- //
- // Returns true if artifact accepted.
- //
- //---------------------------------------------------------------------------
- boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
- {
- int i;
- int j;
- boolean slidePointer;
- slidePointer = false;
- i = 0;
- while(player->inventory[i].type != arti && i < player->inventorySlotNum)
- {
- i++;
- }
- if(i == player->inventorySlotNum)
- {
- if(arti < arti_firstpuzzitem)
- {
- i = 0;
- while(player->inventory[i].type < arti_firstpuzzitem
- && i < player->inventorySlotNum)
- {
- i++;
- }
- if(i != player->inventorySlotNum)
- {
- for(j = player->inventorySlotNum; j > i; j--)
- {
- player->inventory[j].count = player->inventory[j-1].count;
- player->inventory[j].type = player->inventory[j-1].type;
- slidePointer = true;
- }
- }
- }
- player->inventory[i].count = 1;
- player->inventory[i].type = arti;
- player->inventorySlotNum++;
- }
- else
- {
- if(arti >= arti_firstpuzzitem && netgame && !deathmatch)
- { // Can't carry more than 1 puzzle item in coop netplay
- return false;
- }
- if(player->inventory[i].count >= 25)
- { // Player already has 25 of this item
- return false;
- }
- player->inventory[i].count++;
- }
- if(!player->artifactCount)
- {
- player->readyArtifact = arti;
- }
- else if(player == &players[consoleplayer] && slidePointer
- && i <= inv_ptr)
- {
- inv_ptr++;
- curpos++;
- if(curpos > 6)
- {
- curpos = 6;
- }
- }
- player->artifactCount++;
- return(true);
- }
- //==========================================================================
- //
- // SetDormantArtifact
- //
- // Removes the MF_SPECIAL flag and initiates the artifact pickup
- // animation.
- //
- //==========================================================================
- static void SetDormantArtifact(mobj_t *arti)
- {
- arti->flags &= ~MF_SPECIAL;
- if(deathmatch && !(arti->flags2 & MF2_DROPPED))
- {
- if(arti->type == MT_ARTIINVULNERABILITY)
- {
- P_SetMobjState(arti, S_DORMANTARTI3_1);
- }
- else if(arti->type == MT_SUMMONMAULATOR
- || arti->type == MT_ARTIFLY)
- {
- P_SetMobjState(arti, S_DORMANTARTI2_1);
- }
- else
- {
- P_SetMobjState(arti, S_DORMANTARTI1_1);
- }
- }
- else
- { // Don't respawn
- P_SetMobjState(arti, S_DEADARTI1);
- }
- }
- //---------------------------------------------------------------------------
- //
- // PROC A_RestoreArtifact
- //
- //---------------------------------------------------------------------------
- void A_RestoreArtifact(mobj_t *arti)
- {
- arti->flags |= MF_SPECIAL;
- P_SetMobjState(arti, arti->info->spawnstate);
- S_StartSound(arti, SFX_RESPAWN);
- }
- //---------------------------------------------------------------------------
- //
- // PROC A_RestoreSpecialThing1
- //
- // Make a special thing visible again.
- //
- //---------------------------------------------------------------------------
- void A_RestoreSpecialThing1(mobj_t *thing)
- {
- thing->flags2 &= ~MF2_DONTDRAW;
- S_StartSound(thing, SFX_RESPAWN);
- }
- //---------------------------------------------------------------------------
- //
- // PROC A_RestoreSpecialThing2
- //
- //---------------------------------------------------------------------------
- void A_RestoreSpecialThing2(mobj_t *thing)
- {
- thing->flags |= MF_SPECIAL;
- P_SetMobjState(thing, thing->info->spawnstate);
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_TouchSpecialThing
- //
- //---------------------------------------------------------------------------
- void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
- {
- player_t *player;
- fixed_t delta;
- int sound;
- boolean respawn;
- delta = special->z-toucher->z;
- if(delta > toucher->height || delta < -32*FRACUNIT)
- { // Out of reach
- return;
- }
- if(toucher->health <= 0)
- { // Toucher is dead
- return;
- }
- sound = SFX_PICKUP_ITEM;
- player = toucher->player;
- respawn = true;
- switch(special->sprite)
- {
- // Items
- case SPR_PTN1: // Item_HealingPotion
- if(!P_GiveBody(player, 10))
- {
- return;
- }
- P_SetMessage(player, TXT_ITEMHEALTH, false);
- break;
- case SPR_ARM1:
- if(!P_GiveArmor(player, ARMOR_ARMOR, -1))
- {
- return;
- }
- P_SetMessage(player, TXT_ARMOR1, false);
- break;
- case SPR_ARM2:
- if(!P_GiveArmor(player, ARMOR_SHIELD, -1))
- {
- return;
- }
- P_SetMessage(player, TXT_ARMOR2, false);
- break;
- case SPR_ARM3:
- if(!P_GiveArmor(player, ARMOR_HELMET, -1))
- {
- return;
- }
- P_SetMessage(player, TXT_ARMOR3, false);
- break;
- case SPR_ARM4:
- if(!P_GiveArmor(player, ARMOR_AMULET, -1))
- {
- return;
- }
- P_SetMessage(player, TXT_ARMOR4, false);
- break;
- // Keys
- case SPR_KEY1:
- case SPR_KEY2:
- case SPR_KEY3:
- case SPR_KEY4:
- case SPR_KEY5:
- case SPR_KEY6:
- case SPR_KEY7:
- case SPR_KEY8:
- case SPR_KEY9:
- case SPR_KEYA:
- case SPR_KEYB:
- if(!P_GiveKey(player, special->sprite-SPR_KEY1))
- {
- return;
- }
- P_SetMessage(player, TextKeyMessages[special->sprite-SPR_KEY1],
- true);
- sound = SFX_PICKUP_KEY;
- // Check and process the special now in case the key doesn't
- // get removed for coop netplay
- if(special->special)
- {
- P_ExecuteLineSpecial(special->special, special->args,
- NULL, 0, toucher);
- special->special = 0;
- }
- if(!netgame)
- { // Only remove keys in single player game
- break;
- }
- player->bonuscount += BONUSADD;
- if(player == &players[consoleplayer])
- {
- S_StartSound(NULL, sound);
- SB_PaletteFlash(false);
- }
- return;
- // Artifacts
- case SPR_PTN2:
- TryPickupArtifact(player, arti_health, special);
- return;
- case SPR_SOAR:
- TryPickupArtifact(player, arti_fly, special);
- return;
- case SPR_INVU:
- TryPickupArtifact(player, arti_invulnerability, special);
- return;
- case SPR_SUMN:
- TryPickupArtifact(player, arti_summon, special);
- return;
- case SPR_PORK:
- TryPickupArtifact(player, arti_egg, special);
- return;
- case SPR_SPHL:
- TryPickupArtifact(player, arti_superhealth, special);
- return;
- case SPR_HRAD:
- TryPickupArtifact(player, arti_healingradius, special);
- return;
- case SPR_TRCH:
- TryPickupArtifact(player, arti_torch, special);
- return;
- case SPR_ATLP:
- TryPickupArtifact(player, arti_teleport, special);
- return;
- case SPR_TELO:
- TryPickupArtifact(player, arti_teleportother, special);
- return;
- case SPR_PSBG:
- TryPickupArtifact(player, arti_poisonbag, special);
- return;
- case SPR_SPED:
- TryPickupArtifact(player, arti_speed, special);
- return;
- case SPR_BMAN:
- TryPickupArtifact(player, arti_boostmana, special);
- return;
- case SPR_BRAC:
- TryPickupArtifact(player, arti_boostarmor, special);
- return;
- case SPR_BLST:
- TryPickupArtifact(player, arti_blastradius, special);
- return;
- // Puzzle artifacts
- case SPR_ASKU:
- TryPickupArtifact(player, arti_puzzskull, special);
- return;
- case SPR_ABGM:
- TryPickupArtifact(player, arti_puzzgembig, special);
- return;
- case SPR_AGMR:
- TryPickupArtifact(player, arti_puzzgemred, special);
- return;
- case SPR_AGMG:
- TryPickupArtifact(player, arti_puzzgemgreen1, special);
- return;
- case SPR_AGG2:
- TryPickupArtifact(player, arti_puzzgemgreen2, special);
- return;
- case SPR_AGMB:
- TryPickupArtifact(player, arti_puzzgemblue1, special);
- return;
- case SPR_AGB2:
- TryPickupArtifact(player, arti_puzzgemblue2, special);
- return;
- case SPR_ABK1:
- TryPickupArtifact(player, arti_puzzbook1, special);
- return;
- case SPR_ABK2:
- TryPickupArtifact(player, arti_puzzbook2, special);
- return;
- case SPR_ASK2:
- TryPickupArtifact(player, arti_puzzskull2, special);
- return;
- case SPR_AFWP:
- TryPickupArtifact(player, arti_puzzfweapon, special);
- return;
- case SPR_ACWP:
- TryPickupArtifact(player, arti_puzzcweapon, special);
- return;
- case SPR_AMWP:
- TryPickupArtifact(player, arti_puzzmweapon, special);
- return;
- case SPR_AGER:
- TryPickupArtifact(player, arti_puzzgear1, special);
- return;
- case SPR_AGR2:
- TryPickupArtifact(player, arti_puzzgear2, special);
- return;
- case SPR_AGR3:
- TryPickupArtifact(player, arti_puzzgear3, special);
- return;
- case SPR_AGR4:
- TryPickupArtifact(player, arti_puzzgear4, special);
- return;
- // Mana
- case SPR_MAN1:
- if(!P_GiveMana(player, MANA_1, 15))
- {
- return;
- }
- P_SetMessage(player, TXT_MANA_1, false);
- break;
- case SPR_MAN2:
- if(!P_GiveMana(player, MANA_2, 15))
- {
- return;
- }
- P_SetMessage(player, TXT_MANA_2, false);
- break;
- case SPR_MAN3: // Double Mana Dodecahedron
- if(!P_GiveMana(player, MANA_1, 20))
- {
- if(!P_GiveMana(player, MANA_2, 20))
- {
- return;
- }
- }
- else
- {
- P_GiveMana(player, MANA_2, 20);
- }
- P_SetMessage(player, TXT_MANA_BOTH, false);
- break;
- // 2nd and 3rd Mage Weapons
- case SPR_WMCS: // Frost Shards
- TryPickupWeapon(player, PCLASS_MAGE, WP_SECOND,
- special, TXT_WEAPON_M2);
- return;
- case SPR_WMLG: // Arc of Death
- TryPickupWeapon(player, PCLASS_MAGE, WP_THIRD,
- special, TXT_WEAPON_M3);
- return;
- // 2nd and 3rd Fighter Weapons
- case SPR_WFAX: // Timon's Axe
- TryPickupWeapon(player, PCLASS_FIGHTER, WP_SECOND,
- special, TXT_WEAPON_F2);
- return;
- case SPR_WFHM: // Hammer of Retribution
- TryPickupWeapon(player, PCLASS_FIGHTER, WP_THIRD,
- special, TXT_WEAPON_F3);
- return;
- // 2nd and 3rd Cleric Weapons
- case SPR_WCSS: // Serpent Staff
- TryPickupWeapon(player, PCLASS_CLERIC, WP_SECOND,
- special, TXT_WEAPON_C2);
- return;
- case SPR_WCFM: // Firestorm
- TryPickupWeapon(player, PCLASS_CLERIC, WP_THIRD,
- special, TXT_WEAPON_C3);
- return;
- // Fourth Weapon Pieces
- case SPR_WFR1:
- TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE1,
- special);
- return;
- case SPR_WFR2:
- TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE2,
- special);
- return;
- case SPR_WFR3:
- TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE3,
- special);
- return;
- case SPR_WCH1:
- TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE1,
- special);
- return;
- case SPR_WCH2:
- TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE2,
- special);
- return;
- case SPR_WCH3:
- TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE3,
- special);
- return;
- case SPR_WMS1:
- TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE1,
- special);
- return;
- case SPR_WMS2:
- TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE2,
- special);
- return;
- case SPR_WMS3:
- TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE3,
- special);
- return;
- default:
- I_Error("P_SpecialThing: Unknown gettable thing");
- }
- if(special->special)
- {
- P_ExecuteLineSpecial(special->special, special->args, NULL,
- 0, toucher);
- special->special = 0;
- }
- if(deathmatch && respawn && !(special->flags2&MF2_DROPPED))
- {
- P_HideSpecialThing(special);
- }
- else
- {
- P_RemoveMobj(special);
- }
- player->bonuscount += BONUSADD;
- if(player == &players[consoleplayer])
- {
- S_StartSound(NULL, sound);
- SB_PaletteFlash(false);
- }
- }
- // Search thinker list for minotaur
- mobj_t *ActiveMinotaur(player_t *master)
- {
- mobj_t *mo;
- player_t *plr;
- thinker_t *think;
- unsigned int *starttime;
- for(think = thinkercap.next; think != &thinkercap; think = think->next)
- {
- if(think->function != P_MobjThinker) continue;
- mo = (mobj_t *)think;
- if(mo->type != MT_MINOTAUR) continue;
- if(mo->health <= 0) continue;
- if(!(mo->flags&MF_COUNTKILL)) continue; // for morphed minotaurs
- if(mo->flags&MF_CORPSE) continue;
- starttime = (unsigned int *)mo->args;
- if ((leveltime - *starttime) >= MAULATORTICS) continue;
- plr = ((mobj_t *)mo->special1)->player;
- if(plr == master) return(mo);
- }
- return(NULL);
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_KillMobj
- //
- //---------------------------------------------------------------------------
- void P_KillMobj(mobj_t *source, mobj_t *target)
- {
- int dummy;
- mobj_t *master;
- target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_NOGRAVITY);
- target->flags |= MF_CORPSE|MF_DROPOFF;
- target->flags2 &= ~MF2_PASSMOBJ;
- target->height >>= 2;
- if((target->flags&MF_COUNTKILL || target->type == MT_ZBELL)
- && target->special)
- { // Initiate monster death actions
- if(target->type == MT_SORCBOSS)
- {
- dummy = 0;
- P_StartACS(target->special, 0, (byte *)&dummy, target,
- NULL, 0);
- }
- else
- {
- P_ExecuteLineSpecial(target->special, target->args,
- NULL, 0, target);
- }
- }
- if(source && source->player)
- { // Check for frag changes
- if(target->player)
- {
- if(target == source)
- { // Self-frag
- target->player->frags[target->player-players]--;
- if(cmdfrag && netgame
- && source->player == &players[consoleplayer])
- { // Send out a frag count packet
- NET_SendFrags(source->player);
- }
- }
- else
- {
- source->player->frags[target->player-players]++;
- if(cmdfrag && netgame
- && source->player == &players[consoleplayer])
- { // Send out a frag count packet
- NET_SendFrags(source->player);
- }
- }
- }
- }
- if(target->player)
- { // Player death
- if(!source)
- { // Self-frag
- target->player->frags[target->player-players]--;
- if(cmdfrag && netgame
- && target->player == &players[consoleplayer])
- { // Send out a frag count packet
- NET_SendFrags(target->player);
- }
- }
- target->flags &= ~MF_SOLID;
- target->flags2 &= ~MF2_FLY;
- target->player->powers[pw_flight] = 0;
- target->player->playerstate = PST_DEAD;
- P_DropWeapon(target->player);
- if(target->flags2&MF2_FIREDAMAGE)
- { // Player flame death
- switch(target->player->class)
- {
- case PCLASS_FIGHTER:
- S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
- P_SetMobjState(target, S_PLAY_F_FDTH1);
- return;
- case PCLASS_CLERIC:
- S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
- P_SetMobjState(target, S_PLAY_C_FDTH1);
- return;
- case PCLASS_MAGE:
- S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
- P_SetMobjState(target, S_PLAY_M_FDTH1);
- return;
- default:
- break;
- }
- }
- if(target->flags2&MF2_ICEDAMAGE)
- { // Player ice death
- target->flags &= ~(7<<MF_TRANSSHIFT); //no translation
- target->flags |= MF_ICECORPSE;
- switch(target->player->class)
- {
- case PCLASS_FIGHTER:
- P_SetMobjState(target, S_FPLAY_ICE);
- return;
- case PCLASS_CLERIC:
- P_SetMobjState(target, S_CPLAY_ICE);
- return;
- case PCLASS_MAGE:
- P_SetMobjState(target, S_MPLAY_ICE);
- return;
- case PCLASS_PIG:
- P_SetMobjState(target, S_PIG_ICE);
- return;
- default:
- break;
- }
- }
- }
- if(target->flags2&MF2_FIREDAMAGE)
- {
- if(target->type == MT_FIGHTER_BOSS
- || target->type == MT_CLERIC_BOSS
- || target->type == MT_MAGE_BOSS)
- {
- switch(target->type)
- {
- case MT_FIGHTER_BOSS:
- S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
- P_SetMobjState(target, S_PLAY_F_FDTH1);
- return;
- case MT_CLERIC_BOSS:
- S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
- P_SetMobjState(target, S_PLAY_C_FDTH1);
- return;
- case MT_MAGE_BOSS:
- S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
- P_SetMobjState(target, S_PLAY_M_FDTH1);
- return;
- default:
- break;
- }
- }
- else if(target->type == MT_TREEDESTRUCTIBLE)
- {
- P_SetMobjState(target, S_ZTREEDES_X1);
- target->height = 24*FRACUNIT;
- S_StartSound(target, SFX_TREE_EXPLODE);
- return;
- }
- }
- if(target->flags2&MF2_ICEDAMAGE)
- {
- target->flags |= MF_ICECORPSE;
- switch(target->type)
- {
- case MT_BISHOP:
- P_SetMobjState(target, S_BISHOP_ICE);
- return;
- case MT_CENTAUR:
- case MT_CENTAURLEADER:
- P_SetMobjState(target, S_CENTAUR_ICE);
- return;
- case MT_DEMON:
- case MT_DEMON2:
- P_SetMobjState(target, S_DEMON_ICE);
- return;
- case MT_SERPENT:
- case MT_SERPENTLEADER:
- P_SetMobjState(target, S_SERPENT_ICE);
- return;
- case MT_WRAITH:
- case MT_WRAITHB:
- P_SetMobjState(target, S_WRAITH_ICE);
- return;
- case MT_ETTIN:
- P_SetMobjState(target, S_ETTIN_ICE1);
- return;
- case MT_FIREDEMON:
- P_SetMobjState(target, S_FIRED_ICE1);
- return;
- case MT_FIGHTER_BOSS:
- P_SetMobjState(target, S_FIGHTER_ICE);
- return;
- case MT_CLERIC_BOSS:
- P_SetMobjState(target, S_CLERIC_ICE);
- return;
- case MT_MAGE_BOSS:
- P_SetMobjState(target, S_MAGE_ICE);
- return;
- case MT_PIG:
- P_SetMobjState(target, S_PIG_ICE);
- return;
- default:
- target->flags &= ~MF_ICECORPSE;
- break;
- }
- }
- if(target->type == MT_MINOTAUR)
- {
- master = (mobj_t *)target->special1;
- if(master->health > 0)
- {
- if (!ActiveMinotaur(master->player))
- {
- master->player->powers[pw_minotaur] = 0;
- }
- }
- }
- else if(target->type == MT_TREEDESTRUCTIBLE)
- {
- target->height = 24*FRACUNIT;
- }
- if(target->health < -(target->info->spawnhealth>>1)
- && target->info->xdeathstate)
- { // Extreme death
- P_SetMobjState(target, target->info->xdeathstate);
- }
- else
- { // Normal death
- if ((target->type==MT_FIREDEMON) &&
- (target->z <= target->floorz + 2*FRACUNIT) &&
- (target->info->xdeathstate))
- {
- // This is to fix the imps' staying in fall state
- P_SetMobjState(target, target->info->xdeathstate);
- }
- else
- {
- P_SetMobjState(target, target->info->deathstate);
- }
- }
- target->tics -= P_Random()&3;
- // I_StartSound(&actor->r, actor->info->deathsound);
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_MinotaurSlam
- //
- //---------------------------------------------------------------------------
- void P_MinotaurSlam(mobj_t *source, mobj_t *target)
- {
- angle_t angle;
- fixed_t thrust;
- angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
- angle >>= ANGLETOFINESHIFT;
- thrust = 16*FRACUNIT+(P_Random()<<10);
- target->momx += FixedMul(thrust, finecosine[angle]);
- target->momy += FixedMul(thrust, finesine[angle]);
- P_DamageMobj(target, NULL, source, HITDICE(4));
- if(target->player)
- {
- target->reactiontime = 14+(P_Random()&7);
- }
- source->args[0] = 0; // Stop charging
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_MorphPlayer
- //
- // Returns true if the player gets turned into a pig
- //
- //---------------------------------------------------------------------------
- boolean P_MorphPlayer(player_t *player)
- {
- mobj_t *pmo;
- mobj_t *fog;
- mobj_t *beastMo;
- fixed_t x;
- fixed_t y;
- fixed_t z;
- angle_t angle;
- int oldFlags2;
- if(player->powers[pw_invulnerability])
- { // Immune when invulnerable
- return(false);
- }
- if(player->morphTics)
- { // Player is already a beast
- return false;
- }
- pmo = player->mo;
- x = pmo->x;
- y = pmo->y;
- z = pmo->z;
- angle = pmo->angle;
- oldFlags2 = pmo->flags2;
- P_SetMobjState(pmo, S_FREETARGMOBJ);
- fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
- S_StartSound(fog, SFX_TELEPORT);
- beastMo = P_SpawnMobj(x, y, z, MT_PIGPLAYER);
- beastMo->special1 = player->readyweapon;
- beastMo->angle = angle;
- beastMo->player = player;
- player->health = beastMo->health = MAXMORPHHEALTH;
- player->mo = beastMo;
- memset(&player->armorpoints[0], 0, NUMARMOR*sizeof(int));
- player->class = PCLASS_PIG;
- if(oldFlags2&MF2_FLY)
- {
- beastMo->flags2 |= MF2_FLY;
- }
- player->morphTics = MORPHTICS;
- P_ActivateMorphWeapon(player);
- return(true);
- }
- //---------------------------------------------------------------------------
- //
- // FUNC P_MorphMonster
- //
- //---------------------------------------------------------------------------
- boolean P_MorphMonster(mobj_t *actor)
- {
- mobj_t *master, *monster, *fog;
- mobjtype_t moType;
- fixed_t x;
- fixed_t y;
- fixed_t z;
- mobj_t oldMonster;
- if(actor->player) return(false);
- if(!(actor->flags&MF_COUNTKILL)) return false;
- if(actor->flags2&MF2_BOSS) return false;
- moType = actor->type;
- switch(moType)
- {
- case MT_PIG:
- return(false);
- case MT_FIGHTER_BOSS:
- case MT_CLERIC_BOSS:
- case MT_MAGE_BOSS:
- return(false);
- default:
- break;
- }
- oldMonster = *actor;
- x = oldMonster.x;
- y = oldMonster.y;
- z = oldMonster.z;
- P_RemoveMobjFromTIDList(actor);
- P_SetMobjState(actor, S_FREETARGMOBJ);
- fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
- S_StartSound(fog, SFX_TELEPORT);
- monster = P_SpawnMobj(x, y, z, MT_PIG);
- monster->special2 = moType;
- monster->special1 = MORPHTICS+P_Random();
- monster->flags |= (oldMonster.flags&MF_SHADOW);
- monster->target = oldMonster.target;
- monster->angle = oldMonster.angle;
- monster->tid = oldMonster.tid;
- monster->special = oldMonster.special;
- P_InsertMobjIntoTIDList(monster, oldMonster.tid);
- memcpy(monster->args, oldMonster.args, 5);
- // check for turning off minotaur power for active icon
- if (moType==MT_MINOTAUR)
- {
- master = (mobj_t *)oldMonster.special1;
- if(master->health > 0)
- {
- if (!ActiveMinotaur(master->player))
- {
- master->player->powers[pw_minotaur] = 0;
- }
- }
- }
- return(true);
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_AutoUseHealth
- //
- //---------------------------------------------------------------------------
- void P_AutoUseHealth(player_t *player, int saveHealth)
- {
- int i;
- int count;
- int normalCount;
- int normalSlot=0;
- int superCount;
- int superSlot=0;
- normalCount = superCount = 0;
- for(i = 0; i < player->inventorySlotNum; i++)
- {
- if(player->inventory[i].type == arti_health)
- {
- normalSlot = i;
- normalCount = player->inventory[i].count;
- }
- else if(player->inventory[i].type == arti_superhealth)
- {
- superSlot = i;
- superCount = player->inventory[i].count;
- }
- }
- if((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
- { // Use quartz flasks
- count = (saveHealth+24)/25;
- for(i = 0; i < count; i++)
- {
- player->health += 25;
- P_PlayerRemoveArtifact(player, normalSlot);
- }
- }
- else if(superCount*100 >= saveHealth)
- { // Use mystic urns
- count = (saveHealth+99)/100;
- for(i = 0; i < count; i++)
- {
- player->health += 100;
- P_PlayerRemoveArtifact(player, superSlot);
- }
- }
- else if((gameskill == sk_baby)
- && (superCount*100+normalCount*25 >= saveHealth))
- { // Use mystic urns and quartz flasks
- count = (saveHealth+24)/25;
- saveHealth -= count*25;
- for(i = 0; i < count; i++)
- {
- player->health += 25;
- P_PlayerRemoveArtifact(player, normalSlot);
- }
- count = (saveHealth+99)/100;
- for(i = 0; i < count; i++)
- {
- player->health += 100;
- P_PlayerRemoveArtifact(player, normalSlot);
- }
- }
- player->mo->health = player->health;
- }
- /*
- =================
- =
- = P_DamageMobj
- =
- = Damages both enemies and players
- = inflictor is the thing that caused the damage
- = creature or missile, can be NULL (slime, etc)
- = source is the thing to target after taking damage
- = creature or NULL
- = Source and inflictor are the same for melee attacks
- = source can be null for barrel explosions and other environmental stuff
- ==================
- */
- void P_DamageMobj
- (
- mobj_t *target,
- mobj_t *inflictor,
- mobj_t *source,
- int damage
- )
- {
- unsigned ang;
- int saved;
- fixed_t savedPercent;
- player_t *player;
- mobj_t *master;
- fixed_t thrust;
- int temp;
- int i;
- if(!(target->flags&MF_SHOOTABLE))
- {
- // Shouldn't happen
- return;
- }
- if(target->health <= 0)
- {
- if (inflictor && inflictor->flags2&MF2_ICEDAMAGE)
- {
- return;
- }
- else if (target->flags&MF_ICECORPSE) // frozen
- {
- target->tics = 1;
- target->momx = target->momy = 0;
- }
- return;
- }
- if ((target->flags2&MF2_INVULNERABLE) && damage < 10000)
- { // mobj is invulnerable
- if(target->player) return; // for player, no exceptions
- if(inflictor)
- {
- switch(inflictor->type)
- {
- // These inflictors aren't foiled by invulnerability
- case MT_HOLY_FX:
- case MT_POISONCLOUD:
- case MT_FIREBOMB:
- break;
- default:
- return;
- }
- }
- else
- {
- return;
- }
- }
- if(target->player)
- {
- if(damage < 1000 && ((target->player->cheats&CF_GODMODE)
- || target->player->powers[pw_invulnerability]))
- {
- return;
- }
- }
- if(target->flags&MF_SKULLFLY)
- {
- target->momx = target->momy = target->momz = 0;
- }
- if(target->flags2&MF2_DORMANT)
- {
- // Invulnerable, and won't wake up
- return;
- }
- player = target->player;
- if(player && gameskill == sk_baby)
- {
- // Take half damage in trainer mode
- damage >>= 1;
- }
- // Special damage types
- if(inflictor)
- {
- switch(inflictor->type)
- {
- case MT_EGGFX:
- if(player)
- {
- P_MorphPlayer(player);
- }
- else
- {
- P_MorphMonster(target);
- }
- return; // Always return
- case MT_TELOTHER_FX1:
- case MT_TELOTHER_FX2:
- case MT_TELOTHER_FX3:
- case MT_TELOTHER_FX4:
- case MT_TELOTHER_FX5:
- if ((target->flags&MF_COUNTKILL) &&
- (target->type != MT_SERPENT) &&
- (target->type != MT_SERPENTLEADER) &&
- (!(target->flags2 & MF2_BOSS)))
- {
- P_TeleportOther(target);
- }
- return;
- case MT_MINOTAUR:
- if(inflictor->flags&MF_SKULLFLY)
- { // Slam only when in charge mode
- P_MinotaurSlam(inflictor, target);
- return;
- }
- break;
- case MT_BISH_FX:
- // Bishops are just too nasty
- damage >>= 1;
- break;
- case MT_SHARDFX1:
- switch(inflictor->special2)
- {
- case 3:
- damage <<= 3;
- break;
- case 2:
- damage <<= 2;
- break;
- case 1:
- damage <<= 1;
- break;
- default:
- break;
- }
- break;
- case MT_CSTAFF_MISSILE:
- // Cleric Serpent Staff does poison damage
- if(target->player)
- {
- P_PoisonPlayer(target->player, source, 20);
- damage >>= 1;
- }
- break;
- case MT_ICEGUY_FX2:
- damage >>= 1;
- break;
- case MT_POISONDART:
- if(target->player)
- {
- P_PoisonPlayer(target->player, source, 20);
- damage >>= 1;
- }
- break;
- case MT_POISONCLOUD:
- if(target->player)
- {
- if(target->player->poisoncount < 4)
- {
- P_PoisonDamage(target->player, source,
- 15+(P_Random()&15), false); // Don't play painsound
- P_PoisonPlayer(target->player, source, 50);
- S_StartSound(target, SFX_PLAYER_POISONCOUGH);
- }
- return;
- }
- else if(!(target->flags&MF_COUNTKILL))
- { // only damage monsters/players with the poison cloud
- return;
- }
- break;
- case MT_FSWORD_MISSILE:
- if(target->player)
- {
- damage -= damage>>2;
- }
- break;
- default:
- break;
- }
- }
- // Push the target unless source is using the gauntlets
- if(inflictor && (!source || !source->player)
- && !(inflictor->flags2&MF2_NODMGTHRUST))
- {
- ang = R_PointToAngle2(inflictor->x, inflictor->y,
- target->x, target->y);
- //thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
- thrust = damage*(FRACUNIT>>3)*150/target->info->mass;
- // make fall forwards sometimes
- if((damage < 40) && (damage > target->health)
- && (target->z-inflictor->z > 64*FRACUNIT) && (P_Random()&1))
- {
- ang += ANG180;
- thrust *= 4;
- }
- ang >>= ANGLETOFINESHIFT;
- target->momx += FixedMul(thrust, finecosine[ang]);
- target->momy += FixedMul(thrust, finesine[ang]);
- }
- //
- // player specific
- //
- if(player)
- {
- savedPercent = AutoArmorSave[player->class]
- +player->armorpoints[ARMOR_ARMOR]+player->armorpoints[ARMOR_SHIELD]
- +player->armorpoints[ARMOR_HELMET]
- +player->armorpoints[ARMOR_AMULET];
- if(savedPercent)
- { // armor absorbed some damage
- if(savedPercent > 100*FRACUNIT)
- {
- savedPercent = 100*FRACUNIT;
- }
- for(i = 0; i < NUMARMOR; i++)
- {
- if(player->armorpoints[i])
- {
- player->armorpoints[i] -=
- FixedDiv(FixedMul(damage<<FRACBITS,
- ArmorIncrement[player->class][i]), 300*FRACUNIT);
- if(player->armorpoints[i] < 2*FRACUNIT)
- {
- player->armorpoints[i] = 0;
- }
- }
- }
- saved = FixedDiv(FixedMul(damage<<FRACBITS, savedPercent),
- 100*FRACUNIT);
- if(saved > savedPercent*2)
- {
- saved = savedPercent*2;
- }
- damage -= saved>>FRACBITS;
- }
- if(damage >= player->health
- && ((gameskill == sk_baby) || deathmatch)
- && !player->morphTics)
- { // Try to use some inventory health
- P_AutoUseHealth(player, damage-player->health+1);
- }
- player->health -= damage; // mirror mobj health here for Dave
- if(player->health < 0)
- {
- player->health = 0;
- }
- player->attacker = source;
- player->damagecount += damage; // add damage after armor / invuln
- if(player->damagecount > 100)
- {
- player->damagecount = 100; // teleport stomp does 10k points...
- }
- temp = damage < 100 ? damage : 100;
- if(player == &players[consoleplayer])
- {
- I_Tactile(40, 10, 40+temp*2);
- SB_PaletteFlash(false);
- }
- }
- //
- // do the damage
- //
- target->health -= damage;
- if(target->health <= 0)
- { // Death
- if(inflictor)
- { // check for special fire damage or ice damage deaths
- if(inflictor->flags2&MF2_FIREDAMAGE)
- {
- if(player && !player->morphTics)
- { // Check for flame death
- if(target->health > -50 && damage > 25)
- {
- target->flags2 |= MF2_FIREDAMAGE;
- }
- }
- else
- {
- target->flags2 |= MF2_FIREDAMAGE;
- }
- }
- else if(inflictor->flags2&MF2_ICEDAMAGE)
- {
- target->flags2 |= MF2_ICEDAMAGE;
- }
- }
- if(source && (source->type == MT_MINOTAUR))
- { // Minotaur's kills go to his master
- master = (mobj_t *)(source->special1);
- // Make sure still alive and not a pointer to fighter head
- if (master->player && (master->player->mo == master))
- {
- source = master;
- }
- }
- if(source && (source->player) &&
- (source->player->readyweapon == WP_FOURTH))
- {
- // Always extreme death from fourth weapon
- target->health = -5000;
- }
- P_KillMobj(source, target);
- return;
- }
- if((P_Random() < target->info->painchance)
- && !(target->flags&MF_SKULLFLY))
- {
- if(inflictor && (inflictor->type >= MT_LIGHTNING_FLOOR
- && inflictor->type <= MT_LIGHTNING_ZAP))
- {
- if(P_Random() < 96)
- {
- target->flags |= MF_JUSTHIT; // fight back!
- P_SetMobjState(target, target->info->painstate);
- }
- else
- { // "electrocute" the target
- target->frame |= FF_FULLBRIGHT;
- if(target->flags&MF_COUNTKILL && P_Random() < 128
- && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
- {
- if ((target->type == MT_CENTAUR) ||
- (target->type == MT_CENTAURLEADER) ||
- (target->type == MT_ETTIN))
- {
- S_StartSound(target, SFX_PUPPYBEAT);
- }
- }
- }
- }
- else
- {
- target->flags |= MF_JUSTHIT; // fight back!
- P_SetMobjState(target, target->info->painstate);
- if(inflictor && inflictor->type == MT_POISONCLOUD)
- {
- if(target->flags&MF_COUNTKILL && P_Random() < 128
- && !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
- {
- if ((target->type == MT_CENTAUR) ||
- (target->type == MT_CENTAURLEADER) ||
- (target->type == MT_ETTIN))
- {
- S_StartSound(target, SFX_PUPPYBEAT);
- }
- }
- }
- }
- }
- target->reactiontime = 0; // we're awake now...
- if(!target->threshold && source && !(source->flags2&MF2_BOSS)
- && !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR))
- {
- // Target actor is not intent on another actor,
- // so make him chase after source
- if((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER)
- || (target->type == MT_CENTAURLEADER
- && source->type == MT_CENTAUR))
- {
- return;
- }
- target->target = source;
- target->threshold = BASETHRESHOLD;
- if(target->state == &states[target->info->spawnstate]
- && target->info->seestate != S_NULL)
- {
- P_SetMobjState(target, target->info->seestate);
- }
- }
- }
- //==========================================================================
- //
- // P_FallingDamage
- //
- //==========================================================================
- void P_FallingDamage(player_t *player)
- {
- int damage;
- int mom;
- int dist;
- mom = abs(player->mo->momz);
- dist = FixedMul(mom, 16*FRACUNIT/23);
- if(mom >= 63*FRACUNIT)
- { // automatic death
- P_DamageMobj(player->mo, NULL, NULL, 10000);
- return;
- }
- damage = ((FixedMul(dist, dist)/10)>>FRACBITS)-24;
- if(player->mo->momz > -39*FRACUNIT && damage > player->mo->health
- && player->mo->health != 1)
- { // No-death threshold
- damage = player->mo->health-1;
- }
- S_StartSound(player->mo, SFX_PLAYER_LAND);
- P_DamageMobj(player->mo, NULL, NULL, damage);
- }
- //==========================================================================
- //
- // P_PoisonPlayer - Sets up all data concerning poisoning
- //
- //==========================================================================
- void P_PoisonPlayer(player_t *player, mobj_t *poisoner, int poison)
- {
- if((player->cheats&CF_GODMODE) || player->powers[pw_invulnerability])
- {
- return;
- }
- player->poisoncount += poison;
- player->poisoner = poisoner;
- if(player->poisoncount > 100)
- {
- player->poisoncount = 100;
- }
- }
- //==========================================================================
- //
- // P_PoisonDamage - Similar to P_DamageMobj
- //
- //==========================================================================
- void P_PoisonDamage(player_t *player, mobj_t *source, int damage,
- boolean playPainSound)
- {
- mobj_t *target;
- mobj_t *inflictor;
- target = player->mo;
- inflictor = source;
- if(target->health <= 0)
- {
- return;
- }
- if(target->flags2&MF2_INVULNERABLE && damage < 10000)
- { // mobj is invulnerable
- return;
- }
- if(player && gameskill == sk_baby)
- {
- // Take half damage in trainer mode
- damage >>= 1;
- }
- if(damage < 1000 && ((player->cheats&CF_GODMODE)
- || player->powers[pw_invulnerability]))
- {
- return;
- }
- if(damage >= player->health
- && ((gameskill == sk_baby) || deathmatch)
- && !player->morphTics)
- { // Try to use some inventory health
- P_AutoUseHealth(player, damage-player->health+1);
- }
- player->health -= damage; // mirror mobj health here for Dave
- if(player->health < 0)
- {
- player->health = 0;
- }
- player->attacker = source;
- //
- // do the damage
- //
- target->health -= damage;
- if(target->health <= 0)
- { // Death
- target->special1 = damage;
- if(player && inflictor && !player->morphTics)
- { // Check for flame death
- if((inflictor->flags2&MF2_FIREDAMAGE)
- && (target->health > -50) && (damage > 25))
- {
- target->flags2 |= MF2_FIREDAMAGE;
- }
- if(inflictor->flags2&MF2_ICEDAMAGE)
- {
- target->flags2 |= MF2_ICEDAMAGE;
- }
- }
- P_KillMobj(source, target);
- return;
- }
- if(!(leveltime&63) && playPainSound)
- {
- P_SetMobjState(target, target->info->painstate);
- }
- /*
- if((P_Random() < target->info->painchance)
- && !(target->flags&MF_SKULLFLY))
- {
- target->flags |= MF_JUSTHIT; // fight back!
- P_SetMobjState(target, target->info->painstate);
- }
- */
- }
|