DLLInterface.cpp 252 KB

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