1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845 |
- //
- // Copyright 2020 Electronic Arts Inc.
- //
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
- // software: you can redistribute it and/or modify it under the terms of
- // the GNU General Public License as published by the Free Software Foundation,
- // either version 3 of the License, or (at your option) any later version.
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
- // in the hope that it will be useful, but with permitted additional restrictions
- // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
- // distributed with this program. You should have received a copy of the
- // GNU General Public License along with permitted additional restrictions
- // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
- /*
- ** DLLInterfac.cpp
- **
- ** This is where we implement the API expected by the Instance Server.
- **
- ** The Instance Server will pass in requests for loading and starting maps, control input from players,
- ** and requests for game simulation and rendering states.
- **
- **
- */
- // Exception handling isn't enabled
- #pragma warning (disable : 4530) //warning C4530: C++ exception handler used, but unwind semantics are not enabled.
- #include <string>
- #include <vector>
- #include <set>
- #include "function.h"
- #include "externs.h"
- #include "DLLInterface.h"
- #include "Gadget.h"
- #include "defines.h" // VOC_COUNT, VOX_COUNT
- #include "SidebarGlyphx.h"
- #include <chrono>
- /*
- ** Externs
- */
- extern int DLL_Startup(const char * command_line);
- extern void Reallocate_Big_Shape_Buffer(void);
- extern bool ProgEndCalled;
- extern int Write_PCX_File(char* name, GraphicViewPortClass& pic, unsigned char* palette );
- extern void Color_Cycle(void);
- bool Debug_Write_Shape_Type(const ObjectTypeClass *type, int shapenum);
- bool Debug_Write_Shape(const char *file_name, void const * shapefile, int shapenum, int flags = 0, void const * ghostdata = NULL);
- typedef void (__cdecl* CNC_Event_Callback_Type)(const EventCallbackStruct &event);
- typedef unsigned __int64 uint64;
- typedef __int64 int64;
-
- /*
- ** Audio defines
- **
- **
- **
- **
- **
- */
- // For compatibility with Watcom in audio enums
- #pragma warning (disable : 4091)
- // From RedAlert\Audio.cpp
- enum ContextType;
- extern struct SoundEffectNameStruct {
- char const *Name; // Digitized voice file name.
- int Priority; // Playback priority of this sample.
- ContextType Where; // In what game context does this sample exist.
- } SoundEffectName[VOC_COUNT];
- // From RedAlert\Audio.cpp
- extern char const* Speech[VOX_COUNT];
- // From RedAlert\Audio.cpp
- typedef enum {
- IN_NOVAR, // No variation or alterations allowed.
- IN_VAR // Infantry variance response modification.
- };
- /*
- ** Misc defines
- **
- **
- **
- **
- **
- */
- #define GAME_TO_PLAY Session.Type
- #define MULTIPLAYER_COUNT Session.Players.Count()
- #define KEYBOARD Keyboard
- #define RANDOM_START_POSITION 0x7f
- #define KILL_PLAYER_ON_DISCONNECT 1
- /*
- ** DLL Interface
- **
- **
- **
- **
- **
- */
- extern "C" __declspec(dllexport) unsigned int __cdecl CNC_Version(unsigned int version_in);
- extern "C" __declspec(dllexport) void __cdecl CNC_Init(const char *command_line, CNC_Event_Callback_Type event_callback);
- extern "C" __declspec(dllexport) void __cdecl CNC_Config(const CNCRulesDataStruct& rules);
- extern "C" __declspec(dllexport) void __cdecl CNC_Add_Mod_Path(const char *mod_path);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Visible_Page(unsigned char *buffer_in, unsigned int &width, unsigned int &height);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Palette(unsigned char(&palette_in)[256][3]);
- 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);
- 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);
- 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);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Advance_Instance(uint64 player_id);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Game_State(GameStateRequestEnum state_type, uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- 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);
- extern "C" __declspec(dllexport) void __cdecl CNC_Set_Home_Cell(int x, int y, uint64 player_id);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Request(GameRequestEnum request_type);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Settings_Request(int health_bar_display_mode, int resource_bar_display_mode);
- 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);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Structure_Request(StructureRequestEnum request_type, uint64 player_id, int object_id);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Unit_Request(UnitRequestEnum request_type, uint64 player_id);
- 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);
- 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);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_ControlGroup_Request(ControlGroupRequestEnum request_type, uint64 player_id, unsigned char control_group_index);
- 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);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y);
- 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);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Clear_Object_Selection(uint64 player_id);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Select_Object(uint64 player_id, int object_type_id, int object_to_select_id);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const char *file_path_and_name, const char *game_type);
- extern "C" __declspec(dllexport) void __cdecl CNC_Set_Difficulty(int difficulty);
- extern "C" __declspec(dllexport) void __cdecl CNC_Restore_Carryover_Objects(const CarryoverObjectStruct* objects);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uint64 player_id);
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Human_Team_Wins(uint64 player_id);
- extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time);
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index);
- /*
- ** Class to implement the interface, and contain additional game state required by the conversion from peer/peer to client/server
- **
- **
- **
- **
- **
- */
- class DLLExportClass {
- public:
-
- static void Init(void);
- static void Shutdown(void);
- static void Config(const CNCRulesDataStruct& rules);
- static void Add_Mod_Path(const char *mod_path);
- static void Set_Home_Cell(int x, int y, uint64 player_id);
- static void Set_Content_Directory(const char *dir);
- static bool Get_Layer_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static bool Get_Sidebar_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static bool Start_Construction(uint64 player_id, int buildable_type, int buildable_id);
- static bool Hold_Construction(uint64 player_id, int buildable_type, int buildable_id);
- static bool Cancel_Construction(uint64 player_id, int buildable_type, int buildable_id);
- static bool Start_Placement(uint64 player_id, int buildable_type, int buildable_id);
- static BuildingClass *Get_Pending_Placement_Object(uint64 player_id, int buildable_type, int buildable_id);
- static bool Get_Placement_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static void Convert_Type(const ObjectClass *object, CNCObjectStruct &object_out);
- 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);
- static void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip);
- static bool Place(uint64 player_id, int buildable_type, int buildable_id, short cell_x, short cell_y);
- static bool Cancel_Placement(uint64 player_id, int buildable_type, int buildable_id);
- static bool Place_Super_Weapon(uint64 player_id, int buildable_type, int buildable_id, int x, int y);
- static bool Create_Control_Group(unsigned char control_group_index);
- static bool Add_To_Control_Group(unsigned char control_group_index);
- static bool Toggle_Control_Group_Selection(unsigned char control_group_index);
- static bool Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id);
- static bool MP_Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id);
- static bool Passes_Proximity_Check(CELL cell_in, BuildingTypeClass *placement_type, unsigned char* placement_distance);
- static void Calculate_Start_Positions(void);
- static void Computer_Message(bool last_player_taunt);
- static void Repair_Mode(uint64 player_id);
- static void Repair(uint64 player_id, int object_id);
- static void Sell_Mode(uint64 player_id);
- static void Sell(uint64 player_id, int object_id);
- static void Repair_Sell_Cancel(uint64 player_id);
- static void Scatter_Selected(uint64 player_id);
- static void Select_Next_Unit(uint64 player_id);
- static void Select_Previous_Unit(uint64 player_id);
- static void Selected_Guard_Mode(uint64 player_id);
- static void Selected_Stop(uint64 player_id);
- static void Team_Units_Formation_Toggle_On(uint64 player_id);
- static void Units_Queued_Movement_Toggle(uint64 player_id, bool toggle);
- static void Cell_Class_Draw_It(CNCDynamicMapStruct *dynamic_map, int &entry_index, CellClass *cell_ptr, int xpixel, int ypixel, bool debug_output);
- static bool Get_Dynamic_Map_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static bool Get_Shroud_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static bool Get_Occupier_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static bool Get_Player_Info_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size);
- static void Set_Event_Callback(CNC_Event_Callback_Type event_callback) {EventCallback = event_callback;}
- static void Debug_Spawn_Unit(const char *object_name, int x, int y, bool enemy = false);
- static void Debug_Spawn_All(int x, int y);
- static bool Try_Debug_Spawn_Unlimbo(TechnoClass *techno, int &cell_x, int &cell_y);
- static void Debug_Kill_Unit(int x, int y);
- static void Debug_Heal_Unit(int x, int y);
- static void On_Play_Movie(const char * movie_name, ThemeType theme, bool immediate);
- static void On_Display_Briefing_Text();
- static void On_Sound_Effect(const HouseClass* player_ptr, int sound_effect_index, const char* extension, int variation, COORDINATE coord);
- static void On_Speech(const HouseClass* player_ptr, int speech_index);
- static void On_Message(const HouseClass* player_ptr, const char* message, float timeout_seconds, EventCallbackMessageEnum message_type, int64 message_id);
- static void On_Update_Map_Cell(int cell_x, int cell_y, const char* template_type_name);
- static void On_Special_Weapon_Targetting(const HouseClass* player_ptr, SpecialWeaponType weapon_type);
- static void On_Ping(const HouseClass* player_ptr, COORDINATE coord);
- static void On_Game_Over(uint64 glyphx_player_id, bool player_wins);
- static void On_Multiplayer_Game_Over(void);
- static void On_Debug_Output(const char *debug_text);
- static void On_Achievement(const HouseClass* player_ptr, const char *achievement_type, const char *achievement_reason);
- static void On_Center_Camera(const HouseClass* player_ptr, int coord_x, int coord_y);
- static void Glyphx_Queue_AI();
- static void Store_Carryover_Objects();
- static void Force_Human_Team_Wins(uint64 quitting_player_id);
-
- /*
- ** Player context switching for input/output
- */
- static bool Set_Player_Context(uint64 glyphx_player, bool force = false);
- static void Reset_Player_Context(void);
- static void Adjust_Internal_View(bool force_ignore_view_constraints = false);
- static void Logic_Switch_Player_Context(ObjectClass *object);
- static void Logic_Switch_Player_Context(HouseClass *house);
- static void Refresh_Player_Control_Flags(void);
- static __int64 Get_GlyphX_Player_ID(const HouseClass *house);
- static void Recalculate_Placement_Distances();
-
- static void Reset_Sidebars(void);
- static SidebarGlyphxClass *Get_Current_Context_Sidebar(HouseClass *player_ptr = NULL);
- static uint64 GlyphxPlayerIDs[MAX_PLAYERS];
- static const void *Get_Shadow_Shapes(void) {return Map.ShadowShapes;}
- static const unsigned char *Get_Shadow_Trans(void) {return &Map.ShadowTrans[0];}
- static bool Legacy_Render_Enabled(void);
- static bool Get_Input_Key_State(KeyNumType key);
- static void Set_Special_Key_Flags(unsigned char special_key_flags);
- static void Clear_Special_Key_Flags();
- static bool Load(Straw &file);
- static bool Save(Pipe &file);
- static void Code_Pointers(void);
- static void Decode_Pointers(void);
- static bool Get_Game_Over() { return GameOver; }
- private:
- static void Calculate_Single_Player_Score(EventCallbackStruct&);
- static int RA_Calculate_Leadership( HousesType player_house, int units_lost, int buildings_lost );
- static int RA_Calculate_Economy( long available_money, int stolen_buildings_credits, unsigned harvested_credits, long initial_credits );
- static int RA_Calculate_Score( int uspoints, int leadership, int economy );
- static void Convert_Action_Type(ActionType type, ObjectClass* object, TARGET target, DllActionTypeEnum& dll_type);
- static void Convert_Special_Weapon_Type(SpecialWeaponType weapon_type, DllSuperweaponTypeEnum& dll_weapon_type, char* weapon_name);
- static void Fill_Sidebar_Entry_From_Special_Weapon(CNCSidebarEntryStruct& sidebar_entry_out, SuperClass*& super_weapon_out, SpecialWeaponType weapon_type);
- static void Calculate_Placement_Distances(BuildingTypeClass* placement_type, unsigned char* placement_distance);
- static int CurrentDrawCount;
- static int TotalObjectCount;
- static int SortOrder;
- static int ExportLayer;
- static CNCObjectListStruct *ObjectList;
- static CNC_Event_Callback_Type EventCallback;
- static int CurrentLocalPlayerIndex;
- static bool GameOver;
- static std::set<int64> MessagesSent;
- /*
- ** Pseudo sidebars for players in multiplayer
- */
- static SidebarGlyphxClass MultiplayerSidebars[MAX_PLAYERS];
- static CELL MultiplayerStartPositions[MAX_PLAYERS];
- static BuildingTypeClass *PlacementType[MAX_PLAYERS];
- static unsigned char PlacementDistance[MAX_PLAYERS][MAP_CELL_TOTAL];
- static unsigned char SpecialKeyFlags[MAX_PLAYERS];
- /*
- ** Mod directories
- */
- static DynamicVectorClass<char *> ModSearchPaths;
- };
- /*
- ** DLLExportClass static data
- **
- **
- **
- **
- **
- */
- int DLLExportClass::CurrentDrawCount = 0;
- int DLLExportClass::TotalObjectCount = 0;
- int DLLExportClass::SortOrder = 0;
- int DLLExportClass::ExportLayer = 0;
- CNCObjectListStruct *DLLExportClass::ObjectList = NULL;
- SidebarGlyphxClass DLLExportClass::MultiplayerSidebars [MAX_PLAYERS];
- uint64 DLLExportClass::GlyphxPlayerIDs[MAX_PLAYERS] = {0xffffffffl};
- int DLLExportClass::CurrentLocalPlayerIndex = -1;
- CELL DLLExportClass::MultiplayerStartPositions[MAX_PLAYERS];
- BuildingTypeClass *DLLExportClass::PlacementType[MAX_PLAYERS];
- unsigned char DLLExportClass::PlacementDistance[MAX_PLAYERS][MAP_CELL_TOTAL];
- unsigned char DLLExportClass::SpecialKeyFlags[MAX_PLAYERS] = { 0U };
- DynamicVectorClass<char *> DLLExportClass::ModSearchPaths;
- std::set<int64> DLLExportClass::MessagesSent;
- bool DLLExportClass::GameOver = false;
- /*
- ** Global variables
- **
- **
- **
- **
- **
- */
- int DLLForceMouseX = 0;
- int DLLForceMouseY = 0;
- CNC_Event_Callback_Type DLLExportClass::EventCallback = NULL;
- // Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
- int GlyphXClientSidebarWidthInLeptons = 0;
- bool MPlayerIsHuman[MAX_PLAYERS];
- int MPlayerTeamIDs[MAX_PLAYERS];
- int MPlayerStartLocations[MAX_PLAYERS];
- bool MPSuperWeaponDisable = false;
- bool ShareAllyVisibility = true;
- bool UseGlyphXStartLocations = true;
- SpecialClass* SpecialBackup = NULL;
- int GetRandSeed()
- {
- using namespace std::chrono;
- time_point<system_clock> time_since_epoch = system_clock::now();
- auto microseconds_since_epoch = floor<std::chrono::microseconds>(time_since_epoch);
- return abs( static_cast<int>(microseconds_since_epoch.time_since_epoch().count()) );
- }
- void Play_Movie_GlyphX(const char * movie_name, ThemeType theme, bool immediate = false)
- {
- if ((movie_name[0] == 'x' || movie_name[0] == 'X') && movie_name[1] == 0) {
- return;
- }
- DLLExportClass::On_Play_Movie(movie_name, theme, immediate);
- }
- void Display_Briefing_Text_GlyphX()
- {
- DLLExportClass::On_Display_Briefing_Text();
- }
- void On_Sound_Effect(int sound_index, int variation, COORDINATE coord, int house)
- {
- int voc = sound_index;
- if (voc == VOC_NONE)
- {
- return;
- }
- // Borrowed from RedAlert\AUDIO.CPP Sound_Effect()
- //
- #if 1
- /*
- ** Fetch a pointer to the sound effect data. Modify the sound as appropriate and desired.
- */
- char const * ext = ""; // ".AUD";
- if (SoundEffectName[voc].Where == IN_VAR) {
-
- /*
- ** If there is no forced house, then use the current player
- ** act like house.
- */
- if (house == HOUSE_NONE) {
- house = PlayerPtr->ActLike;
- }
-
- /*
- ** Change the extension based on the variation and house accent requested.
- */
- if (((1 << house) & HOUSEF_ALLIES) != 0) {
-
- /*
- ** For infantry, use a variation on the response. For vehicles, always
- ** use the vehicle response table.
- */
- if (variation < 0) {
- if (ABS(variation) % 2) {
- ext = ".V00";
- } else {
- ext = ".V02";
- }
- } else {
- if (variation % 2) {
- ext = ".V01";
- } else {
- ext = ".V03";
- }
- }
- } else {
- if (variation < 0) {
- if (ABS(variation) % 2) {
- ext = ".R00";
- } else {
- ext = ".R02";
- }
- } else {
- if (variation % 2) {
- ext = ".R01";
- } else {
- ext = ".R03";
- }
- }
- }
- }
- #endif
- // END MBL
- DLLExportClass::On_Sound_Effect(PlayerPtr, sound_index, ext, variation, coord);
- #if 0
- int voc = sound_index;
- if (voc == VOC_NONE)
- {
- return;
- }
- // Borrowed from AUDIO.CPP Sound_Effect()
- //
- char const * ext = ""; // ".AUD";
- #ifdef TIBERIAN_DAWN
- if (Special.IsJuvenile && SoundEffectName[voc].Where == IN_JUV) {
- ext = ".JUV";
- } else {
- #endif
- if (SoundEffectName[voc].Where == IN_VAR) {
- /*
- ** For infantry, use a variation on the response. For vehicles, always
- ** use the vehicle response table.
- */
- if (variation < 0) {
- if (ABS(variation) % 2) {
- ext = ".V00";
- } else {
- ext = ".V02";
- }
- } else {
- if (variation % 2) {
- ext = ".V01";
- } else {
- ext = ".V03";
- }
- }
- }
- #ifdef TIBERIAN_DAWN
- }
- #endif
- // END MBL
- DLLExportClass::On_Sound_Effect(PlayerPtr, sound_index, ext, variation, coord);
- #endif
- }
- void On_Speech(int speech_index, HouseClass *house)
- {
- if (house == NULL) {
- DLLExportClass::On_Speech(PlayerPtr, speech_index);
- }
- else
- {
- DLLExportClass::On_Speech(house, speech_index);
- }
- }
- void On_Message(const char* message, float timeout_seconds, int64 id)
- {
- DLLExportClass::On_Message(PlayerPtr, message, timeout_seconds, MESSAGE_TYPE_DIRECT, id);
- }
- void On_Update_Map_Cell(int cell_x, int cell_y, const char* template_type_name)
- {
- DLLExportClass::On_Update_Map_Cell(cell_x, cell_y, template_type_name);
- }
- void On_Special_Weapon_Targetting(const HouseClass* player_ptr, SpecialWeaponType weapon_type)
- {
- DLLExportClass::On_Special_Weapon_Targetting(player_ptr, weapon_type);
- }
- void On_Ping(const HouseClass* player_ptr, COORDINATE coord)
- {
- DLLExportClass::On_Ping(player_ptr, coord);
- }
- void On_Defeated_Message(const char* message, float timeout_seconds)
- {
- DLLExportClass::On_Message(PlayerPtr, message, timeout_seconds, MESSAGE_TYPE_PLAYER_DEFEATED, -1);
- }
- void GlyphX_Debug_Print(const char *debug_text)
- {
- DLLExportClass::On_Debug_Output(debug_text);
- }
- void On_Achievement_Event(const HouseClass* player_ptr, const char *achievement_type, const char *achievement_reason)
- {
- DLLExportClass::On_Achievement(player_ptr, achievement_type, achievement_reason);
- }
- /**************************************************************************************************
- * CNC_Version -- Check DLL/Server version
- *
- * In: Version expected
- *
- * Out: Actual version
- *
- *
- *
- * History: 4/9/2020 2:12PM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) unsigned int __cdecl CNC_Version(unsigned int version_in)
- {
- // Unreferenced, but potentially useful to know which version the server is expecting
- version_in;
- return CNC_DLL_API_VERSION;
- }
- /**************************************************************************************************
- * CNC_Init -- Initialize the .DLL
- *
- * In: Command line
- *
- * Out:
- *
- *
- *
- * History: 1/3/2019 11:33AM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Init(const char *command_line, CNC_Event_Callback_Type event_callback)
- {
- DLLExportClass::Set_Content_Directory(NULL);
-
- DLL_Startup(command_line);
- DLLExportClass::Set_Event_Callback( event_callback );
- DLLExportClass::Init();
- }
- /**************************************************************************************************
- * DLL_Shutdown -- Shutdown the .DLL
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/20/2020 1:58PM - ST
- **************************************************************************************************/
- void DLL_Shutdown(void)
- {
- DLLExportClass::Shutdown();
- }
- /**************************************************************************************************
- * CNC_Config -- Configure the plugin
- *
- * In: Configuration data
- *
- * Out:
- *
- *
- *
- * History: 10/03/2019 - SKY
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Config(const CNCRulesDataStruct& rules)
- {
- DLLExportClass::Config(rules);
- }
- /**************************************************************************************************
- * CNC_Add_Mod_Path -- Add a path to load mod files from
- *
- * In: Path to load mods from
- *
- * Out:
- *
- *
- *
- * History: 2/20/2020 2:04PM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Add_Mod_Path(const char *mod_path)
- {
- DLLExportClass::Add_Mod_Path(mod_path);
- }
- /**************************************************************************************************
- * CNC_Get_Visible_Page -- Get the screen buffer 'SeenBuff' from the game
- *
- * In: If buffer_in is null, just return info about page
- *
- * Out: false if not changed since last call
- *
- *
- *
- * History: 1/3/2019 11:33AM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Visible_Page(unsigned char *buffer_in, unsigned int &width, unsigned int &height)
- {
- if (!DLLExportClass::Legacy_Render_Enabled() || (buffer_in == NULL)) {
- return false;
- }
- /*
- ** Assume the seen page viewport is the same size as the page
- */
- GraphicBufferClass *gbuffer = HidPage.Get_Graphic_Buffer();
- if (gbuffer == NULL) {
- return false;
- }
- int view_port_width = Map.MapCellWidth * CELL_PIXEL_W;
- int view_port_height = Map.MapCellHeight * CELL_PIXEL_H;
- if (view_port_width == 0 || view_port_height == 0) {
- return false;
- }
- unsigned char *raw_buffer = (unsigned char*) gbuffer->Get_Buffer();
- long raw_size = gbuffer->Get_Size();
- if (raw_buffer == NULL || gbuffer->Get_Width() < view_port_width || gbuffer->Get_Height() < view_port_height) {
- return false;
- }
- width = view_port_width;
- height = view_port_height;
- int pitch = gbuffer->Get_Width();
- for (int i = 0; i < view_port_height; ++i, buffer_in += view_port_width, raw_buffer += pitch) {
- memcpy(buffer_in, raw_buffer, view_port_width);
- }
- return true;
- }
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Palette(unsigned char(&palette_in)[256][3])
- {
- memcpy(palette_in, CurrentPalette, sizeof(palette_in));
- return true;
- }
- /**************************************************************************************************
- * CNC_Set_Multiplayer_Data -- Set up for a multiplayer match
- *
- * In: Multiplayer data
- *
- * Out: false if data is bad
- *
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- 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)
- {
-
- if (num_players <= 0) {
- return false;
- }
-
- if (num_players > min(MAX_PLAYERS, max_players)) {
- return false;
- }
- DLLExportClass::Init();
- Session.Options.Bases = game_options.MPlayerBases; // 1 = bases are on for this scenario
- Session.Options.Credits = game_options.MPlayerCredits; // # credits everyone gets
- Session.Options.Tiberium = game_options.MPlayerTiberium; // 1 = tiberium enabled for this scenario
- Session.Options.Goodies = game_options.MPlayerGoodies; // 1 = goodies enabled for this scenario
- Session.Options.Ghosts = game_options.MPlayerGhosts; // 1 = houses with no players will still play
- //MPlayerSolo = game_options.MPlayerSolo; // 1 = allows a single-player net game
- Session.Options.UnitCount = game_options.MPlayerUnitCount; // # units for non-base multiplayer scenarios
- Special.IsShadowGrow = game_options.MPlayerShadowRegrow;
- Special.IsCaptureTheFlag = game_options.CaptureTheFlag;
- if (Session.Options.Tiberium) {
- Special.IsTGrowth = 1;
- Special.IsTSpread = 1;
- } else {
- Special.IsTGrowth = 0;
- Special.IsTSpread = 0;
- }
- Session.Options.ScenarioIndex = scenario_index;
- Special.IsMCVDeploy = game_options.IsMCVDeploy;
- Special.UseMCVDeploy = true;
- MPSuperWeaponDisable = !game_options.EnableSuperweapons; // Are superweapons available
- //Session.Options.AIPlayers = WWGetPrivateProfileInt("Options", "AI", 0, buffer); //Number of AI players
- Special.IsEarlyWin = game_options.DestroyStructures;
- Special.ModernBalance = game_options.ModernBalance;
- /*
- ** Enable Counterstrike/Aftermath units
- */
- OverrideNewUnitsEnabled = game_options.MPlayerAftermathUnits;
- while (Session.Players.Count() > 0) {
- delete Session.Players[0];
- Session.Players.Delete(Session.Players[0]);
- }
-
- for (int i=0 ; i<num_players ; i++) {
- CNCPlayerInfoStruct &player_info = player_list[i];
- NodeNameType *who = new NodeNameType;
- strncpy(who->Name, player_info.Name, MPLAYER_NAME_MAX);
- who->Name[MPLAYER_NAME_MAX - 1] = 0; // Make sure it's terminated
- who->Player.House = (HousesType)player_info.House;
- who->Player.Color = (PlayerColorType) player_info.ColorIndex;
- Session.Players.Add (who);
- /*
- ** Player IDs are done differently in Red Alert vs. TD.
- ** In TD, the ID is created from the house/color combination
- ** In RA, the ID is HOUSE_MULTI1 + the index into the Session.Players vector
- */
- DLLExportClass::GlyphxPlayerIDs[i] = player_info.GlyphxPlayerID;
- MPlayerIsHuman[i] = !player_info.IsAI;
- MPlayerTeamIDs[i] = player_info.Team;
- MPlayerStartLocations[i] = player_info.StartLocationIndex;
- /*
- ** Temp fix for custom maps that don't have valid start positions set from matchmaking
- */
- if (i > 0 && MPlayerStartLocations[i] == 0 && MPlayerStartLocations[0] == 0) {
- MPlayerStartLocations[i] = i;
- }
- }
- /*
- ** Force smart defense always on for multiplayer/skirmish
- */
- Rule.IsSmartDefense = true;
- /*
- ** Backup special
- */
- if (SpecialBackup != NULL) {
- memcpy(SpecialBackup, &Special, sizeof(SpecialClass));
- }
- return true;
- }
- extern "C" __declspec(dllexport) bool __cdecl CNC_Clear_Object_Selection(uint64 player_id)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- Unselect_All();
- return true;
- }
- extern "C" __declspec(dllexport) bool __cdecl CNC_Select_Object(uint64 player_id, int object_type_id, int object_to_select_id)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- switch (object_type_id)
- {
- case INFANTRY:
- {
- for (int index = 0; index < Infantry.Count(); index++) {
- InfantryClass * obj = Infantry.Ptr(index);
- if (obj
- && !obj->IsInLimbo
- && obj->House->IsPlayerControl
- && Infantry.ID((InfantryClass*)obj) == object_to_select_id)
- {
- if (!obj->Is_Selected_By_Player())
- {
- obj->Select();
- AllowVoice = false;
- }
- return true;
- }
- }
- }
- break;
- case UNIT:
- {
- for (int index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj
- && !obj->IsInLimbo
- && obj->House->IsPlayerControl
- && Units.ID((UnitClass*)obj) == object_to_select_id)
- {
- if (!obj->Is_Selected_By_Player())
- {
- obj->Select();
- AllowVoice = false;
- }
- return true;
- }
- }
- }
- break;
- case AIRCRAFT:
- {
- for (int index = 0; index < Aircraft.Count(); index++) {
- AircraftClass * obj = Aircraft.Ptr(index);
- if (obj
- && !obj->IsInLimbo
- && obj->House->IsPlayerControl
- && Aircraft.ID((AircraftClass*)obj) == object_to_select_id)
- {
- if (!obj->Is_Selected_By_Player())
- {
- obj->Select();
- AllowVoice = false;
- }
- return true;
- }
- }
- }
- break;
- case BUILDING:
- {
- for (int index = 0; index < Buildings.Count(); index++) {
- BuildingClass * obj = Buildings.Ptr(index);
- if (obj
- && !obj->IsInLimbo
- && obj->House->IsPlayerControl
- && Buildings.ID((BuildingClass*)obj) == object_to_select_id)
- {
- if (!obj->Is_Selected_By_Player())
- {
- obj->Select();
- AllowVoice = false;
- }
- return true;
- }
- }
- }
- break;
- case VESSEL:
- {
- for (int index = 0; index < Vessels.Count(); index++) {
- VesselClass * obj = Vessels.Ptr(index);
- if (obj
- && !obj->IsInLimbo
- && obj->House->IsPlayerControl
- && Vessels.ID((VesselClass*)obj) == object_to_select_id)
- {
- if (!obj->Is_Selected_By_Player())
- {
- obj->Select();
- AllowVoice = false;
- }
- return true;
- }
- }
- }
- break;
- }
- return false;
- }
- /**************************************************************************************************
- * GlyphX_Assign_Houses -- Replacement for Assign_Houses in INI.CPP / SCNEARIO.CPP
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 8/8/2019 12:37PM - ST
- **************************************************************************************************/
- void GlyphX_Assign_Houses(void)
- {
- /*
- ** RA version
- */
- extern int _build_tech[11];
- int assigned[MAX_PLAYERS];
- bool preassigned;
- int i,j,random_start_location;
- HousesType house, house2;
- HouseClass * housep, *housep2;
- int lowest_color;
- int index;
- srand(timeGetTime());
- /*
- ** Use pre-selected start locations as long as at least one has been defined, otherwise let the original code
- ** in SCENARIO.CPP figure it out
- */
- UseGlyphXStartLocations = false;
- /*
- ** Assign random start positions if needed.
- */
- int random_start_locations[26];
- int num_start_locations = 0;
- int num_random_start_locations = 0;
- for (i = 0; i < 26; i++) {
- if (Scen.Waypoint[i] != -1) {
- preassigned = false;
- for (j = 0; !preassigned && (j < Session.Players.Count()); j++) {
- if (MPlayerStartLocations[j] == num_start_locations) {
- preassigned = true;
- UseGlyphXStartLocations = true;
- }
- }
- if (!preassigned && i < MAX_PLAYERS) {
- random_start_locations[num_random_start_locations] = num_start_locations;
- num_random_start_locations++;
- }
- num_start_locations++;
- }
- }
- if (num_random_start_locations > 1) {
- for (i = 0; i < num_random_start_locations - 1; i++) {
- j = i + rand() / (RAND_MAX / (num_random_start_locations - i) + 1);
- int t = random_start_locations[j];
- random_start_locations[j] = random_start_locations[i];
- random_start_locations[i] = t;
- }
- }
- //------------------------------------------------------------------------
- // Initialize
- //------------------------------------------------------------------------
- for (i = 0; i < MAX_PLAYERS; i++) {
- assigned[i] = 0;
- }
- random_start_location = 0;
- // debugprint( "Assign_Houses()\n" );
- //------------------------------------------------------------------------
- // Assign each player in 'Players' to a multiplayer house. Players will
- // be sorted by their chosen color value (this value must be unique among
- // all the players).
- //------------------------------------------------------------------------
- for (i = 0; i < Session.Players.Count(); i++) {
- //.....................................................................
- // Find the player with the lowest color index
- //.....................................................................
- index = 0;
- lowest_color = 255;
- for (j = 0; j < Session.Players.Count(); j++) {
- //..................................................................
- // If we've already assigned this house, skip it.
- //..................................................................
- if (assigned[j]) {
- continue;
- }
- if (Session.Players[j]->Player.Color < lowest_color) {
- lowest_color = Session.Players[j]->Player.Color;
- index = j;
- }
- }
- //.....................................................................
- // Mark this player as having been assigned.
- //.....................................................................
- assigned[index] = 1;
- //.....................................................................
- // Assign the lowest-color'd player to the next available slot in the
- // HouseClass array.
- //.....................................................................
- house = (HousesType)(i + HOUSE_MULTI1);
- housep = HouseClass::As_Pointer(house);
- memset((char *)housep->IniName, 0, MPLAYER_NAME_MAX);
- strncpy((char *)housep->IniName, Session.Players[index]->Name, MPLAYER_NAME_MAX - 1);
- #ifdef WOLAPI_INTEGRATION
- // Make another copy of name, permanent throughout entire game.
- strncpy((char *)housep->InitialName, Session.Players[index]->Name, MPLAYER_NAME_MAX - 1);
- #endif
- housep->IsHuman = MPlayerIsHuman[index];
- housep->IsPlayerControl = housep->IsHuman;
- if (!housep->IsHuman) {
- housep->IsStarted = true;
- strncpy(housep->IniName, Text_String(TXT_COMPUTER), HOUSE_NAME_MAX);
- housep->IQ = Rule.MaxIQ;
- //housep->Control.TechLevel = _build_tech[BuildLevel];
- } else {
- housep->IQ = 0;
- }
- housep->Init_Data((PlayerColorType)(Session.Players[index]->Player.Color),
- Session.Players[index]->Player.House, Session.Options.Credits);
- /*
- ** Set the start location override
- */
- if (MPlayerStartLocations[index] != RANDOM_START_POSITION) {
- housep->StartLocationOverride = MPlayerStartLocations[index];
- } else {
- if (random_start_location < num_random_start_locations) {
- housep->StartLocationOverride = random_start_locations[random_start_location++];
- } else {
- housep->StartLocationOverride = -1;
- }
- }
- if (index == 0) {
- PlayerPtr = housep;
- }
- /*
- ** Convert the build level into an actual tech level to assign to the house.
- ** There isn't a one-to-one correspondence.
- */
- housep->Control.TechLevel = _build_tech[BuildLevel];
- housep->Assign_Handicap(Scen.Difficulty);
- //.....................................................................
- // Record where we placed this player
- //.....................................................................
- Session.Players[index]->Player.ID = house;
- // debugprint( "Assigned ID of %i to %s\n", house, Session.Players[index]->Name );
- }
- for (i = Session.Players.Count(); i < Rule.MaxPlayers; i++) {
- house = (HousesType)(i + HOUSE_MULTI1);
- housep = HouseClass::As_Pointer(house);
- if (housep != NULL) {
- housep->IsDefeated = true;
- }
- }
- for (i = 0; i < Session.Players.Count(); i++) {
-
- house = Session.Players[i]->Player.ID;
- housep = HouseClass::As_Pointer(house);
- if (housep) {
- int team = MPlayerTeamIDs[i];
- for (int j=0 ; j < Session.Players.Count(); j++) {
-
- if (i != j) {
- if (team == MPlayerTeamIDs[j]) {
-
- house2 = Session.Players[j]->Player.ID;
- housep2 = HouseClass::As_Pointer(house2);
- if (housep2) {
- housep->Make_Ally(house2);
- }
- }
- }
- }
- }
- }
- }
- /**************************************************************************************************
- * CNC_Set_Home_Cell -- Allows overriding the start position for the camera
- *
- *
- * History: 2/14/2020 - LLL
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Set_Home_Cell(int x, int y, uint64 player_id)
- {
- DLLExportClass::Set_Home_Cell(x, y, player_id);
- }
- /**************************************************************************************************
- * CNC_Start_Instance -- Load and start a cnc map -> WITHOUT SPECIFYING A SCENARIO VARIATION (SCEN_VAR)
- *
- * In: Map initialization parameters
- *
- * Out: false if map load failed
- *
- *
- *
- * History: 7/10/2019 - LLL
- **************************************************************************************************/
- 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)
- {
- 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);
- }
- /**************************************************************************************************
- * CNC_Start_Instance -- Load and start a cnc map
- *
- * In: Map initialization parameters
- *
- * Out: false if map load failed
- *
- *
- * Renamed and modified to accept a scenario variation 7/10/2019 - LLL
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- 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)
- {
- if (game_type == NULL) {
- return false;
- }
- if (faction == NULL) {
- return false;
- }
- if (content_directory == NULL) {
- return false;
- }
- ScenarioPlayerType scen_player = SCEN_PLAYER_NONE;
- if (stricmp(faction, "SPAIN") == 0) {
- scen_player = SCEN_PLAYER_SPAIN;
- Whom = HOUSE_GOOD;
- }
-
- if (stricmp(faction, "GREECE") == 0 || stricmp(faction, "ALLY") == 0) {
- scen_player = SCEN_PLAYER_GREECE;
- Whom = HOUSE_GOOD;
- }
- if (stricmp(faction, "USSR") == 0) {
- scen_player = SCEN_PLAYER_USSR;
- Whom = HOUSE_BAD;
- }
- DLLExportClass::Set_Content_Directory(content_directory);
- BuildLevel = build_level;
- Scen.Scenario = scenario_index;
- ScenarioDirType scen_dir = (ScenarioDirType)scenario_direction;
- if (stricmp(game_type, "GAME_NORMAL") == 0) {
- GAME_TO_PLAY = GAME_NORMAL;
- if (scen_player == SCEN_PLAYER_NONE) {
- return false;
- }
- } else {
- if (stricmp(game_type, "GAME_GLYPHX_MULTIPLAYER") == 0) {
- GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER;
- scen_player = SCEN_PLAYER_MPLAYER;
- } else {
- return false;
- }
- }
- /*
- ** Load the scenario. Specify variation 'A' for the editor; for the game,
- ** don't specify a variation, to make 'Set_Scenario_Name()' pick a random one.
- ** Skip this if we've already loaded a save-game.
- */
- Force_CD_Available(ALWAYS_RELOAD_CD);
- if (override_map_name && strlen(override_map_name)) {
- strcpy(Scen.ScenarioName, override_map_name);
- } else {
- Scen.Set_Scenario_Name(Scen.Scenario, scen_player, scen_dir, (ScenarioVarType)scenario_variation);
- }
- HiddenPage.Clear();
- VisiblePage.Clear();
- /*
- ** Set the mouse to some position where it's not going to scroll, or do something else wierd.
- */
- DLLForceMouseX = 100;
- DLLForceMouseY = 100;
- KEYBOARD->MouseQX = 100;
- KEYBOARD->MouseQY = 100;
- GlyphXClientSidebarWidthInLeptons = 0;
- Seed = GetRandSeed();
- Scen.RandomNumber = Seed;
- if (!Start_Scenario(Scen.ScenarioName)) {
- return(false);
- }
- DLLExportClass::Reset_Sidebars();
- DLLExportClass::Reset_Player_Context();
- DLLExportClass::Calculate_Start_Positions();
- /*
- ** Make sure the scroll constraints are applied. This is important for GDI 1 where the map isn't wide enough for the screen
- */
- COORDINATE origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(1, 0));
- Map.Set_Tactical_Position(origin_coord);
- origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(-1, 0));
- Map.Set_Tactical_Position(origin_coord);
- if (GAME_TO_PLAY == GAME_NORMAL) {
- MPSuperWeaponDisable = false;
- } else {
- if (MPSuperWeaponDisable) {
- /*
- ** Write over the tecb level settings we just loaded from the Rules ini
- */
- Rule.GPSTechLevel = 100;
- Rule.ParaInfantryTechLevel = 100;
- Rule.SpyPlaneTechLevel = 100;
- Rule.ParaBombTechLevel = 100;
- Rule.ChronoTechLevel = 100;
- }
- }
- /*
- ** Hide the SeenBuff; force the map to render one frame. The caller can
- ** then fade the palette in.
- ** (If we loaded a game, this step will fade out the title screen. If we
- ** started a scenario, Start_Scenario() will have played a couple of VQ
- ** movies, which will have cleared the screen to black already.)
- */
- //Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back);
- HiddenPage.Clear();
- VisiblePage.Clear();
- Set_Logic_Page(SeenBuff);
-
- /*
- ** Sidebar is always active in hi-res.
- */
- if (!Debug_Map) {
- Map.SidebarClass::Activate(1);
- }
-
- Map.Flag_To_Redraw(true);
- Set_Palette(GamePalette.Get_Data());
- Map.Render();
- Set_Palette(GamePalette.Get_Data());
-
- return true;
- }
- /**************************************************************************************************
- * CNC_Read_INI -- Load an ini file into the supplied buffer
- *
- * In: Map initialization parameters
- *
- * Out: false if ini load failed
- *
- *
- * History: 12/16/2019 11:44AM - ST
- **************************************************************************************************/
- 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)
- {
- if (content_directory == NULL) {
- return false;
- }
- DLLExportClass::Set_Content_Directory(content_directory);
- Scen.Scenario = scenario_index;
- ScenarioDirType scen_dir = (ScenarioDirType)scenario_direction;
-
- GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER;
- ScenarioPlayerType scen_player = SCEN_PLAYER_MPLAYER;
- Force_CD_Available(ALWAYS_RELOAD_CD);
- if (override_map_name && strlen(override_map_name)) {
- strcpy(Scen.ScenarioName, override_map_name);
- } else {
- Scen.Set_Scenario_Name(Scen.Scenario, scen_player, scen_dir, (ScenarioVarType)scenario_variation);
- }
- if (_ini_buffer_size < _ShapeBufferSize) {
- GlyphX_Debug_Print("INI file buffer may be too small");
- return false;
- }
- if (!ini_buffer) {
- GlyphX_Debug_Print("No INI file buffer");
- return false;
- }
- memset(ini_buffer, _ini_buffer_size, 0);
- CCFileClass file(Scen.ScenarioName);
- if (!file.Is_Available()) {
- GlyphX_Debug_Print("Failed to find scenario file");
- GlyphX_Debug_Print(Scen.ScenarioName);
- return(false);
- } else {
-
- GlyphX_Debug_Print("Opened scenario file");
- GlyphX_Debug_Print(Scen.ScenarioName);
-
- int bytes_read = file.Read(ini_buffer, _ini_buffer_size-1);
- if (bytes_read == _ini_buffer_size - 1) {
- GlyphX_Debug_Print("INI file buffer is too small");
- return false;
- }
- }
- /*
- ** Ini buffer should be zero terminated
- */
- if ((int) strlen(ini_buffer) >= _ini_buffer_size) {
- GlyphX_Debug_Print("INI file buffer overrun");
- return false;
- }
- return true;
- }
- /**************************************************************************************************
- * CNC_Start_Custom_Instance -- Load and start a custom map
- *
- * In: Map initialization parameters
- *
- * Out: false if map load failed
- *
- *
- *
- * History: 2019/10/28 - JAS
- **************************************************************************************************/
- 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)
- {
- DLLExportClass::Set_Content_Directory(content_directory);
- char fullname[_MAX_FNAME + _MAX_EXT];
- snprintf(fullname, _MAX_FNAME + _MAX_EXT, "%s%s.mpr", directory_path, scenario_name);
- char name_buffer[128];
- char digest_buffer[32];
- CCFileClass file(fullname);
- INIClass ini;
- ini.Load(file);
- ini.Get_String("Basic", "Name", "No Name", name_buffer, sizeof(name_buffer));
- ini.Get_String("Digest", "1", "No Digest", digest_buffer, sizeof(digest_buffer));
- Session.Scenarios.Add(new MultiMission(fullname, name_buffer, digest_buffer, ini.Get_Bool("Basic", "Official", false), false));
- BuildLevel = build_level;
- ScenarioPlayerType scen_player;
- strncpy(Scen.ScenarioName, fullname, _MAX_FNAME + _MAX_EXT);
- if (multiplayer) {
- GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER;
- } else {
- GAME_TO_PLAY = GAME_NORMAL;
- }
- scen_player = SCEN_PLAYER_MPLAYER;
- //Scen.Scenario = scenario_index;
- //ScenarioDirType scen_dir = (ScenarioDirType)scenario_direction;
- //if (stricmp(game_type, "GAME_NORMAL") == 0) {
- // GAME_TO_PLAY = GAME_NORMAL;
- //}
- //else {
- // if (stricmp(game_type, "GAME_GLYPHX_MULTIPLAYER") == 0) {
- // GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER;
- // scen_player = SCEN_PLAYER_MPLAYER;
- // }
- // else {
- // return false;
- // }
- //}
- ///*
- //** Load the scenario. Specify variation 'A' for the editor; for the game,
- //** don't specify a variation, to make 'Set_Scenario_Name()' pick a random one.
- //** Skip this if we've already loaded a save-game.
- //*/
- //Force_CD_Available(ALWAYS_RELOAD_CD);
- //if (override_map_name && strlen(override_map_name)) {
- // strcpy(Scen.ScenarioName, override_map_name);
- //}
- //else {
- // Scen.Set_Scenario_Name(Scen.Scenario, scen_player, scen_dir, (ScenarioVarType)scenario_variation);
- //}
- HiddenPage.Clear();
- VisiblePage.Clear();
- /*
- ** Set the mouse to some position where it's not going to scroll, or do something else wierd.
- */
- DLLForceMouseX = 100;
- DLLForceMouseY = 100;
- KEYBOARD->MouseQX = 100;
- KEYBOARD->MouseQY = 100;
- GlyphXClientSidebarWidthInLeptons = 0;
- Seed = GetRandSeed();
- Scen.RandomNumber = Seed;
- if (!Start_Scenario(Scen.ScenarioName)) {
- return(false);
- }
- DLLExportClass::Reset_Sidebars();
- DLLExportClass::Reset_Player_Context();
- DLLExportClass::Calculate_Start_Positions();
- /*
- ** Make sure the scroll constraints are applied. This is important for GDI 1 where the map isn't wide enough for the screen
- */
- COORDINATE origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(1, 0));
- Map.Set_Tactical_Position(origin_coord);
- origin_coord = Coord_Add(Map.TacticalCoord, XY_Coord(-1, 0));
- Map.Set_Tactical_Position(origin_coord);
- if (GAME_TO_PLAY == GAME_NORMAL) {
- MPSuperWeaponDisable = false;
- }
- else {
- if (MPSuperWeaponDisable) {
- /*
- ** Write over the tecb level settings we just loaded from the Rules ini
- */
- Rule.GPSTechLevel = 100;
- Rule.ParaInfantryTechLevel = 100;
- Rule.SpyPlaneTechLevel = 100;
- Rule.ParaBombTechLevel = 100;
- Rule.ChronoTechLevel = 100;
- }
- }
- /*
- ** Hide the SeenBuff; force the map to render one frame. The caller can
- ** then fade the palette in.
- ** (If we loaded a game, this step will fade out the title screen. If we
- ** started a scenario, Start_Scenario() will have played a couple of VQ
- ** movies, which will have cleared the screen to black already.)
- */
- //Fade_Palette_To(BlackPalette, FADE_PALETTE_MEDIUM, Call_Back);
- HiddenPage.Clear();
- VisiblePage.Clear();
- Set_Logic_Page(SeenBuff);
- /*
- ** Sidebar is always active in hi-res.
- */
- if (!Debug_Map) {
- Map.SidebarClass::Activate(1);
- }
- Map.Flag_To_Redraw(true);
- Set_Palette(GamePalette.Get_Data());
- Map.Render();
- Set_Palette(GamePalette.Get_Data());
- return true;
- }
- bool Debug_Write_Shape_Type(const ObjectTypeClass *type, int shapenum)
- {
- char fullname[_MAX_FNAME+_MAX_EXT];
- char buffer[_MAX_FNAME];
- CCFileClass file;
- if (type->ImageData != NULL) {
- sprintf(buffer, "%s_%d", type->IniName, shapenum);
- _makepath(fullname, NULL, NULL, buffer, ".PCX");
- return Debug_Write_Shape(fullname, type->ImageData, shapenum);
- }
- return false;
- }
- bool Debug_Write_Shape(const char *file_name, void const * shapefile, int shapenum, int flags, void const * ghostdata)
- {
- /*
- ** Build frame returns a pointer now instead of the shapes length
- */
- char *shape_pointer = (char*) Build_Frame(shapefile , shapenum , _ShapeBuffer);
- if (shape_pointer == NULL) {
- return false;;
- }
- if (Get_Last_Frame_Length() > _ShapeBufferSize) {
- return false;;
- }
- int width = Get_Build_Frame_Width(shapefile);
- int height = Get_Build_Frame_Height(shapefile);
- GraphicBufferClass temp_gbuffer(width, height);
- GraphicViewPortClass temp_viewport(&temp_gbuffer, 0, 0, width, height);
- WindowList[WINDOW_CUSTOM][WINDOWX] = 0;
- WindowList[WINDOW_CUSTOM][WINDOWY] = 0;
- WindowList[WINDOW_CUSTOM][WINDOWWIDTH] = width;
- WindowList[WINDOW_CUSTOM][WINDOWHEIGHT] = height;
- static const char _shape_trans = 0x40;
- if (flags == 0) {
- Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, SHAPE_NORMAL|SHAPE_WIN_REL|_shape_trans); //, ghostdata, predoffset);
- } else {
- Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, flags, ghostdata);
- }
- Write_PCX_File((char*)file_name, temp_viewport, (unsigned char*)GamePalette.Get_Data());
- return true;
- }
- /**************************************************************************************************
- * CNC_Advance_Instance -- Process one logic frame
- *
- * In:
- *
- * Out: Is game still playing?
- *
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) bool __cdecl CNC_Advance_Instance(uint64 player_id)
- {
- //DLLExportClass::Set_Event_Callback(event_callback);
- if (Frame <= 10) { // Don't spam forever, but useful to know that we actually started advancing
- GlyphX_Debug_Print("CNC_Advance_Instance - RA");
- }
- /*
- ** 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.
- ** Might make tbe bugs more repeatable and consistent. ST - 3/15/2019 11:58AM
- */
- if (player_id != 0) {
- DLLExportClass::Set_Player_Context(player_id);
- } else {
- DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0]);
- }
- /*
- ** Restore special from backup
- */
- if (SpecialBackup != NULL) {
- memcpy(&Special, SpecialBackup, sizeof(SpecialClass));
- }
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- TimeQuake = PendingTimeQuake;
- PendingTimeQuake = false;
- #else
- TimeQuake = false;
- #endif
-
- /*
- ** Allocate extra memory for uncompressed shapes as needed
- */
- Reallocate_Big_Shape_Buffer();
- /*
- ** If there is no theme playing, but it looks like one is required, then start one
- ** playing. This is usually the symptom of there being no transition score.
- */
- //if (SampleType && Theme.What_Is_Playing() == THEME_NONE) {
- // Theme.Queue_Song(THEME_PICK_ANOTHER);
- //}
- /*
- ** Update the display, unless we're inside a dialog.
- */
- //if (SpecialDialog == SDLG_NONE && GameInFocus) {
- //WWMouse->Erase_Mouse(&HidPage, TRUE);
- //Map.Input(input, x, y);
- //if (input) {
- // Keyboard_Process(input);
- //}
- /*
- ** The main loop passes these in uninitialized. ST - 2/7/2019 4:36PM
- */
- KeyNumType input = KN_NONE; // Player input.
- int x = 0;
- int y = 0;
- Map.Input(input, x, y);
- //if (input) {
- // Keyboard_Process(input);
- //}
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- /*
- ** Process the sidebar. ST - 4/18/2019 11:59AM
- */
- HouseClass *old_player_ptr = PlayerPtr;
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- DLLExportClass::Logic_Switch_Player_Context(player_ptr);
- Sidebar_Glyphx_AI(player_ptr, input);
- }
- DLLExportClass::Logic_Switch_Player_Context(old_player_ptr);
- }
- //}
- /*
- ** Sort the map's ground layer by y-coordinate value. This is done
- ** outside the IsToRedraw check, for the purposes of game sync'ing
- ** between machines; this way, all machines will sort the Map's
- ** layer in the same way, and any processing done that's based on
- ** the order of this layer will sync on different machines.
- */
- Map.Layer[LAYER_GROUND].Sort();
- /*
- ** AI logic operations are performed here.
- */
- //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
- static bool FirstUpdate = GAME_TO_PLAY != GAME_GLYPHX_MULTIPLAYER;;
- if (!FirstUpdate) {
- HouseClass *old_player_ptr = PlayerPtr;
- Logic.Clear_Recently_Created_Bits();
- Logic.AI();
- DLLExportClass::Logic_Switch_Player_Context(old_player_ptr);
- }
- FirstUpdate = false;
- TimeQuake = false;
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- if (!PendingTimeQuake) {
- TimeQuakeCenter = 0;
- }
- #endif
- /*
- ** Manage the inter-player message list. If Manage() returns true, it means
- ** a message has expired & been removed, and the entire map must be updated.
- */
- if (Session.Messages.Manage()) {
- #ifdef WIN32
- HiddenPage.Clear();
- #else //WIN32
- HidPage.Clear();
- #endif //WIN32
- Map.Flag_To_Redraw(true);
- }
- /*
- ** Process all commands that are ready to be processed.
- */
- if (GAME_TO_PLAY == GAME_NORMAL) {
- Queue_AI();
- } else {
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- DLLExportClass::Glyphx_Queue_AI();
- /*
- ** Process the sidebar. ST - 3/22/2019 2:07PM
- */
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- Sidebar_Glyphx_Recalc(player_ptr);
- }
- }
- }
- /*
- ** Keep track of elapsed time in the game.
- */
- //Score.ElapsedTime += TIMER_SECOND / TICKS_PER_SECOND;
- /*
- ** Perform any win/lose code as indicated by the global control flags.
- */
- /*
- ** Check for player wins or loses according to global event flag.
- */
- if (PlayerWins) {
- //WWMouse->Erase_Mouse(&HidPage, TRUE);
- PlayerLoses = false;
- PlayerWins = false;
- PlayerRestarts = false;
- Map.Help_Text(TXT_NONE);
- GlyphX_Debug_Print("PlayerWins = true");
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- DLLExportClass::On_Multiplayer_Game_Over();
- } else {
- DLLExportClass::On_Game_Over(player_id, true);
- }
- //DLLExportClass::Set_Event_Callback(NULL);
- return false;
- }
- if (PlayerLoses) {
- //WWMouse->Erase_Mouse(&HidPage, TRUE);
- PlayerWins = false;
- PlayerLoses = false;
- PlayerRestarts = false;
- Map.Help_Text(TXT_NONE);
- GlyphX_Debug_Print("PlayerLoses = true");
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- DLLExportClass::On_Multiplayer_Game_Over();
- } else {
- DLLExportClass::On_Game_Over(player_id, false);
- }
- //DLLExportClass::Set_Event_Callback(NULL);
- return false;
- }
- /*
- ** The frame logic has been completed. Increment the frame
- ** counter.
- */
- Frame++;
- /*
- ** Very rarely, the human players will get a message from the computer.
- **
- ** This was disabled in the RA source code, so copying over the functionality from TD
- */
- if (GAME_TO_PLAY != GAME_NORMAL && Session.Options.Ghosts && IRandom(0,10000) == 1) {
- DLLExportClass::Computer_Message(false);
- }
- if (ProgEndCalled) {
- GlyphX_Debug_Print("ProgEndCalled - GameActive = false");
- GameActive = false;
- }
- if (DLLExportClass::Legacy_Render_Enabled()) {
- Map.Render();
- }
- //Sync_Delay();
- //DLLExportClass::Set_Event_Callback(NULL);
- Color_Cycle();
-
-
- /*
- ** Don't respect GameActive. Game will end in multiplayer on win/loss
- */
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- return true;
- }
- return(GameActive);
- }
- /**************************************************************************************************
- * CNC_Save_Load -- Process a save or load game action
- *
- * In:
- *
- * Out: Success?
- *
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) bool __cdecl CNC_Save_Load(bool save, const char *file_path_and_name, const char *game_type)
- {
- bool result = false;
-
- if (save) {
- result = Save_Game(file_path_and_name, "internal");
- } else {
-
- if (game_type == NULL) {
- return false;
- }
-
- if (stricmp(game_type, "GAME_NORMAL") == 0) {
- GAME_TO_PLAY = GAME_NORMAL;
- } else {
- if (stricmp(game_type, "GAME_GLYPHX_MULTIPLAYER") == 0) {
- GAME_TO_PLAY = GAME_GLYPHX_MULTIPLAYER;
- //ScenPlayer = SCEN_PLAYER_MPLAYER;
- } else {
- return false;
- }
- }
- while (Session.Players.Count() > 0) {
- delete Session.Players[0];
- Session.Players.Delete(Session.Players[0]);
- }
-
- result = Load_Game(file_path_and_name);
- if (result == false)
- {
- return false;
- }
-
- DLLExportClass::Set_Player_Context(DLLExportClass::GlyphxPlayerIDs[0], true);
- DLLExportClass::Cancel_Placement(DLLExportClass::GlyphxPlayerIDs[0], -1, -1);
- Set_Logic_Page(SeenBuff);
- VisiblePage.Clear();
- Map.Flag_To_Redraw(true);
- if (DLLExportClass::Legacy_Render_Enabled()) {
- Map.Render();
- }
- Set_Palette(GamePalette.Get_Data());
- }
- return result;
- }
- /**************************************************************************************************
- * CNC_Set_Difficulty -- Set game difficulty
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 10/02/2019 - SKY
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Set_Difficulty(int difficulty)
- {
- if (GAME_TO_PLAY == GAME_NORMAL) {
- Set_Scenario_Difficulty(difficulty);
- }
- }
- /**************************************************************************************************
- * CNC_Restore_Carryover_Objects
- *
- * History: 11/15/2019 - LLL
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Restore_Carryover_Objects(const CarryoverObjectStruct* objects)
- {
- //Delete the list
- while (Carryover) {
- CarryoverClass* cptr = (CarryoverClass*)Carryover->Get_Next();
- delete Carryover;
- Carryover = cptr;
- }
- //Populate the list
- const CarryoverObjectStruct* next_object = objects;
- while (next_object) {
- CarryoverClass* cptr = new CarryoverClass();
- cptr->RTTI = (RTTIType)next_object->RTTI;
- 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
- cptr->Cell = (CELL)next_object->Cell;
- cptr->House = (HousesType)next_object->House;
- cptr->Strength = next_object->Strength;
- next_object = next_object->Next;
- if (Carryover == NULL) {
- Carryover = cptr;
- }
- else {
- cptr->Add_Tail(*Carryover);
- }
- }
- }
- /**************************************************************************************************
- * CNC_Handle_Player_Switch_To_AI -- Renamed 3/9/2020 - LLL
- * CNC_Handle_Player_Disconnect -- Handle player disconnected during multiplayer game
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 12/3/2019 1:46PM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Player_Switch_To_AI(uint64 player_id)
- {
- if (PlayerWins || PlayerLoses || DLLExportClass::Get_Game_Over()) {
- return;
- }
- GlyphX_Debug_Print("CNC_Handle_Player_Switch_To_AI");
-
- if (GAME_TO_PLAY == GAME_NORMAL) {
- return;
- }
- #ifdef KILL_PLAYER_ON_DISCONNECT
- /*
- ** Kill player's units on disconnect.
- */
- if (player_id != 0) {
- DLLExportClass::Set_Player_Context(player_id);
- if (PlayerPtr) {
- PlayerPtr->Flag_To_Die();
- }
- }
- #else //KILL_PLAYER_ON_DISCONNECT
- if (player_id != 0) {
-
- HousesType house;
- HouseClass *ptr;
-
- DLLExportClass::Set_Player_Context(player_id);
- if (PlayerPtr) {
- PlayerPtr->WasHuman = true;
- PlayerPtr->IsHuman = false;
- PlayerPtr->IQ = Rule.MaxIQ;
- strcpy (PlayerPtr->IniName, Text_String(TXT_COMPUTER));
- PlayerPtr->IsBaseBuilding = true;
- /*
- ** Start the unload mission for MCVs
- */
- for (int index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr) {
- if (*obj == UNIT_MCV) {
- obj->Assign_Mission(MISSION_GUARD);
- obj->Assign_Target(TARGET_NONE);
- obj->Assign_Destination(TARGET_NONE);
- obj->Assign_Mission(MISSION_UNLOAD);
- obj->Commence();
- }
- }
- }
- DLLExportClass::On_Message(PlayerPtr, "", 60.0f, MESSAGE_TYPE_PLAYER_DISCONNECTED, -1);
- /*
- ** Send the disconnect taunt message
- */
- int human_count = 0;
- for (house = HOUSE_MULTI1; house < (HOUSE_MULTI1 + MULTIPLAYER_COUNT); house++) {
- ptr = HouseClass::As_Pointer(house);
- if (ptr && ptr->IsHuman && !ptr->IsDefeated) {
- human_count++;
- }
- }
- if (human_count == 1) {
- DLLExportClass::Computer_Message(true);
- }
- }
- }
- #endif //KILL_PLAYER_ON_DISCONNECT
- }
- /**************************************************************************************************
- * CNC_Handle_Human_Team_Wins
- *
- * History: 3/10/2020 - LLL
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Human_Team_Wins(uint64 quitting_player_id)
- {
- GlyphX_Debug_Print("CNC_Handle_Human_Team_Wins");
- DLLExportClass::Force_Human_Team_Wins(quitting_player_id);
- }
- /**************************************************************************************************
- * CNC_Start_Mission_Timer
- *
- * History: 11/25/2019 - LLL
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Start_Mission_Timer(int time)
- {
- if (GameActive)
- {
- Scen.MissionTimer = time;
- if (!Scen.MissionTimer.Is_Active()) {
- Scen.MissionTimer.Start();
- }
- Map.Redraw_Tab();
- }
- }
- /**************************************************************************************************
- * CNC_Get_Start_Game_Info
- *
- * History: 8/31/2020 11:37AM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Start_Game_Info(uint64 player_id, int &start_location_waypoint_index)
- {
- start_location_waypoint_index = 0;
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
-
- start_location_waypoint_index = PlayerPtr->StartLocationOverride;
- return true;
- }
- /**************************************************************************************************
- * Is_Legacy_Render_Enabled -- Is the legacy rendering enabled?
- *
- * In:
- *
- * Out: True if only one human player
- *
- *
- *
- * History: 8/25/2020 5:55PM - ST
- **************************************************************************************************/
- bool Is_Legacy_Render_Enabled(void)
- {
- return DLLExportClass::Legacy_Render_Enabled();
- }
- /**************************************************************************************************
- * DLLExportClass::Init -- Init the class
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/12/2019 10:52AM - ST
- **************************************************************************************************/
- void DLLExportClass::Init(void)
- {
- for (int i=0 ; i<MAX_PLAYERS ; i++) {
- GlyphxPlayerIDs[i] = 0xffffffffull;
- }
- CurrentLocalPlayerIndex = 0;
- MessagesSent.clear();
- if (SpecialBackup == NULL) {
- SpecialBackup = new SpecialClass;
- }
- memcpy(SpecialBackup, &Special, sizeof(SpecialClass));
- }
- /**************************************************************************************************
- * DLLExportClass::Shutdown -- Shutdown
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/20/2020 1:59PM - ST
- **************************************************************************************************/
- void DLLExportClass::Shutdown(void)
- {
- delete SpecialBackup;
- SpecialBackup = NULL;
- for (int i=0 ; i<ModSearchPaths.Count() ; i++) {
- delete [] ModSearchPaths[i];
- }
- ModSearchPaths.Clear();
- }
- /**************************************************************************************************
- * DLLExportClass::Add_Mod_Path -- Add a path to load mod files from
- *
- * In: Mod path
- *
- * Out:
- *
- *
- *
- * History: 2/20/2020 2:03PM - ST
- **************************************************************************************************/
- void DLLExportClass::Add_Mod_Path(const char *mod_path)
- {
- char *copy_path = strdup(mod_path);
- ModSearchPaths.Add(copy_path);
- }
-
- /**************************************************************************************************
- * DLLExportClass::Set_Content_Directory -- Update the locations that the original code will load from
- *
- * In: Main (official) content directory
- *
- * Out:
- *
- *
- *
- * History: 2/20/2020 2:03PM - ST
- **************************************************************************************************/
- void DLLExportClass::Set_Content_Directory(const char *content_directory)
- {
- CCFileClass::Clear_Search_Drives();
- CCFileClass::Reset_Raw_Path();
- if ((content_directory == NULL || strlen(content_directory) == 0) && ModSearchPaths.Count() == 0) {
- return;
- }
- char *all_paths = new char [_MAX_PATH * 100];
- *all_paths = 0;
- for (int i=0 ; i<ModSearchPaths.Count() ; i++) {
- if (i != 0) {
- strcat(all_paths, ";");
- }
- strcat(all_paths, ModSearchPaths[i]);
- }
- if (ModSearchPaths.Count() && content_directory && strlen(content_directory)) {
- strcat(all_paths, ";");
- }
- if (content_directory) {
- strcat(all_paths, content_directory);
- }
- CCFileClass::Set_Search_Drives(all_paths);
- delete [] all_paths;
- }
- /**************************************************************************************************
- * DLLExportClass::Config
- *
- * History: 1/16/2020 - SKY
- **************************************************************************************************/
- void DLLExportClass::Config(const CNCRulesDataStruct& rules)
- {
- for (int i = 0; i < 3; ++i)
- {
- Rule.Diff[i].FirepowerBias = rules.Difficulties[i].FirepowerBias;
- Rule.Diff[i].GroundspeedBias = rules.Difficulties[i].GroundspeedBias;
- Rule.Diff[i].AirspeedBias = rules.Difficulties[i].AirspeedBias;
- Rule.Diff[i].ArmorBias = rules.Difficulties[i].ArmorBias;
- Rule.Diff[i].ROFBias = rules.Difficulties[i].ROFBias;
- Rule.Diff[i].CostBias = rules.Difficulties[i].CostBias;
- Rule.Diff[i].BuildSpeedBias = rules.Difficulties[i].BuildSpeedBias;
- Rule.Diff[i].RepairDelay = rules.Difficulties[i].RepairDelay;
- Rule.Diff[i].BuildDelay = rules.Difficulties[i].BuildDelay;
- Rule.Diff[i].IsBuildSlowdown = rules.Difficulties[i].IsBuildSlowdown ? 1 : 0;
- Rule.Diff[i].IsWallDestroyer = rules.Difficulties[i].IsWallDestroyer ? 1 : 0;
- Rule.Diff[i].IsContentScan = rules.Difficulties[i].IsContentScan ? 1 : 0;
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Set_Home_Cell
- *
- * History: 2/14/2020 - LLL
- **************************************************************************************************/
- void DLLExportClass::Set_Home_Cell(int x, int y, uint64 player_id)
- {
- if (GAME_TO_PLAY == GAME_NORMAL) {
- MultiplayerStartPositions[0] = XY_Cell(x, y);
- }
- else {
- for (int i = 0; i < MAX_PLAYERS && i < 4; i++) {
- if (GlyphxPlayerIDs[i] == player_id) {
- MultiplayerStartPositions[i] = XY_Cell(x, y);
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::On_Play_Movie
- *
- * History: 7/23/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::On_Play_Movie(const char * movie_name, ThemeType theme, bool immediate)
- {
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_MOVIE;
- new_event.Movie.MovieName = movie_name;
- new_event.Movie.Theme = (int)theme;
- new_event.Movie.Immediate = immediate;
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Display_Briefing_Text
- *
- * Called when Red Alert wants to display the mission breifing screen before a mission.
- *
- * History: 12/04/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::On_Display_Briefing_Text()
- {
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_BRIEFING_SCREEN;
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Sound_Effect -- Called when C&C wants to play a sound effect
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/20/2019 2:39PM - ST
- **************************************************************************************************/
- void DLLExportClass::On_Sound_Effect(const HouseClass* player_ptr, int sound_effect_index, const char* extension, int variation, COORDINATE coord)
- {
- // player_ptr could be NULL
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_SOUND_EFFECT;
- new_event.SoundEffect.SFXIndex = sound_effect_index;
- new_event.SoundEffect.Variation = variation;
- new_event.GlyphXPlayerID = 0;
- if ( player_ptr != NULL )
- {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- if ( coord == 0 )
- {
- new_event.SoundEffect.PixelX = -1;
- new_event.SoundEffect.PixelY = -1;
- }
- else
- {
- // Use world pixel coordinates
- new_event.SoundEffect.PixelX = Lepton_To_Pixel(Coord_X(coord));
- new_event.SoundEffect.PixelY = Lepton_To_Pixel(Coord_Y(coord));
- }
- if ( sound_effect_index >= VOC_FIRST && sound_effect_index < VOC_COUNT )
- {
- strncpy( new_event.SoundEffect.SoundEffectName, SoundEffectName[ sound_effect_index ].Name , 16);
- if ( extension != NULL )
- {
- strncat( new_event.SoundEffect.SoundEffectName, extension , 16);
- }
- new_event.SoundEffect.SoundEffectPriority = SoundEffectName[ sound_effect_index ].Priority;
- new_event.SoundEffect.SoundEffectContext = SoundEffectName[ sound_effect_index ].Where;
- }
- else
- {
- strncpy( new_event.SoundEffect.SoundEffectName, "BADINDEX", 16 );
- new_event.SoundEffect.SoundEffectPriority = -1;
- new_event.SoundEffect.SoundEffectContext = -1;
- }
- EventCallback(new_event);
- }
-
- /**************************************************************************************************
- * DLLExportClass::On_Speech -- Called when C&C wants to play a speech line
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/20/2019 2:39PM - ST
- **************************************************************************************************/
- void DLLExportClass::On_Speech(const HouseClass* player_ptr, int speech_index)
- {
- // player_ptr could be NULL
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_SPEECH;
- new_event.Speech.SpeechIndex = speech_index;
- new_event.GlyphXPlayerID = 0;
- if (player_ptr != NULL)
- {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- if (speech_index >= VOX_FIRST && speech_index < VOX_COUNT)
- {
- strncpy(new_event.Speech.SpeechName, Speech[speech_index], 16);
- }
- else
- {
- strncpy(new_event.Speech.SpeechName, "BAD_SPEECH_INDEX", 16);
- }
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::RA_Calculate_Leadership --
- *
- * History: 10.30.2019 MBL (Based on LLL's Calculate_Single_Player_Score())
- **************************************************************************************************/
- int DLLExportClass::RA_Calculate_Leadership( HousesType player_house, int units_lost, int buildings_lost )
- {
- int house = (player_house == HOUSE_USSR || player_house == HOUSE_UKRAINE); // 0 or 1
- int leadership = 0;
- for (int index = 0; index < Logic.Count(); index++) {
- ObjectClass* object = Logic[index];
- HousesType owner = object->Owner();
- if ((house) && (owner == HOUSE_USSR || owner == HOUSE_BAD || owner == HOUSE_UKRAINE)) {
- leadership++;
- }
- else {
- if ((!house) && (object->Owner() == HOUSE_GREECE)) {
- leadership++;
- }
- }
- }
- if (!leadership) leadership++;
- leadership = 100 * fixed(leadership, (units_lost + buildings_lost + leadership));
- leadership = min(150, leadership);
- return leadership;
- }
- /**************************************************************************************************
- * DLLExportClass::RA_Calculate_Economy --
- *
- * History: 10.30.2019 MBL (Based on LLL's Calculate_Single_Player_Score())
- **************************************************************************************************/
- int DLLExportClass::RA_Calculate_Economy( long available_money, int stolen_buildings_credits, unsigned harvested_credits, long initial_credits )
- {
- int economy = 100 * fixed((unsigned)available_money + 1 + stolen_buildings_credits, harvested_credits + (unsigned)initial_credits + 1);
- economy = min(economy, 150);
- return economy;
- }
- /**************************************************************************************************
- * DLLExportClass::RA_Calculate_Score --
- *
- * History: 10.30.2019 MBL (Based on LLL's Calculate_Single_Player_Score())
- **************************************************************************************************/
- int DLLExportClass::RA_Calculate_Score( int uspoints, int leadership, int economy )
- {
- int score_total = ((uspoints * leadership) / 100) + ((uspoints * economy) / 100);
- if (score_total < -9999) score_total = -9999;
- score_total = min(score_total, 99999);
- return score_total;
- }
- /**************************************************************************************************
- * DLLExportClass::CalculateScore*
- *
- * History: 10/16/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Calculate_Single_Player_Score(EventCallbackStruct& event)
- {
- //Adapted from Red Alert SCORE.CPP Presentation() - LLL
- int house = (PlayerPtr->Class->House == HOUSE_USSR || PlayerPtr->Class->House == HOUSE_UKRAINE); // 0 or 1
- int good_units_lost = (HouseClass::As_Pointer(HOUSE_GOOD))->UnitsLost;
- int bad_units_lost = (HouseClass::As_Pointer(HOUSE_BAD))->UnitsLost;
- int neutral_units_lost = (HouseClass::As_Pointer(HOUSE_NEUTRAL))->UnitsLost;
- int good_buildings_lost = (HouseClass::As_Pointer(HOUSE_GOOD))->BuildingsLost;
- int bad_buildings_lost = (HouseClass::As_Pointer(HOUSE_BAD))->BuildingsLost;
- int neutral_buildings_lost = (HouseClass::As_Pointer(HOUSE_NEUTRAL))->BuildingsLost;
- int good_credits_harvested = (HouseClass::As_Pointer(HOUSE_GOOD))->HarvestedCredits;
- int bad_credits_harvested = (HouseClass::As_Pointer(HOUSE_BAD))->HarvestedCredits;
- int uspoints = 0;
- for (HousesType hous = HOUSE_SPAIN; hous <= HOUSE_BAD; hous++) {
- HouseClass *hows = HouseClass::As_Pointer(hous);
- if (hous == HOUSE_USSR || hous == HOUSE_BAD || hous == HOUSE_UKRAINE) {
- bad_units_lost += hows->UnitsLost;
- bad_buildings_lost += hows->BuildingsLost;
- }
- else {
- good_units_lost += hows->UnitsLost;
- good_buildings_lost += hows->BuildingsLost;
- }
- if (PlayerPtr->Is_Ally(hous)) {
- uspoints += hows->PointTotal;
- }
- }
- // if(uspoints < 0) uspoints = 0;
- // uspoints += 1000; //BG 1000 bonus points for winning mission
- /*
- ** Bias the base score upward according to the difficulty level.
- */
- switch (PlayerPtr->Difficulty) {
- case DIFF_EASY:
- uspoints += 500;
- break;
- case DIFF_NORMAL:
- uspoints += 1500;
- break;
- case DIFF_HARD:
- uspoints += 3500;
- break;
- }
- /*
- ** Determine leadership rating.
- */
- int leadership = 0;
- for (int index = 0; index < Logic.Count(); index++) {
- ObjectClass * object = Logic[index];
- HousesType owner = object->Owner();
- if ((house) && (owner == HOUSE_USSR || owner == HOUSE_BAD || owner == HOUSE_UKRAINE)) {
- leadership++;
- }
- else {
- if ((!house) && (object->Owner() == HOUSE_GREECE)) {
- leadership++;
- }
- }
- }
- if (!leadership) leadership++;
- leadership = 100 * fixed(leadership, (house ? bad_units_lost + bad_buildings_lost + leadership : good_units_lost + good_buildings_lost + leadership));
- leadership = min(150, leadership);
- /*
- ** Determine economy rating.
- */
- // int init = PlayerPtr->Control.InitialCredits;
- // int cred = PlayerPtr->Available_Money();
- int economy = 100 * fixed((unsigned)PlayerPtr->Available_Money() + 1 + PlayerPtr->StolenBuildingsCredits, PlayerPtr->HarvestedCredits + (unsigned)PlayerPtr->Control.InitialCredits + 1);
- economy = min(economy, 150);
- int score_total = ((uspoints * leadership) / 100) + ((uspoints * economy) / 100);
- if (score_total < -9999) score_total = -9999;
- score_total = min(score_total, 99999);
- //Score Stats
- event.GameOver.Leadership = leadership;
- event.GameOver.Efficiency = economy;
- event.GameOver.Score = score_total;
- event.GameOver.CategoryTotal = uspoints;
- event.GameOver.NODKilled = bad_units_lost;
- event.GameOver.GDIKilled = good_units_lost;
- event.GameOver.CiviliansKilled = neutral_units_lost;
- event.GameOver.NODBuildingsDestroyed = bad_buildings_lost;
- event.GameOver.GDIBuildingsDestroyed = good_buildings_lost;
- event.GameOver.CiviliansBuildingsDestroyed = neutral_buildings_lost;
- event.GameOver.RemainingCredits = PlayerPtr->Available_Money();
- if (Scen.IsSkipScore) {
- event.GameOver.Score = -1;
- }
- }
- /**************************************************************************************************
- * DLLExportClass::On_Message -- Called when the game wants to display a message (ex. tutorial text)
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 10/16/2019 - SKY
- **************************************************************************************************/
- void DLLExportClass::On_Message(const HouseClass* player_ptr, const char* message, float timeout_seconds, EventCallbackMessageEnum message_type, int64 message_id)
- {
- if (EventCallback == NULL)
- {
- return;
- }
- const char* p_msg = message;
- std::string localized_text_name;
- if (message_id != -1) {
- if (message_id == TXT_INSUFFICIENT_FUNDS) {
- localized_text_name = "TEXT_INSUFFICIENT_FUNDS_MESSAGE";
- }
- else if (message_id == TXT_LOW_POWER) {
- localized_text_name = "TEXT_LOW_POWER_MESSAGE_001";
- }
- else if (message_id == TXT_POWER_TESLA) {
- localized_text_name = "TEXT_LOW_POWER_MESSAGE_002";
- }
- else if (message_id == TXT_POWER_AAGUN) {
- localized_text_name = "TEXT_LOW_POWER_MESSAGE_003";
- }
- else {
- if (MessagesSent.find(message_id) != MessagesSent.end()) {
- return;
- }
- MessagesSent.insert(message_id);
- localized_text_name = "TEXT_RA_TUTORIAL_MESSAGE_";
- localized_text_name += std::to_string(message_id);
- }
- p_msg = localized_text_name.c_str();
- Sound_Effect(VOC_INCOMING_MESSAGE);
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_MESSAGE;
- new_event.Message.Message = p_msg;
- new_event.Message.TimeoutSeconds = timeout_seconds;
- new_event.Message.MessageType = message_type;
- new_event.Message.MessageParam1 = message_id;
- new_event.GlyphXPlayerID = 0;
- if (player_ptr != NULL)
- {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Update_Map_Cell -- Called when an individual map cell template is updated
- *
- *
- * History: 11/7/2019 - SKY
- **************************************************************************************************/
- void DLLExportClass::On_Update_Map_Cell(int cell_x, int cell_y, const char* template_type_name)
- {
- if (EventCallback == NULL)
- {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_UPDATE_MAP_CELL;
- new_event.UpdateMapCell.CellX = cell_x;
- new_event.UpdateMapCell.CellY = cell_y;
- strncpy(new_event.UpdateMapCell.TemplateTypeName, template_type_name, 32);
- new_event.UpdateMapCell.TemplateTypeName[31] = '\0';
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Special_Weapon_Targetting -- Called when the server initiates targetting
- *
- *
- * History: 11/19/2019 - SKY
- **************************************************************************************************/
- void DLLExportClass::On_Special_Weapon_Targetting(const HouseClass* player_ptr, SpecialWeaponType weapon_type)
- {
- if (EventCallback == NULL)
- {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_SPECIAL_WEAPON_TARGETTING;
- new_event.SpecialWeaponTargetting.Type = RTTI_SPECIAL;
- new_event.SpecialWeaponTargetting.ID = weapon_type;
- Convert_Special_Weapon_Type(weapon_type, new_event.SpecialWeaponTargetting.WeaponType, new_event.SpecialWeaponTargetting.Name);
- new_event.GlyphXPlayerID = 0;
- if (player_ptr != NULL)
- {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Ping -- Called when a radar ping is needed
- *
- *
- * History: 05/15/2019 - SKY
- **************************************************************************************************/
- void DLLExportClass::On_Ping(const HouseClass* player_ptr, COORDINATE coord)
- {
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_PING;
- new_event.Ping.CoordX = Coord_X(coord);
- new_event.Ping.CoordY = Coord_Y(coord);
- new_event.GlyphXPlayerID = 0;
- if (player_ptr != NULL)
- {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Game_Over -- Called when the C&C campaign game finishes
- *
- *
- * History: 6/19/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::On_Game_Over(uint64 glyphx_Player_id, bool player_wins)
- {
- if (EventCallback == NULL) {
- return;
- }
- GameOver = true;
- SaveTanya = IsTanyaDead;
- Scen.CarryOverTimer = Scen.MissionTimer;
- // int timer = Scen.MissionTimer;
- Scen.CarryOverMoney = PlayerPtr->Credits;
- DLLExportClass::Store_Carryover_Objects();
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_GAME_OVER;
- new_event.GlyphXPlayerID = glyphx_Player_id;
- new_event.GameOver.PlayerWins = player_wins;
- new_event.GameOver.AfterScoreMovieName = "";
- new_event.GameOver.Multiplayer = false;
- new_event.GameOver.MultiPlayerTotalPlayers = 0;
- Calculate_Single_Player_Score(new_event);
- VQType movie = player_wins ? Scen.WinMovie : Scen.LoseMovie;
- if (movie > VQ_NONE && movie < VQ_COUNT) {
- new_event.GameOver.MovieName = VQName[movie];
- } else {
- new_event.GameOver.MovieName = "";
- }
- movie = player_wins ? Scen.WinMovie2 : VQ_NONE;
- if (movie > VQ_NONE && movie < VQ_COUNT) {
- new_event.GameOver.MovieName2 = VQName[movie];
- }
- else {
- new_event.GameOver.MovieName2 = "";
- }
- movie = player_wins ? Scen.WinMovie3 : VQ_NONE;
- if (movie > VQ_NONE && movie < VQ_COUNT) {
- new_event.GameOver.MovieName3 = VQName[movie];
- }
- else {
- new_event.GameOver.MovieName3 = "";
- }
- movie = player_wins ? Scen.WinMovie4 : VQ_NONE;
- if (movie > VQ_NONE && movie < VQ_COUNT) {
- new_event.GameOver.MovieName4 = VQName[movie];
- }
- else {
- new_event.GameOver.MovieName4 = "";
- }
- //Campaign win & credits
- if (Scen.IsEndOfGame) {
- if (PlayerPtr->ActLike == HOUSE_USSR) {
- new_event.GameOver.AfterScoreMovieName = VQName[VQ_SOVFINAL];
- }
- else {
- new_event.GameOver.AfterScoreMovieName = VQName[VQ_ALLYEND];
- }
- }
- new_event.GameOver.SabotagedStructureType = -1;
- new_event.GameOver.TimerRemaining = Scen.MissionTimer.Was_Started() ? Scen.MissionTimer.Value() : -1;
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Multiplayer_Game_Over -- Called when the C&C multiplayer game finishes
- *
- *
- * History: 6/19/2019 - LLL
- * History: 10/31/2019 - MBL - Adding the multi-player score stats support for debrief
- **************************************************************************************************/
- void DLLExportClass::On_Multiplayer_Game_Over(void)
- {
- if (EventCallback == NULL) {
- return;
- }
- GameOver = true;
- EventCallbackStruct event;
- event.EventType = CALLBACK_EVENT_GAME_OVER;
- // Includes AI's for skirmish
- int player_count = Session.Players.Count();
- // Multiplayer players data for debrief stats
- event.GameOver.Multiplayer = true;
- event.GameOver.MultiPlayerTotalPlayers = player_count;
- for ( int player_index = 0; player_index < player_count; player_index ++ )
- {
- HouseClass* player_ptr = HouseClass::As_Pointer(Session.Players[ player_index ]->Player.ID);
- if ( player_ptr != NULL )
- {
- HousesType player_house = PlayerPtr->Class->House;
- int uspoints = 0;
- for (HousesType hous = HOUSE_SPAIN; hous <= HOUSE_BAD; hous++) {
- HouseClass* hows = HouseClass::As_Pointer(hous);
- if (player_ptr->Is_Ally(hous)) {
- uspoints += hows->PointTotal;
- }
- }
- // if(uspoints < 0) uspoints = 0;
- // uspoints += 1000; //BG 1000 bonus points for winning mission
- // N/A for multi-player
- #if 0
- // Bias the base score upward according to the difficulty level.
- switch (PlayerPtr->Difficulty) {
- case DIFF_EASY:
- uspoints += 500;
- break;
-
- case DIFF_NORMAL:
- uspoints += 1500;
- break;
-
- case DIFF_HARD:
- uspoints += 3500;
- break;
- }
- #endif
- int leadership = RA_Calculate_Leadership( player_ptr->Class->House, player_ptr->UnitsLost, player_ptr->BuildingsLost );
- int economy = RA_Calculate_Economy( player_ptr->Available_Money(), player_ptr->StolenBuildingsCredits, player_ptr->HarvestedCredits, player_ptr->Control.InitialCredits );
- int total_score = RA_Calculate_Score( uspoints, leadership, economy );
- int units_killed = 0;
- int structures_killed = 0;
- for ( unsigned int house_index = 0; house_index < HOUSE_COUNT; house_index ++ )
- {
- units_killed += player_ptr->UnitsKilled[ house_index ];
- structures_killed += player_ptr->BuildingsKilled[ house_index ];
- }
- // Populate and copy the multiplayer player data structure
- GameOverMultiPlayerStatsStruct multi_player_data;
- multi_player_data.GlyphXPlayerID = Get_GlyphX_Player_ID( player_ptr );
- multi_player_data.IsHuman = (player_ptr->IsHuman || player_ptr->WasHuman);
- multi_player_data.WasHuman = player_ptr->WasHuman;
- multi_player_data.IsWinner = !player_ptr->IsDefeated;
- multi_player_data.Efficiency = economy;
- multi_player_data.Score = total_score;
- multi_player_data.ResourcesGathered = player_ptr->HarvestedCredits;
- multi_player_data.TotalUnitsKilled = units_killed;
- multi_player_data.TotalStructuresKilled = structures_killed;
- if ( player_index < GAME_OVER_MULTIPLAYER_MAX_PLAYERS_TRACKED )
- {
- event.GameOver.MultiPlayerPlayersData[ player_index ] = multi_player_data;
- }
- }
- }
- for ( int player_index = player_count; player_index < GAME_OVER_MULTIPLAYER_MAX_PLAYERS_TRACKED; player_index ++ )
- {
- memset( &event.GameOver.MultiPlayerPlayersData[ player_index ], 0, sizeof( GameOverMultiPlayerStatsStruct ) );
- }
- // Single-player N/A stuff
- event.GameOver.MovieName = "";
- event.GameOver.MovieName2 = "";
- event.GameOver.MovieName3 = "";
- event.GameOver.MovieName4 = "";
- event.GameOver.AfterScoreMovieName = "";
- event.GameOver.Leadership = 0;
- event.GameOver.Efficiency = 0;
- event.GameOver.Score = 0;
- event.GameOver.NODKilled = 0;
- event.GameOver.GDIKilled = 0;
- event.GameOver.CiviliansKilled = 0;
- event.GameOver.NODBuildingsDestroyed = 0;
- event.GameOver.GDIBuildingsDestroyed = 0;
- event.GameOver.CiviliansBuildingsDestroyed = 0;
- event.GameOver.RemainingCredits = 0;
- event.GameOver.SabotagedStructureType = 0;
- event.GameOver.TimerRemaining = -1;
- // Trigger an event for each human player, winner first (even if it's an AI)
- for (int i = 0; i < player_count; i++) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- if (!player_ptr->IsDefeated) {
- event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- event.GameOver.IsHuman = player_ptr->IsHuman;
- event.GameOver.PlayerWins = true;
- event.GameOver.RemainingCredits = player_ptr->Available_Money();
- EventCallback(event);
- }
- }
- for (int i = 0; i < player_count; i++) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- if (player_ptr->IsHuman && player_ptr->IsDefeated) {
- event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- event.GameOver.IsHuman = true;
- event.GameOver.PlayerWins = false;
- event.GameOver.RemainingCredits = player_ptr->Available_Money();
- EventCallback(event);
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::On_Achievement -- Called when something achievement-related happens
- *
- * In: Type of achievement, reason this happened
- *
- * Out:
- *
- *
- *
- * History: 11/11/2019 11:37AM - ST
- **************************************************************************************************/
- void DLLExportClass::On_Achievement(const HouseClass* player_ptr, const char *achievement_type, const char *achievement_reason)
- {
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_ACHIEVEMENT;
- new_event.Achievement.AchievementType = achievement_type;
- new_event.Achievement.AchievementReason = achievement_reason;
- new_event.GlyphXPlayerID = 0;
- if (player_ptr != NULL) {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- EventCallback(new_event);
- }
- void DLLExportClass::On_Center_Camera(const HouseClass* player_ptr, int coord_x, int coord_y)
- {
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_CENTER_CAMERA;
- new_event.CenterCamera.CoordX = coord_x;
- new_event.CenterCamera.CoordY = coord_y;
- new_event.GlyphXPlayerID = 0;
- if (player_ptr != NULL) {
- new_event.GlyphXPlayerID = Get_GlyphX_Player_ID(player_ptr);
- }
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::On_Debug_Output -- Called when C&C wants to print debug output
- *
- * In: String to print to GlyphX log system
- *
- * Out:
- *
- *
- *
- * History: 2/20/2019 2:39PM - ST
- **************************************************************************************************/
- void DLLExportClass::On_Debug_Output(const char *debug_text)
- {
- if (EventCallback == NULL) {
- return;
- }
- EventCallbackStruct new_event;
- new_event.EventType = CALLBACK_EVENT_DEBUG_PRINT;
- new_event.DebugPrint.PrintString = debug_text;
- EventCallback(new_event);
- }
- /**************************************************************************************************
- * DLLExportClass::Force_Human_Team_Wins
- *
- * History: 3/10/2020 - LL
- **************************************************************************************************/
- void DLLExportClass::Force_Human_Team_Wins(uint64 quitting_player_id)
- {
- int winning_team = -1;
- //Find the first human's multiplayer team.
- for (int i = 0; i < Session.Players.Count(); i++)
- {
- if (GlyphxPlayerIDs[i] != quitting_player_id) {
- HousesType house_type = Session.Players[i]->Player.ID;
- HouseClass* house_class = HouseClass::As_Pointer(house_type);
- if (house_class && house_class->IsHuman && !house_class->IsDefeated) {
- winning_team = MPlayerTeamIDs[i];
- break;
- }
- }
- }
- //Mark all players not on that team as defeated.
- for (int i = 0; i < Session.Players.Count(); i++)
- {
- HousesType house_type = Session.Players[i]->Player.ID;
- HouseClass* house_class = HouseClass::As_Pointer(house_type);
- if (house_class) {
- house_class->IsDefeated = MPlayerTeamIDs[i] != winning_team;
- }
- }
- PlayerWins = true;
- }
- /**************************************************************************************************
- * CNC_Get_Game_State -- Get game state
- *
- * In: Type of state requested
- * Player perspective
- * Buffer to contain game state
- * Size of buffer
- *
- * Out: Game state returned in buffer
- *
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- extern "C" __declspec(dllexport) bool __cdecl CNC_Get_Game_State(GameStateRequestEnum state_type, uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- bool got_state = false;
- switch (state_type) {
-
- case GAME_STATE_LAYERS:
- {
- got_state = DLLExportClass::Get_Layer_State(player_id, buffer_in, buffer_size);
- break;
- }
- case GAME_STATE_SIDEBAR:
- {
- got_state = DLLExportClass::Get_Sidebar_State(player_id, buffer_in, buffer_size);
- break;
- }
- case GAME_STATE_PLACEMENT:
- {
- got_state = DLLExportClass::Get_Placement_State(player_id, buffer_in, buffer_size);
- break;
- }
-
- case GAME_STATE_DYNAMIC_MAP:
- got_state = DLLExportClass::Get_Dynamic_Map_State(player_id, buffer_in, buffer_size);
- break;
- case GAME_STATE_SHROUD:
- got_state = DLLExportClass::Get_Shroud_State(player_id, buffer_in, buffer_size);
- break;
- case GAME_STATE_OCCUPIER:
- got_state = DLLExportClass::Get_Occupier_State(player_id, buffer_in, buffer_size);
- break;
- case GAME_STATE_PLAYER_INFO:
- got_state = DLLExportClass::Get_Player_Info_State(player_id, buffer_in, buffer_size);
- break;
- case GAME_STATE_STATIC_MAP:
- {
- if (buffer_size < sizeof(CNCMapDataStruct)) {
- got_state = false;
- break;
- }
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- CNCMapDataStruct *map_data = (CNCMapDataStruct *)buffer_in;
-
- map_data->OriginalMapCellX = map_cell_x;
- map_data->OriginalMapCellY = map_cell_y;
- map_data->OriginalMapCellWidth = map_cell_width;
- map_data->OriginalMapCellHeight = map_cell_height;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_width < MAP_MAX_CELL_WIDTH) {
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
- map_cell_height++;
- }
- map_data->MapCellX = map_cell_x;
- map_data->MapCellY = map_cell_y;
- map_data->MapCellWidth = map_cell_width;
- map_data->MapCellHeight = map_cell_height;
- map_data->Theater = (CnCTheaterType) Scen.Theater;
- char* dot_ptr = strchr(Scen.ScenarioName, '.');
- const int count = (dot_ptr != nullptr) ? (dot_ptr - Scen.ScenarioName) : sizeof(Scen.ScenarioName);
- memset(map_data->ScenarioName, 0, sizeof(map_data->ScenarioName));
- strncpy(map_data->ScenarioName, Scen.ScenarioName, min(sizeof(map_data->ScenarioName) - 1, count));
- int cell_index = 0;
- char cell_name[_MAX_PATH];
- char icon_number[32];
-
- for (int y = 0 ; y < map_cell_height ; y++) {
- for (int x = 0 ; x < map_cell_width ; x++) {
- CELL cell = XY_Cell(map_cell_x+x, map_cell_y+y);
- CellClass * cellptr = &Map[cell];
- cell_name[0] = 0;
- int icon = 0;
- void *image_data = 0;
- if (cellptr->Get_Template_Info(cell_name, icon, image_data)) {
- itoa(icon, icon_number, 10);
- strncat(cell_name, "_i", 32);
- strncat(cell_name, icon_number, 32);
- strncat(cell_name, ".tga", 32);
- CNCStaticCellStruct &cell_info = map_data->StaticCells[cell_index++];
- strncpy(cell_info.TemplateTypeName, cell_name, 32);
- cell_info.IconNumber = icon;
- }
- }
- }
-
- got_state = true;
- break;
- }
- default:
- {
- got_state = false;
- break;
- }
- }
- return got_state;
- }
- /**************************************************************************************************
- * CNC_Handle_Game_Request
- *
- * Callback for when the requested movie is done playing.
- *
- * 7/23/2019 - LLL
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Request(GameRequestEnum request_type)
- {
- switch (request_type)
- {
- case INPUT_GAME_MOVIE_DONE:
- break;
- }
- }
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Game_Settings_Request(int health_bar_display_mode, int resource_bar_display_mode)
- {
- if (!DLLExportClass::Legacy_Render_Enabled()) {
- return;
- }
- RulesClass::eHealthBarDisplayMode new_hb_mode = (RulesClass::eHealthBarDisplayMode)health_bar_display_mode;
- if (new_hb_mode != Rule.HealthBarDisplayMode) {
- Rule.HealthBarDisplayMode = new_hb_mode;
- Map.Flag_To_Redraw(true);
- }
- RulesClass::eResourceBarDisplayMode new_rb_mode = (RulesClass::eResourceBarDisplayMode)resource_bar_display_mode;
- if (new_rb_mode != Rule.ResourceBarDisplayMode) {
- Rule.ResourceBarDisplayMode = new_rb_mode;
- Map.Flag_To_Redraw(true);
- }
- }
-
-
- 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)
- {
- DLLExportClass::DLL_Draw_Intercept(shape_number, x, y, width, height, flags, object, rotation, scale, shape_file_name, override_owner);
- }
- void DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip)
- {
- DLLExportClass::DLL_Draw_Pip_Intercept(object, pip);
- }
- 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)
- {
- CNCObjectStruct& new_object = ObjectList->Objects[TotalObjectCount + CurrentDrawCount];
- memset(&new_object, 0, sizeof(new_object));
- Convert_Type(object, new_object);
- if (new_object.Type == UNKNOWN) {
- return;
- }
- CNCObjectStruct* base_object = NULL;
- char sub_object = 0;
- for (int i = 0; i < CurrentDrawCount; ++i) {
- CNCObjectStruct& draw_object = ObjectList->Objects[TotalObjectCount + i];
- if (draw_object.CNCInternalObjectPointer == object) {
- if (base_object == NULL) {
- base_object = &draw_object;
- }
- sub_object++;
- }
- }
- new_object.CNCInternalObjectPointer = (void*)object;
- new_object.OccupyListLength = 0;
- if (CurrentDrawCount == 0) {
- new_object.SortOrder = (ExportLayer << 29) + (object->Sort_Y() >> 3);
- } else {
- new_object.SortOrder = ObjectList->Objects[TotalObjectCount].SortOrder + CurrentDrawCount;
- }
- strncpy(new_object.TypeName, object->Class_Of().IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
- if (shape_file_name != NULL) {
- strncpy(new_object.AssetName, shape_file_name, CNC_OBJECT_ASSET_NAME_LENGTH);
- }
- else {
- strncpy(new_object.AssetName, object->Class_Of().Graphic_Name(), CNC_OBJECT_ASSET_NAME_LENGTH);
- }
- new_object.Owner = (base_object != NULL) ? ((override_owner != HOUSE_NONE) ? override_owner : base_object->Owner) : (char)object->Owner();
- HouseClass* owner_house = nullptr;
- for (int i = 0; i < Houses.Count(); ++i) {
- HouseClass* hptr = Houses.Ptr(i);
- if ((hptr != nullptr) && (hptr->Class->House == new_object.Owner)) {
- owner_house = hptr;
- break;
- }
- }
- new_object.RemapColor = (owner_house != nullptr) ? owner_house->RemapColor : -1;
- if (base_object == NULL) {
- CNCObjectStruct& root_object = ObjectList->Objects[TotalObjectCount];
- if (new_object.Type == BUILDING) {
- BuildingClass *building = (BuildingClass*)object;
- if (building->BState == BSTATE_CONSTRUCTION) {
- strncat(new_object.AssetName, "MAKE", CNC_OBJECT_ASSET_NAME_LENGTH);
- }
- const BuildingTypeClass *building_type = building->Class;
- short const *occupy_list = building_type->Occupy_List();
- if (occupy_list) {
- while (*occupy_list != REFRESH_EOL && new_object.OccupyListLength < MAX_OCCUPY_CELLS) {
- new_object.OccupyList[new_object.OccupyListLength] = *occupy_list;
- new_object.OccupyListLength++;
- occupy_list++;
- }
- }
- }
- COORDINATE coord = object->Render_Coord();
- CELL cell = Coord_Cell(coord);
- int dimx, dimy;
- object->Class_Of().Dimensions(dimx, dimy);
- new_object.PositionX = x;
- new_object.PositionY = y;
- new_object.Width = width;
- new_object.Height = height;
- new_object.Altitude = object->Height;
- new_object.DrawFlags = flags;
- new_object.SubObject = 0;
- new_object.ShapeIndex = (unsigned short)shape_number;
- new_object.IsTheaterSpecific = IsTheaterShape;
- new_object.Rotation = (unsigned char)rotation;
- new_object.Scale = scale;
- new_object.FlashingFlags = 0;
- new_object.Cloak = (CurrentDrawCount > 0) ? root_object.Cloak : UNCLOAKED;
- new_object.VisibleFlags = CNCObjectStruct::VISIBLE_FLAGS_ALL;
- new_object.SpiedByFlags = 0U;
- new_object.IsSelectable = object->Class_Of().IsSelectable;
- new_object.IsSelectedMask = object->IsSelectedMask;
- new_object.MaxStrength = object->Class_Of().MaxStrength;
- new_object.Strength = object->Strength;
- new_object.CellX = (CurrentDrawCount > 0) ? root_object.CellX : Cell_X(cell);
- new_object.CellY = (CurrentDrawCount > 0) ? root_object.CellY : Cell_Y(cell);
- new_object.CenterCoordX = Coord_X(object->Center_Coord());
- new_object.CenterCoordY = Coord_Y(object->Center_Coord());
- new_object.DimensionX = dimx;
- new_object.DimensionY = dimy;
- new_object.SimLeptonX = (CurrentDrawCount > 0) ? root_object.SimLeptonX : 0;
- new_object.SimLeptonY = (CurrentDrawCount > 0) ? root_object.SimLeptonY : 0;
- new_object.BaseObjectID = ((CurrentDrawCount > 0) && (root_object.Type != BUILDING) && (root_object.Type != VESSEL)) ? root_object.ID : 0;
- new_object.BaseObjectType = ((CurrentDrawCount > 0) && (root_object.Type != BUILDING) && (root_object.Type != VESSEL)) ? root_object.Type : UNKNOWN;
- new_object.NumLines = 0;
- new_object.RecentlyCreated = object->IsRecentlyCreated;
- new_object.NumPips = 0;
- new_object.MaxPips = 0;
- new_object.CanDemolish = object->Can_Demolish();
- new_object.CanDemolishUnit = object->Can_Demolish_Unit();
- new_object.CanRepair = object->Can_Repair();
- memset(new_object.CanMove, false, sizeof(new_object.CanMove));
- memset(new_object.CanFire, false, sizeof(new_object.CanFire));
- memset(new_object.ActionWithSelected, DAT_NONE, sizeof(new_object.ActionWithSelected));
- HouseClass* old_player_ptr = PlayerPtr;
- for (int i = 0; i < Houses.Count(); ++i) {
- HouseClass* hptr = Houses.Ptr(i);
- if ((hptr != nullptr) && hptr->IsActive && hptr->IsHuman) {
- HousesType house = hptr->Class->House;
- DynamicVectorClass<ObjectClass*>& selected_objects = CurrentObject.Raw(house);
- if (selected_objects.Count() > 0) {
- Logic_Switch_Player_Context(hptr);
- Convert_Action_Type(Best_Object_Action(selected_objects, object), (selected_objects.Count() == 1) ? selected_objects[0] : NULL, object->As_Target(), new_object.ActionWithSelected[house]);
- }
- }
- }
- Logic_Switch_Player_Context(old_player_ptr);
- RTTIType what_is_object = object->What_Am_I();
- new_object.IsRepairing = false;
- new_object.IsDumping = false;
- new_object.IsALoaner = false;
- new_object.IsFactory = false;
- new_object.IsPrimaryFactory = false;
- new_object.IsNominal = false;
- new_object.IsDog = false;
- new_object.IsIronCurtain = false;
- new_object.IsAntiGround = false;
- new_object.IsAntiAircraft = false;
- new_object.IsSubSurface = false;
- new_object.IsFake = false;
- new_object.ProductionAssetName[0] = '\0';
- new_object.OverrideDisplayName = "\0";
- bool is_building = what_is_object == RTTI_BUILDING;
- if (is_building) {
- const BuildingClass* building = static_cast<const BuildingClass*>(object);
- new_object.IsRepairing = building->IsRepairing;
- new_object.IsFactory = building->Class->Is_Factory();
- new_object.IsPrimaryFactory = building->IsLeader;
- new_object.IsFake = building->Class->IsFake;
- }
- if (object->Is_Techno()) {
- const TechnoClass* techno_object = static_cast<const TechnoClass*>(object);
- const TechnoTypeClass *ttype = techno_object->Techno_Type_Class();
- new_object.MaxSpeed = (unsigned char)ttype->MaxSpeed;
- new_object.IsALoaner = techno_object->IsALoaner;
- new_object.IsNominal = ttype->IsNominal;
- new_object.MaxPips = ttype->Max_Pips();
- new_object.IsAntiGround = (ttype->PrimaryWeapon != NULL) && (ttype->PrimaryWeapon->Bullet != NULL) && ttype->PrimaryWeapon->Bullet->IsAntiGround;
- new_object.IsAntiAircraft = (ttype->PrimaryWeapon != NULL) && (ttype->PrimaryWeapon->Bullet != NULL) && ttype->PrimaryWeapon->Bullet->IsAntiAircraft;
- new_object.IsSubSurface = (ttype->PrimaryWeapon != NULL) && (ttype->PrimaryWeapon->Bullet != NULL) && ttype->PrimaryWeapon->Bullet->IsSubSurface;
- new_object.IsIronCurtain = techno_object->IronCurtainCountDown > 0;
- int full_name = techno_object->Full_Name();
- if (full_name < 0)
- {
- new_object.OverrideDisplayName = Text_String(full_name);
- }
- HouseClass* old_player_ptr = PlayerPtr;
- for (int i = 0; i < Houses.Count(); ++i) {
- HouseClass* hptr = Houses.Ptr(i);
- if ((hptr != nullptr) && hptr->IsActive && hptr->IsHuman) {
- Logic_Switch_Player_Context(hptr);
- HousesType house = hptr->Class->House;
- new_object.CanMove[house] = techno_object->Can_Player_Move();
- new_object.CanFire[house] = techno_object->Can_Player_Fire();
- }
- }
- Logic_Switch_Player_Context(old_player_ptr);
- }
- new_object.ControlGroup = (unsigned char)(-1);
- new_object.IsInFormation = false;
- new_object.CanPlaceBombs = false;
- if (object->Is_Foot()) {
- const FootClass* foot = static_cast<const FootClass*>(object);
- new_object.ControlGroup = foot->Group;
- new_object.IsInFormation = foot->XFormOffset != 0x80000000UL;
- }
- bool is_infantry = what_is_object == RTTI_INFANTRY;
- if (is_infantry) {
- const InfantryClass* infantry = static_cast<const InfantryClass*>(object);
- new_object.IsDog = infantry->Class->IsDog;
- new_object.CanPlaceBombs = infantry->Class->IsBomber;
- }
- new_object.CanHarvest = false;
- bool is_unit = what_is_object == RTTI_UNIT;
- if (is_unit) {
- const UnitClass* unit = static_cast<const UnitClass*>(object);
- if (unit->Class->Type == UNIT_HARVESTER)
- {
- new_object.CanHarvest = true;
- }
- new_object.IsDumping = unit->IsDumping;
- }
- new_object.IsFixedWingedAircraft = false;
- bool is_aircraft = what_is_object == RTTI_AIRCRAFT;
- if (is_aircraft) {
- const AircraftClass* aircraft = static_cast<const AircraftClass*>(object);;
- new_object.IsFixedWingedAircraft = aircraft->Class->IsFixedWing;
- }
- switch (what_is_object)
- {
- case RTTI_INFANTRY:
- case RTTI_INFANTRYTYPE:
- case RTTI_UNIT:
- case RTTI_UNITTYPE:
- case RTTI_AIRCRAFT:
- case RTTI_AIRCRAFTTYPE:
- case RTTI_BUILDING:
- case RTTI_BUILDINGTYPE:
- case RTTI_VESSEL:
- case RTTI_VESSELTYPE:
- {
- const TechnoClass* techno_object = static_cast<const TechnoClass*>(object);
- new_object.FlashingFlags = techno_object->Get_Flashing_Flags();
- new_object.Cloak = techno_object->Cloak;
- new_object.SpiedByFlags = techno_object->Spied_By();
- if (techno_object->Techno_Type_Class()->IsInvisible) {
- // Hide for enemy players
- HouseClass* owner = HouseClass::As_Pointer(object->Owner());
- if (owner != nullptr) {
- for (int i = 0; i < Houses.Count(); ++i) {
- HouseClass* hptr = Houses.Ptr(i);
- if ((hptr != nullptr) && hptr->IsActive && !owner->Is_Ally(hptr)) {
- new_object.VisibleFlags &= ~(1 << hptr->Class->House);
- }
- }
- }
- }
- }
- break;
- case RTTI_ANIM:
- case RTTI_ANIMTYPE:
- {
- const AnimClass* anim_object = static_cast<const AnimClass*>(object);
- new_object.Owner = anim_object->OwnerHouse;
- new_object.RemapColor = -1;
- new_object.VisibleFlags = anim_object->Get_Visible_Flags();
- const AnimTypeClass& anim_type = static_cast<const AnimTypeClass&>(anim_object->Class_Of());
- if (anim_type.VirtualName != NULL) {
- strncpy(new_object.AssetName, anim_type.VirtualName, CNC_OBJECT_ASSET_NAME_LENGTH);
- }
- }
- break;
- case RTTI_TERRAIN:
- case RTTI_TERRAINTYPE:
- {
- if (strncmp(new_object.AssetName, "MINE", CNC_OBJECT_ASSET_NAME_LENGTH) == 0) {
- strncpy(new_object.AssetName, "OREMINE", CNC_OBJECT_ASSET_NAME_LENGTH);
- }
- }
- break;
- }
- }
- else {
- new_object.MaxStrength = 0;
- new_object.MaxSpeed = 0;
- new_object.Strength = 0;
- new_object.CellX = base_object->CellX;
- new_object.CellY = base_object->CellY;
- new_object.CenterCoordX = base_object->CenterCoordX;
- new_object.CenterCoordY = base_object->CenterCoordY;
- new_object.DimensionX = base_object->DimensionX;
- new_object.DimensionY = base_object->DimensionY;
- new_object.IsSelectable = false;
- new_object.IsSelectedMask = 0U;
- new_object.SimLeptonX = base_object->SimLeptonX;
- new_object.SimLeptonY = base_object->SimLeptonY;
- new_object.PositionX = x;
- new_object.PositionY = y;
- new_object.Width = width;
- new_object.Height = height;
- new_object.Altitude = base_object->Altitude;
- new_object.DrawFlags = flags;
- new_object.ShapeIndex = (unsigned short)shape_number;
- new_object.IsTheaterSpecific = IsTheaterShape;
- new_object.Rotation = (unsigned char)rotation;
- new_object.Scale = scale;
- new_object.SubObject = sub_object;
- new_object.BaseObjectID = base_object->ID;
- new_object.BaseObjectType = base_object->Type;
- new_object.FlashingFlags = base_object->FlashingFlags;
- new_object.Cloak = base_object->Cloak;
- new_object.OccupyListLength = 0;
- new_object.NumPips = 0;
- new_object.MaxPips = 0;
- new_object.NumLines = 0;
- new_object.IsRepairing = false;
- new_object.IsDumping = false;
- new_object.IsALoaner = base_object->IsALoaner;
- new_object.CanDemolish = base_object->CanDemolish;
- new_object.CanDemolishUnit = base_object->CanDemolishUnit;
- new_object.CanRepair = base_object->CanRepair;
- new_object.RecentlyCreated = base_object->RecentlyCreated;
- new_object.IsFactory = base_object->IsFactory;
- new_object.IsPrimaryFactory = base_object->IsPrimaryFactory;
- new_object.IsAntiGround = base_object->IsAntiGround;
- new_object.IsAntiAircraft = base_object->IsAntiAircraft;
- new_object.IsSubSurface = base_object->IsSubSurface;
- new_object.IsNominal = base_object->IsNominal;
- new_object.IsDog = base_object->IsDog;
- new_object.IsIronCurtain = base_object->IsIronCurtain;
- new_object.IsInFormation = false;
- new_object.CanHarvest = base_object->CanHarvest;
- new_object.CanPlaceBombs = base_object->CanPlaceBombs;
- new_object.ControlGroup = base_object->ControlGroup;
- new_object.VisibleFlags = base_object->VisibleFlags;
- new_object.SpiedByFlags = base_object->SpiedByFlags;
- new_object.IsFixedWingedAircraft = base_object->IsFixedWingedAircraft;
- new_object.IsFake = base_object->IsFake;
- new_object.ProductionAssetName[0] = '\0';
- new_object.OverrideDisplayName = "\0";
- memset(new_object.CanMove, false, sizeof(new_object.CanMove));
- memset(new_object.CanFire, false, sizeof(new_object.CanFire));
- memset(new_object.ActionWithSelected, DAT_NONE, sizeof(new_object.ActionWithSelected));
- }
- CurrentDrawCount++;
- }
- void DLLExportClass::DLL_Draw_Pip_Intercept(const ObjectClass* object, int pip)
- {
- CNCObjectStruct* base_object = NULL;
- for (int i = 0; i < CurrentDrawCount; ++i) {
- CNCObjectStruct& draw_object = ObjectList->Objects[TotalObjectCount + i];
- if (draw_object.CNCInternalObjectPointer == object) {
- base_object = &draw_object;
- break;
- }
- }
- if ((base_object != NULL) && (base_object->NumPips < MAX_OBJECT_PIPS)) {
- base_object->Pips[base_object->NumPips] = pip;
- base_object->NumPips++;
- base_object->MaxPips = max(base_object->MaxPips, base_object->NumPips);
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Layer_State -- Get game objects from the layers
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/29/2019 11:37AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Get_Layer_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- player_id;
- static int _export_count = 0;
- bool got_state = false;
- ObjectList = (CNCObjectListStruct*) buffer_in;
- TotalObjectCount = 0;
- /*
- ** Get a reference draw coordinate for cells
- */
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- if (map_cell_x > 0) {
- map_cell_x--;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- }
- SortOrder = 0;
- /*
- ** Get the ground layer first and then followed by all the layers in increasing altitude.
- */
- for (int layer = 0; layer < DLL_LAYER_COUNT; layer++) {
-
- ExportLayer = layer;
-
- for (int index = 0; index < Map.Layer[layer].Count(); index++) {
-
- ObjectClass *object = Map.Layer[layer][index];
- if (object->IsActive) {
-
- unsigned int memory_needed = sizeof(CNCObjectListStruct);
- memory_needed += (TotalObjectCount + 10) * sizeof(CNCObjectStruct);
- if (memory_needed >= buffer_size) {
- return false;
- }
-
- if (object->Is_Techno()) {
- /*
- ** Skip units tethered to buildings, since the building will draw them itself
- */
- TechnoClass* techno_object = static_cast<TechnoClass*>(object);
- TechnoClass* contact_object = techno_object->In_Radio_Contact() ? techno_object->Contact_With_Whom() : nullptr;
- 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) {
- continue;
- }
- /*
- ** Skip units tethered to vessels, since the vessel will draw them itself
- */
- if ((contact_object != nullptr) && (contact_object->What_Am_I() == RTTI_VESSEL) && !contact_object->Is_Door_Closed() && contact_object->IsTethered && !techno_object->IsInLimbo) {
- continue;
- }
- }
- if (Debug_Map || Debug_Unshroud || (object->IsDown && !object->IsInLimbo)) {
- int x, y;
- Map.Coord_To_Pixel(object->Render_Coord(), x, y);
-
- /*
- ** Call to Draw_It can result in multiple callbacks to the draw intercept
- */
- CurrentDrawCount = 0;
- object->Draw_It(x, y, WINDOW_VIRTUAL);
- /*
- ** If the root object is a factory, then the last base object is the object in production (rendered after infiltrated buildings when selected).
- ** The root object is updated with the production asset name, but otherwise a separate object isn't created.
- ** This only occurs in skirmish and multiplayer.
- */
- if ((GAME_TO_PLAY != GAME_NORMAL) && (CurrentDrawCount > 0)) {
- CNCObjectStruct& root_object = ObjectList->Objects[TotalObjectCount];
- if (root_object.IsFactory) {
- BuildingClass* building = (BuildingClass*)root_object.CNCInternalObjectPointer;
- FactoryClass* factory = building->House->IsHuman ? building->House->Fetch_Factory(building->Class->ToBuild) : building->Factory;
- if (factory != nullptr) {
- for (int i = CurrentDrawCount - 1; i > 0; --i) {
- CNCObjectStruct& base_object = ObjectList->Objects[TotalObjectCount + i];
- if (base_object.SubObject) {
- continue;
- }
- strncpy(root_object.ProductionAssetName, base_object.TypeName, CNC_OBJECT_ASSET_NAME_LENGTH);
- void* production_object = base_object.CNCInternalObjectPointer;
- int new_draw_count = i;
- for (int j = i + 1; j < CurrentDrawCount; ++j) {
- CNCObjectStruct& cnc_object = ObjectList->Objects[TotalObjectCount + j];
- if (cnc_object.CNCInternalObjectPointer != production_object) {
- memcpy(ObjectList->Objects + TotalObjectCount + new_draw_count, &cnc_object, sizeof(CNCObjectStruct));
- new_draw_count++;
- }
- }
- memset(ObjectList->Objects + TotalObjectCount + new_draw_count, 0, (CurrentDrawCount - new_draw_count) * sizeof(CNCObjectStruct));
- CurrentDrawCount = new_draw_count;
- break;
- }
- }
- }
- }
- /*
- ** Shadows need to be rendered before the base object so they appear underneath,
- ** even though they get drawn as sub-objects (after the base object)
- */
- for (int i = 1; i < CurrentDrawCount; ++i) {
- CNCObjectStruct& sub_object = ObjectList->Objects[TotalObjectCount + i];
- if (!sub_object.SubObject) {
- continue;
- }
- static const int shadow_flags = SHAPE_PREDATOR | SHAPE_FADING;
- if (((sub_object.DrawFlags & shadow_flags) == shadow_flags) || (strncmp(sub_object.AssetName, "WAKE", CNC_OBJECT_ASSET_NAME_LENGTH) == 0)) {
- if ((strncmp(sub_object.AssetName, "RROTOR", CNC_OBJECT_ASSET_NAME_LENGTH) != 0) &&
- (strncmp(sub_object.AssetName, "LROTOR", CNC_OBJECT_ASSET_NAME_LENGTH) != 0)) {
- for (int j = i - 1; j >= 0; --j) {
- CNCObjectStruct& base_object = ObjectList->Objects[TotalObjectCount + j];
- if (!base_object.SubObject && (base_object.CNCInternalObjectPointer == sub_object.CNCInternalObjectPointer)) {
- int sort_order = base_object.SortOrder;
- base_object.SortOrder = sub_object.SortOrder;
- sub_object.SortOrder = sort_order;
- break;
- }
- }
- }
- }
- }
- TotalObjectCount += CurrentDrawCount;
- }
- }
- }
- }
- ObjectList->Count = TotalObjectCount;
- if (ObjectList->Count) {
- _export_count++;
- return true;
- }
- return false;
- }
- void DLLExportClass::Convert_Type(const ObjectClass *object, CNCObjectStruct &object_out)
- {
- object_out.Type = UNKNOWN;
- object_out.ID = -1;
-
- if (object == NULL) {
- return;
- }
- RTTIType type = object->What_Am_I();
-
- switch (type) {
- default:
- break;
- case RTTI_VESSEL:
- object_out.Type = VESSEL;
- object_out.ID = Vessels.ID((VesselClass*)object);
- break;
- case RTTI_INFANTRY:
- object_out.Type = INFANTRY;
- object_out.ID = Infantry.ID((InfantryClass*)object);
- break;
-
- case RTTI_UNIT:
- object_out.Type = UNIT;
- object_out.ID = Units.ID((UnitClass*)object);
- break;
-
- case RTTI_AIRCRAFT:
- object_out.Type = AIRCRAFT;
- object_out.ID = Aircraft.ID((AircraftClass*)object);
- break;
-
- case RTTI_BUILDING:
- object_out.Type = BUILDING;
- object_out.ID = Buildings.ID((BuildingClass*)object);
- break;
- case RTTI_BULLET:
- object_out.Type = BULLET;
- object_out.ID = Bullets.ID((BulletClass*)object);
- break;
- case RTTI_ANIM:
- object_out.Type = ANIM;
- object_out.ID = Anims.ID((AnimClass*)object);
- break;
- case RTTI_SMUDGE:
- object_out.Type = SMUDGE;
- object_out.ID = Smudges.ID((SmudgeClass*)object);
- break;
- case RTTI_TERRAIN:
- object_out.Type = TERRAIN;
- object_out.ID = Terrains.ID((TerrainClass*)object);
- break;
- }
- }
- /**************************************************************************************************
- * CNC_Handle_Input -- Process input to the game
- *
- * In:
- *
- *
- *
- *
- * Out: Game state returned in buffer
- *
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- 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)
- {
-
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- switch (input_event) {
- /*
- ** Special keys have changed
- */
- case INPUT_REQUEST_SPECIAL_KEYS:
- {
- DLLExportClass::Set_Special_Key_Flags(special_key_flags);
- break;
- }
- /*
- ** The mouse is moving
- */
- case INPUT_REQUEST_MOUSE_MOVE:
- {
- if (!DLLExportClass::Legacy_Render_Enabled()) {
- break;
- }
-
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- KEYBOARD->MouseQX = x1;
- KEYBOARD->MouseQY = y1;
- COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
- CELL cell = Coord_Cell(coord);
- if (coord) {
- //x -= Map.TacPixelX;
- //y -= Map.TacPixelY;
- /*
- ** Cause any displayed cursor to move along with the mouse cursor.
- */
- if (cell != Map.ZoneCell) {
- Map.Set_Cursor_Pos(cell);
- }
- }
- break;
- }
- /*
- ** Player left-clicked
- */
- case INPUT_REQUEST_MOUSE_LEFT_CLICK:
- {
- DLLExportClass::Adjust_Internal_View();
-
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- KEYBOARD->MouseQX = x1;
- KEYBOARD->MouseQY = y1;
- KeyNumType key = (KeyNumType)(KN_LMOUSE | KN_RLSE_BIT);
- if (Map.Pixel_To_Coord(x1, y1)) {
- //DisplayClass::TacButton.Clicked_On(key, GadgetClass::LEFTRELEASE, x1, y1);
- DisplayClass::TacButton.Clicked_On(key, GadgetClass::LEFTRELEASE, 100, 100);
- }
- break;
- }
-
- /*
- ** Player right-clicked (on up)
- */
- case INPUT_REQUEST_MOUSE_RIGHT_CLICK:
- {
- DLLExportClass::Adjust_Internal_View();
-
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- KEYBOARD->MouseQX = x1;
- KEYBOARD->MouseQY = y1;
- KeyNumType key = (KeyNumType)(KN_RMOUSE | KN_RLSE_BIT);
- if (Map.Pixel_To_Coord(x1, y1)) {
- //DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTRELEASE, x1, y1);
- DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTRELEASE, 100, 100);
- }
- break;
- }
- /*
- ** Player right button down
- */
- case INPUT_REQUEST_MOUSE_RIGHT_DOWN:
- {
- DLLExportClass::Adjust_Internal_View();
-
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- KEYBOARD->MouseQX = x1;
- KEYBOARD->MouseQY = y1;
- KeyNumType key = (KeyNumType)(KN_RMOUSE);
- if (Map.Pixel_To_Coord(x1, y1)) {
- //DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTPRESS, x1, y1);
- DisplayClass::TacButton.Clicked_On(key, GadgetClass::RIGHTPRESS, 100, 100);
- }
- break;
- }
-
- /*
- ** Player drag selected
- */
- case INPUT_REQUEST_MOUSE_AREA:
- {
- DLLExportClass::Adjust_Internal_View();
- Map.Select_These(XYP_Coord(x1, y1), XYP_Coord(x2, y2), false);
- break;
- }
- case INPUT_REQUEST_MOUSE_AREA_ADDITIVE:
- {
- DLLExportClass::Adjust_Internal_View();
- Map.Select_These(XYP_Coord(x1, y1), XYP_Coord(x2, y2), true);
- break;
- }
- case INPUT_REQUEST_SELL_AT_POSITION:
- {
- DLLExportClass::Adjust_Internal_View();
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- KEYBOARD->MouseQX = x1;
- KEYBOARD->MouseQY = y1;
- COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
- CELL cell = Coord_Cell(coord);
- PlayerPtr->Sell_Wall(cell);
- break;
- }
- case INPUT_REQUEST_SELECT_AT_POSITION:
- {
- DLLExportClass::Adjust_Internal_View();
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- Keyboard->MouseQX = x1;
- Keyboard->MouseQY = y1;
- COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
- CELL cell = Coord_Cell(coord);
- if (Map.Pixel_To_Coord(x1, y1))
- {
- KeyNumType key = (KeyNumType)(KN_LMOUSE | KN_RLSE_BIT);
- DisplayClass::TacButton.Selection_At_Mouse(GadgetClass::LEFTRELEASE, key);
- }
- break;
- }
- case INPUT_REQUEST_COMMAND_AT_POSITION:
- {
- DLLExportClass::Adjust_Internal_View();
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- Keyboard->MouseQX = x1;
- Keyboard->MouseQY = y1;
- COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
- CELL cell = Coord_Cell(coord);
- if (Map.Pixel_To_Coord(x1, y1))
- {
- KeyNumType key = (KeyNumType)(KN_LMOUSE | KN_RLSE_BIT);
- DisplayClass::TacButton.Command_Object(GadgetClass::LEFTRELEASE, key);
- }
- break;
- }
- // MBL 09.08.2020 - Mod Support
- case INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION:
- case INPUT_REQUEST_MOD_GAME_COMMAND_2_AT_POSITION:
- case INPUT_REQUEST_MOD_GAME_COMMAND_3_AT_POSITION:
- case INPUT_REQUEST_MOD_GAME_COMMAND_4_AT_POSITION:
- {
- DLLExportClass::Adjust_Internal_View();
- DLLForceMouseX = x1;
- DLLForceMouseY = y1;
- Keyboard->MouseQX = x1;
- Keyboard->MouseQY = y1;
- COORDINATE coord = Map.Pixel_To_Coord(x1, y1);
- CELL cell = Coord_Cell(coord);
- if (Map.Pixel_To_Coord(x1, y1))
- {
- // TBD: For our ever-awesome Community Modders!
- //
- // PlayerPtr->Handle_Mod_Game_Command(cell, input_event - INPUT_REQUEST_MOD_GAME_COMMAND_1_AT_POSITION);
- }
- break;
- }
- default:
- break;
- }
- }
- /**************************************************************************************************
- * CNC_Handle_Structure_Request -- Process requests to repair and sell structures.
- *
- * In:
- *
- *
- * Out:
- *
- *
- *
- * History: 4/29/2019 - LLL
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Structure_Request(StructureRequestEnum request_type, uint64 player_id, int object_id)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- switch (request_type)
- {
- case INPUT_STRUCTURE_REPAIR_START:
- DLLExportClass::Repair_Mode(player_id);
- break;
- case INPUT_STRUCTURE_REPAIR:
- DLLExportClass::Repair(player_id, object_id);
- break;
- case INPUT_STRUCTURE_SELL_START:
- DLLExportClass::Sell_Mode(player_id);
- break;
- case INPUT_STRUCTURE_SELL:
- DLLExportClass::Sell(player_id, object_id);
- break;
- case INPUT_STRUCTURE_CANCEL:
- DLLExportClass::Repair_Sell_Cancel(player_id);
- break;
- default:
- break;
- }
- }
- /**************************************************************************************************
- * CNC_Handle_Unit_Request -- Process requests on selected units.
- *
- * In:
- *
- *
- * Out:
- *
- *
- *
- * History: 10/15/2019 - SKY
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Unit_Request(UnitRequestEnum request_type, uint64 player_id)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- switch (request_type)
- {
- case INPUT_UNIT_SCATTER:
- DLLExportClass::Scatter_Selected(player_id);
- break;
- case INPUT_UNIT_SELECT_NEXT:
- DLLExportClass::Select_Next_Unit(player_id);
- break;
- case INPUT_UNIT_SELECT_PREVIOUS:
- DLLExportClass::Select_Previous_Unit(player_id);
- break;
- case INPUT_UNIT_GUARD_MODE:
- DLLExportClass::Selected_Guard_Mode(player_id);
- break;
- case INPUT_UNIT_STOP:
- DLLExportClass::Selected_Stop(player_id);
- break;
- case INPUT_UNIT_FORMATION_TOGGLE:
- DLLExportClass::Team_Units_Formation_Toggle_On(player_id);
- break;
- case INPUT_UNIT_QUEUED_MOVEMENT_ON:
- // Red Alert Only
- DLLExportClass::Units_Queued_Movement_Toggle(player_id, true);
- break;
- case INPUT_UNIT_QUEUED_MOVEMENT_OFF:
- // Red Alert Only
- DLLExportClass::Units_Queued_Movement_Toggle(player_id, false);
- break;
- default:
- break;
- }
- }
- /**************************************************************************************************
- * CNC_Handle_Sidebar_Request -- Process an input request to the sidebar
- *
- * In:
- *
- *
- * Out:
- *
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- 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)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
-
- switch (request_type) {
-
- // 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
- // Handle and fall through to start construction (from hold state) below
- case SIDEBAR_REQUEST_START_CONSTRUCTION_MULTI:
- case SIDEBAR_REQUEST_START_CONSTRUCTION:
- DLLExportClass::Start_Construction(player_id, buildable_type, buildable_id);
- break;
-
- case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
- DLLExportClass::Hold_Construction(player_id, buildable_type, buildable_id);
- break;
-
- case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
- DLLExportClass::Cancel_Construction(player_id, buildable_type, buildable_id);
- break;
- case SIDEBAR_REQUEST_START_PLACEMENT:
- DLLExportClass::Start_Placement(player_id, buildable_type, buildable_id);
- break;
-
- case SIDEBAR_REQUEST_PLACE:
- DLLExportClass::Place(player_id, buildable_type, buildable_id, cell_x, cell_y);
- break;
- case SIDEBAR_CANCEL_PLACE:
- DLLExportClass::Cancel_Placement(player_id, buildable_type, buildable_id);
- break;
- default:
- break;
- }
- }
- /**************************************************************************************************
- * CNC_Handle_SuperWeapon_Request
- *
- * In:
- *
- *
- * Out:
- *
- *
- *
- * History:
- **************************************************************************************************/
- 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)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- switch (request_type)
- {
- case SUPERWEAPON_REQUEST_PLACE_SUPER_WEAPON:
- DLLExportClass::Place_Super_Weapon(player_id, buildable_type, buildable_id, x1, y1);
- break;
- }
- }
- /**************************************************************************************************
- * CNC_Handle_ControlGroup_Request
- *
- * In:
- *
- *
- * Out:
- *
- *
- *
- * History:
- **************************************************************************************************/
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_ControlGroup_Request(ControlGroupRequestEnum request_type, uint64 player_id, unsigned char control_group_index)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- switch (request_type)
- {
- case CONTROL_GROUP_REQUEST_CREATE:
- DLLExportClass::Create_Control_Group(control_group_index);
- break;
- case CONTROL_GROUP_REQUEST_TOGGLE:
- DLLExportClass::Toggle_Control_Group_Selection(control_group_index);
- break;
- case CONTROL_GROUP_REQUEST_ADDITIVE_SELECTION:
- DLLExportClass::Add_To_Control_Group(control_group_index);
- break;
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Layer_State -- Get a snapshot of the sidebar state
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/29/2019 11:37AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Get_Sidebar_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- CNCSidebarStruct *sidebar = (CNCSidebarStruct*) buffer_in;
-
- unsigned int memory_needed = sizeof(*sidebar); // Base amount needed. Will need more depending on how many entries there are
-
- int entry_index = 0;
- sidebar->Credits = 0;
- sidebar->CreditsCounter = 0;
- sidebar->Tiberium = 0;
- sidebar->MaxTiberium = 0;
- sidebar->PowerProduced = 0;
- sidebar->PowerDrained = 0;
- sidebar->RepairBtnEnabled = false;
- sidebar->SellBtnEnabled = false;
- sidebar->RadarMapActive = false;
- sidebar->MissionTimer = Scen.MissionTimer.Is_Active() ? (Scen.MissionTimer / TICKS_PER_SECOND) : -1;
- sidebar->UnitsKilled = 0;
- sidebar->BuildingsKilled = 0;
- sidebar->UnitsLost = 0;
- sidebar->BuildingsLost = 0;
- sidebar->TotalHarvestedCredits = 0;
- if (PlayerPtr) {
- sidebar->Credits = PlayerPtr->Credits;
- sidebar->CreditsCounter = PlayerPtr->VisibleCredits.Current; // Timed display
- // sidebar->CreditsCounter = PlayerPtr->VisibleCredits.Credits; // Actual
- sidebar->Tiberium = PlayerPtr->Tiberium;
- sidebar->MaxTiberium = PlayerPtr->Capacity;
- sidebar->PowerProduced = PlayerPtr->Power;
- sidebar->PowerDrained = PlayerPtr->Drain;
- sidebar->RepairBtnEnabled = PlayerPtr->BScan > 0;
- sidebar->SellBtnEnabled = PlayerPtr->BScan > 0;
- sidebar->RadarMapActive = PlayerPtr->Radar == RADAR_ON;
- // A. Get the DestroyedBuildings and DestroyedInfantry stats if they are available at this point
- if (PlayerPtr->DestroyedBuildings) {
- for ( int index = 0; index < PlayerPtr->DestroyedBuildings->Get_Unit_Count(); index ++ )
- {
- unsigned int count = (unsigned int) PlayerPtr->DestroyedBuildings->Get_Unit_Total( index );
- sidebar->BuildingsKilled += count;
- }
- }
- if (PlayerPtr->DestroyedInfantry) {
- for ( int index = 0; index < PlayerPtr->DestroyedInfantry->Get_Unit_Count(); index ++ )
- {
- unsigned int count = (unsigned int) PlayerPtr->DestroyedInfantry->Get_Unit_Total( index );
- sidebar->UnitsKilled += count; // Includes Infantry, Vehicles, Aircraft
- }
- }
- if (PlayerPtr->DestroyedUnits) {
- for ( int index = 0; index < PlayerPtr->DestroyedUnits->Get_Unit_Count(); index ++ )
- {
- unsigned int count = (unsigned int) PlayerPtr->DestroyedUnits->Get_Unit_Total( index );
- sidebar->UnitsKilled += count; // Includes Infantry, Vehicles, Aircraft
- }
- }
- if (PlayerPtr->DestroyedAircraft) {
- for ( int index = 0; index < PlayerPtr->DestroyedAircraft->Get_Unit_Count(); index ++ )
- {
- unsigned int count = (unsigned int) PlayerPtr->DestroyedAircraft->Get_Unit_Total( index );
- sidebar->UnitsKilled += count; // Includes Infantry, Vehicles, Aircraft
- }
- }
- // B. If the DestroyedBuildings and DestroyedInfantry stats seemed to be unvailable, this is another way to do it
- // 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
- // We can't just do it this way for everything, as it does not work for all cases
- if (sidebar->BuildingsKilled == 0)
- {
- for (unsigned int house_index = 0; house_index < HOUSE_COUNT; house_index ++)
- {
- sidebar->BuildingsKilled += PlayerPtr->BuildingsKilled[ house_index ];
- }
- }
- if (sidebar->UnitsKilled == 0)
- {
- for (unsigned int house_index = 0; house_index < HOUSE_COUNT; house_index ++)
- {
- sidebar->UnitsKilled += PlayerPtr->UnitsKilled[ house_index ]; // Includes Infantry, Vehicles, Aircraft
- }
- }
- sidebar->UnitsLost = PlayerPtr->UnitsLost;
- sidebar->BuildingsLost = PlayerPtr->BuildingsLost;
- sidebar->TotalHarvestedCredits = PlayerPtr->HarvestedCredits;
- }
- if (GAME_TO_PLAY == GAME_NORMAL) {
- /*
- ** Get each sidebar column
- */
- for (int c = 0 ; c < 2 ; c++) {
-
- sidebar->EntryCount[c] = Map.Column[c].BuildableCount;
-
- /*
- ** Each production slot in the column
- */
- for (int b=0 ; b < Map.Column[c].BuildableCount ; b++) {
-
- CNCSidebarEntryStruct &sidebar_entry = sidebar->Entries[entry_index++];
- if ((entry_index + 1) * sizeof(CNCSidebarEntryStruct) + memory_needed > buffer_size) {
- return false;
- }
- memset(&sidebar_entry, 0, sizeof(sidebar_entry));
- sidebar_entry.AssetName[0] = 0;
- sidebar_entry.Type = UNKNOWN;
- sidebar_entry.BuildableID = Map.Column[c].Buildables[b].BuildableID;
- sidebar_entry.BuildableType = Map.Column[c].Buildables[b].BuildableType;
- sidebar_entry.BuildableViaCapture = Map.Column[c].Buildables[b].BuildableViaCapture;
- sidebar_entry.Fake = false;
- TechnoTypeClass const * tech = Fetch_Techno_Type(Map.Column[c].Buildables[b].BuildableType, Map.Column[c].Buildables[b].BuildableID);
-
- sidebar_entry.SuperWeaponType = SW_NONE;
- if (tech) {
- sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias; // If this gets modified, also modify below for skirmish and multiplayer
- sidebar_entry.PowerProvided = 0;
- sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
- strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
- } else {
- sidebar_entry.Cost = 0;
- sidebar_entry.AssetName[0] = 0;
- }
-
- SuperClass* super_weapon = nullptr;
-
- bool isbusy = false;
- switch (Map.Column[c].Buildables[b].BuildableType) {
- case RTTI_INFANTRYTYPE:
- sidebar_entry.Type = INFANTRY_TYPE;
- isbusy = (PlayerPtr->InfantryFactory != -1);
- isbusy |= Infantry.Avail() <= 0;
- break;
-
- case RTTI_UNITTYPE:
- isbusy = (PlayerPtr->UnitFactory != -1);
- isbusy |= Units.Avail() <= 0;
- sidebar_entry.Type = UNIT_TYPE;
- break;
-
- case RTTI_AIRCRAFTTYPE:
- isbusy = (PlayerPtr->AircraftFactory != -1);
- isbusy |= Aircraft.Avail() <= 0;
- sidebar_entry.Type = AIRCRAFT_TYPE;
- break;
-
- case RTTI_BUILDINGTYPE:
- {
- isbusy = (PlayerPtr->BuildingFactory != -1);
- isbusy |= Buildings.Avail() <= 0;
- sidebar_entry.Type = BUILDING_TYPE;
- const BuildingTypeClass* build_type = static_cast<const BuildingTypeClass*>(tech);
- sidebar_entry.PowerProvided = build_type->Power - build_type->Drain;
- sidebar_entry.Fake = build_type->IsFake;
- }
- break;
- case RTTI_VESSELTYPE:
- sidebar_entry.Type = VESSEL_TYPE;
- isbusy = (PlayerPtr->VesselFactory != -1);
- isbusy |= Vessels.Avail() <= 0;
- break;
- default:
- sidebar_entry.Type = UNKNOWN;
- break;
- case RTTI_SPECIAL:
- Fill_Sidebar_Entry_From_Special_Weapon(sidebar_entry, super_weapon, (SpecialWeaponType)Map.Column[c].Buildables[b].BuildableID);
- break;
- }
- if (super_weapon != nullptr)
- {
- sidebar_entry.Progress = (float)super_weapon->Anim_Stage() / (float)SuperClass::ANIMATION_STAGES;
- sidebar_entry.Completed = super_weapon->Is_Ready();
- sidebar_entry.Constructing = super_weapon->Anim_Stage() != SuperClass::ANIMATION_STAGES;
- sidebar_entry.ConstructionOnHold = false;
- sidebar_entry.PlacementListLength = 0;
- sidebar_entry.PowerProvided = 0;
- sidebar_entry.BuildTime = super_weapon->Get_Recharge_Time();
- }
- else
- {
- int fnumber = Map.Column[c].Buildables[b].Factory;
- FactoryClass * factory = NULL;
- if (tech && fnumber != -1) {
- factory = Factories.Raw_Ptr(fnumber);
- }
- sidebar_entry.Completed = false;
- sidebar_entry.Constructing = false;
- sidebar_entry.ConstructionOnHold = false;
- sidebar_entry.Progress = 0.0f;
- sidebar_entry.Busy = isbusy;
- sidebar_entry.PlacementListLength = 0;
- if (factory) {
- if (factory->Is_Building()) {
- sidebar_entry.Constructing = true;
- sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
- sidebar_entry.Completed = factory->Has_Completed();
- }
- else {
- sidebar_entry.Completed = factory->Has_Completed();
- if (!sidebar_entry.Completed)
- {
- sidebar_entry.ConstructionOnHold = true;
- sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
- }
- if (sidebar_entry.Completed && sidebar_entry.Type == BUILDING_TYPE) {
- if (tech) {
- BuildingTypeClass *building_type = (BuildingTypeClass*)tech;
- short const *occupy_list = building_type->Occupy_List(true);
- if (occupy_list) {
- while (*occupy_list != REFRESH_EOL && sidebar_entry.PlacementListLength < MAX_OCCUPY_CELLS) {
- sidebar_entry.PlacementList[sidebar_entry.PlacementListLength] = *occupy_list;
- sidebar_entry.PlacementListLength++;
- occupy_list++;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- } else {
-
-
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
-
- SidebarGlyphxClass *context_sidebar = DLLExportClass::Get_Current_Context_Sidebar();
-
- /*
- ** Get each sidebar column
- */
- for (int c = 0 ; c < 2 ; c++) {
-
- sidebar->EntryCount[c] = context_sidebar->Column[c].BuildableCount;
-
- /*
- ** Each production slot in the column
- */
- for (int b=0 ; b < context_sidebar->Column[c].BuildableCount ; b++) {
-
- CNCSidebarEntryStruct &sidebar_entry = sidebar->Entries[entry_index++];
- if ((entry_index + 1) * sizeof(CNCSidebarEntryStruct) + memory_needed > buffer_size) {
- return false;
- }
- memset(&sidebar_entry, 0, sizeof(sidebar_entry));
- sidebar_entry.AssetName[0] = 0;
- sidebar_entry.Type = UNKNOWN;
- sidebar_entry.BuildableID = context_sidebar->Column[c].Buildables[b].BuildableID;
- sidebar_entry.BuildableType = context_sidebar->Column[c].Buildables[b].BuildableType;
- sidebar_entry.BuildableViaCapture = context_sidebar->Column[c].Buildables[b].BuildableViaCapture;
- sidebar_entry.Fake = false;
-
- TechnoTypeClass const * tech = Fetch_Techno_Type(context_sidebar->Column[c].Buildables[b].BuildableType, context_sidebar->Column[c].Buildables[b].BuildableID);
-
- sidebar_entry.SuperWeaponType = SW_NONE;
- if (tech) {
- // Updated to apply and difficulty abd/or faction price modifier; See https://jaas.ea.com/browse/TDRA-6864
- // If this gets modified, also modify above for non-skirmish / non-multiplayer
- //
- // sidebar_entry.Cost = tech->Cost;
- sidebar_entry.Cost = tech->Cost * PlayerPtr->CostBias;
- sidebar_entry.PowerProvided = 0;
- sidebar_entry.BuildTime = tech->Time_To_Build(PlayerPtr->Class->House); // sidebar_entry.BuildTime = tech->Time_To_Build() / 60;
- strncpy(sidebar_entry.AssetName, tech->IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
- } else {
- sidebar_entry.Cost = 0;
- sidebar_entry.AssetName[0] = 0;
- }
-
- SuperClass* super_weapon = nullptr;
- bool isbusy = false;
- switch (context_sidebar->Column[c].Buildables[b].BuildableType) {
- case RTTI_INFANTRYTYPE:
- sidebar_entry.Type = INFANTRY_TYPE;
- isbusy = (PlayerPtr->InfantryFactory != -1);
- isbusy |= Infantry.Avail() <= 0;
- break;
-
- case RTTI_UNITTYPE:
- isbusy = (PlayerPtr->UnitFactory != -1);
- isbusy |= Units.Avail() <= 0;
- sidebar_entry.Type = UNIT_TYPE;
- break;
-
- case RTTI_AIRCRAFTTYPE:
- isbusy = (PlayerPtr->AircraftFactory != -1);
- isbusy |= Aircraft.Avail() <= 0;
- sidebar_entry.Type = AIRCRAFT_TYPE;
- break;
-
- case RTTI_BUILDINGTYPE:
- {
- isbusy = (PlayerPtr->BuildingFactory != -1);
- isbusy |= Buildings.Avail() <= 0;
- sidebar_entry.Type = BUILDING_TYPE;
- const BuildingTypeClass* build_type = static_cast<const BuildingTypeClass*>(tech);
- sidebar_entry.PowerProvided = build_type->Power - build_type->Drain;
- sidebar_entry.Fake = build_type->IsFake;
- break;
- }
- case RTTI_VESSELTYPE:
- isbusy = (PlayerPtr->VesselFactory != -1);
- isbusy |= Vessels.Avail() <= 0;
- sidebar_entry.Type = VESSEL_TYPE;
- break;
- default:
- sidebar_entry.Type = UNKNOWN;
- break;
- case RTTI_SPECIAL:
- Fill_Sidebar_Entry_From_Special_Weapon(sidebar_entry, super_weapon, (SpecialWeaponType)sidebar_entry.BuildableID);
- break;
- }
- if (super_weapon != nullptr)
- {
- sidebar_entry.Progress = (float)super_weapon->Anim_Stage() / (float)SuperClass::ANIMATION_STAGES;
- sidebar_entry.Completed = super_weapon->Is_Ready();
- sidebar_entry.Constructing = super_weapon->Anim_Stage() != SuperClass::ANIMATION_STAGES;
- sidebar_entry.ConstructionOnHold = false;
- sidebar_entry.PlacementListLength = 0;
- sidebar_entry.PowerProvided = 0;
- sidebar_entry.BuildTime = super_weapon->Get_Recharge_Time();
- }
- else
- {
- int fnumber = context_sidebar->Column[c].Buildables[b].Factory;
- FactoryClass * factory = NULL;
- if (tech && fnumber != -1) {
- factory = Factories.Raw_Ptr(fnumber);
- }
-
- sidebar_entry.Completed = false;
- sidebar_entry.Constructing = false;
- sidebar_entry.ConstructionOnHold = false;
- sidebar_entry.Progress = 0.0f;
- sidebar_entry.Busy = isbusy;
- sidebar_entry.PlacementListLength = 0;
-
- if (factory) {
- if (factory->Is_Building()) {
- sidebar_entry.Constructing = true;
- sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
- sidebar_entry.Completed = factory->Has_Completed();
- }
- else {
- sidebar_entry.Completed = factory->Has_Completed();
- if (!sidebar_entry.Completed)
- {
- sidebar_entry.ConstructionOnHold = true;
- sidebar_entry.Progress = (float)factory->Completion() / (float)FactoryClass::STEP_COUNT;
- }
- if (sidebar_entry.Completed && sidebar_entry.Type == BUILDING_TYPE) {
- if (tech) {
- BuildingTypeClass *building_type = (BuildingTypeClass*)tech;
- short const *occupy_list = building_type->Occupy_List(true);
- if (occupy_list) {
- while (*occupy_list != REFRESH_EOL && sidebar_entry.PlacementListLength < MAX_OCCUPY_CELLS) {
- sidebar_entry.PlacementList[sidebar_entry.PlacementListLength] = *occupy_list;
- sidebar_entry.PlacementListLength++;
- occupy_list++;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return true;
- }
- void DLLExportClass::Convert_Action_Type(ActionType type, ObjectClass* object, TARGET target, DllActionTypeEnum& dll_type)
- {
- switch (type)
- {
- case ACTION_NONE:
- default:
- dll_type = DAT_NONE;
- break;
- case ACTION_MOVE:
- dll_type = DAT_MOVE;
- break;
- case ACTION_NOMOVE:
- dll_type = DAT_NOMOVE;
- break;
- case ACTION_ENTER:
- dll_type = DAT_ENTER;
- break;
- case ACTION_SELF:
- dll_type = DAT_SELF;
- break;
- case ACTION_ATTACK:
- if (Target_Legal(target) && (object != NULL) && object->Is_Techno() && ((TechnoClass*)object)->In_Range(target, 0)) {
- dll_type = DAT_ATTACK;
- }
- else {
- dll_type = DAT_ATTACK_OUT_OF_RANGE;
- }
- break;
- case ACTION_GUARD_AREA:
- dll_type = DAT_GUARD;
- break;
- case ACTION_HARVEST:
- dll_type = DAT_ATTACK;
- break;
- case ACTION_SELECT:
- case ACTION_TOGGLE_SELECT:
- dll_type = DAT_SELECT;
- break;
- case ACTION_CAPTURE:
- dll_type = DAT_CAPTURE;
- break;
- case ACTION_DAMAGE:
- dll_type = DAT_DAMAGE;
- break;
- case ACTION_SABOTAGE:
- dll_type = DAT_SABOTAGE;
- break;
- case ACTION_HEAL:
- dll_type = DAT_HEAL;
- break;
- case ACTION_TOGGLE_PRIMARY:
- dll_type = DAT_TOGGLE_PRIMARY;
- break;
- case ACTION_NO_DEPLOY:
- dll_type = DAT_CANT_DEPLOY;
- break;
- case ACTION_GREPAIR:
- dll_type = DAT_REPAIR;
- break;
- case ACTION_NO_GREPAIR:
- dll_type = DAT_CANT_REPAIR;
- break;
- }
- }
- void DLLExportClass::Convert_Special_Weapon_Type(SpecialWeaponType weapon_type, DllSuperweaponTypeEnum& dll_weapon_type, char* weapon_name)
- {
- switch (weapon_type)
- {
- case SPC_SONAR_PULSE:
- dll_weapon_type = SW_SONAR_PULSE;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_SonarPulse", 16);
- }
- break;
- case SPC_NUCLEAR_BOMB:
- dll_weapon_type = SW_NUKE;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_Nuke", 16);
- }
- break;
- case SPC_CHRONOSPHERE:
- dll_weapon_type = SW_CHRONOSPHERE;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_Chrono", 16);
- }
- break;
- case SPC_PARA_BOMB:
- dll_weapon_type = SW_PARA_BOMB;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_ParaBomb", 16);
- }
- break;
- case SPC_PARA_INFANTRY:
- dll_weapon_type = SW_PARA_INFANTRY;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_ParaInfantry", 16);
- }
- break;
- case SPC_SPY_MISSION:
- dll_weapon_type = SW_SPY_MISSION;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_SpyMission", 16);
- }
- break;
- case SPC_IRON_CURTAIN:
- dll_weapon_type = SW_IRON_CURTAIN;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_IronCurtain", 16);
- }
- break;
- case SPC_GPS:
- dll_weapon_type = SW_GPS;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_GPS", 16);
- }
- break;
- case SPC_CHRONO2:
- dll_weapon_type = SW_CHRONOSPHERE_DESTINATION;
- if (weapon_name != NULL)
- {
- strncpy(weapon_name, "SW_Chrono2", 16);
- }
- break;
- default:
- dll_weapon_type = SW_UNKNOWN;
- if (weapon_name != NULL)
- {
- weapon_name[0] = '\0';
- }
- break;
- }
- }
- void DLLExportClass::Fill_Sidebar_Entry_From_Special_Weapon(CNCSidebarEntryStruct& sidebar_entry_out, SuperClass*& super_weapon_out, SpecialWeaponType weapon_type)
- {
- sidebar_entry_out.Type = SPECIAL;
- switch (weapon_type)
- {
- case SPC_SONAR_PULSE:
- case SPC_NUCLEAR_BOMB:
- case SPC_CHRONOSPHERE:
- case SPC_PARA_BOMB:
- case SPC_PARA_INFANTRY:
- case SPC_SPY_MISSION:
- case SPC_IRON_CURTAIN:
- case SPC_GPS:
- case SPC_CHRONO2:
- Convert_Special_Weapon_Type(weapon_type, sidebar_entry_out.SuperWeaponType, sidebar_entry_out.AssetName);
- break;
- default:
- sidebar_entry_out.SuperWeaponType = SW_UNKNOWN;
- sidebar_entry_out.Type = UNKNOWN;
- super_weapon_out = nullptr;
- return;
- }
- super_weapon_out = &(PlayerPtr->SuperWeapon[weapon_type]);
- }
- static const int _map_width_shift_bits = 7;
- void DLLExportClass::Calculate_Placement_Distances(BuildingTypeClass* placement_type, unsigned char* placement_distance)
- {
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_width < MAP_MAX_CELL_WIDTH) {
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- if (map_cell_height < MAP_MAX_CELL_WIDTH) {
- map_cell_height++;
- }
- static const FacingType _scan_facings[] = {
- FACING_E,
- FACING_S,
- FACING_W,
- FACING_N
- };
- memset(placement_distance, 255U, MAP_CELL_TOTAL);
- for (int y = 0; y < map_cell_height; y++) {
- for (int x = 0; x < map_cell_width; x++) {
- CELL cell = (CELL)map_cell_x + x + ((map_cell_y + y) << _map_width_shift_bits);
- BuildingClass* base = (BuildingClass*)Map[cell].Cell_Find_Object(RTTI_BUILDING);
- if ((base && base->House->Class->House == PlayerPtr->Class->House && base->Class->IsBase) ||
- ((placement_type->IsWall || ((Map[cell].Smudge != SMUDGE_NONE) && SmudgeTypeClass::As_Reference(Map[cell].Smudge).IsBib)) &&
- Map[cell].Owner == PlayerPtr->Class->House)) {
- placement_distance[cell] = 0U;
- CELL startcell = cell;
- for (unsigned char distance = 1U; distance <= (placement_type->Adjacent + 1U); distance++) {
- startcell = Adjacent_Cell(startcell, FACING_NW);
- CELL scancell = startcell;
- for (int i = 0; i < ARRAY_SIZE(_scan_facings); i++) {
- CELL nextcell = scancell;
- for (unsigned char scan = 0U; scan <= (distance * 2U); scan++) {
- scancell = nextcell;
- if (Map.In_Radar(scancell)) {
- placement_distance[scancell] = min(placement_distance[scancell], distance);
- }
- nextcell = Adjacent_Cell(scancell, _scan_facings[i]);
- }
- }
- }
- }
- }
- }
- }
- void Recalculate_Placement_Distances()
- {
- DLLExportClass::Recalculate_Placement_Distances();
- }
- void DLLExportClass::Recalculate_Placement_Distances()
- {
- if (PlacementType[CurrentLocalPlayerIndex] != NULL) {
- Calculate_Placement_Distances(PlacementType[CurrentLocalPlayerIndex], PlacementDistance[CurrentLocalPlayerIndex]);
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Placement_State -- Get a snapshot of legal validity of placing a structure on all map cells
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/4/2019 3:11PM - ST
- **************************************************************************************************/
- bool DLLExportClass::Get_Placement_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- if (PlacementType[CurrentLocalPlayerIndex] == NULL) {
- return false;
- }
- CNCPlacementInfoStruct *placement_info = (CNCPlacementInfoStruct*) buffer_in;
-
- unsigned int memory_needed = sizeof(*placement_info); // Base amount needed. Will need more depending on how many entries there are
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_width < MAP_MAX_CELL_WIDTH) {
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- if (map_cell_height < MAP_MAX_CELL_WIDTH) {
- map_cell_height++;
- }
- memory_needed += map_cell_width * map_cell_height * sizeof(CNCPlacementCellInfoStruct);
- if (memory_needed + 128 >= buffer_size) {
- return false;
- }
- placement_info->Count = map_cell_width * map_cell_height;
- int index = 0;
- for (int y=0 ; y < map_cell_height ; y++) {
- for (int x=0 ; x < map_cell_width ; x++) {
- CELL cell = (CELL) map_cell_x + x + ((map_cell_y + y) << _map_width_shift_bits);
- bool pass = Passes_Proximity_Check(cell, PlacementType[CurrentLocalPlayerIndex], PlacementDistance[CurrentLocalPlayerIndex]);
- CellClass * cellptr = &Map[cell];
- bool clear = cellptr->Is_Clear_To_Build(PlacementType[CurrentLocalPlayerIndex]->Speed);
- CNCPlacementCellInfoStruct &placement_cell_info = placement_info->CellInfo[index++];
- placement_cell_info.PassesProximityCheck = pass;
- placement_cell_info.GenerallyClear = clear;
- }
- }
- Map.ZoneOffset = 0;
- return true;
- }
- bool DLLExportClass::Passes_Proximity_Check(CELL cell_in, BuildingTypeClass *placement_type, unsigned char* placement_distance)
- {
-
- /*
- ** Scan through all cells that the building foundation would cover. If any adjacent
- ** cells to these are of friendly persuasion, then consider the proximity check to
- ** have been a success.
- */
- short const *occupy_list = placement_type->Occupy_List(true);
-
- while (*occupy_list != REFRESH_EOL) {
- CELL center_cell = cell_in + *occupy_list++;
- if (!Map.In_Radar(center_cell)) {
- return false;
- }
- if (placement_distance[center_cell] <= (placement_type->Adjacent + 1)) {
- return true;
- }
- }
- return false;
- }
- /**************************************************************************************************
- * DLLExportClass::Start_Construction -- Start sidebar construction
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/29/2019 11:37AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Start_Construction(uint64 player_id, int buildable_type, int buildable_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- if (GAME_TO_PLAY == GAME_NORMAL) {
- return Construction_Action(SIDEBAR_REQUEST_START_CONSTRUCTION, player_id, buildable_type, buildable_id);
- }
- return MP_Construction_Action(SIDEBAR_REQUEST_START_CONSTRUCTION, player_id, buildable_type, buildable_id);
- }
- /**************************************************************************************************
- * DLLExportClass::Hold_Construction -- Pause sidebar construction
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 6/12/2019 JAS
- **************************************************************************************************/
- bool DLLExportClass::Hold_Construction(uint64 player_id, int buildable_type, int buildable_id)
- {
- if (!DLLExportClass::Set_Player_Context(player_id))
- {
- return false;
- }
- if (GAME_TO_PLAY == GAME_NORMAL) {
- return Construction_Action(SIDEBAR_REQUEST_HOLD_CONSTRUCTION, player_id, buildable_type, buildable_id);
- }
- return MP_Construction_Action(SIDEBAR_REQUEST_HOLD_CONSTRUCTION, player_id, buildable_type, buildable_id);
- }
- /**************************************************************************************************
- * DLLExportClass::Cancel_Construction -- Stop sidebar construction
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 6/12/2019 JAS
- **************************************************************************************************/
- bool DLLExportClass::Cancel_Construction(uint64 player_id, int buildable_type, int buildable_id)
- {
- if (!DLLExportClass::Set_Player_Context(player_id))
- {
- return false;
- }
- return Cancel_Placement(player_id, buildable_type, buildable_id) &&
- ((GAME_TO_PLAY == GAME_NORMAL) ?
- Construction_Action(SIDEBAR_REQUEST_CANCEL_CONSTRUCTION, player_id, buildable_type, buildable_id) :
- MP_Construction_Action(SIDEBAR_REQUEST_CANCEL_CONSTRUCTION, player_id, buildable_type, buildable_id));
- }
- /**************************************************************************************************
- * DLLExportClass::Construction_Action -- Reproduce actions on the sidebar
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/29/2019 11:37AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id)
- {
-
- /*
- **
- ** Based on SidebarClass::StripClass::SelectClass::Action
- **
- ** Most of this code is validating that the game is in the correct state to be able to act on a sidebar icon
- **
- */
-
- for (int c = 0 ; c < 2 ; c++) {
-
- /*
- ** Each production slot in the column
- */
- for (int b=0 ; b < Map.Column[c].BuildableCount ; b++) {
- if (Map.Column[c].Buildables[b].BuildableID == buildable_id) {
- if (Map.Column[c].Buildables[b].BuildableType == buildable_type) {
-
- int fnumber = Map.Column[c].Buildables[b].Factory;
- int spc = 0;
- ObjectTypeClass const * choice = NULL;
- if (buildable_type != RTTI_SPECIAL) {
- choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
- } else {
- spc = buildable_id;
- }
- FactoryClass * factory = PlayerPtr->Fetch_Factory((RTTIType)buildable_type);
- if (fnumber != -1) {
- factory = Factories.Raw_Ptr(fnumber);
- }
- if (spc == 0 && choice) {
- if (fnumber == -1 && factory != NULL) {
- return(false);
- }
- if (factory) {
- switch (construction_action)
- {
- case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
- On_Speech(PlayerPtr, VOX_CANCELED); // Speak(VOX_CANCELED);
- OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
- break;
- case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
- if (factory->Is_Building())
- {
- On_Speech(PlayerPtr, VOX_SUSPENDED); // Speak(VOX_SUSPENDED);
- OutList.Add(EventClass(EventClass::SUSPEND, (RTTIType)buildable_type, buildable_id));
- }
- break;
- default:
- /*
- ** If this object is currently being built, then give a scold sound and text and then
- ** bail.
- */
- if (factory->Is_Building()) {
- On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
- return false;
- }
- else {
- /*
- ** If production has completed, then attempt to have the object exit
- ** the factory or go into placement mode.
- */
- if (factory->Has_Completed()) {
- TechnoClass * pending = factory->Get_Object();
- if (!pending && factory->Get_Special_Item()) {
- // TO_DO
- //Map.IsTargettingMode = true;
- }
- else {
- BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
- if (!builder) {
- OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
- On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
- }
- else {
- /*
- ** If the completed object is a building, then change the
- ** game state into building placement mode. This fact is
- ** not transmitted to any linked computers until the moment
- ** the building is actually placed down.
- */
- if (pending->What_Am_I() == RTTI_BUILDING) {
- if (construction_action == SIDEBAR_REQUEST_START_PLACEMENT) {
- PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
- }
- }
- else {
- /*
- ** For objects that can leave the factory under their own
- ** power, queue this event and process through normal house
- ** production channels.
- */
- //OutList.Add(EventClass(EventClass::PLACE, otype, -1));
- }
- }
- }
- }
- else {
- /*
- ** The factory must have been in a suspended state. Resume construction
- ** normally.
- */
- if (construction_action == SIDEBAR_REQUEST_START_CONSTRUCTION) {
- if ((RTTIType)buildable_type == RTTI_INFANTRYTYPE)
- {
- On_Speech(PlayerPtr, VOX_TRAINING); // Speak(VOX_TRAINING);
- }
- else
- {
- On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
- }
- OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
- return true;
- }
- }
- }
- }
- } else {
- switch (construction_action)
- {
- case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
- case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
- break;
- default:
- /*
- ** If this side strip is already busy with production, then ignore the
- ** input and announce this fact.
- */
- if ((RTTIType)buildable_type == RTTI_INFANTRYTYPE)
- {
- On_Speech(PlayerPtr, VOX_TRAINING); // Speak(VOX_TRAINING);
- }
- else
- {
- On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
- }
- OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
- /*
- ** Execute immediately so we get the sidebar feedback
- */
- Queue_AI();
- return true;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
- /**************************************************************************************************
- * DLLExportClass::MP_Construction_Action -- Reproduce actions on the sidebar
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/26/2019 1:02PM - ST
- **************************************************************************************************/
- bool DLLExportClass::MP_Construction_Action(SidebarRequestEnum construction_action, uint64 player_id, int buildable_type, int buildable_id)
- {
-
- /*
- **
- ** Based on SidebarClass::StripClass::SelectClass::Action
- **
- ** Most of this code is validating that the game is in the correct state to be able to act on a sidebar icon
- **
- */
-
- SidebarGlyphxClass *context_sidebar = DLLExportClass::Get_Current_Context_Sidebar();
-
- for (int c = 0 ; c < 2 ; c++) {
-
- /*
- ** Each production slot in the column
- */
- for (int b=0 ; b < context_sidebar->Column[c].BuildableCount ; b++) {
- if (context_sidebar->Column[c].Buildables[b].BuildableID == buildable_id) {
- if (context_sidebar->Column[c].Buildables[b].BuildableType == buildable_type) {
-
- int genfactory = -1;
- switch (buildable_type) {
- case RTTI_INFANTRYTYPE:
- genfactory = PlayerPtr->InfantryFactory;
- break;
- case RTTI_UNITTYPE:
- genfactory = PlayerPtr->UnitFactory;
- break;
- case RTTI_AIRCRAFTTYPE:
- genfactory = PlayerPtr->AircraftFactory;
- break;
- case RTTI_BUILDINGTYPE:
- genfactory = PlayerPtr->BuildingFactory;
- break;
- default:
- genfactory = -1;
- break;
- }
- int fnumber = context_sidebar->Column[c].Buildables[b].Factory;
- int spc = 0;
- ObjectTypeClass const * choice = NULL;
- if (buildable_type != RTTI_SPECIAL) {
- choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
- } else {
- spc = buildable_id;
- }
- FactoryClass * factory = NULL;
- if (fnumber != -1) {
- factory = Factories.Raw_Ptr(fnumber);
- }
- if (spc == 0 && choice) {
- /*
- ** If there is already a factory attached to this strip but the player didn't click
- ** on the icon that has the attached factory, then say that the factory is busy and
- ** ignore the click.
- */
- if (fnumber == -1 && genfactory != -1) {
- On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
- return(false);
- }
- if (factory) {
- switch (construction_action)
- {
- case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
- On_Speech(PlayerPtr, VOX_CANCELED); // Speak(VOX_CANCELED);
- OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
- break;
- case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
- if (factory->Is_Building())
- {
- On_Speech(PlayerPtr, VOX_SUSPENDED); // Speak(VOX_SUSPENDED);
- OutList.Add(EventClass(EventClass::SUSPEND, (RTTIType)buildable_type, buildable_id));
- }
- break;
- default:
- /*
- ** If this object is currently being built, then give a scold sound and text and then
- ** bail.
- */
- if (factory->Is_Building()) {
- On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
- return false;
- }
- else {
- /*
- ** If production has completed, then attempt to have the object exit
- ** the factory or go into placement mode.
- */
- if (factory->Has_Completed()) {
- TechnoClass * pending = factory->Get_Object();
- if (!pending && factory->Get_Special_Item()) {
- // TO_DO
- //Map.IsTargettingMode = true;
- }
- else {
- BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
- if (!builder) {
- On_Speech(PlayerPtr, VOX_NO_FACTORY); //Speak(VOX_NO_FACTORY); // "Cannot Comply"
- OutList.Add(EventClass(EventClass::ABANDON, (RTTIType)buildable_type, buildable_id));
- //Speak(VOX_NO_FACTORY);
- }
- else {
- /*
- ** If the completed object is a building, then change the
- ** game state into building placement mode. This fact is
- ** not transmitted to any linked computers until the moment
- ** the building is actually placed down.
- */
- if (pending->What_Am_I() == RTTI_BUILDING) {
- if (construction_action == SIDEBAR_REQUEST_START_PLACEMENT) {
- if (DLLExportClass::Legacy_Render_Enabled()) {
- PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
- } else {
- Unselect_All();
- }
- }
- }
- else {
- /*
- ** For objects that can leave the factory under their own
- ** power, queue this event and process through normal house
- ** production channels.
- */
- //OutList.Add(EventClass(EventClass::PLACE, otype, -1));
- }
- }
- }
- }
- else {
- /*
- ** The factory must have been in a suspended state. Resume construction
- ** normally.
- */
- if (construction_action == SIDEBAR_REQUEST_START_CONSTRUCTION) {
- if ((RTTIType)buildable_type == RTTI_INFANTRYTYPE)
- {
- On_Speech(PlayerPtr, VOX_TRAINING); // Speak(VOX_TRAINING);
- }
- else
- {
- On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
- }
- OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
- return true;
- }
- }
- }
- break;
- }
- } else {
- switch (construction_action)
- {
- case SIDEBAR_REQUEST_CANCEL_CONSTRUCTION:
- case SIDEBAR_REQUEST_HOLD_CONSTRUCTION:
- break;
- default:
- /*
- **
- */
- if ((RTTIType)buildable_type == RTTI_INFANTRYTYPE)
- {
- On_Speech(PlayerPtr, VOX_TRAINING); // Speak(VOX_TRAINING);
- }
- else
- {
- On_Speech(PlayerPtr, VOX_BUILDING); // Speak(VOX_BUILDING);
- }
- OutList.Add(EventClass(EventClass::PRODUCE, (RTTIType)buildable_type, buildable_id));
- /*
- ** Execute immediately so we get the sidebar feedback
- */
- DLLExportClass::Glyphx_Queue_AI();
- return true;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
- /**************************************************************************************************
- * DLLExportClass::Start_Placement -- Start placing a completed structure
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/29/2019 11:37AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Start_Placement(uint64 player_id, int buildable_type, int buildable_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- BuildingClass *building = Get_Pending_Placement_Object(player_id, buildable_type, buildable_id);
- if (building) {
-
- TechnoTypeClass const * tech = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
- if (tech) {
- BuildingTypeClass *building_type = (BuildingTypeClass*) tech;
- //short const *occupy_list = building_type->Get_Occupy_List(true);
- PlacementType[CurrentLocalPlayerIndex] = building_type;
- Recalculate_Placement_Distances();
- if (GAME_TO_PLAY == GAME_NORMAL) {
- return Construction_Action(SIDEBAR_REQUEST_START_PLACEMENT, player_id, buildable_type, buildable_id);
- }
- return MP_Construction_Action(SIDEBAR_REQUEST_START_PLACEMENT, player_id, buildable_type, buildable_id);
- }
- }
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Cancel_Placement -- Cancel placing a completed structure
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/7/2019 10:52AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Cancel_Placement(uint64 player_id, int buildable_type, int buildable_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
- PlacementType[CurrentLocalPlayerIndex] = NULL;
- Map.PendingObjectPtr = 0;
- Map.PendingObject = 0;
- Map.PendingHouse = HOUSE_NONE;
- Map.IsTargettingMode = SPC_NONE;
- Map.Set_Cursor_Shape(0);
- return true;
- }
-
- /**************************************************************************************************
- * DLLExportClass::Place -- Place a completed structure down
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/6/2019 11:51AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Place(uint64 player_id, int buildable_type, int buildable_id, short cell_x, short cell_y)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
-
- static const int _map_width_shift_bits = 7;
- BuildingClass *building = Get_Pending_Placement_Object(player_id, buildable_type, buildable_id);
- if (building) {
-
- TechnoTypeClass const * tech = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
- if (tech) {
- BuildingTypeClass *building_type = (BuildingTypeClass*) tech;
- //short const *occupy_list = building_type->Get_Occupy_List(true);
- PlacementType[CurrentLocalPlayerIndex] = building_type;
- /*
- ** The cell coordinates passed in will be relative to the playable area that the client knows about
- */
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- CELL cell = (CELL) (map_cell_x + cell_x) + ( (map_cell_y + cell_y) << _map_width_shift_bits);
- /*
- ** Call the place directly instead of queueing it, so we can evaluate the return code.
- */
- if (PlayerPtr->Place_Object(building->What_Am_I(), cell + Map.ZoneOffset)) {
- PlacementType[CurrentLocalPlayerIndex] = NULL;
- }
- }
- }
- return true;
- }
- BuildingClass *DLLExportClass::Get_Pending_Placement_Object(uint64 player_id, int buildable_type, int buildable_id)
- {
- /*
- **
- ** Based on SidebarClass::StripClass::SelectClass::Action
- **
- **
- */
- if (GAME_TO_PLAY == GAME_NORMAL) {
-
- for (int c = 0 ; c < 2 ; c++) {
-
- /*
- ** Each production slot in the column
- */
- for (int b=0 ; b < Map.Column[c].BuildableCount ; b++) {
- if (Map.Column[c].Buildables[b].BuildableID == buildable_id) {
- if (Map.Column[c].Buildables[b].BuildableType == buildable_type) {
-
-
- int genfactory = -1;
- switch (buildable_type) {
- case RTTI_INFANTRYTYPE:
- genfactory = PlayerPtr->InfantryFactory;
- break;
- case RTTI_UNITTYPE:
- genfactory = PlayerPtr->UnitFactory;
- break;
- case RTTI_AIRCRAFTTYPE:
- genfactory = PlayerPtr->AircraftFactory;
- break;
- case RTTI_BUILDINGTYPE:
- genfactory = PlayerPtr->BuildingFactory;
- break;
- default:
- genfactory = -1;
- break;
- }
- int fnumber = Map.Column[c].Buildables[b].Factory;
- int spc = 0;
- ObjectTypeClass const * choice = NULL;
- if (buildable_type != RTTI_SPECIAL) {
- choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
- } else {
- spc = buildable_id;
- }
- FactoryClass * factory = NULL;
- if (fnumber != -1) {
- factory = Factories.Raw_Ptr(fnumber);
- }
- if (spc == 0 && choice) {
- if (fnumber == -1 && genfactory != -1) {
- return(NULL);
- }
- if (factory) {
- /*
- ** If production has completed, then attempt to have the object exit
- ** the factory or go into placement mode.
- */
- if (factory->Has_Completed()) {
-
- TechnoClass * pending = factory->Get_Object();
- if (!pending && factory->Get_Special_Item()) {
- //Map.IsTargettingMode = true;
- } else {
- BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
- if (!builder) {
- OutList.Add(EventClass(EventClass::ABANDON, buildable_type, buildable_id));
- On_Speech(PlayerPtr, VOX_NO_FACTORY); // Speak(VOX_NO_FACTORY);
- } else {
- /*
- ** If the completed object is a building, then change the
- ** game state into building placement mode. This fact is
- ** not transmitted to any linked computers until the moment
- ** the building is actually placed down.
- */
- if (pending->What_Am_I() == RTTI_BUILDING) {
- return (BuildingClass*)pending;
- //PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- } else {
-
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
-
-
- SidebarGlyphxClass *context_sidebar = DLLExportClass::Get_Current_Context_Sidebar();
-
- for (int c = 0 ; c < 2 ; c++) {
-
- /*
- ** Each production slot in the column
- */
- for (int b=0 ; b < context_sidebar->Column[c].BuildableCount ; b++) {
- if (context_sidebar->Column[c].Buildables[b].BuildableID == buildable_id) {
- if (context_sidebar->Column[c].Buildables[b].BuildableType == buildable_type) {
-
-
- int genfactory = -1;
- switch (buildable_type) {
- case RTTI_INFANTRYTYPE:
- genfactory = PlayerPtr->InfantryFactory;
- break;
- case RTTI_UNITTYPE:
- genfactory = PlayerPtr->UnitFactory;
- break;
- case RTTI_AIRCRAFTTYPE:
- genfactory = PlayerPtr->AircraftFactory;
- break;
- case RTTI_BUILDINGTYPE:
- genfactory = PlayerPtr->BuildingFactory;
- break;
- default:
- genfactory = -1;
- break;
- }
- int fnumber = context_sidebar->Column[c].Buildables[b].Factory;
- int spc = 0;
- ObjectTypeClass const * choice = NULL;
- if (buildable_type != RTTI_SPECIAL) {
- choice = Fetch_Techno_Type((RTTIType)buildable_type, buildable_id);
- } else {
- spc = buildable_id;
- }
- FactoryClass * factory = NULL;
- if (fnumber != -1) {
- factory = Factories.Raw_Ptr(fnumber);
- }
- if (spc == 0 && choice) {
- if (fnumber == -1 && genfactory != -1) {
- return(NULL);
- }
- if (factory) {
- /*
- ** If production has completed, then attempt to have the object exit
- ** the factory or go into placement mode.
- */
- if (factory->Has_Completed()) {
-
- TechnoClass * pending = factory->Get_Object();
- if (!pending && factory->Get_Special_Item()) {
- //Map.IsTargettingMode = true;
- } else {
- BuildingClass * builder = pending->Who_Can_Build_Me(false, false);
- if (!builder) {
- OutList.Add(EventClass(EventClass::ABANDON, buildable_type, buildable_id));
- On_Speech(PlayerPtr, VOX_NO_FACTORY); // Speak(VOX_NO_FACTORY);
- } else {
- /*
- ** If the completed object is a building, then change the
- ** game state into building placement mode. This fact is
- ** not transmitted to any linked computers until the moment
- ** the building is actually placed down.
- */
- if (pending->What_Am_I() == RTTI_BUILDING) {
- return (BuildingClass*)pending;
- //PlayerPtr->Manual_Place(builder, (BuildingClass *)pending);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return NULL;
- }
- /**************************************************************************************************
- * DLLExportClass::Place_Super_Weapon
- *
- * History:
- **************************************************************************************************/
- bool DLLExportClass::Place_Super_Weapon(uint64 player_id, int buildable_type, int buildable_id, int x, int y)
- {
- if (buildable_type != RTTI_SPECIAL)
- {
- return false;
- }
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- SpecialWeaponType weapon_type = (SpecialWeaponType)buildable_id;
- OutList.Add(EventClass(EventClass::SPECIAL_PLACE, weapon_type, cell));
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Create_Control_Group
- *
- * History:
- **************************************************************************************************/
- bool DLLExportClass::Create_Control_Group(unsigned char control_group_index)
- {
- Handle_Team(control_group_index, 2);
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Add_To_Control_Group
- *
- * History:
- **************************************************************************************************/
- bool DLLExportClass::Add_To_Control_Group(unsigned char control_group_index)
- {
- Handle_Team(control_group_index, 1);
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Toggle_Control_Group_Selection
- *
- * History:
- **************************************************************************************************/
- bool DLLExportClass::Toggle_Control_Group_Selection(unsigned char control_group_index)
- {
- Handle_Team(control_group_index, 0);
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Shroud_State -- Get a snapshot of the shroud for the given player
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/12/2019 3:44PM - ST
- **************************************************************************************************/
- bool DLLExportClass::Get_Shroud_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
-
- /*
- ** Apply mobile gap generators
- */
- static unsigned int _shroud_bits[UNIT_MAX];
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- for (int index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj->Class->IsGapper && obj->IsActive && obj->Strength) {
- if (!obj->House->Is_Ally(PlayerPtr)) {
- _shroud_bits[index] = obj->Apply_Temporary_Jamming_Shroud(PlayerPtr);
- }
- }
- }
- }
- CNCShroudStruct *shroud = (CNCShroudStruct*) buffer_in;
-
- unsigned int memory_needed = sizeof(*shroud) + 256; // Base amount needed. Will need more depending on how many entries there are
- int entry_index = 0;
- /*
- **
- ** Based loosely on DisplayClass::Redraw_Icons
- **
- **
- */
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_width < MAP_MAX_CELL_WIDTH) {
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
- map_cell_height++;
- }
- for (int y = 0; y < map_cell_height; y++) {
- for (int x = 0; x < map_cell_width; x++) {
- CELL cell = XY_Cell(map_cell_x + x, map_cell_y + y);
- COORDINATE coord = Cell_Coord(cell) & 0xFF00FF00L;
- memory_needed += sizeof(CNCShroudEntryStruct);
- if (memory_needed >= buffer_size) {
- return false;
- }
- int xpixel;
- int ypixel;
- Map.Coord_To_Pixel(coord, xpixel, ypixel);
- CellClass * cellptr = &Map[Coord_Cell(coord)];
- CNCShroudEntryStruct &shroud_entry = shroud->Entries[entry_index];
- shroud_entry.IsVisible = cellptr->Is_Visible(PlayerPtr);
- shroud_entry.IsMapped = cellptr->Is_Mapped(PlayerPtr);
- shroud_entry.IsJamming = cellptr->Is_Jamming(PlayerPtr);
- //shroud_entry.IsVisible = cellptr->IsVisible;
- //shroud_entry.IsMapped = cellptr->IsMapped;
- shroud_entry.ShadowIndex = -1;
- if (shroud_entry.IsMapped) {
- if (!shroud_entry.IsVisible) {
- shroud_entry.ShadowIndex = (char)Map.Cell_Shadow(cell, PlayerPtr);
- }
- }
- entry_index++;
- }
- }
- shroud->Count = entry_index;
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- for (int index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj->Class->IsGapper && obj->IsActive && obj->Strength) {
- if (!obj->House->Is_Ally(PlayerPtr)) {
- obj->Unapply_Temporary_Jamming_Shroud(PlayerPtr, _shroud_bits[index]);
- }
- }
- }
- }
-
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Occupier_State -- Get the occupier state for this player
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 10/25/2019 - SKY
- **************************************************************************************************/
- bool DLLExportClass::Get_Occupier_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- UNREFERENCED_PARAMETER(player_id);
- CNCOccupierHeaderStruct* occupiers = (CNCOccupierHeaderStruct*)buffer_in;
- CNCOccupierEntryHeaderStruct* entry = reinterpret_cast<CNCOccupierEntryHeaderStruct*>(occupiers + 1U);
- occupiers->Count = 0;
- unsigned int memory_needed = sizeof(CNCOccupierHeaderStruct);
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_width < MAP_MAX_CELL_WIDTH) {
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- if (map_cell_height < MAP_MAX_CELL_HEIGHT) {
- map_cell_height++;
- }
- for (int y = 0; y < map_cell_height; y++) {
- for (int x = 0; x < map_cell_width; x++, occupiers->Count++) {
- CELL cell = XY_Cell(map_cell_x + x, map_cell_y + y);
- CellClass * cellptr = &Map[cell];
- int occupier_count = 0;
- ObjectClass* optr = cellptr->Cell_Occupier();
- while (optr != NULL) {
- occupier_count++;
- optr = optr->Next;
- }
- memory_needed += sizeof(CNCOccupierEntryHeaderStruct) + (sizeof(CNCOccupierObjectStruct) * occupier_count);
- if (memory_needed >= buffer_size) {
- return false;
- }
- CNCOccupierObjectStruct* occupier = reinterpret_cast<CNCOccupierObjectStruct*>(entry + 1U);
- entry->Count = 0;
- optr = cellptr->Cell_Occupier();
- for (int i = 0; i < occupier_count; i++, occupier++, entry->Count++) {
- CNCObjectStruct object;
- Convert_Type(optr, object);
- occupier->Type = object.Type;
- occupier->ID = object.ID;
- optr = optr->Next;
- }
- entry = reinterpret_cast<CNCOccupierEntryHeaderStruct*>(occupier + 1U);
- }
- }
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Player_Info_State -- Get the multiplayer info for this player
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/22/2019 10:33AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Get_Player_Info_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return false;
- }
-
- CNCPlayerInfoStruct *player_info = (CNCPlayerInfoStruct*) buffer_in;
-
- unsigned int memory_needed = sizeof(*player_info) + 32; // A little extra for no reason
- if (memory_needed >= buffer_size) {
- return false;
- }
-
- player_info->GlyphxPlayerID = 0;
- if (PlayerPtr == NULL) {
- return false;;
- }
- if (Session.Players.Count() > CurrentLocalPlayerIndex) {
- strncpy(&player_info->Name[0], Session.Players[CurrentLocalPlayerIndex]->Name, MPLAYER_NAME_MAX);
- }
-
- player_info->Name[MPLAYER_NAME_MAX - 1] = 0; // Make sure it's terminated
- player_info->House = PlayerPtr->Class->House;
- player_info->AllyFlags = PlayerPtr->Get_Ally_Flags();
-
- if (Session.Players.Count() > CurrentLocalPlayerIndex) {
- player_info->ColorIndex = Session.Players[CurrentLocalPlayerIndex]->Player.Color;
- } else {
- player_info->ColorIndex = (PlayerPtr->Class->House == HOUSE_USSR) ? 2 : 1; // Fudge to a sensible color in campaign; 2 = red, 1 = blue
- }
-
- player_info->GlyphxPlayerID = player_id;
- player_info->HomeCellX = Cell_X(MultiplayerStartPositions[CurrentLocalPlayerIndex]);
- player_info->HomeCellY = Cell_Y(MultiplayerStartPositions[CurrentLocalPlayerIndex]);
- player_info->IsDefeated = PlayerPtr->IsDefeated;
- // Can see other players' power if ally (except for the player themself) or spying on a power plant
- // Can see other players' money if spying on a resource building
- player_info->SpiedPowerFlags = 0U;
- player_info->SpiedMoneyFlags = 0U;
- for (int i = 0; i < Houses.Count(); ++i) {
- HouseClass* house = Houses.Ptr(i);
- if ((house != nullptr) && house->IsActive && (house != PlayerPtr) && house->Is_Ally(PlayerPtr)) {
- player_info->SpiedPowerFlags |= 1U << house->Class->House;
- }
- }
- for (int i = 0; i < Buildings.Count(); ++i) {
- BuildingClass* building = Buildings.Ptr(i);
- if ((building != nullptr) && building->IsActive && (building->Spied_By() & (1U << PlayerPtr->Class->House))) {
- if ((*building == STRUCT_POWER) || (*building == STRUCT_ADVANCED_POWER)) {
- player_info->SpiedPowerFlags |= 1U << building->House->Class->House;
- } else if ((*building == STRUCT_REFINERY) || (*building == STRUCT_STORAGE)) {
- player_info->SpiedMoneyFlags |= 1U << building->House->Class->House;
- }
- }
- }
- // Populate spied data
- for (char house = 0; house < MAX_HOUSES; ++house) {
- HouseClass* hptr = HouseClass::As_Pointer((HousesType)house);
- if ((hptr != nullptr) && hptr->IsActive) {
- if (player_info->SpiedPowerFlags & (1U << house)) {
- player_info->SpiedInfo[house].Power = hptr->Power;
- player_info->SpiedInfo[house].Drain = hptr->Drain;
- }
- if (player_info->SpiedMoneyFlags & (1U << house)) {
- player_info->SpiedInfo[house].Money = hptr->Available_Money();
- }
- }
- }
- // Populate selection info
- if (CurrentObject.Count() > 0) {
- CNCObjectStruct object;
- Convert_Type(CurrentObject[0], object);
- player_info->SelectedID = object.ID;
- player_info->SelectedType = object.Type;
- const int left = Map.MapCellX;
- const int right = Map.MapCellX + Map.MapCellWidth - 1;
- const int top = Map.MapCellY;
- const int bottom = Map.MapCellY + Map.MapCellHeight - 1;
- // Use first object with a weapon, or first object if none
- ObjectClass* action_object = nullptr;
- for (int i = 0; i < CurrentObject.Count(); ++i) {
- ObjectClass* object = CurrentObject[i];
- if (object->Is_Techno()) {
- TechnoClass* techno = (TechnoClass*)object;
- if (techno->Techno_Type_Class()->PrimaryWeapon != NULL || techno->Techno_Type_Class()->SecondaryWeapon != NULL) {
- action_object = object;
- break;
- }
- }
- }
- if (action_object == nullptr) {
- action_object = CurrentObject[0];
- }
- int index = 0;
- for (int y = top; y <= bottom; ++y) {
- for (int x = left; x <= right; ++x, ++index) {
- 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]);
- }
- }
- player_info->ActionWithSelectedCount = Map.MapCellWidth * Map.MapCellHeight;
- }
- else {
- player_info->SelectedID = -1;
- player_info->SelectedType = UNKNOWN;
- player_info->ActionWithSelectedCount = 0U;
- }
- // Screen shake
- player_info->ScreenShake = PlayerPtr->ScreenShakeTime;
- // Radar jammed
- player_info->IsRadarJammed = Map.Get_Jammed(PlayerPtr);
- return true;
- };
- /**************************************************************************************************
- * DLLExportClass::Get_Dynamic_Map_State -- Get a snapshot of the smudges and overlays on the terrain
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/8/2019 10:45AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Get_Dynamic_Map_State(uint64 player_id, unsigned char *buffer_in, unsigned int buffer_size)
- {
- /*
- ** Get the player for this...
- */
- player_id;
- static int _call_count = 0;
- CNCDynamicMapStruct *dynamic_map = (CNCDynamicMapStruct*) buffer_in;
-
- unsigned int memory_needed = sizeof(*dynamic_map) + 256; // Base amount needed. Will need more depending on how many entries there are
- int entry_index = 0;
- /*
- **
- ** Based loosely on DisplayClass::Redraw_Icons
- **
- **
- */
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_width = Map.MapCellWidth;
- int map_cell_height = Map.MapCellHeight;
- if (map_cell_x > 0) {
- map_cell_x--;
- map_cell_width++;
- }
- if (map_cell_width < MAP_MAX_CELL_WIDTH) {
- map_cell_width++;
- }
- if (map_cell_y > 0) {
- map_cell_y--;
- map_cell_height++;
- }
- if (map_cell_height < MAP_MAX_CELL_WIDTH) {
- map_cell_height++;
- }
- int cell_index = 0;
- bool debug_output = false;
- //if (_call_count == 20) {
- //debug_output = true;
- //}
-
- // Need to ignore view constraints for dynamic map updates, so the radar map
- // has the latest tiberium state for cells outside the tactical view
- DLLExportClass::Adjust_Internal_View(true);
- for (int y = 0 ; y < map_cell_height ; y++) {
- for (int x = 0 ; x < map_cell_width ; x++) {
- CELL cell = XY_Cell(map_cell_x+x, map_cell_y+y);
- COORDINATE coord = Cell_Coord(cell) & 0xFF00FF00L;
- memory_needed += sizeof(CNCDynamicMapEntryStruct) * 2;
- if (memory_needed >= buffer_size) {
- return false;
- }
- /*
- ** Only cells flagged to be redraw are examined.
- */
- //if (In_View(cell) && Is_Cell_Flagged(cell)) {
- int xpixel;
- int ypixel;
- if (Map.Coord_To_Pixel(coord, xpixel, ypixel)) {
- CellClass * cellptr = &Map[Coord_Cell(coord)];
- /*
- ** If there is a portion of the underlying icon that could be visible,
- ** then draw it. Also draw the cell if the shroud is off.
- */
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER || cellptr->IsMapped || Debug_Unshroud) {
- Cell_Class_Draw_It(dynamic_map, entry_index, cellptr, xpixel, ypixel, debug_output);
- }
- /*
- ** If any cell is not fully mapped, then flag it so that the shadow drawing
- ** process will occur. Only draw the shadow if Debug_Unshroud is false.
- */
- //if (!cellptr->IsMapped && !Debug_Unshroud) {
- // IsShadowPresent = true;
- //}
- }
- //}
- }
- }
- if (entry_index) {
- _call_count++;
- }
- dynamic_map->Count = entry_index;
- dynamic_map->VortexActive = ChronalVortex.Is_Active();
- dynamic_map->VortexX = Coord_X(ChronalVortex.Get_Position());
- dynamic_map->VortexY = Coord_Y(ChronalVortex.Get_Position());
- dynamic_map->VortexWidth = Pixel_To_Lepton(64);
- dynamic_map->VortexHeight = Pixel_To_Lepton(64);
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Cell_Class_Draw_It -- Go through the motions of drawing a cell to get the smudge and overlay info
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 2/8/2019 11:09AM - ST
- **************************************************************************************************/
- void DLLExportClass::Cell_Class_Draw_It(CNCDynamicMapStruct *dynamic_map, int &entry_index, CellClass *cell_ptr, int xpixel, int ypixel, bool debug_output)
- {
- /*
- **
- ** Based on CellClass::Draw_It and SmudgeTypeClass::Draw_It
- **
- **
- */
- CELL cell = cell_ptr->Cell_Number();
- /*
- ** Redraw any smudge.
- */
- if (cell_ptr->Smudge != SMUDGE_NONE) {
- //SmudgeTypeClass::As_Reference(Smudge).Draw_It(x, y, SmudgeData);
-
- const SmudgeTypeClass &smudge_type = SmudgeTypeClass::As_Reference(cell_ptr->Smudge);
- if (smudge_type.Get_Image_Data() != NULL) {
- if (debug_output) {
- IsTheaterShape = true;
- Debug_Write_Shape_Type(&smudge_type, 0);
- IsTheaterShape = false;
- }
-
- CNCDynamicMapEntryStruct &smudge_entry = dynamic_map->Entries[entry_index++];
- strncpy(smudge_entry.AssetName, smudge_type.IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
- smudge_entry.Type = (short) cell_ptr->Smudge;
- smudge_entry.Owner = (char)cell_ptr->Owner;
- smudge_entry.DrawFlags = SHAPE_WIN_REL; // Looks like smudges are drawn top left
- smudge_entry.PositionX = xpixel;
- smudge_entry.PositionY = ypixel;
- smudge_entry.Width = Get_Build_Frame_Width(smudge_type.Get_Image_Data());
- smudge_entry.Height = Get_Build_Frame_Height(smudge_type.Get_Image_Data());
- smudge_entry.CellX = Cell_X(cell);
- smudge_entry.CellY = Cell_Y(cell);
- smudge_entry.ShapeIndex = cell_ptr->SmudgeData;
- smudge_entry.IsSmudge = true;
- smudge_entry.IsOverlay = false;
- smudge_entry.IsResource = false;
- smudge_entry.IsSellable = false;
- smudge_entry.IsTheaterShape = true; // Smudges are always theater-specific
- smudge_entry.IsFlag = false;
- }
- }
- /*
- ** Draw the overlay object.
- */
- if (cell_ptr->Overlay != OVERLAY_NONE) {
- //OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(Overlay);
- //IsTheaterShape = (bool)otype.IsTheater;
- //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);
- //IsTheaterShape = false;
-
- const OverlayTypeClass &overlay_type = OverlayTypeClass::As_Reference(cell_ptr->Overlay);
- if (overlay_type.Get_Image_Data() != NULL) {
-
- CNCDynamicMapEntryStruct &overlay_entry = dynamic_map->Entries[entry_index++];
- if (debug_output) {
- IsTheaterShape = (bool)overlay_type.IsTheater;
- Debug_Write_Shape_Type(&overlay_type, 0);
- IsTheaterShape = false;
- }
- strncpy(overlay_entry.AssetName, overlay_type.IniName, CNC_OBJECT_ASSET_NAME_LENGTH);
- overlay_entry.Type = (short)cell_ptr->Overlay;
- overlay_entry.Owner = (char)cell_ptr->Owner;
- overlay_entry.DrawFlags = SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST; // Looks like overlays are drawn centered and translucent
- overlay_entry.PositionX = xpixel + (CELL_PIXEL_W>>1);
- overlay_entry.PositionY = ypixel + (CELL_PIXEL_H>>1);
- overlay_entry.Width = Get_Build_Frame_Width(overlay_type.Get_Image_Data());
- overlay_entry.Height = Get_Build_Frame_Height(overlay_type.Get_Image_Data());
- overlay_entry.CellX = Cell_X(cell);
- overlay_entry.CellY = Cell_Y(cell);
- overlay_entry.ShapeIndex = cell_ptr->OverlayData;
- overlay_entry.IsSmudge = false;
- overlay_entry.IsOverlay = true;
- overlay_entry.IsResource = overlay_entry.Type >= OVERLAY_GOLD1 && overlay_entry.Type <= OVERLAY_GEMS4;
- overlay_entry.IsSellable = (overlay_entry.Type >= OVERLAY_SANDBAG_WALL && overlay_entry.Type <= OVERLAY_WOOD_WALL) || overlay_entry.Type == OVERLAY_FENCE;
- overlay_entry.IsTheaterShape = (bool)overlay_type.IsTheater;
- overlay_entry.IsFlag = false;
- }
- }
- if (cell_ptr->IsFlagged) {
- const void* image_data = MFCD::Retrieve("FLAGFLY.SHP");
- if (image_data != NULL) {
- CNCDynamicMapEntryStruct &flag_entry = dynamic_map->Entries[entry_index++];
- strncpy(flag_entry.AssetName, "FLAGFLY", CNC_OBJECT_ASSET_NAME_LENGTH);
- flag_entry.AssetName[CNC_OBJECT_ASSET_NAME_LENGTH - 1] = 0;
- flag_entry.Type = -1;
- flag_entry.Owner = cell_ptr->Owner;
- flag_entry.DrawFlags = SHAPE_CENTER|SHAPE_GHOST|SHAPE_FADING;
- flag_entry.PositionX = xpixel + (ICON_PIXEL_W / 2);
- flag_entry.PositionY = ypixel + (ICON_PIXEL_H / 2);
- flag_entry.Width = Get_Build_Frame_Width(image_data);
- flag_entry.Height = Get_Build_Frame_Height(image_data);
- flag_entry.CellX = Cell_X(cell);
- flag_entry.CellY = Cell_Y(cell);
- flag_entry.ShapeIndex = Frame % 14;
- flag_entry.IsSmudge = false;
- flag_entry.IsOverlay = false;
- flag_entry.IsResource = false;
- flag_entry.IsSellable = false;
- flag_entry.IsTheaterShape = false;
- flag_entry.IsFlag = true;
- }
- }
-
- }
- /**************************************************************************************************
- * DLLExportClass::Glyphx_Queue_AI -- Special queue processing for Glyphx multiplayer mode
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/12/2019 10:52AM - ST
- **************************************************************************************************/
- void DLLExportClass::Glyphx_Queue_AI(void)
- {
-
- //------------------------------------------------------------------------
- // Move events from the OutList (events generated by this player) into the
- // DoList (the list of events to execute).
- //------------------------------------------------------------------------
- while (OutList.Count) {
- OutList.First().IsExecuted = false;
- if (!DoList.Add(OutList.First())) {
- ;
- }
- OutList.Next();
- }
- /*
- ** Based on Execute_DoList in queue.cpp
- **
- ** The events have the ID of the player encoded in them, so no special per-player processing should be needed.
- ** When the event is created, the 'local player' is assumed to be the originator of the event, so PlayerPtr will need
- ** to be swapped out to represent the real originating player prior to any events being created as a result of GlyphX input
- **
- ** ST - 3/12/2019 10:51AM
- */
- for (int i = 0; i < MULTIPLAYER_COUNT; i++) {
- HousesType house;
- HouseClass *housep;
- house = Session.Players[i]->Player.ID;
-
- housep= HouseClass::As_Pointer (house);
- //.....................................................................
- // If for some reason this house doesn't exist, skip it.
- // Also, if this house has exited the game, skip it. (The user can
- // generate events after he exits, because the exit event is scheduled
- // at least FrameSendRate*3 frames ahead. If one system gets these
- // packets & another system doesn't, they'll go out of sync because
- // they aren't checking the CommandCount for that house, since that
- // house isn't connected any more.)
- //.....................................................................
- if (!housep){
- continue;
- }
- if (!housep->IsHuman){
- continue;
- }
- //.....................................................................
- // Loop through all events
- //.....................................................................
- for (int j = 0; j < DoList.Count; j++) {
- if (!DoList[j].IsExecuted && (unsigned)Frame >= DoList[j].Frame) {
- DoList[j].Execute();
- //...............................................................
- // Mark this event as executed.
- //...............................................................
- DoList[j].IsExecuted = 1;
- }
- }
- }
- //------------------------------------------------------------------------
- // Clean out the DoList
- //------------------------------------------------------------------------
- while (DoList.Count) {
- //.....................................................................
- // Discard events that have been executed, OR it's too late to execute.
- // (This happens if another player exits the game; he'll leave FRAMEINFO
- // events lying around in my queue. They won't have been "executed",
- // because his IPX connection was destroyed.)
- //.....................................................................
- if ( (DoList.First().IsExecuted) || ((unsigned)Frame > DoList.First().Frame) ) {
- DoList.Next();
- }
- else {
- break;
- }
- }
- }
- CarryoverClass Test_CC(CarryoverObjectStruct* cptr)
- {
- CarryoverClass cc;
- cc.RTTI = (RTTIType)cptr->RTTI;
- cc.Type.Building = (StructType)cptr->Type; //This works regardless of what the RTTI-type and the enum type, because they're all enums. - LLL
- cc.Cell = (CELL)cptr->Cell;
- cc.House = (HousesType)cptr->House;
- cc.Strength = cptr->Strength;
- return cc;
- }
- /**************************************************************************************************
- * DLLExportClass::Reset_Sidebars -- Init the multiplayer sidebars
- *
- *
- *
- * History: 11/8/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Store_Carryover_Objects()
- {
- if (EventCallback == NULL || Scen.IsToCarryOver == false) {
- return;
- }
- CarryoverObjectStruct* carryover_list = 0;
- CarryoverObjectStruct* carryover_list_tail = 0;
- /*
- ** Record all objects, that are to be part of the carry over set, into the carry over list.
- */
- for (int building_index = 0; building_index < Buildings.Count(); building_index++) {
- BuildingClass * building = Buildings.Ptr(building_index);
- if (building && !building->IsInLimbo && building->Strength > 0) {
- CarryoverClass carryover = CarryoverClass(building);
- CarryoverObjectStruct* cptr = new CarryoverObjectStruct();
- if (cptr) {
- cptr->RTTI = carryover.RTTI;
- cptr->Type = (int)carryover.Type.Building;
- cptr->House = carryover.House;
- cptr->Cell = carryover.Cell;
- cptr->Strength = carryover.Strength;
- CarryoverClass cc = Test_CC(cptr);
- cc;
- if (!carryover_list_tail) {
- carryover_list = cptr;
- carryover_list_tail = cptr;
- }
- else {
- carryover_list_tail->Next = cptr;
- carryover_list_tail = cptr;
- }
- }
- }
- }
- for (int unit_index = 0; unit_index < Units.Count(); unit_index++) {
- UnitClass * unit = Units.Ptr(unit_index);
- if (unit && !unit->IsInLimbo && unit->Strength > 0) {
- CarryoverClass carryover = CarryoverClass(unit);
- CarryoverObjectStruct* cptr = new CarryoverObjectStruct();
- if (cptr) {
- cptr->RTTI = carryover.RTTI;
- cptr->Type = (int)carryover.Type.Unit;
- cptr->House = carryover.House;
- cptr->Cell = carryover.Cell;
- cptr->Strength = carryover.Strength;
- CarryoverClass cc = Test_CC(cptr);
- cc;
- if (!carryover_list_tail) {
- carryover_list = cptr;
- carryover_list_tail = cptr;
- }
- else {
- carryover_list_tail->Next = cptr;
- carryover_list_tail = cptr;
- }
- }
- }
- }
- for (int infantry_index = 0; infantry_index < Infantry.Count(); infantry_index++) {
- InfantryClass * infantry = Infantry.Ptr(infantry_index);
- if (infantry && !infantry->IsInLimbo && infantry->Strength > 0) {
- CarryoverClass carryover = CarryoverClass(infantry);
- CarryoverObjectStruct* cptr = new CarryoverObjectStruct();
- if (cptr) {
- cptr->RTTI = carryover.RTTI;
- cptr->Type = (int)carryover.Type.Building;
- cptr->House = carryover.House;
- cptr->Cell = carryover.Cell;
- cptr->Strength = carryover.Strength;
- CarryoverClass cc = Test_CC(cptr);
- cc;
- if (!carryover_list_tail) {
- carryover_list = cptr;
- carryover_list_tail = cptr;
- }
- else {
- carryover_list_tail->Next = cptr;
- carryover_list_tail = cptr;
- }
- }
- }
- }
- for (int vessel_index = 0; vessel_index < Vessels.Count(); vessel_index++) {
- VesselClass * vessel = Vessels.Ptr(vessel_index);
- if (vessel && !vessel->IsInLimbo && vessel->Strength > 0) {
- CarryoverClass carryover = CarryoverClass(vessel);
- CarryoverObjectStruct* cptr = new CarryoverObjectStruct();
- if (cptr) {
- cptr->RTTI = carryover.RTTI;
- cptr->Type = (int)carryover.Type.Building;
- cptr->House = carryover.House;
- cptr->Cell = carryover.Cell;
- cptr->Strength = carryover.Strength;
- CarryoverClass cc = Test_CC(cptr);
- cc;
- if (!carryover_list_tail) {
- carryover_list = cptr;
- carryover_list_tail = cptr;
- }
- else {
- carryover_list_tail->Next = cptr;
- carryover_list_tail = cptr;
- }
- }
- }
- }
- //Make & Send Event
- EventCallbackStruct event;
- event.EventType = CALLBACK_EVENT_STORE_CARRYOVER_OBJECTS;
- event.CarryoverObjects.CarryoverList = carryover_list;
- EventCallback(event);
- //Delete the list
- while (carryover_list) {
- CarryoverObjectStruct* cptr = (CarryoverObjectStruct*)carryover_list->Next;
- delete carryover_list;
- carryover_list = cptr;
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Reset_Sidebars -- Init the multiplayer sidebars
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/14/2019 3:10PM - ST
- **************************************************************************************************/
- void DLLExportClass::Reset_Sidebars(void)
- {
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- if (i >= Session.Players.Count()) {
- continue;
- }
- if (Session.Players[i] == NULL) {
- continue;
- }
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- MultiplayerSidebars[i].Init_Clear(player_ptr);
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Set_Player_Context -- Switch the C&C local player context
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/14/2019 3:20PM - ST
- **************************************************************************************************/
- bool DLLExportClass::Set_Player_Context(uint64 glyphx_player_id, bool force)
- {
- /*
- ** Context never needs to change in single player
- */
- if (GAME_TO_PLAY == GAME_NORMAL) {
- if (PlayerPtr) {
- CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
- }
- return true;
- }
-
- /*
- ** C&C relies a lot on PlayerPtr, which is a pointer to the 'local' player's house. Historically, in a peer-to-peer
- ** multiplayer game, each player's PlayerPtr pointed to their own local player.
- **
- ** Since much of the IO logic depends on PlayerPtr being the player performing the action, we need to set PlayerPtr
- ** correctly depending on which player generated input or needs output
- */
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- if (GlyphxPlayerIDs[i] == glyphx_player_id) {
-
- if (!force && i == CurrentLocalPlayerIndex) {
- return true;
- }
- PlayerPtr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
- CurrentLocalPlayerIndex = i;
-
- Refresh_Player_Control_Flags();
- return true;
- }
- }
- return false;
- }
- /**************************************************************************************************
- * DLLExportClass::Reset_Player_Context -- Clear out old player context data
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/16/2019 10:36AM - ST
- **************************************************************************************************/
- void DLLExportClass::Reset_Player_Context(void)
- {
- CurrentLocalPlayerIndex = 0;
- CurrentObject.Clear_All();
- }
- /**************************************************************************************************
- * DLLExportClass::Refresh_Player_Control_Flags -- Set the IsPlayerControl flags so that the player
- * in context has IsPlayerControl
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/16/2019 10:36AM - ST
- **************************************************************************************************/
- void DLLExportClass::Refresh_Player_Control_Flags(void)
- {
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- if (player_ptr) {
-
- if (i == CurrentLocalPlayerIndex && player_ptr->IsHuman) {
- player_ptr->IsPlayerControl = true;
- } else {
- player_ptr->IsPlayerControl = false;
- }
- }
- }
- }
- /**************************************************************************************************
- * Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/17/2019 9:45AM - ST
- **************************************************************************************************/
- void Logic_Switch_Player_Context(ObjectClass *object)
- {
- DLLExportClass::Logic_Switch_Player_Context(object);
- }
- /**************************************************************************************************
- * DLLExportClass::Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/17/2019 9:45AM - ST
- **************************************************************************************************/
- void DLLExportClass::Logic_Switch_Player_Context(ObjectClass *object)
- {
- if (object == NULL) {
- return;
- }
-
- /*
- ** If it's not a techno, it can't be owned.
- */
- if (!object->Is_Techno()) {
- return;
- }
-
- TechnoClass *tech = static_cast<TechnoClass*>(object);
- //HousesType house = tech->House->Class->House;
- DLLExportClass::Logic_Switch_Player_Context(tech->House);
- }
-
-
-
- /**************************************************************************************************
- * Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/17/2019 9:45AM - ST
- **************************************************************************************************/
- void Logic_Switch_Player_Context(HouseClass *object)
- {
- DLLExportClass::Logic_Switch_Player_Context(object);
- }
- /**************************************************************************************************
- * DLLExportClass::Logic_Switch_Player_Context -- Called when the internal game locic needs to switch player context
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/17/2019 9:45AM - ST
- **************************************************************************************************/
- void DLLExportClass::Logic_Switch_Player_Context(HouseClass *house)
- {
- if (GAME_TO_PLAY == GAME_NORMAL) {
- CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
- return;
- }
- if (house == NULL) {
- return;
- }
-
- /*
- ** C&C relies a lot on PlayerPtr, which is a pointer to the 'local' player's house. Historically, in a peer-to-peer
- ** multiplayer game, each player's PlayerPtr pointed to their own local player.
- **
- ** Since much of the IO logic depends on PlayerPtr being the player performing the action, we need to set PlayerPtr
- ** correctly depending on which player generated input or needs output
- */
- HousesType house_type = house->Class->House;
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
-
- if (house_type == Session.Players[i]->Player.ID) {
-
- if (i == CurrentLocalPlayerIndex) {
- return;
- }
- PlayerPtr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- CurrentObject.Set_Active_Context(PlayerPtr->Class->House);
- CurrentLocalPlayerIndex = i;
- Refresh_Player_Control_Flags();
- return;
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Calculate_Start_Positions -- Calculate the initial view positions for the players
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/16/2019 6/12/2019 3:00PM - ST
- **************************************************************************************************/
- void DLLExportClass::Calculate_Start_Positions(void)
- {
- if (GAME_TO_PLAY == GAME_NORMAL) {
- MultiplayerStartPositions[0] = Scen.Views[0];
- return;
- }
- HouseClass *player_ptr = PlayerPtr;
-
- ScenarioInit++;
- COORDINATE old_tac = Map.TacticalCoord;
- for (int i=0 ; i< MULTIPLAYER_COUNT; i++) {
- PlayerPtr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- if (PlayerPtr) {
- long x, y;
- Map.Compute_Start_Pos(x, y);
- MultiplayerStartPositions[i] = XY_Cell(x, y);
- }
- }
- Map.TacticalCoord = old_tac;
- ScenarioInit--;
- PlayerPtr = player_ptr;
- }
- /**************************************************************************************************
- * DLLExportClass::Get_GlyphX_Player_ID -- Get the external GlyphX player ID from the C&C house/player pointer
- * Returns 0 in single player or if player ID isn't found
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/22/2019 6:23PM - ST
- **************************************************************************************************/
- __int64 DLLExportClass::Get_GlyphX_Player_ID(const HouseClass *house)
- {
- /*
- ** C&C relies a lot on PlayerPtr, which is a pointer to the 'local' player's house. Historically, in a peer-to-peer
- ** multiplayer game, each player's PlayerPtr pointed to their own local player.
- **
- ** Since much of the IO logic depends on PlayerPtr being the player performing the action, we need to set PlayerPtr
- ** correctly depending on which player generated input or needs output
- */
-
- if (GAME_TO_PLAY == GAME_NORMAL) {
- return 0;
- }
- if (house == NULL) {
- return 0;
- }
-
- HousesType house_type = house->Class->House;
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- if (house_type == Session.Players[i]->Player.ID) {
- return GlyphxPlayerIDs[i];
- }
- }
- /*
- ** Failure case.
- */
- return 0;
- }
- /**************************************************************************************************
- * DLLExportClass::Adjust_Internal_View -- Set the internal tactical view to encompass the input coordinates
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/16/2019 3:00PM - ST
- **************************************************************************************************/
- void DLLExportClass::Adjust_Internal_View(bool force_ignore_view_constraints)
- {
- /*
- ** When legacy rendering is disabled (especially in multiplayer) we can get input coordinates that
- ** fall outside the engine's tactical view. In this case, we need to adjust the tactical view before the
- ** input will behave as expected.
- */
-
- if (!force_ignore_view_constraints && Legacy_Render_Enabled()) {
- /*
- ** Render view should already be tracking the player's local view
- */
- DisplayClass::IgnoreViewConstraints = false;
- return;
- }
- DisplayClass::IgnoreViewConstraints = true;
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Current_Context_Sidebar -- Get the sidebar data for the current player context
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/14/2019 3:20PM - ST
- **************************************************************************************************/
- SidebarGlyphxClass *DLLExportClass::Get_Current_Context_Sidebar(HouseClass *player_ptr)
- {
- if (player_ptr) {
-
- for (int i=0 ; i<MULTIPLAYER_COUNT ; i++) {
- if (player_ptr == HouseClass::As_Pointer(Session.Players[i]->Player.ID)) {
- return &MultiplayerSidebars[i];
- }
- }
- }
- return &MultiplayerSidebars[CurrentLocalPlayerIndex];
- }
- SidebarGlyphxClass *Get_Current_Context_Sidebar(HouseClass *player_ptr)
- {
- return DLLExportClass::Get_Current_Context_Sidebar(player_ptr);
- }
- /**************************************************************************************************
- * DLLExportClass::Repair_Mode -- Starts the player's repair mode. All it does here is unselect all units.
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 5/1/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Repair_Mode(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- Unselect_All();
- }
- /**************************************************************************************************
- * DLLExportClass::Repair -- Repairs a specific building
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 5/1/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Repair(uint64 player_id, int object_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- TARGET target = Build_Target(RTTI_BUILDING, object_id);
- if (target != TARGET_NONE)
- {
- BuildingClass* building = As_Building(target);
- if (building) {
- if (!building->IsActive) {
- GlyphX_Debug_Print("DLLExportClass::Repair -- trying to repair a non-active building");
- } else {
- if (building->Can_Repair() && building->House.Is_Valid() && building->House->Class->House == PlayerPtr->Class->House)
- {
- building->Repair(-1);
- }
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Sell_Mode -- Starts the player's sell mode. All it does here is unselect all units.
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 5/1/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Sell_Mode(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- Unselect_All();
- }
- /**************************************************************************************************
- * DLLExportClass::Sell -- Sell's a player's speceific building.
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 5/1/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Sell(uint64 player_id, int object_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- TARGET target = Build_Target(RTTI_BUILDING, object_id);
- if (target != TARGET_NONE)
- {
- BuildingClass* building = As_Building(target);
- if (building) {
- if (!building->IsActive) {
- GlyphX_Debug_Print("DLLExportClass::Sell -- trying to sell a non-active building");
- } else {
- if (building->Can_Demolish() && building->House.Is_Valid() && building->House->Class->House == PlayerPtr->Class->House)
- {
- building->Sell_Back(1);
- }
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Repair_Sell_Cancel -- Ends the player's repair or sell mode. Doesn't do anything right now.
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 5/1/2019 - LLL
- **************************************************************************************************/
- void DLLExportClass::Repair_Sell_Cancel(uint64 player_id)
- {
- //OutputDebugString("Repair_Sell_Cancel\n");
- }
- /**************************************************************************************************
- * DLLExportClass::Scatter_Selected -- Scatter the selected units
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 10/15/2019 - SKY
- **************************************************************************************************/
- void DLLExportClass::Scatter_Selected(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- if (CurrentObject.Count()) {
- for (int index = 0; index < CurrentObject.Count(); index++) {
- ObjectClass const * tech = CurrentObject[index];
- if (tech != NULL && tech->Can_Player_Move()) {
- OutList.Add(EventClass(EventClass::SCATTER, TargetClass(tech)));
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Select_Next_Unit
- *
- * History: 03.02.2020 MBL
- **************************************************************************************************/
- void DLLExportClass::Select_Next_Unit(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- ObjectClass* obj = Map.Next_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
- if (obj) {
- Unselect_All();
- obj->Select();
- COORDINATE center = Map.Center_Map();
- Map.Flag_To_Redraw(true);
- if (center) {
- On_Center_Camera(PlayerPtr, Coord_X(center), Coord_Y(center));
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Select_Previous_Unit
- *
- * History: 03.02.2020 MBL
- **************************************************************************************************/
- void DLLExportClass::Select_Previous_Unit(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- ObjectClass* obj = Map.Prev_Object(CurrentObject.Count() ? CurrentObject[0] : NULL);
- if (obj) {
- Unselect_All();
- obj->Select();
- COORDINATE center = Map.Center_Map();
- Map.Flag_To_Redraw(true);
- if (center) {
- On_Center_Camera(PlayerPtr, Coord_X(center), Coord_Y(center));
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Selected_Guard_Mode
- *
- * History: 03.03.2020 MBL
- **************************************************************************************************/
- void DLLExportClass::Selected_Guard_Mode(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- if (CurrentObject.Count()) {
- for (int index = 0; index < CurrentObject.Count(); index++) {
- ObjectClass const * tech = CurrentObject[index];
- if (tech != NULL && tech->Can_Player_Fire()) {
- if (tech->Can_Player_Move()) {
- OutList.Add(EventClass(TargetClass(tech), MISSION_GUARD_AREA));
- } else {
- OutList.Add(EventClass(TargetClass(tech), MISSION_GUARD));
- }
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Selected_Stop
- *
- * History: 03.03.2020 MBL
- **************************************************************************************************/
- void DLLExportClass::Selected_Stop(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- // Copied from RedAlert/Conquer.cpp - Keyboard_Process() with Options.KeyStop (VK_S)
- if (CurrentObject.Count()) {
- for (int index = 0; index < CurrentObject.Count(); index++) {
- ObjectClass const * tech = CurrentObject[index];
- if (tech != NULL && (tech->Can_Player_Move() || (tech->Can_Player_Fire() && tech->What_Am_I() != RTTI_BUILDING))) {
- OutList.Add(EventClass(EventClass::IDLE, TargetClass(tech)));
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Units_Queued_Movement_Toggle
- *
- * History: 03.03.2020 MBL
- **************************************************************************************************/
- void DLLExportClass::Units_Queued_Movement_Toggle(uint64 player_id, bool toggle)
- {
- // Currently Red Alert only
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- if (PlayerPtr != NULL)
- {
- PlayerPtr->IsQueuedMovementToggle = toggle;
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Team_Units_Formation_Toggle_On
- *
- * History: 03.03.2020 MBL
- **************************************************************************************************/
- // extern void Toggle_Formation(void); // Code\RedAlert\Conquer.cpp
- extern char FormationEvent; // Code\RedAlert\Conquer.cpp
- void DLLExportClass::Team_Units_Formation_Toggle_On(uint64 player_id)
- {
- /*
- ** Get the player for this...
- */
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- //
- // Code here copied and modified from Toggle_Formation(), since obj->IsSelected is not supported
- // Replacing with ObjectClass::Is_Selected_By_Player(HouseClass *player);
- //
- int team = MAX_TEAMS;
- long minx = 0x7FFFFFFFL, miny = 0x7FFFFFFFL;
- long maxx = 0, maxy = 0;
- int index;
- bool setform = 0;
- TeamFormDataStruct& team_form_data = TeamFormData[PlayerPtr->Class->House];
- //
- // Recording support
- //
- if (Session.Record) {
- FormationEvent = 1;
- }
- /*
- ** Find the first selected object that is a member of a team, and
- ** register his group as the team we're using. Once we find the team
- ** number, update the 'setform' flag to know whether we should be setting
- ** the formation's offsets, or clearing them. If they currently have
- ** illegal offsets (as in 0x80000000), then we're setting.
- */
- for (index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj) {
- if (obj->House == PlayerPtr) {
- if (!obj->IsInLimbo) {
- if (obj->Is_Selected_By_Player(PlayerPtr)) {
- team = obj->Group;
- if (team < MAX_TEAMS) {
- setform = obj->XFormOffset == (int)0x80000000;
- team_form_data.TeamSpeed[team] = SPEED_WHEEL;
- team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
- break;
- }
- }
- }
- }
- }
- }
- if (team >= MAX_TEAMS) {
- for (index = 0; index < Infantry.Count(); index++) {
- InfantryClass * obj = Infantry.Ptr(index);
- if (obj) {
- if (obj->House == PlayerPtr) {
- if (!obj->IsInLimbo) {
- if (obj->Is_Selected_By_Player(PlayerPtr)) {
- team = obj->Group;
- if (team < MAX_TEAMS) {
- setform = obj->XFormOffset == (int)0x80000000;
- team_form_data.TeamSpeed[team] = SPEED_WHEEL;
- team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
- break;
- }
- }
- }
- }
- }
- }
- }
- if (team >= MAX_TEAMS) {
- for (index = 0; index < Vessels.Count(); index++) {
- VesselClass * obj = Vessels.Ptr(index);
- if (obj) {
- if (obj->House == PlayerPtr) {
- if (!obj->IsInLimbo) {
- if (obj->Is_Selected_By_Player(PlayerPtr)) {
- team = obj->Group;
- if (team < MAX_TEAMS) {
- setform = obj->XFormOffset == 0x80000000UL;
- team_form_data.TeamSpeed[team] = SPEED_WHEEL;
- team_form_data.TeamMaxSpeed[team] = MPH_LIGHT_SPEED;
- break;
- }
- }
- }
- }
- }
- }
- }
- if (team >= MAX_TEAMS) return;
- /*
- ** Now that we have a team, let's go set (or clear) the formation offsets.
- */
- for (index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
- obj->Mark(MARK_CHANGE);
- if (setform) {
- long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
- long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
- if (xc < minx) minx = xc;
- if (xc > maxx) maxx = xc;
- if (yc < miny) miny = yc;
- if (yc > maxy) maxy = yc;
- if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
- team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
- team_form_data.TeamSpeed[team] = obj->Class->Speed;
- }
- } else {
- obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
- }
- }
- }
- for (index = 0; index < Infantry.Count(); index++) {
- InfantryClass * obj = Infantry.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
- obj->Mark(MARK_CHANGE);
- if (setform) {
- long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
- long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
- if (xc < minx) minx = xc;
- if (xc > maxx) maxx = xc;
- if (yc < miny) miny = yc;
- if (yc > maxy) maxy = yc;
- if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
- team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
- }
- } else {
- obj->XFormOffset = obj->YFormOffset = (int)0x80000000;
- }
- }
- }
- for (index = 0; index < Vessels.Count(); index++) {
- VesselClass * obj = Vessels.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
- obj->Mark(MARK_CHANGE);
- if (setform) {
- long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
- long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
- if (xc < minx) minx = xc;
- if (xc > maxx) maxx = xc;
- if (yc < miny) miny = yc;
- if (yc > maxy) maxy = yc;
- if (obj->Class->MaxSpeed < team_form_data.TeamMaxSpeed[team]) {
- team_form_data.TeamMaxSpeed[team] = obj->Class->MaxSpeed;
- }
- } else {
- obj->XFormOffset = obj->YFormOffset = 0x80000000UL;
- }
- }
- }
- /*
- ** All the units have been counted to find the bounding rectangle and
- ** center of the formation, or to clear their offsets. Now, if we're to
- ** set them into formation, proceed to do so. Otherwise, bail.
- */
- if (setform) {
- int centerx = (int)((maxx - minx)/2)+minx;
- int centery = (int)((maxy - miny)/2)+miny;
- for (index = 0; index < Units.Count(); index++) {
- UnitClass * obj = Units.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team) {
- long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
- long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
- obj->XFormOffset = xc - centerx;
- obj->YFormOffset = yc - centery;
- }
- }
- for (index = 0; index < Infantry.Count(); index++) {
- InfantryClass * obj = Infantry.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team ) {
- long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
- long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
- obj->XFormOffset = xc - centerx;
- obj->YFormOffset = yc - centery;
- }
- }
- for (index = 0; index < Vessels.Count(); index++) {
- VesselClass * obj = Vessels.Ptr(index);
- if (obj && !obj->IsInLimbo && obj->House == PlayerPtr && obj->Group == team ) {
- long xc = Cell_X(Coord_Cell(obj->Center_Coord()));
- long yc = Cell_Y(Coord_Cell(obj->Center_Coord()));
- obj->XFormOffset = xc - centerx;
- obj->YFormOffset = yc - centery;
- }
- }
- }
- }
- /**************************************************************************************************
- * CNC_Handle_Debug_Request -- Process a debug input request
- *
- * In:
- *
- *
- * Out:
- *
- *
- * History: 1/7/2019 5:20PM - ST
- **************************************************************************************************/
- 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)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
-
- switch (debug_request_type) {
-
- case DEBUG_REQUEST_SPAWN_OBJECT:
- DLLExportClass::Debug_Spawn_Unit(object_name, x, y, enemy);
- break;
- case DEBUG_REQUEST_FORCE_CRASH:
- Debug_Force_Crash = true;
- break;
- case DEBUG_REQUEST_KILL_OBJECT:
- if (strcmp(object_name, "HEAL") == 0) {
- DLLExportClass::Debug_Heal_Unit(x, y);
- }
- else {
- DLLExportClass::Debug_Kill_Unit(x, y);
- }
- break;
- case DEBUG_REQUEST_END_GAME:
- {
- bool win = true;
- const char lose[] = "LOSE";
- if (strcmp(lose, object_name) == 0) {
- win = false;
- }
- PlayerWins = win;
- PlayerLoses = !win;
- }
- break;
- case DEBUG_REQUEST_UNSHROUD:
- Debug_Unshroud = unshroud;
- Map.Flag_To_Redraw(true);
- break;
- case DEBUG_REQUEST_SUPERWEAPON_RECHARGE:
- for (int i = 0; i < SPC_COUNT; ++i)
- {
- PlayerPtr->SuperWeapon[i].Forced_Charge(true);
- }
- break;
-
- case DEBUG_REQUEST_END_PRODUCTION:
- {
- for (int index = 0; index < Factories.Count(); index++) {
- FactoryClass* factory = Factories.Ptr(index);
- if (factory->Get_House()->IsHuman) {
- Factories.Ptr(index)->Force_Complete();
- }
- }
- }
- break;
- case DEBUG_REQUEST_ADD_RESOURCES:
- {
- if (object_name) {
- int amount = atoi(object_name);
- PlayerPtr->Credits += amount;
- if (PlayerPtr->Credits < 0) {
- PlayerPtr->Credits = 0;
- }
- }
- }
- break;
- case DEBUG_REQUEST_UNLOCK_BUILDABLES:
- PlayerPtr->DebugUnlockBuildables = !PlayerPtr->DebugUnlockBuildables;
- PlayerPtr->IsRecalcNeeded = true;
- break;
- case DEBUG_REQUEST_SET_GLOBAL_FLAG:
- Scen.Set_Global_To(x, true);
- break;
- default:
- break;
- }
- }
- extern "C" __declspec(dllexport) void __cdecl CNC_Handle_Beacon_Request(BeaconRequestEnum beacon_request_type, uint64 player_id, int pixel_x, int pixel_y)
- {
- if (!DLLExportClass::Set_Player_Context(player_id)) {
- return;
- }
- // Beacons are only available if legacy rendering is disabled
- if (DLLExportClass::Legacy_Render_Enabled()) {
- return;
- }
- // Only allow one beacon per player
- for (int index = 0; index < Anims.Count(); ++index) {
- AnimClass* anim = Anims.Ptr(index);
- if (anim != NULL &&
- (*anim == ANIM_BEACON || *anim == ANIM_BEACON_VIRTUAL) &&
- anim->OwnerHouse == PlayerPtr->Class->House) {
- delete anim;
- }
- }
- OutList.Add(EventClass(ANIM_BEACON, PlayerPtr->Class->House, Map.Pixel_To_Coord(pixel_x, pixel_y), PlayerPtr->Get_Allies()));
- // Send sound effect to allies
- for (int index = 0; index < Houses.Count(); ++index) {
- HouseClass* hptr = Houses.Ptr(index);
- if (hptr != NULL && hptr->IsActive && hptr->IsHuman && PlayerPtr->Is_Ally(hptr)) {
- DLLExportClass::On_Sound_Effect(hptr, VOC_BEACON, "", 0, 0);
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Debug_Spawn_All -- Debug spawn all buildable units and structures
- *
- * In: Object to unlimbo , x & y cell positions
- *
- *
- * Out: True if unlimbo succeeded
- *
- *
- *
- * History: 1/22/2020 2:57PM - ST
- **************************************************************************************************/
- bool DLLExportClass::Try_Debug_Spawn_Unlimbo(TechnoClass *techno, int &cell_x, int &cell_y)
- {
- if (techno) {
-
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_right = map_cell_x + Map.MapCellWidth;
- int map_cell_bottom = map_cell_y + Map.MapCellHeight;
- map_cell_right = min(map_cell_right, cell_x + 26); // Generally try to prevent the objects from spawing off the right of the screen
-
- int try_x = cell_x;
- int try_y = cell_y;
-
- while (try_y < map_cell_bottom) {
-
- CELL cell = XY_Cell(try_x, try_y);
-
- if (techno->Unlimbo(Cell_Coord(cell))) {
-
- try_x++;
- if (try_x > map_cell_right - 2) {
- try_x = cell_x; //map_cell_x + 2;
- try_y++;
- }
- cell_x = try_x;
- cell_y = try_y;
- return true;
- }
- try_x++;
- if (try_x > map_cell_right - 2) {
- try_x = cell_x; //map_cell_x + 2;
- try_y++;
- }
- }
- cell_x = try_x;
- cell_y = try_y;
- }
- return false;
- }
- /**************************************************************************************************
- * DLLExportClass::Debug_Spawn_All -- Debug spawn all buildable units and structures
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/22/2020 2:57PM - ST
- **************************************************************************************************/
- void DLLExportClass::Debug_Spawn_All(int x, int y)
- {
- int map_cell_x = Map.MapCellX;
- int map_cell_y = Map.MapCellY;
- int map_cell_bottom = map_cell_y + Map.MapCellHeight;
- int origin_x = map_cell_x + 2;
- int origin_y = map_cell_y + 2;
- if (x != 0 || y != 0) {
- CELL screen_cell = Coord_Cell(Map.Pixel_To_Coord(x, y));
- origin_x = Cell_X(screen_cell);
- origin_y = Cell_Y(screen_cell);
- }
- int try_x = origin_x;
- int try_y = origin_y;
- HousesType house = PlayerPtr->Class->House;
-
- for (StructType sindex = STRUCT_FIRST; sindex < STRUCT_COUNT; sindex++) {
- BuildingTypeClass const & building_type = BuildingTypeClass::As_Reference(sindex);
- if (building_type.Get_Ownable() && building_type.Level != -1) {
-
- BuildingClass * building = new BuildingClass(building_type, house);
- if (building) {
-
- try_x = origin_x;
- try_y = origin_y;
-
- while (try_y < map_cell_bottom) {
- if (Try_Debug_Spawn_Unlimbo(building, try_x, try_y)) {
- break;
- }
- }
- }
- }
- }
- for (UnitType index = UNIT_FIRST; index < UNIT_COUNT; index++) {
- UnitTypeClass const & unit_type = UnitTypeClass::As_Reference(index);
- /*
- ** Fetch the sidebar cameo image for this building.
- */
- if (unit_type.Get_Ownable() && unit_type.Level != -1) {
-
- UnitClass * unit = (UnitClass*) unit_type.Create_One_Of(PlayerPtr);
- if (unit) {
-
- try_x = origin_x;
- try_y = origin_y;
-
- while (try_y < map_cell_bottom) {
- if (Try_Debug_Spawn_Unlimbo(unit, try_x, try_y)) {
- break;
- }
- }
- }
- }
- }
- for (InfantryType index = INFANTRY_FIRST; index < INFANTRY_COUNT; index++) {
- InfantryTypeClass const &infantry_type = InfantryTypeClass::As_Reference(index);
- /*
- ** Fetch the sidebar cameo image for this building.
- */
- if (infantry_type.Get_Ownable() && infantry_type.Level != -1) {
-
- InfantryClass * inf = (InfantryClass*) infantry_type.Create_One_Of(PlayerPtr);
- if (inf) {
-
- try_x = origin_x;
- try_y = origin_y;
-
- while (try_y < map_cell_bottom) {
- if (Try_Debug_Spawn_Unlimbo(inf, try_x, try_y)) {
- break;
- }
- }
- }
- }
- }
- for (AircraftType index = AIRCRAFT_FIRST; index < AIRCRAFT_COUNT; index++) {
- AircraftTypeClass const &aircraft_type = AircraftTypeClass::As_Reference(index);
- /*
- ** Fetch the sidebar cameo image for this building.
- */
- if (aircraft_type.Get_Ownable() && aircraft_type.Level != -1) {
-
- AircraftClass * air = (AircraftClass*) aircraft_type.Create_One_Of(PlayerPtr);
- if (air) {
-
- try_x = origin_x;
- try_y = origin_y;
-
- while (try_y < map_cell_bottom) {
- if (Try_Debug_Spawn_Unlimbo(air, try_x, try_y)) {
- break;
- }
- }
- }
- }
- }
- for (VesselType index = VESSEL_FIRST; index < VESSEL_COUNT; index++) {
- VesselTypeClass const &vessel_type = VesselTypeClass::As_Reference(index);
- /*
- ** Fetch the sidebar cameo image for this building.
- */
- if (vessel_type.Get_Ownable() && vessel_type.Level != -1) {
-
- VesselClass * boat = (VesselClass*) vessel_type.Create_One_Of(PlayerPtr);
- if (boat) {
-
- try_x = origin_x;
- try_y = origin_y;
-
- while (try_y < map_cell_bottom) {
- if (Try_Debug_Spawn_Unlimbo(boat, try_x, try_y)) {
- break;
- }
- }
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Debug_Spawn_Unit -- Debug spawn a unit at the specified location
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 3/14/2019 3:20PM - ST
- **************************************************************************************************/
- void DLLExportClass::Debug_Spawn_Unit(const char *object_name, int x, int y, bool enemy)
- {
- if (object_name == NULL) {
- return;
- }
-
- if (strlen(object_name) == 0) {
- return;
- }
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- HousesType house = PlayerPtr->Class->House;
- /*
- ** Place all?
- */
- if (stricmp(object_name, "ALLOBJECTS") == 0) {
- Debug_Spawn_All(x, y);
- return;
- }
- /*
- ** If this is for the enemy, find the enemy with the most stuff
- */
- if (enemy) {
- unsigned max_count = 0;
- for (int i = 0; i < Houses.Count(); ++i) {
- const HouseClass* player = Houses.Ptr(i);
- const unsigned count = player->CurUnits + player->CurBuildings + player->CurInfantry + player->CurVessels + player->CurAircraft;
- if (!PlayerPtr->Is_Ally(player) && (count >= max_count)) {
- house = player->Class->House;
- max_count = count;
- }
- }
- }
- /*
- ** What is this thing?
- */
- StructType structure_type = BuildingTypeClass::From_Name(object_name);
- if (structure_type != STRUCT_NONE) {
-
- BuildingClass * building = new BuildingClass(structure_type, house);
- if (building) {
- if (!building->Unlimbo(Cell_Coord(cell))) {
- delete building;
- }
- }
-
- #if (0)
- Map.PendingObject = &BuildingTypeClass::As_Reference(structure_type);
- Map.PendingHouse = PlayerPtr->ActLike;
- Map.PendingObjectPtr = Map.PendingObject->Create_One_Of(PlayerPtr);
- if (Map.PendingObjectPtr) {
- Map.Set_Cursor_Pos();
- Map.Set_Cursor_Shape(Map.PendingObject->Occupy_List());
- //OutList.Add(EventClass(EventClass::PLACE, RTTI_BUILDING, (CELL)(cell + Map.ZoneOffset)));
- }
- #endif
- return;
- }
-
- UnitType unit_type = UnitTypeClass::From_Name(object_name);
- if (unit_type != UNIT_NONE) {
-
- UnitClass * unit = new UnitClass(unit_type, house);
- if (unit) {
- unit->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N);
- }
-
- return;
- }
- InfantryType infantry_type = InfantryTypeClass::From_Name(object_name);
- if (infantry_type != INFANTRY_NONE) {
-
- InfantryClass * inf = new InfantryClass(infantry_type, house);
- if (inf) {
- inf->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N);
- }
- return;
- }
- AircraftType aircraft_type = AircraftTypeClass::From_Name(object_name);
- if (aircraft_type != AIRCRAFT_NONE) {
- AircraftClass * air = new AircraftClass(aircraft_type, house);
- if (air) {
- air->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N);
- }
- return;
- }
- VesselType vessel_type = VesselTypeClass::From_Name(object_name);
- if (vessel_type != VESSEL_NONE) {
-
- VesselClass *boat = new VesselClass(vessel_type, house);
- if (boat != NULL) {
-
- if (boat->Unlimbo(Map.Pixel_To_Coord(x, y), DIR_N)) {
- boat->Enter_Idle_Mode();
- } else {
- delete boat;
- }
- }
- }
- OverlayType overlay_type = OverlayTypeClass::From_Name(object_name);
- if (overlay_type != OVERLAY_NONE)
- {
- new OverlayClass(overlay_type, cell);
- return;
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Debug_Kill_Unit -- Kill a unit at the specified location
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 8/19/2019 3:09PM - ST
- **************************************************************************************************/
- void DLLExportClass::Debug_Kill_Unit(int x, int y)
- {
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- CellClass * cellptr = &Map[cell];
- if (cellptr) {
- ObjectClass *obj = cellptr->Cell_Object();
- static const int debug_damage = 100; // 100 = Incremental damage
- if (obj) {
- int damage = debug_damage;
- obj->Take_Damage(damage, 0, WARHEAD_HE, 0, true);
- } else {
- if (cellptr->Overlay != OVERLAY_NONE) {
- OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
- if (optr->IsTiberium) {
- cellptr->Reduce_Tiberium(1);
- }
- if (optr->IsWall) {
- Map[cell].Reduce_Wall(debug_damage);
- }
- }
- if (cellptr->TType == TEMPLATE_BRIDGE1 || cellptr->TType == TEMPLATE_BRIDGE2 ||
- cellptr->TType == TEMPLATE_BRIDGE1H || cellptr->TType == TEMPLATE_BRIDGE2H ||
- cellptr->TType == TEMPLATE_BRIDGE_1A || cellptr->TType == TEMPLATE_BRIDGE_1B ||
- cellptr->TType == TEMPLATE_BRIDGE_2A || cellptr->TType == TEMPLATE_BRIDGE_2B ||
- cellptr->TType == TEMPLATE_BRIDGE_3A || cellptr->TType == TEMPLATE_BRIDGE_3B) {
- Map.Destroy_Bridge_At(cell);
- }
- }
- }
- }
- void DLLExportClass::Debug_Heal_Unit(int x, int y)
- {
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- CellClass * cellptr = &Map[cell];
- if (cellptr) {
- ObjectClass *obj = cellptr->Cell_Object();
- if (obj) {
- obj->Strength = obj->Class_Of().MaxStrength;
- }
- else {
- if (cellptr->Overlay != OVERLAY_NONE) {
- OverlayTypeClass const * optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
- if (optr->IsTiberium) {
- const int cellcount = (int)FACING_COUNT + 1;
- CellClass* cells[cellcount];
- cells[0] = cellptr;
- for (FacingType index = FACING_N; index < FACING_COUNT; index++) {
- cells[(int)index + 1] = cellptr->Adjacent_Cell(index);
- }
- for (int index = 0; index < cellcount; index++) {
- CellClass * newcell = cells[index];
- if (newcell != NULL) {
- if (newcell->Can_Tiberium_Germinate()) {
- switch (cellptr->Overlay) {
- case OVERLAY_GOLD1:
- case OVERLAY_GOLD2:
- case OVERLAY_GOLD3:
- case OVERLAY_GOLD4:
- new OverlayClass(Random_Pick(OVERLAY_GOLD1, OVERLAY_GOLD4), newcell->Cell_Number());
- newcell->OverlayData = 0;
- break;
- case OVERLAY_GEMS1:
- case OVERLAY_GEMS2:
- case OVERLAY_GEMS3:
- case OVERLAY_GEMS4:
- new OverlayClass(Random_Pick(OVERLAY_GEMS1, OVERLAY_GEMS4), newcell->Cell_Number());
- newcell->OverlayData = 0;
- break;
- default:
- break;
- }
- }
- else if (newcell->Land_Type() == LAND_TIBERIUM) {
- switch (newcell->Overlay) {
- case OVERLAY_GOLD1:
- case OVERLAY_GOLD2:
- case OVERLAY_GOLD3:
- case OVERLAY_GOLD4:
- newcell->OverlayData = MIN(newcell->OverlayData + 1, 11);
- newcell->Recalc_Attributes();
- newcell->Redraw_Objects();
- break;
- case OVERLAY_GEMS1:
- case OVERLAY_GEMS2:
- case OVERLAY_GEMS3:
- case OVERLAY_GEMS4:
- newcell->OverlayData = MIN(newcell->OverlayData + 1, 2);
- newcell->Recalc_Attributes();
- newcell->Redraw_Objects();
- break;
- default:
- break;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Legacy_Render_Enabled -- Is the legacy rendering enabled?
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 4/15/2019 5:46PM - ST
- **************************************************************************************************/
- bool DLLExportClass::Legacy_Render_Enabled(void)
- {
- if (GAME_TO_PLAY == GAME_GLYPHX_MULTIPLAYER) {
- unsigned int num_humans = 0U;
- for (int i = 0; i < MULTIPLAYER_COUNT; ++i) {
- HouseClass *player_ptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
- if (player_ptr && player_ptr->IsHuman) {
- if (++num_humans > 1) break;
- }
- }
- return num_humans < 2;
- }
- //return false;
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Computer_Message -- Replacement for original Computer_Message function
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 1/27/2020 1:42PM - ST
- **************************************************************************************************/
- void DLLExportClass::Computer_Message(bool last_player_taunt)
- {
- HousesType house;
- HouseClass *ptr;
- HouseClass *ai_players[MAX_PLAYERS];
- int ai_player_count = 0;
- /*------------------------------------------------------------------------
- Find the computer house that the message will be from
- ------------------------------------------------------------------------*/
- for (house = HOUSE_MULTI1; house < (HOUSE_MULTI1 + MULTIPLAYER_COUNT); house++) {
- ptr = HouseClass::As_Pointer(house);
- if (!ptr || ptr->IsHuman || ptr->IsDefeated) {
- continue;
- }
- ai_players[ai_player_count++] = ptr;
- }
- if (ai_player_count) {
- int ai_player_index = 0;
- if (ai_player_count > 1) {
- ai_player_index = IRandom(0, ai_player_count - 1);
- }
- int taunt_index;
- if (last_player_taunt) {
- taunt_index = 13;
- } else {
- taunt_index = IRandom(0,12);
- }
- On_Message(ai_players[ai_player_index], "", 15.0f, MESSAGE_TYPE_COMPUTER_TAUNT, taunt_index);
- }
- }
- /**************************************************************************************************
- * DLLExportClass::Set_Special_Key_Flags --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 6/27/2019 - JAS
- **************************************************************************************************/
- void DLLExportClass::Set_Special_Key_Flags(unsigned char special_key_flags)
- {
- SpecialKeyFlags[CurrentLocalPlayerIndex] = special_key_flags;
- }
- /**************************************************************************************************
- * DLLExportClass::Clear_Special_Key_Flags --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 6/27/2019 - JAS
- **************************************************************************************************/
- void DLLExportClass::Clear_Special_Key_Flags()
- {
- SpecialKeyFlags[CurrentLocalPlayerIndex] = 0;
- }
- /**************************************************************************************************
- * DLLExportClass::Get_Input_Key_State --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 6/27/2019 - JAS
- **************************************************************************************************/
- bool DLLExportClass::Get_Input_Key_State(KeyNumType key)
- {
- switch (key)
- {
- case KN_LCTRL:
- return (SpecialKeyFlags[CurrentLocalPlayerIndex] & INPUT_SPECIAL_KEY_CTRL) != 0;
- break;
- case KN_LSHIFT:
- return (SpecialKeyFlags[CurrentLocalPlayerIndex] & INPUT_SPECIAL_KEY_SHIFT) != 0;
- break;
- case KN_LALT:
- return (SpecialKeyFlags[CurrentLocalPlayerIndex] & INPUT_SPECIAL_KEY_ALT) != 0;
- break;
- default:
- break;
- };
- return false;
- }
- /**************************************************************************************************
- * Get_Input_Key_State
- *
- * History: 6/27/2019 - JAS
- **************************************************************************************************/
- bool DLL_Export_Get_Input_Key_State(KeyNumType key)
- {
- return DLLExportClass::Get_Input_Key_State(key);
- }
- bool DLLSave(Pipe &file)
- {
- return DLLExportClass::Save(file);
- }
- bool DLLLoad(Straw &file)
- {
- return DLLExportClass::Load(file);
- }
- /**************************************************************************************************
- * DLLExportClass::Save --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 9/10/2019 10:24AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Save(Pipe & pipe)
- {
- /*
- ** Version first
- */
- unsigned int version = CNC_DLL_API_VERSION;
- pipe.Put(&version, sizeof(version));
-
- pipe.Put(MultiplayerStartPositions, sizeof(MultiplayerStartPositions));
- pipe.Put(GlyphxPlayerIDs, sizeof(GlyphxPlayerIDs));
- pipe.Put(&GlyphXClientSidebarWidthInLeptons, sizeof(GlyphXClientSidebarWidthInLeptons));
- pipe.Put(MPlayerIsHuman, sizeof(MPlayerIsHuman));
- pipe.Put(MultiplayerStartPositions, sizeof(MultiplayerStartPositions));
- pipe.Put(PlacementType, sizeof(PlacementType));
- pipe.Put(&OverrideNewUnitsEnabled, sizeof(OverrideNewUnitsEnabled));
- for (int i=0 ; i<MAX_PLAYERS ; i++) {
- Sidebar_Glyphx_Save(pipe, &MultiplayerSidebars[i]);
- int has_player = false;
- if (i < Session.Players.Count() && Session.Players[i]) {
- has_player = true;
- pipe.Put(&has_player, sizeof(has_player));
- pipe.Put(Session.Players[i], sizeof(NodeNameType));
- } else {
- pipe.Put(&has_player, sizeof(has_player));
- }
- }
- pipe.Put(&Special, sizeof(Special));
- /*
- ** Special case for MPSuperWeaponDisable - store negated value so it defaults to enabled
- */
- bool not_allow_super_weapons = !MPSuperWeaponDisable;
- pipe.Put(¬_allow_super_weapons, sizeof(not_allow_super_weapons));
- /*
- ** Room for save game expansion
- */
- unsigned char padding[4095];
- memset(padding, 0, sizeof(padding));
-
- pipe.Put(padding, sizeof(padding));
- return true;
- }
-
- /**************************************************************************************************
- * DLLExportClass::Load --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 9/10/2019 10:24AM - ST
- **************************************************************************************************/
- bool DLLExportClass::Load(Straw & file)
- {
- unsigned int version = 0;
- if (file.Get(&version, sizeof(version)) != sizeof(version)) {
- return false;
- }
-
- if (file.Get(MultiplayerStartPositions, sizeof(MultiplayerStartPositions)) != sizeof(MultiplayerStartPositions)) {
- return false;
- }
- if (file.Get(GlyphxPlayerIDs, sizeof(GlyphxPlayerIDs)) != sizeof(GlyphxPlayerIDs)) {
- return false;
- }
-
- if (file.Get(&GlyphXClientSidebarWidthInLeptons, sizeof(GlyphXClientSidebarWidthInLeptons)) != sizeof(GlyphXClientSidebarWidthInLeptons)) {
- return false;
- }
- if (file.Get(MPlayerIsHuman, sizeof(MPlayerIsHuman)) != sizeof(MPlayerIsHuman)) {
- return false;
- }
- if (file.Get(MultiplayerStartPositions, sizeof(MultiplayerStartPositions)) != sizeof(MultiplayerStartPositions)) {
- return false;
- }
- if (file.Get(PlacementType, sizeof(PlacementType)) != sizeof(PlacementType)) {
- return false;
- }
-
- if (file.Get(&OverrideNewUnitsEnabled, sizeof(OverrideNewUnitsEnabled)) != sizeof(OverrideNewUnitsEnabled)) {
- return false;
- }
- if (Is_Aftermath_Installed()) {
- if (Session.Type == GAME_SKIRMISH || Session.Type == GAME_GLYPHX_MULTIPLAYER) {
- bAftermathMultiplayer = NewUnitsEnabled = OverrideNewUnitsEnabled;
- }
- }
- Session.NumPlayers = 0;
- for (int i=0 ; i<MAX_PLAYERS ; i++) {
- Sidebar_Glyphx_Load(file, &MultiplayerSidebars[i]);
- int has_player = false;
- file.Get(&has_player, sizeof(has_player));
-
- if (has_player) {
- NodeNameType *who = new NodeNameType;
- file.Get(who, sizeof(NodeNameType));
- Session.Players.Add (who);
- Session.NumPlayers++;
- }
- }
- if (file.Get(&Special, sizeof(Special)) != sizeof(Special)) {
- return false;
- }
- /*
- ** Restore backup
- */
- if (SpecialBackup != NULL) {
- memcpy(SpecialBackup, &Special, sizeof(SpecialClass));
- }
- /*
- ** Special case for MPSuperWeaponDisable - store negated value so it defaults to enabled
- */
- bool not_allow_super_weapons = false;
- if (file.Get(¬_allow_super_weapons, sizeof(not_allow_super_weapons)) != sizeof(not_allow_super_weapons)) {
- return false;
- }
- MPSuperWeaponDisable = !not_allow_super_weapons;
- unsigned char padding[4095];
-
- if (file.Get(padding, sizeof(padding)) != sizeof(padding)) {
- return false;
- }
- return true;
- }
- /**************************************************************************************************
- * DLLExportClass::Code_Pointers --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 9/10/2019 10:24AM - ST
- **************************************************************************************************/
- void DLLExportClass::Code_Pointers(void)
- {
- for (int i=0 ; i<MAX_PLAYERS ; i++) {
- Sidebar_Glyphx_Code_Pointers(&MultiplayerSidebars[i]);
-
- if (PlacementType[i]) {
- PlacementType[i] = (BuildingTypeClass *) PlacementType[i]->Type;
- }
- }
- }
-
- /**************************************************************************************************
- * DLLExportClass::Decode_Pointers --
- *
- * In:
- *
- * Out:
- *
- *
- *
- * History: 9/10/2019 10:24AM - ST
- **************************************************************************************************/
- void DLLExportClass::Decode_Pointers(void)
- {
- for (int i=0 ; i<MAX_PLAYERS ; i++) {
- Sidebar_Glyphx_Decode_Pointers(&MultiplayerSidebars[i]);
- if (PlacementType[i]) {
- StructType type = (StructType) reinterpret_cast<unsigned int>(PlacementType[i]);
- PlacementType[i] = NULL;
- if (type >= STRUCT_FIRST && type < STRUCT_COUNT) {
-
- TechnoTypeClass const * tech = Fetch_Techno_Type(RTTI_BUILDINGTYPE, type);
- if (tech) {
- BuildingTypeClass* build_type = (BuildingTypeClass*)(tech);
- if (build_type) {
- PlacementType[i] = build_type;
- }
- }
- }
- }
- }
- }
- void DLL_Code_Pointers(void)
- {
- DLLExportClass::Code_Pointers();
- }
- void DLL_Decode_Pointers(void)
- {
- DLLExportClass::Decode_Pointers();
- }
|