DLLInterface.cpp 222 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /*
  15. ** DLLInterfac.cpp
  16. **
  17. ** This is where we implement the API expected by the Instance Server.
  18. **
  19. ** The Instance Server will pass in requests for loading and starting maps, control input from players,
  20. ** and requests for game simulation and rendering states.
  21. **
  22. **
  23. */
  24. #include <stdio.h>
  25. #include "function.h"
  26. #include "externs.h"
  27. #include "DLLInterface.h"
  28. #include "Gadget.h"
  29. #include "defines.h" // VOC_COUNT, VOX_COUNT
  30. #include "SidebarGlyphx.h"
  31. /*
  32. ** Externs
  33. */
  34. extern int DLL_Startup(const char * command_line);
  35. extern void Reallocate_Big_Shape_Buffer(void);
  36. extern bool ProgEndCalled;
  37. extern int Write_PCX_File(char* name, GraphicViewPortClass& pic, unsigned char* palette );
  38. extern bool Color_Cycle(void);
  39. /*
  40. ** Prototypes and constants
  41. */
  42. bool Debug_Write_Shape_Type(const ObjectTypeClass *type, int shapenum);
  43. bool Debug_Write_Shape(const char *file_name, void const * shapefile, int shapenum, int flags = 0, void const * ghostdata = NULL);
  44. typedef void (__cdecl* CNC_Event_Callback_Type)(const EventCallbackStruct &event);
  45. typedef unsigned __int64 uint64;
  46. typedef __int64 int64;
  47. /*
  48. ** Audio defines
  49. **
  50. **
  51. **
  52. **
  53. **
  54. */
  55. // For compatibility with Watcom in audio enums
  56. #pragma warning (disable : 4091)
  57. // From TiberianDawn\Audio.cpp
  58. enum ContextType;
  59. extern struct SoundEffectNameStruct {
  60. char const *Name; // Digitized voice file name.
  61. int Priority; // Playback priority of this sample.
  62. ContextType Where; // In what game context does this sample exist.
  63. } SoundEffectName[VOC_COUNT];
  64. // From TiberianDawn\Audio.cpp
  65. extern char const* Speech[VOX_COUNT];
  66. // From TiberianDawn\Audio.cpp
  67. typedef enum {
  68. IN_NOVAR, // No variation or alterations allowed.
  69. IN_JUV, // Juvenile sound effect alternate option.
  70. IN_VAR, // Infantry variance response modification.
  71. };
  72. /*
  73. ** Misc defines
  74. **
  75. **
  76. **
  77. **
  78. **
  79. */
  80. #define RANDOM_START_POSITION 0x7f
  81. #define KILL_PLAYER_ON_DISCONNECT 1
  82. /*
  83. ** DLL Interface
  84. **
  85. **
  86. **
  87. **
  88. **
  89. */
  90. extern "C" __declspec(dllexport) unsigned int __cdecl CNC_Version(unsigned int version_in);
  91. extern "C" __declspec(dllexport) void __cdecl CNC_Init(const char *command_line, CNC_Event_Callback_Type event_callback);
  92. extern "C" __declspec(dllexport) void __cdecl CNC_Config(const CNCRulesDataStruct& rules);
  93. extern "C" __declspec(dllexport) void __cdecl CNC_Add_Mod_Path(const char *mod_path);
  94. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Visible_Page(unsigned char *buffer_in, unsigned int &width, unsigned int &height);
  95. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Palette(unsigned char(&palette_in)[256][3]);
  96. extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Instance(int scenario_index, int build_level, const char *faction, const char *game_type, const char *content_directory, int sabotaged_structure, const char *override_map_name);
  97. extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Instance_Variation(int scenario_index, int scenario_variation, int scenario_direction, int build_level, const char *faction, const char *game_type, const char *content_directory, int sabotaged_structure, const char *override_map_name);
  98. extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Custom_Instance(const char* content_directory, const char* directory_path, const char* scenario_name, int build_level, bool multiplayer);
  99. extern "C" __declspec(dllexport) bool __cdecl CNC_Advance_Instance(uint64 player_id);
  100. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Game_State(GameStateRequestEnum state_type, uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  101. extern "C" __declspec(dllexport) bool __cdecl CNC_Read_INI(int scenario_index, int scenario_variation, int scenario_direction, const char *content_directory, const char *override_map_name, char *ini_buffer, int _ini_buffer_size);
  102. extern "C" __declspec(dllexport) void __cdecl CNC_Set_Home_Cell(int x, int y, uint64 player_id);
  103. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Request(GameRequestEnum request_type);
  104. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Settings_Request(int health_bar_display_mode, int resource_bar_display_mode);
  105. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Input(InputRequestEnum mouse_event, unsigned char special_key_flags, uint64 player_id, int x1, int y1, int x2, int y2);
  106. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Structure_Request(StructureRequestEnum request_type, uint64 player_id, int object_id);
  107. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Unit_Request(UnitRequestEnum request_type, uint64 player_id);
  108. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(SidebarRequestEnum request_type, uint64 player_id, int buildable_type, int buildable_id, short cell_x, short cell_y);
  109. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_SuperWeapon_Request(SuperWeaponRequestEnum request_type, uint64 player_id, int buildable_type, int buildable_id, int x1, int y1);
  110. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_ControlGroup_Request(ControlGroupRequestEnum request_type, uint64 player_id, unsigned char control_group_index);
  111. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Debug_Request(DebugRequestEnum debug_request_type, uint64 player_id, const char *object_name, int x, int y, bool unshroud, bool enemy);
  112. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y);
  113. extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scenario_index, CNCMultiplayerOptionsStruct &game_options, int num_players, CNCPlayerInfoStruct *player_list, int max_players);
  114. extern "C" __declspec(dllexport) bool __cdecl CNC_Clear_Object_Selection(uint64 player_id);
  115. extern "C" __declspec(dllexport) bool __cdecl CNC_Select_Object(uint64 player_id, int object_type_id, int object_to_select_id);
  116. extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const char *file_path_and_name, const char *game_type);
  117. extern "C" __declspec(dllexport) void __cdecl CNC_Set_Difficulty(int difficulty);
  118. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uint64 player_id);
  119. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Human_Team_Wins(uint64 player_id);
  120. extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time);
  121. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index);
  122. /*
  123. ** Class to implement the interface, and contain additional game state required by the conversion from peer/peer to client/server
  124. **
  125. **
  126. **
  127. **
  128. **
  129. */
  130. class DLLExportClass {
  131. public:
  132. static void Init(void);
  133. static void Shutdown(void);
  134. static void Config(const CNCRulesDataStruct& rules);
  135. static void Add_Mod_Path(const char *mod_path);
  136. static void Set_Home_Cell(int x, int y, uint64 player_id);
  137. static void Set_Content_Directory(const char *dir);
  138. static bool Get_Layer_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  139. static bool Get_Sidebar_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  140. static bool Start_Construction(uint64 player_id, int buildable_type, int buildable_id);
  141. static bool Hold_Construction(uint64 player_id, int buildable_type, int buildable_id);
  142. static bool Cancel_Construction(uint64 player_id, int buildable_type, int buildable_id);
  143. static bool Start_Placement(uint64 player_id, int buildable_type, int buildable_id);
  144. static BuildingClass *Get_Pending_Placement_Object(uint64 player_id, int buildable_type, int buildable_id);
  145. static bool Get_Placement_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  146. static void Convert_Type(const ObjectClass *object, CNCObjectStruct &object_out);
  147. static void DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, ObjectClass *object, const char *shape_file_name = NULL, char override_owner = HOUSE_NONE, int scale = 0x100);
  148. static void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip);
  149. static void DLL_Draw_Line_Intercept(int x, int y, int x1, int y1, unsigned char color, int frame);
  150. static bool Place(uint64 player_id, int buildable_type, int buildable_id, short cell_x, short cell_y);
  151. static bool Cancel_Placement(uint64 player_id, int buildable_type, int buildable_id);
  152. static bool Place_Super_Weapon(uint64 player_id, int buildable_type, int buildable_id, int x, int y);
  153. static bool Create_Control_Group(unsigned char control_group_index);
  154. static bool Add_To_Control_Group(unsigned char control_group_index);
  155. static bool Toggle_Control_Group_Selection(unsigned char control_group_index);
  156. static bool Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id);
  157. static bool MP_Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id);
  158. static bool Passes_Proximity_Check(CELL cell_in, BuildingTypeClass *placement_type, unsigned char* placement_distance);
  159. static void Calculate_Start_Positions(void);
  160. static void Computer_Message(bool last_player_taunt);
  161. static void Repair_Mode(uint64 player_id);
  162. static void Repair(uint64 player_id, int object_id);
  163. static void Sell_Mode(uint64 player_id);
  164. static void Sell(uint64 player_id, int object_id);
  165. static void Repair_Sell_Cancel(uint64 player_id);
  166. static void Scatter_Selected(uint64 player_id);
  167. static void Select_Next_Unit(uint64 player_id);
  168. static void Select_Previous_Unit(uint64 player_id);
  169. static void Selected_Guard_Mode(uint64 player_id);
  170. static void Selected_Stop(uint64 player_id);
  171. static void Team_Units_Formation_Toggle_On(uint64 player_id);
  172. static void Units_Queued_Movement_Toggle(uint64 player_id, bool toggle);
  173. static void Cell_Class_Draw_It(CNCDynamicMapStruct *dynamic_map, int &entry_index, CellClass *cell_ptr, int xpixel, int ypixel, bool debug_output);
  174. static bool Get_Dynamic_Map_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  175. static bool Get_Shroud_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  176. static bool Get_Occupier_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  177. static bool Get_Player_Info_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
  178. static void Set_Event_Callback(CNC_Event_Callback_Type event_callback) {EventCallback = event_callback;}
  179. static void Debug_Spawn_Unit(const char *object_name, int x, int y, bool enemy = false);
  180. static void Debug_Spawn_All(int x, int y);
  181. static bool Try_Debug_Spawn_Unlimbo(TechnoClass *techno, int &cell_x, int &cell_y);
  182. static void Debug_Kill_Unit(int x, int y);
  183. static void Debug_Heal_Unit(int x, int y);
  184. static void On_Play_Movie(const char * movie_name, ThemeType theme, bool immediate);
  185. static void On_Display_Briefing_Text();
  186. static void On_Sound_Effect(const HouseClass* player_ptr, int sound_effect_index, const char* extension, int variation, COORDINATE coord);
  187. static void On_Speech(const HouseClass* player_ptr, int speech_index);
  188. static void On_Game_Over(uint64 glyphx_player_id, bool player_wins);
  189. static void On_Multiplayer_Game_Over(void);
  190. static void On_Message(const HouseClass* player_ptr, const char* message, float timeout_seconds, EventCallbackMessageEnum message_type, int64 message_id);
  191. static void On_Debug_Output(const char *debug_text);
  192. static void On_Achievement(const HouseClass* player_ptr, const char *achievement_type, const char *achievement_reason);
  193. static void On_Center_Camera(const HouseClass* player_ptr, int coord_x, int coord_y);
  194. static void On_Ping(const HouseClass* player_ptr, COORDINATE coord);
  195. static void Glyphx_Queue_AI();
  196. static void Force_Human_Team_Wins(uint64 quitting_player_id);
  197. /*
  198. ** Player context switching for input/output
  199. */
  200. static bool Set_Player_Context(uint64 glyphx_player, bool force = false);
  201. static void Reset_Player_Context(void);
  202. static void Adjust_Internal_View(bool force_ignore_view_constraints = false);
  203. static void Logic_Switch_Player_Context(ObjectClass *object);
  204. static void Logic_Switch_Player_Context(HouseClass *house);
  205. static __int64 Get_GlyphX_Player_ID(const HouseClass *house);
  206. static void Recalculate_Placement_Distances();
  207. static void Reset_Sidebars(void);
  208. static SidebarGlyphxClass *Get_Current_Context_Sidebar(HouseClass *player_ptr = NULL);
  209. static uint64 GlyphxPlayerIDs[MAX_PLAYERS];
  210. static const void *Get_Shadow_Shapes(void) {return Map.ShadowShapes;}
  211. static const unsigned char *Get_Shadow_Trans(void) {return &Map.ShadowTrans[0];}
  212. static bool Legacy_Render_Enabled(void);
  213. static bool Get_Input_Key_State(KeyNumType key);
  214. static void Set_Special_Key_Flags(unsigned char special_key_flags);
  215. static void Clear_Special_Key_Flags();
  216. static bool Load(FileClass & file);
  217. static bool Save(FileClass & file);
  218. static void Code_Pointers(void);
  219. static void Decode_Pointers(void);
  220. static bool Get_Game_Over() { return GameOver; }
  221. private:
  222. static void Calculate_Single_Player_Score(EventCallbackStruct&);
  223. static unsigned int TD_Calculate_Efficiency( unsigned int harvested_credits, unsigned int initial_credits, unsigned int available_credits );
  224. static unsigned int TD_Calculate_Leadership( int house, unsigned int units_lost, unsigned int buildings_lost );
  225. static unsigned int TD_Calculate_Score( unsigned int leadership, unsigned int efficiency, unsigned int build_level );
  226. static void Convert_Action_Type(ActionType type, ObjectClass* object, TARGET target, DllActionTypeEnum& dll_type);
  227. static void Calculate_Placement_Distances(BuildingTypeClass* placement_type, unsigned char* placement_distance);
  228. static int CurrentDrawCount;
  229. static int TotalObjectCount;
  230. static int SortOrder;
  231. static int ExportLayer;
  232. static CNCObjectListStruct *ObjectList;
  233. static CNC_Event_Callback_Type EventCallback;
  234. static int CurrentLocalPlayerIndex;
  235. static bool GameOver;
  236. /*
  237. ** Pseudo sidebars for players in multiplayer
  238. */
  239. static SidebarGlyphxClass MultiplayerSidebars[MAX_PLAYERS];
  240. static CELL MultiplayerStartPositions[MAX_PLAYERS];
  241. static BuildingTypeClass *PlacementType[MAX_PLAYERS];
  242. static unsigned char PlacementDistance[MAX_PLAYERS][MAP_CELL_TOTAL];
  243. static unsigned char SpecialKeyFlags[MAX_PLAYERS];
  244. /*
  245. ** Mod directories
  246. */
  247. static DynamicVectorClass<char *> ModSearchPaths;
  248. };
  249. /*
  250. ** DLLExportClass static data
  251. **
  252. **
  253. **
  254. **
  255. **
  256. */
  257. int DLLExportClass::CurrentDrawCount = 0;
  258. int DLLExportClass::TotalObjectCount = 0;
  259. int DLLExportClass::SortOrder = 0;
  260. int DLLExportClass::ExportLayer = 0;
  261. CNCObjectListStruct *DLLExportClass::ObjectList = NULL;
  262. SidebarGlyphxClass DLLExportClass::MultiplayerSidebars [MAX_PLAYERS];
  263. uint64 DLLExportClass::GlyphxPlayerIDs[MAX_PLAYERS] = {0xffffffffl};
  264. int DLLExportClass::CurrentLocalPlayerIndex = -1;
  265. CELL DLLExportClass::MultiplayerStartPositions[MAX_PLAYERS];
  266. BuildingTypeClass *DLLExportClass::PlacementType[MAX_PLAYERS];
  267. unsigned char DLLExportClass::PlacementDistance[MAX_PLAYERS][MAP_CELL_TOTAL];
  268. unsigned char DLLExportClass::SpecialKeyFlags[MAX_PLAYERS] = { 0U };
  269. DynamicVectorClass<char *> DLLExportClass::ModSearchPaths;
  270. bool DLLExportClass::GameOver = false;
  271. /*
  272. ** Global variables
  273. **
  274. **
  275. **
  276. **
  277. **
  278. */
  279. int DLLForceMouseX = 0;
  280. int DLLForceMouseY = 0;
  281. CNC_Event_Callback_Type DLLExportClass::EventCallback = NULL;
  282. // Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
  283. int GlyphXClientSidebarWidthInLeptons = 0;
  284. bool MPlayerIsHuman[MAX_PLAYERS];
  285. int MPlayerTeamIDs[MAX_PLAYERS];
  286. int MPlayerStartLocations[MAX_PLAYERS];
  287. bool ShareAllyVisibility = true;
  288. void Play_Movie_GlyphX(const char * movie_name, ThemeType theme)
  289. {
  290. if ((movie_name[0] == 'x' || movie_name[0] == 'X') && movie_name[1] == 0) {
  291. return;
  292. }
  293. DLLExportClass::On_Play_Movie(movie_name, theme, false);
  294. }
  295. void On_Sound_Effect(int sound_index, int variation, COORDINATE coord)
  296. {
  297. int voc = sound_index;
  298. if (voc == VOC_NONE)
  299. {
  300. return;
  301. }
  302. // Borrowed from AUDIO.CPP Sound_Effect()
  303. //
  304. #if 1
  305. char const * ext = ""; // ".AUD";
  306. if (Special.IsJuvenile && SoundEffectName[voc].Where == IN_JUV) {
  307. ext = ".JUV";
  308. } else {
  309. if (SoundEffectName[voc].Where == IN_VAR) {
  310. /*
  311. ** For infantry, use a variation on the response. For vehicles, always
  312. ** use the vehicle response table.
  313. */
  314. if (variation < 0) {
  315. if (ABS(variation) % 2) {
  316. ext = ".V00";
  317. } else {
  318. ext = ".V02";
  319. }
  320. } else {
  321. if (variation % 2) {
  322. ext = ".V01";
  323. } else {
  324. ext = ".V03";
  325. }
  326. }
  327. }
  328. }
  329. #endif
  330. DLLExportClass::On_Sound_Effect(PlayerPtr, sound_index, ext, variation, coord);
  331. }
  332. void On_Speech(int speech_index, HouseClass *house)
  333. {
  334. if (house == NULL) {
  335. DLLExportClass::On_Speech(PlayerPtr, speech_index);
  336. }
  337. else
  338. {
  339. DLLExportClass::On_Speech(house, speech_index);
  340. }
  341. }
  342. void On_Ping(const HouseClass* player_ptr, COORDINATE coord)
  343. {
  344. DLLExportClass::On_Ping(player_ptr, coord);
  345. }
  346. void GlyphX_Debug_Print(const char *debug_text)
  347. {
  348. DLLExportClass::On_Debug_Output(debug_text);
  349. }
  350. void On_Achievement_Event(const HouseClass* player_ptr, const char *achievement_type, const char *achievement_reason)
  351. {
  352. DLLExportClass::On_Achievement(player_ptr, achievement_type, achievement_reason);
  353. }
  354. /**************************************************************************************************
  355. * CNC_Version -- Check DLL/Server version
  356. *
  357. * In: Version expected
  358. *
  359. * Out: Actual version
  360. *
  361. *
  362. *
  363. * History: 4/9/2020 2:12PM - ST
  364. **************************************************************************************************/
  365. extern "C" __declspec(dllexport) unsigned int __cdecl CNC_Version(unsigned int version_in)
  366. {
  367. // Unreferenced, but potentially useful to know which version the server is expecting
  368. version_in;
  369. return CNC_DLL_API_VERSION;
  370. }
  371. /**************************************************************************************************
  372. * CNC_Init -- Initialize the .DLL
  373. *
  374. * In: Command line
  375. *
  376. * Out:
  377. *
  378. *
  379. *
  380. * History: 1/3/2019 11:33AM - ST
  381. **************************************************************************************************/
  382. extern "C" __declspec(dllexport) void __cdecl CNC_Init(const char *command_line, CNC_Event_Callback_Type event_callback)
  383. {
  384. DLLExportClass::Set_Content_Directory(NULL);
  385. DLL_Startup(command_line);
  386. DLLExportClass::Set_Event_Callback( event_callback );
  387. DLLExportClass::Init();
  388. }
  389. /**************************************************************************************************
  390. * DLL_Shutdown -- Shutdown the .DLL
  391. *
  392. * In:
  393. *
  394. * Out:
  395. *
  396. *
  397. *
  398. * History: 2/20/2020 1:58PM - ST
  399. **************************************************************************************************/
  400. void DLL_Shutdown(void)
  401. {
  402. DLLExportClass::Shutdown();
  403. }
  404. /**************************************************************************************************
  405. * CNC_Config -- Configure the plugin
  406. *
  407. * In: Configuration data
  408. *
  409. * Out:
  410. *
  411. *
  412. *
  413. * History: 10/03/2019 - SKY
  414. **************************************************************************************************/
  415. extern "C" __declspec(dllexport) void __cdecl CNC_Config(const CNCRulesDataStruct& rules)
  416. {
  417. DLLExportClass::Config(rules);
  418. }
  419. /**************************************************************************************************
  420. * CNC_Add_Mod_Path -- Add a path to load mod files from
  421. *
  422. * In: Path to load mods from
  423. *
  424. * Out:
  425. *
  426. *
  427. *
  428. * History: 2/20/2020 2:04PM - ST
  429. **************************************************************************************************/
  430. extern "C" __declspec(dllexport) void __cdecl CNC_Add_Mod_Path(const char *mod_path)
  431. {
  432. DLLExportClass::Add_Mod_Path(mod_path);
  433. }
  434. /**************************************************************************************************
  435. * CNC_Get_Visible_Page -- Get the screen buffer 'SeenBuff' from the game
  436. *
  437. * In: If buffer_in is null, just return info about page
  438. *
  439. * Out: false if not changed since last call
  440. *
  441. *
  442. *
  443. * History: 1/3/2019 11:33AM - ST
  444. **************************************************************************************************/
  445. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Visible_Page(unsigned char *buffer_in, unsigned int &width, unsigned int &height)
  446. {
  447. if (!DLLExportClass::Legacy_Render_Enabled() || (buffer_in == NULL)) {
  448. return false;
  449. }
  450. /*
  451. ** Assume the seen page viewport is the same size as the page
  452. */
  453. GraphicBufferClass *gbuffer = HidPage.Get_Graphic_Buffer();
  454. if (gbuffer == NULL) {
  455. return false;
  456. }
  457. int view_port_width = Map.MapCellWidth * CELL_PIXEL_W;
  458. int view_port_height = Map.MapCellHeight * CELL_PIXEL_H;
  459. if (view_port_width == 0 || view_port_height == 0) {
  460. return false;
  461. }
  462. unsigned char *raw_buffer = (unsigned char*) gbuffer->Get_Buffer();
  463. long raw_size = gbuffer->Get_Size();
  464. if (raw_buffer == NULL || gbuffer->Get_Width() < view_port_width || gbuffer->Get_Height() < view_port_height) {
  465. return false;
  466. }
  467. width = view_port_width;
  468. height = view_port_height;
  469. int pitch = gbuffer->Get_Width();
  470. for (int i = 0; i < view_port_height; ++i, buffer_in += view_port_width, raw_buffer += pitch) {
  471. memcpy(buffer_in, raw_buffer, view_port_width);
  472. }
  473. return true;
  474. }
  475. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Palette(unsigned char(&palette_in)[256][3])
  476. {
  477. memcpy(palette_in, CurrentPalette, sizeof(palette_in));
  478. return true;
  479. }
  480. /**************************************************************************************************
  481. * CNC_Set_Multiplayer_Data -- Set up for a multiplayer match
  482. *
  483. * In: Multiplayer data
  484. *
  485. * Out: false if data is bad
  486. *
  487. *
  488. *
  489. * History: 1/7/2019 5:20PM - ST
  490. **************************************************************************************************/
  491. extern "C" __declspec(dllexport) bool __cdecl CNC_Set_Multiplayer_Data(int scenario_index, CNCMultiplayerOptionsStruct &game_options, int num_players, CNCPlayerInfoStruct *player_list, int max_players)
  492. {
  493. if (num_players <= 0) {
  494. return false;
  495. }
  496. if (num_players > min(MAX_PLAYERS, max_players)) {
  497. return false;
  498. }
  499. DLLExportClass::Init();
  500. //MPlayerPrefColor; // preferred color index for this player
  501. //MPlayerColorIdx; // actual color index of this player
  502. //MPlayerHouse; // House of this player (GDI/NOD)
  503. //MPlayerLocalID; // ID of this player
  504. MPlayerCount = num_players; // # of human players in this game
  505. MPlayerBases = game_options.MPlayerBases; // 1 = bases are on for this scenario
  506. MPlayerCredits = game_options.MPlayerCredits; // # credits everyone gets
  507. MPlayerTiberium = game_options.MPlayerTiberium; // 1 = tiberium enabled for this scenario
  508. MPlayerGoodies = game_options.MPlayerGoodies; // 1 = goodies enabled for this scenario
  509. MPlayerGhosts = game_options.MPlayerGhosts; // 1 = houses with no players will still play
  510. MPlayerSolo = game_options.MPlayerSolo; // 1 = allows a single-player net game
  511. MPlayerUnitCount = game_options.MPlayerUnitCount; // # units for non-base multiplayer scenarios
  512. Special.IsMCVDeploy = game_options.IsMCVDeploy;
  513. Special.IsVisceroids = game_options.SpawnVisceroids;
  514. Special.IsCaptureTheFlag = game_options.CaptureTheFlag;
  515. Special.IsEarlyWin = game_options.DestroyStructures;
  516. Special.ModernBalance = game_options.ModernBalance;
  517. Rule.AllowSuperWeapons = game_options.EnableSuperweapons; // Are superweapons available
  518. if (MPlayerTiberium) {
  519. Special.IsTGrowth = 1;
  520. Special.IsTSpread = 1;
  521. } else {
  522. Special.IsTGrowth = 0;
  523. Special.IsTSpread = 0;
  524. }
  525. Scenario = scenario_index;
  526. MPlayerCount = 0;
  527. for (int i=0 ; i<num_players ; i++) {
  528. CNCPlayerInfoStruct &player_info = player_list[i];
  529. MPlayerHouses[i] = (HousesType) player_info.House;
  530. strncpy(MPlayerNames[i], player_info.Name, MPLAYER_NAME_MAX);
  531. MPlayerNames[i][MPLAYER_NAME_MAX - 1] = 0; // Make sure it's terminated
  532. MPlayerID[i] = Build_MPlayerID(player_info.ColorIndex, (HousesType)player_info.House);
  533. DLLExportClass::GlyphxPlayerIDs[i] = player_info.GlyphxPlayerID;
  534. MPlayerIsHuman[i] = !player_info.IsAI;
  535. if (player_info.IsAI) {
  536. MPlayerGhosts = true;
  537. }
  538. MPlayerTeamIDs[i] = player_info.Team;
  539. MPlayerStartLocations[i] = player_info.StartLocationIndex;
  540. /*
  541. ** Temp fix for custom maps that don't have valid start positions set from matchmaking
  542. */
  543. if (i > 0 && MPlayerStartLocations[i] == 0 && MPlayerStartLocations[0] == 0) {
  544. MPlayerStartLocations[i] = i;
  545. }
  546. MPlayerCount++;
  547. }
  548. /*
  549. ** We need some default for the local ID in order to have a valid PlayerPtr during scenario load. ST - 4/24/2019 10:33AM
  550. */
  551. MPlayerLocalID = MPlayerID[0];
  552. return true;
  553. }
  554. extern "C" __declspec(dllexport) bool __cdecl CNC_Clear_Object_Selection(uint64 player_id)
  555. {
  556. if (!DLLExportClass::Set_Player_Context(player_id)) {
  557. return false;
  558. }
  559. Unselect_All();
  560. return true;
  561. }
  562. extern "C" __declspec(dllexport) bool __cdecl CNC_Select_Object(uint64 player_id, int object_type_id, int object_to_select_id)
  563. {
  564. if (!DLLExportClass::Set_Player_Context(player_id)) {
  565. return false;
  566. }
  567. switch (object_type_id)
  568. {
  569. case INFANTRY:
  570. {
  571. for (int index = 0; index < Infantry.Count(); index++) {
  572. InfantryClass * obj = Infantry.Ptr(index);
  573. if (obj
  574. && !obj->IsInLimbo
  575. && obj->House == PlayerPtr
  576. && Infantry.ID((InfantryClass*)obj) == object_to_select_id)
  577. {
  578. if (!obj->Is_Selected_By_Player())
  579. {
  580. obj->Select();
  581. AllowVoice = false;
  582. }
  583. return true;
  584. }
  585. }
  586. }
  587. break;
  588. case UNIT:
  589. {
  590. for (int index = 0; index < Units.Count(); index++) {
  591. UnitClass * obj = Units.Ptr(index);
  592. if (obj
  593. && !obj->IsInLimbo
  594. && obj->House == PlayerPtr
  595. && Units.ID((UnitClass*)obj) == object_to_select_id)
  596. {
  597. if (!obj->Is_Selected_By_Player())
  598. {
  599. obj->Select();
  600. AllowVoice = false;
  601. }
  602. return true;
  603. }
  604. }
  605. }
  606. break;
  607. case AIRCRAFT:
  608. {
  609. for (int index = 0; index < Aircraft.Count(); index++) {
  610. AircraftClass * obj = Aircraft.Ptr(index);
  611. if (obj
  612. && !obj->IsInLimbo
  613. && obj->House == PlayerPtr
  614. && Aircraft.ID((AircraftClass*)obj) == object_to_select_id)
  615. {
  616. if (!obj->Is_Selected_By_Player())
  617. {
  618. obj->Select();
  619. AllowVoice = false;
  620. }
  621. return true;
  622. }
  623. }
  624. }
  625. break;
  626. case BUILDING:
  627. {
  628. for (int index = 0; index < Buildings.Count(); index++) {
  629. BuildingClass * obj = Buildings.Ptr(index);
  630. if (obj
  631. && !obj->IsInLimbo
  632. && obj->House == PlayerPtr
  633. && Buildings.ID((BuildingClass*)obj) == object_to_select_id)
  634. {
  635. if (!obj->Is_Selected_By_Player())
  636. {
  637. obj->Select();
  638. AllowVoice = false;
  639. }
  640. return true;
  641. }
  642. }
  643. }
  644. break;
  645. }
  646. return false;
  647. }
  648. /**************************************************************************************************
  649. * GlyphX_Assign_Houses -- Replacement for Assign_Houses in INI.CPP
  650. *
  651. * In:
  652. *
  653. * Out:
  654. *
  655. *
  656. *
  657. * History: 6/25/2019 11:09AM - ST
  658. **************************************************************************************************/
  659. void GlyphX_Assign_Houses(void)
  660. {
  661. HousesType house;
  662. HousesType pref_house;
  663. HouseClass *housep;
  664. bool house_used[MAX_PLAYERS]; // true = this house is in use
  665. bool color_used[16]; // true = this color is in use. We have more than 6 color options now, so bumped this to 16. ST - 6/19/2019 5:18PM
  666. bool preassigned;
  667. int i,j,random_start_location;
  668. PlayerColorType color;
  669. HousesType house2;
  670. HouseClass *housep2;
  671. srand(timeGetTime());
  672. /*
  673. ** Init the 'used' flag for all houses & colors to 0
  674. */
  675. for (i = 0; i < MAX_PLAYERS; i++) {
  676. house_used[i] = false;
  677. }
  678. for (i = 0; i < 16; i++) {
  679. color_used[i] = false;
  680. }
  681. /*
  682. ** Assign random start positions if needed.
  683. */
  684. int random_start_locations[26];
  685. int num_start_locations = 0;
  686. int num_random_start_locations = 0;
  687. for (i = 0; i < 26; i++) {
  688. if (Waypoint[i] != -1) {
  689. preassigned = false;
  690. for (j = 0; !preassigned && (j < MPlayerCount); j++) {
  691. if (MPlayerStartLocations[j] == num_start_locations) {
  692. preassigned = true;
  693. }
  694. }
  695. if (!preassigned && i < MAX_PLAYERS) {
  696. random_start_locations[num_random_start_locations] = num_start_locations;
  697. num_random_start_locations++;
  698. }
  699. num_start_locations++;
  700. }
  701. }
  702. if (num_random_start_locations > 1) {
  703. for (i = 0; i < num_random_start_locations - 1; i++) {
  704. j = i + rand() / (RAND_MAX / (num_random_start_locations - i) + 1);
  705. int t = random_start_locations[j];
  706. random_start_locations[j] = random_start_locations[i];
  707. random_start_locations[i] = t;
  708. }
  709. }
  710. /*
  711. ** For each player, randomly pick a house
  712. */
  713. random_start_location = 0;
  714. for (i = 0; i < MPlayerCount; i++) {
  715. j = Random_Pick(0, MPlayerMax-1);
  716. /*
  717. ** If this house was already selected, decrement 'i' & keep looping.
  718. */
  719. if (house_used[j]) {
  720. i--;
  721. continue;
  722. }
  723. /*
  724. ** Set the house, preferred house (GDI/NOD), color, and actual house;
  725. ** get a pointer to the house instance
  726. */
  727. house = (HousesType)(j + (int)HOUSE_MULTI1);
  728. pref_house = MPlayerID_To_HousesType(MPlayerID[i]);
  729. color = MPlayerID_To_ColorIndex(MPlayerID[i]);
  730. housep = HouseClass::As_Pointer(house);
  731. MPlayerHouses[i] = house;
  732. /*
  733. ** Mark this house & color as used
  734. */
  735. house_used[j] = true;
  736. color_used[color] = true;
  737. /*
  738. ** Set the house's IsHuman, Credits, ActLike, & RemapTable
  739. */
  740. memset((char *)housep->Name, 0, MPLAYER_NAME_MAX);
  741. strncpy((char *)housep->Name, MPlayerNames[i], MPLAYER_NAME_MAX-1);
  742. housep->IsHuman = MPlayerIsHuman[i];
  743. housep->Init_Data(color, pref_house, MPlayerCredits);
  744. /*
  745. ** Set the start location override
  746. */
  747. if (MPlayerStartLocations[i] != RANDOM_START_POSITION) {
  748. housep->StartLocationOverride = MPlayerStartLocations[i];
  749. } else {
  750. if (random_start_location < num_random_start_locations) {
  751. housep->StartLocationOverride = random_start_locations[random_start_location++];
  752. } else {
  753. housep->StartLocationOverride = -1;
  754. }
  755. }
  756. /*
  757. ** If this ID is for myself, set up PlayerPtr
  758. */
  759. if (MPlayerID[i] == MPlayerLocalID) {
  760. PlayerPtr = housep;
  761. }
  762. }
  763. /*
  764. ** From INI.CPP. Remove unused AI players.
  765. */
  766. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  767. if (house_used[i]) {
  768. continue;
  769. }
  770. house = (HousesType)(i + (int)HOUSE_MULTI1);
  771. housep = HouseClass::As_Pointer (house);
  772. if (housep && housep->IsHuman == false) {
  773. housep->Clobber_All();
  774. }
  775. }
  776. for (i = 0; i < MPlayerCount; i++) {
  777. house = MPlayerHouses[i];
  778. housep = HouseClass::As_Pointer(house);
  779. if (housep) {
  780. int team = MPlayerTeamIDs[i];
  781. for (int j=0 ; j<MPlayerCount ; j++) {
  782. if (i != j) {
  783. if (team == MPlayerTeamIDs[j]) {
  784. house2 = MPlayerHouses[j];
  785. housep2 = HouseClass::As_Pointer(house2);
  786. if (housep2) {
  787. housep->Make_Ally(house2);
  788. }
  789. }
  790. }
  791. }
  792. }
  793. }
  794. }
  795. /**************************************************************************************************
  796. * CNC_Start_Instance -- Load and start a cnc map to use WITHOUT a sceanrio variation (SCEN_VAR) or scenarion direction (SCEN_DIR)
  797. *
  798. * In: Map initialization parameters
  799. *
  800. * Out: false if map load failed
  801. *
  802. *
  803. *
  804. * History: 7/10/2019 - LLL
  805. **************************************************************************************************/
  806. extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Instance(int scenario_index, int build_level, const char *faction, const char *game_type, const char *content_directory, int sabotaged_structure, const char *override_map_name)
  807. {
  808. return CNC_Start_Instance_Variation(scenario_index, (int)SCEN_VAR_NONE, (int)SCEN_DIR_EAST, build_level, faction, game_type, content_directory, sabotaged_structure, override_map_name);
  809. }
  810. /**************************************************************************************************
  811. * HandleSabotagedStructure
  812. *
  813. * A port of the code from the original game code which is suppose to remove the main previously sabatoged building.
  814. * From what I can tell since it only stores the type it might remove a different building of the same type.
  815. * Watching the GDI longplay on YouTube the player destroys the refinery and yet it exists in the next level. Perhaps there are 2 refineries.
  816. *
  817. * History: 7/10/2019 - LLL
  818. **************************************************************************************************/
  819. void HandleSabotagedStructure(int structure_type)
  820. {
  821. SabotagedType = (StructType) structure_type;
  822. int index;
  823. if (SabotagedType != STRUCT_NONE && Scenario == 7 && PlayerPtr->Class->House == HOUSE_GOOD) {
  824. for (index = 0; index < Buildings.Count(); index++) {
  825. BuildingClass * building = Buildings.Ptr(index);
  826. if (building && !building->IsInLimbo && building->House != PlayerPtr && building->Class->Type == SabotagedType) {
  827. building->Limbo();
  828. delete building;
  829. break;
  830. }
  831. }
  832. /*
  833. ** Remove the building from the prebuild list.
  834. */
  835. for (index = 0; index < Base.Nodes.Count(); index++) {
  836. BaseNodeClass * node = Base.Get_Node(index);
  837. if (node && node->Type == SabotagedType) {
  838. Base.Nodes.Delete(index);
  839. break;
  840. }
  841. }
  842. }
  843. SabotagedType = STRUCT_NONE;
  844. }
  845. /**************************************************************************************************
  846. * CNC_Read_INI -- Load an ini file into the supplied buffer
  847. *
  848. * In: Map initialization parameters
  849. *
  850. * Out: false if ini load failed
  851. *
  852. *
  853. * History: 12/16/2019 11:44AM - ST
  854. **************************************************************************************************/
  855. extern "C" __declspec(dllexport) bool __cdecl CNC_Read_INI(int scenario_index, int scenario_variation, int scenario_direction, const char *content_directory, const char *override_map_name, char *ini_buffer, int _ini_buffer_size)
  856. {
  857. if (content_directory == NULL) {
  858. return false;
  859. }
  860. DLLExportClass::Set_Content_Directory(content_directory);
  861. // Hack a fix for scenario 21 since the same mission number is used in Covert Ops and N64
  862. Scenario = (scenario_index == 81) ? 21 : scenario_index;
  863. ScenVar = (ScenarioVarType)scenario_variation;
  864. ScenDir = (ScenarioDirType)scenario_direction;
  865. GameToPlay = GAME_GLYPHX_MULTIPLAYER;
  866. ScenPlayer = SCEN_PLAYER_MPLAYER;
  867. if (override_map_name && strlen(override_map_name)) {
  868. strcpy(ScenarioName, override_map_name);
  869. } else {
  870. Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, (ScenarioDirType)scenario_direction, (ScenarioVarType)scenario_variation);
  871. }
  872. if (_ini_buffer_size < _ShapeBufferSize) {
  873. GlyphX_Debug_Print("INI file buffer may be too small");
  874. return false;
  875. }
  876. if (!ini_buffer) {
  877. GlyphX_Debug_Print("No INI file buffer");
  878. return false;
  879. }
  880. memset(ini_buffer, _ini_buffer_size, 0);
  881. char fname[_MAX_PATH];
  882. sprintf(fname,"%s.INI", ScenarioName);
  883. CCFileClass file(fname);
  884. if (!file.Is_Available()) {
  885. GlyphX_Debug_Print("Failed to find scenario file");
  886. GlyphX_Debug_Print(fname);
  887. return(false);
  888. } else {
  889. GlyphX_Debug_Print("Opened scenario file");
  890. GlyphX_Debug_Print(fname);
  891. int bytes_read = file.Read(ini_buffer, _ini_buffer_size-1);
  892. if (bytes_read == _ini_buffer_size - 1) {
  893. GlyphX_Debug_Print("INI file buffer is too small");
  894. return false;
  895. }
  896. }
  897. /*
  898. ** Ini buffer should be zero terminated
  899. */
  900. if ((int) strlen(ini_buffer) >= _ini_buffer_size) {
  901. GlyphX_Debug_Print("INI file buffer overrun");
  902. return false;
  903. }
  904. return true;
  905. }
  906. /**************************************************************************************************
  907. * CNC_Set_Home_Cell -- Allows overriding the start position for the camera
  908. *
  909. *
  910. * History: 2/14/2020 - LLL
  911. **************************************************************************************************/
  912. extern "C" __declspec(dllexport) void __cdecl CNC_Set_Home_Cell(int x, int y, uint64 player_id)
  913. {
  914. DLLExportClass::Set_Home_Cell(x, y, player_id);
  915. }
  916. /**************************************************************************************************
  917. * CNC_Start_Instance -- Load and start a cnc map
  918. *
  919. * In: Map initialization parameters
  920. *
  921. * Out: false if map load failed
  922. *
  923. *
  924. * Renamed and modified to accept a scenario variation 7/10/2019 - LLL
  925. * Modified to accept a scenario direction 7/12/2019 - LLL
  926. *
  927. * History: 1/7/2019 5:20PM - ST
  928. **************************************************************************************************/
  929. extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Instance_Variation(int scenario_index, int scenario_variation, int scenario_direction, int build_level, const char *faction, const char *game_type, const char *content_directory, int sabotaged_structure, const char *override_map_name)
  930. {
  931. if (game_type == NULL) {
  932. return false;
  933. }
  934. if (faction == NULL) {
  935. return false;
  936. }
  937. if (content_directory == NULL) {
  938. return false;
  939. }
  940. if (stricmp(faction, "GDI") == 0) {
  941. ScenPlayer = SCEN_PLAYER_GDI;
  942. Whom = HOUSE_GOOD;
  943. }
  944. if (stricmp(faction, "NOD") == 0) {
  945. ScenPlayer = SCEN_PLAYER_NOD;
  946. Whom = HOUSE_BAD;
  947. }
  948. if (stricmp(faction, "Jurassic") == 0) {
  949. ScenPlayer = SCEN_PLAYER_JP;
  950. Whom = HOUSE_JP;
  951. Special.IsJurassic = true;
  952. AreThingiesEnabled = true;
  953. }
  954. DLLExportClass::Set_Content_Directory(content_directory);
  955. // Hack a fix for scenario 21 since the same mission number is used in Covert Ops and N64
  956. Scenario = (scenario_index == 81) ? 21 : scenario_index;
  957. BuildLevel = build_level;
  958. SabotagedType = (StructType)sabotaged_structure;
  959. ScenVar = (ScenarioVarType)scenario_variation;
  960. ScenDir = (ScenarioDirType)scenario_direction;
  961. if (stricmp(game_type, "GAME_NORMAL") == 0) {
  962. GameToPlay = GAME_NORMAL;
  963. } else {
  964. if (stricmp(game_type, "GAME_GLYPHX_MULTIPLAYER") == 0) {
  965. GameToPlay = GAME_GLYPHX_MULTIPLAYER;
  966. ScenPlayer = SCEN_PLAYER_MPLAYER;
  967. } else {
  968. return false;
  969. }
  970. }
  971. if (override_map_name && strlen(override_map_name)) {
  972. strcpy(ScenarioName, override_map_name);
  973. } else {
  974. Set_Scenario_Name(ScenarioName, Scenario, ScenPlayer, (ScenarioDirType)scenario_direction, (ScenarioVarType)scenario_variation);
  975. }
  976. HiddenPage.Clear();
  977. VisiblePage.Clear();
  978. /*
  979. ** Set the mouse to some position where it's not going to scroll, or do something else wierd.
  980. */
  981. DLLForceMouseX = 100;
  982. DLLForceMouseY = 100;
  983. _Kbd->MouseQX = 100;
  984. _Kbd->MouseQY = 100;
  985. GlyphXClientSidebarWidthInLeptons = 0;
  986. Seed = timeGetTime();
  987. if (!Start_Scenario(ScenarioName)) {
  988. return(false);
  989. }
  990. HandleSabotagedStructure(sabotaged_structure);
  991. DLLExportClass::Reset_Sidebars();
  992. DLLExportClass::Reset_Player_Context();
  993. /*
  994. ** Make sure the scroll constraints are applied. This is important for GDI 1 where the map isn't wide enough for the screen
  995. */
  996. COORDINATE origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(1, 0));
  997. Map.Set_Tactical_Position(origin_coord);
  998. origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(-1, 0));
  999. Map.Set_Tactical_Position(origin_coord);
  1000. DLLExportClass::Calculate_Start_Positions();
  1001. /*
  1002. ** Hide the SeenBuff; force the map to render one frame. The caller can
  1003. ** then fade the palette in.
  1004. ** (If we loaded a game, this step will fade out the title screen. If we
  1005. ** started a scenario, Start_Scenario() will have played a couple of VQ
  1006. ** movies, which will have cleared the screen to black already.)
  1007. */
  1008. //Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back);
  1009. HiddenPage.Clear();
  1010. VisiblePage.Clear();
  1011. Set_Logic_Page(SeenBuff);
  1012. Map.Flag_To_Redraw(true);
  1013. Map.Render();
  1014. Set_Palette(GamePalette);
  1015. return true;
  1016. }
  1017. /**************************************************************************************************
  1018. * CNC_Start_Custom_Instance --
  1019. *
  1020. *
  1021. *
  1022. *
  1023. * History: 2019/10/17 - JAS
  1024. **************************************************************************************************/
  1025. extern "C" __declspec(dllexport) bool __cdecl CNC_Start_Custom_Instance(const char* content_directory, const char* directory_path,
  1026. const char* scenario_name, int build_level, bool multiplayer)
  1027. {
  1028. if (content_directory == NULL) {
  1029. return false;
  1030. }
  1031. DLLExportClass::Set_Content_Directory(content_directory);
  1032. if (multiplayer) {
  1033. GameToPlay = GAME_GLYPHX_MULTIPLAYER;
  1034. ScenPlayer = SCEN_PLAYER_MPLAYER;
  1035. } else {
  1036. GameToPlay = GAME_NORMAL;
  1037. ScenPlayer = SCEN_PLAYER_GDI; // Don't think it matters since we are specifying the exact file to load
  1038. }
  1039. BuildLevel = build_level;
  1040. const int MAX_FILE_PATH = 1024;
  1041. char scenario_file_name[MAX_FILE_PATH];
  1042. char bin_file_name[MAX_FILE_PATH];
  1043. snprintf(scenario_file_name, MAX_FILE_PATH, "%s%s.INI", directory_path, scenario_name);
  1044. snprintf(bin_file_name, MAX_FILE_PATH, "%s%s.BIN", directory_path, scenario_name);
  1045. Seed = timeGetTime();
  1046. Clear_Scenario();
  1047. if (!Read_Scenario_Ini_File(scenario_file_name, bin_file_name, scenario_name, true)) {
  1048. return false;
  1049. }
  1050. HiddenPage.Clear();
  1051. VisiblePage.Clear();
  1052. /*
  1053. ** Set the mouse to some position where it's not going to scroll, or do something else wierd.
  1054. */
  1055. DLLForceMouseX = 100;
  1056. DLLForceMouseY = 100;
  1057. _Kbd->MouseQX = 100;
  1058. _Kbd->MouseQY = 100;
  1059. GlyphXClientSidebarWidthInLeptons = 0;
  1060. Play_Movie(IntroMovie);
  1061. Play_Movie(BriefMovie);
  1062. Play_Movie(ActionMovie, TransitTheme);
  1063. /*
  1064. if (!Start_Scenario(ScenarioName)) {
  1065. return(false);
  1066. }
  1067. */
  1068. DLLExportClass::Reset_Sidebars();
  1069. DLLExportClass::Reset_Player_Context();
  1070. /*
  1071. ** Make sure the scroll constraints are applied. This is important for GDI 1 where the map isn't wide enough for the screen
  1072. */
  1073. COORDINATE origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(1, 0));
  1074. Map.Set_Tactical_Position(origin_coord);
  1075. origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(-1, 0));
  1076. Map.Set_Tactical_Position(origin_coord);
  1077. DLLExportClass::Calculate_Start_Positions();
  1078. /*
  1079. ** Hide the SeenBuff; force the map to render one frame. The caller can
  1080. ** then fade the palette in.
  1081. ** (If we loaded a game, this step will fade out the title screen. If we
  1082. ** started a scenario, Start_Scenario() will have played a couple of VQ
  1083. ** movies, which will have cleared the screen to black already.)
  1084. */
  1085. //Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back);
  1086. HiddenPage.Clear();
  1087. VisiblePage.Clear();
  1088. Set_Logic_Page(SeenBuff);
  1089. Map.Flag_To_Redraw(true);
  1090. Map.Render();
  1091. Set_Palette(GamePalette);
  1092. return true;
  1093. }
  1094. bool Debug_Write_Shape_Type(const ObjectTypeClass *type, int shapenum)
  1095. {
  1096. char fullname[_MAX_FNAME+_MAX_EXT];
  1097. char buffer[_MAX_FNAME];
  1098. CCFileClass file;
  1099. if (type->ImageData != NULL) {
  1100. sprintf(buffer, "%s_%d", type->IniName, shapenum);
  1101. _makepath(fullname, NULL, NULL, buffer, ".PCX");
  1102. return Debug_Write_Shape(fullname, type->ImageData, shapenum);
  1103. }
  1104. return false;
  1105. }
  1106. bool Debug_Write_Shape(const char *file_name, void const * shapefile, int shapenum, int flags, void const * ghostdata)
  1107. {
  1108. /*
  1109. ** Build frame returns a pointer now instead of the shapes length
  1110. */
  1111. char *shape_pointer = (char*) Build_Frame(shapefile , shapenum , _ShapeBuffer);
  1112. if (shape_pointer == NULL) {
  1113. return false;;
  1114. }
  1115. if (Get_Last_Frame_Length() > _ShapeBufferSize) {
  1116. return false;;
  1117. }
  1118. int width = Get_Build_Frame_Width(shapefile);
  1119. int height = Get_Build_Frame_Height(shapefile);
  1120. GraphicBufferClass temp_gbuffer(width, height);
  1121. GraphicViewPortClass temp_viewport(&temp_gbuffer, 0, 0, width, height);
  1122. WindowList[WINDOW_CUSTOM][WINDOWX] = 0;
  1123. WindowList[WINDOW_CUSTOM][WINDOWY] = 0;
  1124. WindowList[WINDOW_CUSTOM][WINDOWWIDTH] = width;
  1125. WindowList[WINDOW_CUSTOM][WINDOWHEIGHT] = height;
  1126. static const char _shape_trans = 0x40;
  1127. if (flags == 0) {
  1128. Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, SHAPE_NORMAL|SHAPE_WIN_REL|_shape_trans); //, ghostdata, predoffset);
  1129. } else {
  1130. Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, flags, ghostdata);
  1131. }
  1132. Write_PCX_File((char*)file_name, temp_viewport, GamePalette);
  1133. return true;
  1134. }
  1135. /**************************************************************************************************
  1136. * CNC_Advance_Instance -- Process one logic frame
  1137. *
  1138. * In:
  1139. *
  1140. * Out: Is game still playing?
  1141. *
  1142. *
  1143. *
  1144. * History: 1/7/2019 5:20PM - ST
  1145. **************************************************************************************************/
  1146. extern "C" __declspec(dllexport) bool __cdecl CNC_Advance_Instance(uint64 player_id)
  1147. {
  1148. //DLLExportClass::Set_Event_Callback(event_callback);
  1149. InMainLoop = true;
  1150. if (Frame <= 10) { // Don't spam forever, but useful to know that we actually started advancing
  1151. GlyphX_Debug_Print("CNC_Advance_Instance - TD");
  1152. }
  1153. /*
  1154. ** Shouldn't really need to do this, but I like the idea of always running the main loop in the context of the same player.
  1155. ** Might make tbe bugs more repeatable and consistent. ST - 3/15/2019 11:58AM
  1156. */
  1157. if (player_id != 0) {
  1158. DLLExportClass::Set_Player_Context(player_id);
  1159. } else {
  1160. DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0]);
  1161. }
  1162. /*
  1163. ** Allocate extra memory for uncompressed shapes as needed
  1164. */
  1165. Reallocate_Big_Shape_Buffer();
  1166. /*
  1167. ** If there is no theme playing, but it looks like one is required, then start one
  1168. ** playing. This is usually the symptom of there being no transition score.
  1169. */
  1170. //if (SampleType && Theme.What_Is_Playing() == THEME_NONE) {
  1171. // Theme.Queue_Song(THEME_PICK_ANOTHER);
  1172. //}
  1173. /*
  1174. ** Update the display, unless we're inside a dialog.
  1175. */
  1176. //if (SpecialDialog == SDLG_NONE && GameInFocus) {
  1177. //WWMouse->Erase_Mouse(&HidPage, TRUE);
  1178. //Map.Input(input, x, y);
  1179. //if (input) {
  1180. // Keyboard_Process(input);
  1181. //}
  1182. /*
  1183. ** The main loop passes these in uninitialized. ST - 2/7/2019 4:36PM
  1184. */
  1185. KeyNumType input = KN_NONE; // Player input.
  1186. int x = 0;
  1187. int y = 0;
  1188. Map.Input(input, x, y);
  1189. //if (input) {
  1190. // Keyboard_Process(input);
  1191. //}
  1192. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  1193. /*
  1194. ** Process the sidebar. ST - 4/18/2019 11:59AM
  1195. */
  1196. HouseClass *old_player_ptr = PlayerPtr;
  1197. for (int i=0 ; i<MPlayerCount ; i++) {
  1198. HouseClass *player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  1199. DLLExportClass::Logic_Switch_Player_Context(player_ptr);
  1200. Sidebar_Glyphx_AI(player_ptr, input);
  1201. }
  1202. DLLExportClass::Logic_Switch_Player_Context(old_player_ptr);
  1203. }
  1204. //}
  1205. /*
  1206. ** Sort the map's ground layer by y-coordinate value. This is done
  1207. ** outside the IsToRedraw check, for the purposes of game sync'ing
  1208. ** between machines; this way, all machines will sort the Map's
  1209. ** layer in the same way, and any processing done that's based on
  1210. ** the order of this layer will sync on different machines.
  1211. */
  1212. Map.Layer[LAYER_GROUND].Sort();
  1213. /*
  1214. ** AI logic operations are performed here.
  1215. */
  1216. //Skip this block of code on first update of single-player games. This helps prevents trigger generated messages on the first update from being lost during loading screen or movie. - LLL
  1217. static bool FirstUpdate = GameToPlay != GAME_GLYPHX_MULTIPLAYER;;
  1218. if (!FirstUpdate)
  1219. {
  1220. HouseClass *old_player_ptr = PlayerPtr;
  1221. Logic.Clear_Recently_Created_Bits();
  1222. Logic.AI();
  1223. DLLExportClass::Logic_Switch_Player_Context(old_player_ptr);
  1224. }
  1225. FirstUpdate = false;
  1226. /*
  1227. ** Manage the inter-player message list. If Manage() returns true, it means
  1228. ** a message has expired & been removed, and the entire map must be updated.
  1229. */
  1230. //if (Messages.Manage()) {
  1231. // HiddenPage.Clear();
  1232. // Map.Flag_To_Redraw(true);
  1233. //}
  1234. /*
  1235. ** Process all commands that are ready to be processed.
  1236. */
  1237. if (GameToPlay == GAME_NORMAL) {
  1238. Queue_AI();
  1239. } else {
  1240. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  1241. DLLExportClass::Glyphx_Queue_AI();
  1242. /*
  1243. ** Process the sidebar. ST - 3/22/2019 2:07PM
  1244. */
  1245. for (int i=0 ; i<MPlayerCount ; i++) {
  1246. HouseClass *player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  1247. Sidebar_Glyphx_Recalc(player_ptr);
  1248. }
  1249. }
  1250. }
  1251. /*
  1252. ** Keep track of elapsed time in the game.
  1253. */
  1254. //Score.ElapsedTime += TIMER_SECOND / TICKS_PER_SECOND;
  1255. /*
  1256. ** Perform any win/lose code as indicated by the global control flags.
  1257. */
  1258. if (EndCountDown) EndCountDown--;
  1259. /*
  1260. ** Check for player wins or loses according to global event flag.
  1261. */
  1262. if (PlayerWins) {
  1263. //WWMouse->Erase_Mouse(&HidPage, TRUE);
  1264. PlayerLoses = false;
  1265. PlayerWins = false;
  1266. PlayerRestarts = false;
  1267. Map.Help_Text(TXT_NONE);
  1268. InMainLoop = false;
  1269. GlyphX_Debug_Print("PlayerWins = true");
  1270. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  1271. DLLExportClass::On_Multiplayer_Game_Over();
  1272. } else {
  1273. DLLExportClass::On_Game_Over(player_id, true);
  1274. }
  1275. return false;
  1276. }
  1277. if (PlayerLoses) {
  1278. //WWMouse->Erase_Mouse(&HidPage, TRUE);
  1279. PlayerWins = false;
  1280. PlayerLoses = false;
  1281. PlayerRestarts = false;
  1282. Map.Help_Text(TXT_NONE);
  1283. //Do_Lose(); //Old C&C code
  1284. GlyphX_Debug_Print("PlayerLoses = true");
  1285. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  1286. DLLExportClass::On_Multiplayer_Game_Over();
  1287. } else {
  1288. DLLExportClass::On_Game_Over(player_id, false);
  1289. }
  1290. InMainLoop = false;
  1291. return false;
  1292. }
  1293. /*
  1294. ** The frame logic has been completed. Increment the frame
  1295. ** counter.
  1296. */
  1297. Frame++;
  1298. /*
  1299. ** Very rarely, the human players will get a message from the computer.
  1300. */
  1301. if (GameToPlay != GAME_NORMAL && MPlayerGhosts && IRandom(0,10000) == 1) {
  1302. DLLExportClass::Computer_Message(false);
  1303. }
  1304. /*
  1305. ** The code is often leaving dangling pointers in overlappers. We can afford the CPU time to just clean them up. I suspect
  1306. ** the underlying cause was probably fixed in RA.
  1307. ** ST - 4/14/2020 11:45AM
  1308. */
  1309. Map.Clean();
  1310. #ifndef NDEBUG
  1311. /*
  1312. ** Is there a memory trasher altering the map??
  1313. */
  1314. if (!Map.Validate()) {
  1315. GlyphX_Debug_Print("Map.Validate() failed");
  1316. //if (CCMessageBox().Process ("Map Error!","Stop","Continue")==0) {
  1317. // GameActive = false;
  1318. //}
  1319. Map.Validate(); // give debugger a chance to catch it
  1320. }
  1321. #endif NDEBUG
  1322. InMainLoop = false;
  1323. if (ProgEndCalled) {
  1324. GlyphX_Debug_Print("ProgEndCalled - GameActive = false");
  1325. GameActive = false;
  1326. }
  1327. if (DLLExportClass::Legacy_Render_Enabled()) {
  1328. Map.Render();
  1329. }
  1330. //Sync_Delay();
  1331. Color_Cycle();
  1332. //DLLExportClass::Set_Event_Callback(NULL);
  1333. return(GameActive);
  1334. }
  1335. /**************************************************************************************************
  1336. * CNC_Save_Load -- Process a save or load game action
  1337. *
  1338. * In:
  1339. *
  1340. * Out: Success?
  1341. *
  1342. *
  1343. *
  1344. * History: 1/7/2019 5:20PM - ST
  1345. **************************************************************************************************/
  1346. extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const char *file_path_and_name, const char *game_type)
  1347. {
  1348. bool result = false;
  1349. if (save) {
  1350. result = Save_Game(file_path_and_name, "internal");
  1351. } else {
  1352. if (game_type == NULL) {
  1353. return false;
  1354. }
  1355. if (stricmp(game_type, "GAME_NORMAL") == 0) {
  1356. GameToPlay = GAME_NORMAL;
  1357. } else {
  1358. if (stricmp(game_type, "GAME_GLYPHX_MULTIPLAYER") == 0) {
  1359. GameToPlay = GAME_GLYPHX_MULTIPLAYER;
  1360. ScenPlayer = SCEN_PLAYER_MPLAYER;
  1361. } else {
  1362. return false;
  1363. }
  1364. }
  1365. result = Load_Game(file_path_and_name);
  1366. if (result == false)
  1367. {
  1368. return false;
  1369. }
  1370. DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
  1371. DLLExportClass::Cancel_Placement(DLLExportClass::GlyphxPlayerIDs[0], -1, -1);
  1372. Set_Logic_Page(SeenBuff);
  1373. VisiblePage.Clear();
  1374. Map.Flag_To_Redraw(true);
  1375. if (DLLExportClass::Legacy_Render_Enabled()) {
  1376. Map.Render();
  1377. }
  1378. Set_Palette(GamePalette);
  1379. }
  1380. return result;
  1381. }
  1382. /**************************************************************************************************
  1383. * CNC_Set_Difficulty -- Set game difficulty
  1384. *
  1385. * In:
  1386. *
  1387. * Out:
  1388. *
  1389. *
  1390. *
  1391. * History: 10/02/2019 - SKY
  1392. **************************************************************************************************/
  1393. extern "C" __declspec(dllexport) void __cdecl CNC_Set_Difficulty(int difficulty)
  1394. {
  1395. if (GameToPlay == GAME_NORMAL) {
  1396. Set_Scenario_Difficulty(difficulty);
  1397. }
  1398. }
  1399. /**************************************************************************************************
  1400. * CNC_Handle_Player_Switch_To_AI -- Renamed 3/9/20202 - LLL
  1401. * previously named: CNC_Handle_Player_Disconnect -- Handle player disconnected during multiplayuer game
  1402. *
  1403. * In:
  1404. *
  1405. * Out:
  1406. *
  1407. *
  1408. *
  1409. * History: 12/3/2019 1:46PM - ST
  1410. **************************************************************************************************/
  1411. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uint64 player_id)
  1412. {
  1413. if (PlayerWins || PlayerLoses || DLLExportClass::Get_Game_Over()) {
  1414. return;
  1415. }
  1416. GlyphX_Debug_Print("CNC_Handle_Player_Switch_To_AI");
  1417. if (GameToPlay == GAME_NORMAL) {
  1418. return;
  1419. }
  1420. #ifdef KILL_PLAYER_ON_DISCONNECT
  1421. /*
  1422. ** Kill player's units on disconnect.
  1423. */
  1424. if (player_id != 0) {
  1425. DLLExportClass::Set_Player_Context(player_id);
  1426. if (PlayerPtr) {
  1427. PlayerPtr->Flag_To_Die();
  1428. }
  1429. }
  1430. #else //KILL_PLAYER_ON_DISCONNECT
  1431. if (player_id != 0) {
  1432. HousesType house;
  1433. HouseClass *ptr;
  1434. DLLExportClass::Set_Player_Context(player_id);
  1435. if (PlayerPtr) {
  1436. PlayerPtr->WasHuman = true;
  1437. PlayerPtr->IsHuman = false;
  1438. PlayerPtr->IsStarted = true;
  1439. PlayerPtr->IQ = Rule.MaxIQ;
  1440. PlayerPtr->IsBaseBuilding = true;
  1441. /*
  1442. ** Start the unload mission for MCVs
  1443. */
  1444. for (int index = 0; index < Units.Count(); index++) {
  1445. UnitClass * obj = Units.Ptr(index);
  1446. if (obj && !obj->IsInLimbo && obj->House == PlayerPtr) {
  1447. if (*obj == UNIT_MCV) {
  1448. obj->Assign_Mission(MISSION_GUARD);
  1449. obj->Assign_Target(TARGET_NONE);
  1450. obj->Assign_Destination(TARGET_NONE);
  1451. obj->Assign_Mission(MISSION_UNLOAD);
  1452. obj->Commence();
  1453. }
  1454. }
  1455. }
  1456. DLLExportClass::On_Message(PlayerPtr, "", 60.0f, MESSAGE_TYPE_PLAYER_DISCONNECTED, -1);
  1457. /*
  1458. ** Send the disconnect taunt message
  1459. */
  1460. int human_count = 0;
  1461. for (house = HOUSE_MULTI1; house < (HOUSE_MULTI1 + MPlayerMax); house++) {
  1462. ptr = HouseClass::As_Pointer(house);
  1463. if (ptr && ptr->IsHuman && !ptr->IsDefeated) {
  1464. human_count++;
  1465. }
  1466. }
  1467. if (human_count == 1) {
  1468. DLLExportClass::Computer_Message(true);
  1469. }
  1470. }
  1471. }
  1472. #endif //KILL_PLAYER_ON_DISCONNECT
  1473. }
  1474. /**************************************************************************************************
  1475. * CNC_Handle_Human_Team_Wins
  1476. *
  1477. * History: 3/10/2020 - LLL
  1478. **************************************************************************************************/
  1479. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Human_Team_Wins(uint64 quitting_player_id)
  1480. {
  1481. GlyphX_Debug_Print("CNC_Handle_Human_Team_Wins");
  1482. DLLExportClass::Force_Human_Team_Wins(quitting_player_id);
  1483. }
  1484. /**************************************************************************************************
  1485. * CNC_Start_Mission_Timer
  1486. *
  1487. * History: 11/25/2019 - LLL
  1488. **************************************************************************************************/
  1489. extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time)
  1490. {
  1491. //Only implemented in Red Alert.
  1492. }
  1493. /**************************************************************************************************
  1494. * CNC_Get_Start_Game_Info
  1495. *
  1496. * History: 8/31/2020 11:37AM - ST
  1497. **************************************************************************************************/
  1498. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index)
  1499. {
  1500. start_location_waypoint_index = 0;
  1501. if (!DLLExportClass::Set_Player_Context(player_id)) {
  1502. return false;
  1503. }
  1504. start_location_waypoint_index = PlayerPtr->StartLocationOverride;
  1505. return true;
  1506. }
  1507. /**************************************************************************************************
  1508. * DLLExportClass::Init -- Init the class
  1509. *
  1510. * In:
  1511. *
  1512. * Out:
  1513. *
  1514. *
  1515. *
  1516. * History: 3/12/2019 10:52AM - ST
  1517. **************************************************************************************************/
  1518. void DLLExportClass::Init(void)
  1519. {
  1520. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  1521. GlyphxPlayerIDs[i] = 0xffffffffull;
  1522. }
  1523. CurrentLocalPlayerIndex = 0;
  1524. }
  1525. /**************************************************************************************************
  1526. * DLLExportClass::Shutdown -- Shutdown
  1527. *
  1528. * In:
  1529. *
  1530. * Out:
  1531. *
  1532. *
  1533. *
  1534. * History: 2/20/2020 1:59PM - ST
  1535. **************************************************************************************************/
  1536. void DLLExportClass::Shutdown(void)
  1537. {
  1538. for (int i=0 ; i<ModSearchPaths.Count() ; i++) {
  1539. delete [] ModSearchPaths[i];
  1540. }
  1541. ModSearchPaths.Clear();
  1542. }
  1543. /**************************************************************************************************
  1544. * DLLExportClass::Add_Mod_Path -- Add a path to load mod files from
  1545. *
  1546. * In: Mod path
  1547. *
  1548. * Out:
  1549. *
  1550. *
  1551. *
  1552. * History: 2/20/2020 2:03PM - ST
  1553. **************************************************************************************************/
  1554. void DLLExportClass::Add_Mod_Path(const char *mod_path)
  1555. {
  1556. char *copy_path = strdup(mod_path);
  1557. ModSearchPaths.Add(copy_path);
  1558. }
  1559. /**************************************************************************************************
  1560. * DLLExportClass::Set_Content_Directory -- Update the locations that the original code will load from
  1561. *
  1562. * In: Main (official) content directory
  1563. *
  1564. * Out:
  1565. *
  1566. *
  1567. *
  1568. * History: 2/20/2020 2:03PM - ST
  1569. **************************************************************************************************/
  1570. void DLLExportClass::Set_Content_Directory(const char *content_directory)
  1571. {
  1572. CCFileClass::Clear_Search_Drives();
  1573. CCFileClass::Reset_Raw_Path();
  1574. if ((content_directory == NULL || strlen(content_directory) == 0) && ModSearchPaths.Count() == 0) {
  1575. return;
  1576. }
  1577. char *all_paths = new char [_MAX_PATH * 100];
  1578. *all_paths = 0;
  1579. for (int i=0 ; i<ModSearchPaths.Count() ; i++) {
  1580. if (i != 0) {
  1581. strcat(all_paths, ";");
  1582. }
  1583. strcat(all_paths, ModSearchPaths[i]);
  1584. }
  1585. if (ModSearchPaths.Count() && content_directory && strlen(content_directory)) {
  1586. strcat(all_paths, ";");
  1587. }
  1588. if (content_directory) {
  1589. strcat(all_paths, content_directory);
  1590. }
  1591. CCFileClass::Set_Search_Drives(all_paths);
  1592. delete [] all_paths;
  1593. }
  1594. /**************************************************************************************************
  1595. * DLLExportClass::Config
  1596. *
  1597. * History: 1/16/2020 - SKY
  1598. **************************************************************************************************/
  1599. void DLLExportClass::Config(const CNCRulesDataStruct& rules)
  1600. {
  1601. for (int i = 0; i < 3; ++i)
  1602. {
  1603. Rule.Diff[i].FirepowerBias = rules.Difficulties[i].FirepowerBias;
  1604. Rule.Diff[i].GroundspeedBias = rules.Difficulties[i].GroundspeedBias;
  1605. Rule.Diff[i].AirspeedBias = rules.Difficulties[i].AirspeedBias;
  1606. Rule.Diff[i].ArmorBias = rules.Difficulties[i].ArmorBias;
  1607. Rule.Diff[i].ROFBias = rules.Difficulties[i].ROFBias;
  1608. Rule.Diff[i].CostBias = rules.Difficulties[i].CostBias;
  1609. Rule.Diff[i].BuildSpeedBias = rules.Difficulties[i].BuildSpeedBias;
  1610. Rule.Diff[i].RepairDelay = rules.Difficulties[i].RepairDelay;
  1611. Rule.Diff[i].BuildDelay = rules.Difficulties[i].BuildDelay;
  1612. Rule.Diff[i].IsBuildSlowdown = rules.Difficulties[i].IsBuildSlowdown ? 1 : 0;
  1613. Rule.Diff[i].IsWallDestroyer = rules.Difficulties[i].IsWallDestroyer ? 1 : 0;
  1614. Rule.Diff[i].IsContentScan = rules.Difficulties[i].IsContentScan ? 1 : 0;
  1615. }
  1616. }
  1617. /**************************************************************************************************
  1618. * DLLExportClass::Set_Home_Cell
  1619. *
  1620. * History: 2/14/2020 - LLL
  1621. **************************************************************************************************/
  1622. extern CELL Views[4];
  1623. void DLLExportClass::Set_Home_Cell(int x, int y, uint64 player_id)
  1624. {
  1625. if (GameToPlay == GAME_NORMAL) {
  1626. MultiplayerStartPositions[0] = Views[0] = XY_Cell(x, y);
  1627. }
  1628. else {
  1629. for (int i = 0; i < MPlayerCount && i < 4; i++) {
  1630. if (GlyphxPlayerIDs[i] == player_id) {
  1631. Views[i] = MultiplayerStartPositions[i] = XY_Cell(x, y);
  1632. }
  1633. }
  1634. }
  1635. }
  1636. /**************************************************************************************************
  1637. * DLLExportClass::On_Play_Movie
  1638. *
  1639. * History: 7/23/2019 - LLL
  1640. **************************************************************************************************/
  1641. void DLLExportClass::On_Play_Movie(const char * movie_name, ThemeType theme, bool immediate)
  1642. {
  1643. if (EventCallback == NULL) {
  1644. return;
  1645. }
  1646. InMainLoop = false;
  1647. EventCallbackStruct new_event;
  1648. new_event.EventType = CALLBACK_EVENT_MOVIE;
  1649. new_event.Movie.MovieName = movie_name;
  1650. new_event.Movie.Theme = (int)theme;
  1651. new_event.Movie.Immediate = immediate;
  1652. EventCallback(new_event);
  1653. }
  1654. /**************************************************************************************************
  1655. * DLLExportClass::On_Display_Briefing_Text
  1656. *
  1657. * Called when Red Alert wants to display the mission breifing screen before a mission.
  1658. *
  1659. * History: 12/04/2019 - LLL
  1660. **************************************************************************************************/
  1661. void DLLExportClass::On_Display_Briefing_Text()
  1662. {
  1663. //Only implemeneted for Red Alert - LLL
  1664. }
  1665. /**************************************************************************************************
  1666. * DLLExportClass::On_Sound_Effect -- Called when C&C wants to play a sound effect
  1667. *
  1668. * In:
  1669. *
  1670. * Out:
  1671. *
  1672. *
  1673. *
  1674. * History: 2/20/2019 2:39PM - ST
  1675. **************************************************************************************************/
  1676. void DLLExportClass::On_Sound_Effect(const HouseClass* player_ptr, int sound_effect_index, const char* extension, int variation, COORDINATE coord)
  1677. {
  1678. // player_ptr could be NULL
  1679. if (EventCallback == NULL) {
  1680. return;
  1681. }
  1682. EventCallbackStruct new_event;
  1683. new_event.EventType = CALLBACK_EVENT_SOUND_EFFECT;
  1684. new_event.SoundEffect.SFXIndex = sound_effect_index;
  1685. new_event.SoundEffect.Variation = variation;
  1686. new_event.GlyphXPlayerID = 0;
  1687. if ( player_ptr != NULL )
  1688. {
  1689. new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  1690. }
  1691. if ( coord == 0 )
  1692. {
  1693. new_event.SoundEffect.PixelX = -1;
  1694. new_event.SoundEffect.PixelY = -1;
  1695. }
  1696. else
  1697. {
  1698. // Use world pixel coordinates
  1699. new_event.SoundEffect.PixelX = Lepton_To_Pixel(Coord_X(coord));
  1700. new_event.SoundEffect.PixelY = Lepton_To_Pixel(Coord_Y(coord));
  1701. }
  1702. if ( sound_effect_index >= VOC_FIRST && sound_effect_index < VOC_COUNT )
  1703. {
  1704. strncpy( new_event.SoundEffect.SoundEffectName, SoundEffectName[ sound_effect_index ].Name, CNC_OBJECT_ASSET_NAME_LENGTH);
  1705. new_event.SoundEffect.SoundEffectName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0; // strncpy can leave strings unterminated
  1706. if ( extension != NULL )
  1707. {
  1708. strncat( new_event.SoundEffect.SoundEffectName, extension, CNC_OBJECT_ASSET_NAME_LENGTH);
  1709. new_event.SoundEffect.SoundEffectName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0; // strncat can leave strings unterminated
  1710. }
  1711. new_event.SoundEffect.SoundEffectPriority = SoundEffectName[ sound_effect_index ].Priority;
  1712. new_event.SoundEffect.SoundEffectContext = SoundEffectName[ sound_effect_index ].Where;
  1713. }
  1714. else
  1715. {
  1716. strncpy( new_event.SoundEffect.SoundEffectName, "BADINDEX", CNC_OBJECT_ASSET_NAME_LENGTH);
  1717. new_event.SoundEffect.SoundEffectPriority = -1;
  1718. new_event.SoundEffect.SoundEffectContext = -1;
  1719. }
  1720. EventCallback(new_event);
  1721. }
  1722. /**************************************************************************************************
  1723. * DLLExportClass::On_Speech -- Called when C&C wants to play a speech line
  1724. *
  1725. * In:
  1726. *
  1727. * Out:
  1728. *
  1729. *
  1730. *
  1731. * History: 2/20/2019 2:39PM - ST
  1732. **************************************************************************************************/
  1733. void DLLExportClass::On_Speech(const HouseClass* player_ptr, int speech_index)
  1734. {
  1735. // player_ptr could be NULL
  1736. if (EventCallback == NULL) {
  1737. return;
  1738. }
  1739. EventCallbackStruct new_event;
  1740. new_event.EventType = CALLBACK_EVENT_SPEECH;
  1741. new_event.Speech.SpeechIndex = speech_index;
  1742. new_event.GlyphXPlayerID = 0;
  1743. if ( player_ptr != NULL )
  1744. {
  1745. new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  1746. }
  1747. if ( speech_index >= VOX_FIRST && speech_index < VOX_COUNT )
  1748. {
  1749. strncpy( new_event.Speech.SpeechName, Speech[ speech_index ], CNC_OBJECT_ASSET_NAME_LENGTH);
  1750. new_event.Speech.SpeechName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0; // strncpy can leave strings unterminated
  1751. }
  1752. else
  1753. {
  1754. strncpy( new_event.Speech.SpeechName, "BAD_SPEECH_INDEX", CNC_OBJECT_ASSET_NAME_LENGTH);
  1755. }
  1756. EventCallback(new_event);
  1757. }
  1758. /**************************************************************************************************
  1759. * DLLExportClass::TD_Calculate_Efficiency --
  1760. *
  1761. * History: 10.29.2019 MBL (Based on LLL's Calculate_Single_Player_Score())
  1762. **************************************************************************************************/
  1763. unsigned int DLLExportClass::TD_Calculate_Efficiency( unsigned int harvested_credits, unsigned int initial_credits, unsigned int available_credits )
  1764. {
  1765. unsigned efficiency = Cardinal_To_Fixed( harvested_credits + (initial_credits + 1), (available_credits + 1) );
  1766. if ( efficiency == 0 ) {
  1767. efficiency++;
  1768. }
  1769. efficiency = Fixed_To_Cardinal(100, efficiency);
  1770. if (efficiency > 100) {
  1771. efficiency = 100;
  1772. }
  1773. return efficiency;
  1774. }
  1775. /**************************************************************************************************
  1776. * DLLExportClass::TD_Calculate_Leadership --
  1777. *
  1778. * History: 10.29.2019 MBL (Based on LLL's Calculate_Single_Player_Score())
  1779. **************************************************************************************************/
  1780. unsigned int DLLExportClass::TD_Calculate_Leadership( int house, unsigned int units_lost, unsigned int buildings_lost )
  1781. {
  1782. unsigned int leadership = 0;
  1783. for (int index = 0; index < Logic.Count(); index++) {
  1784. ObjectClass * object = Logic[index];
  1785. if (object->Owner() == house) {
  1786. leadership++;
  1787. }
  1788. }
  1789. if (leadership == 0) {
  1790. leadership = 1;
  1791. }
  1792. leadership = Cardinal_To_Fixed(units_lost + buildings_lost + leadership, leadership);
  1793. leadership = Fixed_To_Cardinal(100, leadership);
  1794. if (leadership > 100) {
  1795. leadership = 100;
  1796. }
  1797. return leadership;
  1798. }
  1799. /**************************************************************************************************
  1800. * DLLExportClass::TD_Calculate_Score --
  1801. *
  1802. * History: 10.29.2019 MBL (Based on LLL's Calculate_Single_Player_Score())
  1803. **************************************************************************************************/
  1804. unsigned int DLLExportClass::TD_Calculate_Score( unsigned int leadership, unsigned int efficiency, unsigned int build_level )
  1805. {
  1806. long total = ((leadership * 40) + (4600) + (efficiency * 14)) / 100;
  1807. if (!total) total++;
  1808. total *= (build_level + 1);
  1809. return total;
  1810. }
  1811. void DLLExportClass::Calculate_Single_Player_Score(EventCallbackStruct& event)
  1812. {
  1813. //Adapted from Tiberian Dawn SCORE.CPP Presentation() - LLL
  1814. int house = PlayerPtr->Class->House; // 0 or 1
  1815. HouseClass *houses[3];
  1816. for (int index = 0; index < 3; index++) {
  1817. houses[index] = (HouseClass::As_Pointer((HousesType)(HOUSE_GOOD + index)));
  1818. }
  1819. int gdi_units_lost = (HouseClass::As_Pointer(HOUSE_GOOD))->UnitsLost;
  1820. int nod_units_lost = (HouseClass::As_Pointer(HOUSE_BAD))->UnitsLost;
  1821. int civilians_killed = (HouseClass::As_Pointer(HOUSE_NEUTRAL))->UnitsLost;
  1822. int gdi_buildings_lost = (HouseClass::As_Pointer(HOUSE_GOOD))->BuildingsLost;
  1823. int nod_buildings_lost = (HouseClass::As_Pointer(HOUSE_BAD))->BuildingsLost;
  1824. int civilian_buildings_lost = (HouseClass::As_Pointer(HOUSE_NEUTRAL))->BuildingsLost;
  1825. int gdi_harvested = (HouseClass::As_Pointer(HOUSE_GOOD))->HarvestedCredits;
  1826. int nod_harvested = (HouseClass::As_Pointer(HOUSE_BAD))->HarvestedCredits;
  1827. // unsigned leadership = 0;
  1828. // int index;
  1829. // for (index = 0; index < Logic.Count(); index++) {
  1830. // ObjectClass * object = Logic[index];
  1831. // if (object->Owner() == house) {
  1832. // leadership++;
  1833. // }
  1834. // }
  1835. //
  1836. // if (leadership == 0) {
  1837. // leadership = 1;
  1838. // }
  1839. //
  1840. // leadership = Cardinal_To_Fixed(gdi_units_lost + gdi_buildings_lost + leadership, leadership);
  1841. // leadership = Fixed_To_Cardinal(100, leadership);
  1842. // if (leadership > 100) {
  1843. // leadership = 100;
  1844. // }
  1845. //
  1846. unsigned leadership = TD_Calculate_Leadership( house, (house == HOUSE_GOOD ? gdi_units_lost : nod_units_lost), (house == HOUSE_GOOD ? gdi_buildings_lost : nod_buildings_lost) );
  1847. /*
  1848. ** Determine efficiency rating.
  1849. */
  1850. // int gharv = gdi_harvested;
  1851. // int init = PlayerPtr->InitialCredits;
  1852. // int cred = PlayerPtr->Available_Money();
  1853. //
  1854. // unsigned efficiency = Cardinal_To_Fixed((house == HOUSE_GOOD ? gdi_harvested : nod_harvested) + (unsigned)PlayerPtr->InitialCredits + 1, (unsigned)PlayerPtr->Available_Money() + 1);
  1855. // if (!efficiency) efficiency++;
  1856. // efficiency = Fixed_To_Cardinal(100, efficiency);
  1857. // if (efficiency > 100) {
  1858. // efficiency = 100;
  1859. // }
  1860. //
  1861. unsigned efficiency = TD_Calculate_Efficiency((house == HOUSE_GOOD ? gdi_harvested : nod_harvested), PlayerPtr->InitialCredits, PlayerPtr->Available_Money());
  1862. /*
  1863. ** Calculate total score
  1864. */
  1865. // long total_score = ((leadership * 40) + (4600) + (efficiency * 14)) / 100;
  1866. // if (!total_score) total_score++;
  1867. // total_score *= (BuildLevel + 1);
  1868. //
  1869. unsigned total_score = TD_Calculate_Score( leadership, efficiency, BuildLevel );
  1870. //Score Stats
  1871. event.GameOver.Leadership = leadership;
  1872. event.GameOver.Efficiency = efficiency;
  1873. event.GameOver.Score = total_score;
  1874. event.GameOver.CategoryTotal = 0; //Only used in Red Alert
  1875. event.GameOver.NODKilled = nod_units_lost;
  1876. event.GameOver.GDIKilled = gdi_units_lost;
  1877. event.GameOver.CiviliansKilled = civilians_killed;
  1878. event.GameOver.NODBuildingsDestroyed = nod_buildings_lost;
  1879. event.GameOver.GDIBuildingsDestroyed = gdi_buildings_lost;
  1880. event.GameOver.CiviliansBuildingsDestroyed = civilian_buildings_lost;
  1881. event.GameOver.RemainingCredits = PlayerPtr->Available_Money();
  1882. }
  1883. void DLLExportClass::Convert_Action_Type(ActionType type, ObjectClass* object, TARGET target, DllActionTypeEnum& dll_type)
  1884. {
  1885. switch (type)
  1886. {
  1887. case ACTION_NONE:
  1888. default:
  1889. dll_type = DAT_NONE;
  1890. break;
  1891. case ACTION_MOVE:
  1892. dll_type = DAT_MOVE;
  1893. break;
  1894. case ACTION_NOMOVE:
  1895. dll_type = DAT_NOMOVE;
  1896. break;
  1897. case ACTION_ENTER:
  1898. dll_type = DAT_ENTER;
  1899. break;
  1900. case ACTION_SELF:
  1901. dll_type = DAT_SELF;
  1902. break;
  1903. case ACTION_ATTACK:
  1904. if (Target_Legal(target) && (object != NULL) && object->Is_Techno() && ((TechnoClass*)object)->In_Range(target, 0)) {
  1905. dll_type = DAT_ATTACK;
  1906. }
  1907. else {
  1908. dll_type = DAT_ATTACK_OUT_OF_RANGE;
  1909. }
  1910. break;
  1911. case ACTION_GUARD_AREA:
  1912. dll_type = DAT_GUARD;
  1913. break;
  1914. case ACTION_HARVEST:
  1915. dll_type = DAT_ATTACK;
  1916. break;
  1917. case ACTION_SELECT:
  1918. case ACTION_TOGGLE_SELECT:
  1919. dll_type = DAT_SELECT;
  1920. break;
  1921. case ACTION_CAPTURE:
  1922. dll_type = DAT_CAPTURE;
  1923. break;
  1924. case ACTION_SABOTAGE:
  1925. dll_type = DAT_SABOTAGE;
  1926. break;
  1927. case ACTION_TOGGLE_PRIMARY:
  1928. dll_type = DAT_TOGGLE_PRIMARY;
  1929. break;
  1930. case ACTION_NO_DEPLOY:
  1931. dll_type = DAT_CANT_DEPLOY;
  1932. break;
  1933. }
  1934. }
  1935. /**************************************************************************************************
  1936. * DLLExportClass::On_Game_Over -- Called when the C&C campaign game finishes
  1937. *
  1938. *
  1939. * History: 6/19/2019 - LLL
  1940. **************************************************************************************************/
  1941. void DLLExportClass::On_Game_Over(uint64 glyphx_Player_id, bool player_wins)
  1942. {
  1943. if (EventCallback == NULL) {
  1944. return;
  1945. }
  1946. GameOver = true;
  1947. EventCallbackStruct new_event;
  1948. new_event.EventType = CALLBACK_EVENT_GAME_OVER;
  1949. new_event.GlyphXPlayerID = glyphx_Player_id;
  1950. new_event.GameOver.PlayerWins = player_wins;
  1951. new_event.GameOver.MovieName = player_wins ? WinMovie : LoseMovie;
  1952. new_event.GameOver.AfterScoreMovieName = "";
  1953. new_event.GameOver.Multiplayer = false;
  1954. new_event.GameOver.MultiPlayerTotalPlayers = 0;
  1955. Calculate_Single_Player_Score(new_event);
  1956. if (player_wins)
  1957. {
  1958. if (PlayerPtr->Class->House == HOUSE_BAD && Scenario == 13) {
  1959. //TODO: Nod_Ending() Also looks like it plays some audio that might need to be integrated.
  1960. new_event.GameOver.MovieName = "";
  1961. new_event.GameOver.AfterScoreMovieName = "NODFINAL";
  1962. }
  1963. else if (PlayerPtr->Class->House == HOUSE_GOOD && Scenario == 15) {
  1964. if (TempleIoned) {
  1965. new_event.GameOver.MovieName = "GDIFINB";
  1966. new_event.GameOver.AfterScoreMovieName = "GDIEND2";
  1967. }
  1968. else {
  1969. new_event.GameOver.MovieName = "GDIFINA";
  1970. new_event.GameOver.AfterScoreMovieName = "GDIEND1";
  1971. }
  1972. }
  1973. }
  1974. if (strcmp(new_event.GameOver.MovieName, "x") == 0 || strcmp(new_event.GameOver.MovieName, "X") == 0) {
  1975. new_event.GameOver.MovieName = "";
  1976. }
  1977. new_event.GameOver.MovieName2 = WinMovie2;
  1978. if (strcmp(new_event.GameOver.MovieName2, "x") == 0 || strcmp(new_event.GameOver.MovieName2, "X") == 0) {
  1979. new_event.GameOver.MovieName2 = "";
  1980. }
  1981. new_event.GameOver.MovieName3 = WinMovie3;
  1982. if (strcmp(new_event.GameOver.MovieName3, "x") == 0 || strcmp(new_event.GameOver.MovieName3, "X") == 0) {
  1983. new_event.GameOver.MovieName3 = "";
  1984. }
  1985. new_event.GameOver.MovieName4 = WinMovie4;
  1986. if (strcmp(new_event.GameOver.MovieName4, "x") == 0 || strcmp(new_event.GameOver.MovieName4, "X") == 0) {
  1987. new_event.GameOver.MovieName4 = "";
  1988. }
  1989. new_event.GameOver.SabotagedStructureType = SabotagedType;
  1990. new_event.GameOver.TimerRemaining = -1; //Used in RA
  1991. EventCallback(new_event);
  1992. }
  1993. /**************************************************************************************************
  1994. * DLLExportClass::On_Multiplayer_Game_Over -- Called when the C&C multiplayer game finishes
  1995. *
  1996. *
  1997. * History: 6/19/2019 - LLL
  1998. * History: 10/25/2019 - MBL - Adding the multi-player score stats support for debrief
  1999. **************************************************************************************************/
  2000. void DLLExportClass::On_Multiplayer_Game_Over(void)
  2001. {
  2002. if (EventCallback == NULL) {
  2003. return;
  2004. }
  2005. GameOver = true;
  2006. EventCallbackStruct event;
  2007. event.EventType = CALLBACK_EVENT_GAME_OVER;
  2008. // Multiplayer players data for debrief stats
  2009. event.GameOver.Multiplayer = true;
  2010. event.GameOver.MultiPlayerTotalPlayers = MPlayerCount;
  2011. for ( int player_index = 0; player_index < MPlayerCount; player_index ++ )
  2012. {
  2013. HouseClass* player_ptr = HouseClass::As_Pointer( MPlayerHouses[player_index] ); //HouseClass::As_Pointer(HOUSE_MULTI2);
  2014. if ( player_ptr != NULL )
  2015. {
  2016. int house = player_ptr->Class->House;
  2017. unsigned int leadership = TD_Calculate_Leadership( house, player_ptr->UnitsLost, player_ptr->BuildingsLost );
  2018. unsigned int efficiency = TD_Calculate_Efficiency( player_ptr->HarvestedCredits, player_ptr->InitialCredits, player_ptr->Available_Money() );
  2019. unsigned int total_score = TD_Calculate_Score( leadership, efficiency, BuildLevel );
  2020. int units_killed = 0;
  2021. int structures_killed = 0;
  2022. for ( unsigned int house_index = 0; house_index < HOUSE_COUNT; house_index ++ )
  2023. {
  2024. units_killed += player_ptr->UnitsKilled[ house_index ];
  2025. structures_killed += player_ptr->BuildingsKilled[ house_index ];
  2026. }
  2027. // Populate and copy the multiplayer player data structure
  2028. GameOverMultiPlayerStatsStruct multi_player_data;
  2029. multi_player_data.GlyphXPlayerID = Get_GlyphX_Player_ID( player_ptr );
  2030. multi_player_data.IsHuman = (player_ptr->IsHuman || player_ptr->WasHuman);
  2031. multi_player_data.WasHuman = player_ptr->WasHuman;
  2032. multi_player_data.IsWinner = !player_ptr->IsDefeated;
  2033. multi_player_data.Efficiency = efficiency;
  2034. multi_player_data.Score = total_score;
  2035. multi_player_data.ResourcesGathered = player_ptr->HarvestedCredits;
  2036. multi_player_data.TotalUnitsKilled = units_killed;
  2037. multi_player_data.TotalStructuresKilled = structures_killed;
  2038. if ( player_index < GAME_OVER_MULTIPLAYER_MAX_PLAYERS_TRACKED )
  2039. {
  2040. event.GameOver.MultiPlayerPlayersData[ player_index ] = multi_player_data;
  2041. }
  2042. }
  2043. }
  2044. for ( int player_index = MPlayerCount; player_index < GAME_OVER_MULTIPLAYER_MAX_PLAYERS_TRACKED; player_index ++ )
  2045. {
  2046. memset( &event.GameOver.MultiPlayerPlayersData[ player_index ], 0, sizeof( GameOverMultiPlayerStatsStruct ) );
  2047. }
  2048. // Single-player N/A stuff
  2049. event.GameOver.MovieName = "";
  2050. event.GameOver.MovieName2 = "";
  2051. event.GameOver.MovieName3 = "";
  2052. event.GameOver.MovieName4 = "";
  2053. event.GameOver.AfterScoreMovieName = "";
  2054. event.GameOver.Leadership = 0;
  2055. event.GameOver.Efficiency = 0;
  2056. event.GameOver.Score = 0;
  2057. event.GameOver.NODKilled = 0;
  2058. event.GameOver.GDIKilled = 0;
  2059. event.GameOver.CiviliansKilled = 0;
  2060. event.GameOver.NODBuildingsDestroyed = 0;
  2061. event.GameOver.GDIBuildingsDestroyed = 0;
  2062. event.GameOver.CiviliansBuildingsDestroyed = 0;
  2063. event.GameOver.RemainingCredits = 0;
  2064. event.GameOver.SabotagedStructureType = 0;
  2065. event.GameOver.TimerRemaining = -1;
  2066. // Trigger an event for each human player, winner first (even if it's an AI)
  2067. for (int i = 0; i < MPlayerCount; i++) {
  2068. HouseClass* player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  2069. if (player_ptr != NULL && !player_ptr->IsDefeated) {
  2070. event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  2071. event.GameOver.IsHuman = player_ptr->IsHuman;
  2072. event.GameOver.PlayerWins = true;
  2073. event.GameOver.RemainingCredits = player_ptr->Available_Money();
  2074. EventCallback(event);
  2075. }
  2076. }
  2077. for (int i = 0; i < MPlayerCount; i++) {
  2078. HouseClass* player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  2079. if (player_ptr != NULL && player_ptr->IsHuman && player_ptr->IsDefeated) {
  2080. event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  2081. event.GameOver.IsHuman = true;
  2082. event.GameOver.PlayerWins = false;
  2083. event.GameOver.RemainingCredits = player_ptr->Available_Money();
  2084. EventCallback(event);
  2085. }
  2086. }
  2087. }
  2088. /**************************************************************************************************
  2089. * DLLExportClass::On_Message -- Called when the game wants to display a message (ex. tutorial text)
  2090. *
  2091. * In:
  2092. *
  2093. * Out:
  2094. *
  2095. *
  2096. *
  2097. * History: 10/16/2019 - SKY
  2098. **************************************************************************************************/
  2099. void DLLExportClass::On_Message(const HouseClass* player_ptr, const char* message, float timeout_seconds, EventCallbackMessageEnum message_type, int64 message_id)
  2100. {
  2101. if (EventCallback == NULL)
  2102. {
  2103. return;
  2104. }
  2105. const char* p_msg = message;
  2106. if (message_id != -1) {
  2107. if (message_id == TXT_LOW_POWER) {
  2108. p_msg = "TEXT_LOW_POWER_MESSAGE_001";
  2109. }
  2110. else if (message_id == TXT_INSUFFICIENT_FUNDS) {
  2111. p_msg = "TEXT_INSUFFICIENT_FUNDS_MESSAGE";
  2112. }
  2113. }
  2114. EventCallbackStruct new_event;
  2115. new_event.EventType = CALLBACK_EVENT_MESSAGE;
  2116. new_event.Message.Message = p_msg;
  2117. new_event.Message.TimeoutSeconds = timeout_seconds;
  2118. new_event.Message.MessageType = message_type;
  2119. new_event.Message.MessageParam1 = message_id;
  2120. new_event.GlyphXPlayerID = 0;
  2121. if (player_ptr != NULL)
  2122. {
  2123. new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  2124. }
  2125. EventCallback(new_event);
  2126. }
  2127. void On_Message(const char* message, float timeout_seconds, EventCallbackMessageEnum message_type, int64 message_id)
  2128. {
  2129. DLLExportClass::On_Message(PlayerPtr, message, timeout_seconds, message_type, message_id);
  2130. }
  2131. void On_Message(const char* message, float timeout_seconds, int64 message_id)
  2132. {
  2133. DLLExportClass::On_Message(PlayerPtr, message, timeout_seconds, MESSAGE_TYPE_DIRECT, message_id);
  2134. }
  2135. void On_Defeated_Message(const char* message, float timeout_seconds)
  2136. {
  2137. DLLExportClass::On_Message(PlayerPtr, message, timeout_seconds, MESSAGE_TYPE_PLAYER_DEFEATED, -1);
  2138. }
  2139. /**************************************************************************************************
  2140. * DLLExportClass::On_Achievement -- Called when something achievement-related happens
  2141. *
  2142. * In: Type of achievement, reason this happened
  2143. *
  2144. * Out:
  2145. *
  2146. *
  2147. *
  2148. * History: 11/11/2019 11:37AM - ST
  2149. **************************************************************************************************/
  2150. void DLLExportClass::On_Achievement(const HouseClass* player_ptr, const char *achievement_type, const char *achievement_reason)
  2151. {
  2152. if (EventCallback == NULL) {
  2153. return;
  2154. }
  2155. EventCallbackStruct new_event;
  2156. new_event.EventType = CALLBACK_EVENT_ACHIEVEMENT;
  2157. new_event.Achievement.AchievementType = achievement_type;
  2158. new_event.Achievement.AchievementReason = achievement_reason;
  2159. new_event.GlyphXPlayerID = 0;
  2160. if (player_ptr != NULL) {
  2161. new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  2162. }
  2163. EventCallback(new_event);
  2164. }
  2165. void DLLExportClass::On_Center_Camera(const HouseClass* player_ptr, int coord_x, int coord_y)
  2166. {
  2167. if (EventCallback == NULL) {
  2168. return;
  2169. }
  2170. EventCallbackStruct new_event;
  2171. new_event.EventType = CALLBACK_EVENT_CENTER_CAMERA;
  2172. new_event.CenterCamera.CoordX = coord_x;
  2173. new_event.CenterCamera.CoordY = coord_y;
  2174. new_event.GlyphXPlayerID = 0;
  2175. if (player_ptr != NULL) {
  2176. new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  2177. }
  2178. EventCallback(new_event);
  2179. }
  2180. void DLLExportClass::On_Ping(const HouseClass* player_ptr, COORDINATE coord)
  2181. {
  2182. if (EventCallback == NULL) {
  2183. return;
  2184. }
  2185. EventCallbackStruct new_event;
  2186. new_event.EventType = CALLBACK_EVENT_PING;
  2187. new_event.Ping.CoordX = Coord_X(coord);
  2188. new_event.Ping.CoordY = Coord_Y(coord);
  2189. new_event.GlyphXPlayerID = 0;
  2190. if (player_ptr != NULL) {
  2191. new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
  2192. }
  2193. EventCallback(new_event);
  2194. }
  2195. /**************************************************************************************************
  2196. * DLLExportClass::On_Debug_Output -- Called when C&C wants to print debug output
  2197. *
  2198. * In: String to print to GlyphX log system
  2199. *
  2200. * Out:
  2201. *
  2202. *
  2203. *
  2204. * History: 2/20/2019 2:39PM - ST
  2205. **************************************************************************************************/
  2206. void DLLExportClass::On_Debug_Output(const char *debug_text)
  2207. {
  2208. if (EventCallback == NULL) {
  2209. return;
  2210. }
  2211. EventCallbackStruct new_event;
  2212. new_event.EventType = CALLBACK_EVENT_DEBUG_PRINT;
  2213. new_event.DebugPrint.PrintString = debug_text;
  2214. EventCallback(new_event);
  2215. }
  2216. /**************************************************************************************************
  2217. * DLLExportClass::Force_Human_Team_Wins
  2218. *
  2219. * History: 3/10/2020 - LL
  2220. **************************************************************************************************/
  2221. void DLLExportClass::Force_Human_Team_Wins(uint64 quitting_player_id)
  2222. {
  2223. if (PlayerWins || PlayerLoses || GameOver) {
  2224. return;
  2225. }
  2226. int winning_team = -1;
  2227. //Find the first human's multiplayer team.
  2228. for (int i = 0; i < MPlayerCount; i++)
  2229. {
  2230. if (GlyphxPlayerIDs[i] != quitting_player_id) {
  2231. HousesType house_type = MPlayerHouses[i];
  2232. HouseClass* house_class = HouseClass::As_Pointer(house_type);
  2233. if (house_class && house_class->IsHuman && !house_class->IsDefeated) {
  2234. winning_team = MPlayerTeamIDs[i];
  2235. break;
  2236. }
  2237. }
  2238. }
  2239. //Mark all players not on that team as defeated.
  2240. for (int i = 0; i < MPlayerCount; i++)
  2241. {
  2242. HousesType house_type = MPlayerHouses[i];
  2243. HouseClass* house_class = HouseClass::As_Pointer(house_type);
  2244. if (house_class) {
  2245. house_class->IsDefeated = MPlayerTeamIDs[i] != winning_team;
  2246. }
  2247. }
  2248. PlayerWins = true;
  2249. }
  2250. /**************************************************************************************************
  2251. * CNC_Get_Game_State -- Get game state
  2252. *
  2253. * In: Type of state requested
  2254. * Player perspective
  2255. * Buffer to contain game state
  2256. * Size of buffer
  2257. *
  2258. * Out: Game state returned in buffer
  2259. *
  2260. *
  2261. *
  2262. * History: 1/7/2019 5:20PM - ST
  2263. **************************************************************************************************/
  2264. extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Game_State(GameStateRequestEnum state_type, uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  2265. {
  2266. bool got_state = false;
  2267. switch (state_type) {
  2268. case GAME_STATE_LAYERS:
  2269. {
  2270. got_state = DLLExportClass::Get_Layer_State(player_id, buffer_in, buffer_size);
  2271. break;
  2272. }
  2273. case GAME_STATE_SIDEBAR:
  2274. {
  2275. got_state = DLLExportClass::Get_Sidebar_State(player_id, buffer_in, buffer_size);
  2276. break;
  2277. }
  2278. case GAME_STATE_PLACEMENT:
  2279. {
  2280. got_state = DLLExportClass::Get_Placement_State(player_id, buffer_in, buffer_size);
  2281. break;
  2282. }
  2283. case GAME_STATE_DYNAMIC_MAP:
  2284. got_state = DLLExportClass::Get_Dynamic_Map_State(player_id, buffer_in, buffer_size);
  2285. break;
  2286. case GAME_STATE_SHROUD:
  2287. got_state = DLLExportClass::Get_Shroud_State(player_id, buffer_in, buffer_size);
  2288. break;
  2289. case GAME_STATE_OCCUPIER:
  2290. got_state = DLLExportClass::Get_Occupier_State(player_id, buffer_in, buffer_size);
  2291. break;
  2292. case GAME_STATE_PLAYER_INFO:
  2293. got_state = DLLExportClass::Get_Player_Info_State(player_id, buffer_in, buffer_size);
  2294. break;
  2295. case GAME_STATE_STATIC_MAP:
  2296. {
  2297. if (buffer_size < sizeof(CNCMapDataStruct)) {
  2298. got_state = false;
  2299. break;
  2300. }
  2301. int map_cell_x = Map.MapCellX;
  2302. int map_cell_y = Map.MapCellY;
  2303. int map_cell_width = Map.MapCellWidth;
  2304. int map_cell_height = Map.MapCellHeight;
  2305. CNCMapDataStruct *map_data = (CNCMapDataStruct *)buffer_in;
  2306. map_data->OriginalMapCellX = map_cell_x;
  2307. map_data->OriginalMapCellY = map_cell_y;
  2308. map_data->OriginalMapCellWidth = map_cell_width;
  2309. map_data->OriginalMapCellHeight = map_cell_height;
  2310. if (map_cell_x > 0) {
  2311. map_cell_x--;
  2312. map_cell_width++;
  2313. }
  2314. if (map_cell_width < MAP_MAX_CELL_WIDTH) {
  2315. map_cell_width++;
  2316. }
  2317. if (map_cell_y > 0) {
  2318. map_cell_y--;
  2319. map_cell_height++;
  2320. }
  2321. if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
  2322. map_cell_height++;
  2323. }
  2324. map_data->MapCellX = map_cell_x;
  2325. map_data->MapCellY = map_cell_y;
  2326. map_data->MapCellWidth = map_cell_width;
  2327. map_data->MapCellHeight = map_cell_height;
  2328. map_data->Theater = (CnCTheaterType) Map.Theater;
  2329. // Hack a fix for scenario 21 since the same mission number is used in Covert Ops and N64
  2330. memset(map_data->ScenarioName, 0, sizeof(map_data->ScenarioName));
  2331. if ((Map.Theater == CNC_THEATER_DESERT) && (Scenario == 21)) {
  2332. strncpy(map_data->ScenarioName, "SCB81EA", sizeof(map_data->ScenarioName) - 1);
  2333. } else {
  2334. strncpy(map_data->ScenarioName, ScenarioName, sizeof(map_data->ScenarioName) - 1);
  2335. }
  2336. int cell_index = 0;
  2337. char cell_name[_MAX_PATH];
  2338. char icon_number[32];
  2339. for (int y = 0 ; y < map_cell_height ; y++) {
  2340. for (int x = 0 ; x < map_cell_width ; x++) {
  2341. CELL cell = XY_Cell(map_cell_x+x, map_cell_y+y);
  2342. CellClass * cellptr = &Map[cell];
  2343. cell_name[0] = 0;
  2344. int icon = 0;
  2345. void *image_data = 0;
  2346. if (cellptr->Get_Template_Info(cell_name, icon, image_data)) {
  2347. itoa(icon, icon_number, 10);
  2348. strncat(cell_name, "_i", 32);
  2349. strncat(cell_name, icon_number, 32);
  2350. strncat(cell_name, ".tga", 32);
  2351. cell_name[31] = 0;
  2352. CNCStaticCellStruct &cell_info = map_data->StaticCells[cell_index++];
  2353. strncpy(cell_info.TemplateTypeName, cell_name, 32);
  2354. cell_info.TemplateTypeName[31] = 0;
  2355. cell_info.IconNumber = icon;
  2356. }
  2357. }
  2358. }
  2359. got_state = true;
  2360. break;
  2361. }
  2362. default:
  2363. {
  2364. got_state = false;
  2365. break;
  2366. }
  2367. }
  2368. return got_state;
  2369. }
  2370. /**************************************************************************************************
  2371. * CNC_Handle_Game_Request
  2372. *
  2373. * Callback for when the requested movie is done playing.
  2374. *
  2375. * 7/23/2019 - LLL
  2376. **************************************************************************************************/
  2377. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Request(GameRequestEnum request_type)
  2378. {
  2379. switch (request_type)
  2380. {
  2381. case INPUT_GAME_MOVIE_DONE:
  2382. InMainLoop = true;
  2383. break;
  2384. }
  2385. }
  2386. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Settings_Request(int health_bar_display_mode, int resource_bar_display_mode)
  2387. {
  2388. if (!DLLExportClass::Legacy_Render_Enabled()) {
  2389. return;
  2390. }
  2391. SpecialClass::eHealthBarDisplayMode new_hb_mode = (SpecialClass::eHealthBarDisplayMode)health_bar_display_mode;
  2392. if (new_hb_mode != Special.HealthBarDisplayMode) {
  2393. Special.HealthBarDisplayMode = new_hb_mode;
  2394. Map.Flag_To_Redraw(true);
  2395. }
  2396. SpecialClass::eResourceBarDisplayMode new_rb_mode = (SpecialClass::eResourceBarDisplayMode)resource_bar_display_mode;
  2397. if (new_rb_mode != Special.ResourceBarDisplayMode) {
  2398. Special.ResourceBarDisplayMode = new_rb_mode;
  2399. Map.Flag_To_Redraw(true);
  2400. }
  2401. }
  2402. void DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, ObjectClass *object, const char *shape_file_name = NULL, char override_owner = HOUSE_NONE, int scale = 0x100)
  2403. {
  2404. DLLExportClass::DLL_Draw_Intercept(shape_number, x, y, width, height, flags, object, shape_file_name, override_owner, scale);
  2405. }
  2406. void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip)
  2407. {
  2408. DLLExportClass::DLL_Draw_Pip_Intercept(object, pip);
  2409. }
  2410. void DLL_Draw_Line_Intercept(int x, int y, int x1, int y1, unsigned char color, int frame)
  2411. {
  2412. DLLExportClass::DLL_Draw_Line_Intercept(x, y, x1, y1, color, frame);
  2413. }
  2414. void DLLExportClass::DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, ObjectClass *object, const char *shape_file_name, char override_owner, int scale)
  2415. {
  2416. CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
  2417. memset(&new_object, 0, sizeof(new_object));
  2418. Convert_Type(object, new_object);
  2419. if (new_object.Type == UNKNOWN) {
  2420. return;
  2421. }
  2422. CNCObjectStruct* base_object = NULL;
  2423. for (int i = 0; i < CurrentDrawCount; ++i) {
  2424. CNCObjectStruct& draw_object = ObjectList->Objects[TotalObjectCount + i];
  2425. if (draw_object.CNCInternalObjectPointer == object) {
  2426. base_object = &draw_object;
  2427. break;
  2428. }
  2429. }
  2430. new_object.CNCInternalObjectPointer = (void*)object;
  2431. new_object.OccupyListLength = 0;
  2432. if (CurrentDrawCount == 0) {
  2433. new_object.SortOrder = (ExportLayer << 29) + (object->Sort_Y() >> 3);
  2434. } else {
  2435. new_object.SortOrder = ObjectList->Objects[TotalObjectCount].SortOrder + CurrentDrawCount;
  2436. }
  2437. strncpy(new_object.TypeName, object->Class_Of().IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
  2438. if (shape_file_name != NULL) {
  2439. strncpy(new_object.AssetName, shape_file_name, CNC_OBJECT_ASSET_NAME_LENGTH);
  2440. }
  2441. else {
  2442. strncpy(new_object.AssetName, object->Class_Of().IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
  2443. }
  2444. new_object.TypeName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  2445. new_object.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  2446. new_object.Owner = ((base_object != NULL) && (override_owner != HOUSE_NONE)) ? override_owner : (char)object->Owner();
  2447. HouseClass* owner_house = nullptr;
  2448. for (int i = 0; i < Houses.Count(); ++i) {
  2449. HouseClass* hptr = Houses.Ptr(i);
  2450. if ((hptr != nullptr) && (hptr->Class->House == new_object.Owner)) {
  2451. owner_house = hptr;
  2452. break;
  2453. }
  2454. }
  2455. new_object.RemapColor = (owner_house != nullptr) ? owner_house->RemapColor : -1;
  2456. if (base_object == NULL) {
  2457. CNCObjectStruct& root_object = ObjectList->Objects[TotalObjectCount];
  2458. if (new_object.Type == BUILDING) {
  2459. BuildingClass *building = (BuildingClass*)object;
  2460. if (building->BState == BSTATE_CONSTRUCTION) {
  2461. strncat(new_object.AssetName, "MAKE", CNC_OBJECT_ASSET_NAME_LENGTH);
  2462. new_object.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  2463. }
  2464. const BuildingTypeClass *building_type = building->Class;
  2465. short const *occupy_list = building_type->Occupy_List();
  2466. if (occupy_list) {
  2467. while (*occupy_list != REFRESH_EOL && new_object.OccupyListLength < MAX_OCCUPY_CELLS) {
  2468. new_object.OccupyList[new_object.OccupyListLength] = *occupy_list;
  2469. new_object.OccupyListLength++;
  2470. occupy_list++;
  2471. }
  2472. }
  2473. }
  2474. COORDINATE coord = object->Render_Coord();
  2475. CELL cell = Coord_Cell(coord);
  2476. int dimx, dimy;
  2477. object->Class_Of().Dimensions(dimx, dimy);
  2478. short sim_lepton_x = 0;
  2479. short sim_lepton_y = 0;
  2480. if (new_object.Type == UNIT) {
  2481. sim_lepton_x = ((DriveClass*)object)->SimLeptonX;
  2482. sim_lepton_y = ((DriveClass*)object)->SimLeptonY;
  2483. }
  2484. new_object.PositionX = x;
  2485. new_object.PositionY = y;
  2486. new_object.Width = width;
  2487. new_object.Height = height;
  2488. new_object.Altitude = 0;
  2489. new_object.DrawFlags = flags;
  2490. new_object.SubObject = 0;
  2491. new_object.ShapeIndex = (unsigned short)shape_number;
  2492. new_object.IsTheaterSpecific = IsTheaterShape;
  2493. new_object.Scale = scale;
  2494. new_object.Rotation = 0;
  2495. new_object.FlashingFlags = 0;
  2496. new_object.Cloak = (CurrentDrawCount > 0) ? root_object.Cloak : UNCLOAKED;
  2497. new_object.VisibleFlags = CNCObjectStruct::VISIBLE_FLAGS_ALL;
  2498. new_object.SpiedByFlags = 0U;
  2499. new_object.SortOrder = SortOrder++;
  2500. new_object.IsSelectable = object->Class_Of().IsSelectable;
  2501. new_object.IsSelectedMask = object->IsSelectedMask;
  2502. new_object.MaxStrength = object->Class_Of().MaxStrength;
  2503. new_object.Strength = object->Strength;
  2504. new_object.CellX = (CurrentDrawCount > 0) ? root_object.CellX : Cell_X(cell);
  2505. new_object.CellY = (CurrentDrawCount > 0) ? root_object.CellY : Cell_Y(cell);
  2506. new_object.CenterCoordX = Coord_X(object->Center_Coord());
  2507. new_object.CenterCoordY = Coord_Y(object->Center_Coord());
  2508. new_object.DimensionX = dimx;
  2509. new_object.DimensionY = dimy;
  2510. new_object.SimLeptonX = (CurrentDrawCount > 0) ? root_object.SimLeptonX : sim_lepton_x;
  2511. new_object.SimLeptonY = (CurrentDrawCount > 0) ? root_object.SimLeptonY : sim_lepton_y;
  2512. new_object.BaseObjectID = ((CurrentDrawCount > 0) && (root_object.Type != BUILDING)) ? root_object.ID : 0;
  2513. new_object.BaseObjectType = ((CurrentDrawCount > 0) && (root_object.Type != BUILDING)) ? root_object.Type : UNKNOWN;
  2514. new_object.NumLines = 0;
  2515. new_object.RecentlyCreated = object->IsRecentlyCreated;
  2516. new_object.NumPips = 0;
  2517. new_object.MaxPips = 0;
  2518. new_object.CanDemolish = object->Can_Demolish();
  2519. new_object.CanDemolishUnit = object->Can_Demolish_Unit();
  2520. new_object.CanRepair = object->Can_Repair();
  2521. memset(new_object.CanMove, false, sizeof(new_object.CanMove));
  2522. memset(new_object.CanFire, false, sizeof(new_object.CanFire));
  2523. memset(new_object.ActionWithSelected, DAT_NONE, sizeof(new_object.ActionWithSelected));
  2524. HouseClass* old_player_ptr = PlayerPtr;
  2525. for (int i = 0; i < Houses.Count(); ++i) {
  2526. HouseClass* hptr = Houses.Ptr(i);
  2527. if ((hptr != nullptr) && hptr->IsActive && hptr->IsHuman) {
  2528. HousesType house = hptr->Class->House;
  2529. DynamicVectorClass<ObjectClass*>& selected_objects = CurrentObject.Raw(house);
  2530. if (selected_objects.Count() > 0) {
  2531. Logic_Switch_Player_Context(hptr);
  2532. Convert_Action_Type(Best_Object_Action(selected_objects, object), (selected_objects.Count() == 1) ? selected_objects[0] : NULL, object->As_Target(), new_object.ActionWithSelected[house]);
  2533. }
  2534. }
  2535. }
  2536. Logic_Switch_Player_Context(old_player_ptr);
  2537. RTTIType what_is_object = object->What_Am_I();
  2538. new_object.IsRepairing = false;
  2539. new_object.IsDumping = false;
  2540. new_object.IsALoaner = false;
  2541. new_object.IsFactory = false;
  2542. new_object.IsPrimaryFactory = false;
  2543. new_object.IsAntiGround = false;
  2544. new_object.IsAntiAircraft = false;
  2545. new_object.IsSubSurface = false;
  2546. new_object.IsNominal = false;
  2547. new_object.IsDog = false;
  2548. new_object.IsIronCurtain = false;
  2549. new_object.IsInFormation = false;
  2550. new_object.IsFake = false;
  2551. new_object.ProductionAssetName[0] = '\0';
  2552. new_object.OverrideDisplayName = "\0";
  2553. bool is_building = what_is_object == RTTI_BUILDING;
  2554. if (is_building) {
  2555. BuildingClass* building = static_cast<BuildingClass*>(object);
  2556. new_object.IsRepairing = building->IsRepairing;
  2557. new_object.IsFactory = building->Class->IsFactory;
  2558. new_object.IsPrimaryFactory = building->IsLeader;
  2559. }
  2560. if (object->Is_Techno()) {
  2561. TechnoClass* techno_object = static_cast<TechnoClass*>(object);
  2562. const TechnoTypeClass *ttype = techno_object->Techno_Type_Class();
  2563. new_object.MaxSpeed = (unsigned char)ttype->MaxSpeed;
  2564. new_object.IsALoaner = techno_object->IsALoaner;
  2565. new_object.IsNominal = ttype->IsNominal;
  2566. new_object.MaxPips = ttype->Max_Pips();
  2567. new_object.IsAntiGround = ttype->Primary != WEAPON_NONE;
  2568. new_object.IsAntiAircraft = (ttype->Primary != WEAPON_NONE) && (Weapons[ttype->Primary].Fires != BULLET_NONE) && BulletTypeClass::As_Reference(Weapons[ttype->Primary].Fires).IsAntiAircraft;
  2569. HouseClass* old_player_ptr = PlayerPtr;
  2570. for (int i = 0; i < Houses.Count(); ++i) {
  2571. HouseClass* hptr = Houses.Ptr(i);
  2572. if ((hptr != nullptr) && hptr->IsActive && hptr->IsHuman) {
  2573. Logic_Switch_Player_Context(hptr);
  2574. HousesType house = hptr->Class->House;
  2575. new_object.CanMove[house] = techno_object->Can_Player_Move();
  2576. new_object.CanFire[house] = techno_object->Can_Player_Fire();
  2577. }
  2578. }
  2579. Logic_Switch_Player_Context(old_player_ptr);
  2580. }
  2581. new_object.ControlGroup = (unsigned char)(-1);
  2582. new_object.CanPlaceBombs = false;
  2583. bool is_infantry = what_is_object == RTTI_INFANTRY;
  2584. if (is_infantry) {
  2585. InfantryClass* infantry = static_cast<InfantryClass*>(object);
  2586. new_object.ControlGroup = infantry->Group;
  2587. new_object.CanPlaceBombs = infantry->Class->Type == INFANTRY_RAMBO;
  2588. }
  2589. new_object.CanHarvest = false;
  2590. bool is_unit = what_is_object == RTTI_UNIT;
  2591. if (is_unit) {
  2592. UnitClass* unit = static_cast<UnitClass*>(object);
  2593. if (unit->Class->Type == UNIT_HARVESTER) {
  2594. new_object.CanHarvest = true;
  2595. }
  2596. new_object.ControlGroup = unit->Group;
  2597. }
  2598. new_object.IsFixedWingedAircraft = false;
  2599. bool is_aircraft = what_is_object == RTTI_AIRCRAFT;
  2600. if (is_aircraft) {
  2601. AircraftClass* aircraft = static_cast<AircraftClass*>(object);
  2602. new_object.Altitude = Pixel_To_Lepton(aircraft->Altitude);
  2603. new_object.IsFixedWingedAircraft = aircraft->Class->IsFixedWing;
  2604. new_object.ControlGroup = aircraft->Group;
  2605. }
  2606. switch (what_is_object)
  2607. {
  2608. case RTTI_INFANTRY:
  2609. case RTTI_INFANTRYTYPE:
  2610. case RTTI_UNIT:
  2611. case RTTI_UNITTYPE:
  2612. case RTTI_AIRCRAFT:
  2613. case RTTI_AIRCRAFTTYPE:
  2614. case RTTI_BUILDING:
  2615. case RTTI_BUILDINGTYPE:
  2616. {
  2617. TechnoClass* techno_object = static_cast<TechnoClass*>(object);
  2618. new_object.FlashingFlags = techno_object->Get_Flashing_Flags();
  2619. new_object.Cloak = techno_object->Cloak;
  2620. }
  2621. break;
  2622. case RTTI_ANIM:
  2623. {
  2624. AnimClass* anim_object = static_cast<AnimClass*>(object);
  2625. new_object.VisibleFlags = anim_object->Get_Visible_Flags();
  2626. }
  2627. break;
  2628. }
  2629. }
  2630. else {
  2631. new_object.MaxStrength = 0;
  2632. new_object.MaxSpeed = 0;
  2633. new_object.Strength = 0;
  2634. new_object.CellX = base_object->CellX;
  2635. new_object.CellY = base_object->CellY;
  2636. new_object.CenterCoordX = base_object->CenterCoordX;
  2637. new_object.CenterCoordY = base_object->CenterCoordY;
  2638. new_object.DimensionX = base_object->DimensionX;
  2639. new_object.DimensionY = base_object->DimensionY;
  2640. new_object.IsSelectable = false;
  2641. new_object.IsSelectedMask = 0U;
  2642. new_object.SimLeptonX = base_object->SimLeptonX;
  2643. new_object.SimLeptonY = base_object->SimLeptonY;
  2644. new_object.PositionX = x;
  2645. new_object.PositionY = y;
  2646. new_object.Width = width;
  2647. new_object.Height = height;
  2648. new_object.Altitude = base_object->Altitude;
  2649. new_object.DrawFlags = flags;
  2650. new_object.ShapeIndex = (unsigned short)shape_number;
  2651. new_object.IsTheaterSpecific = IsTheaterShape;
  2652. new_object.Scale = scale;
  2653. new_object.Rotation = 0;
  2654. new_object.SubObject = CurrentDrawCount;
  2655. new_object.BaseObjectID = base_object->ID;
  2656. new_object.BaseObjectType = base_object->Type;
  2657. new_object.FlashingFlags = base_object->FlashingFlags;
  2658. new_object.Cloak = base_object->Cloak;
  2659. new_object.OccupyListLength = 0;
  2660. new_object.NumPips = 0;
  2661. new_object.MaxPips = 0;
  2662. new_object.IsRepairing = false;
  2663. new_object.IsDumping = false;
  2664. new_object.IsALoaner = base_object->IsALoaner;
  2665. new_object.NumLines = 0;
  2666. new_object.CanDemolish = base_object->CanDemolish;
  2667. new_object.CanDemolishUnit = base_object->CanDemolishUnit;
  2668. new_object.CanRepair = base_object->CanRepair;
  2669. new_object.RecentlyCreated = base_object->RecentlyCreated;
  2670. new_object.IsFactory = base_object->IsFactory;
  2671. new_object.IsPrimaryFactory = base_object->IsPrimaryFactory;
  2672. new_object.IsAntiGround = base_object->IsAntiGround;
  2673. new_object.IsAntiAircraft = base_object->IsAntiAircraft;
  2674. new_object.IsSubSurface = base_object->IsSubSurface;
  2675. new_object.IsNominal = base_object->IsNominal;
  2676. new_object.IsDog = base_object->IsDog;
  2677. new_object.IsIronCurtain = base_object->IsIronCurtain;
  2678. new_object.IsInFormation = false;
  2679. new_object.CanHarvest = base_object->CanHarvest;
  2680. new_object.CanPlaceBombs = base_object->CanPlaceBombs;
  2681. new_object.ControlGroup = base_object->ControlGroup;
  2682. new_object.VisibleFlags = base_object->VisibleFlags;
  2683. new_object.SpiedByFlags = base_object->SpiedByFlags;
  2684. new_object.IsFixedWingedAircraft = base_object->IsFixedWingedAircraft;
  2685. new_object.IsFake = base_object->IsFake;
  2686. new_object.ProductionAssetName[0] = '\0';
  2687. new_object.OverrideDisplayName = "\0";
  2688. memset(new_object.CanMove, false, sizeof(new_object.CanMove));
  2689. memset(new_object.CanFire, false, sizeof(new_object.CanFire));
  2690. memset(new_object.ActionWithSelected, DAT_NONE, sizeof(new_object.ActionWithSelected));
  2691. }
  2692. CurrentDrawCount++;
  2693. }
  2694. void DLLExportClass::DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip)
  2695. {
  2696. CNCObjectStruct* base_object = NULL;
  2697. for (int i = 0; i < CurrentDrawCount; ++i) {
  2698. CNCObjectStruct& draw_object = ObjectList->Objects[TotalObjectCount + i];
  2699. if (draw_object.CNCInternalObjectPointer == object) {
  2700. base_object = &draw_object;
  2701. break;
  2702. }
  2703. }
  2704. if ((base_object != NULL) && (base_object->NumPips < MAX_OBJECT_PIPS)) {
  2705. base_object->Pips[base_object->NumPips] = pip;
  2706. base_object->NumPips++;
  2707. base_object->MaxPips = max(base_object->MaxPips, base_object->NumPips);
  2708. }
  2709. }
  2710. void DLLExportClass::DLL_Draw_Line_Intercept(int x, int y, int x1, int y1, unsigned char color, int frame)
  2711. {
  2712. CNCObjectStruct& root_object = ObjectList->Objects[TotalObjectCount];
  2713. if (root_object.NumLines < MAX_OBJECT_LINES) {
  2714. root_object.Lines[root_object.NumLines].X = x;
  2715. root_object.Lines[root_object.NumLines].Y = y;
  2716. root_object.Lines[root_object.NumLines].X1 = x1;
  2717. root_object.Lines[root_object.NumLines].Y1 = y1;
  2718. root_object.Lines[root_object.NumLines].Frame = frame;
  2719. root_object.Lines[root_object.NumLines].Color = color;
  2720. SortOrder++;
  2721. root_object.NumLines++;
  2722. }
  2723. }
  2724. /**************************************************************************************************
  2725. * DLLExportClass::Get_Layer_State -- Get game objects from the layers
  2726. *
  2727. * In:
  2728. *
  2729. * Out:
  2730. *
  2731. *
  2732. *
  2733. * History: 1/29/2019 11:37AM - ST
  2734. **************************************************************************************************/
  2735. bool DLLExportClass::Get_Layer_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  2736. {
  2737. player_id;
  2738. static int _export_count = 0;
  2739. bool got_state = false;
  2740. ObjectList = (CNCObjectListStruct*) buffer_in;
  2741. TotalObjectCount = 0;
  2742. /*
  2743. ** Get a reference draw coordinate for cells
  2744. */
  2745. int map_cell_x = Map.MapCellX;
  2746. int map_cell_y = Map.MapCellY;
  2747. if (map_cell_x > 0) {
  2748. map_cell_x--;
  2749. }
  2750. if (map_cell_y > 0) {
  2751. map_cell_y--;
  2752. }
  2753. SortOrder = 0;
  2754. /*
  2755. ** Get the ground layer first and then followed by all the layers in increasing altitude.
  2756. */
  2757. for (int layer = 0; layer < DLL_LAYER_COUNT; layer++) {
  2758. ExportLayer = layer;
  2759. for (int index = 0; index < Map.Layer[layer].Count(); index++) {
  2760. ObjectClass *object = Map.Layer[layer][index];
  2761. if (object->IsActive) {
  2762. unsigned int memory_needed = sizeof(CNCObjectListStruct);
  2763. memory_needed += (TotalObjectCount + 10) * sizeof(CNCObjectStruct);
  2764. if (memory_needed >= buffer_size) {
  2765. return false;
  2766. }
  2767. if (object->Is_Techno()) {
  2768. /*
  2769. ** Skip units tethered to buildings, since the building will draw them itself
  2770. */
  2771. TechnoClass* techno_object = static_cast<TechnoClass*>(object);
  2772. TechnoClass* contact_object = techno_object->In_Radio_Contact() ? techno_object->Contact_With_Whom() : nullptr;
  2773. if ((contact_object != nullptr) && (contact_object->What_Am_I() == RTTI_BUILDING) && contact_object->IsTethered && *((BuildingClass*)contact_object) == STRUCT_WEAP) {
  2774. continue;
  2775. }
  2776. }
  2777. if (Debug_Map || Debug_Unshroud || (object->IsDown && !object->IsInLimbo)) {
  2778. int x, y;
  2779. Map.Coord_To_Pixel(object->Render_Coord(), x, y);
  2780. /*
  2781. ** Call to Draw_It can result in multiple callbacks to the draw intercept
  2782. */
  2783. CurrentDrawCount = 0;
  2784. object->Draw_It(x, y, WINDOW_VIRTUAL);
  2785. /*
  2786. ** Shadows need to be rendered before the base object so they appear underneath,
  2787. ** even though they get drawn as sub-objects (after the base object)
  2788. */
  2789. for (int i = 1; i < CurrentDrawCount; ++i) {
  2790. CNCObjectStruct& sub_object = ObjectList->Objects[TotalObjectCount + i];
  2791. if (!sub_object.SubObject) {
  2792. continue;
  2793. }
  2794. static const int shadow_flags = SHAPE_PREDATOR | SHAPE_FADING;
  2795. if (((sub_object.DrawFlags & shadow_flags) == shadow_flags) || (strncmp(sub_object.AssetName, "WAKE", CNC_OBJECT_ASSET_NAME_LENGTH) == 0)) {
  2796. if ((strncmp(sub_object.AssetName, "RROTOR", CNC_OBJECT_ASSET_NAME_LENGTH) != 0) &&
  2797. (strncmp(sub_object.AssetName, "LROTOR", CNC_OBJECT_ASSET_NAME_LENGTH) != 0)) {
  2798. for (int j = i - 1; j >= 0; --j) {
  2799. CNCObjectStruct& base_object = ObjectList->Objects[TotalObjectCount + j];
  2800. if (!base_object.SubObject && (base_object.CNCInternalObjectPointer == sub_object.CNCInternalObjectPointer)) {
  2801. int sort_order = base_object.SortOrder;
  2802. base_object.SortOrder = sub_object.SortOrder;
  2803. sub_object.SortOrder = sort_order;
  2804. break;
  2805. }
  2806. }
  2807. }
  2808. }
  2809. }
  2810. TotalObjectCount += CurrentDrawCount;
  2811. }
  2812. }
  2813. }
  2814. }
  2815. ObjectList->Count = TotalObjectCount;
  2816. if (ObjectList->Count) {
  2817. _export_count++;
  2818. return true;
  2819. }
  2820. return false;
  2821. }
  2822. void DLLExportClass::Convert_Type(const ObjectClass *object, CNCObjectStruct &object_out)
  2823. {
  2824. object_out.Type = UNKNOWN;
  2825. object_out.ID = -1;
  2826. if (object == NULL) {
  2827. return;
  2828. }
  2829. RTTIType type = object->What_Am_I();
  2830. switch (type) {
  2831. default:
  2832. break;
  2833. case RTTI_INFANTRY:
  2834. object_out.Type = INFANTRY;
  2835. object_out.ID = Infantry.ID((InfantryClass*)object);
  2836. break;
  2837. case RTTI_UNIT:
  2838. object_out.Type = UNIT;
  2839. object_out.ID = Units.ID((UnitClass*)object);
  2840. break;
  2841. case RTTI_AIRCRAFT:
  2842. object_out.Type = AIRCRAFT;
  2843. object_out.ID = Aircraft.ID((AircraftClass*)object);
  2844. break;
  2845. case RTTI_BUILDING:
  2846. object_out.Type = BUILDING;
  2847. object_out.ID = Buildings.ID((BuildingClass*)object);
  2848. break;
  2849. case RTTI_BULLET:
  2850. object_out.Type = BULLET;
  2851. object_out.ID = Bullets.ID((BulletClass*)object);
  2852. break;
  2853. case RTTI_ANIM:
  2854. object_out.Type = ANIM;
  2855. object_out.ID = Anims.ID((AnimClass*)object);
  2856. break;
  2857. case RTTI_SMUDGE:
  2858. object_out.Type = SMUDGE;
  2859. object_out.ID = Smudges.ID((SmudgeClass*)object);
  2860. break;
  2861. case RTTI_TERRAIN:
  2862. object_out.Type = TERRAIN;
  2863. object_out.ID = Terrains.ID((TerrainClass*)object);
  2864. break;
  2865. }
  2866. }
  2867. /**************************************************************************************************
  2868. * CNC_Handle_Input -- Process input to the game
  2869. *
  2870. * In:
  2871. *
  2872. *
  2873. *
  2874. *
  2875. * Out: Game state returned in buffer
  2876. *
  2877. *
  2878. *
  2879. * History: 1/7/2019 5:20PM - ST
  2880. **************************************************************************************************/
  2881. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Input(InputRequestEnum input_event, unsigned char special_key_flags, uint64 player_id, int x1, int y1, int x2, int y2)
  2882. {
  2883. if (!DLLExportClass::Set_Player_Context(player_id)) {
  2884. return;
  2885. }
  2886. switch (input_event) {
  2887. /*
  2888. ** Special keys have changed
  2889. */
  2890. case INPUT_REQUEST_SPECIAL_KEYS:
  2891. {
  2892. DLLExportClass::Set_Special_Key_Flags(special_key_flags);
  2893. break;
  2894. }
  2895. /*
  2896. ** The mouse is moving
  2897. */
  2898. case INPUT_REQUEST_MOUSE_MOVE:
  2899. {
  2900. if (!DLLExportClass::Legacy_Render_Enabled()) {
  2901. break;
  2902. }
  2903. DLLForceMouseX = x1;
  2904. DLLForceMouseY = y1;
  2905. _Kbd->MouseQX = x1;
  2906. _Kbd->MouseQY = y1;
  2907. COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
  2908. CELL cell = Coord_Cell(coord);
  2909. if (coord) {
  2910. //x -= Map.TacPixelX;
  2911. //y -= Map.TacPixelY;
  2912. /*
  2913. ** Cause any displayed cursor to move along with the mouse cursor.
  2914. */
  2915. if (cell != Map.ZoneCell) {
  2916. Map.Set_Cursor_Pos(cell);
  2917. }
  2918. }
  2919. break;
  2920. }
  2921. /*
  2922. ** Player left-clicked
  2923. */
  2924. case INPUT_REQUEST_MOUSE_LEFT_CLICK:
  2925. {
  2926. DLLExportClass::Adjust_Internal_View();
  2927. DLLForceMouseX = x1;
  2928. DLLForceMouseY = y1;
  2929. _Kbd->MouseQX = x1;
  2930. _Kbd->MouseQY = y1;
  2931. KeyNumType key = (KeyNumType)(KN_LMOUSE | KN_RLSE_BIT);
  2932. if (Map.Pixel_To_Coord(x1, y1)) {
  2933. //DisplayClass::TacButton.Clicked_On(key, GadgetClass::LEFTRELEASE, x1, y1);
  2934. DisplayClass::TacButton.Clicked_On(key, GadgetClass::LEFTRELEASE, 100, 100);
  2935. }
  2936. break;
  2937. }
  2938. /*
  2939. ** Player right-clicked (on up)
  2940. */
  2941. case INPUT_REQUEST_MOUSE_RIGHT_CLICK:
  2942. {
  2943. DLLExportClass::Adjust_Internal_View();
  2944. DLLForceMouseX = x1;
  2945. DLLForceMouseY = y1;
  2946. _Kbd->MouseQX = x1;
  2947. _Kbd->MouseQY = y1;
  2948. KeyNumType key = (KeyNumType)(KN_RMOUSE | KN_RLSE_BIT);
  2949. if (Map.Pixel_To_Coord(x1, y1)) {
  2950. //DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTRELEASE, x1, y1);
  2951. DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTRELEASE, 100, 100);
  2952. }
  2953. break;
  2954. }
  2955. /*
  2956. ** Player right button down
  2957. */
  2958. case INPUT_REQUEST_MOUSE_RIGHT_DOWN:
  2959. {
  2960. DLLExportClass::Adjust_Internal_View();
  2961. DLLForceMouseX = x1;
  2962. DLLForceMouseY = y1;
  2963. _Kbd->MouseQX = x1;
  2964. _Kbd->MouseQY = y1;
  2965. KeyNumType key = (KeyNumType)(KN_RMOUSE);
  2966. if (Map.Pixel_To_Coord(x1, y1)) {
  2967. //DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTPRESS, x1, y1);
  2968. DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTPRESS, 100, 100);
  2969. }
  2970. break;
  2971. }
  2972. /*
  2973. ** Player drag selected
  2974. */
  2975. case INPUT_REQUEST_MOUSE_AREA:
  2976. {
  2977. DLLExportClass::Adjust_Internal_View();
  2978. Map.Select_These(XYPixel_Coord(x1, y1), XYPixel_Coord(x2, y2), false);
  2979. break;
  2980. }
  2981. case INPUT_REQUEST_MOUSE_AREA_ADDITIVE:
  2982. {
  2983. DLLExportClass::Adjust_Internal_View();
  2984. Map.Select_These(XYPixel_Coord(x1, y1), XYPixel_Coord(x2, y2), true);
  2985. break;
  2986. }
  2987. case INPUT_REQUEST_SELL_AT_POSITION:
  2988. {
  2989. DLLExportClass::Adjust_Internal_View();
  2990. DLLForceMouseX = x1;
  2991. DLLForceMouseY = y1;
  2992. _Kbd->MouseQX = x1;
  2993. _Kbd->MouseQY = y1;
  2994. COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
  2995. CELL cell = Coord_Cell(coord);
  2996. if (Map.Pixel_To_Coord(x1, y1))
  2997. {
  2998. PlayerPtr->Sell_Wall(cell);
  2999. }
  3000. break;
  3001. }
  3002. case INPUT_REQUEST_SELECT_AT_POSITION:
  3003. {
  3004. DLLExportClass::Adjust_Internal_View();
  3005. DLLForceMouseX = x1;
  3006. DLLForceMouseY = y1;
  3007. _Kbd->MouseQX = x1;
  3008. _Kbd->MouseQY = y1;
  3009. COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
  3010. CELL cell = Coord_Cell(coord);
  3011. if (Map.Pixel_To_Coord(x1, y1))
  3012. {
  3013. KeyNumType key = (KeyNumType)(KN_LMOUSE | KN_RLSE_BIT);
  3014. DisplayClass::TacButton.Selection_At_Mouse(GadgetClass::LEFTRELEASE, key);
  3015. }
  3016. break;
  3017. }
  3018. case INPUT_REQUEST_COMMAND_AT_POSITION:
  3019. {
  3020. DLLExportClass::Adjust_Internal_View();
  3021. DLLForceMouseX = x1;
  3022. DLLForceMouseY = y1;
  3023. _Kbd->MouseQX = x1;
  3024. _Kbd->MouseQY = y1;
  3025. COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
  3026. CELL cell = Coord_Cell(coord);
  3027. if (Map.Pixel_To_Coord(x1, y1))
  3028. {
  3029. KeyNumType key = (KeyNumType)(KN_LMOUSE | KN_RLSE_BIT);
  3030. DisplayClass::TacButton.Command_Object(GadgetClass::LEFTRELEASE, key);
  3031. }
  3032. break;
  3033. }
  3034. // MBL 09.08.2020 - Mod Support
  3035. case INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION:
  3036. case INPUT_REQUEST_MOD_GAME_COMMAND_2_AT_POSITION:
  3037. case INPUT_REQUEST_MOD_GAME_COMMAND_3_AT_POSITION:
  3038. case INPUT_REQUEST_MOD_GAME_COMMAND_4_AT_POSITION:
  3039. {
  3040. DLLExportClass::Adjust_Internal_View();
  3041. DLLForceMouseX = x1;
  3042. DLLForceMouseY = y1;
  3043. _Kbd->MouseQX = x1;
  3044. _Kbd->MouseQY = y1;
  3045. COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
  3046. CELL cell = Coord_Cell(coord);
  3047. if (Map.Pixel_To_Coord(x1, y1))
  3048. {
  3049. // TBD: For our ever-awesome Community Modders!
  3050. //
  3051. // PlayerPtr->Handle_Mod_Game_Command(cell, input_event - INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION);
  3052. }
  3053. break;
  3054. }
  3055. default:
  3056. break;
  3057. }
  3058. }
  3059. /**************************************************************************************************
  3060. * CNC_Handle_Structure_Request -- Process requests to repair and sell structures.
  3061. *
  3062. * In:
  3063. *
  3064. *
  3065. * Out:
  3066. *
  3067. *
  3068. *
  3069. * History: 4/29/2019 - LLL
  3070. **************************************************************************************************/
  3071. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Structure_Request(StructureRequestEnum request_type, uint64 player_id, int object_id)
  3072. {
  3073. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3074. return;
  3075. }
  3076. switch (request_type)
  3077. {
  3078. case INPUT_STRUCTURE_REPAIR_START:
  3079. DLLExportClass::Repair_Mode(player_id);
  3080. break;
  3081. case INPUT_STRUCTURE_REPAIR:
  3082. DLLExportClass::Repair(player_id, object_id);
  3083. break;
  3084. case INPUT_STRUCTURE_SELL_START:
  3085. DLLExportClass::Sell_Mode(player_id);
  3086. break;
  3087. case INPUT_STRUCTURE_SELL:
  3088. DLLExportClass::Sell(player_id, object_id);
  3089. break;
  3090. case INPUT_STRUCTURE_CANCEL:
  3091. DLLExportClass::Repair_Sell_Cancel(player_id);
  3092. break;
  3093. default:
  3094. break;
  3095. }
  3096. }
  3097. /**************************************************************************************************
  3098. * CNC_Handle_Unit_Request -- Process requests on selected units.
  3099. *
  3100. * In:
  3101. *
  3102. *
  3103. * Out:
  3104. *
  3105. *
  3106. *
  3107. * History: 10/15/2019 - SKY
  3108. **************************************************************************************************/
  3109. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Unit_Request(UnitRequestEnum request_type, uint64 player_id)
  3110. {
  3111. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3112. return;
  3113. }
  3114. switch (request_type)
  3115. {
  3116. case INPUT_UNIT_SCATTER:
  3117. DLLExportClass::Scatter_Selected(player_id);
  3118. break;
  3119. case INPUT_UNIT_SELECT_NEXT:
  3120. DLLExportClass::Select_Next_Unit(player_id);
  3121. break;
  3122. case INPUT_UNIT_SELECT_PREVIOUS:
  3123. DLLExportClass::Select_Previous_Unit(player_id);
  3124. break;
  3125. case INPUT_UNIT_GUARD_MODE:
  3126. DLLExportClass::Selected_Guard_Mode(player_id);
  3127. break;
  3128. case INPUT_UNIT_STOP:
  3129. DLLExportClass::Selected_Stop(player_id);
  3130. break;
  3131. case INPUT_UNIT_FORMATION_TOGGLE:
  3132. DLLExportClass::Team_Units_Formation_Toggle_On(player_id);
  3133. break;
  3134. case INPUT_UNIT_QUEUED_MOVEMENT_ON:
  3135. // Red Alert Only
  3136. DLLExportClass::Units_Queued_Movement_Toggle(player_id, true);
  3137. break;
  3138. case INPUT_UNIT_QUEUED_MOVEMENT_OFF:
  3139. // Red Alert Only
  3140. DLLExportClass::Units_Queued_Movement_Toggle(player_id, false);
  3141. break;
  3142. default:
  3143. break;
  3144. }
  3145. }
  3146. /**************************************************************************************************
  3147. * CNC_Handle_Sidebar_Request -- Process an input request to the sidebar
  3148. *
  3149. * In:
  3150. *
  3151. *
  3152. * Out:
  3153. *
  3154. *
  3155. *
  3156. * History: 1/7/2019 5:20PM - ST
  3157. **************************************************************************************************/
  3158. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Sidebar_Request(SidebarRequestEnum request_type, uint64 player_id, int buildable_type, int buildable_id, short cell_x, short cell_y)
  3159. {
  3160. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3161. return;
  3162. }
  3163. switch (request_type) {
  3164. // Changing right-click support for first put building on hold, and then subsequenct right-clicks to decrement that queue count for 1x or 5x; Then, 1x or 5x Left click will resume from hold
  3165. // Handle and fall through to start construction (from hold state) below
  3166. case SIDEBAR_REQUEST_START_CONSTRUCTION_MULTI:
  3167. case SIDEBAR_REQUEST_START_CONSTRUCTION:
  3168. DLLExportClass::Start_Construction(player_id, buildable_type, buildable_id);
  3169. break;
  3170. case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
  3171. DLLExportClass::Hold_Construction(player_id, buildable_type, buildable_id);
  3172. break;
  3173. case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
  3174. DLLExportClass::Cancel_Construction(player_id, buildable_type, buildable_id);
  3175. break;
  3176. case SIDEBAR_REQUEST_START_PLACEMENT:
  3177. DLLExportClass::Start_Placement(player_id, buildable_type, buildable_id);
  3178. break;
  3179. case SIDEBAR_REQUEST_PLACE:
  3180. DLLExportClass::Place(player_id, buildable_type, buildable_id, cell_x, cell_y);
  3181. break;
  3182. case SIDEBAR_CANCEL_PLACE:
  3183. DLLExportClass::Cancel_Placement(player_id, buildable_type, buildable_id);
  3184. break;
  3185. default:
  3186. break;
  3187. }
  3188. }
  3189. /**************************************************************************************************
  3190. * CNC_Handle_SuperWeapon_Request
  3191. *
  3192. * In:
  3193. *
  3194. *
  3195. * Out:
  3196. *
  3197. *
  3198. *
  3199. * History:
  3200. **************************************************************************************************/
  3201. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_SuperWeapon_Request(SuperWeaponRequestEnum request_type, uint64 player_id, int buildable_type, int buildable_id, int x1, int y1)
  3202. {
  3203. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3204. return;
  3205. }
  3206. switch (request_type)
  3207. {
  3208. case SUPERWEAPON_REQUEST_PLACE_SUPER_WEAPON:
  3209. DLLExportClass::Place_Super_Weapon(player_id, buildable_type, buildable_id, x1, y1);
  3210. break;
  3211. }
  3212. }
  3213. /**************************************************************************************************
  3214. * CNC_Handle_ControlGroup_Request
  3215. *
  3216. * In:
  3217. *
  3218. *
  3219. * Out:
  3220. *
  3221. *
  3222. *
  3223. * History:
  3224. **************************************************************************************************/
  3225. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_ControlGroup_Request(ControlGroupRequestEnum request_type, uint64 player_id, unsigned char control_group_index)
  3226. {
  3227. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3228. return;
  3229. }
  3230. switch (request_type)
  3231. {
  3232. case CONTROL_GROUP_REQUEST_CREATE:
  3233. DLLExportClass::Create_Control_Group(control_group_index);
  3234. break;
  3235. case CONTROL_GROUP_REQUEST_TOGGLE:
  3236. DLLExportClass::Toggle_Control_Group_Selection(control_group_index);
  3237. break;
  3238. case CONTROL_GROUP_REQUEST_ADDITIVE_SELECTION:
  3239. DLLExportClass::Add_To_Control_Group(control_group_index);
  3240. break;
  3241. }
  3242. }
  3243. /**************************************************************************************************
  3244. * DLLExportClass::Get_Layer_State -- Get a snapshot of the sidebar state
  3245. *
  3246. * In:
  3247. *
  3248. * Out:
  3249. *
  3250. *
  3251. *
  3252. * History: 1/29/2019 11:37AM - ST
  3253. **************************************************************************************************/
  3254. bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  3255. {
  3256. /*
  3257. ** Get the player for this...
  3258. */
  3259. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3260. return false;
  3261. }
  3262. CNCSidebarStruct *sidebar = (CNCSidebarStruct*) buffer_in;
  3263. unsigned int memory_needed = sizeof(*sidebar); // Base amount needed. Will need more depending on how many entries there are
  3264. int entry_index = 0;
  3265. sidebar->Credits = 0;
  3266. sidebar->CreditsCounter = 0;
  3267. sidebar->Tiberium = 0;
  3268. sidebar->MaxTiberium = 0;
  3269. sidebar->PowerProduced = 0;
  3270. sidebar->PowerDrained = 0;
  3271. sidebar->RepairBtnEnabled = false;
  3272. sidebar->SellBtnEnabled = false;
  3273. sidebar->RadarMapActive = false;
  3274. sidebar->MissionTimer = -1;
  3275. sidebar->UnitsKilled = 0;
  3276. sidebar->BuildingsKilled = 0;
  3277. sidebar->UnitsLost = 0;
  3278. sidebar->BuildingsLost = 0;
  3279. sidebar->TotalHarvestedCredits = 0;
  3280. if (PlayerPtr) {
  3281. sidebar->Credits = PlayerPtr->Credits;
  3282. sidebar->CreditsCounter = PlayerPtr->VisibleCredits.Current; // Timed display
  3283. // sidebar->CreditsCounter = PlayerPtr->VisibleCredits.Credits; // Actual
  3284. sidebar->Tiberium = PlayerPtr->Tiberium;
  3285. sidebar->MaxTiberium = PlayerPtr->Capacity;
  3286. sidebar->PowerProduced = PlayerPtr->Power;
  3287. sidebar->PowerDrained = PlayerPtr->Drain;
  3288. sidebar->RepairBtnEnabled = PlayerPtr->BScan > 0;
  3289. sidebar->SellBtnEnabled = PlayerPtr->BScan > 0;
  3290. sidebar->RadarMapActive = PlayerPtr->Radar == RADAR_ON;
  3291. // A. Get the DestroyedBuildings and DestroyedInfantry stats if they are available at this point
  3292. if (PlayerPtr->DestroyedBuildings) {
  3293. for ( int index = 0; index < PlayerPtr->DestroyedBuildings->Get_Unit_Count(); index ++ )
  3294. {
  3295. unsigned int count = (unsigned int) PlayerPtr->DestroyedBuildings->Get_Unit_Total( index );
  3296. sidebar->BuildingsKilled += count;
  3297. }
  3298. }
  3299. if (PlayerPtr->DestroyedInfantry) {
  3300. for ( int index = 0; index < PlayerPtr->DestroyedInfantry->Get_Unit_Count(); index ++ )
  3301. {
  3302. unsigned int count = (unsigned int) PlayerPtr->DestroyedInfantry->Get_Unit_Total( index );
  3303. sidebar->UnitsKilled += count; // Includes Infantry, Vehicles, Aircraft
  3304. }
  3305. }
  3306. if (PlayerPtr->DestroyedUnits) {
  3307. for ( int index = 0; index < PlayerPtr->DestroyedUnits->Get_Unit_Count(); index ++ )
  3308. {
  3309. unsigned int count = (unsigned int) PlayerPtr->DestroyedUnits->Get_Unit_Total( index );
  3310. sidebar->UnitsKilled += count; // Includes Infantry, Vehicles, Aircraft
  3311. }
  3312. }
  3313. if (PlayerPtr->DestroyedAircraft) {
  3314. for ( int index = 0; index < PlayerPtr->DestroyedAircraft->Get_Unit_Count(); index ++ )
  3315. {
  3316. unsigned int count = (unsigned int) PlayerPtr->DestroyedAircraft->Get_Unit_Total( index );
  3317. sidebar->UnitsKilled += count; // Includes Infantry, Vehicles, Aircraft
  3318. }
  3319. }
  3320. // B. If the DestroyedBuildings and DestroyedInfantry stats seemed to be unvailable, this is another way to do it
  3321. // Note that we need to do both of these depending on which type of match we are running, as well as for Replays/Observer and live stats reporting
  3322. // We can't just do it this way for everything, as it does not work for all cases
  3323. if (sidebar->BuildingsKilled == 0)
  3324. {
  3325. for (unsigned int house_index = 0; house_index < HOUSE_COUNT; house_index ++)
  3326. {
  3327. sidebar->BuildingsKilled += PlayerPtr->BuildingsKilled[ house_index ];
  3328. }
  3329. }
  3330. if (sidebar->UnitsKilled == 0)
  3331. {
  3332. for (unsigned int house_index = 0; house_index < HOUSE_COUNT; house_index ++)
  3333. {
  3334. sidebar->UnitsKilled += PlayerPtr->UnitsKilled[ house_index ]; // Includes Infantry, Vehicles, Aircraft
  3335. }
  3336. }
  3337. sidebar->UnitsLost = PlayerPtr->UnitsLost;
  3338. sidebar->BuildingsLost = PlayerPtr->BuildingsLost;
  3339. sidebar->TotalHarvestedCredits = PlayerPtr->HarvestedCredits;
  3340. }
  3341. if (GameToPlay == GAME_NORMAL) {
  3342. /*
  3343. ** Get each sidebar column
  3344. */
  3345. for (int c = 0 ; c < 2 ; c++) {
  3346. sidebar->EntryCount[c] = Map.Column[c].BuildableCount;
  3347. /*
  3348. ** Each production slot in the column
  3349. */
  3350. for (int b=0 ; b < Map.Column[c].BuildableCount ; b++) {
  3351. CNCSidebarEntryStruct &sidebar_entry = sidebar->Entries[entry_index++];
  3352. if ((entry_index + 1) * sizeof(CNCSidebarEntryStruct) + memory_needed > buffer_size) {
  3353. return false;
  3354. }
  3355. memset(&sidebar_entry, 0, sizeof(sidebar_entry));
  3356. sidebar_entry.AssetName[0] = 0;
  3357. sidebar_entry.Type = UNKNOWN;
  3358. sidebar_entry.BuildableID = Map.Column[c].Buildables[b].BuildableID;
  3359. sidebar_entry.BuildableType = Map.Column[c].Buildables[b].BuildableType;
  3360. sidebar_entry.BuildableViaCapture = Map.Column[c].Buildables[b].BuildableViaCapture;
  3361. sidebar_entry.Fake = false;
  3362. TechnoTypeClass const * tech = Fetch_Techno_Type(Map.Column[c].Buildables[b].BuildableType, Map.Column[c].Buildables[b].BuildableID);
  3363. sidebar_entry.SuperWeaponType = SW_NONE;
  3364. if (tech) {
  3365. sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias;
  3366. sidebar_entry.PowerProvided = 0;
  3367. sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House);
  3368. strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
  3369. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3370. } else {
  3371. sidebar_entry.Cost = 0;
  3372. sidebar_entry.AssetName[0] = 0;
  3373. }
  3374. SuperClass* super_weapon = nullptr;
  3375. bool isbusy = false;
  3376. switch (Map.Column[c].Buildables[b].BuildableType) {
  3377. case RTTI_INFANTRYTYPE:
  3378. sidebar_entry.Type = INFANTRY_TYPE;
  3379. isbusy = (PlayerPtr->InfantryFactory != -1);
  3380. isbusy |= Infantry.Avail() <= 0;
  3381. break;
  3382. case RTTI_UNITTYPE:
  3383. isbusy = (PlayerPtr->UnitFactory != -1);
  3384. sidebar_entry.Type = UNIT_TYPE;
  3385. isbusy |= Units.Avail() <= 0;
  3386. break;
  3387. case RTTI_AIRCRAFTTYPE:
  3388. isbusy = (PlayerPtr->AircraftFactory != -1);
  3389. sidebar_entry.Type = AIRCRAFT_TYPE;
  3390. isbusy |= Aircraft.Avail() <= 0;
  3391. break;
  3392. case RTTI_BUILDINGTYPE:
  3393. {
  3394. isbusy = (PlayerPtr->BuildingFactory != -1);
  3395. isbusy |= Buildings.Avail() <= 0;
  3396. sidebar_entry.Type = BUILDING_TYPE;
  3397. const BuildingTypeClass* build_type = static_cast<const BuildingTypeClass*>(tech);
  3398. sidebar_entry.PowerProvided = build_type->Power - build_type->Drain;
  3399. }
  3400. break;
  3401. default:
  3402. sidebar_entry.Type = UNKNOWN;
  3403. break;
  3404. case RTTI_SPECIAL:
  3405. switch (Map.Column[c].Buildables[b].BuildableID)
  3406. {
  3407. case SPC_ION_CANNON:
  3408. sidebar_entry.SuperWeaponType = SW_ION_CANNON;
  3409. sidebar_entry.Type = SPECIAL;
  3410. strncpy(sidebar_entry.AssetName, "SW_Ion", CNC_OBJECT_ASSET_NAME_LENGTH);
  3411. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3412. super_weapon = &PlayerPtr->IonCannon;
  3413. break;
  3414. case SPC_NUCLEAR_BOMB:
  3415. sidebar_entry.SuperWeaponType = SW_NUKE;
  3416. sidebar_entry.Type = SPECIAL;
  3417. strncpy(sidebar_entry.AssetName, "SW_Nuke", CNC_OBJECT_ASSET_NAME_LENGTH);
  3418. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3419. super_weapon = &PlayerPtr->NukeStrike;
  3420. break;
  3421. case SPC_AIR_STRIKE:
  3422. sidebar_entry.SuperWeaponType = SW_AIR_STRIKE;
  3423. sidebar_entry.Type = SPECIAL;
  3424. strncpy(sidebar_entry.AssetName, "SW_AirStrike", CNC_OBJECT_ASSET_NAME_LENGTH);
  3425. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3426. super_weapon = &PlayerPtr->AirStrike;
  3427. break;
  3428. default:
  3429. sidebar_entry.SuperWeaponType = SW_UNKNOWN;
  3430. sidebar_entry.Type = SPECIAL;
  3431. break;
  3432. }
  3433. break;
  3434. }
  3435. int fnumber = Map.Column[c].Buildables[b].Factory;
  3436. FactoryClass * factory = NULL;
  3437. if (tech && fnumber != -1) {
  3438. factory = Factories.Raw_Ptr(fnumber);
  3439. }
  3440. if (super_weapon != nullptr)
  3441. {
  3442. sidebar_entry.Progress = (float)super_weapon->Anim_Stage() / (float)SuperClass::ANIMATION_STAGES;
  3443. sidebar_entry.Completed = super_weapon->Is_Ready();
  3444. sidebar_entry.Constructing = super_weapon->Anim_Stage() != SuperClass::ANIMATION_STAGES;
  3445. sidebar_entry.ConstructionOnHold = false;
  3446. sidebar_entry.PlacementListLength = 0;
  3447. sidebar_entry.PowerProvided = 0;
  3448. sidebar_entry.BuildTime = super_weapon->Get_Recharge_Time();
  3449. }
  3450. else
  3451. {
  3452. sidebar_entry.Completed = false;
  3453. sidebar_entry.Constructing = false;
  3454. sidebar_entry.ConstructionOnHold = false;
  3455. sidebar_entry.Progress = 0.0f;
  3456. sidebar_entry.Busy = isbusy;
  3457. sidebar_entry.PlacementListLength = 0;
  3458. if (factory) {
  3459. if (factory->Is_Building()) {
  3460. sidebar_entry.Constructing = true;
  3461. sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
  3462. sidebar_entry.Completed = factory->Has_Completed();
  3463. }
  3464. else {
  3465. sidebar_entry.Completed = factory->Has_Completed();
  3466. if (!sidebar_entry.Completed)
  3467. {
  3468. sidebar_entry.ConstructionOnHold = true;
  3469. sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
  3470. }
  3471. if (sidebar_entry.Completed && sidebar_entry.Type == BUILDING_TYPE) {
  3472. if (tech) {
  3473. BuildingTypeClass *building_type = (BuildingTypeClass*)tech;
  3474. short const *occupy_list = building_type->Occupy_List(true);
  3475. if (occupy_list) {
  3476. while (*occupy_list != REFRESH_EOL && sidebar_entry.PlacementListLength < MAX_OCCUPY_CELLS) {
  3477. sidebar_entry.PlacementList[sidebar_entry.PlacementListLength] = *occupy_list;
  3478. sidebar_entry.PlacementListLength++;
  3479. occupy_list++;
  3480. }
  3481. }
  3482. }
  3483. }
  3484. }
  3485. }
  3486. }
  3487. }
  3488. }
  3489. } else {
  3490. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  3491. SidebarGlyphxClass *context_sidebar = DLLExportClass::Get_Current_Context_Sidebar();
  3492. /*
  3493. ** Get each sidebar column
  3494. */
  3495. for (int c = 0 ; c < 2 ; c++) {
  3496. sidebar->EntryCount[c] = context_sidebar->Column[c].BuildableCount;
  3497. /*
  3498. ** Each production slot in the column
  3499. */
  3500. for (int b=0 ; b < context_sidebar->Column[c].BuildableCount ; b++) {
  3501. CNCSidebarEntryStruct &sidebar_entry = sidebar->Entries[entry_index++];
  3502. if ((entry_index + 1) * sizeof(CNCSidebarEntryStruct) + memory_needed > buffer_size) {
  3503. return false;
  3504. }
  3505. memset(&sidebar_entry, 0, sizeof(sidebar_entry));
  3506. sidebar_entry.AssetName[0] = 0;
  3507. sidebar_entry.Type = UNKNOWN;
  3508. sidebar_entry.BuildableID = context_sidebar->Column[c].Buildables[b].BuildableID;
  3509. sidebar_entry.BuildableType = context_sidebar->Column[c].Buildables[b].BuildableType;
  3510. sidebar_entry.BuildableViaCapture = context_sidebar->Column[c].Buildables[b].BuildableViaCapture;
  3511. sidebar_entry.Fake = false;
  3512. TechnoTypeClass const * tech = Fetch_Techno_Type(context_sidebar->Column[c].Buildables[b].BuildableType, context_sidebar->Column[c].Buildables[b].BuildableID);
  3513. sidebar_entry.SuperWeaponType = SW_NONE;
  3514. if (tech) {
  3515. sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias;
  3516. sidebar_entry.PowerProvided = 0;
  3517. sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House);
  3518. strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
  3519. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3520. } else {
  3521. sidebar_entry.Cost = 0;
  3522. sidebar_entry.AssetName[0] = 0;
  3523. }
  3524. SuperClass* super_weapon = nullptr;
  3525. bool isbusy = false;
  3526. switch (context_sidebar->Column[c].Buildables[b].BuildableType) {
  3527. case RTTI_INFANTRYTYPE:
  3528. sidebar_entry.Type = INFANTRY_TYPE;
  3529. isbusy = (PlayerPtr->InfantryFactory != -1);
  3530. isbusy |= Infantry.Avail() <= 0;
  3531. break;
  3532. case RTTI_UNITTYPE:
  3533. isbusy = (PlayerPtr->UnitFactory != -1);
  3534. isbusy |= Units.Avail() <= 0;
  3535. sidebar_entry.Type = UNIT_TYPE;
  3536. break;
  3537. case RTTI_AIRCRAFTTYPE:
  3538. isbusy = (PlayerPtr->AircraftFactory != -1);
  3539. isbusy |= Aircraft.Avail() <= 0;
  3540. sidebar_entry.Type = AIRCRAFT_TYPE;
  3541. break;
  3542. case RTTI_BUILDINGTYPE:
  3543. {
  3544. isbusy = (PlayerPtr->BuildingFactory != -1);
  3545. isbusy |= Buildings.Avail() <= 0;
  3546. sidebar_entry.Type = BUILDING_TYPE;
  3547. const BuildingTypeClass* build_type = static_cast<const BuildingTypeClass*>(tech);
  3548. sidebar_entry.PowerProvided = build_type->Power - build_type->Drain;
  3549. }
  3550. break;
  3551. default:
  3552. sidebar_entry.Type = UNKNOWN;
  3553. break;
  3554. case RTTI_SPECIAL:
  3555. switch (context_sidebar->Column[c].Buildables[b].BuildableID) {
  3556. case SPC_ION_CANNON:
  3557. sidebar_entry.SuperWeaponType = SW_ION_CANNON;
  3558. sidebar_entry.Type = SPECIAL;
  3559. strncpy(sidebar_entry.AssetName, "SW_Ion", CNC_OBJECT_ASSET_NAME_LENGTH);
  3560. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3561. super_weapon = &PlayerPtr->IonCannon;
  3562. break;
  3563. case SPC_NUCLEAR_BOMB:
  3564. sidebar_entry.SuperWeaponType = SW_NUKE;
  3565. sidebar_entry.Type = SPECIAL;
  3566. strncpy(sidebar_entry.AssetName, "SW_Nuke", CNC_OBJECT_ASSET_NAME_LENGTH);
  3567. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3568. super_weapon = &PlayerPtr->NukeStrike;
  3569. break;
  3570. case SPC_AIR_STRIKE:
  3571. sidebar_entry.SuperWeaponType = SW_AIR_STRIKE;
  3572. sidebar_entry.Type = SPECIAL;
  3573. strncpy(sidebar_entry.AssetName, "SW_AirStrike", CNC_OBJECT_ASSET_NAME_LENGTH);
  3574. sidebar_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  3575. super_weapon = &PlayerPtr->AirStrike;
  3576. break;
  3577. default:
  3578. sidebar_entry.SuperWeaponType = SW_UNKNOWN;
  3579. sidebar_entry.Type = SPECIAL;
  3580. break;
  3581. }
  3582. break;
  3583. }
  3584. if (super_weapon != nullptr)
  3585. {
  3586. sidebar_entry.Progress = (float)super_weapon->Anim_Stage() / (float)SuperClass::ANIMATION_STAGES;
  3587. sidebar_entry.Completed = super_weapon->Is_Ready();
  3588. sidebar_entry.Constructing = super_weapon->Anim_Stage() != SuperClass::ANIMATION_STAGES;
  3589. sidebar_entry.ConstructionOnHold = false;
  3590. sidebar_entry.PlacementListLength = 0;
  3591. sidebar_entry.PowerProvided = 0;
  3592. sidebar_entry.BuildTime = super_weapon->Get_Recharge_Time();
  3593. }
  3594. else
  3595. {
  3596. int fnumber = context_sidebar->Column[c].Buildables[b].Factory;
  3597. FactoryClass * factory = NULL;
  3598. if (tech && fnumber != -1) {
  3599. factory = Factories.Raw_Ptr(fnumber);
  3600. }
  3601. sidebar_entry.Completed = false;
  3602. sidebar_entry.Constructing = false;
  3603. sidebar_entry.ConstructionOnHold = false;
  3604. sidebar_entry.Progress = 0.0f;
  3605. sidebar_entry.Busy = isbusy;
  3606. sidebar_entry.PlacementListLength = 0;
  3607. if (factory) {
  3608. if (factory->Is_Building()) {
  3609. sidebar_entry.Constructing = true;
  3610. sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
  3611. sidebar_entry.Completed = factory->Has_Completed();
  3612. }
  3613. else {
  3614. sidebar_entry.Completed = factory->Has_Completed();
  3615. if (!sidebar_entry.Completed)
  3616. {
  3617. sidebar_entry.ConstructionOnHold = true;
  3618. sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
  3619. }
  3620. if (sidebar_entry.Completed && sidebar_entry.Type == BUILDING_TYPE) {
  3621. if (tech) {
  3622. BuildingTypeClass *building_type = (BuildingTypeClass*)tech;
  3623. short const *occupy_list = building_type->Occupy_List(true);
  3624. if (occupy_list) {
  3625. while (*occupy_list != REFRESH_EOL && sidebar_entry.PlacementListLength < MAX_OCCUPY_CELLS) {
  3626. sidebar_entry.PlacementList[sidebar_entry.PlacementListLength] = *occupy_list;
  3627. sidebar_entry.PlacementListLength++;
  3628. occupy_list++;
  3629. }
  3630. }
  3631. }
  3632. }
  3633. }
  3634. }
  3635. }
  3636. }
  3637. }
  3638. }
  3639. }
  3640. return true;
  3641. }
  3642. static const int _map_width_shift_bits = 6;
  3643. void DLLExportClass::Calculate_Placement_Distances(BuildingTypeClass* placement_type, unsigned char* placement_distance)
  3644. {
  3645. int map_cell_x = Map.MapCellX;
  3646. int map_cell_y = Map.MapCellY;
  3647. int map_cell_width = Map.MapCellWidth;
  3648. int map_cell_height = Map.MapCellHeight;
  3649. if (map_cell_x > 0) {
  3650. map_cell_x--;
  3651. map_cell_width++;
  3652. }
  3653. if (map_cell_width < MAP_MAX_CELL_WIDTH) {
  3654. map_cell_width++;
  3655. }
  3656. if (map_cell_y > 0) {
  3657. map_cell_y--;
  3658. map_cell_height++;
  3659. }
  3660. if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
  3661. map_cell_height++;
  3662. }
  3663. memset(placement_distance, 255U, MAP_CELL_TOTAL);
  3664. for (int y = 0; y < map_cell_height; y++) {
  3665. for (int x = 0; x < map_cell_width; x++) {
  3666. CELL cell = (CELL)map_cell_x + x + ((map_cell_y + y) << _map_width_shift_bits);
  3667. BuildingClass* base = (BuildingClass*)Map[cell].Cell_Find_Object(RTTI_BUILDING);
  3668. if ((base && base->House->Class->House == PlayerPtr->Class->House) || (Map[cell].Owner == PlayerPtr->Class->House)) {
  3669. placement_distance[cell] = 0U;
  3670. for (FacingType facing = FACING_N; facing < FACING_COUNT; facing++) {
  3671. CELL adjcell = Adjacent_Cell(cell, facing);
  3672. if (Map.In_Radar(adjcell)) {
  3673. placement_distance[adjcell] = min(placement_distance[adjcell], 1U);
  3674. }
  3675. }
  3676. }
  3677. }
  3678. }
  3679. }
  3680. void Recalculate_Placement_Distances()
  3681. {
  3682. DLLExportClass::Recalculate_Placement_Distances();
  3683. }
  3684. void DLLExportClass::Recalculate_Placement_Distances()
  3685. {
  3686. if (PlacementType[CurrentLocalPlayerIndex] != NULL) {
  3687. Calculate_Placement_Distances(PlacementType[CurrentLocalPlayerIndex], PlacementDistance[CurrentLocalPlayerIndex]);
  3688. }
  3689. }
  3690. /**************************************************************************************************
  3691. * DLLExportClass::Get_Placement_State -- Get a snapshot of legal validity of placing a structure on all map cells
  3692. *
  3693. * In:
  3694. *
  3695. * Out:
  3696. *
  3697. *
  3698. *
  3699. * History: 2/4/2019 3:11PM - ST
  3700. **************************************************************************************************/
  3701. bool DLLExportClass::Get_Placement_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  3702. {
  3703. /*
  3704. ** Get the player for this...
  3705. */
  3706. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3707. return false;
  3708. }
  3709. if (PlacementType[CurrentLocalPlayerIndex] == NULL) {
  3710. return false;
  3711. }
  3712. CNCPlacementInfoStruct *placement_info = (CNCPlacementInfoStruct*) buffer_in;
  3713. unsigned int memory_needed = sizeof(*placement_info); // Base amount needed. Will need more depending on how many entries there are
  3714. int map_cell_x = Map.MapCellX;
  3715. int map_cell_y = Map.MapCellY;
  3716. int map_cell_width = Map.MapCellWidth;
  3717. int map_cell_height = Map.MapCellHeight;
  3718. if (map_cell_x > 0) {
  3719. map_cell_x--;
  3720. map_cell_width++;
  3721. }
  3722. if (map_cell_width < MAP_MAX_CELL_WIDTH) {
  3723. map_cell_width++;
  3724. }
  3725. if (map_cell_y > 0) {
  3726. map_cell_y--;
  3727. map_cell_height++;
  3728. }
  3729. if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
  3730. map_cell_height++;
  3731. }
  3732. memory_needed += map_cell_width * map_cell_height * sizeof(CNCPlacementCellInfoStruct);
  3733. if (memory_needed + 128 >= buffer_size) {
  3734. return false;
  3735. }
  3736. placement_info->Count = map_cell_width * map_cell_height;
  3737. int index = 0;
  3738. for (int y=0 ; y < map_cell_height ; y++) {
  3739. for (int x=0 ; x < map_cell_width ; x++) {
  3740. CELL cell = (CELL) map_cell_x + x + ((map_cell_y + y) << _map_width_shift_bits);
  3741. bool pass = Passes_Proximity_Check(cell, PlacementType[CurrentLocalPlayerIndex], PlacementDistance[CurrentLocalPlayerIndex]);
  3742. CellClass * cellptr = &Map[cell];
  3743. bool clear = cellptr->Is_Generally_Clear();
  3744. CNCPlacementCellInfoStruct &placement_cell_info = placement_info->CellInfo[index++];
  3745. placement_cell_info.PassesProximityCheck = pass;
  3746. placement_cell_info.GenerallyClear = clear;
  3747. }
  3748. }
  3749. Map.ZoneOffset = 0;
  3750. return true;
  3751. }
  3752. bool DLLExportClass::Passes_Proximity_Check(CELL cell_in, BuildingTypeClass *placement_type, unsigned char* placement_distance)
  3753. {
  3754. /*
  3755. ** Scan through all cells that the building foundation would cover. If any adjacent
  3756. ** cells to these are of friendly persuasion, then consider the proximity check to
  3757. ** have been a success.
  3758. */
  3759. short const *occupy_list = placement_type->Occupy_List(true);
  3760. while (*occupy_list != REFRESH_EOL) {
  3761. CELL center_cell = cell_in + *occupy_list++;
  3762. if (!Map.In_Radar(center_cell)) {
  3763. return false;
  3764. }
  3765. if (placement_distance[center_cell] <= 1U) {
  3766. return true;
  3767. }
  3768. }
  3769. return false;
  3770. }
  3771. /**************************************************************************************************
  3772. * DLLExportClass::Start_Construction -- Start sidebar construction
  3773. *
  3774. * In:
  3775. *
  3776. * Out:
  3777. *
  3778. *
  3779. *
  3780. * History: 1/29/2019 11:37AM - ST
  3781. **************************************************************************************************/
  3782. bool DLLExportClass::Start_Construction(uint64 player_id, int buildable_type, int buildable_id)
  3783. {
  3784. /*
  3785. ** Get the player for this...
  3786. */
  3787. if (!DLLExportClass::Set_Player_Context(player_id)) {
  3788. return false;
  3789. }
  3790. if (GameToPlay == GAME_NORMAL) {
  3791. return Construction_Action(SIDEBAR_REQUEST_START_CONSTRUCTION, player_id, buildable_type, buildable_id);
  3792. }
  3793. return MP_Construction_Action(SIDEBAR_REQUEST_START_CONSTRUCTION, player_id, buildable_type, buildable_id);
  3794. }
  3795. /**************************************************************************************************
  3796. * DLLExportClass::Hold_Construction -- Pause sidebar construction
  3797. *
  3798. * In:
  3799. *
  3800. * Out:
  3801. *
  3802. *
  3803. *
  3804. * History: 6/12/2019 JAS
  3805. **************************************************************************************************/
  3806. bool DLLExportClass::Hold_Construction(uint64 player_id, int buildable_type, int buildable_id)
  3807. {
  3808. if (!DLLExportClass::Set_Player_Context(player_id))
  3809. {
  3810. return false;
  3811. }
  3812. if (GameToPlay == GAME_NORMAL) {
  3813. return Construction_Action(SIDEBAR_REQUEST_HOLD_CONSTRUCTION, player_id, buildable_type, buildable_id);
  3814. }
  3815. return MP_Construction_Action(SIDEBAR_REQUEST_HOLD_CONSTRUCTION, player_id, buildable_type, buildable_id);
  3816. }
  3817. /**************************************************************************************************
  3818. * DLLExportClass::Cancel_Construction -- Stop sidebar construction
  3819. *
  3820. * In:
  3821. *
  3822. * Out:
  3823. *
  3824. *
  3825. *
  3826. * History: 6/12/2019 JAS
  3827. **************************************************************************************************/
  3828. bool DLLExportClass::Cancel_Construction(uint64 player_id, int buildable_type, int buildable_id)
  3829. {
  3830. if (!DLLExportClass::Set_Player_Context(player_id))
  3831. {
  3832. return false;
  3833. }
  3834. return Cancel_Placement(player_id, buildable_type, buildable_id) &&
  3835. ((GameToPlay == GAME_NORMAL) ?
  3836. Construction_Action(SIDEBAR_REQUEST_CANCEL_CONSTRUCTION, player_id, buildable_type, buildable_id) :
  3837. MP_Construction_Action(SIDEBAR_REQUEST_CANCEL_CONSTRUCTION, player_id, buildable_type, buildable_id));
  3838. }
  3839. /**************************************************************************************************
  3840. * DLLExportClass::Construction_Action -- Reproduce actions on the sidebar
  3841. *
  3842. * In:
  3843. *
  3844. * Out:
  3845. *
  3846. *
  3847. *
  3848. * History: 1/29/2019 11:37AM - ST
  3849. **************************************************************************************************/
  3850. bool DLLExportClass::Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id)
  3851. {
  3852. /*
  3853. **
  3854. ** Based on SidebarClass::StripClass::SelectClass::Action
  3855. **
  3856. ** Most of this code is validating that the game is in the correct state to be able to act on a sidebar icon
  3857. **
  3858. */
  3859. for (int c = 0 ; c < 2 ; c++) {
  3860. /*
  3861. ** Each production slot in the column
  3862. */
  3863. for (int b=0 ; b < Map.Column[c].BuildableCount ; b++) {
  3864. if (Map.Column[c].Buildables[b].BuildableID == buildable_id) {
  3865. if (Map.Column[c].Buildables[b].BuildableType == buildable_type) {
  3866. int genfactory = -1;
  3867. switch (buildable_type) {
  3868. case RTTI_INFANTRYTYPE:
  3869. genfactory = PlayerPtr->InfantryFactory;
  3870. break;
  3871. case RTTI_UNITTYPE:
  3872. genfactory = PlayerPtr->UnitFactory;
  3873. break;
  3874. case RTTI_AIRCRAFTTYPE:
  3875. genfactory = PlayerPtr->AircraftFactory;
  3876. break;
  3877. case RTTI_BUILDINGTYPE:
  3878. genfactory = PlayerPtr->BuildingFactory;
  3879. break;
  3880. default:
  3881. genfactory = -1;
  3882. break;
  3883. }
  3884. int fnumber = Map.Column[c].Buildables[b].Factory;
  3885. int spc = 0;
  3886. ObjectTypeClass const * choice = NULL;
  3887. if (buildable_type != RTTI_SPECIAL) {
  3888. choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
  3889. } else {
  3890. spc = buildable_id;
  3891. }
  3892. FactoryClass * factory = NULL;
  3893. if (fnumber != -1) {
  3894. factory = Factories.Raw_Ptr(fnumber);
  3895. }
  3896. if (spc == 0 && choice) {
  3897. if (fnumber == -1 && genfactory != -1) {
  3898. return(false);
  3899. }
  3900. if (factory) {
  3901. /*
  3902. ** If this object is currently being built, then give a scold sound and text and then
  3903. ** bail.
  3904. */
  3905. switch (construction_action)
  3906. {
  3907. case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
  3908. On_Speech(PlayerPtr, VOX_CANCELED); // Speak(VOX_CANCELED);
  3909. OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
  3910. break;
  3911. case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
  3912. if (factory->Is_Building())
  3913. {
  3914. On_Speech(PlayerPtr, VOX_SUSPENDED); // Speak(VOX_SUSPENDED);
  3915. OutList.Add(EventClass(EventClass::SUSPEND, (RTTIType)buildable_type, buildable_id));
  3916. }
  3917. break;
  3918. default:
  3919. if (factory->Is_Building()) {
  3920. On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
  3921. return false;
  3922. }
  3923. else {
  3924. /*
  3925. ** If production has completed, then attempt to have the object exit
  3926. ** the factory or go into placement mode.
  3927. */
  3928. if (factory->Has_Completed()) {
  3929. TechnoClass * pending = factory->Get_Object();
  3930. if (!pending && factory->Get_Special_Item()) {
  3931. // TO_DO
  3932. //Map.IsTargettingMode = true;
  3933. }
  3934. else {
  3935. BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
  3936. if (!builder) {
  3937. OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
  3938. On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
  3939. }
  3940. else {
  3941. /*
  3942. ** If the completed object is a building, then change the
  3943. ** game state into building placement mode. This fact is
  3944. ** not transmitted to any linked computers until the moment
  3945. ** the building is actually placed down.
  3946. */
  3947. if (pending->What_Am_I() == RTTI_BUILDING) {
  3948. if (construction_action == SIDEBAR_REQUEST_START_PLACEMENT) {
  3949. PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
  3950. }
  3951. }
  3952. else {
  3953. /*
  3954. ** For objects that can leave the factory under their own
  3955. ** power, queue this event and process through normal house
  3956. ** production channels.
  3957. */
  3958. //OutList.Add(EventClass(EventClass::PLACE, otype, -1));
  3959. }
  3960. }
  3961. }
  3962. }
  3963. else {
  3964. /*
  3965. ** The factory must have been in a suspended state. Resume construction
  3966. ** normally.
  3967. */
  3968. if (construction_action == SIDEBAR_REQUEST_START_CONSTRUCTION) {
  3969. On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
  3970. OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
  3971. return true;
  3972. }
  3973. }
  3974. }
  3975. break;
  3976. }
  3977. } else {
  3978. switch (construction_action)
  3979. {
  3980. case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
  3981. case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
  3982. break;
  3983. default:
  3984. /*
  3985. ** If this side strip is already busy with production, then ignore the
  3986. ** input and announce this fact.
  3987. */
  3988. On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
  3989. OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
  3990. /*
  3991. ** Execute immediately so we get the sidebar feedback
  3992. */
  3993. Queue_AI();
  3994. return true;
  3995. }
  3996. }
  3997. }
  3998. }
  3999. }
  4000. }
  4001. }
  4002. return false;
  4003. }
  4004. /**************************************************************************************************
  4005. * DLLExportClass::MP_Construction_Action -- Reproduce actions on the sidebar
  4006. *
  4007. * In:
  4008. *
  4009. * Out:
  4010. *
  4011. *
  4012. *
  4013. * History: 3/26/2019 1:02PM - ST
  4014. **************************************************************************************************/
  4015. bool DLLExportClass::MP_Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id)
  4016. {
  4017. /*
  4018. **
  4019. ** Based on SidebarClass::StripClass::SelectClass::Action
  4020. **
  4021. ** Most of this code is validating that the game is in the correct state to be able to act on a sidebar icon
  4022. **
  4023. */
  4024. SidebarGlyphxClass *context_sidebar = DLLExportClass::Get_Current_Context_Sidebar();
  4025. for (int c = 0 ; c < 2 ; c++) {
  4026. /*
  4027. ** Each production slot in the column
  4028. */
  4029. for (int b=0 ; b < context_sidebar->Column[c].BuildableCount ; b++) {
  4030. if (context_sidebar->Column[c].Buildables[b].BuildableID == buildable_id) {
  4031. if (context_sidebar->Column[c].Buildables[b].BuildableType == buildable_type) {
  4032. int genfactory = -1;
  4033. switch (buildable_type) {
  4034. case RTTI_INFANTRYTYPE:
  4035. genfactory = PlayerPtr->InfantryFactory;
  4036. break;
  4037. case RTTI_UNITTYPE:
  4038. genfactory = PlayerPtr->UnitFactory;
  4039. break;
  4040. case RTTI_AIRCRAFTTYPE:
  4041. genfactory = PlayerPtr->AircraftFactory;
  4042. break;
  4043. case RTTI_BUILDINGTYPE:
  4044. genfactory = PlayerPtr->BuildingFactory;
  4045. break;
  4046. default:
  4047. genfactory = -1;
  4048. break;
  4049. }
  4050. int fnumber = context_sidebar->Column[c].Buildables[b].Factory;
  4051. int spc = 0;
  4052. ObjectTypeClass const * choice = NULL;
  4053. if (buildable_type != RTTI_SPECIAL) {
  4054. choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
  4055. } else {
  4056. spc = buildable_id;
  4057. }
  4058. FactoryClass * factory = NULL;
  4059. if (fnumber != -1) {
  4060. factory = Factories.Raw_Ptr(fnumber);
  4061. }
  4062. if (spc == 0 && choice) {
  4063. /*
  4064. ** If there is already a factory attached to this strip but the player didn't click
  4065. ** on the icon that has the attached factory, then say that the factory is busy and
  4066. ** ignore the click.
  4067. */
  4068. if (fnumber == -1 && genfactory != -1) {
  4069. On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
  4070. return(false);
  4071. }
  4072. if (factory) {
  4073. switch (construction_action)
  4074. {
  4075. case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
  4076. On_Speech(PlayerPtr, VOX_CANCELED); // Speak(VOX_CANCELED);
  4077. OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
  4078. break;
  4079. case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
  4080. if (factory->Is_Building())
  4081. {
  4082. On_Speech(PlayerPtr, VOX_SUSPENDED); // Speak(VOX_SUSPENDED);
  4083. OutList.Add(EventClass(EventClass::SUSPEND, (RTTIType)buildable_type, buildable_id));
  4084. }
  4085. break;
  4086. default:
  4087. /*
  4088. ** If this object is currently being built, then give a scold sound and text and then
  4089. ** bail.
  4090. */
  4091. if (factory->Is_Building()) {
  4092. On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
  4093. return false;
  4094. }
  4095. else {
  4096. /*
  4097. ** If production has completed, then attempt to have the object exit
  4098. ** the factory or go into placement mode.
  4099. */
  4100. if (factory->Has_Completed()) {
  4101. TechnoClass * pending = factory->Get_Object();
  4102. if (!pending && factory->Get_Special_Item()) {
  4103. // TO_DO
  4104. //Map.IsTargettingMode = true;
  4105. }
  4106. else {
  4107. BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
  4108. if (!builder) {
  4109. On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
  4110. OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
  4111. }
  4112. else {
  4113. /*
  4114. ** If the completed object is a building, then change the
  4115. ** game state into building placement mode. This fact is
  4116. ** not transmitted to any linked computers until the moment
  4117. ** the building is actually placed down.
  4118. */
  4119. if (pending->What_Am_I() == RTTI_BUILDING) {
  4120. if (construction_action == SIDEBAR_REQUEST_START_PLACEMENT) {
  4121. if (DLLExportClass::Legacy_Render_Enabled()) {
  4122. PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
  4123. } else {
  4124. Unselect_All();
  4125. }
  4126. }
  4127. }
  4128. else {
  4129. /*
  4130. ** For objects that can leave the factory under their own
  4131. ** power, queue this event and process through normal house
  4132. ** production channels.
  4133. */
  4134. //OutList.Add(EventClass(EventClass::PLACE, otype, -1));
  4135. }
  4136. }
  4137. }
  4138. }
  4139. else {
  4140. /*
  4141. ** The factory must have been in a suspended state. Resume construction
  4142. ** normally.
  4143. */
  4144. if (construction_action == SIDEBAR_REQUEST_START_CONSTRUCTION) {
  4145. On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
  4146. OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
  4147. return true;
  4148. }
  4149. }
  4150. }
  4151. break;
  4152. }
  4153. } else {
  4154. switch (construction_action)
  4155. {
  4156. case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
  4157. case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
  4158. break;
  4159. default:
  4160. /*
  4161. **
  4162. */
  4163. On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
  4164. OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
  4165. /*
  4166. ** Execute immediately so we get the sidebar feedback
  4167. */
  4168. DLLExportClass::Glyphx_Queue_AI();
  4169. return true;
  4170. }
  4171. }
  4172. }
  4173. }
  4174. }
  4175. }
  4176. }
  4177. return false;
  4178. }
  4179. /**************************************************************************************************
  4180. * DLLExportClass::Start_Placement -- Start placing a completed structure
  4181. *
  4182. * In:
  4183. *
  4184. * Out:
  4185. *
  4186. *
  4187. *
  4188. * History: 1/29/2019 11:37AM - ST
  4189. **************************************************************************************************/
  4190. bool DLLExportClass::Start_Placement(uint64 player_id, int buildable_type, int buildable_id)
  4191. {
  4192. /*
  4193. ** Get the player for this...
  4194. */
  4195. if (!DLLExportClass::Set_Player_Context(player_id)) {
  4196. return false;
  4197. }
  4198. BuildingClass *building = Get_Pending_Placement_Object(player_id, buildable_type, buildable_id);
  4199. if (building) {
  4200. TechnoTypeClass const * tech = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
  4201. if (tech) {
  4202. BuildingTypeClass *building_type = (BuildingTypeClass*) tech;
  4203. //short const *occupy_list = building_type->Get_Occupy_List(true);
  4204. PlacementType[CurrentLocalPlayerIndex] = building_type;
  4205. Recalculate_Placement_Distances();
  4206. if (GameToPlay == GAME_NORMAL) {
  4207. return Construction_Action(SIDEBAR_REQUEST_START_PLACEMENT, player_id, buildable_type, buildable_id);
  4208. }
  4209. return MP_Construction_Action(SIDEBAR_REQUEST_START_PLACEMENT, player_id, buildable_type, buildable_id);
  4210. }
  4211. }
  4212. return true;
  4213. }
  4214. /**************************************************************************************************
  4215. * DLLExportClass::Cancel_Placement -- Cancel placing a completed structure
  4216. *
  4217. * In:
  4218. *
  4219. * Out:
  4220. *
  4221. *
  4222. *
  4223. * History: 2/7/2019 10:52AM - ST
  4224. **************************************************************************************************/
  4225. bool DLLExportClass::Cancel_Placement(uint64 player_id, int buildable_type, int buildable_id)
  4226. {
  4227. /*
  4228. ** Get the player for this...
  4229. */
  4230. if (!DLLExportClass::Set_Player_Context(player_id)) {
  4231. return false;
  4232. }
  4233. PlacementType[CurrentLocalPlayerIndex] = NULL;
  4234. Map.PendingObjectPtr = 0;
  4235. Map.PendingObject = 0;
  4236. Map.PendingHouse = HOUSE_NONE;
  4237. Map.Set_Cursor_Shape(0);
  4238. return true;
  4239. }
  4240. /**************************************************************************************************
  4241. * DLLExportClass::Place -- Place a completed structure down
  4242. *
  4243. * In:
  4244. *
  4245. * Out:
  4246. *
  4247. *
  4248. *
  4249. * History: 2/6/2019 11:51AM - ST
  4250. **************************************************************************************************/
  4251. bool DLLExportClass::Place(uint64 player_id, int buildable_type, int buildable_id, short cell_x, short cell_y)
  4252. {
  4253. /*
  4254. ** Get the player for this...
  4255. */
  4256. if (!DLLExportClass::Set_Player_Context(player_id)) {
  4257. return false;
  4258. }
  4259. /*
  4260. ** Need to check for proximity again here?
  4261. */
  4262. #if (0)
  4263. Map.Passes_Proximity_Check
  4264. Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
  4265. OutList.Add(EventClass(EventClass::PLACE, PendingObjectPtr->What_Am_I(), cell + ZoneOffset));
  4266. #endif
  4267. BuildingClass *building = Get_Pending_Placement_Object(player_id, buildable_type, buildable_id);
  4268. if (building) {
  4269. TechnoTypeClass const * tech = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
  4270. if (tech) {
  4271. BuildingTypeClass *building_type = (BuildingTypeClass*) tech;
  4272. //short const *occupy_list = building_type->Get_Occupy_List(true);
  4273. PlacementType[CurrentLocalPlayerIndex] = building_type;
  4274. /*
  4275. ** The cell coordinates passed in will be relative to the playable area that the client knows about
  4276. */
  4277. int map_cell_x = Map.MapCellX;
  4278. int map_cell_y = Map.MapCellY;
  4279. int map_cell_width = Map.MapCellWidth;
  4280. int map_cell_height = Map.MapCellHeight;
  4281. if (map_cell_x > 0) {
  4282. map_cell_x--;
  4283. map_cell_width++;
  4284. }
  4285. if (map_cell_y > 0) {
  4286. map_cell_y--;
  4287. map_cell_height++;
  4288. }
  4289. CELL cell = (CELL) (map_cell_x + cell_x) + ( (map_cell_y + cell_y) << _map_width_shift_bits );
  4290. /*
  4291. ** Call the place directly instead of queueing it, so we can evaluate the return code.
  4292. */
  4293. if (PlayerPtr->Place_Object(building->What_Am_I(), cell + Map.ZoneOffset)) {
  4294. PlacementType[CurrentLocalPlayerIndex] = NULL;
  4295. }
  4296. }
  4297. }
  4298. return true;
  4299. }
  4300. BuildingClass *DLLExportClass::Get_Pending_Placement_Object(uint64 player_id, int buildable_type, int buildable_id)
  4301. {
  4302. /*
  4303. **
  4304. ** Based on SidebarClass::StripClass::SelectClass::Action
  4305. **
  4306. **
  4307. */
  4308. if (GameToPlay == GAME_NORMAL) {
  4309. for (int c = 0 ; c < 2 ; c++) {
  4310. /*
  4311. ** Each production slot in the column
  4312. */
  4313. for (int b=0 ; b < Map.Column[c].BuildableCount ; b++) {
  4314. if (Map.Column[c].Buildables[b].BuildableID == buildable_id) {
  4315. if (Map.Column[c].Buildables[b].BuildableType == buildable_type) {
  4316. int genfactory = -1;
  4317. switch (buildable_type) {
  4318. case RTTI_INFANTRYTYPE:
  4319. genfactory = PlayerPtr->InfantryFactory;
  4320. break;
  4321. case RTTI_UNITTYPE:
  4322. genfactory = PlayerPtr->UnitFactory;
  4323. break;
  4324. case RTTI_AIRCRAFTTYPE:
  4325. genfactory = PlayerPtr->AircraftFactory;
  4326. break;
  4327. case RTTI_BUILDINGTYPE:
  4328. genfactory = PlayerPtr->BuildingFactory;
  4329. break;
  4330. default:
  4331. genfactory = -1;
  4332. break;
  4333. }
  4334. int fnumber = Map.Column[c].Buildables[b].Factory;
  4335. int spc = 0;
  4336. ObjectTypeClass const * choice = NULL;
  4337. if (buildable_type != RTTI_SPECIAL) {
  4338. choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
  4339. } else {
  4340. spc = buildable_id;
  4341. }
  4342. FactoryClass * factory = NULL;
  4343. if (fnumber != -1) {
  4344. factory = Factories.Raw_Ptr(fnumber);
  4345. }
  4346. if (spc == 0 && choice) {
  4347. if (fnumber == -1 && genfactory != -1) {
  4348. return(NULL);
  4349. }
  4350. if (factory) {
  4351. /*
  4352. ** If production has completed, then attempt to have the object exit
  4353. ** the factory or go into placement mode.
  4354. */
  4355. if (factory->Has_Completed()) {
  4356. TechnoClass * pending = factory->Get_Object();
  4357. if (!pending && factory->Get_Special_Item()) {
  4358. //Map.IsTargettingMode = true;
  4359. } else {
  4360. BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
  4361. if (!builder) {
  4362. OutList.Add(EventClass(EventClass::ABANDON, buildable_type, buildable_id));
  4363. On_Speech(PlayerPtr, VOX_NO_FACTORY); // Speak(VOX_NO_FACTORY);
  4364. } else {
  4365. /*
  4366. ** If the completed object is a building, then change the
  4367. ** game state into building placement mode. This fact is
  4368. ** not transmitted to any linked computers until the moment
  4369. ** the building is actually placed down.
  4370. */
  4371. if (pending->What_Am_I() == RTTI_BUILDING) {
  4372. return (BuildingClass*)pending;
  4373. //PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
  4374. }
  4375. }
  4376. }
  4377. }
  4378. }
  4379. }
  4380. }
  4381. }
  4382. }
  4383. }
  4384. } else {
  4385. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  4386. SidebarGlyphxClass *context_sidebar = DLLExportClass::Get_Current_Context_Sidebar();
  4387. for (int c = 0 ; c < 2 ; c++) {
  4388. /*
  4389. ** Each production slot in the column
  4390. */
  4391. for (int b=0 ; b < context_sidebar->Column[c].BuildableCount ; b++) {
  4392. if (context_sidebar->Column[c].Buildables[b].BuildableID == buildable_id) {
  4393. if (context_sidebar->Column[c].Buildables[b].BuildableType == buildable_type) {
  4394. int genfactory = -1;
  4395. switch (buildable_type) {
  4396. case RTTI_INFANTRYTYPE:
  4397. genfactory = PlayerPtr->InfantryFactory;
  4398. break;
  4399. case RTTI_UNITTYPE:
  4400. genfactory = PlayerPtr->UnitFactory;
  4401. break;
  4402. case RTTI_AIRCRAFTTYPE:
  4403. genfactory = PlayerPtr->AircraftFactory;
  4404. break;
  4405. case RTTI_BUILDINGTYPE:
  4406. genfactory = PlayerPtr->BuildingFactory;
  4407. break;
  4408. default:
  4409. genfactory = -1;
  4410. break;
  4411. }
  4412. int fnumber = context_sidebar->Column[c].Buildables[b].Factory;
  4413. int spc = 0;
  4414. ObjectTypeClass const * choice = NULL;
  4415. if (buildable_type != RTTI_SPECIAL) {
  4416. choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
  4417. } else {
  4418. spc = buildable_id;
  4419. }
  4420. FactoryClass * factory = NULL;
  4421. if (fnumber != -1) {
  4422. factory = Factories.Raw_Ptr(fnumber);
  4423. }
  4424. if (spc == 0 && choice) {
  4425. if (fnumber == -1 && genfactory != -1) {
  4426. return(NULL);
  4427. }
  4428. if (factory) {
  4429. /*
  4430. ** If production has completed, then attempt to have the object exit
  4431. ** the factory or go into placement mode.
  4432. */
  4433. if (factory->Has_Completed()) {
  4434. TechnoClass * pending = factory->Get_Object();
  4435. if (!pending && factory->Get_Special_Item()) {
  4436. //Map.IsTargettingMode = true;
  4437. } else {
  4438. BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
  4439. if (!builder) {
  4440. OutList.Add(EventClass(EventClass::ABANDON, buildable_type, buildable_id));
  4441. On_Speech(PlayerPtr, VOX_NO_FACTORY); // Speak(VOX_NO_FACTORY);
  4442. } else {
  4443. /*
  4444. ** If the completed object is a building, then change the
  4445. ** game state into building placement mode. This fact is
  4446. ** not transmitted to any linked computers until the moment
  4447. ** the building is actually placed down.
  4448. */
  4449. if (pending->What_Am_I() == RTTI_BUILDING) {
  4450. return (BuildingClass*)pending;
  4451. //PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
  4452. }
  4453. }
  4454. }
  4455. }
  4456. }
  4457. }
  4458. }
  4459. }
  4460. }
  4461. }
  4462. }
  4463. }
  4464. return NULL;
  4465. }
  4466. /**************************************************************************************************
  4467. * DLLExportClass::Place_Super_Weapon
  4468. *
  4469. * History:
  4470. **************************************************************************************************/
  4471. bool DLLExportClass::Place_Super_Weapon(uint64 player_id, int buildable_type, int buildable_id, int x, int y)
  4472. {
  4473. if (buildable_type != RTTI_SPECIAL)
  4474. {
  4475. return false;
  4476. }
  4477. COORDINATE coord = Map.Pixel_To_Coord(x, y);
  4478. CELL cell = Coord_Cell(coord);
  4479. SpecialWeaponType weapon_type = (SpecialWeaponType)buildable_id;
  4480. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, weapon_type, cell));
  4481. return true;
  4482. }
  4483. /**************************************************************************************************
  4484. * DLLExportClass::Create_Control_Group
  4485. *
  4486. * History:
  4487. **************************************************************************************************/
  4488. bool DLLExportClass::Create_Control_Group(unsigned char control_group_index)
  4489. {
  4490. Handle_Team(control_group_index, 2);
  4491. return true;
  4492. }
  4493. /**************************************************************************************************
  4494. * DLLExportClass::Add_To_Control_Group
  4495. *
  4496. * History:
  4497. **************************************************************************************************/
  4498. bool DLLExportClass::Add_To_Control_Group(unsigned char control_group_index)
  4499. {
  4500. Handle_Team(control_group_index, 1);
  4501. return true;
  4502. }
  4503. /**************************************************************************************************
  4504. * DLLExportClass::Toggle_Control_Group_Selection
  4505. *
  4506. * History:
  4507. **************************************************************************************************/
  4508. bool DLLExportClass::Toggle_Control_Group_Selection(unsigned char control_group_index)
  4509. {
  4510. Handle_Team(control_group_index, 0);
  4511. return true;
  4512. }
  4513. /**************************************************************************************************
  4514. * DLLExportClass::Get_Shroud_State -- Get a snapshot of the shroud for the given player
  4515. *
  4516. * In:
  4517. *
  4518. * Out:
  4519. *
  4520. *
  4521. *
  4522. * History: 4/12/2019 3:44PM - ST
  4523. **************************************************************************************************/
  4524. bool DLLExportClass::Get_Shroud_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  4525. {
  4526. if (!DLLExportClass::Set_Player_Context(player_id)) {
  4527. return false;
  4528. }
  4529. CNCShroudStruct *shroud = (CNCShroudStruct*) buffer_in;
  4530. unsigned int memory_needed = sizeof(*shroud) + 256; // Base amount needed. Will need more depending on how many entries there are
  4531. int entry_index = 0;
  4532. /*
  4533. **
  4534. ** Based loosely on DisplayClass::Redraw_Icons
  4535. **
  4536. **
  4537. */
  4538. int map_cell_x = Map.MapCellX;
  4539. int map_cell_y = Map.MapCellY;
  4540. int map_cell_width = Map.MapCellWidth;
  4541. int map_cell_height = Map.MapCellHeight;
  4542. if (map_cell_x > 0) {
  4543. map_cell_x--;
  4544. map_cell_width++;
  4545. }
  4546. if (map_cell_width < MAP_MAX_CELL_WIDTH) {
  4547. map_cell_width++;
  4548. }
  4549. if (map_cell_y > 0) {
  4550. map_cell_y--;
  4551. map_cell_height++;
  4552. }
  4553. if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
  4554. map_cell_height++;
  4555. }
  4556. for (int y = 0 ; y < map_cell_height ; y++) {
  4557. for (int x = 0 ; x < map_cell_width ; x++) {
  4558. CELL cell = XY_Cell(map_cell_x+x, map_cell_y+y);
  4559. COORDINATE coord = Cell_Coord(cell) & 0xFF00FF00L;
  4560. memory_needed += sizeof(CNCShroudEntryStruct);
  4561. if (memory_needed >= buffer_size) {
  4562. return false;
  4563. }
  4564. int xpixel;
  4565. int ypixel;
  4566. Map.Coord_To_Pixel(coord, xpixel, ypixel);
  4567. CellClass * cellptr = &Map[Coord_Cell(coord)];
  4568. CNCShroudEntryStruct &shroud_entry = shroud->Entries[entry_index];
  4569. shroud_entry.IsVisible = cellptr->Is_Visible(PlayerPtr);
  4570. shroud_entry.IsMapped = cellptr->Is_Mapped(PlayerPtr);
  4571. shroud_entry.IsJamming = false;
  4572. shroud_entry.ShadowIndex = -1;
  4573. if (!shroud_entry.IsMapped) {
  4574. if (shroud_entry.IsVisible) {
  4575. shroud_entry.ShadowIndex = (char) Map.Cell_Shadow(cell, PlayerPtr);
  4576. }
  4577. }
  4578. entry_index++;
  4579. }
  4580. }
  4581. shroud->Count = entry_index;
  4582. return true;
  4583. }
  4584. /**************************************************************************************************
  4585. * DLLExportClass::Get_Occupier_State -- Get the occupier state for this player
  4586. *
  4587. * In:
  4588. *
  4589. * Out:
  4590. *
  4591. *
  4592. *
  4593. * History: 10/25/2019 - SKY
  4594. **************************************************************************************************/
  4595. bool DLLExportClass::Get_Occupier_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  4596. {
  4597. UNREFERENCED_PARAMETER(player_id);
  4598. CNCOccupierHeaderStruct* occupiers = (CNCOccupierHeaderStruct*)buffer_in;
  4599. CNCOccupierEntryHeaderStruct* entry = reinterpret_cast<CNCOccupierEntryHeaderStruct*>(occupiers + 1U);
  4600. occupiers->Count = 0;
  4601. unsigned int memory_needed = sizeof(CNCOccupierHeaderStruct);
  4602. int map_cell_x = Map.MapCellX;
  4603. int map_cell_y = Map.MapCellY;
  4604. int map_cell_width = Map.MapCellWidth;
  4605. int map_cell_height = Map.MapCellHeight;
  4606. if (map_cell_x > 0) {
  4607. map_cell_x--;
  4608. map_cell_width++;
  4609. }
  4610. if (map_cell_width < MAP_MAX_CELL_WIDTH) {
  4611. map_cell_width++;
  4612. }
  4613. if (map_cell_y > 0) {
  4614. map_cell_y--;
  4615. map_cell_height++;
  4616. }
  4617. if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
  4618. map_cell_height++;
  4619. }
  4620. for (int y = 0; y < map_cell_height; y++) {
  4621. for (int x = 0; x < map_cell_width; x++, occupiers->Count++) {
  4622. CELL cell = XY_Cell(map_cell_x + x, map_cell_y + y);
  4623. CellClass * cellptr = &Map[cell];
  4624. int occupier_count = 0;
  4625. ObjectClass* const cell_occupier = cellptr->Cell_Occupier();
  4626. for (ObjectClass* optr = cell_occupier; optr != NULL; optr = optr->Next) {
  4627. if (optr->IsActive) {
  4628. occupier_count++;
  4629. }
  4630. }
  4631. memory_needed += sizeof(CNCOccupierEntryHeaderStruct) + (sizeof(CNCOccupierObjectStruct) * occupier_count);
  4632. if (memory_needed >= buffer_size) {
  4633. return false;
  4634. }
  4635. CNCOccupierObjectStruct* occupier = reinterpret_cast<CNCOccupierObjectStruct*>(entry + 1U);
  4636. entry->Count = occupier_count;
  4637. for (ObjectClass* optr = cell_occupier; optr != NULL; optr = optr->Next) {
  4638. if (optr->IsActive) {
  4639. CNCObjectStruct object;
  4640. Convert_Type(optr, object);
  4641. occupier->Type = object.Type;
  4642. occupier->ID = object.ID;
  4643. occupier++;
  4644. }
  4645. }
  4646. entry = reinterpret_cast<CNCOccupierEntryHeaderStruct*>(occupier + 1U);
  4647. }
  4648. }
  4649. return true;
  4650. }
  4651. /**************************************************************************************************
  4652. * DLLExportClass::Get_Player_Info_State -- Get the multiplayer info for this player
  4653. *
  4654. * In:
  4655. *
  4656. * Out:
  4657. *
  4658. *
  4659. *
  4660. * History: 4/22/2019 10:33AM - ST
  4661. **************************************************************************************************/
  4662. bool DLLExportClass::Get_Player_Info_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  4663. {
  4664. if (!DLLExportClass::Set_Player_Context(player_id)) {
  4665. return false;
  4666. }
  4667. CNCPlayerInfoStruct *player_info = (CNCPlayerInfoStruct*) buffer_in;
  4668. unsigned int memory_needed = sizeof(*player_info) + 32; // A little extra for no reason
  4669. if (memory_needed >= buffer_size) {
  4670. return false;
  4671. }
  4672. player_info->GlyphxPlayerID = 0;
  4673. if (PlayerPtr == NULL) {
  4674. return false;;
  4675. }
  4676. strncpy(&player_info->Name[0], MPlayerNames[CurrentLocalPlayerIndex], MPLAYER_NAME_MAX);
  4677. player_info->Name[MPLAYER_NAME_MAX - 1] = 0; // Make sure it's terminated
  4678. player_info->House = PlayerPtr->Class->House;
  4679. player_info->AllyFlags = PlayerPtr->Get_Ally_Flags();
  4680. player_info->ColorIndex = MPlayerID_To_ColorIndex(MPlayerID[CurrentLocalPlayerIndex]);
  4681. player_info->GlyphxPlayerID = player_id;
  4682. player_info->HomeCellX = Cell_X(MultiplayerStartPositions[CurrentLocalPlayerIndex]);
  4683. player_info->HomeCellY = Cell_Y(MultiplayerStartPositions[CurrentLocalPlayerIndex]);
  4684. player_info->IsDefeated = PlayerPtr->IsDefeated;
  4685. player_info->SpiedPowerFlags = 0U;
  4686. player_info->SpiedMoneyFlags = 0U;
  4687. player_info->IsRadarJammed = false;
  4688. // Populate selection info
  4689. if (CurrentObject.Count() > 0) {
  4690. CNCObjectStruct object;
  4691. Convert_Type(CurrentObject[0], object);
  4692. player_info->SelectedID = object.ID;
  4693. player_info->SelectedType = object.Type;
  4694. const int left = Map.MapCellX;
  4695. const int right = Map.MapCellX + Map.MapCellWidth - 1;
  4696. const int top = Map.MapCellY;
  4697. const int bottom = Map.MapCellY + Map.MapCellHeight - 1;
  4698. // Use first object with a weapon, or first object if none
  4699. ObjectClass* action_object = nullptr;
  4700. for (int i = 0; i < CurrentObject.Count(); ++i) {
  4701. ObjectClass* object = CurrentObject[i];
  4702. if (object->Is_Techno()) {
  4703. TechnoClass* techno = (TechnoClass*)object;
  4704. if (techno->Techno_Type_Class()->Primary != WEAPON_NONE || techno->Techno_Type_Class()->Secondary != WEAPON_NONE) {
  4705. action_object = object;
  4706. break;
  4707. }
  4708. }
  4709. }
  4710. if (action_object == nullptr) {
  4711. action_object = CurrentObject[0];
  4712. }
  4713. int index = 0;
  4714. for (int y = top; y <= bottom; ++y) {
  4715. for (int x = left; x <= right; ++x, ++index) {
  4716. Convert_Action_Type(action_object->What_Action(XY_Cell(x, y)), (CurrentObject.Count() == 1) ? action_object : NULL, As_Target(XY_Cell(x, y)), player_info->ActionWithSelected[index]);
  4717. }
  4718. }
  4719. player_info->ActionWithSelectedCount = Map.MapCellWidth * Map.MapCellHeight;
  4720. }
  4721. else {
  4722. player_info->SelectedID = -1;
  4723. player_info->SelectedType = UNKNOWN;
  4724. player_info->ActionWithSelectedCount = 0U;
  4725. }
  4726. // Screen shake
  4727. player_info->ScreenShake = PlayerPtr->ScreenShakeTime;
  4728. return true;
  4729. };
  4730. /**************************************************************************************************
  4731. * DLLExportClass::Get_Dynamic_Map_State -- Get a snapshot of the smudges and overlays on the terrain
  4732. *
  4733. * In:
  4734. *
  4735. * Out:
  4736. *
  4737. *
  4738. *
  4739. * History: 2/8/2019 10:45AM - ST
  4740. **************************************************************************************************/
  4741. bool DLLExportClass::Get_Dynamic_Map_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
  4742. {
  4743. /*
  4744. ** Get the player for this...
  4745. */
  4746. player_id;
  4747. static int _call_count = 0;
  4748. CNCDynamicMapStruct *dynamic_map = (CNCDynamicMapStruct*) buffer_in;
  4749. unsigned int memory_needed = sizeof(*dynamic_map) + 256; // Base amount needed. Will need more depending on how many entries there are
  4750. int entry_index = 0;
  4751. /*
  4752. **
  4753. ** Based loosely on DisplayClass::Redraw_Icons
  4754. **
  4755. **
  4756. */
  4757. int map_cell_x = Map.MapCellX;
  4758. int map_cell_y = Map.MapCellY;
  4759. int map_cell_width = Map.MapCellWidth;
  4760. int map_cell_height = Map.MapCellHeight;
  4761. if (map_cell_x > 0) {
  4762. map_cell_x--;
  4763. map_cell_width++;
  4764. }
  4765. if (map_cell_width < MAP_MAX_CELL_WIDTH) {
  4766. map_cell_width++;
  4767. }
  4768. if (map_cell_y > 0) {
  4769. map_cell_y--;
  4770. map_cell_height++;
  4771. }
  4772. if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
  4773. map_cell_height++;
  4774. }
  4775. int cell_index = 0;
  4776. bool debug_output = false;
  4777. //if (_call_count == 20) {
  4778. //debug_output = true;
  4779. //}
  4780. // Need to ignore view constraints for dynamic map updates, so the radar map
  4781. // has the latest tiberium state for cells outside the tactical view
  4782. DLLExportClass::Adjust_Internal_View(true);
  4783. for (int y = 0 ; y < map_cell_height ; y++) {
  4784. for (int x = 0 ; x < map_cell_width ; x++) {
  4785. CELL cell = XY_Cell(map_cell_x+x, map_cell_y+y);
  4786. COORDINATE coord = Cell_Coord(cell) & 0xFF00FF00L;
  4787. memory_needed += sizeof(CNCDynamicMapEntryStruct) * 2;
  4788. if (memory_needed >= buffer_size) {
  4789. return false;
  4790. }
  4791. /*
  4792. ** Only cells flagged to be redraw are examined.
  4793. */
  4794. //if (In_View(cell) && Is_Cell_Flagged(cell)) {
  4795. int xpixel;
  4796. int ypixel;
  4797. if (Map.Coord_To_Pixel(coord, xpixel, ypixel)) {
  4798. CellClass * cellptr = &Map[Coord_Cell(coord)];
  4799. /*
  4800. ** If there is a portion of the underlying icon that could be visible,
  4801. ** then draw it. Also draw the cell if the shroud is off.
  4802. */
  4803. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER || cellptr->IsVisible || Debug_Unshroud) {
  4804. Cell_Class_Draw_It(dynamic_map, entry_index, cellptr, xpixel, ypixel, debug_output);
  4805. }
  4806. /*
  4807. ** If any cell is not fully mapped, then flag it so that the shadow drawing
  4808. ** process will occur. Only draw the shadow if Debug_Unshroud is false.
  4809. */
  4810. //if (!cellptr->IsMapped && !Debug_Unshroud) {
  4811. // IsShadowPresent = true;
  4812. //}
  4813. }
  4814. //}
  4815. }
  4816. }
  4817. if (entry_index) {
  4818. _call_count++;
  4819. }
  4820. dynamic_map->Count = entry_index;
  4821. dynamic_map->VortexActive = false;
  4822. return true;
  4823. }
  4824. /**************************************************************************************************
  4825. * DLLExportClass::Cell_Class_Draw_It -- Go through the motions of drawing a cell to get the smudge and overlay info
  4826. *
  4827. * In:
  4828. *
  4829. * Out:
  4830. *
  4831. *
  4832. *
  4833. * History: 2/8/2019 11:09AM - ST
  4834. **************************************************************************************************/
  4835. void DLLExportClass::Cell_Class_Draw_It(CNCDynamicMapStruct *dynamic_map, int &entry_index, CellClass *cell_ptr, int xpixel, int ypixel, bool debug_output)
  4836. {
  4837. /*
  4838. **
  4839. ** Based on CellClass::Draw_It and SmudgeTypeClass::Draw_It
  4840. **
  4841. **
  4842. */
  4843. CELL cell = cell_ptr->Cell_Number();
  4844. /*
  4845. ** Redraw any smudge.
  4846. */
  4847. if (cell_ptr->Smudge != SMUDGE_NONE) {
  4848. //SmudgeTypeClass::As_Reference(Smudge).Draw_It(x, y, SmudgeData);
  4849. const SmudgeTypeClass &smudge_type = SmudgeTypeClass::As_Reference(cell_ptr->Smudge);
  4850. if (smudge_type.Get_Image_Data() != NULL) {
  4851. if (debug_output) {
  4852. IsTheaterShape = true;
  4853. Debug_Write_Shape_Type(&smudge_type, 0);
  4854. IsTheaterShape = false;
  4855. }
  4856. CNCDynamicMapEntryStruct &smudge_entry = dynamic_map->Entries[entry_index++];
  4857. strncpy(smudge_entry.AssetName, smudge_type.IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
  4858. smudge_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  4859. smudge_entry.Type = (short) cell_ptr->Smudge;
  4860. smudge_entry.Owner = (char)cell_ptr->Owner;
  4861. smudge_entry.DrawFlags = SHAPE_WIN_REL; // Looks like smudges are drawn top left
  4862. smudge_entry.PositionX = xpixel;
  4863. smudge_entry.PositionY = ypixel;
  4864. smudge_entry.Width = Get_Build_Frame_Width(smudge_type.Get_Image_Data());
  4865. smudge_entry.Height = Get_Build_Frame_Height(smudge_type.Get_Image_Data());
  4866. smudge_entry.CellX = Cell_X(cell);
  4867. smudge_entry.CellY = Cell_Y(cell);
  4868. smudge_entry.ShapeIndex = cell_ptr->SmudgeData;
  4869. smudge_entry.IsSmudge = true;
  4870. smudge_entry.IsOverlay = false;
  4871. smudge_entry.IsResource = false;
  4872. smudge_entry.IsSellable = false;
  4873. smudge_entry.IsTheaterShape = true; // Smudges are always theater-specific
  4874. smudge_entry.IsFlag = false;
  4875. }
  4876. }
  4877. /*
  4878. ** Draw the overlay object.
  4879. */
  4880. if (cell_ptr->Overlay != OVERLAY_NONE) {
  4881. //OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(Overlay);
  4882. //IsTheaterShape = (bool)otype.IsTheater;
  4883. //CC_Draw_Shape(otype.Get_Image_Data(), OverlayData, (x+(CELL_PIXEL_W>>1)), (y+(CELL_PIXEL_H>>1)), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST, NULL, Map.UnitShadow);
  4884. //IsTheaterShape = false;
  4885. const OverlayTypeClass &overlay_type = OverlayTypeClass::As_Reference(cell_ptr->Overlay);
  4886. if (overlay_type.Get_Image_Data() != NULL) {
  4887. CNCDynamicMapEntryStruct &overlay_entry = dynamic_map->Entries[entry_index++];
  4888. if (debug_output) {
  4889. IsTheaterShape = (bool)overlay_type.IsTheater;
  4890. Debug_Write_Shape_Type(&overlay_type, 0);
  4891. IsTheaterShape = false;
  4892. }
  4893. strncpy(overlay_entry.AssetName, overlay_type.IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
  4894. overlay_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  4895. overlay_entry.Type = (short)cell_ptr->Overlay;
  4896. overlay_entry.Owner = (char) cell_ptr->Owner;
  4897. overlay_entry.DrawFlags = SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST; // Looks like overlays are drawn centered and translucent
  4898. overlay_entry.PositionX = xpixel + (CELL_PIXEL_W>>1);
  4899. overlay_entry.PositionY = ypixel + (CELL_PIXEL_H>>1);
  4900. overlay_entry.Width = Get_Build_Frame_Width(overlay_type.Get_Image_Data());
  4901. overlay_entry.Height = Get_Build_Frame_Height(overlay_type.Get_Image_Data());
  4902. overlay_entry.CellX = Cell_X(cell);
  4903. overlay_entry.CellY = Cell_Y(cell);
  4904. overlay_entry.ShapeIndex = cell_ptr->OverlayData;
  4905. overlay_entry.IsSmudge = false;
  4906. overlay_entry.IsOverlay = true;
  4907. overlay_entry.IsResource = overlay_entry.Type >= OVERLAY_TIBERIUM1 && overlay_entry.Type <= OVERLAY_TIBERIUM12;
  4908. overlay_entry.IsSellable = overlay_entry.Type >= OVERLAY_SANDBAG_WALL && overlay_entry.Type <= OVERLAY_WOOD_WALL;
  4909. overlay_entry.IsTheaterShape = (bool)overlay_type.IsTheater;
  4910. overlay_entry.IsFlag = false;
  4911. }
  4912. }
  4913. if (cell_ptr->IsFlagged) {
  4914. const void* image_data = MixFileClass::Retrieve("FLAGFLY.SHP");
  4915. if (image_data != NULL) {
  4916. CNCDynamicMapEntryStruct &flag_entry = dynamic_map->Entries[entry_index++];
  4917. strncpy(flag_entry.AssetName, "FLAGFLY", CNC_OBJECT_ASSET_NAME_LENGTH);
  4918. flag_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
  4919. flag_entry.Type = -1;
  4920. flag_entry.Owner = cell_ptr->Owner;
  4921. flag_entry.DrawFlags = SHAPE_CENTER|SHAPE_GHOST|SHAPE_FADING;
  4922. flag_entry.PositionX = xpixel + (ICON_PIXEL_W / 2);
  4923. flag_entry.PositionY = ypixel + (ICON_PIXEL_H / 2);
  4924. flag_entry.Width = Get_Build_Frame_Width(image_data);
  4925. flag_entry.Height = Get_Build_Frame_Height(image_data);
  4926. flag_entry.CellX = Cell_X(cell);
  4927. flag_entry.CellY = Cell_Y(cell);
  4928. flag_entry.ShapeIndex = Frame % 14;
  4929. flag_entry.IsSmudge = false;
  4930. flag_entry.IsOverlay = false;
  4931. flag_entry.IsResource = false;
  4932. flag_entry.IsSellable = false;
  4933. flag_entry.IsTheaterShape = false;
  4934. flag_entry.IsFlag = true;
  4935. }
  4936. }
  4937. }
  4938. /**************************************************************************************************
  4939. * DLLExportClass::Glyphx_Queue_AI -- Special queue processing for Glyphx multiplayer mode
  4940. *
  4941. * In:
  4942. *
  4943. * Out:
  4944. *
  4945. *
  4946. *
  4947. * History: 3/12/2019 10:52AM - ST
  4948. **************************************************************************************************/
  4949. void DLLExportClass::Glyphx_Queue_AI(void)
  4950. {
  4951. //------------------------------------------------------------------------
  4952. // Move events from the OutList (events generated by this player) into the
  4953. // DoList (the list of events to execute).
  4954. //------------------------------------------------------------------------
  4955. while (OutList.Count) {
  4956. OutList.First().IsExecuted = false;
  4957. if (!DoList.Add(OutList.First())) {
  4958. ;
  4959. }
  4960. OutList.Next();
  4961. }
  4962. /*
  4963. ** Based on Execute_DoList in queue.cpp
  4964. **
  4965. ** The events have the ID of the player encoded in them, so no special per-player processing should be needed.
  4966. ** When the event is created, the 'local player' is assumed to be the originator of the event, so PlayerPtr will need
  4967. ** to be swapped out to represent the real originating player prior to any events being created as a result of GlyphX input
  4968. **
  4969. ** ST - 3/12/2019 10:51AM
  4970. */
  4971. for (int i = 0; i < MPlayerCount; i++) {
  4972. HousesType house;
  4973. HouseClass *housep;
  4974. house = MPlayerHouses [i];
  4975. housep= HouseClass::As_Pointer (house);
  4976. //.....................................................................
  4977. // If for some reason this house doesn't exist, skip it.
  4978. // Also, if this house has exited the game, skip it. (The user can
  4979. // generate events after he exits, because the exit event is scheduled
  4980. // at least FrameSendRate*3 frames ahead. If one system gets these
  4981. // packets & another system doesn't, they'll go out of sync because
  4982. // they aren't checking the CommandCount for that house, since that
  4983. // house isn't connected any more.)
  4984. //.....................................................................
  4985. if (!housep){
  4986. continue;
  4987. }
  4988. if (!housep->IsHuman){
  4989. continue;
  4990. }
  4991. //.....................................................................
  4992. // Loop through all events
  4993. //.....................................................................
  4994. for (int j = 0; j < DoList.Count; j++) {
  4995. if (!DoList[j].IsExecuted && (unsigned)Frame >= DoList[j].Frame) {
  4996. DoList[j].Execute();
  4997. //...............................................................
  4998. // Mark this event as executed.
  4999. //...............................................................
  5000. DoList[j].IsExecuted = 1;
  5001. }
  5002. }
  5003. }
  5004. //------------------------------------------------------------------------
  5005. // Clean out the DoList
  5006. //------------------------------------------------------------------------
  5007. while (DoList.Count) {
  5008. //.....................................................................
  5009. // Discard events that have been executed, OR it's too late to execute.
  5010. // (This happens if another player exits the game; he'll leave FRAMEINFO
  5011. // events lying around in my queue. They won't have been "executed",
  5012. // because his IPX connection was destroyed.)
  5013. //.....................................................................
  5014. if ( (DoList.First().IsExecuted) || ((unsigned)Frame > DoList.First().Frame) ) {
  5015. DoList.Next();
  5016. }
  5017. else {
  5018. break;
  5019. }
  5020. }
  5021. }
  5022. /**************************************************************************************************
  5023. * DLLExportClass::Reset_Sidebars -- Init the multiplayer sidebars
  5024. *
  5025. * In:
  5026. *
  5027. * Out:
  5028. *
  5029. *
  5030. *
  5031. * History: 3/14/2019 3:10PM - ST
  5032. **************************************************************************************************/
  5033. void DLLExportClass::Reset_Sidebars(void)
  5034. {
  5035. for (int i=0 ; i<MPlayerCount ; i++) {
  5036. HouseClass *player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  5037. MultiplayerSidebars[i].Init_Clear(player_ptr);
  5038. }
  5039. }
  5040. /**************************************************************************************************
  5041. * DLLExportClass::Set_Player_Context -- Switch the C&C local player context
  5042. *
  5043. * In:
  5044. *
  5045. * Out:
  5046. *
  5047. *
  5048. *
  5049. * History: 3/14/2019 3:20PM - ST
  5050. **************************************************************************************************/
  5051. bool DLLExportClass::Set_Player_Context(uint64 glyphx_player_id, bool force)
  5052. {
  5053. /*
  5054. ** Context never needs to change in single player
  5055. */
  5056. if (GameToPlay == GAME_NORMAL) {
  5057. if (PlayerPtr) {
  5058. CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
  5059. }
  5060. return true;
  5061. }
  5062. /*
  5063. ** C&C relies a lot on PlayerPtr, which is a pointer to the 'local' player's house. Historically, in a peer-to-peer
  5064. ** multiplayer game, each player's PlayerPtr pointed to their own local player.
  5065. **
  5066. ** Since much of the IO logic depends on PlayerPtr being the player performing the action, we need to set PlayerPtr
  5067. ** correctly depending on which player generated input or needs output
  5068. */
  5069. for (int i=0 ; i<MPlayerCount ; i++) {
  5070. if (GlyphxPlayerIDs[i] == glyphx_player_id) {
  5071. if (!force && i == CurrentLocalPlayerIndex) {
  5072. return true;
  5073. }
  5074. MPlayerLocalID = MPlayerID[i];
  5075. PlayerPtr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  5076. CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
  5077. CurrentLocalPlayerIndex = i;
  5078. return true;
  5079. }
  5080. }
  5081. return false;
  5082. }
  5083. /**************************************************************************************************
  5084. * DLLExportClass::Reset_Player_Context -- Clear out old player context data
  5085. *
  5086. * In:
  5087. *
  5088. * Out:
  5089. *
  5090. *
  5091. *
  5092. * History: 4/16/2019 10:36AM - ST
  5093. **************************************************************************************************/
  5094. void DLLExportClass::Reset_Player_Context(void)
  5095. {
  5096. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  5097. PlacementType[i] = NULL;
  5098. }
  5099. CurrentLocalPlayerIndex = 0;
  5100. CurrentObject.Clear_All();
  5101. }
  5102. /**************************************************************************************************
  5103. * Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
  5104. *
  5105. * In:
  5106. *
  5107. * Out:
  5108. *
  5109. *
  5110. *
  5111. * History: 4/17/2019 9:45AM - ST
  5112. **************************************************************************************************/
  5113. void Logic_Switch_Player_Context(ObjectClass *object)
  5114. {
  5115. DLLExportClass::Logic_Switch_Player_Context(object);
  5116. }
  5117. /**************************************************************************************************
  5118. * DLLExportClass::Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
  5119. *
  5120. * In:
  5121. *
  5122. * Out:
  5123. *
  5124. *
  5125. *
  5126. * History: 4/17/2019 9:45AM - ST
  5127. **************************************************************************************************/
  5128. void DLLExportClass::Logic_Switch_Player_Context(ObjectClass *object)
  5129. {
  5130. if (object == NULL) {
  5131. return;
  5132. }
  5133. /*
  5134. ** If it's not a techno, it can't be owned.
  5135. */
  5136. if (!object->Is_Techno()) {
  5137. return;
  5138. }
  5139. TechnoClass *tech = static_cast<TechnoClass*>(object);
  5140. //HousesType house = tech->House->Class->House;
  5141. DLLExportClass::Logic_Switch_Player_Context(tech->House);
  5142. }
  5143. /**************************************************************************************************
  5144. * Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
  5145. *
  5146. * In:
  5147. *
  5148. * Out:
  5149. *
  5150. *
  5151. *
  5152. * History: 4/17/2019 9:45AM - ST
  5153. **************************************************************************************************/
  5154. void Logic_Switch_Player_Context(HouseClass *object)
  5155. {
  5156. DLLExportClass::Logic_Switch_Player_Context(object);
  5157. }
  5158. /**************************************************************************************************
  5159. * DLLExportClass::Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
  5160. *
  5161. * In:
  5162. *
  5163. * Out:
  5164. *
  5165. *
  5166. *
  5167. * History: 4/17/2019 9:45AM - ST
  5168. **************************************************************************************************/
  5169. void DLLExportClass::Logic_Switch_Player_Context(HouseClass *house)
  5170. {
  5171. if (GameToPlay == GAME_NORMAL) {
  5172. CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
  5173. return;
  5174. }
  5175. if (house == NULL) {
  5176. return;
  5177. }
  5178. /*
  5179. ** C&C relies a lot on PlayerPtr, which is a pointer to the 'local' player's house. Historically, in a peer-to-peer
  5180. ** multiplayer game, each player's PlayerPtr pointed to their own local player.
  5181. **
  5182. ** Since much of the IO logic depends on PlayerPtr being the player performing the action, we need to set PlayerPtr
  5183. ** correctly depending on which player generated input or needs output
  5184. */
  5185. HousesType house_type = house->Class->House;
  5186. for (int i=0 ; i<MPlayerCount ; i++) {
  5187. if (house_type == MPlayerHouses[i]) {
  5188. if (i == CurrentLocalPlayerIndex) {
  5189. return;
  5190. }
  5191. MPlayerLocalID = MPlayerID[i];
  5192. PlayerPtr = HouseClass::As_Pointer(MPlayerHouses[i]); //HouseClass::As_Pointer(HOUSE_MULTI2);
  5193. CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
  5194. CurrentLocalPlayerIndex = i;
  5195. return;
  5196. }
  5197. }
  5198. }
  5199. /**************************************************************************************************
  5200. * DLLExportClass::Calculate_Start_Positions -- Calculate the initial view positions for the players
  5201. *
  5202. * In:
  5203. *
  5204. * Out:
  5205. *
  5206. *
  5207. *
  5208. * History: 4/16/2019 6/12/2019 3:00PM - ST
  5209. **************************************************************************************************/
  5210. void DLLExportClass::Calculate_Start_Positions(void)
  5211. {
  5212. if (GameToPlay == GAME_NORMAL) {
  5213. MultiplayerStartPositions[0] = Views[0];
  5214. return;
  5215. }
  5216. HouseClass *player_ptr = PlayerPtr;
  5217. ScenarioInit++;
  5218. COORDINATE old_tac = Map.TacticalCoord;
  5219. for (int i=0 ; i<MPlayerCount ; i++) {
  5220. PlayerPtr = HouseClass::As_Pointer(MPlayerHouses[i]);
  5221. if (PlayerPtr) {
  5222. long x, y;
  5223. Map.Compute_Start_Pos(x, y);
  5224. MultiplayerStartPositions[i] = XY_Cell(x, y);
  5225. }
  5226. }
  5227. Map.TacticalCoord = old_tac;
  5228. ScenarioInit--;
  5229. PlayerPtr = player_ptr;
  5230. }
  5231. /**************************************************************************************************
  5232. * DLLExportClass::Get_GlyphX_Player_ID -- Get the external GlyphX player ID from the C&C house/player pointer
  5233. * Returns 0 in single player or if player ID isn't found
  5234. *
  5235. * In:
  5236. *
  5237. * Out:
  5238. *
  5239. *
  5240. *
  5241. * History: 4/22/2019 6:23PM - ST
  5242. **************************************************************************************************/
  5243. __int64 DLLExportClass::Get_GlyphX_Player_ID(const HouseClass *house)
  5244. {
  5245. /*
  5246. ** C&C relies a lot on PlayerPtr, which is a pointer to the 'local' player's house. Historically, in a peer-to-peer
  5247. ** multiplayer game, each player's PlayerPtr pointed to their own local player.
  5248. **
  5249. ** Since much of the IO logic depends on PlayerPtr being the player performing the action, we need to set PlayerPtr
  5250. ** correctly depending on which player generated input or needs output
  5251. */
  5252. if (GameToPlay == GAME_NORMAL) {
  5253. return 0;
  5254. }
  5255. if (house == NULL) {
  5256. return 0;
  5257. }
  5258. HousesType house_type = house->Class->House;
  5259. for (int i=0 ; i<MPlayerCount ; i++) {
  5260. if (house_type == MPlayerHouses[i]) {
  5261. return GlyphxPlayerIDs[i];
  5262. }
  5263. }
  5264. /*
  5265. ** Failure case.
  5266. */
  5267. return 0;
  5268. }
  5269. /**************************************************************************************************
  5270. * DLLExportClass::Adjust_Internal_View -- Set the internal tactical view to encompass the input coordinates
  5271. *
  5272. * In:
  5273. *
  5274. * Out:
  5275. *
  5276. *
  5277. *
  5278. * History: 4/16/2019 3:00PM - ST
  5279. **************************************************************************************************/
  5280. void DLLExportClass::Adjust_Internal_View(bool force_ignore_view_constraints)
  5281. {
  5282. /*
  5283. ** When legacy rendering is disabled (especially in multiplayer) we can get input coordinates that
  5284. ** fall outside the engine's tactical view. In this case, we need to adjust the tactical view before the
  5285. ** input will behave as expected.
  5286. */
  5287. if (!force_ignore_view_constraints && Legacy_Render_Enabled()) {
  5288. /*
  5289. ** Render view should already be tracking the player's local view
  5290. */
  5291. DisplayClass::IgnoreViewConstraints = false;
  5292. return;
  5293. }
  5294. DisplayClass::IgnoreViewConstraints = true;
  5295. }
  5296. /**************************************************************************************************
  5297. * DLLExportClass::Get_Current_Context_Sidebar -- Get the sidebar data for the current player context
  5298. *
  5299. * In:
  5300. *
  5301. * Out:
  5302. *
  5303. *
  5304. *
  5305. * History: 3/14/2019 3:20PM - ST
  5306. **************************************************************************************************/
  5307. SidebarGlyphxClass *DLLExportClass::Get_Current_Context_Sidebar(HouseClass *player_ptr)
  5308. {
  5309. if (player_ptr) {
  5310. for (int i=0 ; i<MPlayerCount ; i++) {
  5311. if (player_ptr == HouseClass::As_Pointer(MPlayerHouses[i])) {
  5312. return &MultiplayerSidebars[i];
  5313. }
  5314. }
  5315. }
  5316. return &MultiplayerSidebars[CurrentLocalPlayerIndex];
  5317. }
  5318. SidebarGlyphxClass *Get_Current_Context_Sidebar(HouseClass *player_ptr)
  5319. {
  5320. return DLLExportClass::Get_Current_Context_Sidebar(player_ptr);
  5321. }
  5322. /**************************************************************************************************
  5323. * DLLExportClass::Repair_Mode -- Starts the player's repair mode. All it does here is unselect all units.
  5324. *
  5325. * In:
  5326. *
  5327. * Out:
  5328. *
  5329. *
  5330. *
  5331. * History: 5/1/2019 - LLL
  5332. **************************************************************************************************/
  5333. void DLLExportClass::Repair_Mode(uint64 player_id)
  5334. {
  5335. /*
  5336. ** Get the player for this...
  5337. */
  5338. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5339. return;
  5340. }
  5341. Unselect_All();
  5342. }
  5343. /**************************************************************************************************
  5344. * DLLExportClass::Repair -- Repairs a specific building
  5345. *
  5346. * In:
  5347. *
  5348. * Out:
  5349. *
  5350. *
  5351. *
  5352. * History: 5/1/2019 - LLL
  5353. **************************************************************************************************/
  5354. void DLLExportClass::Repair(uint64 player_id, int object_id)
  5355. {
  5356. /*
  5357. ** Get the player for this...
  5358. */
  5359. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5360. return;
  5361. }
  5362. TARGET target = Build_Target(KIND_BUILDING, object_id);
  5363. if (target != TARGET_NONE)
  5364. {
  5365. BuildingClass* building = As_Building(target);
  5366. if (building) {
  5367. if (!building->IsActive) {
  5368. GlyphX_Debug_Print("DLLExportClass::Repair -- trying to repair a non-active building");
  5369. } else {
  5370. if (building && building->Can_Repair() && building->House && building->House->Class->House == PlayerPtr->Class->House)
  5371. {
  5372. building->Repair(-1);
  5373. }
  5374. }
  5375. }
  5376. }
  5377. }
  5378. /**************************************************************************************************
  5379. * DLLExportClass::Sell_Mode -- Starts the player's sell mode. All it does here is unselect all units.
  5380. *
  5381. * In:
  5382. *
  5383. * Out:
  5384. *
  5385. *
  5386. *
  5387. * History: 5/1/2019 - LLL
  5388. **************************************************************************************************/
  5389. void DLLExportClass::Sell_Mode(uint64 player_id)
  5390. {
  5391. /*
  5392. ** Get the player for this...
  5393. */
  5394. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5395. return;
  5396. }
  5397. Unselect_All();
  5398. }
  5399. /**************************************************************************************************
  5400. * DLLExportClass::Sell -- Sell's a player's speceific building.
  5401. *
  5402. * In:
  5403. *
  5404. * Out:
  5405. *
  5406. *
  5407. *
  5408. * History: 5/1/2019 - LLL
  5409. **************************************************************************************************/
  5410. void DLLExportClass::Sell(uint64 player_id, int object_id)
  5411. {
  5412. /*
  5413. ** Get the player for this...
  5414. */
  5415. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5416. return;
  5417. }
  5418. TARGET target = Build_Target(KIND_BUILDING, object_id);
  5419. if (target != TARGET_NONE)
  5420. {
  5421. BuildingClass* building = As_Building(target);
  5422. if (building) {
  5423. if (!building->IsActive) {
  5424. GlyphX_Debug_Print("DLLExportClass::Sell -- trying to sell a non-active building");
  5425. } else {
  5426. if (building->House && building->House->Class->House == PlayerPtr->Class->House)
  5427. {
  5428. building->Sell_Back(1);
  5429. }
  5430. }
  5431. }
  5432. }
  5433. }
  5434. /**************************************************************************************************
  5435. * DLLExportClass::Repair_Sell_Cancel -- Ends the player's repair or sell mode. Doesn't do anything right now.
  5436. *
  5437. * In:
  5438. *
  5439. * Out:
  5440. *
  5441. *
  5442. *
  5443. * History: 5/1/2019 - LLL
  5444. **************************************************************************************************/
  5445. void DLLExportClass::Repair_Sell_Cancel(uint64 player_id)
  5446. {
  5447. //OutputDebugString("Repair_Sell_Cancel\n");
  5448. }
  5449. /**************************************************************************************************
  5450. * DLLExportClass::Scatter_Selected -- Scatter the selected units
  5451. *
  5452. * In:
  5453. *
  5454. * Out:
  5455. *
  5456. *
  5457. *
  5458. * History: 10/15/2019 - SKY
  5459. **************************************************************************************************/
  5460. void DLLExportClass::Scatter_Selected(uint64 player_id)
  5461. {
  5462. /*
  5463. ** Get the player for this...
  5464. */
  5465. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5466. return;
  5467. }
  5468. if (CurrentObject.Count()) {
  5469. for (int index = 0; index < CurrentObject.Count(); index++) {
  5470. ObjectClass const * tech = CurrentObject[index];
  5471. if (tech && tech->Can_Player_Move()) {
  5472. OutList.Add(EventClass(EventClass::SCATTER, tech->As_Target()));
  5473. }
  5474. }
  5475. }
  5476. }
  5477. /**************************************************************************************************
  5478. * DLLExportClass::Select_Next_Unit
  5479. *
  5480. * History: 03.02.2020 MBL
  5481. **************************************************************************************************/
  5482. void DLLExportClass::Select_Next_Unit(uint64 player_id)
  5483. {
  5484. /*
  5485. ** Get the player for this...
  5486. */
  5487. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5488. return;
  5489. }
  5490. ObjectClass* obj = Map.Next_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
  5491. if (obj) {
  5492. Unselect_All();
  5493. obj->Select();
  5494. COORDINATE center = Map.Center_Map();
  5495. Map.Flag_To_Redraw(true);
  5496. if (center) {
  5497. On_Center_Camera(PlayerPtr, Coord_X(center), Coord_Y(center));
  5498. }
  5499. }
  5500. }
  5501. /**************************************************************************************************
  5502. * DLLExportClass::Select_Previous_Unit
  5503. *
  5504. * History: 03.02.2020 MBL
  5505. **************************************************************************************************/
  5506. void DLLExportClass::Select_Previous_Unit(uint64 player_id)
  5507. {
  5508. /*
  5509. ** Get the player for this...
  5510. */
  5511. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5512. return;
  5513. }
  5514. ObjectClass* obj = Map.Prev_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
  5515. if (obj) {
  5516. Unselect_All();
  5517. obj->Select();
  5518. COORDINATE center = Map.Center_Map();
  5519. Map.Flag_To_Redraw(true);
  5520. if (center) {
  5521. On_Center_Camera(PlayerPtr, Coord_X(center), Coord_Y(center));
  5522. }
  5523. }
  5524. }
  5525. /**************************************************************************************************
  5526. * DLLExportClass::Selected_Guard_Mode
  5527. *
  5528. * History: 03.03.2020 MBL
  5529. **************************************************************************************************/
  5530. void DLLExportClass::Selected_Guard_Mode(uint64 player_id)
  5531. {
  5532. /*
  5533. ** Get the player for this...
  5534. */
  5535. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5536. return;
  5537. }
  5538. if (CurrentObject.Count()) {
  5539. for (int index = 0; index < CurrentObject.Count(); index++) {
  5540. ObjectClass const * tech = CurrentObject[index];
  5541. if (tech && tech->Can_Player_Fire()) {
  5542. if (tech->Can_Player_Move()) {
  5543. OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD_AREA));
  5544. } else {
  5545. OutList.Add(EventClass(tech->As_Target(), MISSION_GUARD));
  5546. }
  5547. }
  5548. }
  5549. }
  5550. }
  5551. /**************************************************************************************************
  5552. * DLLExportClass::Selected_Stop
  5553. *
  5554. * History: 03.03.2020 MBL
  5555. **************************************************************************************************/
  5556. void DLLExportClass::Selected_Stop(uint64 player_id)
  5557. {
  5558. /*
  5559. ** Get the player for this...
  5560. */
  5561. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5562. return;
  5563. }
  5564. // Copied from TiberianDawn/Conquer.cpp - Keyboard_Process() with VK_S
  5565. if (CurrentObject.Count()) {
  5566. for (int index = 0; index < CurrentObject.Count(); index++) {
  5567. ObjectClass const * tech = CurrentObject[index];
  5568. if (tech && (tech->Can_Player_Move() || (tech->Can_Player_Fire() &&
  5569. tech->What_Am_I() != RTTI_BUILDING))) {
  5570. OutList.Add(EventClass(EventClass::IDLE, tech->As_Target()));
  5571. }
  5572. }
  5573. }
  5574. }
  5575. /**************************************************************************************************
  5576. * DLLExportClass::Units_Queued_Movement_Toggle
  5577. *
  5578. * History: 03.03.2020 MBL
  5579. **************************************************************************************************/
  5580. void DLLExportClass::Units_Queued_Movement_Toggle(uint64 /*player_id*/, bool /*toggle*/)
  5581. {
  5582. // Currently Red Alert only but stubbed in support in case we add to Tiberian Dawn later
  5583. }
  5584. /**************************************************************************************************
  5585. * DLLExportClass::Team_Units_Formation_Toggle_On
  5586. *
  5587. * History: 03.03.2020 MBL
  5588. **************************************************************************************************/
  5589. void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
  5590. {
  5591. /*
  5592. ** Get the player for this...
  5593. */
  5594. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5595. return;
  5596. }
  5597. // Red Alert only at this time, unless we do some updates to support in Tiberian Dawn
  5598. #if 0
  5599. Toggle_Formation(); // Conquer.cpp
  5600. #endif
  5601. }
  5602. /**************************************************************************************************
  5603. * CNC_Handle_Debug_Request -- Process a debug input request
  5604. *
  5605. * In:
  5606. *
  5607. *
  5608. * Out:
  5609. *
  5610. *
  5611. * History: 1/7/2019 5:20PM - ST
  5612. **************************************************************************************************/
  5613. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Debug_Request(DebugRequestEnum debug_request_type, uint64 player_id, const char *object_name, int x, int y, bool unshroud, bool enemy)
  5614. {
  5615. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5616. return;
  5617. }
  5618. switch (debug_request_type) {
  5619. case DEBUG_REQUEST_SPAWN_OBJECT:
  5620. {
  5621. DLLExportClass::Debug_Spawn_Unit(object_name, x, y, enemy);
  5622. }
  5623. break;
  5624. case DEBUG_REQUEST_FORCE_CRASH:
  5625. Debug_Force_Crash = true;
  5626. break;
  5627. case DEBUG_REQUEST_KILL_OBJECT:
  5628. if (strcmp(object_name, "HEAL") == 0) {
  5629. DLLExportClass::Debug_Heal_Unit(x, y);
  5630. }
  5631. else {
  5632. DLLExportClass::Debug_Kill_Unit(x, y);
  5633. }
  5634. break;
  5635. case DEBUG_REQUEST_END_GAME:
  5636. {
  5637. bool win = true;
  5638. const char lose[] = "LOSE";
  5639. if (strcmp(lose, object_name) == 0) {
  5640. win = false;
  5641. }
  5642. PlayerWins = win;
  5643. PlayerLoses = !win;
  5644. }
  5645. break;
  5646. case DEBUG_REQUEST_UNSHROUD:
  5647. Debug_Unshroud = unshroud;
  5648. Map.Flag_To_Redraw(true);
  5649. break;
  5650. case DEBUG_REQUEST_SUPERWEAPON_RECHARGE:
  5651. PlayerPtr->IonCannon.Forced_Charge(true);
  5652. PlayerPtr->NukeStrike.Forced_Charge(true);
  5653. PlayerPtr->AirStrike.Forced_Charge(true);
  5654. break;
  5655. case DEBUG_REQUEST_END_PRODUCTION:
  5656. {
  5657. for (int index = 0; index < Factories.Count(); index++) {
  5658. FactoryClass* factory = Factories.Ptr(index);
  5659. if (factory->Get_House()->IsHuman) {
  5660. Factories.Ptr(index)->Force_Complete();
  5661. }
  5662. }
  5663. }
  5664. break;
  5665. case DEBUG_REQUEST_ADD_RESOURCES:
  5666. {
  5667. if (object_name) {
  5668. int amount = atoi(object_name);
  5669. PlayerPtr->Credits += amount;
  5670. if (PlayerPtr->Credits < 0) {
  5671. PlayerPtr->Credits = 0;
  5672. }
  5673. }
  5674. }
  5675. break;
  5676. case DEBUG_REQUEST_UNLOCK_BUILDABLES:
  5677. PlayerPtr->DebugUnlockBuildables = !PlayerPtr->DebugUnlockBuildables;
  5678. PlayerPtr->IsRecalcNeeded = true;
  5679. break;
  5680. default:
  5681. break;
  5682. }
  5683. }
  5684. extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y)
  5685. {
  5686. if (!DLLExportClass::Set_Player_Context(player_id)) {
  5687. return;
  5688. }
  5689. // Beacons are only available if legacy rendering is disabled
  5690. if (DLLExportClass::Legacy_Render_Enabled()) {
  5691. return;
  5692. }
  5693. // Only allow one beacon per player
  5694. for (int index = 0; index < Anims.Count(); ++index) {
  5695. AnimClass* anim = Anims.Ptr(index);
  5696. if (anim != NULL &&
  5697. (*anim == ANIM_BEACON || *anim == ANIM_BEACON_VIRTUAL) &&
  5698. anim->OwnerHouse == PlayerPtr->Class->House) {
  5699. delete anim;
  5700. }
  5701. }
  5702. OutList.Add(EventClass(ANIM_BEACON, PlayerPtr->Class->House, Map.Pixel_To_Coord(pixel_x, pixel_y), PlayerPtr->Get_Allies()));
  5703. // Send sound effect to allies
  5704. for (int index = 0; index < Houses.Count(); ++index) {
  5705. HouseClass* hptr = Houses.Ptr(index);
  5706. if (hptr != NULL && hptr->IsActive && hptr->IsHuman && PlayerPtr->Is_Ally(hptr)) {
  5707. DLLExportClass::On_Sound_Effect(hptr, VOC_BEACON, "", 0, 0);
  5708. }
  5709. }
  5710. }
  5711. /**************************************************************************************************
  5712. * DLLExportClass::Debug_Spawn_All -- Debug spawn all buildable units and structures
  5713. *
  5714. * In: Object to unlimbo , x & y cell positions
  5715. *
  5716. *
  5717. * Out: True if unlimbo succeeded
  5718. *
  5719. *
  5720. *
  5721. * History: 1/22/2020 2:57PM - ST
  5722. **************************************************************************************************/
  5723. bool DLLExportClass::Try_Debug_Spawn_Unlimbo(TechnoClass *techno, int &cell_x, int &cell_y)
  5724. {
  5725. if (techno) {
  5726. int map_cell_x = Map.MapCellX;
  5727. int map_cell_y = Map.MapCellY;
  5728. int map_cell_right = map_cell_x + Map.MapCellWidth;
  5729. int map_cell_bottom = map_cell_y + Map.MapCellHeight;
  5730. map_cell_right = min(map_cell_right, cell_x + 26); // Generally try to prevent the objects from spawing off the right of the screen
  5731. int try_x = cell_x;
  5732. int try_y = cell_y;
  5733. while (try_y < map_cell_bottom) {
  5734. CELL cell = XY_Cell(try_x, try_y);
  5735. if (techno->Unlimbo(Cell_Coord(cell))) {
  5736. try_x++;
  5737. if (try_x > map_cell_right - 2) {
  5738. try_x = cell_x; //map_cell_x + 2;
  5739. try_y++;
  5740. }
  5741. cell_x = try_x;
  5742. cell_y = try_y;
  5743. return true;
  5744. }
  5745. try_x++;
  5746. if (try_x > map_cell_right - 2) {
  5747. try_x = cell_x; //map_cell_x + 2;
  5748. try_y++;
  5749. }
  5750. }
  5751. cell_x = try_x;
  5752. cell_y = try_y;
  5753. }
  5754. return false;
  5755. }
  5756. /**************************************************************************************************
  5757. * DLLExportClass::Debug_Spawn_All -- Debug spawn all buildable units and structures
  5758. *
  5759. * In:
  5760. *
  5761. * Out:
  5762. *
  5763. *
  5764. *
  5765. * History: 1/22/2020 2:57PM - ST
  5766. **************************************************************************************************/
  5767. void DLLExportClass::Debug_Spawn_All(int x, int y)
  5768. {
  5769. int map_cell_x = Map.MapCellX;
  5770. int map_cell_y = Map.MapCellY;
  5771. int map_cell_bottom = map_cell_y + Map.MapCellHeight;
  5772. int origin_x = map_cell_x + 2;
  5773. int origin_y = map_cell_y + 2;
  5774. if (x != 0 || y != 0) {
  5775. CELL screen_cell = Coord_Cell(Map.Pixel_To_Coord(x, y));
  5776. origin_x = Cell_X(screen_cell);
  5777. origin_y = Cell_Y(screen_cell);
  5778. }
  5779. int try_x = origin_x;
  5780. int try_y = origin_y;
  5781. HousesType house = PlayerPtr->Class->House;
  5782. for (StructType sindex = STRUCT_FIRST; sindex < STRUCT_COUNT; sindex++) {
  5783. BuildingTypeClass const & building_type = BuildingTypeClass::As_Reference(sindex);
  5784. if (building_type.IsBuildable) {
  5785. BuildingClass * building = new BuildingClass(building_type, house);
  5786. if (building) {
  5787. try_x = origin_x;
  5788. try_y = origin_y;
  5789. while (try_y < map_cell_bottom) {
  5790. if (Try_Debug_Spawn_Unlimbo(building, try_x, try_y)) {
  5791. break;
  5792. }
  5793. }
  5794. }
  5795. }
  5796. }
  5797. for (UnitType index = UNIT_FIRST; index < UNIT_COUNT; index++) {
  5798. UnitTypeClass const & unit_type = UnitTypeClass::As_Reference(index);
  5799. /*
  5800. ** Fetch the sidebar cameo image for this building.
  5801. */
  5802. if (unit_type.IsBuildable) {
  5803. UnitClass * unit = (UnitClass*) unit_type.Create_One_Of(PlayerPtr);
  5804. if (unit) {
  5805. try_x = origin_x;
  5806. try_y = origin_y;
  5807. while (try_y < map_cell_bottom) {
  5808. if (Try_Debug_Spawn_Unlimbo(unit, try_x, try_y)) {
  5809. break;
  5810. }
  5811. }
  5812. }
  5813. }
  5814. }
  5815. for (InfantryType index = INFANTRY_FIRST; index < INFANTRY_COUNT; index++) {
  5816. InfantryTypeClass const &infantry_type = InfantryTypeClass::As_Reference(index);
  5817. /*
  5818. ** Fetch the sidebar cameo image for this building.
  5819. */
  5820. if (infantry_type.IsBuildable) {
  5821. InfantryClass * inf = (InfantryClass*) infantry_type.Create_One_Of(PlayerPtr);
  5822. if (inf) {
  5823. try_x = origin_x;
  5824. try_y = origin_y;
  5825. while (try_y < map_cell_bottom) {
  5826. if (Try_Debug_Spawn_Unlimbo(inf, try_x, try_y)) {
  5827. break;
  5828. }
  5829. }
  5830. }
  5831. }
  5832. }
  5833. for (AircraftType index = AIRCRAFT_FIRST; index < AIRCRAFT_COUNT; index++) {
  5834. AircraftTypeClass const &aircraft_type = AircraftTypeClass::As_Reference(index);
  5835. /*
  5836. ** Fetch the sidebar cameo image for this building.
  5837. */
  5838. if (aircraft_type.IsBuildable) {
  5839. AircraftClass * air = (AircraftClass*) aircraft_type.Create_One_Of(PlayerPtr);
  5840. if (air) {
  5841. try_x = origin_x;
  5842. try_y = origin_y;
  5843. while (try_y < map_cell_bottom) {
  5844. if (Try_Debug_Spawn_Unlimbo(air, try_x, try_y)) {
  5845. break;
  5846. }
  5847. }
  5848. }
  5849. }
  5850. }
  5851. }
  5852. /**************************************************************************************************
  5853. * DLLExportClass::Debug_Spawn_Unit -- Debug spawn a unit at the specified location
  5854. *
  5855. * In:
  5856. *
  5857. * Out:
  5858. *
  5859. *
  5860. *
  5861. * History: 3/14/2019 3:20PM - ST
  5862. **************************************************************************************************/
  5863. void DLLExportClass::Debug_Spawn_Unit(const char *object_name, int x, int y, bool enemy)
  5864. {
  5865. if (object_name == NULL) {
  5866. return;
  5867. }
  5868. if (strlen(object_name) == 0) {
  5869. return;
  5870. }
  5871. COORDINATE coord = Map.Pixel_To_Coord(x, y);
  5872. CELL cell = Coord_Cell(coord);
  5873. HousesType house = PlayerPtr->Class->House;
  5874. /*
  5875. ** Place all?
  5876. */
  5877. if (stricmp(object_name, "ALLOBJECTS") == 0) {
  5878. Debug_Spawn_All(x, y);
  5879. return;
  5880. }
  5881. /*
  5882. ** If this is for the enemy, find the enemy with the most stuff
  5883. */
  5884. if (enemy) {
  5885. unsigned max_count = 0;
  5886. for (int i = 0; i < Houses.Count(); ++i) {
  5887. const HouseClass* player = Houses.Ptr(i);
  5888. const unsigned count = player->CurUnits + player->CurBuildings + player->CurInfantry + player->CurAircraft;
  5889. if (!PlayerPtr->Is_Ally(player) && (count >= max_count)) {
  5890. house = player->Class->House;
  5891. max_count = count;
  5892. }
  5893. }
  5894. }
  5895. /*
  5896. ** What is this thing?
  5897. */
  5898. StructType structure_type = BuildingTypeClass::From_Name(object_name);
  5899. if (structure_type != STRUCT_NONE) {
  5900. BuildingClass * building = new BuildingClass(structure_type, house);
  5901. if (building) {
  5902. if (!building->Unlimbo(Cell_Coord(cell))) {
  5903. delete building;
  5904. }
  5905. }
  5906. #if (0)
  5907. Map.PendingObject = &BuildingTypeClass::As_Reference(structure_type);
  5908. Map.PendingHouse = PlayerPtr->ActLike;
  5909. Map.PendingObjectPtr = Map.PendingObject->Create_One_Of(PlayerPtr);
  5910. if (Map.PendingObjectPtr) {
  5911. Map.Set_Cursor_Pos();
  5912. Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
  5913. //OutList.Add(EventClass(EventClass::PLACE, RTTI_BUILDING, (CELL)(cell + Map.ZoneOffset)));
  5914. }
  5915. #endif
  5916. return;
  5917. }
  5918. UnitType unit_type = UnitTypeClass::From_Name(object_name);
  5919. if (unit_type != UNIT_NONE) {
  5920. UnitClass * unit = new UnitClass(unit_type, house);
  5921. if (unit) {
  5922. unit->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N);
  5923. }
  5924. return;
  5925. }
  5926. InfantryType infantry_type = InfantryTypeClass::From_Name(object_name);
  5927. if (infantry_type != INFANTRY_NONE) {
  5928. InfantryClass * inf = new InfantryClass(infantry_type, house);
  5929. if (inf) {
  5930. inf->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N);
  5931. }
  5932. return;
  5933. }
  5934. AircraftType aircraft_type = AircraftTypeClass::From_Name(object_name);
  5935. if (aircraft_type != AIRCRAFT_NONE) {
  5936. AircraftClass * air = new AircraftClass(aircraft_type, house);
  5937. if (air) {
  5938. air->Altitude = 0;
  5939. air->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N);
  5940. }
  5941. return;
  5942. }
  5943. OverlayType overlay_type = OverlayTypeClass::From_Name(object_name);
  5944. if (overlay_type != OVERLAY_NONE)
  5945. {
  5946. new OverlayClass(overlay_type, cell);
  5947. return;
  5948. }
  5949. }
  5950. /**************************************************************************************************
  5951. * DLLExportClass::Debug_Kill_Unit -- Kill a unit at the specified location
  5952. *
  5953. * In:
  5954. *
  5955. * Out:
  5956. *
  5957. *
  5958. *
  5959. * History: 8/19/2019 3:09PM - ST
  5960. **************************************************************************************************/
  5961. void DLLExportClass::Debug_Kill_Unit(int x, int y)
  5962. {
  5963. COORDINATE coord = Map.Pixel_To_Coord(x, y);
  5964. CELL cell = Coord_Cell(coord);
  5965. CellClass * cellptr = &Map[cell];
  5966. if (cellptr) {
  5967. ObjectClass *obj = cellptr->Cell_Object();
  5968. static const int debug_damage = 1000;
  5969. if (obj) {
  5970. int damage = debug_damage;
  5971. obj->Take_Damage(damage, 0, WARHEAD_HE, 0);
  5972. } else {
  5973. if (cellptr->Overlay != OVERLAY_NONE) {
  5974. OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
  5975. if (optr->IsTiberium) {
  5976. cellptr->Reduce_Tiberium(1);
  5977. }
  5978. if (optr->IsWall) {
  5979. Map[cell].Reduce_Wall(debug_damage);
  5980. }
  5981. }
  5982. }
  5983. }
  5984. }
  5985. void DLLExportClass::Debug_Heal_Unit(int x, int y)
  5986. {
  5987. COORDINATE coord = Map.Pixel_To_Coord(x, y);
  5988. CELL cell = Coord_Cell(coord);
  5989. CellClass * cellptr = &Map[cell];
  5990. if (cellptr) {
  5991. ObjectClass *obj = cellptr->Cell_Object();
  5992. if (obj) {
  5993. obj->Strength = obj->Class_Of().MaxStrength;
  5994. }
  5995. else {
  5996. if (cellptr->Overlay != OVERLAY_NONE) {
  5997. OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
  5998. if (optr->IsTiberium) {
  5999. const int cellcount = (int)FACING_COUNT + 1;
  6000. CellClass* cells[cellcount];
  6001. cells[0] = cellptr;
  6002. for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
  6003. cells[(int)index + 1] = cellptr->Adjacent_Cell(index);
  6004. }
  6005. for (int index = 0; index < cellcount; index++) {
  6006. CellClass *newcell = cells[index];
  6007. if (newcell && newcell->Cell_Object() == NULL) {
  6008. if (newcell->Land_Type() == LAND_CLEAR && newcell->Overlay == OVERLAY_NONE) {
  6009. switch (newcell->TType) {
  6010. case TEMPLATE_BRIDGE1:
  6011. case TEMPLATE_BRIDGE2:
  6012. case TEMPLATE_BRIDGE3:
  6013. case TEMPLATE_BRIDGE4:
  6014. break;
  6015. default:
  6016. new OverlayClass(Random_Pick(OVERLAY_TIBERIUM1, OVERLAY_TIBERIUM12), newcell->Cell_Number());
  6017. newcell->OverlayData = 1;
  6018. break;
  6019. }
  6020. }
  6021. else if (newcell->Land_Type() == LAND_TIBERIUM) {
  6022. newcell->OverlayData = MIN(newcell->OverlayData + 1, 11);
  6023. newcell->Recalc_Attributes();
  6024. newcell->Redraw_Objects();
  6025. }
  6026. }
  6027. }
  6028. }
  6029. }
  6030. }
  6031. }
  6032. }
  6033. /**************************************************************************************************
  6034. * DLLExportClass::Legacy_Render_Enabled -- Is the legacy rendering enabled?
  6035. *
  6036. * In:
  6037. *
  6038. * Out:
  6039. *
  6040. *
  6041. *
  6042. * History: 4/15/2019 5:46PM - ST
  6043. **************************************************************************************************/
  6044. bool DLLExportClass::Legacy_Render_Enabled(void)
  6045. {
  6046. if (GameToPlay == GAME_GLYPHX_MULTIPLAYER) {
  6047. unsigned int num_humans = 0U;
  6048. for (int i = 0; i < MPlayerCount; ++i) {
  6049. HouseClass *player_ptr = HouseClass::As_Pointer(MPlayerHouses[i]);
  6050. if (player_ptr && player_ptr->IsHuman) {
  6051. if (++num_humans > 1) break;
  6052. }
  6053. }
  6054. return num_humans < 2;
  6055. }
  6056. //return false;
  6057. return true;
  6058. }
  6059. /**************************************************************************************************
  6060. * DLLExportClass::Computer_Message -- Replacement for original Computer_Message function
  6061. *
  6062. * In:
  6063. *
  6064. * Out:
  6065. *
  6066. *
  6067. *
  6068. * History: 1/27/2020 1:42PM - ST
  6069. **************************************************************************************************/
  6070. void DLLExportClass::Computer_Message(bool last_player_taunt)
  6071. {
  6072. HousesType house;
  6073. HouseClass *ptr;
  6074. HouseClass *ai_players[MAX_PLAYERS];
  6075. int ai_player_count = 0;
  6076. /*------------------------------------------------------------------------
  6077. Find the computer house that the message will be from
  6078. ------------------------------------------------------------------------*/
  6079. for (house = HOUSE_MULTI1; house < (HOUSE_MULTI1 + MPlayerMax); house++) {
  6080. ptr = HouseClass::As_Pointer(house);
  6081. if (!ptr || ptr->IsHuman || ptr->IsDefeated) {
  6082. continue;
  6083. }
  6084. ai_players[ai_player_count++] = ptr;
  6085. }
  6086. if (ai_player_count) {
  6087. int ai_player_index = 0;
  6088. if (ai_player_count > 1) {
  6089. ai_player_index = IRandom(0, ai_player_count - 1);
  6090. }
  6091. int taunt_index;
  6092. if (last_player_taunt) {
  6093. taunt_index = 13;
  6094. } else {
  6095. taunt_index = IRandom(0,12);
  6096. }
  6097. On_Message(ai_players[ai_player_index], "", 15.0f, MESSAGE_TYPE_COMPUTER_TAUNT, taunt_index);
  6098. }
  6099. }
  6100. /**************************************************************************************************
  6101. * DLLExportClass::Set_Special_Key_Flags --
  6102. *
  6103. * In:
  6104. *
  6105. * Out:
  6106. *
  6107. *
  6108. *
  6109. * History: 6/27/2019 - JAS
  6110. **************************************************************************************************/
  6111. void DLLExportClass::Set_Special_Key_Flags(unsigned char special_key_flags)
  6112. {
  6113. SpecialKeyFlags[CurrentLocalPlayerIndex] = special_key_flags;
  6114. }
  6115. /**************************************************************************************************
  6116. * DLLExportClass::Clear_Special_Key_Flags --
  6117. *
  6118. * In:
  6119. *
  6120. * Out:
  6121. *
  6122. *
  6123. *
  6124. * History: 6/27/2019 - JAS
  6125. **************************************************************************************************/
  6126. void DLLExportClass::Clear_Special_Key_Flags()
  6127. {
  6128. SpecialKeyFlags[CurrentLocalPlayerIndex] = 0;
  6129. }
  6130. /**************************************************************************************************
  6131. * DLLExportClass::Get_Input_Key_State --
  6132. *
  6133. * In:
  6134. *
  6135. * Out:
  6136. *
  6137. *
  6138. *
  6139. * History: 6/27/2019 - JAS
  6140. **************************************************************************************************/
  6141. bool DLLExportClass::Get_Input_Key_State(KeyNumType key)
  6142. {
  6143. switch (key)
  6144. {
  6145. case KN_LCTRL:
  6146. return (SpecialKeyFlags[CurrentLocalPlayerIndex] & INPUT_SPECIAL_KEY_CTRL) != 0;
  6147. break;
  6148. case KN_LSHIFT:
  6149. return (SpecialKeyFlags[CurrentLocalPlayerIndex] & INPUT_SPECIAL_KEY_SHIFT) != 0;
  6150. break;
  6151. case KN_LALT:
  6152. return (SpecialKeyFlags[CurrentLocalPlayerIndex] & INPUT_SPECIAL_KEY_ALT) != 0;
  6153. break;
  6154. default:
  6155. break;
  6156. };
  6157. return false;
  6158. }
  6159. /**************************************************************************************************
  6160. * Get_Input_Key_State
  6161. *
  6162. * History: 6/27/2019 - JAS
  6163. **************************************************************************************************/
  6164. bool DLL_Export_Get_Input_Key_State(KeyNumType key)
  6165. {
  6166. return DLLExportClass::Get_Input_Key_State(key);
  6167. }
  6168. bool DLLSave(FileClass &file)
  6169. {
  6170. return DLLExportClass::Save(file);
  6171. }
  6172. bool DLLLoad(FileClass &file)
  6173. {
  6174. return DLLExportClass::Load(file);
  6175. }
  6176. /**************************************************************************************************
  6177. * DLLExportClass::Save --
  6178. *
  6179. * In:
  6180. *
  6181. * Out:
  6182. *
  6183. *
  6184. *
  6185. * History: 9/10/2019 10:24AM - ST
  6186. **************************************************************************************************/
  6187. bool DLLExportClass::Save(FileClass & file)
  6188. {
  6189. /*
  6190. ** Version first
  6191. */
  6192. unsigned int version = CNC_DLL_API_VERSION;
  6193. if (file.Write(&version, sizeof(version)) != sizeof(version)) {
  6194. return false;
  6195. }
  6196. if (file.Write(MultiplayerStartPositions, sizeof(MultiplayerStartPositions)) != sizeof(MultiplayerStartPositions)) {
  6197. return false;
  6198. }
  6199. if (file.Write(GlyphxPlayerIDs, sizeof(GlyphxPlayerIDs)) != sizeof(GlyphxPlayerIDs)) {
  6200. return false;
  6201. }
  6202. if (file.Write(&GlyphXClientSidebarWidthInLeptons, sizeof(GlyphXClientSidebarWidthInLeptons)) != sizeof(GlyphXClientSidebarWidthInLeptons)) {
  6203. return false;
  6204. }
  6205. if (file.Write(MPlayerIsHuman, sizeof(MPlayerIsHuman)) != sizeof(MPlayerIsHuman)) {
  6206. return false;
  6207. }
  6208. if (file.Write(MultiplayerStartPositions, sizeof(MultiplayerStartPositions)) != sizeof(MultiplayerStartPositions)) {
  6209. return false;
  6210. }
  6211. if (file.Write(PlacementType, sizeof(PlacementType)) != sizeof(PlacementType)) {
  6212. return false;
  6213. }
  6214. if (file.Write(&MPlayerCount, sizeof(MPlayerCount)) != sizeof(MPlayerCount)) {
  6215. return false;
  6216. }
  6217. if (file.Write(&MPlayerBases, sizeof(MPlayerBases)) != sizeof(MPlayerBases)) {
  6218. return false;
  6219. }
  6220. if (file.Write(&MPlayerCredits, sizeof(MPlayerCredits)) != sizeof(MPlayerCredits)) {
  6221. return false;
  6222. }
  6223. if (file.Write(&MPlayerTiberium, sizeof(MPlayerTiberium)) != sizeof(MPlayerTiberium)) {
  6224. return false;
  6225. }
  6226. if (file.Write(&MPlayerGoodies, sizeof(MPlayerGoodies)) != sizeof(MPlayerGoodies)) {
  6227. return false;
  6228. }
  6229. if (file.Write(&MPlayerGhosts, sizeof(MPlayerGhosts)) != sizeof(MPlayerGhosts)) {
  6230. return false;
  6231. }
  6232. if (file.Write(&MPlayerSolo, sizeof(MPlayerSolo)) != sizeof(MPlayerSolo)) {
  6233. return false;
  6234. }
  6235. if (file.Write(&MPlayerUnitCount, sizeof(MPlayerUnitCount)) != sizeof(MPlayerUnitCount)) {
  6236. return false;
  6237. }
  6238. if (file.Write(&MPlayerLocalID, sizeof(MPlayerLocalID)) != sizeof(MPlayerLocalID)) {
  6239. return false;
  6240. }
  6241. if (file.Write(MPlayerHouses, sizeof(MPlayerHouses)) != sizeof(MPlayerHouses)) {
  6242. return false;
  6243. }
  6244. if (file.Write(MPlayerNames, sizeof(MPlayerNames)) != sizeof(MPlayerNames)) {
  6245. return false;
  6246. }
  6247. if (file.Write(MPlayerID, sizeof(MPlayerID)) != sizeof(MPlayerID)) {
  6248. return false;
  6249. }
  6250. if (file.Write(MPlayerIsHuman, sizeof(MPlayerIsHuman)) != sizeof(MPlayerIsHuman)) {
  6251. return false;
  6252. }
  6253. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  6254. Sidebar_Glyphx_Save(file, &MultiplayerSidebars[i]);
  6255. }
  6256. if (file.Write(&Special, sizeof(Special)) != sizeof(Special)) {
  6257. return false;
  6258. }
  6259. /*
  6260. ** Special case for Rule.AllowSuperWeapons - store negated value so it defaults to enabled
  6261. */
  6262. bool not_allow_super_weapons = !Rule.AllowSuperWeapons;
  6263. if (file.Write(&not_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
  6264. return false;
  6265. }
  6266. /*
  6267. ** Room for save game expansion
  6268. */
  6269. unsigned char padding[4095];
  6270. memset(padding, 0, sizeof(padding));
  6271. if (file.Write(padding, sizeof(padding)) != sizeof(padding)) {
  6272. return false;
  6273. }
  6274. return true;
  6275. }
  6276. /**************************************************************************************************
  6277. * DLLExportClass::Load --
  6278. *
  6279. * In:
  6280. *
  6281. * Out:
  6282. *
  6283. *
  6284. *
  6285. * History: 9/10/2019 10:24AM - ST
  6286. **************************************************************************************************/
  6287. bool DLLExportClass::Load(FileClass & file)
  6288. {
  6289. unsigned int version = 0;
  6290. if (file.Read(&version, sizeof(version)) != sizeof(version)) {
  6291. return false;
  6292. }
  6293. if (file.Read(MultiplayerStartPositions, sizeof(MultiplayerStartPositions)) != sizeof(MultiplayerStartPositions)) {
  6294. return false;
  6295. }
  6296. if (file.Read(GlyphxPlayerIDs, sizeof(GlyphxPlayerIDs)) != sizeof(GlyphxPlayerIDs)) {
  6297. return false;
  6298. }
  6299. if (file.Read(&GlyphXClientSidebarWidthInLeptons, sizeof(GlyphXClientSidebarWidthInLeptons)) != sizeof(GlyphXClientSidebarWidthInLeptons)) {
  6300. return false;
  6301. }
  6302. if (file.Read(MPlayerIsHuman, sizeof(MPlayerIsHuman)) != sizeof(MPlayerIsHuman)) {
  6303. return false;
  6304. }
  6305. if (file.Read(MultiplayerStartPositions, sizeof(MultiplayerStartPositions)) != sizeof(MultiplayerStartPositions)) {
  6306. return false;
  6307. }
  6308. if (file.Read(PlacementType, sizeof(PlacementType)) != sizeof(PlacementType)) {
  6309. return false;
  6310. }
  6311. if (file.Read(&MPlayerCount, sizeof(MPlayerCount)) != sizeof(MPlayerCount)) {
  6312. return false;
  6313. }
  6314. if (file.Read(&MPlayerBases, sizeof(MPlayerBases)) != sizeof(MPlayerBases)) {
  6315. return false;
  6316. }
  6317. if (file.Read(&MPlayerCredits, sizeof(MPlayerCredits)) != sizeof(MPlayerCredits)) {
  6318. return false;
  6319. }
  6320. if (file.Read(&MPlayerTiberium, sizeof(MPlayerTiberium)) != sizeof(MPlayerTiberium)) {
  6321. return false;
  6322. }
  6323. if (file.Read(&MPlayerGoodies, sizeof(MPlayerGoodies)) != sizeof(MPlayerGoodies)) {
  6324. return false;
  6325. }
  6326. if (file.Read(&MPlayerGhosts, sizeof(MPlayerGhosts)) != sizeof(MPlayerGhosts)) {
  6327. return false;
  6328. }
  6329. if (file.Read(&MPlayerSolo, sizeof(MPlayerSolo)) != sizeof(MPlayerSolo)) {
  6330. return false;
  6331. }
  6332. if (file.Read(&MPlayerUnitCount, sizeof(MPlayerUnitCount)) != sizeof(MPlayerUnitCount)) {
  6333. return false;
  6334. }
  6335. if (file.Read(&MPlayerLocalID, sizeof(MPlayerLocalID)) != sizeof(MPlayerLocalID)) {
  6336. return false;
  6337. }
  6338. if (file.Read(MPlayerHouses, sizeof(MPlayerHouses)) != sizeof(MPlayerHouses)) {
  6339. return false;
  6340. }
  6341. if (file.Read(MPlayerNames, sizeof(MPlayerNames)) != sizeof(MPlayerNames)) {
  6342. return false;
  6343. }
  6344. if (file.Read(MPlayerID, sizeof(MPlayerID)) != sizeof(MPlayerID)) {
  6345. return false;
  6346. }
  6347. if (file.Read(MPlayerIsHuman, sizeof(MPlayerIsHuman)) != sizeof(MPlayerIsHuman)) {
  6348. return false;
  6349. }
  6350. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  6351. Sidebar_Glyphx_Load(file, &MultiplayerSidebars[i]);
  6352. }
  6353. if (file.Read(&Special, sizeof(Special)) != sizeof(Special)) {
  6354. return false;
  6355. }
  6356. /*
  6357. ** Special case for Rule.AllowSuperWeapons - store negated value so it defaults to enabled
  6358. */
  6359. bool not_allow_super_weapons = false;
  6360. if (file.Read(&not_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
  6361. return false;
  6362. }
  6363. Rule.AllowSuperWeapons = !not_allow_super_weapons;
  6364. unsigned char padding[4095];
  6365. if (file.Read(padding, sizeof(padding)) != sizeof(padding)) {
  6366. return false;
  6367. }
  6368. return true;
  6369. }
  6370. /**************************************************************************************************
  6371. * DLLExportClass::Code_Pointers --
  6372. *
  6373. * In:
  6374. *
  6375. * Out:
  6376. *
  6377. *
  6378. *
  6379. * History: 9/10/2019 10:24AM - ST
  6380. **************************************************************************************************/
  6381. void DLLExportClass::Code_Pointers(void)
  6382. {
  6383. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  6384. Sidebar_Glyphx_Code_Pointers(&MultiplayerSidebars[i]);
  6385. if (PlacementType[i]) {
  6386. PlacementType[i] = (BuildingTypeClass *) PlacementType[i]->Type;
  6387. }
  6388. }
  6389. }
  6390. /**************************************************************************************************
  6391. * DLLExportClass::Decode_Pointers --
  6392. *
  6393. * In:
  6394. *
  6395. * Out:
  6396. *
  6397. *
  6398. *
  6399. * History: 9/10/2019 10:24AM - ST
  6400. **************************************************************************************************/
  6401. void DLLExportClass::Decode_Pointers(void)
  6402. {
  6403. for (int i=0 ; i<MAX_PLAYERS ; i++) {
  6404. Sidebar_Glyphx_Decode_Pointers(&MultiplayerSidebars[i]);
  6405. if (PlacementType[i]) {
  6406. StructType type = (StructType) reinterpret_cast<unsigned int>(PlacementType[i]);
  6407. PlacementType[i] = NULL;
  6408. if (type >= STRUCT_FIRST && type < STRUCT_COUNT) {
  6409. TechnoTypeClass const * tech = Fetch_Techno_Type(RTTI_BUILDINGTYPE, type);
  6410. if (tech) {
  6411. BuildingTypeClass* build_type = (BuildingTypeClass*)(tech);
  6412. if (build_type) {
  6413. PlacementType[i] = build_type;
  6414. }
  6415. }
  6416. }
  6417. }
  6418. }
  6419. }
  6420. void DLL_Code_Pointers(void)
  6421. {
  6422. DLLExportClass::Code_Pointers();
  6423. }
  6424. void DLL_Decode_Pointers(void)
  6425. {
  6426. DLLExportClass::Decode_Pointers();
  6427. }