| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984 | /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- *///// Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.// All rights reserved.//// This file is part of SDLPAL.//// SDLPAL is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program.  If not, see <http://www.gnu.org/licenses/>.//// Modified by Lou Yihua <louyihua@21cn.com> with Unicode support, 2015//#include "main.h"#include <math.h>//#define INVINCIBLE 1static BOOLPAL_IsPlayerDying(   WORD        wPlayerRole)/*++  Purpose:    Check if the player is dying.  Parameters:    [IN]  wPlayerRole - the player role ID.  Return value:    TRUE if the player is dying, FALSE if not.--*/{   return gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] < gpGlobals->g.PlayerRoles.rgwMaxHP[wPlayerRole] / 5;}INTPAL_BattleSelectAutoTarget(   VOID)/*++  Purpose:    Pick an enemy target automatically.  Parameters:    None.  Return value:    The index of enemy. -1 if failed.--*/{   int          i;   i = (int)g_Battle.UI.wPrevEnemyTarget;   if (i >= 0 && i <= g_Battle.wMaxEnemyIndex &&      g_Battle.rgEnemy[i].wObjectID != 0 &&      g_Battle.rgEnemy[i].e.wHealth > 0)   {      return i;   }   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID != 0 &&         g_Battle.rgEnemy[i].e.wHealth > 0)      {         return i;      }   }   return -1;}static SHORTPAL_CalcBaseDamage(   WORD        wAttackStrength,   WORD        wDefense)/*++  Purpose:    Calculate the base damage value of attacking.  Parameters:    [IN]  wAttackStrength - attack strength of attacker.    [IN]  wDefense - defense value of inflictor.  Return value:    The base damage value of the attacking.--*/{   SHORT            sDamage;   //   // Formula courtesy of palxex and shenyanduxing   //   if (wAttackStrength > wDefense)   {      sDamage = (SHORT)(wAttackStrength * 2 - wDefense * 1.6 + 0.5);   }   else if (wAttackStrength > wDefense * 0.6)   {      sDamage = (SHORT)(wAttackStrength - wDefense * 0.6 + 0.5);   }   else   {      sDamage = 0;   }   return sDamage;}static SHORTPAL_CalcMagicDamage(   WORD             wMagicStrength,   WORD             wDefense,   const WORD       rgwElementalResistance[NUM_MAGIC_ELEMENTAL],   WORD             wPoisonResistance,   WORD             wMagicID)/*++   Purpose:     Calculate the damage of magic.   Parameters:     [IN]  wMagicStrength - magic strength of attacker.     [IN]  wDefense - defense value of inflictor.     [IN]  rgwElementalResistance - inflictor's resistance to the elemental magics.     [IN]  wPoisonResistance - inflictor's resistance to poison.     [IN]  wMagicID - object ID of the magic.   Return value:     The damage value of the magic attack.--*/{   SHORT           sDamage;   WORD            wElem;   wMagicID = gpGlobals->g.rgObject[wMagicID].magic.wMagicNumber;   //   // Formula courtesy of palxex and shenyanduxing   //   wMagicStrength *= RandomFloat(10, 11);   wMagicStrength /= 10;   sDamage = PAL_CalcBaseDamage(wMagicStrength, wDefense);   sDamage /= 4;   sDamage += gpGlobals->g.lprgMagic[wMagicID].wBaseDamage;   if (gpGlobals->g.lprgMagic[wMagicID].wElemental != 0)   {      wElem = gpGlobals->g.lprgMagic[wMagicID].wElemental;      if (wElem > NUM_MAGIC_ELEMENTAL)      {         sDamage *= 10 - wPoisonResistance;      }      else if (wElem == 0)      {         sDamage *= 5;      }      else      {         sDamage *= 10 - rgwElementalResistance[wElem - 1];      }      sDamage /= 5;      if (wElem <= NUM_MAGIC_ELEMENTAL)      {         sDamage *= 10 + gpGlobals->g.lprgBattleField[gpGlobals->wNumBattleField].rgsMagicEffect[wElem - 1];         sDamage /= 10;      }   }   return sDamage;}SHORTPAL_CalcPhysicalAttackDamage(   WORD           wAttackStrength,   WORD           wDefense,   WORD           wAttackResistance)/*++  Purpose:    Calculate the damage value of physical attacking.  Parameters:    [IN]  wAttackStrength - attack strength of attacker.    [IN]  wDefense - defense value of inflictor.    [IN]  wAttackResistance - inflictor's resistance to physical attack.  Return value:    The damage value of the physical attacking.--*/{   SHORT             sDamage;   sDamage = PAL_CalcBaseDamage(wAttackStrength, wDefense);   if (wAttackResistance != 0)   {      sDamage /= wAttackResistance;   }   return sDamage;}static SHORTPAL_GetEnemyDexterity(   WORD          wEnemyIndex)/*++  Purpose:    Get the dexterity value of the enemy.  Parameters:    [IN]  wEnemyIndex - the index of the enemy.  Return value:    The dexterity value of the enemy.--*/{   SHORT      s;   assert(g_Battle.rgEnemy[wEnemyIndex].wObjectID != 0);   s = (g_Battle.rgEnemy[wEnemyIndex].e.wLevel + 6) * 3;   s += (SHORT)g_Battle.rgEnemy[wEnemyIndex].e.wDexterity;#ifndef PAL_CLASSIC   if (s < 20)   {      s = 20;   }   if (g_Battle.rgEnemy[wEnemyIndex].rgwStatus[kStatusHaste] != 0)   {      s *= 6;      s /= 5;   }   else if (g_Battle.rgEnemy[wEnemyIndex].rgwStatus[kStatusSlow] != 0)   {      s *= 2;      s /= 3;   }#endif   return s;}static WORDPAL_GetPlayerActualDexterity(   WORD            wPlayerRole)/*++  Purpose:    Get player's actual dexterity value in battle.  Parameters:    [IN]  wPlayerRole - the player role ID.  Return value:    The player's actual dexterity value.--*/{   WORD wDexterity = PAL_GetPlayerDexterity(wPlayerRole);   if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusHaste] != 0)   {#ifdef PAL_CLASSIC      wDexterity *= 3;#else      wDexterity *= 6;      wDexterity /= 5;#endif   }#ifndef PAL_CLASSIC   else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSlow] != 0)   {      wDexterity *= 2;      wDexterity /= 3;   }#endif   if (PAL_IsPlayerDying(wPlayerRole))   {      //      // player who is low of HP should be slower      //#ifdef PAL_CLASSIC      wDexterity /= 2;#else      wDexterity *= 4;      wDexterity /= 5;#endif   }#ifdef PAL_CLASSIC   if (wDexterity > 999)   {      wDexterity = 999;   }#endif   return wDexterity;}#ifndef PAL_CLASSICVOIDPAL_UpdateTimeChargingUnit(   VOID)/*++  Purpose:    Update the base time unit of time-charging.  Parameters:    None.  Return value:    None.--*/{   g_Battle.flTimeChargingUnit = (FLOAT)(pow(PAL_GetPlayerDexterity(0) + 5, 0.3));   g_Battle.flTimeChargingUnit /= PAL_GetPlayerDexterity(0);   if (gpGlobals->bBattleSpeed > 1)   {      g_Battle.flTimeChargingUnit /= 1 + (gpGlobals->bBattleSpeed - 1) * 0.5;   }   else   {      g_Battle.flTimeChargingUnit /= 1.2f;   }}FLOATPAL_GetTimeChargingSpeed(   WORD           wDexterity)/*++  Purpose:    Calculate the time charging speed.  Parameters:    [IN]  wDexterity - the dexterity value of player or enemy.  Return value:    The time-charging speed of the player or enemy.--*/{   if ((g_Battle.UI.state == kBattleUISelectMove &&      g_Battle.UI.MenuState != kBattleMenuMain) ||      SDL_GetTicks() < g_Battle.UI.dwMsgShowTime)   {      //      // Pause the time when there are submenus or text messages      //      return 0;   }   //   // The battle should be faster when using Auto-Battle   //   if (gpGlobals->fAutoBattle)   {      wDexterity *= 3;   }   return g_Battle.flTimeChargingUnit * wDexterity;}#endifVOIDPAL_BattleDelay(   WORD       wDuration,   WORD       wObjectID,   BOOL       fUpdateGesture)/*++  Purpose:    Delay a while during battle.  Parameters:    [IN]  wDuration - Number of frames of the delay.    [IN]  wObjectID - The object ID to be displayed during the delay.    [IN]  fUpdateGesture - TRUE if update the gesture for enemies, FALSE if not.  Return value:    None.--*/{   int    i, j;   DWORD  dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME;   for (i = 0; i < wDuration; i++)   {      if (fUpdateGesture)      {         //         // Update the gesture of enemies.         //         for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)         {            if (g_Battle.rgEnemy[j].wObjectID == 0 ||               g_Battle.rgEnemy[j].rgwStatus[kStatusSleep] != 0 ||               g_Battle.rgEnemy[j].rgwStatus[kStatusParalyzed] != 0)            {               continue;            }            if (--g_Battle.rgEnemy[j].e.wIdleAnimSpeed == 0)            {               g_Battle.rgEnemy[j].wCurrentFrame++;               g_Battle.rgEnemy[j].e.wIdleAnimSpeed =                  gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[g_Battle.rgEnemy[j].wObjectID].enemy.wEnemyID].wIdleAnimSpeed;            }            if (g_Battle.rgEnemy[j].wCurrentFrame >= g_Battle.rgEnemy[j].e.wIdleFrames)            {               g_Battle.rgEnemy[j].wCurrentFrame = 0;            }         }      }      //      // Wait for the time of one frame. Accept input here.      //      PAL_ProcessEvent();      while (SDL_GetTicks() <= dwTime)      {         PAL_ProcessEvent();         SDL_Delay(1);      }      //      // Set the time of the next frame.      //      dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME;      PAL_BattleMakeScene();      SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);      PAL_BattleUIUpdate();      if (wObjectID != 0)      {         if (wObjectID == BATTLE_LABEL_ESCAPEFAIL) // HACKHACK         {            PAL_DrawText(PAL_GetWord(wObjectID), PAL_XY(130, 75),               15, TRUE, FALSE);         }         else if ((SHORT)wObjectID < 0)         {            PAL_DrawText(PAL_GetWord(-((SHORT)wObjectID)), PAL_XY(170, 45),               DESCTEXT_COLOR, TRUE, FALSE);         }         else         {            PAL_DrawText(PAL_GetWord(wObjectID), PAL_XY(210, 50),               15, TRUE, FALSE);         }      }      VIDEO_UpdateScreen(NULL);   }}static VOIDPAL_BattleBackupStat(   VOID)/*++  Purpose:    Backup HP and MP values of all players and enemies.  Parameters:    None.  Return value:    None.--*/{   int          i;   WORD         wPlayerRole;   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID == 0)      {         continue;      }      g_Battle.rgEnemy[i].wPrevHP = g_Battle.rgEnemy[i].e.wHealth;   }   for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)   {      wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;      g_Battle.rgPlayer[i].wPrevHP =         gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole];      g_Battle.rgPlayer[i].wPrevMP =         gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole];   }}static BOOLPAL_BattleDisplayStatChange(   VOID)/*++  Purpose:    Display the HP and MP changes of all players and enemies.  Parameters:    None.  Return value:    TRUE if there are any number displayed, FALSE if not.--*/{   int      i, x, y;   SHORT    sDamage;   WORD     wPlayerRole;   BOOL     f = FALSE;   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID == 0)      {         continue;      }      if (g_Battle.rgEnemy[i].wPrevHP != g_Battle.rgEnemy[i].e.wHealth)      {         //         // Show the number of damage         //         sDamage = g_Battle.rgEnemy[i].e.wHealth - g_Battle.rgEnemy[i].wPrevHP;         x = PAL_X(g_Battle.rgEnemy[i].pos) - 9;         y = PAL_Y(g_Battle.rgEnemy[i].pos) - 115;         if (y < 10)         {            y = 10;         }         if (sDamage < 0)         {            PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue);         }         else         {            PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorYellow);         }         f = TRUE;      }   }   for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)   {      wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;      if (g_Battle.rgPlayer[i].wPrevHP != gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole])      {         sDamage =            gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] - g_Battle.rgPlayer[i].wPrevHP;         x = PAL_X(g_Battle.rgPlayer[i].pos) - 9;         y = PAL_Y(g_Battle.rgPlayer[i].pos) - 75;         if (y < 10)         {            y = 10;         }         if (sDamage < 0)         {            PAL_BattleUIShowNum((WORD)(-sDamage), PAL_XY(x, y), kNumColorBlue);         }         else         {            PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorYellow);         }         f = TRUE;      }      if (g_Battle.rgPlayer[i].wPrevMP != gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole])      {         sDamage =            gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] - g_Battle.rgPlayer[i].wPrevMP;         x = PAL_X(g_Battle.rgPlayer[i].pos) - 9;         y = PAL_Y(g_Battle.rgPlayer[i].pos) - 67;         if (y < 10)         {            y = 10;         }         //         // Only show MP increasing         //         if (sDamage > 0)         {            PAL_BattleUIShowNum((WORD)(sDamage), PAL_XY(x, y), kNumColorCyan);         }         f = TRUE;      }   }   return f;}static VOIDPAL_BattlePostActionCheck(   BOOL      fCheckPlayers)/*++  Purpose:    Essential checks after an action is executed.  Parameters:    [IN]  fCheckPlayers - TRUE if check for players, FALSE if not.  Return value:    None.--*/{   int      i, j;   BOOL     fFade = FALSE;   BOOL     fEnemyRemaining = FALSE;   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID == 0)      {         continue;      }      if ((SHORT)(g_Battle.rgEnemy[i].e.wHealth) <= 0)      {         //         // This enemy is KO'ed         //         g_Battle.iExpGained += g_Battle.rgEnemy[i].e.wExp;         g_Battle.iCashGained += g_Battle.rgEnemy[i].e.wCash;         SOUND_Play(g_Battle.rgEnemy[i].e.wDeathSound);         g_Battle.rgEnemy[i].wObjectID = 0;         fFade = TRUE;         continue;      }      fEnemyRemaining = TRUE;   }   if (!fEnemyRemaining)   {      g_Battle.fEnemyCleared = TRUE;      g_Battle.UI.state = kBattleUIWait;   }   if (fCheckPlayers && !gpGlobals->fAutoBattle)   {      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         WORD w = gpGlobals->rgParty[i].wPlayerRole, wName;         if (gpGlobals->g.PlayerRoles.rgwHP[w] < g_Battle.rgPlayer[i].wPrevHP &&            gpGlobals->g.PlayerRoles.rgwHP[w] == 0)         {            w = gpGlobals->g.PlayerRoles.rgwCoveredBy[w];            for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)            {               if (gpGlobals->rgParty[j].wPlayerRole == w)               {                  break;               }            }            if (gpGlobals->g.PlayerRoles.rgwHP[w] > 0 &&               gpGlobals->rgPlayerStatus[w][kStatusSleep] == 0 &&               gpGlobals->rgPlayerStatus[w][kStatusParalyzed] == 0 &&               gpGlobals->rgPlayerStatus[w][kStatusConfused] == 0 &&               j <= gpGlobals->wMaxPartyMemberIndex)            {               wName = gpGlobals->g.PlayerRoles.rgwName[w];               if (gpGlobals->g.rgObject[wName].player.wScriptOnFriendDeath != 0)               {                  PAL_BattleDelay(10, 0, TRUE);                  PAL_BattleMakeScene();                  SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);                  VIDEO_UpdateScreen(NULL);                  g_Battle.BattleResult = kBattleResultPause;                  gpGlobals->g.rgObject[wName].player.wScriptOnFriendDeath =                     PAL_RunTriggerScript(gpGlobals->g.rgObject[wName].player.wScriptOnFriendDeath, w);                  g_Battle.BattleResult = kBattleResultOnGoing;                  PAL_ClearKeyState();                  goto end;               }            }         }      }      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         WORD w = gpGlobals->rgParty[i].wPlayerRole, wName;         if (gpGlobals->rgPlayerStatus[w][kStatusSleep] != 0 ||            gpGlobals->rgPlayerStatus[w][kStatusConfused] != 0)         {            continue;         }         if (gpGlobals->g.PlayerRoles.rgwHP[w] < g_Battle.rgPlayer[i].wPrevHP)         {            if (gpGlobals->g.PlayerRoles.rgwHP[w] > 0 && PAL_IsPlayerDying(w) &&               g_Battle.rgPlayer[i].wPrevHP >= gpGlobals->g.PlayerRoles.rgwMaxHP[w] / 5)            {               WORD wCover = gpGlobals->g.PlayerRoles.rgwCoveredBy[w];               if (gpGlobals->rgPlayerStatus[wCover][kStatusSleep] != 0 ||                  gpGlobals->rgPlayerStatus[wCover][kStatusParalyzed] != 0 ||                  gpGlobals->rgPlayerStatus[wCover][kStatusConfused] != 0)               {                  continue;               }               wName = gpGlobals->g.PlayerRoles.rgwName[w];               SOUND_Play(gpGlobals->g.PlayerRoles.rgwDyingSound[w]);               for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)               {                  if (gpGlobals->rgParty[j].wPlayerRole == wCover)                  {                     break;                  }               }               if (j > gpGlobals->wMaxPartyMemberIndex || gpGlobals->g.PlayerRoles.rgwHP[wCover] == 0)               {                  continue;               }               if (gpGlobals->g.rgObject[wName].player.wScriptOnDying != 0)               {                  PAL_BattleDelay(10, 0, TRUE);                  PAL_BattleMakeScene();                  SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);                  VIDEO_UpdateScreen(NULL);                  g_Battle.BattleResult = kBattleResultPause;                  gpGlobals->g.rgObject[wName].player.wScriptOnDying =                     PAL_RunTriggerScript(gpGlobals->g.rgObject[wName].player.wScriptOnDying, w);                  g_Battle.BattleResult = kBattleResultOnGoing;                  PAL_ClearKeyState();               }               goto end;            }         }      }   }end:   if (fFade)   {      PAL_BattleBackupScene();      PAL_BattleMakeScene();      PAL_BattleFadeScene();   }   //   // Fade out the summoned god   //   if (g_Battle.lpSummonSprite != NULL)   {      PAL_BattleUpdateFighters();      PAL_BattleDelay(1, 0, FALSE);      free(g_Battle.lpSummonSprite);      g_Battle.lpSummonSprite = NULL;      g_Battle.sBackgroundColorShift = 0;      PAL_BattleBackupScene();      PAL_BattleMakeScene();      PAL_BattleFadeScene();   }}VOIDPAL_BattleUpdateFighters(   VOID)/*++  Purpose:    Update players' and enemies' gestures and locations in battle.  Parameters:    None.  Return value:    None.--*/{   int        i;   WORD       wPlayerRole;   //   // Update the gesture for all players   //   for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)   {      wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;      g_Battle.rgPlayer[i].pos = g_Battle.rgPlayer[i].posOriginal;      g_Battle.rgPlayer[i].iColorShift = 0;      if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)      {         if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] == 0)         {            g_Battle.rgPlayer[i].wCurrentFrame = 2; // dead         }         else         {            g_Battle.rgPlayer[i].wCurrentFrame = 0; // puppet         }      }      else      {         if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] != 0 ||            PAL_IsPlayerDying(wPlayerRole))         {            g_Battle.rgPlayer[i].wCurrentFrame = 1;         }#ifndef PAL_CLASSIC         else if (g_Battle.rgPlayer[i].state == kFighterAct &&            g_Battle.rgPlayer[i].action.ActionType == kBattleActionMagic &&            !g_Battle.fEnemyCleared)         {            //            // Player is using a magic            //            g_Battle.rgPlayer[i].wCurrentFrame = 5;         }#endif         else if (g_Battle.rgPlayer[i].fDefending && !g_Battle.fEnemyCleared)         {            g_Battle.rgPlayer[i].wCurrentFrame = 3;         }         else         {            g_Battle.rgPlayer[i].wCurrentFrame = 0;         }      }   }   //   // Update the gesture for all enemies   //   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID == 0)      {         continue;      }      g_Battle.rgEnemy[i].pos = g_Battle.rgEnemy[i].posOriginal;      g_Battle.rgEnemy[i].iColorShift = 0;      if (g_Battle.rgEnemy[i].rgwStatus[kStatusSleep] > 0 ||         g_Battle.rgEnemy[i].rgwStatus[kStatusParalyzed] > 0)      {         g_Battle.rgEnemy[i].wCurrentFrame = 0;         continue;      }      if (--g_Battle.rgEnemy[i].e.wIdleAnimSpeed == 0)      {         g_Battle.rgEnemy[i].wCurrentFrame++;         g_Battle.rgEnemy[i].e.wIdleAnimSpeed =            gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[g_Battle.rgEnemy[i].wObjectID].enemy.wEnemyID].wIdleAnimSpeed;      }      if (g_Battle.rgEnemy[i].wCurrentFrame >= g_Battle.rgEnemy[i].e.wIdleFrames)      {         g_Battle.rgEnemy[i].wCurrentFrame = 0;      }   }}VOIDPAL_BattlePlayerCheckReady(   VOID)/*++  Purpose:    Check if there are player who is ready.  Parameters:    None.  Return value:    None.--*/{   float   flMax = 0;   int     iMax = 0, i;   //   // Start the UI for the fastest and ready player   //   for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)   {      if (g_Battle.rgPlayer[i].state == kFighterCom ||         (g_Battle.rgPlayer[i].state == kFighterAct && g_Battle.rgPlayer[i].action.ActionType == kBattleActionCoopMagic))      {         flMax = 0;         break;      }      else if (g_Battle.rgPlayer[i].state == kFighterWait)      {         if (g_Battle.rgPlayer[i].flTimeMeter > flMax)         {            iMax = i;            flMax = g_Battle.rgPlayer[i].flTimeMeter;         }      }   }   if (flMax >= 100.0f)   {      g_Battle.rgPlayer[iMax].state = kFighterCom;      g_Battle.rgPlayer[iMax].fDefending = FALSE;   }}VOIDPAL_BattleStartFrame(   VOID)/*++  Purpose:    Called once per video frame in battle.  Parameters:    None.  Return value:    None.--*/{   int                      i, j;   WORD                     wPlayerRole;   WORD                     wDexterity;   BOOL                     fOnlyPuppet = TRUE;#ifndef PAL_CLASSIC   FLOAT                    flMax;   BOOL                     fMoved = FALSE;   SHORT                    sMax, sMaxIndex;#endif   if (!g_Battle.fEnemyCleared)   {      PAL_BattleUpdateFighters();   }   //   // Update the scene   //   PAL_BattleMakeScene();   SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);   //   // Check if the battle is over   //   if (g_Battle.fEnemyCleared)   {      //      // All enemies are cleared. Won the battle.      //      g_Battle.BattleResult = kBattleResultWon;      SOUND_Play(-1);      return;   }   else   {      BOOL fEnded = TRUE;      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;         if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] != 0)         {            fOnlyPuppet = FALSE;            fEnded = FALSE;            break;         }         else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] != 0)         {            fEnded = FALSE;         }      }      if (fEnded)      {         //         // All players are dead. Lost the battle.         //         g_Battle.BattleResult = kBattleResultLost;         return;      }   }#ifndef PAL_CLASSIC   //   // Check for hiding status   //   if (g_Battle.iHidingTime > 0)   {      if (PAL_GetTimeChargingSpeed(9999) > 0)      {         g_Battle.iHidingTime--;      }      if (g_Battle.iHidingTime == 0)      {         PAL_BattleBackupScene();         PAL_BattleMakeScene();         PAL_BattleFadeScene();      }   }   //   // Run the logic for all enemies   //   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID == 0)      {         continue;      }      if (g_Battle.rgEnemy[i].fTurnStart)      {         g_Battle.rgEnemy[i].wScriptOnTurnStart =            PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnTurnStart, i);         g_Battle.rgEnemy[i].fTurnStart = FALSE;         fMoved = TRUE;      }   }   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      if (g_Battle.rgEnemy[i].wObjectID == 0)      {         continue;      }      switch (g_Battle.rgEnemy[i].state)      {      case kFighterWait:         flMax = PAL_GetTimeChargingSpeed(PAL_GetEnemyDexterity(i));         flMax /= (gpGlobals->fAutoBattle ? 2 : 1);         if (flMax != 0)         {            g_Battle.rgEnemy[i].flTimeMeter += flMax;            if (g_Battle.rgEnemy[i].flTimeMeter > 100 && flMax > 0)            {               if (g_Battle.iHidingTime == 0)               {                  g_Battle.rgEnemy[i].state = kFighterCom;               }               else               {                  g_Battle.rgEnemy[i].flTimeMeter = 0;               }            }         }         break;      case kFighterCom:         g_Battle.rgEnemy[i].wScriptOnReady =            PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnReady, i);         g_Battle.rgEnemy[i].state = kFighterAct;         fMoved = TRUE;         break;      case kFighterAct:         if (!fMoved && (PAL_GetTimeChargingSpeed(9999) > 0 || g_Battle.rgEnemy[i].fDualMove) && !fOnlyPuppet)         {            fMoved = TRUE;            g_Battle.fEnemyMoving = TRUE;            g_Battle.rgEnemy[i].fDualMove =               (!g_Battle.rgEnemy[i].fFirstMoveDone &&                  (g_Battle.rgEnemy[i].e.wDualMove >= 2 ||                     (g_Battle.rgEnemy[i].e.wDualMove != 0 && RandomLong(0, 1))));            PAL_BattleEnemyPerformAction(i);            g_Battle.rgEnemy[i].flTimeMeter = 0;            g_Battle.rgEnemy[i].state = kFighterWait;            g_Battle.fEnemyMoving = FALSE;            if (g_Battle.rgEnemy[i].fDualMove)            {               g_Battle.rgEnemy[i].flTimeMeter = 100;               g_Battle.rgEnemy[i].state = kFighterCom;               g_Battle.rgEnemy[i].fFirstMoveDone = TRUE;            }            else            {               g_Battle.rgEnemy[i].fFirstMoveDone = FALSE;               g_Battle.rgEnemy[i].fTurnStart = TRUE;            }         }         break;      }   }   //   // Update the battle UI   //   PAL_BattleUIUpdate();   //   // Run the logic for all players   //   for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)   {      wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;      //      // Skip dead players      //      if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 &&         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] == 0)      {         g_Battle.rgPlayer[i].state = kFighterWait;         g_Battle.rgPlayer[i].flTimeMeter = 0;         g_Battle.rgPlayer[i].flTimeSpeedModifier = 1.0f;         g_Battle.rgPlayer[i].sTurnOrder = -1;         continue;      }      switch (g_Battle.rgPlayer[i].state)      {      case kFighterWait:         wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole);         g_Battle.rgPlayer[i].flTimeMeter +=            PAL_GetTimeChargingSpeed(wDexterity) * g_Battle.rgPlayer[i].flTimeSpeedModifier;         break;      case kFighterCom:         break;      case kFighterAct:         if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] > 0)         {            g_Battle.rgPlayer[i].action.ActionType = kBattleActionPass;            g_Battle.rgPlayer[i].action.flRemainingTime = 0;         }         else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] > 0)         {            g_Battle.rgPlayer[i].action.ActionType = kBattleActionAttackMate;            g_Battle.rgPlayer[i].action.flRemainingTime = 0;         }         else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSilence] > 0 &&            g_Battle.rgPlayer[i].action.ActionType == kBattleActionMagic)         {            g_Battle.rgPlayer[i].action.flRemainingTime = 0;         }         wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole);         g_Battle.rgPlayer[i].action.flRemainingTime -= PAL_GetTimeChargingSpeed(wDexterity);         if (g_Battle.rgPlayer[i].action.flRemainingTime <= 0 &&            g_Battle.rgPlayer[i].sTurnOrder == -1)         {	        sMax = -1;	        for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)	        {		       if (g_Battle.rgPlayer[j].sTurnOrder > sMax)		       {			      sMax = g_Battle.rgPlayer[j].sTurnOrder;		       }	        }	        g_Battle.rgPlayer[i].sTurnOrder = sMax + 1;         }         break;      }   }   //   // Preform action for player   //   if (!fMoved)   {      sMax = 9999;      sMaxIndex = -1;      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;         //         // Skip dead players         //         if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 &&            gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] == 0)         {            continue;         }         if (g_Battle.rgPlayer[i].state == kFighterAct &&            g_Battle.rgPlayer[i].sTurnOrder != -1 &&            g_Battle.rgPlayer[i].sTurnOrder < sMax)         {	        sMax = g_Battle.rgPlayer[i].sTurnOrder;	        sMaxIndex = i;         }      }      if (sMaxIndex != -1)      {         //         // Perform the action for this player.         //         PAL_BattlePlayerPerformAction(sMaxIndex);         g_Battle.rgPlayer[sMaxIndex].flTimeMeter = 0;         g_Battle.rgPlayer[sMaxIndex].flTimeSpeedModifier = 1.0f;         g_Battle.rgPlayer[sMaxIndex].sTurnOrder = -1;      }   }#else   if (g_Battle.Phase == kBattlePhaseSelectAction)   {      if (g_Battle.UI.state == kBattleUIWait)      {         for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)         {            wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;            //            // Don't select action for this player if player is KO'ed,            // sleeped, confused or paralyzed            //            if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 ||               gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] ||               gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] ||               gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed])            {               continue;            }            //            // Start the menu for the first player whose action is not            // yet selected            //            if (g_Battle.rgPlayer[i].state == kFighterWait)            {               g_Battle.wMovingPlayerIndex = i;               g_Battle.rgPlayer[i].state = kFighterCom;               PAL_BattleUIPlayerReady(i);               break;            }            else if (g_Battle.rgPlayer[i].action.ActionType == kBattleActionCoopMagic)            {               //               // Skip other players if someone selected coopmagic               //               i = gpGlobals->wMaxPartyMemberIndex + 1;               break;            }         }         if (i > gpGlobals->wMaxPartyMemberIndex)         {            //            // actions for all players are decided. fill in the action queue.            //            g_Battle.fRepeat = FALSE;            g_Battle.fForce = FALSE;            g_Battle.fFlee = FALSE;            g_Battle.iCurAction = 0;            for (i = 0; i < MAX_ACTIONQUEUE_ITEMS; i++)            {               g_Battle.ActionQueue[i].wIndex = 0xFFFF;               g_Battle.ActionQueue[i].wDexterity = 0xFFFF;            }            j = 0;            //            // Put all enemies into action queue            //            for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)            {               if (g_Battle.rgEnemy[i].wObjectID == 0)               {                  continue;               }               g_Battle.ActionQueue[j].fIsEnemy = TRUE;               g_Battle.ActionQueue[j].wIndex = i;               g_Battle.ActionQueue[j].wDexterity = PAL_GetEnemyDexterity(i);               g_Battle.ActionQueue[j].wDexterity *= RandomFloat(0.9f, 1.1f);               j++;               if (g_Battle.rgEnemy[i].e.wDualMove * 50 + RandomLong(0, 100) > 100)               {                  g_Battle.ActionQueue[j].fIsEnemy = TRUE;                  g_Battle.ActionQueue[j].wIndex = i;                  g_Battle.ActionQueue[j].wDexterity = PAL_GetEnemyDexterity(i);                  g_Battle.ActionQueue[j].wDexterity *= RandomFloat(0.9f, 1.1f);                  j++;               }            }            //            // Put all players into action queue            //            for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)            {               wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;               g_Battle.ActionQueue[j].fIsEnemy = FALSE;               g_Battle.ActionQueue[j].wIndex = i;               if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0 ||                  gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] > 0 ||                  gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] > 0)               {                  //                  // players who are unable to move should attack physically if recovered                  // in the same turn                  //                  g_Battle.ActionQueue[j].wDexterity = 0;                  g_Battle.rgPlayer[i].action.ActionType = kBattleActionAttack;                  g_Battle.rgPlayer[i].state = kFighterAct;               }               else               {                  wDexterity = PAL_GetPlayerActualDexterity(wPlayerRole);                  if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] > 0)                  {                     g_Battle.rgPlayer[i].action.ActionType = kBattleActionAttack;                     g_Battle.rgPlayer[i].state = kFighterAct;                  }                  switch (g_Battle.rgPlayer[i].action.ActionType)                  {                  case kBattleActionCoopMagic:                     wDexterity *= 10;                     break;                  case kBattleActionDefend:                     wDexterity *= 5;                     break;                  case kBattleActionMagic:                     if ((gpGlobals->g.rgObject[g_Battle.rgPlayer[i].action.wActionID].magic.wFlags & kMagicFlagUsableToEnemy) == 0)                     {                        wDexterity *= 3;                     }                     break;                  case kBattleActionFlee:                     wDexterity /= 2;                     break;                  case kBattleActionUseItem:                     wDexterity *= 3;                     break;                  default:                     break;                  }                  if (PAL_IsPlayerDying(wPlayerRole))                  {                     wDexterity /= 2;                  }                  wDexterity *= RandomFloat(0.9f, 1.1f);                  g_Battle.ActionQueue[j].wDexterity = wDexterity;               }               j++;            }            //            // Sort the action queue by dexterity value            //            for (i = 0; i < MAX_ACTIONQUEUE_ITEMS; i++)            {               for (j = i; j < MAX_ACTIONQUEUE_ITEMS; j++)               {                  if ((SHORT)g_Battle.ActionQueue[i].wDexterity < (SHORT)g_Battle.ActionQueue[j].wDexterity)                  {                     ACTIONQUEUE t = g_Battle.ActionQueue[i];                     g_Battle.ActionQueue[i] = g_Battle.ActionQueue[j];                     g_Battle.ActionQueue[j] = t;                  }               }            }            //            // Perform the actions            //            g_Battle.Phase = kBattlePhasePerformAction;         }      }   }   else   {      //      // Are all actions finished?      //      if (g_Battle.iCurAction >= MAX_ACTIONQUEUE_ITEMS ||         g_Battle.ActionQueue[g_Battle.iCurAction].wDexterity == 0xFFFF)      {         for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)         {            g_Battle.rgPlayer[i].fDefending = FALSE;         }         //         // Run poison scripts         //         PAL_BattleBackupStat();         for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)         {            wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;            for (j = 0; j < MAX_POISONS; j++)            {               if (gpGlobals->rgPoisonStatus[j][i].wPoisonID != 0)               {                  gpGlobals->rgPoisonStatus[j][i].wPoisonScript =                     PAL_RunTriggerScript(gpGlobals->rgPoisonStatus[j][i].wPoisonScript, wPlayerRole);               }            }            //            // Update statuses            //            for (j = 0; j < kStatusAll; j++)            {               if (gpGlobals->rgPlayerStatus[wPlayerRole][j] > 0)               {                  gpGlobals->rgPlayerStatus[wPlayerRole][j]--;               }            }         }         for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)         {            for (j = 0; j < MAX_POISONS; j++)            {               if (g_Battle.rgEnemy[i].rgPoisons[j].wPoisonID != 0)               {                  g_Battle.rgEnemy[i].rgPoisons[j].wPoisonScript =                     PAL_RunTriggerScript(g_Battle.rgEnemy[i].rgPoisons[j].wPoisonScript, (WORD)i);               }            }            //            // Update statuses            //            for (j = 0; j < kStatusAll; j++)            {               if (g_Battle.rgEnemy[i].rgwStatus[j] > 0)               {                  g_Battle.rgEnemy[i].rgwStatus[j]--;               }            }         }         PAL_BattlePostActionCheck(FALSE);         if (PAL_BattleDisplayStatChange())         {            PAL_BattleDelay(8, 0, TRUE);         }         if (g_Battle.iHidingTime > 0)         {            if (--g_Battle.iHidingTime == 0)            {               PAL_BattleBackupScene();               PAL_BattleMakeScene();               PAL_BattleFadeScene();            }         }         if (g_Battle.iHidingTime == 0)         {            for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)            {               if (g_Battle.rgEnemy[i].wObjectID == 0)               {                  continue;               }               g_Battle.rgEnemy[i].wScriptOnTurnStart =                  PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnTurnStart, i);            }         }         //         // Clear all item-using records         //         for (i = 0; i < MAX_INVENTORY; i++)         {            gpGlobals->rgInventory[i].nAmountInUse = 0;         }         //         // Proceed to next turn...         //         g_Battle.Phase = kBattlePhaseSelectAction;      }      else      {         i = g_Battle.ActionQueue[g_Battle.iCurAction].wIndex;         if (g_Battle.ActionQueue[g_Battle.iCurAction].fIsEnemy)         {            if (g_Battle.iHidingTime == 0 && !fOnlyPuppet &&               g_Battle.rgEnemy[i].wObjectID != 0)            {               g_Battle.rgEnemy[i].wScriptOnReady =                  PAL_RunTriggerScript(g_Battle.rgEnemy[i].wScriptOnReady, i);               g_Battle.fEnemyMoving = TRUE;               PAL_BattleEnemyPerformAction(i);               g_Battle.fEnemyMoving = FALSE;            }         }         else if (g_Battle.rgPlayer[i].state == kFighterAct)         {            wPlayerRole = gpGlobals->rgParty[i].wPlayerRole;            if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)            {               if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusPuppet] == 0)               {                  g_Battle.rgPlayer[i].action.ActionType = kBattleActionPass;               }            }            else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] > 0 ||               gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] > 0)            {               g_Battle.rgPlayer[i].action.ActionType = kBattleActionPass;            }            else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] > 0)            {               g_Battle.rgPlayer[i].action.ActionType = kBattleActionAttackMate;            }            //            // Perform the action for this player.            //            g_Battle.wMovingPlayerIndex = i;            PAL_BattlePlayerPerformAction(i);         }         g_Battle.iCurAction++;      }   }   //   // The R and F keys and Fleeing should affect all players   //   if (g_Battle.UI.MenuState == kBattleMenuMain &&      g_Battle.UI.state == kBattleUISelectMove)   {      if (g_InputState.dwKeyPress & kKeyRepeat)      {         g_Battle.fRepeat = TRUE;      }      else if (g_InputState.dwKeyPress & kKeyForce)      {         g_Battle.fForce = TRUE;      }   }   if (g_Battle.fRepeat)   {      g_InputState.dwKeyPress = kKeyRepeat;   }   else if (g_Battle.fForce)   {      g_InputState.dwKeyPress = kKeyForce;   }   else if (g_Battle.fFlee)   {      g_InputState.dwKeyPress = kKeyFlee;   }   //   // Update the battle UI   //   PAL_BattleUIUpdate();#endif}VOIDPAL_BattleCommitAction(   BOOL           fRepeat)/*++  Purpose:    Commit the action which the player decided.  Parameters:    [IN]  fRepeat - TRUE if repeat the last action.  Return value:    None.--*/{   WORD      w;   if (!fRepeat)   {      g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType =         g_Battle.UI.wActionType;      g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.sTarget =         (SHORT)g_Battle.UI.wSelectedIndex;      g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID =         g_Battle.UI.wObjectID;   }   else if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType == kBattleActionPass)   {      g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType = kBattleActionAttack;      g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.sTarget = -1;   }   //   // Check if the action is valid   //   switch (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType)   {   case kBattleActionMagic:      w = g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID;      w = gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[w].magic.wMagicNumber].wCostMP;      if (gpGlobals->g.PlayerRoles.rgwMP[gpGlobals->rgParty[g_Battle.UI.wCurPlayerIndex].wPlayerRole] < w)      {         w = g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID;         w = gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[w].magic.wMagicNumber].wType;         if (w == kMagicTypeApplyToPlayer || w == kMagicTypeApplyToParty ||            w == kMagicTypeTrance)         {            g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType = kBattleActionDefend;         }         else         {            g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType = kBattleActionAttack;            if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.sTarget == -1)            {               g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.sTarget = 0;            }         }      }      break;#ifdef PAL_CLASSIC   case kBattleActionUseItem:      if ((gpGlobals->g.rgObject[g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID].item.wFlags & kItemFlagConsuming) == 0)      {         break;      }   case kBattleActionThrowItem:      for (w = 0; w < MAX_INVENTORY; w++)      {         if (gpGlobals->rgInventory[w].wItem == g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID)         {            gpGlobals->rgInventory[w].nAmountInUse++;            break;         }      }      break;#endif   default:      break;   }#ifndef PAL_CLASSIC   //   // Calculate the waiting time for the action   //   switch (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.ActionType)   {   case kBattleActionMagic:      {         LPMAGIC      p;         WORD         wCostMP;         //         // The base casting time of magic is set to the MP costed         //         w = g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.wActionID;         p = &(gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[w].magic.wMagicNumber]);         wCostMP = p->wCostMP;         if (wCostMP == 1)         {            if (p->wType == kMagicTypeSummon)            {               //               // The Wine God is an ultimate move which should take long               //               wCostMP = 175;            }         }         else if (p->wType == kMagicTypeApplyToPlayer || p->wType == kMagicTypeApplyToParty ||            p->wType == kMagicTypeTrance)         {            //            // Healing magics should take shorter            //            wCostMP /= 3;         }         g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.flRemainingTime = wCostMP + 5;      }      break;   case kBattleActionAttack:   case kBattleActionFlee:   case kBattleActionUseItem:   case kBattleActionThrowItem:   default:      //      // Other actions take no time      //      g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.flRemainingTime = 0;      break;   }#else   if (g_Battle.UI.wActionType == kBattleActionFlee)   {      g_Battle.fFlee = TRUE;   }#endif   g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].state = kFighterAct;   g_Battle.UI.state = kBattleUIWait;#ifndef PAL_CLASSIC   if (g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].action.flRemainingTime <= 0)   {	  SHORT sMax = -1;	  for (w = 0; w <= gpGlobals->wMaxPartyMemberIndex; w++)	  {		 if (g_Battle.rgPlayer[w].sTurnOrder > sMax)		 {			sMax = g_Battle.rgPlayer[w].sTurnOrder;		 }	  }	  g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].sTurnOrder = sMax + 1;   }   else   {	  g_Battle.rgPlayer[g_Battle.UI.wCurPlayerIndex].sTurnOrder = -1;   }#endif}static VOIDPAL_BattleShowPlayerAttackAnim(   WORD        wPlayerIndex,   BOOL        fCritical)/*++  Purpose:    Show the physical attack effect for player.  Parameters:    [IN]  wPlayerIndex - the index of the player.    [IN]  fCritical - TRUE if this is a critical hit.  Return value:    None.--*/{   WORD wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole;   SHORT sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget;   int index, i, j;   int enemy_x = 0, enemy_y = 0, enemy_h = 0, x, y, dist = 0;   DWORD dwTime;   if (sTarget != -1)   {      enemy_x = PAL_X(g_Battle.rgEnemy[sTarget].pos);      enemy_y = PAL_Y(g_Battle.rgEnemy[sTarget].pos);      enemy_h = PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[sTarget].lpSprite, g_Battle.rgEnemy[sTarget].wCurrentFrame));      if (sTarget >= 3)      {         dist = (sTarget - wPlayerIndex) * 8;      }   }   else   {      enemy_x = 150;      enemy_y = 100;   }   index = gpGlobals->g.rgwBattleEffectIndex[PAL_GetPlayerBattleSprite(wPlayerRole)][1];   index *= 3;   //   // Play the attack voice   //   if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] > 0)   {      if (!fCritical)      {         SOUND_Play(gpGlobals->g.PlayerRoles.rgwAttackSound[wPlayerRole]);      }      else      {         SOUND_Play(gpGlobals->g.PlayerRoles.rgwCriticalSound[wPlayerRole]);      }   }   //   // Show the animation   //   x = enemy_x - dist + 64;   y = enemy_y + dist + 20;   g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 8;   g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x, y);   PAL_BattleDelay(2, 0, TRUE);   x -= 10;   y -= 2;   g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x, y);   PAL_BattleDelay(1, 0, TRUE);   g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 9;   x -= 16;   y -= 4;   SOUND_Play(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]);   x = enemy_x;   y = enemy_y - enemy_h / 3 + 10;   dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME;   for (i = 0; i < 3; i++)   {      LPCBITMAPRLE b = PAL_SpriteGetFrame(g_Battle.lpEffectSprite, index++);      //      // Wait for the time of one frame. Accept input here.      //      PAL_ProcessEvent();      while (SDL_GetTicks() <= dwTime)      {         PAL_ProcessEvent();         SDL_Delay(1);      }      //      // Set the time of the next frame.      //      dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME;      //      // Update the gesture of enemies.      //      for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)      {         if (g_Battle.rgEnemy[j].wObjectID == 0 ||            g_Battle.rgEnemy[j].rgwStatus[kStatusSleep] > 0 ||            g_Battle.rgEnemy[j].rgwStatus[kStatusParalyzed] > 0)         {            continue;         }         if (--g_Battle.rgEnemy[j].e.wIdleAnimSpeed == 0)         {            g_Battle.rgEnemy[j].wCurrentFrame++;            g_Battle.rgEnemy[j].e.wIdleAnimSpeed =               gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[g_Battle.rgEnemy[j].wObjectID].enemy.wEnemyID].wIdleAnimSpeed;         }         if (g_Battle.rgEnemy[j].wCurrentFrame >= g_Battle.rgEnemy[j].e.wIdleFrames)         {            g_Battle.rgEnemy[j].wCurrentFrame = 0;         }      }      PAL_BattleMakeScene();      SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);      PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));      x -= 16;      y += 16;      PAL_BattleUIUpdate();      if (i == 0)      {         if (sTarget == -1)         {            for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)            {               g_Battle.rgEnemy[j].iColorShift = 6;            }         }         else         {            g_Battle.rgEnemy[sTarget].iColorShift = 6;         }         PAL_BattleDisplayStatChange();         PAL_BattleBackupStat();      }      VIDEO_UpdateScreen(NULL);      if (i == 1)      {         g_Battle.rgPlayer[wPlayerIndex].pos =            PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) + 2,                   PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) + 1);      }   }   dist = 8;   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      g_Battle.rgEnemy[i].iColorShift = 0;   }   if (sTarget == -1)   {      for (i = 0; i < 3; i++)      {         for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)         {            x = PAL_X(g_Battle.rgEnemy[j].pos);            y = PAL_Y(g_Battle.rgEnemy[j].pos);            x -= dist;            y -= dist / 2;            g_Battle.rgEnemy[j].pos = PAL_XY(x, y);         }         PAL_BattleDelay(1, 0, TRUE);         dist /= -2;      }   }   else   {      x = PAL_X(g_Battle.rgEnemy[sTarget].pos);      y = PAL_Y(g_Battle.rgEnemy[sTarget].pos);      for (i = 0; i < 3; i++)      {         x -= dist;         dist /= -2;         y += dist;         g_Battle.rgEnemy[sTarget].pos = PAL_XY(x, y);         PAL_BattleDelay(1, 0, TRUE);      }   }}static VOIDPAL_BattleShowPlayerUseItemAnim(   WORD         wPlayerIndex,   WORD         wObjectID,   SHORT        sTarget)/*++  Purpose:    Show the "use item" effect for player.  Parameters:    [IN]  wPlayerIndex - the index of the player.    [IN]  wObjectID - the object ID of the item to be used.    [IN]  sTarget - the target player of the action.  Return value:    None.--*/{   int i, j;   PAL_BattleDelay(4, 0, TRUE);   g_Battle.rgPlayer[wPlayerIndex].pos =      PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) - 15,             PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) - 7);   g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;   SOUND_Play(28);   for (i = 0; i <= 6; i++)   {      if (sTarget == -1)      {         for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)         {            g_Battle.rgPlayer[j].iColorShift = i;         }      }      else      {         g_Battle.rgPlayer[sTarget].iColorShift = i;      }      PAL_BattleDelay(1, wObjectID, TRUE);   }   for (i = 5; i >= 0; i--)   {      if (sTarget == -1)      {         for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)         {            g_Battle.rgPlayer[j].iColorShift = i;         }      }      else      {         g_Battle.rgPlayer[sTarget].iColorShift = i;      }      PAL_BattleDelay(1, wObjectID, TRUE);   }}VOIDPAL_BattleShowPlayerPreMagicAnim(   WORD         wPlayerIndex,   BOOL         fSummon)/*++  Purpose:    Show the effect for player before using a magic.  Parameters:    [IN]  wPlayerIndex - the index of the player.    [IN]  fSummon - TRUE if player is using a summon magic.  Return value:    None.--*/{   int   i, j;   DWORD dwTime = SDL_GetTicks();   WORD  wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole;   for (i = 0; i < 4; i++)   {      g_Battle.rgPlayer[wPlayerIndex].pos =         PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) - (4 - i),                PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) - (4 - i) / 2);      PAL_BattleDelay(1, 0, TRUE);   }   PAL_BattleDelay(2, 0, TRUE);   g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;   if (!gpGlobals->fIsWIN95)   {      SOUND_Play(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);   }   if (!fSummon)   {      int x, y, index;      x = PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos);      y = PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos);      index = gpGlobals->g.rgwBattleEffectIndex[PAL_GetPlayerBattleSprite(wPlayerRole)][0];      index *= 10;      index += 15;	  if (gpGlobals->fIsWIN95)	  {		  SOUND_Play(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);	  }	  for (i = 0; i < 10; i++)      {         LPCBITMAPRLE b = PAL_SpriteGetFrame(g_Battle.lpEffectSprite, index++);         //         // Wait for the time of one frame. Accept input here.         //         PAL_ProcessEvent();         while (SDL_GetTicks() <= dwTime)         {            PAL_ProcessEvent();            SDL_Delay(1);         }         //         // Set the time of the next frame.         //         dwTime = SDL_GetTicks() + BATTLE_FRAME_TIME;         //         // Update the gesture of enemies.         //         for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)         {            if (g_Battle.rgEnemy[j].wObjectID == 0 ||               g_Battle.rgEnemy[j].rgwStatus[kStatusSleep] != 0 ||               g_Battle.rgEnemy[j].rgwStatus[kStatusParalyzed] != 0)            {               continue;            }            if (--g_Battle.rgEnemy[j].e.wIdleAnimSpeed == 0)            {               g_Battle.rgEnemy[j].wCurrentFrame++;               g_Battle.rgEnemy[j].e.wIdleAnimSpeed =                  gpGlobals->g.lprgEnemy[gpGlobals->g.rgObject[g_Battle.rgEnemy[j].wObjectID].enemy.wEnemyID].wIdleAnimSpeed;            }            if (g_Battle.rgEnemy[j].wCurrentFrame >= g_Battle.rgEnemy[j].e.wIdleFrames)            {               g_Battle.rgEnemy[j].wCurrentFrame = 0;            }         }         PAL_BattleMakeScene();         SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);         PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         PAL_BattleUIUpdate();         VIDEO_UpdateScreen(NULL);      }   }   PAL_BattleDelay(1, 0, TRUE);}static VOIDPAL_BattleShowPlayerDefMagicAnim(   WORD         wPlayerIndex,   WORD         wObjectID,   SHORT        sTarget)/*++  Purpose:    Show the defensive magic effect for player.  Parameters:    [IN]  wPlayerIndex - the index of the player.    [IN]  wObjectID - the object ID of the magic to be used.    [IN]  sTarget - the target player of the action.  Return value:    None.--*/{   LPSPRITE   lpSpriteEffect;   int        l, iMagicNum, iEffectNum, n, i, j, x, y;   DWORD      dwTime = SDL_GetTicks();   iMagicNum = gpGlobals->g.rgObject[wObjectID].magic.wMagicNumber;   iEffectNum = gpGlobals->g.lprgMagic[iMagicNum].wEffect;   l = PAL_MKFGetDecompressedSize(iEffectNum, gpGlobals->f.fpFIRE);   if (l <= 0)   {      return;   }   lpSpriteEffect = (LPSPRITE)UTIL_malloc(l);   PAL_MKFDecompressChunk((LPBYTE)lpSpriteEffect, l, iEffectNum, gpGlobals->f.fpFIRE);   n = PAL_SpriteGetNumFrames(lpSpriteEffect);   g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 6;   PAL_BattleDelay(1, 0, TRUE);   for (i = 0; i < n; i++)   {      LPCBITMAPRLE b = PAL_SpriteGetFrame(lpSpriteEffect, i);      if (i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay)      {         SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);      }      //      // Wait for the time of one frame. Accept input here.      //      PAL_ProcessEvent();      while (SDL_GetTicks() <= dwTime)      {         PAL_ProcessEvent();         SDL_Delay(1);      }      //      // Set the time of the next frame.      //      dwTime = SDL_GetTicks() +         ((SHORT)(gpGlobals->g.lprgMagic[iMagicNum].wSpeed) + 5) * 10;      PAL_BattleMakeScene();      SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);      if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeApplyToParty)      {         assert(sTarget == -1);         for (l = 0; l <= gpGlobals->wMaxPartyMemberIndex; l++)         {            x = PAL_X(g_Battle.rgPlayer[l].pos);            y = PAL_Y(g_Battle.rgPlayer[l].pos);            x += (SHORT) gpGlobals->g.lprgMagic[iMagicNum].wXOffset;            y += (SHORT) gpGlobals->g.lprgMagic[iMagicNum].wYOffset;            PAL_RLEBlitToSurface(b, gpScreen,               PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         }      }      else if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeApplyToPlayer)      {         assert(sTarget != -1);         x = PAL_X(g_Battle.rgPlayer[sTarget].pos);         y = PAL_Y(g_Battle.rgPlayer[sTarget].pos);         x += (SHORT) gpGlobals->g.lprgMagic[iMagicNum].wXOffset;         y += (SHORT) gpGlobals->g.lprgMagic[iMagicNum].wYOffset;         PAL_RLEBlitToSurface(b, gpScreen,            PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         //         // Repaint the previous player         //         if (sTarget > 0 && g_Battle.iHidingTime == 0)         {            if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[sTarget - 1].wPlayerRole][kStatusConfused] == 0)            {               LPCBITMAPRLE p = PAL_SpriteGetFrame(g_Battle.rgPlayer[sTarget - 1].lpSprite, g_Battle.rgPlayer[sTarget - 1].wCurrentFrame);               x = PAL_X(g_Battle.rgPlayer[sTarget - 1].pos);               y = PAL_Y(g_Battle.rgPlayer[sTarget - 1].pos);               x -= PAL_RLEGetWidth(p) / 2;               y -= PAL_RLEGetHeight(p);               PAL_RLEBlitToSurface(p, gpScreen, PAL_XY(x, y));            }         }      }      else      {         assert(FALSE);      }      PAL_BattleUIUpdate();      VIDEO_UpdateScreen(NULL);   }   free(lpSpriteEffect);   for (i = 0; i < 6; i++)   {      if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeApplyToParty)      {         for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)         {            g_Battle.rgPlayer[j].iColorShift = i;         }      }      else      {         g_Battle.rgPlayer[sTarget].iColorShift = i;      }      PAL_BattleDelay(1, 0, TRUE);   }   for (i = 6; i >= 0; i--)   {      if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeApplyToParty)      {         for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)         {            g_Battle.rgPlayer[j].iColorShift = i;         }      }      else      {         g_Battle.rgPlayer[sTarget].iColorShift = i;      }      PAL_BattleDelay(1, 0, TRUE);   }}static VOIDPAL_BattleShowPlayerOffMagicAnim(   WORD         wPlayerIndex,   WORD         wObjectID,   SHORT        sTarget,   BOOL         fSummon)/*++  Purpose:    Show the offensive magic animation for player.  Parameters:    [IN]  wPlayerIndex - the index of the player.    [IN]  wObjectID - the object ID of the magic to be used.    [IN]  sTarget - the target enemy of the action.  Return value:    None.--*/{   LPSPRITE   lpSpriteEffect;   int        l, iMagicNum, iEffectNum, n, i, k, x, y, wave, blow;   DWORD      dwTime = SDL_GetTicks();   iMagicNum = gpGlobals->g.rgObject[wObjectID].magic.wMagicNumber;   iEffectNum = gpGlobals->g.lprgMagic[iMagicNum].wEffect;   l = PAL_MKFGetDecompressedSize(iEffectNum, gpGlobals->f.fpFIRE);   if (l <= 0)   {      return;   }   lpSpriteEffect = (LPSPRITE)UTIL_malloc(l);   PAL_MKFDecompressChunk((LPBYTE)lpSpriteEffect, l, iEffectNum, gpGlobals->f.fpFIRE);   n = PAL_SpriteGetNumFrames(lpSpriteEffect);   if (gpGlobals->fIsWIN95 && wPlayerIndex != (WORD)-1)   {      g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 6;   }   PAL_BattleDelay(1, 0, TRUE);   l = n - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;   l *= (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wEffectTimes;   l += n;   l += gpGlobals->g.lprgMagic[iMagicNum].wShake;   wave = gpGlobals->wScreenWave;   gpGlobals->wScreenWave += gpGlobals->g.lprgMagic[iMagicNum].wWave;   if (gpGlobals->fIsWIN95 && !fSummon && gpGlobals->g.lprgMagic[iMagicNum].wSound != 0)   {      SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);   }   for (i = 0; i < l; i++)   {      LPCBITMAPRLE b;	  if (!gpGlobals->fIsWIN95 && i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay && wPlayerIndex != (WORD)-1)      {         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 6;      }      blow = ((g_Battle.iBlow > 0) ? RandomLong(0, g_Battle.iBlow) : RandomLong(g_Battle.iBlow, 0));      for (k = 0; k <= g_Battle.wMaxEnemyIndex; k++)      {         if (g_Battle.rgEnemy[k].wObjectID == 0)         {            continue;         }         x = PAL_X(g_Battle.rgEnemy[k].pos) + blow;         y = PAL_Y(g_Battle.rgEnemy[k].pos) + blow / 2;         g_Battle.rgEnemy[k].pos = PAL_XY(x, y);      }      if (l - i > gpGlobals->g.lprgMagic[iMagicNum].wShake)      {         if (i < n)         {            k = i;         }         else         {            k = i - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;            k %= n - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;            k += gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;         }         b = PAL_SpriteGetFrame(lpSpriteEffect, k);		 if (!gpGlobals->fIsWIN95 && (i - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay) % n == 0)         {            SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);         }      }      else      {         VIDEO_ShakeScreen(i, 3);         b = PAL_SpriteGetFrame(lpSpriteEffect, (l - gpGlobals->g.lprgMagic[iMagicNum].wShake - 1) % n);      }      //      // Wait for the time of one frame. Accept input here.      //      PAL_ProcessEvent();      while (SDL_GetTicks() <= dwTime)      {         PAL_ProcessEvent();         SDL_Delay(1);      }      //      // Set the time of the next frame.      //      dwTime = SDL_GetTicks() +         ((SHORT)(gpGlobals->g.lprgMagic[iMagicNum].wSpeed) + 5) * 10;      PAL_BattleMakeScene();      SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);      if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeNormal)      {         assert(sTarget != -1);         x = PAL_X(g_Battle.rgEnemy[sTarget].pos);         y = PAL_Y(g_Battle.rgEnemy[sTarget].pos);         x += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wXOffset;         y += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wYOffset;         PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         if (i == l - 1 && gpGlobals->wScreenWave < 9 &&            gpGlobals->g.lprgMagic[iMagicNum].wKeepEffect == 0xFFFF)         {            PAL_RLEBlitToSurface(b, g_Battle.lpBackground,               PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         }      }      else if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackAll)      {         const int effectpos[3][2] = {{70, 140}, {100, 110}, {160, 100}};         assert(sTarget == -1);         for (k = 0; k < 3; k++)         {            x = effectpos[k][0];            y = effectpos[k][1];            x += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wXOffset;            y += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wYOffset;            PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));            if (i == l - 1 && gpGlobals->wScreenWave < 9 &&               gpGlobals->g.lprgMagic[iMagicNum].wKeepEffect == 0xFFFF)            {               PAL_RLEBlitToSurface(b, g_Battle.lpBackground,                  PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));            }         }      }      else if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackWhole ||         gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackField)      {         assert(sTarget == -1);         if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackWhole)         {            x = 120;            y = 100;         }         else         {            x = 160;            y = 200;         }         x += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wXOffset;         y += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wYOffset;         PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         if (i == l - 1 && gpGlobals->wScreenWave < 9 &&            gpGlobals->g.lprgMagic[iMagicNum].wKeepEffect == 0xFFFF)         {            PAL_RLEBlitToSurface(b, g_Battle.lpBackground,               PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         }      }      else      {         assert(FALSE);      }      PAL_BattleUIUpdate();      VIDEO_UpdateScreen(NULL);   }   gpGlobals->wScreenWave = wave;   VIDEO_ShakeScreen(0, 0);   free(lpSpriteEffect);   for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)   {      g_Battle.rgEnemy[i].pos = g_Battle.rgEnemy[i].posOriginal;   }}static VOIDPAL_BattleShowEnemyMagicAnim(   WORD         wObjectID,   SHORT        sTarget)/*++  Purpose:    Show the offensive magic animation for enemy.  Parameters:    [IN]  wObjectID - the object ID of the magic to be used.    [IN]  sTarget - the target player index of the action.  Return value:    None.--*/{   LPSPRITE   lpSpriteEffect;   int        l, iMagicNum, iEffectNum, n, i, k, x, y, wave, blow;   DWORD      dwTime = SDL_GetTicks();   iMagicNum = gpGlobals->g.rgObject[wObjectID].magic.wMagicNumber;   iEffectNum = gpGlobals->g.lprgMagic[iMagicNum].wEffect;   l = PAL_MKFGetDecompressedSize(iEffectNum, gpGlobals->f.fpFIRE);   if (l <= 0)   {      return;   }   lpSpriteEffect = (LPSPRITE)UTIL_malloc(l);   PAL_MKFDecompressChunk((LPBYTE)lpSpriteEffect, l, iEffectNum, gpGlobals->f.fpFIRE);   n = PAL_SpriteGetNumFrames(lpSpriteEffect);   l = n - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;   l *= (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wEffectTimes;   l += n;   l += gpGlobals->g.lprgMagic[iMagicNum].wShake;   wave = gpGlobals->wScreenWave;   gpGlobals->wScreenWave += gpGlobals->g.lprgMagic[iMagicNum].wWave;   for (i = 0; i < l; i++)   {      LPCBITMAPRLE b;      blow = ((g_Battle.iBlow > 0) ? RandomLong(0, g_Battle.iBlow) : RandomLong(g_Battle.iBlow, 0));      for (k = 0; k <= gpGlobals->wMaxPartyMemberIndex; k++)      {         x = PAL_X(g_Battle.rgPlayer[k].pos) + blow;         y = PAL_Y(g_Battle.rgPlayer[k].pos) + blow / 2;         g_Battle.rgPlayer[k].pos = PAL_XY(x, y);      }      if (l - i > gpGlobals->g.lprgMagic[iMagicNum].wShake)      {         if (i < n)         {            k = i;         }         else         {            k = i - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;            k %= n - gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;            k += gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay;         }         b = PAL_SpriteGetFrame(lpSpriteEffect, k);         if (i == gpGlobals->g.lprgMagic[iMagicNum].wSoundDelay)         {            SOUND_Play(gpGlobals->g.lprgMagic[iMagicNum].wSound);         }      }      else      {         VIDEO_ShakeScreen(i, 3);         b = PAL_SpriteGetFrame(lpSpriteEffect, (l - gpGlobals->g.lprgMagic[iMagicNum].wShake - 1) % n);      }      //      // Wait for the time of one frame. Accept input here.      //      PAL_ProcessEvent();      while (SDL_GetTicks() <= dwTime)      {         PAL_ProcessEvent();         SDL_Delay(1);      }      //      // Set the time of the next frame.      //      dwTime = SDL_GetTicks() +         ((SHORT)(gpGlobals->g.lprgMagic[iMagicNum].wSpeed) + 5) * 10;      PAL_BattleMakeScene();      SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);      if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeNormal)      {         assert(sTarget != -1);         x = PAL_X(g_Battle.rgPlayer[sTarget].pos);         y = PAL_Y(g_Battle.rgPlayer[sTarget].pos);         x += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wXOffset;         y += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wYOffset;         PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         if (i == l - 1 && gpGlobals->wScreenWave < 9 &&            gpGlobals->g.lprgMagic[iMagicNum].wKeepEffect == 0xFFFF)         {            PAL_RLEBlitToSurface(b, g_Battle.lpBackground,               PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         }      }      else if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackAll)      {         const int effectpos[3][2] = {{180, 180}, {234, 170}, {270, 146}};         assert(sTarget == -1);         for (k = 0; k < 3; k++)         {            x = effectpos[k][0];            y = effectpos[k][1];            x += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wXOffset;            y += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wYOffset;            PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));            if (i == l - 1 && gpGlobals->wScreenWave < 9 &&               gpGlobals->g.lprgMagic[iMagicNum].wKeepEffect == 0xFFFF)            {               PAL_RLEBlitToSurface(b, g_Battle.lpBackground,                  PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));            }         }      }      else if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackWhole ||         gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackField)      {         assert(sTarget == -1);         if (gpGlobals->g.lprgMagic[iMagicNum].wType == kMagicTypeAttackWhole)         {            x = 240;            y = 150;         }         else         {            x = 160;            y = 200;         }         x += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wXOffset;         y += (SHORT)gpGlobals->g.lprgMagic[iMagicNum].wYOffset;         PAL_RLEBlitToSurface(b, gpScreen, PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         if (i == l - 1 && gpGlobals->wScreenWave < 9 &&            gpGlobals->g.lprgMagic[iMagicNum].wKeepEffect == 0xFFFF)         {            PAL_RLEBlitToSurface(b, g_Battle.lpBackground,               PAL_XY(x - PAL_RLEGetWidth(b) / 2, y - PAL_RLEGetHeight(b)));         }      }      else      {         assert(FALSE);      }      PAL_BattleUIUpdate();      VIDEO_UpdateScreen(NULL);   }   gpGlobals->wScreenWave = wave;   VIDEO_ShakeScreen(0, 0);   free(lpSpriteEffect);   for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)   {      g_Battle.rgPlayer[i].pos = g_Battle.rgPlayer[i].posOriginal;   }}static VOIDPAL_BattleShowPlayerSummonMagicAnim(   WORD         wPlayerIndex,   WORD         wObjectID)/*++  Purpose:    Show the summon magic animation for player.  Parameters:    [IN]  wPlayerIndex - the index of the player.    [IN]  wObjectID - the object ID of the magic to be used.  Return value:    None.--*/{   int           i, j;   WORD          wMagicNum = gpGlobals->g.rgObject[wObjectID].magic.wMagicNumber;   WORD          wEffectMagicID = 0;   DWORD         dwTime = SDL_GetTicks();   for (wEffectMagicID = 0; wEffectMagicID < MAX_OBJECTS; wEffectMagicID++)   {      if (gpGlobals->g.rgObject[wEffectMagicID].magic.wMagicNumber ==         gpGlobals->g.lprgMagic[wMagicNum].wEffect)      {         break;      }   }   assert(wEffectMagicID < MAX_OBJECTS);   //   // Brighten the players   //   for (i = 1; i <= 10; i++)   {      for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)      {         g_Battle.rgPlayer[j].iColorShift = i;      }      PAL_BattleDelay(1, wObjectID, TRUE);   }   PAL_BattleBackupScene();   if (gpGlobals->fIsWIN95)   {      SOUND_Play(gpGlobals->g.lprgMagic[wMagicNum].wSound);   }   //   // Load the sprite of the summoned god   //   j = gpGlobals->g.lprgMagic[wMagicNum].wSummonEffect + 10;   i = PAL_MKFGetDecompressedSize(j, gpGlobals->f.fpF);   g_Battle.lpSummonSprite = UTIL_malloc(i);   PAL_MKFDecompressChunk(g_Battle.lpSummonSprite, i, j, gpGlobals->f.fpF);   g_Battle.iSummonFrame = 0;   g_Battle.posSummon = PAL_XY(230 + (SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wXOffset),      155 + (SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wYOffset));   g_Battle.sBackgroundColorShift = (SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wEffectTimes);   //   // Fade in the summoned god   //   PAL_BattleMakeScene();   PAL_BattleFadeScene();   //   // Show the animation of the summoned god   // TODO: There is still something missing here compared to the original game.   //   while (g_Battle.iSummonFrame < PAL_SpriteGetNumFrames(g_Battle.lpSummonSprite) - 1)   {      //      // Wait for the time of one frame. Accept input here.      //      PAL_ProcessEvent();      while (SDL_GetTicks() <= dwTime)      {         PAL_ProcessEvent();         SDL_Delay(1);      }      //      // Set the time of the next frame.      //      dwTime = SDL_GetTicks() +         ((SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wSpeed) + 5) * 10;      PAL_BattleMakeScene();      SDL_BlitSurface(g_Battle.lpSceneBuf, NULL, gpScreen, NULL);      PAL_BattleUIUpdate();      VIDEO_UpdateScreen(NULL);      g_Battle.iSummonFrame++;   }   //   // Show the actual magic effect   //   PAL_BattleShowPlayerOffMagicAnim((WORD)-1, wEffectMagicID, -1, TRUE);}static VOIDPAL_BattleShowPostMagicAnim(   VOID)/*++  Purpose:    Show the post-magic animation.  Parameters:    None  Return value:    None.--*/{   int         i, j, x, y, dist = 8;   PAL_POS     rgEnemyPosBak[MAX_ENEMIES_IN_TEAM];   for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++)   {      rgEnemyPosBak[i] = g_Battle.rgEnemy[i].pos;   }   for (i = 0; i < 3; i++)   {      for (j = 0; j <= g_Battle.wMaxEnemyIndex; j++)      {         if (g_Battle.rgEnemy[j].e.wHealth == g_Battle.rgEnemy[j].wPrevHP)         {            continue;         }         x = PAL_X(g_Battle.rgEnemy[j].pos);         y = PAL_Y(g_Battle.rgEnemy[j].pos);         x -= dist;         y -= dist / 2;         g_Battle.rgEnemy[j].pos = PAL_XY(x, y);         g_Battle.rgEnemy[j].iColorShift = ((i == 1) ? 6 : 0);      }      PAL_BattleDelay(1, 0, TRUE);      dist /= -2;   }   for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++)   {      g_Battle.rgEnemy[i].pos = rgEnemyPosBak[i];   }   PAL_BattleDelay(1, 0, TRUE);}static VOIDPAL_BattlePlayerValidateAction(   WORD         wPlayerIndex)/*++  Purpose:    Validate player's action, fallback to other action when needed.  Parameters:    [IN]  wPlayerIndex - the index of the player.  Return value:    None.--*/{   const WORD   wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole;   const WORD   wObjectID = g_Battle.rgPlayer[wPlayerIndex].action.wActionID;   const SHORT  sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget;   BOOL         fValid = TRUE, fToEnemy = FALSE;   WORD         w;   int          i;   switch (g_Battle.rgPlayer[wPlayerIndex].action.ActionType)   {   case kBattleActionAttack:      fToEnemy = TRUE;      break;   case kBattleActionPass:      break;   case kBattleActionDefend:      break;   case kBattleActionMagic:      //      // Make sure player actually has the magic to be used      //      for (i = 0; i < MAX_PLAYER_MAGICS; i++)      {         if (gpGlobals->g.PlayerRoles.rgwMagic[i][wPlayerRole] == wObjectID)         {            break; // player has this magic         }      }      if (i >= MAX_PLAYER_MAGICS)      {         fValid = FALSE;      }      w = gpGlobals->g.rgObject[wObjectID].magic.wMagicNumber;      if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSilence] > 0)      {         //         // Player is silenced         //         fValid = FALSE;      }      if (gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] <         gpGlobals->g.lprgMagic[w].wCostMP)      {         //         // No enough MP         //         fValid = FALSE;      }      //      // Fallback to physical attack if player is using an offensive magic,      // defend if player is using a defensive or healing magic      //      if (gpGlobals->g.rgObject[wObjectID].magic.wFlags & kMagicFlagUsableToEnemy)      {         if (!fValid)         {            g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionAttack;         }         else if (gpGlobals->g.rgObject[wObjectID].magic.wFlags & kMagicFlagApplyToAll)         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = -1;         }         else if (sTarget == -1)         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = PAL_BattleSelectAutoTarget();         }         fToEnemy = TRUE;      }      else      {         if (!fValid)         {            g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionDefend;         }         else if (gpGlobals->g.rgObject[wObjectID].magic.wFlags & kMagicFlagApplyToAll)         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = -1;         }         else if (g_Battle.rgPlayer[wPlayerIndex].action.sTarget == -1)         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = wPlayerIndex;         }      }      break;   case kBattleActionCoopMagic:      fToEnemy = TRUE;      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         w = gpGlobals->rgParty[i].wPlayerRole;#ifdef PAL_CLASSIC         if (PAL_IsPlayerDying(w) ||            gpGlobals->rgPlayerStatus[w][kStatusSilence] > 0 ||            gpGlobals->rgPlayerStatus[w][kStatusSleep] > 0 ||            gpGlobals->rgPlayerStatus[w][kStatusParalyzed] > 0 ||            gpGlobals->rgPlayerStatus[w][kStatusConfused] > 0)#else         if (PAL_IsPlayerDying(w) ||            gpGlobals->rgPlayerStatus[w][kStatusSilence] > 0 ||            gpGlobals->rgPlayerStatus[w][kStatusSleep] > 0 ||            gpGlobals->rgPlayerStatus[w][kStatusConfused] > 0 ||            g_Battle.rgPlayer[i].flTimeMeter < 100 ||            (g_Battle.rgPlayer[i].state == kFighterAct && i != wPlayerIndex))#endif         {            g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionAttack;            break;         }      }      if (g_Battle.rgPlayer[wPlayerIndex].action.ActionType == kBattleActionCoopMagic)      {         if (gpGlobals->g.rgObject[wObjectID].magic.wFlags & kMagicFlagApplyToAll)         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = -1;         }         else if (sTarget == -1)         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = PAL_BattleSelectAutoTarget();         }      }      break;   case kBattleActionFlee:      break;   case kBattleActionThrowItem:      fToEnemy = TRUE;      if (PAL_GetItemAmount(wObjectID) == 0)      {         g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionAttack;      }      else if (gpGlobals->g.rgObject[wObjectID].item.wFlags & kItemFlagApplyToAll)      {         g_Battle.rgPlayer[wPlayerIndex].action.sTarget = -1;      }      else if (g_Battle.rgPlayer[wPlayerIndex].action.sTarget == -1)      {         g_Battle.rgPlayer[wPlayerIndex].action.sTarget = PAL_BattleSelectAutoTarget();      }      break;   case kBattleActionUseItem:      if (PAL_GetItemAmount(wObjectID) == 0)      {         g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionDefend;      }      else if (gpGlobals->g.rgObject[wObjectID].item.wFlags & kItemFlagApplyToAll)      {         g_Battle.rgPlayer[wPlayerIndex].action.sTarget = -1;      }      else if (g_Battle.rgPlayer[wPlayerIndex].action.sTarget == -1)      {         g_Battle.rgPlayer[wPlayerIndex].action.sTarget = wPlayerIndex;      }      break;   case kBattleActionAttackMate:      if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] == 0)      {         //         // Attack enemies instead if player is not confused         //         fToEnemy = TRUE;         g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionAttack;      }      else      {         for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)         {            if (i != wPlayerIndex &&               gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] != 0)            {               break;            }         }         if (i > gpGlobals->wMaxPartyMemberIndex)         {            //            // Attack enemies if no one else is alive            //            fToEnemy = TRUE;            g_Battle.rgPlayer[wPlayerIndex].action.ActionType = kBattleActionAttack;         }      }      break;   }   //   // Check if player can attack all enemies at once, or attack one enemy   //   if (g_Battle.rgPlayer[wPlayerIndex].action.ActionType == kBattleActionAttack)   {      if (sTarget == -1)      {         if (!PAL_PlayerCanAttackAll(wPlayerRole))         {            g_Battle.rgPlayer[wPlayerIndex].action.sTarget = PAL_BattleSelectAutoTarget();         }      }      else if (PAL_PlayerCanAttackAll(wPlayerRole))      {         g_Battle.rgPlayer[wPlayerIndex].action.sTarget = -1;      }   }   if (fToEnemy && g_Battle.rgPlayer[wPlayerIndex].action.sTarget >= 0)   {      if (g_Battle.rgEnemy[g_Battle.rgPlayer[wPlayerIndex].action.sTarget].wObjectID == 0)      {         g_Battle.rgPlayer[wPlayerIndex].action.sTarget = PAL_BattleSelectAutoTarget();         assert(g_Battle.rgPlayer[wPlayerIndex].action.sTarget >= 0);      }   }}VOIDPAL_BattlePlayerPerformAction(   WORD         wPlayerIndex)/*++  Purpose:    Perform the selected action for a player.  Parameters:    [IN]  wPlayerIndex - the index of the player.  Return value:    None.--*/{   SHORT    sDamage;   WORD     wPlayerRole = gpGlobals->rgParty[wPlayerIndex].wPlayerRole;   SHORT    sTarget;   int      x, y;   int      i, j, t;   WORD     str, def, res, wObject, wMagicNum;   BOOL     fCritical;   WORD     rgwCoopPos[3][2] = {{208, 157}, {234, 170}, {260, 183}};#ifndef PAL_CLASSIC   BOOL     fPoisoned, fCheckPoison;#endif   g_Battle.wMovingPlayerIndex = wPlayerIndex;   g_Battle.iBlow = 0;   PAL_BattlePlayerValidateAction(wPlayerIndex);   PAL_BattleBackupStat();   sTarget = g_Battle.rgPlayer[wPlayerIndex].action.sTarget;   switch (g_Battle.rgPlayer[wPlayerIndex].action.ActionType)   {   case kBattleActionAttack:      if (sTarget != -1)      {         //         // Attack one enemy         //         for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++)         {            str = PAL_GetPlayerAttackStrength(wPlayerRole);            def = g_Battle.rgEnemy[sTarget].e.wDefense;            def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4;            res = g_Battle.rgEnemy[sTarget].e.wPhysicalResistance;            fCritical = FALSE;            sDamage = PAL_CalcPhysicalAttackDamage(str, def, res);            sDamage += RandomLong(1, 2);            if (RandomLong(0, 5) == 0 ||               gpGlobals->rgPlayerStatus[wPlayerRole][kStatusBravery] > 0)            {               //               // Critical Hit               //               sDamage *= 3;               fCritical = TRUE;            }            if (wPlayerRole == 0 && RandomLong(0, 11) == 0)            {               //               // Bonus hit for Li Xiaoyao               //               sDamage *= 2;               fCritical = TRUE;            }            sDamage = (SHORT)(sDamage * RandomFloat(1, 1.125));            if (sDamage <= 0)            {               sDamage = 1;            }            g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage;            if (t == 0)            {               g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7;               PAL_BattleDelay(4, 0, TRUE);            }            PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical);         }      }      else      {         //         // Attack all enemies         //         for (t = 0; t < (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusDualAttack] ? 2 : 1); t++)         {            int division = 1;            const int index[MAX_ENEMIES_IN_TEAM] = {2, 1, 0, 4, 3};            fCritical =               (RandomLong(0, 5) == 0 || gpGlobals->rgPlayerStatus[wPlayerRole][kStatusBravery] > 0);            if (t == 0)            {               g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 7;               PAL_BattleDelay(4, 0, TRUE);            }            for (i = 0; i < MAX_ENEMIES_IN_TEAM; i++)            {               if (g_Battle.rgEnemy[index[i]].wObjectID == 0 ||                  index[i] > g_Battle.wMaxEnemyIndex)               {                  continue;               }               str = PAL_GetPlayerAttackStrength(wPlayerRole);               def = g_Battle.rgEnemy[index[i]].e.wDefense;               def += (g_Battle.rgEnemy[index[i]].e.wLevel + 6) * 4;               res = g_Battle.rgEnemy[index[i]].e.wPhysicalResistance;               sDamage = PAL_CalcPhysicalAttackDamage(str, def, res);               sDamage += RandomLong(1, 2);               if (fCritical)               {                  //                  // Critical Hit                  //                  sDamage *= 3;               }               sDamage /= division;               sDamage = (SHORT)(sDamage * RandomFloat(1, 1.125));               if (sDamage <= 0)               {                  sDamage = 1;               }               g_Battle.rgEnemy[index[i]].e.wHealth -= sDamage;               division++;               if (division > 3)               {                  division = 3;               }            }            PAL_BattleShowPlayerAttackAnim(wPlayerIndex, fCritical);         }      }      PAL_BattleUpdateFighters();      PAL_BattleMakeScene();      PAL_BattleDelay(3, 0, TRUE);      gpGlobals->Exp.rgAttackExp[wPlayerRole].wCount++;      gpGlobals->Exp.rgHealthExp[wPlayerRole].wCount += RandomLong(2, 3);      break;   case kBattleActionAttackMate:      //      // Check if there is someone else who is alive      //      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         if (i == wPlayerIndex)         {            continue;         }         if (gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0)         {            break;         }      }      if (i <= gpGlobals->wMaxPartyMemberIndex)      {         //         // Pick a target randomly         //         do         {            sTarget = RandomLong(0, gpGlobals->wMaxPartyMemberIndex);         } while (sTarget == wPlayerIndex || gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[sTarget].wPlayerRole] == 0);         for (j = 0; j < 2; j++)         {            g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 8;            PAL_BattleDelay(1, 0, TRUE);            g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 0;            PAL_BattleDelay(1, 0, TRUE);         }         PAL_BattleDelay(2, 0, TRUE);         x = PAL_X(g_Battle.rgPlayer[sTarget].pos) + 30;         y = PAL_Y(g_Battle.rgPlayer[sTarget].pos) + 12;         g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x, y);         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 8;         PAL_BattleDelay(5, 0, TRUE);         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 9;         SOUND_Play(gpGlobals->g.PlayerRoles.rgwWeaponSound[wPlayerRole]);         str = PAL_GetPlayerAttackStrength(wPlayerRole);         def = PAL_GetPlayerDefense(gpGlobals->rgParty[sTarget].wPlayerRole);         if (g_Battle.rgPlayer[sTarget].fDefending)         {            def *= 2;         }         sDamage = PAL_CalcPhysicalAttackDamage(str, def, 2);         if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[sTarget].wPlayerRole][kStatusProtect] > 0)         {            sDamage /= 2;         }         if (sDamage <= 0)         {            sDamage = 1;         }         if (sDamage > (SHORT)gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[sTarget].wPlayerRole])         {            sDamage = gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[sTarget].wPlayerRole];         }         gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[sTarget].wPlayerRole] -= sDamage;         g_Battle.rgPlayer[sTarget].pos =            PAL_XY(PAL_X(g_Battle.rgPlayer[sTarget].pos) - 12,                   PAL_Y(g_Battle.rgPlayer[sTarget].pos) - 6);         PAL_BattleDelay(1, 0, TRUE);         g_Battle.rgPlayer[sTarget].iColorShift = 6;         PAL_BattleDelay(1, 0, TRUE);         PAL_BattleDisplayStatChange();         g_Battle.rgPlayer[sTarget].iColorShift = 0;         PAL_BattleDelay(4, 0, TRUE);         PAL_BattleUpdateFighters();         PAL_BattleDelay(4, 0, TRUE);      }      break;   case kBattleActionCoopMagic:      wObject = PAL_GetPlayerCooperativeMagic(gpGlobals->rgParty[wPlayerIndex].wPlayerRole);      wMagicNum = gpGlobals->g.rgObject[wObject].magic.wMagicNumber;      if (gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeSummon)      {         PAL_BattleShowPlayerPreMagicAnim(wPlayerIndex, TRUE);         PAL_BattleShowPlayerSummonMagicAnim((WORD)-1, wObject);      }      else      {         for (i = 1; i <= 6; i++)         {            //            // Update the position for the player who invoked the action            //            x = PAL_X(g_Battle.rgPlayer[wPlayerIndex].posOriginal) * (6 - i);            y = PAL_Y(g_Battle.rgPlayer[wPlayerIndex].posOriginal) * (6 - i);            x += rgwCoopPos[0][0] * i;            y += rgwCoopPos[0][1] * i;            x /= 6;            y /= 6;            g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x, y);            //            // Update the position for other players            //            t = 0;            for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)            {               if ((WORD)j == wPlayerIndex)               {                  continue;               }               t++;               x = PAL_X(g_Battle.rgPlayer[j].posOriginal) * (6 - i);               y = PAL_Y(g_Battle.rgPlayer[j].posOriginal) * (6 - i);               x += rgwCoopPos[t][0] * i;               y += rgwCoopPos[t][1] * i;               x /= 6;               y /= 6;               g_Battle.rgPlayer[j].pos = PAL_XY(x, y);            }            PAL_BattleDelay(1, 0, TRUE);         }         for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--)         {            if ((WORD)i == wPlayerIndex)            {               continue;            }            g_Battle.rgPlayer[i].wCurrentFrame = 5;            PAL_BattleDelay(3, 0, TRUE);         }         g_Battle.rgPlayer[wPlayerIndex].iColorShift = 6;         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;         SOUND_Play(157);         PAL_BattleDelay(5, 0, TRUE);         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 6;         g_Battle.rgPlayer[wPlayerIndex].iColorShift = 0;         PAL_BattleDelay(3, 0, TRUE);         PAL_BattleShowPlayerOffMagicAnim((WORD)-1, wObject, sTarget, FALSE);      }      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] -=            gpGlobals->g.lprgMagic[wMagicNum].wCostMP;         if ((SHORT)(gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole]) <= 0)         {            gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] = 1;         }         //         // Reset the time meter for everyone when using coopmagic         //#ifdef PAL_CLASSIC         g_Battle.rgPlayer[i].state = kFighterWait;#else         g_Battle.rgPlayer[i].flTimeMeter = 0;         g_Battle.rgPlayer[i].flTimeSpeedModifier = 2;#endif      }      PAL_BattleBackupStat(); // so that "damages" to players won't be shown      str = 0;      for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)      {         str += PAL_GetPlayerAttackStrength(gpGlobals->rgParty[i].wPlayerRole);         str += PAL_GetPlayerMagicStrength(gpGlobals->rgParty[i].wPlayerRole);      }      str /= 4;      //      // Inflict damage to enemies      //      if (sTarget == -1)      {         //         // Attack all enemies         //         for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)         {            if (g_Battle.rgEnemy[i].wObjectID == 0)            {               continue;            }            def = g_Battle.rgEnemy[i].e.wDefense;            def += (g_Battle.rgEnemy[i].e.wLevel + 6) * 4;            sDamage = PAL_CalcMagicDamage(str, def,               g_Battle.rgEnemy[i].e.wElemResistance, g_Battle.rgEnemy[i].e.wPoisonResistance, wObject);            if (sDamage <= 0)            {               sDamage = 1;            }            g_Battle.rgEnemy[i].e.wHealth -= sDamage;         }      }      else      {         //         // Attack one enemy         //         def = g_Battle.rgEnemy[sTarget].e.wDefense;         def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4;         sDamage = PAL_CalcMagicDamage(str, def,            g_Battle.rgEnemy[sTarget].e.wElemResistance, g_Battle.rgEnemy[sTarget].e.wPoisonResistance, wObject);         if (sDamage <= 0)         {            sDamage = 1;         }         g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage;      }      PAL_BattleDisplayStatChange();      PAL_BattleShowPostMagicAnim();      PAL_BattleDelay(5, 0, TRUE);      if (gpGlobals->g.lprgMagic[wMagicNum].wType != kMagicTypeSummon)      {         PAL_BattlePostActionCheck(FALSE);         //         // Move all players back to the original position         //         for (i = 1; i <= 6; i++)         {            //            // Update the position for the player who invoked the action            //            x = PAL_X(g_Battle.rgPlayer[wPlayerIndex].posOriginal) * i;            y = PAL_Y(g_Battle.rgPlayer[wPlayerIndex].posOriginal) * i;            x += rgwCoopPos[0][0] * (6 - i);            y += rgwCoopPos[0][1] * (6 - i);            x /= 6;            y /= 6;            g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x, y);            //            // Update the position for other players            //            t = 0;            for (j = 0; j <= gpGlobals->wMaxPartyMemberIndex; j++)            {               g_Battle.rgPlayer[j].wCurrentFrame = 0;               if ((WORD)j == wPlayerIndex)               {                  continue;               }               t++;               x = PAL_X(g_Battle.rgPlayer[j].posOriginal) * i;               y = PAL_Y(g_Battle.rgPlayer[j].posOriginal) * i;               x += rgwCoopPos[t][0] * (6 - i);               y += rgwCoopPos[t][1] * (6 - i);               x /= 6;               y /= 6;               g_Battle.rgPlayer[j].pos = PAL_XY(x, y);            }            PAL_BattleDelay(1, 0, TRUE);         }      }      break;   case kBattleActionDefend:      g_Battle.rgPlayer[wPlayerIndex].fDefending = TRUE;      gpGlobals->Exp.rgDefenseExp[wPlayerRole].wCount += 2;      break;   case kBattleActionFlee:      str = PAL_GetPlayerFleeRate(wPlayerRole);      def = 0;      for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)      {         if (g_Battle.rgEnemy[i].wObjectID == 0)         {            continue;         }         def += (SHORT)(g_Battle.rgEnemy[i].e.wFleeRate);         def += (g_Battle.rgEnemy[i].e.wLevel + 6) * 2;      }      if ((SHORT)def < 0)      {         def = 0;      }      if (RandomLong(0, str) >= RandomLong(0, def) && !g_Battle.fIsBoss)      {         //         // Successful escape         //         PAL_BattlePlayerEscape();      }      else      {         //         // Failed escape         //         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 0;         for (i = 0; i < 3; i++)         {            x = PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) + 4;            y = PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) + 2;            g_Battle.rgPlayer[wPlayerIndex].pos = PAL_XY(x, y);            PAL_BattleDelay(1, 0, TRUE);         }         g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 1;         PAL_BattleDelay(8, BATTLE_LABEL_ESCAPEFAIL, TRUE);         gpGlobals->Exp.rgFleeExp[wPlayerRole].wCount += 2;      }      break;   case kBattleActionMagic:      wObject = g_Battle.rgPlayer[wPlayerIndex].action.wActionID;      wMagicNum = gpGlobals->g.rgObject[wObject].magic.wMagicNumber;      PAL_BattleShowPlayerPreMagicAnim(wPlayerIndex,         (gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeSummon));      if (!gpGlobals->fAutoBattle)      {         gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] -= gpGlobals->g.lprgMagic[wMagicNum].wCostMP;         if ((SHORT)(gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole]) < 0)         {            gpGlobals->g.PlayerRoles.rgwMP[wPlayerRole] = 0;         }      }      if (gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeApplyToPlayer ||         gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeApplyToParty ||         gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeTrance)      {         //         // Using a defensive magic         //         WORD w = 0;         if (g_Battle.rgPlayer[wPlayerIndex].action.sTarget != -1)         {            w = gpGlobals->rgParty[g_Battle.rgPlayer[wPlayerIndex].action.sTarget].wPlayerRole;         }         else if (gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeTrance)         {            w = wPlayerRole;         }         gpGlobals->g.rgObject[wObject].magic.wScriptOnUse =            PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].magic.wScriptOnUse, wPlayerRole);         if (g_fScriptSuccess)         {            PAL_BattleShowPlayerDefMagicAnim(wPlayerIndex, wObject, sTarget);            gpGlobals->g.rgObject[wObject].magic.wScriptOnSuccess =               PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].magic.wScriptOnSuccess, w);            if (g_fScriptSuccess)            {               if (gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeTrance)               {                  for (i = 0; i < 6; i++)                  {                     g_Battle.rgPlayer[wPlayerIndex].iColorShift = i * 2;                     PAL_BattleDelay(1, 0, TRUE);                  }                  PAL_BattleBackupScene();                  PAL_LoadBattleSprites();                  g_Battle.rgPlayer[wPlayerIndex].iColorShift = 0;                  PAL_BattleMakeScene();                  PAL_BattleFadeScene();               }            }         }      }      else      {         //         // Using an offensive magic         //         gpGlobals->g.rgObject[wObject].magic.wScriptOnUse =            PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].magic.wScriptOnUse, wPlayerRole);         if (g_fScriptSuccess)         {            if (gpGlobals->g.lprgMagic[wMagicNum].wType == kMagicTypeSummon)            {               PAL_BattleShowPlayerSummonMagicAnim(wPlayerIndex, wObject);            }            else            {               PAL_BattleShowPlayerOffMagicAnim(wPlayerIndex, wObject, sTarget, FALSE);            }            gpGlobals->g.rgObject[wObject].magic.wScriptOnSuccess =               PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].magic.wScriptOnSuccess, (WORD)sTarget);            //            // Inflict damage to enemies            //            if ((SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wBaseDamage) > 0)            {               if (sTarget == -1)               {                  //                  // Attack all enemies                  //                  for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)                  {                     if (g_Battle.rgEnemy[i].wObjectID == 0)                     {                        continue;                     }                     str = PAL_GetPlayerMagicStrength(wPlayerRole);                     def = g_Battle.rgEnemy[i].e.wDefense;                     def += (g_Battle.rgEnemy[i].e.wLevel + 6) * 4;                     sDamage = PAL_CalcMagicDamage(str, def,                        g_Battle.rgEnemy[i].e.wElemResistance, g_Battle.rgEnemy[i].e.wPoisonResistance, wObject);                     if (sDamage <= 0)                     {                        sDamage = 1;                     }                     g_Battle.rgEnemy[i].e.wHealth -= sDamage;                  }               }               else               {                  //                  // Attack one enemy                  //                  str = PAL_GetPlayerMagicStrength(wPlayerRole);                  def = g_Battle.rgEnemy[sTarget].e.wDefense;                  def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4;                  sDamage = PAL_CalcMagicDamage(str, def,                     g_Battle.rgEnemy[sTarget].e.wElemResistance, g_Battle.rgEnemy[sTarget].e.wPoisonResistance, wObject);                  if (sDamage <= 0)                  {                     sDamage = 1;                  }                  g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage;               }            }         }      }      PAL_BattleDisplayStatChange();      PAL_BattleShowPostMagicAnim();      PAL_BattleDelay(5, 0, TRUE);      gpGlobals->Exp.rgMagicExp[wPlayerRole].wCount += RandomLong(2, 3);      gpGlobals->Exp.rgMagicPowerExp[wPlayerRole].wCount++;      break;   case kBattleActionThrowItem:      wObject = g_Battle.rgPlayer[wPlayerIndex].action.wActionID;      for (i = 0; i < 4; i++)      {         g_Battle.rgPlayer[wPlayerIndex].pos =            PAL_XY(PAL_X(g_Battle.rgPlayer[wPlayerIndex].pos) - (4 - i),                   PAL_Y(g_Battle.rgPlayer[wPlayerIndex].pos) - (4 - i) / 2);         PAL_BattleDelay(1, 0, TRUE);      }      PAL_BattleDelay(2, wObject, TRUE);      g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 5;      SOUND_Play(gpGlobals->g.PlayerRoles.rgwMagicSound[wPlayerRole]);      PAL_BattleDelay(8, wObject, TRUE);      g_Battle.rgPlayer[wPlayerIndex].wCurrentFrame = 6;      PAL_BattleDelay(2, wObject, TRUE);      //      // Run the script      //      gpGlobals->g.rgObject[wObject].item.wScriptOnThrow =         PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].item.wScriptOnThrow, (WORD)sTarget);      //      // Remove the thrown item from inventory      //      PAL_AddItemToInventory(wObject, -1);      PAL_BattleDisplayStatChange();      PAL_BattleDelay(4, 0, TRUE);      PAL_BattleUpdateFighters();      PAL_BattleDelay(4, 0, TRUE);      break;   case kBattleActionUseItem:      wObject = g_Battle.rgPlayer[wPlayerIndex].action.wActionID;      PAL_BattleShowPlayerUseItemAnim(wPlayerIndex, wObject, sTarget);      //      // Run the script      //      gpGlobals->g.rgObject[wObject].item.wScriptOnUse =         PAL_RunTriggerScript(gpGlobals->g.rgObject[wObject].item.wScriptOnUse,            (sTarget == -1) ? 0xFFFF : gpGlobals->rgParty[sTarget].wPlayerRole);      //      // Remove the item if the item is consuming      //      if (gpGlobals->g.rgObject[wObject].item.wFlags & kItemFlagConsuming)      {         PAL_AddItemToInventory(wObject, -1);      }      if (g_Battle.iHidingTime < 0)      {#ifdef PAL_CLASSIC         g_Battle.iHidingTime = -g_Battle.iHidingTime;#else         g_Battle.iHidingTime = -g_Battle.iHidingTime * 20;         if (gpGlobals->bBattleSpeed > 1)         {            g_Battle.iHidingTime *= 1 + (gpGlobals->bBattleSpeed - 1) * 0.5;         }         else         {            g_Battle.iHidingTime *= 1.2;         }#endif         PAL_BattleBackupScene();         PAL_BattleMakeScene();         PAL_BattleFadeScene();      }      PAL_BattleUpdateFighters();      PAL_BattleDisplayStatChange();      PAL_BattleDelay(8, 0, TRUE);      break;   case kBattleActionPass:      break;   }   //   // Revert this player back to waiting state.   //   g_Battle.rgPlayer[wPlayerIndex].state = kFighterWait;   g_Battle.rgPlayer[wPlayerIndex].flTimeMeter = 0;   PAL_BattlePostActionCheck(FALSE);#ifndef PAL_CLASSIC   //   // Only check for poisons when the battle is not ended   //   fCheckPoison = FALSE;   if (g_Battle.BattleResult == kBattleResultOnGoing)   {      for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)      {         if (g_Battle.rgEnemy[i].wObjectID != 0)         {            fCheckPoison = TRUE;            break;         }      }   }   //   // Check for poisons   //   if (fCheckPoison)   {      fPoisoned = FALSE;      PAL_BattleBackupStat();      for (i = 0; i < MAX_POISONS; i++)      {         wObject = gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonID;         if (wObject != 0)         {            fPoisoned = TRUE;            gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript =               PAL_RunTriggerScript(gpGlobals->rgPoisonStatus[i][wPlayerIndex].wPoisonScript, wPlayerRole);         }      }      if (fPoisoned)      {         PAL_BattleDelay(3, 0, TRUE);         PAL_BattleUpdateFighters();         if (PAL_BattleDisplayStatChange())         {            PAL_BattleDelay(6, 0, TRUE);         }      }   }   //   // Update statuses   //   for (i = 0; i < kStatusAll; i++)   {      if (gpGlobals->rgPlayerStatus[wPlayerRole][i] > 0)      {         gpGlobals->rgPlayerStatus[wPlayerRole][i]--;      }   }#endif}static INTPAL_BattleEnemySelectTargetIndex(   VOID)/*++  Purpose:    Select a attackable player randomly.  Parameters:    None.  Return value:    None.--*/{   int i;   i = RandomLong(0, gpGlobals->wMaxPartyMemberIndex);   while (gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] == 0)   {      i = RandomLong(0, gpGlobals->wMaxPartyMemberIndex);   }   return i;}VOIDPAL_BattleEnemyPerformAction(   WORD         wEnemyIndex)/*++  Purpose:    Perform the selected action for a player.  Parameters:    [IN]  wEnemyIndex - the index of the player.  Return value:    None.--*/{   int        str, def, iCoverIndex, i, x, y, ex, ey, iSound;   WORD       rgwElementalResistance[NUM_MAGIC_ELEMENTAL];   WORD       wPlayerRole, w, wMagic, wMagicNum;   SHORT      sTarget, sDamage;   BOOL       fAutoDefend = FALSE, rgfMagAutoDefend[MAX_PLAYERS_IN_PARTY];   PAL_BattleBackupStat();   g_Battle.iBlow = 0;   sTarget = PAL_BattleEnemySelectTargetIndex();   wPlayerRole = gpGlobals->rgParty[sTarget].wPlayerRole;   wMagic = g_Battle.rgEnemy[wEnemyIndex].e.wMagic;   if (g_Battle.rgEnemy[wEnemyIndex].rgwStatus[kStatusSleep] > 0 ||      g_Battle.rgEnemy[wEnemyIndex].rgwStatus[kStatusParalyzed] > 0 ||      g_Battle.iHidingTime > 0)   {      //      // Do nothing      //      goto end;   }   else if (g_Battle.rgEnemy[wEnemyIndex].rgwStatus[kStatusConfused] > 0)   {      // TODO   }   else if (wMagic != 0 &&      RandomLong(0, 9) < g_Battle.rgEnemy[wEnemyIndex].e.wMagicRate &&      g_Battle.rgEnemy[wEnemyIndex].rgwStatus[kStatusSilence] == 0)   {      //      // Magical attack      //      if (wMagic == 0xFFFF)      {         //         // Do nothing         //         goto end;      }      wMagicNum = gpGlobals->g.rgObject[wMagic].magic.wMagicNumber;      str = (SHORT)g_Battle.rgEnemy[wEnemyIndex].e.wMagicStrength;      str += (g_Battle.rgEnemy[wEnemyIndex].e.wLevel + 6) * 6;      if (str < 0)      {         str = 0;      }      ex = PAL_X(g_Battle.rgEnemy[wEnemyIndex].pos);      ey = PAL_Y(g_Battle.rgEnemy[wEnemyIndex].pos);      ex += 12;      ey += 6;      g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(ex, ey);      PAL_BattleDelay(1, 0, FALSE);      ex += 4;      ey += 2;      g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(ex, ey);      PAL_BattleDelay(1, 0, FALSE);      SOUND_Play(g_Battle.rgEnemy[wEnemyIndex].e.wMagicSound);      for (i = 0; i < g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames; i++)      {         g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame =            g_Battle.rgEnemy[wEnemyIndex].e.wIdleFrames + i;         PAL_BattleDelay(g_Battle.rgEnemy[wEnemyIndex].e.wActWaitFrames, 0, FALSE);      }      if (g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames == 0)      {         PAL_BattleDelay(1, 0, FALSE);      }      if (gpGlobals->g.lprgMagic[wMagicNum].wSoundDelay == 0)      {         for (i = 0; i <= g_Battle.rgEnemy[wEnemyIndex].e.wAttackFrames; i++)         {            g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame =               i - 1 + g_Battle.rgEnemy[wEnemyIndex].e.wIdleFrames + g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames;            PAL_BattleDelay(g_Battle.rgEnemy[wEnemyIndex].e.wActWaitFrames, 0, FALSE);         }      }      if (gpGlobals->g.lprgMagic[wMagicNum].wType != kMagicTypeNormal)      {         sTarget = -1;         for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)         {            w = gpGlobals->rgParty[i].wPlayerRole;            if (gpGlobals->rgPlayerStatus[w][kStatusSleep] == 0 &&#ifdef PAL_CLASSIC               gpGlobals->rgPlayerStatus[w][kStatusParalyzed] == 0 &&#else               gpGlobals->rgPlayerStatus[w][kStatusSlow] == 0 &&#endif               gpGlobals->rgPlayerStatus[w][kStatusConfused] == 0 &&               RandomLong(0, 2) == 0 &&               gpGlobals->g.PlayerRoles.rgwHP[w] != 0)            {               rgfMagAutoDefend[i] = TRUE;               g_Battle.rgPlayer[i].wCurrentFrame = 3;            }            else            {               rgfMagAutoDefend[i] = FALSE;            }         }      }      else if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] == 0 &&#ifdef PAL_CLASSIC         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] == 0 &&#else         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSlow] == 0 &&#endif         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] == 0 &&         RandomLong(0, 2) == 0)      {         fAutoDefend = TRUE;         g_Battle.rgPlayer[sTarget].wCurrentFrame = 3;      }//      PAL_BattleDelay(12, (WORD)(-((SHORT)wMagic)), FALSE);      gpGlobals->g.rgObject[wMagic].magic.wScriptOnUse =         PAL_RunTriggerScript(gpGlobals->g.rgObject[wMagic].magic.wScriptOnUse, wPlayerRole);      if (g_fScriptSuccess)      {         PAL_BattleShowEnemyMagicAnim(wMagic, sTarget);         gpGlobals->g.rgObject[wMagic].magic.wScriptOnSuccess =            PAL_RunTriggerScript(gpGlobals->g.rgObject[wMagic].magic.wScriptOnSuccess, wPlayerRole);      }      if ((SHORT)(gpGlobals->g.lprgMagic[wMagicNum].wBaseDamage) > 0)      {         if (sTarget == -1)         {            //            // damage all players            //            for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)            {               w = gpGlobals->rgParty[i].wPlayerRole;               if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0)               {                  //                  // skip dead players                  //                  continue;               }               def = PAL_GetPlayerDefense(w);               for (x = 0; x < NUM_MAGIC_ELEMENTAL; x++)               {                  rgwElementalResistance[x] =                     5 + PAL_GetPlayerElementalResistance(w, x) / 20;               }               sDamage = PAL_CalcMagicDamage(str, def, rgwElementalResistance,                  5 + PAL_GetPlayerPoisonResistance(w) / 20, wMagic);               sDamage /= ((g_Battle.rgPlayer[i].fDefending ? 2 : 1) *                  ((gpGlobals->rgPlayerStatus[w][kStatusProtect] > 0) ? 2 : 1)) +                  (rgfMagAutoDefend[i] ? 1 : 0);               if (sDamage > gpGlobals->g.PlayerRoles.rgwHP[w])               {                  sDamage = gpGlobals->g.PlayerRoles.rgwHP[w];               }#ifndef INVINCIBLE               gpGlobals->g.PlayerRoles.rgwHP[w] -= sDamage;#endif               if (gpGlobals->g.PlayerRoles.rgwHP[w] == 0)               {                  SOUND_Play(gpGlobals->g.PlayerRoles.rgwDeathSound[w]);               }            }         }         else         {            //            // damage one player            //            def = PAL_GetPlayerDefense(wPlayerRole);            for (x = 0; x < NUM_MAGIC_ELEMENTAL; x++)            {               rgwElementalResistance[x] =                  5 + PAL_GetPlayerElementalResistance(wPlayerRole, x) / 20;            }            sDamage = PAL_CalcMagicDamage(str, def, rgwElementalResistance,               5 + PAL_GetPlayerPoisonResistance(wPlayerRole) / 20, wMagic);            sDamage /= ((g_Battle.rgPlayer[sTarget].fDefending ? 2 : 1) *               ((gpGlobals->rgPlayerStatus[wPlayerRole][kStatusProtect] > 0) ? 2 : 1)) +               (fAutoDefend ? 1 : 0);            if (sDamage > gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole])            {               sDamage = gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole];            }#ifndef INVINCIBLE            gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] -= sDamage;#endif            if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)            {               SOUND_Play(gpGlobals->g.PlayerRoles.rgwDeathSound[wPlayerRole]);            }         }      }      if (!gpGlobals->fAutoBattle)      {         PAL_BattleDisplayStatChange();      }      for (i = 0; i < 5; i++)      {         if (sTarget == -1)         {            for (x = 0; x <= gpGlobals->wMaxPartyMemberIndex; x++)            {               if (g_Battle.rgPlayer[x].wPrevHP ==                  gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[x].wPlayerRole])               {                  //                  // Skip unaffected players                  //                  continue;               }               g_Battle.rgPlayer[x].wCurrentFrame = 4;               if (i > 0)               {                  g_Battle.rgPlayer[x].pos =                     PAL_XY(PAL_X(g_Battle.rgPlayer[x].pos) + (8 >> i),                            PAL_Y(g_Battle.rgPlayer[x].pos) + (4 >> i));               }               g_Battle.rgPlayer[x].iColorShift = ((i < 3) ? 6 : 0);            }         }         else         {            g_Battle.rgPlayer[sTarget].wCurrentFrame = 4;            if (i > 0)            {               g_Battle.rgPlayer[sTarget].pos =                  PAL_XY(PAL_X(g_Battle.rgPlayer[sTarget].pos) + (8 >> i),                         PAL_Y(g_Battle.rgPlayer[sTarget].pos) + (4 >> i));            }            g_Battle.rgPlayer[sTarget].iColorShift = ((i < 3) ? 6 : 0);         }         PAL_BattleDelay(1, 0, FALSE);      }      g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame = 0;      g_Battle.rgEnemy[wEnemyIndex].pos = g_Battle.rgEnemy[wEnemyIndex].posOriginal;      PAL_BattleDelay(1, 0, FALSE);      PAL_BattleUpdateFighters();      PAL_BattlePostActionCheck(TRUE);      PAL_BattleDelay(8, 0, TRUE);   }   else   {      //      // Physical attack      //      WORD wFrameBak = g_Battle.rgPlayer[sTarget].wCurrentFrame;      str = (SHORT)g_Battle.rgEnemy[wEnemyIndex].e.wAttackStrength;      str += (g_Battle.rgEnemy[wEnemyIndex].e.wLevel + 6) * 6;      if (str < 0)      {         str = 0;      }      def = PAL_GetPlayerDefense(wPlayerRole);      if (g_Battle.rgPlayer[sTarget].fDefending)      {         def *= 2;      }      SOUND_Play(g_Battle.rgEnemy[wEnemyIndex].e.wAttackSound);      iCoverIndex = -1;      fAutoDefend = (RandomLong(0, 16) >= 10);      //      // Check if the inflictor should be protected      //      if ((PAL_IsPlayerDying(wPlayerRole) ||         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] > 0 ||         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] > 0 ||         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] > 0) && fAutoDefend)      {         w = gpGlobals->g.PlayerRoles.rgwCoveredBy[wPlayerRole];         for (i = 0; i <= gpGlobals->wMaxPartyMemberIndex; i++)         {            if (gpGlobals->rgParty[i].wPlayerRole == w)            {               iCoverIndex = i;               break;            }         }         if (iCoverIndex != -1)         {            if (PAL_IsPlayerDying(gpGlobals->rgParty[iCoverIndex].wPlayerRole) ||               gpGlobals->rgPlayerStatus[gpGlobals->rgParty[iCoverIndex].wPlayerRole][kStatusConfused] > 0 ||               gpGlobals->rgPlayerStatus[gpGlobals->rgParty[iCoverIndex].wPlayerRole][kStatusSleep] > 0 ||               gpGlobals->rgPlayerStatus[gpGlobals->rgParty[iCoverIndex].wPlayerRole][kStatusParalyzed] > 0)            {               iCoverIndex = -1;            }         }      }      //      // If no one can cover the inflictor and inflictor is in a      // bad status, don't evade      //      if (iCoverIndex == -1 &&         (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusConfused] > 0 ||         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSleep] > 0 ||#ifdef PAL_CLASSIC         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusParalyzed] > 0))#else         gpGlobals->rgPlayerStatus[wPlayerRole][kStatusSlow] > 0))#endif      {         fAutoDefend = FALSE;      }      for (i = 0; i < g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames; i++)      {         g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame =            g_Battle.rgEnemy[wEnemyIndex].e.wIdleFrames + i;         PAL_BattleDelay(2, 0, FALSE);      }      for (i = 0; i < 3 - g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames; i++)      {         x = PAL_X(g_Battle.rgEnemy[wEnemyIndex].pos) - 2;         y = PAL_Y(g_Battle.rgEnemy[wEnemyIndex].pos) - 1;         g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(x, y);         PAL_BattleDelay(1, 0, FALSE);      }	  if (!gpGlobals->fIsWIN95 || g_Battle.rgEnemy[wEnemyIndex].e.wActionSound != 0)      {         SOUND_Play(g_Battle.rgEnemy[wEnemyIndex].e.wActionSound);      }      PAL_BattleDelay(1, 0, FALSE);      ex = PAL_X(g_Battle.rgPlayer[sTarget].pos) - 44;      ey = PAL_Y(g_Battle.rgPlayer[sTarget].pos) - 16;      iSound = g_Battle.rgEnemy[wEnemyIndex].e.wCallSound;      if (iCoverIndex != -1)      {         iSound = gpGlobals->g.PlayerRoles.rgwCoverSound[gpGlobals->rgParty[iCoverIndex].wPlayerRole];         g_Battle.rgPlayer[iCoverIndex].wCurrentFrame = 3;         x = PAL_X(g_Battle.rgPlayer[sTarget].pos) - 24;         y = PAL_Y(g_Battle.rgPlayer[sTarget].pos) - 12;         g_Battle.rgPlayer[iCoverIndex].pos = PAL_XY(x, y);      }      else if (fAutoDefend)      {         g_Battle.rgPlayer[sTarget].wCurrentFrame = 3;         iSound = gpGlobals->g.PlayerRoles.rgwCoverSound[wPlayerRole];      }      if (g_Battle.rgEnemy[wEnemyIndex].e.wAttackFrames == 0)      {         g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame =            g_Battle.rgEnemy[wEnemyIndex].e.wIdleFrames - 1;         g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(ex, ey);         PAL_BattleDelay(2, 0, FALSE);      }      else      {         for (i = 0; i <= g_Battle.rgEnemy[wEnemyIndex].e.wAttackFrames; i++)         {            g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame =               g_Battle.rgEnemy[wEnemyIndex].e.wIdleFrames +               g_Battle.rgEnemy[wEnemyIndex].e.wMagicFrames + i - 1;            g_Battle.rgEnemy[wEnemyIndex].pos = PAL_XY(ex, ey);            PAL_BattleDelay(g_Battle.rgEnemy[wEnemyIndex].e.wActWaitFrames, 0, FALSE);         }      }      if (!fAutoDefend)      {         g_Battle.rgPlayer[sTarget].wCurrentFrame = 4;         sDamage = PAL_CalcPhysicalAttackDamage(str + RandomLong(0, 2), def, 2);         sDamage += RandomLong(0, 1);         if (gpGlobals->rgPlayerStatus[wPlayerRole][kStatusProtect])         {            sDamage /= 2;         }         if ((SHORT)gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] < sDamage)         {            sDamage = gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole];         }         if (sDamage <= 0)         {            sDamage = 1;         }#ifndef INVINCIBLE         gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] -= sDamage;#endif         PAL_BattleDisplayStatChange();         g_Battle.rgPlayer[sTarget].iColorShift = 6;      }	  if (!gpGlobals->fIsWIN95 || iSound != 0)      {         SOUND_Play(iSound);      }      PAL_BattleDelay(1, 0, FALSE);      g_Battle.rgPlayer[sTarget].iColorShift = 0;      if (iCoverIndex != -1)      {         g_Battle.rgEnemy[wEnemyIndex].pos =            PAL_XY(PAL_X(g_Battle.rgEnemy[wEnemyIndex].pos) - 10,                   PAL_Y(g_Battle.rgEnemy[wEnemyIndex].pos) - 8);         g_Battle.rgPlayer[iCoverIndex].pos =            PAL_XY(PAL_X(g_Battle.rgPlayer[iCoverIndex].pos) + 4,                   PAL_Y(g_Battle.rgPlayer[iCoverIndex].pos) + 2);      }      else      {         g_Battle.rgPlayer[sTarget].pos =            PAL_XY(PAL_X(g_Battle.rgPlayer[sTarget].pos) + 8,                   PAL_Y(g_Battle.rgPlayer[sTarget].pos) + 4);      }      PAL_BattleDelay(1, 0, FALSE);      if (gpGlobals->g.PlayerRoles.rgwHP[wPlayerRole] == 0)      {         SOUND_Play(gpGlobals->g.PlayerRoles.rgwDeathSound[wPlayerRole]);         wFrameBak = 2;      }      else if (PAL_IsPlayerDying(wPlayerRole))      {         wFrameBak = 1;      }      if (iCoverIndex == -1)      {         g_Battle.rgPlayer[sTarget].pos =            PAL_XY(PAL_X(g_Battle.rgPlayer[sTarget].pos) + 2,                   PAL_Y(g_Battle.rgPlayer[sTarget].pos) + 1);      }      PAL_BattleDelay(3, 0, FALSE);      g_Battle.rgEnemy[wEnemyIndex].pos = g_Battle.rgEnemy[wEnemyIndex].posOriginal;      g_Battle.rgEnemy[wEnemyIndex].wCurrentFrame = 0;      PAL_BattleDelay(1, 0, FALSE);      g_Battle.rgPlayer[sTarget].wCurrentFrame = wFrameBak;      PAL_BattleDelay(1, 0, TRUE);      g_Battle.rgPlayer[sTarget].pos = g_Battle.rgPlayer[sTarget].posOriginal;      PAL_BattleDelay(4, 0, TRUE);      PAL_BattleUpdateFighters();      if (iCoverIndex == -1 && !fAutoDefend &&         g_Battle.rgEnemy[wEnemyIndex].e.wAttackEquivItemRate >= RandomLong(1, 10))      {         i = g_Battle.rgEnemy[wEnemyIndex].e.wAttackEquivItem;         gpGlobals->g.rgObject[i].item.wScriptOnUse =            PAL_RunTriggerScript(gpGlobals->g.rgObject[i].item.wScriptOnUse, wPlayerRole);      }      PAL_BattlePostActionCheck(TRUE);   }end:#ifndef PAL_CLASSIC   //   // Check poisons   //   if (!g_Battle.rgEnemy[wEnemyIndex].fDualMove)   {      PAL_BattleBackupStat();      for (i = 0; i < MAX_POISONS; i++)      {         if (g_Battle.rgEnemy[wEnemyIndex].rgPoisons[i].wPoisonID != 0)         {            g_Battle.rgEnemy[wEnemyIndex].rgPoisons[i].wPoisonScript =               PAL_RunTriggerScript(g_Battle.rgEnemy[wEnemyIndex].rgPoisons[i].wPoisonScript, wEnemyIndex);         }      }      if (PAL_BattleDisplayStatChange())      {         PAL_BattleDelay(6, 0, FALSE);      }   }   PAL_BattlePostActionCheck(FALSE);   //   // Update statuses   //   for (i = 0; i < kStatusAll; i++)   {      if (g_Battle.rgEnemy[wEnemyIndex].rgwStatus[i] > 0)      {         g_Battle.rgEnemy[wEnemyIndex].rgwStatus[i]--;      }   }#else   i = 0; // do nothing#endif}VOIDPAL_BattleStealFromEnemy(   WORD           wTarget,   WORD           wStealRate)/*++  Purpose:    Steal from the enemy.  Parameters:    [IN]  wTarget - the target enemy index.    [IN]  wStealRate - the rate of successful theft.  Return value:    None.--*/{   int   iPlayerIndex = g_Battle.wMovingPlayerIndex;   int   offset, x, y, i;   WCHAR s[256] = L"";   g_Battle.rgPlayer[iPlayerIndex].wCurrentFrame = 10;   offset = ((INT)wTarget - iPlayerIndex) * 8;   x = PAL_X(g_Battle.rgEnemy[wTarget].pos) + 64 - offset;   y = PAL_Y(g_Battle.rgEnemy[wTarget].pos) + 20 - offset / 2;   g_Battle.rgPlayer[iPlayerIndex].pos = PAL_XY(x, y);   PAL_BattleDelay(1, 0, TRUE);   for (i = 0; i < 5; i++)   {      x -= i + 8;      y -= 4;      g_Battle.rgPlayer[iPlayerIndex].pos = PAL_XY(x, y);      if (i == 4)      {         g_Battle.rgEnemy[wTarget].iColorShift = 6;      }      PAL_BattleDelay(1, 0, TRUE);   }   g_Battle.rgEnemy[wTarget].iColorShift = 0;   x--;   g_Battle.rgPlayer[iPlayerIndex].pos = PAL_XY(x, y);   PAL_BattleDelay(3, 0, TRUE);   g_Battle.rgPlayer[iPlayerIndex].state = kFighterWait;   g_Battle.rgPlayer[iPlayerIndex].flTimeMeter = 0;   PAL_BattleUpdateFighters();   PAL_BattleDelay(1, 0, TRUE);   if (g_Battle.rgEnemy[wTarget].e.nStealItem > 0 &&      (RandomLong(0, 10) <= wStealRate || wStealRate == 0))   {      if (g_Battle.rgEnemy[wTarget].e.wStealItem == 0)      {         //         // stolen coins         //         int c = g_Battle.rgEnemy[wTarget].e.nStealItem / RandomLong(2, 3);         g_Battle.rgEnemy[wTarget].e.nStealItem -= c;         gpGlobals->dwCash += c;         if (c > 0)         {            swprintf(s, 256, L"%s %d %s", PAL_GetWord(34), c, PAL_GetWord(10));         }      }      else      {         //         // stolen item         //         g_Battle.rgEnemy[wTarget].e.nStealItem--;         PAL_AddItemToInventory(g_Battle.rgEnemy[wTarget].e.wStealItem, 1);		 wcscpy(s, PAL_GetWord(34));         wcscat(s, PAL_GetWord(g_Battle.rgEnemy[wTarget].e.wStealItem));	  }      if (s[0] != '\0')      {#ifdef PAL_CLASSIC         PAL_StartDialog(kDialogCenterWindow, 0, 0, FALSE);         PAL_ShowDialogText(s);#else         PAL_BattleUIShowText(s, 800);#endif      }   }}VOIDPAL_BattleSimulateMagic(   SHORT      sTarget,   WORD       wMagicObjectID,   WORD       wBaseDamage)/*++  Purpose:    Simulate a magic for players. Mostly used in item throwing script.  Parameters:    [IN]  sTarget - the target enemy index. -1 = all enemies.    [IN]  wMagicObjectID - the object ID of the magic to be simulated.    [IN]  wBaseDamage - the base damage of the simulation.  Return value:    None.--*/{   SHORT   sDamage;   int     i, def;   if (gpGlobals->g.rgObject[wMagicObjectID].magic.wFlags & kMagicFlagApplyToAll)   {      sTarget = -1;   }   else if (sTarget == -1)   {      sTarget = PAL_BattleSelectAutoTarget();   }   //   // Show the magic animation   //   PAL_BattleShowPlayerOffMagicAnim(0xFFFF, wMagicObjectID, sTarget, FALSE);   if (gpGlobals->g.lprgMagic[gpGlobals->g.rgObject[wMagicObjectID].magic.wMagicNumber].wBaseDamage > 0 ||      wBaseDamage > 0)   {      if (sTarget == -1)      {         //         // Apply to all enemies         //         for (i = 0; i <= g_Battle.wMaxEnemyIndex; i++)         {            if (g_Battle.rgEnemy[i].wObjectID == 0)            {               continue;            }            def = (SHORT)g_Battle.rgEnemy[i].e.wDefense;            def += (g_Battle.rgEnemy[i].e.wLevel + 6) * 4;            if (def < 0)            {               def = 0;            }            sDamage = PAL_CalcMagicDamage(wBaseDamage, (WORD)def, g_Battle.rgEnemy[i].e.wElemResistance,               g_Battle.rgEnemy[i].e.wPoisonResistance, wMagicObjectID);            if (sDamage < 0)            {               sDamage = 0;            }            g_Battle.rgEnemy[i].e.wHealth -= sDamage;         }      }      else      {         //         // Apply to one enemy         //         def = (SHORT)g_Battle.rgEnemy[sTarget].e.wDefense;         def += (g_Battle.rgEnemy[sTarget].e.wLevel + 6) * 4;         if (def < 0)         {            def = 0;         }         sDamage = PAL_CalcMagicDamage(wBaseDamage, (WORD)def, g_Battle.rgEnemy[sTarget].e.wElemResistance,            g_Battle.rgEnemy[sTarget].e.wPoisonResistance, wMagicObjectID);         if (sDamage < 0)         {            sDamage = 0;         }         g_Battle.rgEnemy[sTarget].e.wHealth -= sDamage;      }   }}
 |