123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022 |
- /*-------------------------------------------------------------------------
- * FSMission.cpp
- *
- * FedSrv mission handling stuff
- *
- * Owner:
- *
- * Copyright 1986-1998 Microsoft Corporation, All Rights Reserved
- *-----------------------------------------------------------------------*/
- #include "pch.h"
- //CFSMission statics
- ListFSMission CFSMission::s_list;
- int CFSMission::s_iMissionID = 1; // just for igc--this too wil go away when we have single exe
- const DWORD CFSMission::c_sbtPlayer = 0x00000001;
- const DWORD CFSMission::c_sbtLeader = 0x00000002;
- const float c_flUpdateTimeInterval = 10.0f;
- static const char* sideNames[c_cSidesMax] =
- {
- "Team 1",
- "Team 2",
- "Team 3",
- "Team 4",
- "Team 5",
- "Team 6"
- };
- void CFSMission::InitSide(SideID sideID)
- {
- /* { "Crusaders",
- "Unity",
- "Survivors",
- "Protectorate",
- "Colossal Mining Corp",
- "Midnight Runners" };
- */
- assert(sideID >= 0 && sideID < c_cSidesMax);
- strcpy(m_misdef.rgszName[sideID], sideNames[sideID]);
- /*
- if (m_misdef.misparms.rgCivID[sideID] == NA)
- m_misdef.misparms.rgCivID[sideID] = PickNewCiv(sideID, m_misdef.rgCivID);
- assert (m_misdef.misparms.rgCivID[sideID] != NA);
- */
- assert (m_misdef.misparms.rgCivID[sideID] != NA);
- //m_misdef.rgCivID [sideID] = m_misdef.misparms.rgCivID[sideID];
- m_misdef.rgShipIDLeaders[sideID] = NA;
- m_misdef.rgcPlayers [sideID] = 0;
- m_misdef.rgfAutoAccept [sideID] = true;
- m_misdef.rgfReady [sideID] = false;
- m_misdef.rgfForceReady [sideID] = false;
- m_misdef.rgfActive [sideID] = true;
- m_rgMoney[sideID] = 0;
- }
- static int InitializeCivList(const CivilizationListIGC* pcivs,
- CivID civIDs[])
- {
- int n = 0;
- for (CivilizationLinkIGC* pcl = pcivs->first(); (pcl != NULL); pcl = pcl->next())
- {
- CivID civID = pcl->data()->GetObjectID();
- //Hack to prevent bonus civs from showing up
- //if (civID < 300)
- civIDs[n++] = civID;
- }
- return n;
- }
- CFSMission::CFSMission(
- const MissionParams& misparms,
- char * szDesc,
- IMissionSite * psiteMission,
- IIgcSite* psiteIGC,
- CAdditionalAGCParamData * paagcParamData,
- const char* pszStoryText
- ) :
- m_pMission(::CreateMission()), // IGC CreateMission
- m_psiteMission(psiteMission),
- m_psiteIGC(psiteIGC),
- m_fLobbyDirty(true),
- m_timeLastLobbyMissionInfo(Time::Now() - c_flUpdateTimeInterval), // fudge factor--want to
- m_nFrame(0),
- m_bShouldDelete(false),
- m_pszReason(NULL),
- m_flGameDuration(0.0f),
- m_pttbmNewSetting(NULL),
- m_pttbmAltered(NULL),
- m_strStoryText(pszStoryText)
- {
- // Init mission def
- ZeroMemory(&m_misdef, sizeof(m_misdef));
- BEGIN_PFM_CREATE_PREALLOC(g.fm, &m_misdef, S, MISSIONDEF)
- END_PFM_CREATE
- m_misdef.misparms = misparms;
- //m_misdef.misparms.fStartingMoney = 0.0f;
- //m_misdef.misparms.iGoalTerritoryPercentage = 75; //NYI
- //m_misdef.misparms.iRandomEncounters = 2; //NYI
- psiteMission->Create(this);
- assert(!g.strLobbyServer.IsEmpty() == !!g.fmLobby.IsConnected());
- // keep track of whether this is a lobbied and/or club game
- m_misdef.misparms.bLobbiedGame = g.fmLobby.IsConnected();
- #if !defined(ALLSRV_STANDALONE)
- m_misdef.misparms.bClubGame = true;
- strcpy(m_misdef.misparms.szIGCStaticFile, IGC_ENCRYPT_CORE_FILENAME);
- #else // !defined(ALLSRV_STANDALONE)
- m_misdef.misparms.bClubGame = false;
- strcpy(m_misdef.misparms.szIGCStaticFile, IGC_STATIC_CORE_FILENAME);
- // hardcode this cap in one more place to make it harder to work around.
- m_misdef.misparms.nTotalMaxPlayersPerGame = min(c_cMaxPlayersPerGame, misparms.nTotalMaxPlayersPerGame);
- #endif // !defined(ALLSRV_STANDALONE)
- // if this game is an auto-start game, set the start time appropriately
- if (m_misdef.misparms.bAutoRestart)
- m_misdef.misparms.timeStart = Time::Now() + m_misdef.misparms.fStartCountdown;
- // set Mission Name here too so that AGC Admin tool reports the params while mission stage is STAGE_NOTSTARTED
- m_pMission->SetMissionParams(&m_misdef.misparms);
- m_pMission->Initialize(g.timeNow, psiteIGC);
- m_pMission->SetPrivateData((DWORD) this); // so we can get back to a CFSMission from an ImissionIGC
- m_pgrpMission = g.fm.CreateGroup(m_misdef.misparms.strGameName);
- if (szDesc)
- {
- assert(lstrlen(szDesc) < sizeof(m_misdef.szDescription));
- lstrcpy(m_misdef.szDescription, szDesc);
- }
- else
- {
- // use the description in the mission params
- strncpy(m_misdef.szDescription, m_misdef.misparms.strGameName, sizeof(m_misdef.szDescription));
- m_misdef.szDescription[sizeof(m_misdef.szDescription)-1] = '\0';
- }
- m_misdef.iSideMissionOwner = NA; // will turn into the person who created this when they do a SideChange
- m_misdef.fAutoAcceptLeaders = true;
- m_misdef.fInProgress = false;
- m_misdef.stage = STAGE_NOTSTARTED;
- #if !defined(ALLSRV_STANDALONE)
- extern void DoDecrypt(int size, char* pdata);
- m_misdef.misparms.verIGCcore = LoadIGCStaticCore(m_misdef.misparms.szIGCStaticFile, m_pMission, false, DoDecrypt);
- #else // !defined(ALLSRV_STANDALONE)
- m_misdef.misparms.verIGCcore = LoadIGCStaticCore(m_misdef.misparms.szIGCStaticFile, m_pMission, false, NULL);
- #endif // !defined(ALLSRV_STANDALONE)
- m_misdef.dwCookie = NULL;
- const CivilizationListIGC* pcivs = m_pMission->GetCivilizations();
- const int cCivsMax = 20;
- assert (pcivs->n() < cCivsMax);
- //Get random initial civs for each side, minimizing duplication vs. pre-existing sides
- CivID civIDs[cCivsMax];
- int n = InitializeCivList(pcivs, civIDs);
- int iSide = 0;
-
- for (iSide = 0; iSide < c_cSidesMax; iSide++)
- {
- if (NA == m_misdef.misparms.rgCivID[iSide])
- {
- if (n == 1)
- {
- m_misdef.misparms.rgCivID[iSide] = civIDs[0];
- n = InitializeCivList(pcivs, civIDs);
- }
- else
- {
- int index = randomInt(0, --n);
- m_misdef.misparms.rgCivID[iSide] = civIDs[index];
- if (index != n)
- {
- civIDs[index] = civIDs[n];
- }
- }
- }
- InitSide(iSide);
- }
- // Build the mission
- m_pMission->SetMissionID(s_iMissionID++);
- char szRealTeams[] = ": All real teams";
- char szBuff[sizeof(m_misdef.misparms.strGameName) + sizeof(szRealTeams)];
- wsprintf(szBuff, "%s%s", m_misdef.misparms.strGameName, szRealTeams);
- m_pgrpSidesReal = g.fm.CreateGroup(szBuff);
- GetSystemTime(&m_stStartTime);
- m_pMission->UpdateSides(Time::Now(), &m_misdef.misparms, m_misdef.rgszName);
- s_list.last(this); // add us to the list of missions
- // handle initation list, if any
- m_nInvitationListID = m_misdef.misparms.nInvitationListID;
- if (RequiresInvitation())
- {
- // Invitations will NOT be added to the right right now, but will be added later, asynchronously after they come back from sql.
- GetInvitations(m_nInvitationListID, GetMissionID());
- }
- if (paagcParamData)
- {
- TechTreeBitMask ttbmBlank;
- ttbmBlank.ClearAll();
- for (iSide = 0; iSide < c_cSidesMax; iSide++)
- {
- // detect admin made changes
- if (ttbmBlank != paagcParamData->m_ttbmAltered[iSide])
- {
- MakeOverrideTechBits();
- m_pttbmAltered[iSide] = paagcParamData->m_ttbmAltered[iSide];
- m_pttbmNewSetting[iSide] = paagcParamData->m_ttbmNewSetting[iSide];
- }
- // detect admin made changes
- if(paagcParamData->m_szTeamName[iSide][0] != '\0')
- SetSideName(iSide, paagcParamData->m_szTeamName[iSide]);
- }
- }
- //
- // Fire off an AGC event that a game was created
- //
- LPCSTR pszGame = GetMissionDef()->misparms.strGameName;
- long idGame = GetIGCMission() ? GetIGCMission()->GetMissionID() : -1;
- LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
- _AGCModule.TriggerContextEvent(NULL, EventID_GameCreated, pszContext,
- pszGame, idGame, -1, -1, 0);
- }
- CFSMission::~CFSMission()
- {
- //
- // Fire off an AGC event that a game was destroyed
- //
- LPCSTR pszGame = GetMissionDef()->misparms.strGameName;
- long idGame = GetIGCMission() ? GetIGCMission()->GetMissionID() : -1;
- LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
- _AGCModule.TriggerContextEvent(NULL, EventID_GameDestroyed, pszContext,
- pszGame, idGame, -1, -1, 0);
- // Destroy any existing AGC game associated with the IGC mission
- GetAGCGlobal()->RemoveAGCObject(m_pMission, true);
- Vacate();
- // We don't want anymore mission related messages from any players still here
- ShipLinkIGC * pShiplink = m_pMission->GetShips()->first();
- while (pShiplink)
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- pShiplink = pShiplink->next();
- assert (pfsShip->IsPlayer());
- RemovePlayerFromMission(pfsShip->GetPlayer(), QSR_ServerShutdown);
- }
- //
- // free all container elements
- //
- for (std::vector<CFSCluster*>::iterator i(m_pFSClusters.begin()); i != m_pFSClusters.end(); ++i)
- delete static_cast<CFSCluster*>(*i);
- for (std::vector<CFSSide*>::iterator _i(m_pFSSides.begin()); _i != m_pFSSides.end(); ++_i)
- delete static_cast<CFSSide*>(*_i);
- if(m_pttbmNewSetting)
- delete[] m_pttbmNewSetting;
- if(m_pttbmAltered)
- delete[] m_pttbmAltered;
- // And the mission is definitely over at this point, so the lobby and all clients should forget about it
- SetStage(STAGE_TERMINATE);
- g.fm.DeleteGroup(m_pgrpMission);
- if (g.fmLobby.IsConnected())
- {
- BEGIN_PFM_CREATE(g.fmLobby, pfmMissionGone, LS, MISSION_GONE)
- END_PFM_CREATE
- pfmMissionGone->dwCookie = GetCookie();
- g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
- }
-
- // remove us from our list of missions
- for (LinkFSMission * plinkFSMis = s_list.first(); plinkFSMis; plinkFSMis = plinkFSMis->next())
- {
- CFSMission * pfsMission = plinkFSMis->data();
- if (this == pfsMission)
- {
- delete plinkFSMis;
- break;
- }
- }
- assert (plinkFSMis); // better have found it
- m_pMission->Terminate();
- delete m_pMission;
- m_psiteMission->Destroy(this);
- g.fm.DeleteGroup(m_pgrpSidesReal);
- #if defined(ALLSRV_STANDALONE)
- // Possibly shutdown the standalone server if no more games
- if (0 == s_list.n())
- {
- // Disconnect from the lobby server
- DisconnectFromLobby();
- g.strLobbyServer.SetEmpty();
- // Shutdown the server if no sessions exist
- if (0 == CAdminSession::GetSessionCount())
- PostThreadMessage(g.idReceiveThread, WM_QUIT, 0, 0);
- }
- #endif // defined(ALLSRV_STANDALONE)
- // kill any pending ballots
- while (!m_ballots.IsEmpty())
- delete m_ballots.PopFront();
- }
- /*-------------------------------------------------------------------------
- * AddPlayerToMission
- *-------------------------------------------------------------------------
- * Purpose:
- * Set a player on a mission in the team lobby.
- * This must be called INSTEAD OF IGC's SetSide() for the player's new side.
- */
- void CFSMission::AddPlayerToMission(CFSPlayer * pfsPlayer)
- {
- debugf("Player %s, ship=%d joined mission=%x\n",
- pfsPlayer->GetName(), pfsPlayer->GetShipID(),
- GetCookie());
- assert (pfsPlayer->GetPlayerScoreObject());
- OldPlayerLink* popl = GetOldPlayerLink(pfsPlayer->GetName());
- if (popl)
- {
- pfsPlayer->SetBannedSideMask(popl->data().bannedSideMask);
- PlayerScoreObject * ppso = &(popl->data().pso);
- pfsPlayer->GetIGCShip()->SetExperience(0.0f);
- pfsPlayer->GetIGCShip()->SetKills(ppso->GetKills());
- pfsPlayer->GetIGCShip()->SetDeaths(ppso->GetDeaths());
- pfsPlayer->GetIGCShip()->SetEjections(ppso->GetEjections());
- pfsPlayer->SetPlayerScoreObject(ppso);
- if (popl->data().pclusterLifepod)
- pfsPlayer->SetLifepod(popl->data().pclusterLifepod,
- popl->data().positionLifepod);
- //delete popl;
- }
- else
- {
- pfsPlayer->GetIGCShip()->SetKills(0);
- pfsPlayer->GetIGCShip()->SetDeaths(0);
- pfsPlayer->GetIGCShip()->SetEjections(0);
- }
- g.fm.AddConnectionToGroup(GetGroupMission(), pfsPlayer->GetConnection());
- SendLobbyMissionInfo(pfsPlayer);
- pfsPlayer->SetSide(this, GetIGCMission()->GetSide(SIDE_TEAMLOBBY));
- pfsPlayer->GetIGCShip()->CreateDamageTrack();
- SendPlayerInfo(NULL, pfsPlayer, this);
- assert(0 == g.fm.CbUsedSpaceInOutbox()); // everything should've been sent
-
- // tell the lobby that this character is now in this mission
- if (g.fmLobby.IsConnected())
- {
- assert(GetCookie()); // we can't be sending messages w/ cookies unless we have a real cookie
-
- BEGIN_PFM_CREATE(g.fmLobby, pfmPlayerJoined, S, PLAYER_JOINED)
- FM_VAR_PARM(pfsPlayer->GetName(), CB_ZTS)
- FM_VAR_PARM(pfsPlayer->GetCDKey(), CB_ZTS)
- END_PFM_CREATE
- pfmPlayerJoined->dwMissionCookie = GetCookie();
- g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
- }
- m_bShouldDelete = false;
- SetLobbyIsDirty();
- }
- /*-------------------------------------------------------------------------
- * RemovePlayerFromMission
- *-------------------------------------------------------------------------
- * Purpose:
- * Removes a player in the team lobby from the mission.
- * This must be called INSTEAD OF IGC's SetSide() for the player's new side.
- */
- void CFSMission::RemovePlayerFromMission(CFSPlayer * pfsPlayer, QuitSideReason reason, const char* szMessageParam)
- {
- debugf("Player %s, ship=%d quiting mission=%x, reason=%d\n",
- pfsPlayer->GetName(), pfsPlayer->GetShipID(),
- GetCookie(), reason);
- // move them to the lobby first
- PlayerScoreObject* ppso = pfsPlayer->GetPlayerScoreObject();
- if (ppso->Connected())
- {
- pfsPlayer->GetPlayerScoreObject()->Disconnect(g.timeNow);
- }
- //Cache the player's old score object
- SaveAsOldPlayer(pfsPlayer, QSRIsBoot(reason));
- if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
- RemovePlayerFromSide(pfsPlayer, reason, szMessageParam);
- // Since they're quiting, then they're not requesting a position anywhere anymore
- RemoveJoinRequest(pfsPlayer, NULL);
- BEGIN_PFM_CREATE(g.fm, pfmQuitMission, CS, QUIT_MISSION)
- FM_VAR_PARM(szMessageParam, CB_ZTS)
- END_PFM_CREATE
- pfmQuitMission->shipID = pfsPlayer->GetShipID();
- pfmQuitMission->reason = reason;
-
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
-
- // if they are quitting the mission, wait to remove them until we have sent
- // the side change.
- pfsPlayer->GetIGCShip()->DeleteDamageTrack();
- pfsPlayer->SetSide(NULL, NULL);
- // Let's just be super paranoid and make sure they're not in any of the mission's groups
- // TODO: Verify that they're already gone in debug builds
- g.fm.DeleteConnectionFromGroup(GetGroupMission(), pfsPlayer->GetConnection());
- g.fm.DeleteConnectionFromGroup(GetGroupLobbySide(), pfsPlayer->GetConnection());
- g.fm.DeleteConnectionFromGroup(GetGroupRealSides(), pfsPlayer->GetConnection());
- // tell the lobby that this character is no longer in this mission
- if (g.fmLobby.IsConnected() && GetCookie())
- {
- BEGIN_PFM_CREATE(g.fmLobby, pfmPlayerQuit, S, PLAYER_QUIT)
- FM_VAR_PARM(pfsPlayer->GetName(), CB_ZTS)
- END_PFM_CREATE
- pfmPlayerQuit->dwMissionCookie = GetCookie();
- g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
- }
- if (!HasPlayers(NULL, true) && // no one left in the mission
- !m_misdef.misparms.bAllowEmptyTeams && // game doesn't allow empty sides
- m_misdef.misparms.bClubGame && // not a standalone server
- (IMPLIES( GetMissionDef()->misparms.bObjectModelCreated, GetStage() != STAGE_NOTSTARTED )) // not an admin created game that has started
- )
- {
- m_bShouldDelete = true;
- }
- else
- {
- SetLobbyIsDirty();
- }
- }
- /*-------------------------------------------------------------------------
- * AddPlayerToSide
- *-------------------------------------------------------------------------
- * Purpose:
- * Set a player from the team lobby to a side, to maintain team/mission leader status
- * This must be called INSTEAD OF IGC's SetSide() for the player's new side.
- *
- * Side Effects:
- * Maintain team/mission leader status
- */
- void CFSMission::AddPlayerToSide(CFSPlayer * pfsPlayer, IsideIGC * pside)
- {
- assert (pside);
- ShipID shipid = pfsPlayer->GetShipID();
- SideID sideid = pside->GetObjectID();
- bool fTeamLeader = false;
- bool fMissionOwner = false;
- ImissionIGC * pMission = GetIGCMission();
- assert (sideid != SIDE_TEAMLOBBY);
- CFSSide* pfsSide = CFSSide::FromIGC(pside);
- if (pfsPlayer->GetSide() == NULL || pfsPlayer->GetMission() != this)
- {
- assert(false);
- if (pfsPlayer->GetMission())
- RemovePlayerFromMission(pfsPlayer, QSR_Quit);
- pfsPlayer->GetMission()->AddPlayerToMission(pfsPlayer);
- }
- else if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
- RemovePlayerFromSide(pfsPlayer, QSR_SwitchingSides);
- debugf("Player %s, ship=%d joined side %d, mission=%x\n",
- pfsPlayer->GetName(), pfsPlayer->GetShipID(),
- sideid, GetCookie());
- {
- OldPlayerLink* popl = GetOldPlayerLink(pfsPlayer->GetName());
- if (popl)
- {
- delete popl;
- }
- }
- // Since they're changing sides, then they're not requesting a position anywhere anymore
- RemoveJoinRequest(pfsPlayer, pside);
- // check to see if we need a mission leader...
- if (m_misdef.iSideMissionOwner < 0)
- fMissionOwner = true;
- else
- {
- IsideIGC * pside = pMission->GetSide(m_misdef.iSideMissionOwner);
- if (!HasPlayers(pside, true)) // no one on the mission leader's side
- fMissionOwner = true;
- }
- assert(pside->GetActiveF()); // shouldn't be joining an inactive team
- m_misdef.rgcPlayers[sideid]++;
- // Set their stuff appropriate for this side
- assert(pfsPlayer->GetMoney() == 0);
- pfsPlayer->GetIGCShip()->SetWingID(1);
- if (!HasPlayers(pside, true)) // we have a new team leader
- {
- fTeamLeader = true;
- assert (m_misdef.rgShipIDLeaders[sideid] == NA);
- SetLeaderID(sideid, shipid);
- if (fMissionOwner) // we have a new mission leader too
- {
- fMissionOwner = true;
- m_misdef.iSideMissionOwner = sideid;
- }
- }
- // announce the guy that we were called for. Make sure nothing got wacky
- assert(IMPLIES(fMissionOwner, fTeamLeader));
-
- assert(IFF(pside->GetActiveF(),
- (STAGE_NOTSTARTED == GetStage()) || (HasPlayers(pside, true) || m_misdef.misparms.bAllowEmptyTeams)));
- BEGIN_PFM_CREATE(g.fm, pfmJoinSide, S, JOIN_SIDE)
- END_PFM_CREATE
- pfmJoinSide->shipID = shipid;
- pfmJoinSide->sideID = sideid;
- if (fTeamLeader)
- {
- BEGIN_PFM_CREATE(g.fm, pfmSetTeamLeader, CS, SET_TEAM_LEADER)
- END_PFM_CREATE
- pfmSetTeamLeader->shipID = shipid;
- pfmSetTeamLeader->sideID = sideid;
- // put them on the command wing
- pfsPlayer->GetIGCShip()->SetWingID(0);
- }
- if (fMissionOwner)
- {
- BEGIN_PFM_CREATE(g.fm, pfmSetMissionOwner, CS, SET_MISSION_OWNER)
- END_PFM_CREATE
- pfmSetMissionOwner->shipID = shipid;
- pfmSetMissionOwner->sideID = sideid;
- }
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- pfsPlayer->SetTreasureObjectID(NA); //NYI shouldn't we also set money here?
- pfsPlayer->SetSide(this, pside);
- pfsPlayer->SetReady(true);
- // set them on their starting wing
- BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
- END_PFM_CREATE
- pfmSetWingID->wingID = pfsPlayer->GetIGCShip()->GetWingID();
- pfmSetWingID->shipID = shipid;
- pfmSetWingID->bCommanded = true;
- g.fm.SendMessages(pfsSide->GetGroup(), FM_GUARANTEED, FM_FLUSH);
- if (fTeamLeader)
- {
- if (m_misdef.misparms.bLockTeamSettings)
- {
- // if this is a squad game, set the squad to the invited squad.
- if (m_misdef.misparms.bSquadGame)
- {
- const char* pzSquadName = CFSSide::FromIGC(pside)->GetInvitedSquadName();
- if(pzSquadName)
- {
- SquadMembershipLink* pSquadLink = pfsPlayer->GetSquadMembershipList()->first();
- for (; pSquadLink; pSquadLink = pSquadLink->next())
- {
- if (_stricmp(pSquadLink->data()->GetName(), pzSquadName) == 0)
- {
- SetSideSquad(sideid, pSquadLink->data()->GetID());
- break;
- }
- }
- }
- }
- }
- // set the squad if this is a squad game
- else if (m_misdef.misparms.bSquadGame)
- SetSideSquad(sideid, pfsPlayer->GetPreferredSquadToLead());
- // otherwise reset the team name
- else
- SetSideName(sideid, sideNames[sideid]);
- }
- if (STAGE_STARTED != GetStage() && STAGE_STARTING != GetStage())
- {
- g.fm.SetDefaultRecipient((CFMRecipient*) pfsPlayer->GetConnection(),
- FM_GUARANTEED);
- //Tell the player wing ID for every other person on the side
- for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
- {
- IshipIGC* ps = psl->data();
- if (ps != pfsPlayer->GetIGCShip())
- {
- ShipID shipID = ps->GetObjectID();
- BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
- END_PFM_CREATE
- pfmSetWingID->wingID = ps->GetWingID();
- pfmSetWingID->shipID = shipID;
- pfmSetWingID->bCommanded = true;
- }
- }
- g.fm.SendMessages(NULL, FM_GUARANTEED, FM_FLUSH); // default recipient
- if (STAGE_NOTSTARTED == GetStage())
- CheckForSideAllReady(pside);
- }
- else
- {
- // set them to auto-donate to the team leader
- CFSPlayer* pfsLeader = GetLeader(pside->GetObjectID());
- pfsPlayer->SetAutoDonate((pfsPlayer != pfsLeader) ? pfsLeader : NULL, 0, true);
- // tell them their starting sector so they can display the mission briefing
- bool bGenerateCivBriefing = m_strStoryText.IsEmpty();
- const char* szBriefingText = bGenerateCivBriefing
- ? GetBase(pside)->GetCluster()->GetName() : m_strStoryText;
- BEGIN_PFM_CREATE(g.fm, pfmSetBriefingText, S, SET_BRIEFING_TEXT)
- FM_VAR_PARM(szBriefingText, CB_ZTS)
- END_PFM_CREATE
- pfmSetBriefingText->fGenerateCivBriefing = bGenerateCivBriefing;
- g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
- // tell them about the world
- SendMissionInfo(pfsPlayer, pside);
- // tell them about the players who have flags
- {
- const ShipListIGC* pships = m_pMission->GetShips();
- for (ShipLinkIGC* psl = pships->first(); (psl != NULL); psl = psl->next())
- {
- IshipIGC* pship = psl->data();
- SideID sidFlag = pship->GetFlag();
- if (sidFlag != NA)
- {
- BEGIN_PFM_CREATE(g.fm, pfmGain, S, GAIN_FLAG)
- END_PFM_CREATE
- pfmGain->sideidFlag = sidFlag;
- pfmGain->shipidRecipient = pship->GetObjectID();
- }
- }
- }
- assert (pfsPlayer->GetIGCShip()->GetDeaths() == pfsPlayer->GetPlayerScoreObject()->GetDeaths());
- assert (pfsPlayer->GetIGCShip()->GetEjections() == pfsPlayer->GetPlayerScoreObject()->GetEjections());
- assert (pfsPlayer->GetIGCShip()->GetChildShips()->n() == 0);
- if (pfsPlayer->GetLifepodCluster() && (STAGE_STARTED == GetStage()))
- {
- //Flush the send buffer to clear out the flag information.
- g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
- //Oopsie ... joined in their underwear ... make em' walk home
- IhullTypeIGC* pht = pfsPlayer->GetSide()->GetCivilization()->GetLifepod();
- pfsPlayer->GetIGCShip()->SetBaseHullType(pht);
- pfsPlayer->ShipStatusHullChange(pht);
- pfsPlayer->GetIGCShip()->SetPosition(pfsPlayer->GetLifepodPosition());
- pfsPlayer->GetIGCShip()->SetVelocity(Vector::GetZero());
- Orientation o;
- o.Reset();
- pfsPlayer->GetIGCShip()->SetOrientation(o);
- pfsPlayer->GetIGCShip()->SetCluster(pfsPlayer->GetLifepodCluster());
- pfsPlayer->SetLifepod(NULL, Vector::GetZero());
- }
- else
- {
- IstationIGC * pstation = GetBase(pside);
- pfsPlayer->GetIGCShip()->SetStation(pstation);
- pfsPlayer->ShipStatusStart(pstation);
- }
- if (STAGE_STARTED == GetStage())
- {
- pfsPlayer->GetPlayerScoreObject()->Connect(g.timeNow);
- // let them know that the game has started
- BEGIN_PFM_CREATE(g.fm, pfmEnterGame, S, ENTER_GAME)
- END_PFM_CREATE
- if (m_misdef.misparms.IsProsperityGame())
- {
- //Ship down the win the game bucket for all sides
- for (SideLinkIGC* psl = pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- BucketLinkIGC* pbl = psl->data()->GetBuckets()->last();
- {
- assert (pbl != NULL);
- IbucketIGC* pbucket = pbl->data();
- assert ((pbucket->GetBucketType() == OT_development) &&
- (pbucket->GetBuyable()->GetObjectID() == c_didTeamMoney));
- BEGIN_PFM_CREATE(g.fm, pfmBucketStatus, S, BUCKET_STATUS)
- END_PFM_CREATE
- pfmBucketStatus->timeTotal = pbucket->GetTime();
- pfmBucketStatus->moneyTotal = pbucket->GetMoney();
- pfmBucketStatus->iBucket = pbucket->GetObjectID();
- pfmBucketStatus->sideID = psl->data()->GetObjectID();
- }
- }
- }
- g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
- }
- }
- }
- /*-------------------------------------------------------------------------
- * RemovePlayerFromSide
- *-------------------------------------------------------------------------
- * Purpose:
- * Removes a player from a side to the team lobby, to maintain team/mission leader status
- * This must be called INSTEAD OF IGC's SetSide() for the player's new side.
- *
- * Side Effects:
- * Maintain team/mission leader status
- */
- void CFSMission::RemovePlayerFromSide(CFSPlayer * pfsPlayer, QuitSideReason reason, const char* szMessageParam)
- {
- IsideIGC * psideOld = pfsPlayer->GetSide();
- SideID sideidOld = psideOld->GetObjectID();
- pfsPlayer->SetDPGroup(NULL, false);
- ShipID shipid = pfsPlayer->GetShipID();
- SquadID squadID = psideOld->GetSquadID();
- IshipIGC * pshipPlayer = pfsPlayer->GetIGCShip();
- ImissionIGC * pMission = GetIGCMission();
- bool bTurnOnAutoaccept = false;
- bool bWasTeamLeader = false;
- pfsPlayer->GetPlayerScoreObject()->Disconnect(g.timeNow);
- SideID sidFlag = pshipPlayer->GetFlag();
- if (sidFlag != NA)
- {
- const Vector& p = pfsPlayer->GetIGCShip()->GetPosition();
- float lm = m_pMission->GetFloatConstant(c_fcidLensMultiplier);
- float r = 1.5f * m_pMission->GetFloatConstant(c_fcidRadiusUniverse);
- if (p.x*p.x + p.y*p.y + p.z*p.z/(lm*lm) > r*r)
- {
- ((FedSrvSiteBase*)m_psiteIGC)->RespawnFlag(sidFlag);
- }
- else
- {
- DataTreasureIGC dt;
- dt.treasureCode = c_tcFlag;
- dt.treasureID = sidFlag;
- dt.amount = 0;
- dt.createNow = false;
- dt.lifespan = 3600.0f * 24.0f * 10.0f; //10 days
- CreateTreasure(g.timeNow, pfsPlayer->GetIGCShip(), &dt, pfsPlayer->GetIGCShip()->GetPosition(), 100.0f);
- }
- }
- debugf("Player %s, ship=%d quitting side %d, mission=%x\n",
- pfsPlayer->GetName(), pfsPlayer->GetShipID(),
- pfsPlayer->GetSide() ? pfsPlayer->GetSide()->GetObjectID() : NA,
- GetCookie());
- pfsPlayer->ShipStatusExit();
- //They are leaving their team ... promote
- {
- const ShipListIGC* pshipsChildren = pfsPlayer->GetIGCShip()->GetChildShips();
- if (pshipsChildren->first())
- {
- IclusterIGC* pcluster = pfsPlayer->GetIGCShip()->GetCluster();
- IshipIGC* pship = pshipsChildren->first()->data();
- pship->Promote();
- ((CFSShip*)(pship->GetPrivateData()))->ShipStatusRecalculate();
- BEGIN_PFM_CREATE(g.fm, pfmPromote, S, PROMOTE)
- END_PFM_CREATE
- pfmPromote->shipidPromoted = pship->GetObjectID();
- if (pcluster)
- g.fm.SendMessages(GetGroupSectorFlying(pcluster), FM_GUARANTEED, FM_FLUSH); //GetGroupRealSides(),
- else
- g.fm.SendMessages(CFSSide::FromIGC(psideOld)->GetGroup(), FM_GUARANTEED, FM_FLUSH); //GetGroupRealSides(),
- }
- }
- m_misdef.rgcPlayers[sideidOld]--;
- CFSPlayer* pfsNewLeader = NULL;
- if (m_misdef.rgShipIDLeaders[sideidOld] == shipid)
- {
- //The person leaving the team was the team leader ...
- bWasTeamLeader = true;
- SideID iSideNewOwner = sideidOld; // side of person getting promoted, which is same team if anyone left
- ShipID shipidNewOwner = NA;
- bool fMissionOwner = false;
- int cPlayers = GetCountOfPlayers(psideOld, true);
- if (cPlayers == 1)
- {
- //There was one player -- the soon to be gone team leader
-
- if (STAGE_NOTSTARTED == m_misdef.stage)
- {
- //the game hasn't started yet ... accept everyone on the request list
- BEGIN_PFM_CREATE(g.fm, pfmAutoAccept, CS, AUTO_ACCEPT)
- END_PFM_CREATE
- pfmAutoAccept->iSide = sideidOld;
- pfmAutoAccept->fAutoAccept = true;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- bTurnOnAutoaccept = true;
- }
- else
- {
- // otherwise, no one accepted them to the team so I suppose they've
- // been implicitly rejected.
- RejectSideJoinRequests(psideOld);
- }
- }
- if (cPlayers > 1) // Other people still on the side--side count not adjusted yet
- {
- const ShipListIGC * plistShip = psideOld->GetShips();
- if (STAGE_STARTED == m_misdef.stage)
- {
- //Leader left the game in the middle ... pick a leader based on who has the
- //most people donating to them
- IshipIGC* pshipNewLeader = PickNewLeader(plistShip, pshipPlayer, 0);
- if (pshipNewLeader)
- {
- pfsNewLeader = ((CFSShip*)(pshipNewLeader->GetPrivateData()))->GetPlayer();
- shipidNewOwner = pshipNewLeader->GetObjectID();
- }
- }
- if (pfsNewLeader == NULL)
- {
- // Look for someone else on the team to be team leader
- // (there must be one), favoring someone who can lead the current squad.
- for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- if (plinkShip->data() != pshipPlayer && ISPLAYER(plinkShip->data()))
- {
- CFSPlayer* pfsPlayerTemp = ((CFSShip*)(plinkShip->data()->GetPrivateData()))->GetPlayer();
-
- if (pfsPlayerTemp->GetCanLeadSquad(squadID))
- {
- pfsNewLeader = pfsPlayerTemp;
- shipidNewOwner = plinkShip->data()->GetObjectID();
- break;
- }
- else if (!pfsNewLeader)
- {
- pfsNewLeader = pfsPlayerTemp;
- shipidNewOwner = plinkShip->data()->GetObjectID();
- }
- }
- }
- assert(pfsNewLeader);
- }
- SetLeaderID(iSideNewOwner, shipidNewOwner);
- if (m_misdef.iSideMissionOwner == sideidOld)
- {
- fMissionOwner = true;
- }
- }
- else // no one left on the team
- {
- // Then it better be auto-accept again
- SetLeaderID(sideidOld, NA);
- // also, better set the squad to NA if the game hasn't started
- // (but leave the squad for scoring purposes if it has started)
- if (STAGE_NOTSTARTED == m_misdef.stage)
- SetSideSquad(sideidOld, NA);
-
- if (m_misdef.iSideMissionOwner == sideidOld)
- {
- m_misdef.iSideMissionOwner = NA;
- // Now gotta look for another side to be mission owner
- const SideListIGC * plistSide = m_pMission->GetSides();
- for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
- {
- IsideIGC * pside = plinkSide->data();
- if ((psideOld != pside) && HasPlayers(pside, true)) // found one
- {
- iSideNewOwner = pside->GetObjectID();
- shipidNewOwner = GetLeader(iSideNewOwner)->GetShipID();
- fMissionOwner = true;
- assert(m_misdef.rgShipIDLeaders[iSideNewOwner] == shipidNewOwner);
- m_misdef.iSideMissionOwner = iSideNewOwner;
- break;
- }
- }
- // if we don't have a new mission owner, unlock the lobby and the sides
- if (m_misdef.iSideMissionOwner == NA)
- {
- if (m_misdef.misparms.bLockLobby)
- {
- SetLockLobby(false);
- BEGIN_PFM_CREATE(g.fm, pfmLockLobby, CS, LOCK_LOBBY)
- END_PFM_CREATE
- pfmLockLobby->fLock = false;
- }
- if (m_misdef.misparms.bLockSides)
- {
- SetLockSides(false);
- BEGIN_PFM_CREATE(g.fm, pfmLockSides, CS, LOCK_SIDES)
- END_PFM_CREATE
- pfmLockSides->fLock = false;
- }
- }
- // No one's left in this side
- SetLeaderID(sideidOld, NA);
- }
- }
- if (shipidNewOwner != NA) // somebody's getting promoted
- {
- // announce new leader
- BEGIN_PFM_CREATE(g.fm, pfmSetTeamLeader, CS, SET_TEAM_LEADER)
- END_PFM_CREATE
- pfmSetTeamLeader->shipID = shipidNewOwner;
- pfmSetTeamLeader->sideID = iSideNewOwner;
- if (fMissionOwner)
- {
- BEGIN_PFM_CREATE(g.fm, pfmSetMissionOwner, CS, SET_MISSION_OWNER)
- END_PFM_CREATE
- pfmSetMissionOwner->shipID = shipidNewOwner;
- pfmSetMissionOwner->sideID = iSideNewOwner;
- }
- }
- }
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- Money payday;
- if (STAGE_STARTED == m_misdef.stage || STAGE_STARTING == m_misdef.stage)
- {
- //The player was on a side and the game was going
- if (pfsNewLeader && (pfsNewLeader->GetIGCShip()->GetAutoDonate() == pshipPlayer))
- pfsNewLeader->SetAutoDonate(NULL, 0, false);
- //Anyone who was autodonating to this player is no longer autodonating to this player
- for (ShipLinkIGC* psl = psideOld->GetShips()->first(); (psl != NULL); psl = psl->next())
- {
- if ((psl->data()->GetAutoDonate() == pshipPlayer) &&
- ((pfsNewLeader == NULL) || (psl->data() != pfsNewLeader->GetIGCShip())))
- {
- ((CFSShip*)(psl->data()->GetPrivateData()))->GetPlayer()->SetAutoDonate(pfsNewLeader, 0, false);
- }
- }
- g.fm.SendMessages(CFSSide::FromIGC(psideOld)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
- payday = pfsPlayer->GetMoney() + pfsPlayer->GetIGCShip()->GetValue();
- assert(STAGE_STARTING != m_misdef.stage || payday == 0);
- }
- else
- payday = 0;
- pfsPlayer->SetMoney(0);
- // announce the guy that we were called for. Make sure nothing got wacky
- BEGIN_PFM_CREATE(g.fm, pfmSideChange, CS, QUIT_SIDE)
- FM_VAR_PARM(szMessageParam, CB_ZTS)
- END_PFM_CREATE
- pfmSideChange->shipID = shipid;
- pfmSideChange->reason = reason;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- pfsPlayer->Reset(false);
- if (STAGE_STARTED != m_misdef.stage)
- pfsPlayer->GetIGCShip()->SetExperience(1.0f);
- pfsPlayer->SetSide(this, pMission->GetSide(SIDE_TEAMLOBBY));
- pfsPlayer->SetReady(true);
-
- GiveSideMoney(psideOld, payday);
- bool fDeactivate = (STAGE_NOTSTARTED != m_misdef.stage) && !HasPlayers(psideOld, false);
- if (fDeactivate)
- DeactivateSide(psideOld); // deactivate the side _after_ the side change
- else
- CheckForSideAllReady(psideOld); // its ready state may have changed
- // if the game has not started and the leader quit, make sure the squad memberships work
- if (bWasTeamLeader && STAGE_NOTSTARTED == m_misdef.stage && squadID != NA)
- MaintainSquadLeadership(sideidOld);
- if (bTurnOnAutoaccept)
- SetAutoAccept(psideOld, true);
- if (QSRIsBoot(reason) && (sideidOld >= 0))
- {
- unsigned char bannedSideMask = pfsPlayer->GetBannedSideMask() | SideMask(sideidOld);
- pfsPlayer->SetBannedSideMask(bannedSideMask);
- }
- }
- void CFSMission::AddInvitation(SideID sid, char * szPlayerName)
- {
- if(sid >= c_cSidesMax)
- return;
- m_pFSSides[sid]->AddInvitation(szPlayerName);
- }
- /*-------------------------------------------------------------------------
- * IsInvited
- *-------------------------------------------------------------------------
- */
- bool CFSMission::IsInvited(CFSPlayer * pPlayer)
- {
- assert(RequiresInvitation());
- for (std::vector<CFSSide*>::iterator _i(m_pFSSides.begin()); _i != m_pFSSides.end(); ++_i)
- {
- if(static_cast<CFSSide*>(*_i)->IsInvited(pPlayer))
- return true;
- }
- return false;
- }
- /*-------------------------------------------------------------------------
- * AddBallot
- *-------------------------------------------------------------------------
- */
- void CFSMission::AddBallot(Ballot * pBallot)
- {
- m_ballots.PushEnd(pBallot);
- }
- /*-------------------------------------------------------------------------
- * TallyVote
- *-------------------------------------------------------------------------
- */
- void CFSMission::TallyVote(CFSPlayer* pfsPlayer, BallotID ballotID, bool bVote)
- {
- for (BallotList::Iterator iter(m_ballots); !iter.End(); iter.Next())
- {
- if (iter.Value()->GetBallotID() == ballotID)
- {
- iter.Value()->CastVote(pfsPlayer, bVote);
- break;
- }
- }
- }
- /*-------------------------------------------------------------------------
- * RemovePlayerByName
- *-------------------------------------------------------------------------
- * Purpose:
- * Removes all players with the given character name from this mission,
- * if they are a member.
- *
- * Parameters:
- * character name to boot and the reason for booting them.
- *
- * Returns:
- * true if a player was booted
- */
- bool CFSMission::RemovePlayerByName(const char* szCharacterName, QuitSideReason reason, const char* szMessageParam)
- {
- ShipLinkIGC * pShiplink = GetIGCMission()->GetShips()->first();
-
- while (pShiplink)
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
-
- if (pfsShip->IsPlayer())
- {
- CFSPlayer * pfsPlayer = pfsShip->GetPlayer();
-
- if (_stricmp(pfsPlayer->GetName(), szCharacterName) == 0)
- {
- RemovePlayerFromMission(pfsShip->GetPlayer(), reason, szMessageParam);
- debugf("Booted duplicate character %s from mission %x.\n",
- pfsPlayer->GetName(), GetCookie());
- break;
- }
- }
- pShiplink = pShiplink->next();
- }
- return pShiplink != NULL;
- }
- /*-------------------------------------------------------------------------
- * RemovePlayerByCDKey
- *-------------------------------------------------------------------------
- * Purpose:
- * Removes all players with the given CD Key from this mission,
- * if they are a member.
- *
- * Parameters:
- * character CD Key to boot and the reason for booting them.
- *
- * Returns:
- * true if a player was booted
- */
- bool CFSMission::RemovePlayerByCDKey(const char* szCDKey, QuitSideReason reason, const char* szMessageParam)
- {
- ShipLinkIGC * pShiplink = GetIGCMission()->GetShips()->first();
-
- while (pShiplink)
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
-
- if (pfsShip->IsPlayer())
- {
- CFSPlayer * pfsPlayer = pfsShip->GetPlayer();
-
- if (_stricmp(pfsPlayer->GetCDKey(), szCDKey) == 0)
- {
- RemovePlayerFromMission(pfsShip->GetPlayer(), reason, szMessageParam);
- debugf("Booted character %s with duplicate CD Key %s from mission %x.\n",
- pfsPlayer->GetName(), pfsPlayer->GetCDKey(), GetCookie());
- break;
- }
- }
- pShiplink = pShiplink->next();
- }
- return pShiplink != NULL;
- }
- /*-------------------------------------------------------------------------
- * GetCountOfPlayers
- *-------------------------------------------------------------------------
- * Purpose:
- * Count up number of human players on side, or mission (when pside==NULL)
- *
- * Parameters:
- * side to check, NULL for whole mission
- *
- * Returns:
- * count of players
- */
- int CFSMission::GetCountOfPlayers(IsideIGC * pside, bool bCountGhosts)
- {
- int cPlayers = 0;
- const ShipListIGC * plistShip = pside ? pside->GetShips() : m_pMission->GetShips();
- for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- if (ISPLAYER(plinkShip->data()) && (bCountGhosts || !plinkShip->data()->IsGhost()))
- cPlayers++;
- }
- return cPlayers;
- }
- /*-------------------------------------------------------------------------
- * HasPlayers
- *-------------------------------------------------------------------------
- * Purpose:
- * Like GetCountOfPlayers, but just determines whether there's anyone on
- * a side, so slightly faster
- *
- * Parameters:
- * side, or NULL for mission
- *
- * Returns:
- * whether the side has any players
- */
- bool CFSMission::HasPlayers(IsideIGC * pside, bool bCountGhosts)
- {
- const ShipListIGC * plistShip = pside ? pside->GetShips() : m_pMission->GetShips();
- for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- if (ISPLAYER(plinkShip->data()) && (bCountGhosts || !plinkShip->data()->IsGhost()))
- return true;
- }
- return false;
- }
- IstationIGC * CFSMission::GetBase(IsideIGC * pside)
- {
- if (pside)
- {
- for (StationLinkIGC* psl = pside->GetStations()->first(); (psl != NULL); psl = psl->next())
- {
- IstationIGC* pstation = psl->data();
- if (pstation->GetStationType()->HasCapability(c_sabmRestart))
- return pstation;
- }
- }
- return NULL;
- }
- //
- // This probably should be in CFSSide
- //
- CFSPlayer * CFSMission::GetLeader(SideID sid)
- {
- assert (NA != sid);
- if (sid == SIDE_TEAMLOBBY) // lobby side never has a leader
- return NULL;
- ShipID shipid = m_misdef.rgShipIDLeaders[sid];
- return NA == shipid ? NULL : CFSShip::GetShipFromID(shipid)->GetPlayer();
- }
- //
- // This probably should be in CFSSide
- //
- void CFSMission::SetLeaderID(SideID sideID, ShipID shipID)
- {
- if (m_misdef.rgShipIDLeaders[sideID] != NA)
- {
- CFSShip* pfsShip = CFSShip::GetShipFromID(m_misdef.rgShipIDLeaders[sideID]);
- assert (pfsShip);
- assert (pfsShip->IsPlayer());
- pfsShip->GetPlayerScoreObject()->StopCommand(m_pMission->GetLastUpdate());
- }
- m_misdef.rgShipIDLeaders[sideID] = shipID;
- if (shipID != NA)
- {
- CFSShip* pfsShip = CFSShip::GetShipFromID(shipID);
- assert (pfsShip);
- assert (pfsShip->IsPlayer());
- pfsShip->GetPlayerScoreObject()->StartCommand(m_pMission->GetLastUpdate());
- }
- }
- void CFSMission::SetLeader(CFSPlayer * pfsPlayer)
- {
- assert(pfsPlayer);
- SideID sid = pfsPlayer->GetSide()->GetObjectID();
- ShipID shipId = pfsPlayer->GetShipID();
- assert(0 <= sid && sid < m_misdef.misparms.nTeams);
- CFSPlayer * pfsOldLeader = GetLeader(sid);
- assert(pfsOldLeader);
- // take the old leader off of the command wing
- if (pfsOldLeader->GetIGCShip()->GetWingID() == 0)
- {
- pfsOldLeader->GetIGCShip()->SetWingID(1);
- BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
- END_PFM_CREATE
- pfmSetWingID->wingID = 1;
- pfmSetWingID->shipID = pfsOldLeader->GetShipID();
- pfmSetWingID->bCommanded = true;
- }
- // put them on the command wing
- pfsPlayer->GetIGCShip()->SetWingID(0);
- BEGIN_PFM_CREATE(g.fm, pfmSetWingID, CS, SET_WINGID)
- END_PFM_CREATE
- pfmSetWingID->wingID = 0;
- pfmSetWingID->shipID = shipId;
- pfmSetWingID->bCommanded = true;
- g.fm.SendMessages(CFSSide::FromIGC(pfsPlayer->GetSide())->GetGroup(), FM_GUARANTEED, FM_FLUSH);
- // change leaders
- SetLeaderID(sid, shipId);
- BEGIN_PFM_CREATE(g.fm, pfmSetTeamLeader, CS, SET_TEAM_LEADER)
- END_PFM_CREATE
- pfmSetTeamLeader->shipID = shipId;
- pfmSetTeamLeader->sideID = sid;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- /*-------------------------------------------------------------------------
- * SetSideName
- *-------------------------------------------------------------------------
- * Purpose:
- * Set the name of a side and notifies clients
- *
- * Parameters:
- * The side whose name should changed and the new name
- */
- void CFSMission::SetSideName(SideID sid, const char* szName)
- {
- assert(sid >= 0 && sid < c_cSidesMax);
- assert(strlen(szName) < c_cbName);
- IsideIGC* pside = m_pMission->GetSide(sid);
- if (!pside)
- return;
- ZString strNameOld(m_misdef.rgszName[sid]);
- if (szName != m_misdef.rgszName[sid])
- {
- strncpy(m_misdef.rgszName[sid], szName, c_cbName - 1);
- m_misdef.rgszName[sid][c_cbName-1] = '\0';
- m_pMission->GetSide(sid)->SetName(m_misdef.rgszName[sid]);
- }
- // tell the clients about the new side info
- BEGIN_PFM_CREATE(g.fm, pfmSetTeamInfo, CS, SET_TEAM_INFO)
- END_PFM_CREATE
- pfmSetTeamInfo->sideID = sid;
- pfmSetTeamInfo->squadID = pside->GetSquadID();
- strcpy(pfmSetTeamInfo->SideName, m_misdef.rgszName[sid]);
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- // Fire an AGCEvent to indicate the Team info change
- LPCSTR pszGame = GetMissionDef()->misparms.strGameName;
- long idGame = GetIGCMission() ? GetIGCMission()->GetMissionID() : -1;
- long idTeam = GetIGCMission()->GetSide(sid)->GetUniqueID();
- LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
- _AGCModule.TriggerContextEvent(NULL, EventID_TeamInfoChange, pszContext,
- strNameOld, idTeam, -1, -1, 3,
- "GameID" , VT_I4 , idGame,
- "GameName" , VT_LPSTR, pszGame,
- "NewTeamName", VT_LPSTR, szName);
- };
- /*-------------------------------------------------------------------------
- * SetSideSquad
- *-------------------------------------------------------------------------
- * Purpose:
- * Set the squad for a side, booting players who are not on that squad,
- * changing the team name, and notifing players of the team's new squad.
- *
- * Parameters:
- * The side whose squad should changed and the id of the new squad
- */
- void CFSMission::SetSideSquad(SideID sid, SquadID squadID)
- {
- assert(sid >= 0 && sid < c_cSidesMax);
- IsideIGC* pside = m_pMission->GetSide(sid);
- // if the squad doesn't need to be changed, don't touch it.
- if (squadID == pside->GetSquadID())
- return;
- pside->SetSquadID(squadID);
-
- // loop through the players and boot anyone who is not a member of this squad
- if (squadID != NA)
- {
- ShipLinkIGC* pslNext;
- for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = pslNext)
- {
- pslNext = psl->next();
- CFSShip* pcs = (CFSShip *)(psl->data()->GetPrivateData());
- if (pcs->IsPlayer())
- {
- CFSPlayer* pfsPlayer = pcs->GetPlayer();
- if (!pfsPlayer->GetIsMemberOfSquad(squadID))
- {
- RemovePlayerFromSide(pfsPlayer, QSR_SquadChange);
- }
- }
- }
- }
- const char* szSquadName = NULL;
-
- if (m_misdef.misparms.bLockTeamSettings)
- {
- // don't change the name
- szSquadName = m_misdef.rgszName[sid];
- }
- else
- {
- CFSPlayer* pfsLeader = GetLeader(sid);
- if (squadID != NA)
- {
- assert(pfsLeader);
- for (SquadMembershipLink* pSquadLink = pfsLeader->GetSquadMembershipList()->first();
- pSquadLink != NULL; pSquadLink = pSquadLink->next())
- {
- if (pSquadLink->data()->GetID() == squadID)
- szSquadName = pSquadLink->data()->GetName();
- }
- }
- assert((squadID == NA) == (szSquadName == NULL));
- }
- // use SetSideName to send the new squadID along with the new name
- SetSideName(sid, szSquadName ? szSquadName : sideNames[sid]);
- SetLobbyIsDirty();
- };
- /*-------------------------------------------------------------------------
- * MaintainSquadLeadership
- *-------------------------------------------------------------------------
- * Purpose:
- * Makes sure the team has a squand and the current leader can lead the team
- * with the current squad. If not, it tries to fix this first by assigning
- * a new squad and possibly a new leader.
- *
- * Parameters:
- * The side to check
- */
- void CFSMission::MaintainSquadLeadership(SideID sid)
- {
- IsideIGC* pside = m_pMission->GetSide(sid);
- SquadID squadID = pside->GetSquadID();
- CFSPlayer* pfsLeader = GetLeader(sid);
- // don't try anything if the team settings are locked.
- if (m_misdef.misparms.bLockTeamSettings)
- return;
- if (pfsLeader && (squadID == NA || !pfsLeader->GetCanLeadSquad(squadID)))
- {
- // see which squad the current leader would prefer to lead
- squadID = pfsLeader->GetPreferredSquadToLead();
- // failing that, try to find a new leader
- if (squadID == NA)
- {
- ShipLinkIGC* pslNext;
- for (ShipLinkIGC* psl = pside->GetShips()->first(); psl != NULL && squadID == NA; psl = pslNext)
- {
- pslNext = psl->next();
- CFSShip* pcs = (CFSShip *)(psl->data()->GetPrivateData());
- if (pcs->IsPlayer())
- {
- CFSPlayer* pfsPlayer = pcs->GetPlayer();
- squadID = pfsPlayer->GetPreferredSquadToLead();
- pfsLeader = pfsPlayer;
- }
- if (squadID != NA)
- {
- // switch to the new leader who is qualified to lead
- SetLeader(pfsLeader);
- }
- }
- }
- // set the team to its new squad
- SetSideSquad(sid, squadID);
- // if we couldn't find a squad leader, boot everyone on the team
- if (squadID == NA)
- {
- ShipLinkIGC* pslNext;
- for (ShipLinkIGC* psl = pside->GetShips()->first(); psl != NULL && squadID == NA; psl = pslNext)
- {
- pslNext = psl->next();
- CFSShip* pcs = (CFSShip *)(psl->data()->GetPrivateData());
- if (pcs->IsPlayer())
- RemovePlayerFromSide(pcs->GetPlayer(), QSR_SquadChange);
- }
- }
- }
- }
- /*-------------------------------------------------------------------------
- * SetStage
- *-------------------------------------------------------------------------
- * Purpose:
- * Tell the mission what stage it's in, and tell the clients
- *
- * Parameters:
- * new stage
- */
- void CFSMission::SetStage(STAGE stage)
- {
- if (m_misdef.stage != stage)
- {
- assert(m_misdef.stage < stage || stage == STAGE_NOTSTARTED); // it's a one-way road (sort of)
- debugf("SetStage, stage=%d, mission=%x\n", stage, GetCookie());
- m_misdef.stage = stage;
- m_misdef.fInProgress = stage == STAGE_STARTED;
- BEGIN_PFM_CREATE(g.fm, pfmMissionStage, S, MISSION_STAGE)
- END_PFM_CREATE
- pfmMissionStage->stage = GetStage();
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- m_pMission->SetMissionStage(stage);
- SetLobbyIsDirty();
- }
- }
- /*-------------------------------------------------------------------------
- * GiveSideMoney
- *-------------------------------------------------------------------------
- * Purpose:
- * Give a side some money, divided equally among all players
- */
- void CFSMission::GiveSideMoney(IsideIGC * pside, Money money)
- {
- assert (money >= 0);
- if (money != 0)
- {
- SideID sideID = pside->GetObjectID();
- m_rgMoney[sideID] += money;
- DoPayday(pside);
- }
- }
- /*-------------------------------------------------------------------------
- * SetMissionParams
- *-------------------------------------------------------------------------
- * Purpose:
- * Called when a client changes the mission parameters
- */
- void CFSMission::SetMissionParams(const MissionParams & misparmsNew)
- {
- MissionParams misparms = misparmsNew;
- assert(GetStage() == STAGE_NOTSTARTED);
- assert(misparms.Invalid() == NULL);
- // don't even think about changing the IGC static stuff.
- misparms.verIGCcore = m_misdef.misparms.verIGCcore;
- strncpy(misparms.szIGCStaticFile, m_misdef.misparms.szIGCStaticFile, c_cbFileName);
- // make sure it's properly marked as a club or non-club game too.
- #if !defined(ALLSRV_STANDALONE)
- misparms.bClubGame = true;
- #else // !defined(ALLSRV_STANDALONE)
- misparms.bClubGame = false;
- #endif // !defined(ALLSRV_STANDALONE)
- int numTeamsOld = m_misdef.misparms.nTeams;
- if (numTeamsOld > misparms.nTeams)
- {
- // destroy the extra teams
- for (SideID sideID = numTeamsOld - 1; sideID >= misparms.nTeams; sideID--)
- {
- // kick everyone off of the extra team
- IsideIGC* pside = m_pMission->GetSide(sideID);
- while (pside->GetShips()->first())
- {
- CFSShip* pship = (CFSShip*)(pside->GetShips()->first()->data()->GetPrivateData());
- assert(pship->IsPlayer());
- RemovePlayerFromSide(
- pship->GetPlayer(),
- QSR_SideDestroyed
- );
- }
- }
- }
- bool bSquadChange = m_misdef.misparms.bSquadGame != misparms.bSquadGame;
- m_misdef.misparms = misparms;
- // set Mission Name here too so that AGC Admin tool reports the params while mission stage is STAGE_NOTSTARTED
- m_pMission->SetMissionParams(&misparms);
- if (numTeamsOld < misparms.nTeams)
- {
- // add any new teams
- for (SideID sideID = numTeamsOld; sideID < misparms.nTeams; sideID++)
- {
- InitSide(sideID);
- }
- }
- m_pMission->UpdateSides(Time::Now(), &m_misdef.misparms, m_misdef.rgszName);
- // see if that changed the ready state of anyone.
- for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
- {
- CheckForSideAllReady(l->data());
- }
- // boot any players who are no longer the right rank to play in this game
- {
- const ShipListIGC* pships = m_pMission->GetShips();
- ShipLinkIGC* pshipLinkNext;
- for (ShipLinkIGC* pshipLink = pships->first();
- (pshipLink != NULL);
- pshipLink = pshipLinkNext)
- {
- pshipLinkNext = pshipLink->next();
- CFSPlayer* pfsPlayer = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
- RankID rank = pfsPlayer->GetPersistPlayerScore(NA)->GetRank();
- if ((misparms.iMinRank > rank || misparms.iMaxRank < rank) && !pfsPlayer->CanCheat())
- {
- RemovePlayerFromMission(pfsPlayer, QSR_RankLimits);
- }
- }
- }
- // if the squad setting has changed, update the new squad state
- if (bSquadChange)
- {
- for (SideID sideID = 0; sideID < misparms.nTeams; ++sideID)
- {
- if (misparms.bSquadGame)
- MaintainSquadLeadership(sideID);
- else
- SetSideSquad(sideID, NA);
- }
- }
- }
- /*-------------------------------------------------------------------------
- * ChangeCountdown
- *-------------------------------------------------------------------------
- * Purpose:
- * Called when we want to change the countdown to starting the game
- */
- void CFSMission::DelayCountdown(float fDelayLength)
- {
- if (GetStage() == STAGE_NOTSTARTED || GetStage() == STAGE_STARTING)
- {
- // delay the game start time as appropriate.
- m_misdef.misparms.timeStart += fDelayLength;
- // forward the new start time to everyone
- BEGIN_PFM_CREATE(g.fm, pfmStartTime, S, SET_START_TIME)
- END_PFM_CREATE
- pfmStartTime->timeStart = m_misdef.misparms.timeStart;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- }
- /*-------------------------------------------------------------------------
- * StartCountdown
- *-------------------------------------------------------------------------
- * Purpose:
- * Called when we want to start the countdown to starting the game
- */
- void CFSMission::StartCountdown(float fCountdownLength)
- {
- if (GetStage() == STAGE_NOTSTARTED || GetStage() == STAGE_STARTING)
- {
- // set (or reset) the game start time as appropriate.
- m_misdef.misparms.timeStart = Time::Now() + fCountdownLength;
- // forward the new start time to everyone
- BEGIN_PFM_CREATE(g.fm, pfmStartTime, S, SET_START_TIME)
- END_PFM_CREATE
- pfmStartTime->timeStart = m_misdef.misparms.timeStart;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- if (GetStage() == STAGE_NOTSTARTED)
- {
- // create the mission
- {
-
- for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
- {
- IsideIGC* pside = l->data();
- if (m_misdef.misparms.bAllowDevelopments)
- pside->SetGlobalAttributeSet(pside->GetCivilization()->GetBaseAttributes());
- else
- pside->ResetGlobalAttributeSet();
- }
- }
- m_pMission->GenerateMission(Time::Now(), &m_misdef.misparms, m_pttbmAltered, m_pttbmNewSetting);
- // tell each client their starting sector so they can display the mission briefing
- {
- for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
- {
- IsideIGC * pside = l->data();
- // tell them their starting sector so they can display the mission briefing
- bool bGenerateCivBriefing = m_strStoryText.IsEmpty();
- const char* szBriefingText = bGenerateCivBriefing
- ? GetBase(pside)->GetCluster()->GetName() : m_strStoryText;
- BEGIN_PFM_CREATE(g.fm, pfmSetBriefingText, S, SET_BRIEFING_TEXT)
- FM_VAR_PARM(szBriefingText, CB_ZTS)
- END_PFM_CREATE
- pfmSetBriefingText->fGenerateCivBriefing = bGenerateCivBriefing;
- g.fm.SendMessages(CFSSide::FromIGC(pside)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
- }
- }
- // let the clients know that the game is starting
- SetStage(STAGE_STARTING);
- // create the dplay groups for the clusters
- {
- const ClusterListIGC * pclist = m_pMission->GetClusters();
- for (ClusterLinkIGC * l = pclist->first(); (l != NULL); l = l->next())
- {
- IclusterIGC * pcluster = l->data();
- CreateDPGroups(pcluster);
- }
- }
- // set up each of the sides
- {
- const MissionParams* pmp = m_pMission->GetMissionParams();
- float moneyStart = m_pMission->GetFloatConstant(c_fcidStartingMoney);
- for (SideLinkIGC* l = m_pMission->GetSides()->first(); l; l = l->next())
- {
- IsideIGC * pside = l->data();
- CFSPlayer* pfsLeader = GetLeader(pside->GetObjectID());
- float moneyMultiplier = pmp->fStartingMoney + pside->GetCivilization()->GetBonusMoney();
- m_rgMoney[pside->GetObjectID()] = moneyMultiplier > 0.0f
- ? ((Money)(moneyStart * moneyMultiplier))
- : ((Money)0);
-
- //Set the leader to NULL first (so he is a legitimate autodonate target)
- if (pfsLeader)
- pfsLeader->SetAutoDonate(NULL, 0, false);
-
- // set up the team's money, and set up everyone to autodonate to the team leader
- const ShipListIGC* pships = pside->GetShips();
- for (ShipLinkIGC* pshipLink = pships->first();
- (pshipLink != NULL);
- pshipLink = pshipLink->next())
- {
- CFSShip* pfsShip = ((CFSShip*)(pshipLink->data()->GetPrivateData()));
- pfsShip->SetMoney(0);
- pfsShip->GetPlayer()->SetTreasureObjectID(NA);
-
- if ((pfsShip != pfsLeader) && pfsShip->IsPlayer())
- pfsShip->GetPlayer()->SetAutoDonate(pfsLeader, 0, false);
- }
-
- g.fm.SendMessages(CFSSide::FromIGC(pside)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
-
- if (HasPlayers(pside, true))
- {
- // tell them about the world
- SendMissionInfo(NULL, pside);
- }
- else
- {
- // don't penalize a squad who is not in the game
- if (pside->GetSquadID() != NA)
- SetSideSquad(pside->GetObjectID(), NA);
- DeactivateSide(pside);
- }
- const StationListIGC* pstations = pside->GetStations();
- assert (pstations->n() >= 1);
- const int c_stationsMax = 20;
- IstationIGC* stations[c_stationsMax];
- int nStations = 0;
- {
- for (StationLinkIGC* psl = pstations->first(); (psl != NULL); psl = psl->next())
- {
- IstationIGC* pstation = psl->data();
- if (pstation->GetStationType()->HasCapability(c_sabmRestart))
- {
- assert (nStations < c_stationsMax);
- stations[nStations++] = pstation;
- }
- }
- }
- assert (nStations >= 1);
- IstationIGC* pstation = stations[0];
- assert (pstation);
- if (nStations == 1)
- {
- //Start all ships at that station
- for (pshipLink = pships->first();
- (pshipLink != NULL);
- pshipLink = pshipLink->next())
- {
- pshipLink->data()->SetStation(pstation);
- ((CFSShip*)(pshipLink->data()->GetPrivateData()))->ShipStatusStart(pstation);
- }
- }
- else
- {
- //Multiple stations for a side ... try to divy things up evenly without breaking wings up
- //We need at least this many/station,
- int minPerStation = pships->n() / (2 * nStations);
- //and can't have more than this (assuming all the other stations have the min)
- int maxPerStation = pships->n() - minPerStation * (nStations - 1);
- //Count the number of players on each wing
- int players[c_widMax] = {0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0};
- int assignment[c_widMax] = {-2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2};
- int unassignedWings = 0;
- {
- for (pshipLink = pships->first();
- (pshipLink != NULL);
- pshipLink = pshipLink->next())
- {
- IshipIGC* pship = pshipLink->data();
- WingID wid = pship->GetWingID();
- assert (wid >= 0);
- assert (wid < c_widMax);
- if (players[wid]++ == 0)
- unassignedWings++;
- }
- }
- int population[c_stationsMax];
- {
- for (int i = 0; (i < nStations); i++)
- population[i] = 0;
- }
- while (unassignedWings-- > 0)
- {
- //Find the largest unassigned wing
- int widMax = -1;
- {
- for (int i = 0; (i < c_widMax); i++)
- {
- if ((assignment[i] == -2) && ((widMax == -1) || (players[i] >= players[widMax])))
- widMax = i;
- }
- }
- assert (widMax != -1);
- //Find the least populated station
- int stationMin = 0;
- {
- for (int i = 1; (i < nStations); i++)
- {
- if (population[i] < population[stationMin])
- stationMin = i;
- }
- }
- if (population[stationMin] + players[widMax] <= maxPerStation)
- {
- population[stationMin] += players[widMax];
- assignment[widMax] = stationMin;
- }
- else
- assignment[widMax] = -1;
- }
-
- {
- for (pshipLink = pships->first();
- (pshipLink != NULL);
- pshipLink = pshipLink->next())
- {
- IshipIGC* pship = pshipLink->data();
- WingID wid = pship->GetWingID();
- assert (wid >= 0);
- assert (wid < c_widMax);
- int stationMin;
- if (assignment[wid] == -1)
- {
- stationMin = 0;
- {
- for (int i = 1; (i < nStations); i++)
- {
- if (population[i] < population[stationMin])
- stationMin = i;
- }
- }
- population[stationMin]++;
- }
- else
- stationMin = assignment[wid];
- assert (stationMin >= 0);
- IstationIGC* pstation = stations[stationMin];
- pshipLink->data()->SetStation(pstation);
- ((CFSShip*)(pshipLink->data()->GetPrivateData()))->ShipStatusStart(pstation);
- }
- }
- }
-
- if (pmp->bAllowDevelopments)
- {
- //Create miners for each side in the sector with their home starbase
- for (DroneTypeLinkIGC* pdl = m_pMission->GetDroneTypes()->first(); (pdl != NULL); pdl = pdl->next())
- {
- IdroneTypeIGC* pdt = pdl->data();
- if ((pdt->GetPilotType() == c_ptMiner) && pstation->CanBuy(pdt))
- {
- for (int nMiner = 0; nMiner < m_misdef.misparms.nInitialMinersPerTeam; nMiner++)
- {
- CFSDrone * pfsDrone = CreateStockDrone(pdt, pside);
-
- if (pfsDrone)
- {
- pfsDrone->GetIGCShip()->SetStation(pstation); //start them at a station just like everyone else
- }
- }
- break;
- }
- }
- }
- }
- }
- }
- }
- /*-------------------------------------------------------------------------
- * StartGame
- *-------------------------------------------------------------------------
- * Purpose:
- * Called when we're ready to set the ships loose and actually start flying around
- */
- void CFSMission::StartGame()
- {
- if (GetStage() == STAGE_NOTSTARTED)
- {
- // transition through the STAGE_STARTING state for consistancy
- StartCountdown(0.0f);
- }
- if (GetStage() == STAGE_STARTING)
- {
- SetStage(STAGE_STARTED);
- {
- //Connect all players score objects to their side score objects
- for (ShipLinkIGC* psl = m_pMission->GetShips()->first(); (psl != NULL); psl = psl->next())
- {
- CFSShip* pfsship = (CFSShip*)(psl->data()->GetPrivateData());
- IsideIGC* pside = psl->data()->GetSide();
- if (pside->GetObjectID() >= 0)
- {
- pfsship->GetPlayerScoreObject()->Connect(g.timeNow);
- }
- }
- }
- m_timeNextPayday = g.timeNow + m_pMission->GetFloatConstant(c_fcidSecondsBetweenPaydays);
- m_psideWon = NULL;
- m_pszReason = NULL;
- m_bDraw = false;
- m_pMission->EnterGame();
- // let everyone know that the game has started
- BEGIN_PFM_CREATE(g.fm, pfmEnterGame, S, ENTER_GAME)
- END_PFM_CREATE
- g.fm.SendMessages(GetGroupRealSides(), FM_GUARANTEED, FM_FLUSH);
- LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
- GetSite()->SendChat(NULL, CHAT_EVERYONE, NA, NA, "The game has started.");
- _AGCModule.TriggerContextEvent(NULL, AllsrvEventID_GameStarted, pszContext, "", -1, -1, -1, 0);
- DoPayday();
- }
- }
- void CFSMission::DoPayday(void)
- {
- //Paydays for the various sides
- const SideListIGC* psides = GetIGCMission()->GetSides();
- for (SideLinkIGC* l = psides->first();
- (l != NULL);
- l = l->next())
- {
- DoPayday(l->data());
- }
- }
- void CFSMission::DoPayday(IsideIGC* pside)
- {
- SideID sideID = pside->GetObjectID();
- int np = GetCountOfPlayers(pside, true);
- if (np != 0)
- {
- int delta = m_rgMoney[sideID] / np;
- if (delta > 0)
- {
- BEGIN_PFM_CREATE(g.fm, pfmPayday, S, PAYDAY)
- END_PFM_CREATE
- pfmPayday->dMoney = Money(delta);
- g.fm.SendMessages(CFSSide::FromIGC(pside)->GetGroup(), FM_GUARANTEED, FM_FLUSH);
- m_rgMoney[sideID] -= delta * np;
- const ShipListIGC * plistShip = pside->GetShips();
- for(ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- CFSShip * pfsShip = (CFSShip *) plinkShip->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- CFSPlayer* pfsDonate = pfsShip->GetPlayer()->GetAutoDonate();
- if (pfsDonate)
- pfsDonate->SetMoney(pfsDonate->GetMoney() + delta);
- else
- pfsShip->SetMoney(pfsShip->GetMoney() + delta);
- }
- }
- }
- }
- }
- void CFSMission::DoTick(Time timeNow)
- {
- assert (GetStage() == STAGE_STARTED);
- ImissionIGC* pm = GetIGCMission();
- const MissionParams* pmp = pm->GetMissionParams();
- // check for the timeout winning condition
- {
- if (pmp->IsCountdownGame())
- {
- if ((timeNow - pmp->timeStart) > pmp->GetCountDownTime())
- {
- //End the game ... side with the most kills wins (ties -> fewest deaths, ties -> most money)
- IsideIGC* psideWin = NULL;
- const char* pszClue;
- if (pmp->IsConquestGame())
- {
- pszClue = "conquest";
- int maxFlags = 0;
- for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- int nFlags = 0;
- for (StationLinkIGC* l = pside->GetStations()->first(); (l != NULL); l = l->next())
- {
- if (l->data()->GetBaseStationType()->HasCapability(c_sabmFlag))
- nFlags++;
- }
- if (nFlags > maxFlags)
- {
- maxFlags = nFlags;
- psideWin = pside;
- }
- else if (nFlags == maxFlags)
- {
- psideWin = NULL;
- }
- }
- }
- if ((psideWin == NULL) && pmp->IsTerritoryGame())
- {
- pszClue = "territory";
- unsigned char maxSectors = 0;
- for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- int nSectors = pside->GetTerritoryCount();
- if (nSectors > maxSectors)
- {
- maxSectors = nSectors;
- psideWin = pside;
- }
- else if (nSectors == maxSectors)
- {
- psideWin = NULL;
- }
- }
- }
- if ((psideWin == NULL) && pmp->IsProsperityGame())
- {
- pszClue = "prosperity";
- DWORD maxTime = 0;
- for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- IbucketIGC* pbucket = pside->GetBuckets()->last()->data();
- assert ((pbucket->GetBucketType() == OT_development) &&
- (pbucket->GetBuyable()->GetObjectID() == c_didTeamMoney));
- DWORD time = pbucket->GetTime();
- if (time > maxTime)
- {
- maxTime = time;
- psideWin = pside;
- }
- else if (time == maxTime)
- {
- psideWin = NULL;
- }
- }
- }
- if ((psideWin == NULL) && pmp->IsArtifactsGame())
- {
- pszClue = "artifacts";
- short maxFlags = 0;
- for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- short nFlags = pside->GetArtifacts();
- if (nFlags > maxFlags)
- {
- maxFlags = nFlags;
- psideWin = pside;
- }
- else if (nFlags == maxFlags)
- {
- psideWin = NULL;
- }
- }
- }
- if ((psideWin == NULL) && pmp->IsFlagsGame())
- {
- pszClue = "flags";
- short maxFlags = 0;
- for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- short nFlags = pside->GetFlags();
- if (nFlags > maxFlags)
- {
- maxFlags = nFlags;
- psideWin = pside;
- }
- else if (nFlags == maxFlags)
- {
- psideWin = NULL;
- }
- }
- }
- if (psideWin == NULL)
- {
- pszClue = "kills";
- int nKills = -1;
- int nDeaths = INT_MAX;
- for (SideLinkIGC* psl = pm->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- int k = pside->GetKills();
- int d = pside->GetDeaths();
- if ((k > nKills) ||
- ((k == nKills) && (d < nDeaths)))
- {
- nKills = k;
- nDeaths = d;
- psideWin = pside;
- }
- else if ((k == nKills) && (d == nDeaths))
- {
- psideWin = NULL;
- }
- }
- }
- if (psideWin)
- {
- static char szReason[100];
- sprintf(szReason, "The clock has stopped. The winner: %s by %s", psideWin->GetName(), pszClue);
- GameOver(psideWin, szReason);
- }
- else
- {
- GameOver(NULL, "The clock has stopped. The game is a draw.");
- }
- }
- }
- }
- if (m_psideWon || m_bDraw)
- {
- ProcessGameOver();
- return;
- }
- if (timeNow >= m_timeNextPayday)
- {
- float dtPayday = m_pMission->GetFloatConstant(c_fcidSecondsBetweenPaydays);
- float dt = dtPayday + (timeNow - m_timeNextPayday);
- m_timeNextPayday = m_timeNextPayday + dtPayday;
- if (pmp->bAllowDevelopments)
- {
- //Get the average pot size for all teams
- float moneyIncome = m_pMission->GetFloatConstant(c_fcidIncome);
- const SideListIGC* psides = GetIGCMission()->GetSides();
- {
- for (SideLinkIGC* l = psides->first();
- (l != NULL);
- l = l->next())
- {
- IsideIGC* pside = l->data();
- SideID sideID = pside->GetObjectID();
- //Calculate side income
- m_rgMoney[sideID] += (Money)(moneyIncome * (1.0f + pside->GetCivilization()->GetIncomeMoney()));
- Money income = 0;
- for (StationLinkIGC* psl = pside->GetStations()->first();
- (psl != NULL);
- psl = psl->next())
- {
- income += psl->data()->GetStationType()->GetIncome();
- }
- m_rgMoney[sideID] += income;
- }
- }
- //Paydays for the various sides
- DoPayday();
- }
- {
- //Newly created objects for the various sectors
- for (ClusterLinkIGC* l = GetIGCMission()->GetClusters()->first();
- (l != NULL);
- l = l->next())
- {
- IclusterIGC* pcluster = l->data();
- bool bHome = pcluster->GetHomeSector();
- float treasures = pcluster->GetPendingTreasures() +
- dt * (bHome
- ? pmp->nPlayerSectorTreasureRate
- : pmp->nNeutralSectorTreasureRate);
- if (treasures >= 1.0f)
- {
- //Create the appropriate treasures for the
- int n = int(treasures);
- treasures -= float(n);
- short tsi = bHome ? pmp->tsiPlayerRegenerate : pmp->tsiNeutralRegenerate;
- for (int i = n; (i > 0); i--)
- {
- GetIGCMission()->GenerateTreasure(timeNow, pcluster, tsi);
- }
- }
- pcluster->SetPendingTreasures(treasures);
- }
- }
- }
- // update any pending ballots
- for (BallotList::Iterator iter(m_ballots); !iter.End();)
- {
- if (iter.Value()->Update(timeNow))
- iter.Remove();
- else
- iter.Next();
- }
- }
- /*-------------------------------------------------------------------------
- * Vacate
- *-------------------------------------------------------------------------
- Purpose:
- Kicks everyone out
- Moves all players to lifepods in the null cluster and terminates drones
- */
- void CFSMission::Vacate(void)
- {
- const ShipListIGC * pShips = m_pMission->GetShips();
- CFSShip * pfsShip = NULL;
- ShipLinkIGC * pShiplink = NULL;
- pShiplink = pShips->first();
- while (pShiplink)
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- pShiplink = pShiplink->next();
- if (!pfsShip->IsPlayer())
- delete pfsShip->GetDrone();
- else
- {
- pfsShip->Reset(true);
- }
- }
- }
- void CFSMission::SaveAsOldPlayer(CFSPlayer* pfsplayer, bool bBooted)
- {
- OldPlayerLink* popl = GetOldPlayerLink(pfsplayer->GetName());
- if (!popl)
- {
- popl = new OldPlayerLink;
- m_oldPlayers.last(popl);
- }
- OldPlayerInfo& opi = popl->data();
- strcpy(opi.name, pfsplayer->GetName());
- PlayerScoreObject* ppso = pfsplayer->GetPlayerScoreObject();
- opi.pso = *ppso;
- opi.sideID = pfsplayer->GetSide()->GetObjectID();
- if ((GetStage() != STAGE_STARTED) ||
- (m_pMission->GetMissionParams()->bAllowDefections))
- {
- opi.bannedSideMask = pfsplayer->GetBannedSideMask();
- if (bBooted)
- {
- if (opi.sideID < 0)
- {
- opi.bannedSideMask = 0xff;
- }
- else
- {
- opi.bannedSideMask |= SideMask(opi.sideID);
- }
- }
- }
- else
- {
- //No defections
- if (bBooted)
- opi.bannedSideMask = 0xff;
- else if (opi.sideID >= 0)
- opi.bannedSideMask = ~SideMask(opi.sideID);
- else
- opi.bannedSideMask = pfsplayer->GetBannedSideMask();
- }
- opi.characterID = pfsplayer->GetCharacterID();
- IclusterIGC* pcluster = pfsplayer->GetIGCShip()->GetCluster();
- if (pcluster)
- {
- opi.pclusterLifepod = pcluster;
- opi.positionLifepod = pfsplayer->GetIGCShip()->GetSourceShip()->GetPosition();
- }
- }
- /*-------------------------------------------------------------------------
- * GameOver
- *-------------------------------------------------------------------------
- Purpose:
- Let someone forcibly end the game, even though no victory condition was met
-
- Parameters:
- The winning side
- */
- void CFSMission::GameOver(IsideIGC * psideWin, const char* pszReason)
- {
- m_psideWon = psideWin;
- m_pszReason = pszReason;
- m_bDraw = m_psideWon == NULL;
- LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
- // the game will actually end when we get around to checking whether a team has won
- _AGCModule.TriggerContextEvent(NULL, AllsrvEventID_GameEnded, pszContext,
- "", -1, -1, -1, 1,
- "Reason", VT_LPSTR, pszReason);
- }
- /*-------------------------------------------------------------------------
- * MakeOverrideTechBits
- *-------------------------------------------------------------------------
- */
- void CFSMission::MakeOverrideTechBits()
- {
- if (m_pttbmAltered == NULL)
- {
- m_pttbmAltered = new TechTreeBitMask[c_cSidesMax];
- for (int i = 0; i < c_cSidesMax; ++i)
- (m_pttbmAltered)[i].ClearAll();
- }
- if (m_pttbmNewSetting == NULL)
- {
- m_pttbmNewSetting = new TechTreeBitMask[c_cSidesMax];
- for (int i = 0; i < c_cSidesMax; ++i)
- (m_pttbmNewSetting)[i].ClearAll();
- }
- }
- /*-------------------------------------------------------------------------
- * RecordGameResults
- *-------------------------------------------------------------------------
- Purpose:
- Records the results of the game to the database.
- */
- void CFSMission::RecordGameResults()
- {
- #if !defined(ALLSRV_STANDALONE)
- // Create the database update query
- CQGameResults* pquery = new CQGameResults(NULL); // don't need call-back notification
- CQGameResultsData* pqd = pquery->GetData();
- // Populate the query parameters
- strncpy(pqd->szGameID , GetIGCMission()->GetContextName() , sizeofArray(pqd->szGameID));
- strncpy(pqd->szName , m_misdef.misparms.strGameName , sizeofArray(pqd->szName));
- strncpy(pqd->szWinningTeam, m_psideWon ? m_psideWon->GetName() : "", sizeofArray(pqd->szWinningTeam));
- // make SURE they're NULL-terminated
- pqd->szGameID[sizeofArray(pqd->szGameID) - 1] = '\0';
- pqd->szName[sizeofArray(pqd->szName) - 1] = '\0';
- pqd->szWinningTeam[sizeofArray(pqd->szWinningTeam) - 1] = '\0';
- pqd->nWinningTeamID = m_psideWon ? m_psideWon->GetObjectID() : NA;
- pqd->bIsGoalConquest = m_misdef.misparms.IsConquestGame();
- pqd->bIsGoalCountdown = m_misdef.misparms.IsCountdownGame();
- pqd->bIsGoalTeamKills = m_misdef.misparms.IsDeathMatchGame();
- pqd->bIsGoalProsperity = m_misdef.misparms.IsProsperityGame();
- pqd->bIsGoalArtifacts = m_misdef.misparms.IsArtifactsGame();
- pqd->bIsGoalFlags = m_misdef.misparms.IsFlagsGame();
- pqd->nGoalConquest = m_misdef.misparms.iGoalConquestPercentage;
- pqd->nGoalCountdown = m_misdef.misparms.dtGameLength;
- pqd->nGoalTeamKills = m_misdef.misparms.nGoalTeamKills;
- pqd->fGoalProsperity = m_misdef.misparms.fGoalTeamMoney;
- pqd->nGoalArtifacts = m_misdef.misparms.nGoalArtifactsCount;
- pqd->nGoalFlags = m_misdef.misparms.nGoalFlagsCount;
- pqd->nDuration = GetGameDuration();
- // Post the query for async completion
- g.sql.PostQuery(pquery);
- // Iterate through each team of the game
- const SideListIGC* pSides = GetIGCMission()->GetSides();
- for (SideLinkIGC* itSide = pSides->first(); itSide; itSide = itSide->next())
- {
- IsideIGC* pside = itSide->data();
- assert(pside);
- // Record the team results
- RecordTeamResults(pside);
- }
- // Iterate through each player that left the game before it ended
- for (OldPlayerLink* itOld = m_oldPlayers.first(); itOld; itOld = itOld->next())
- {
- OldPlayerInfo& opi = itOld->data();
- // Record the player results (if they played on a real side)
- if (opi.sideID != SIDE_TEAMLOBBY)
- RecordPlayerResults(opi.name, &opi.pso, opi.sideID);
- }
- #endif // !defined(ALLSRV_STANDALONE)
- }
- /*-------------------------------------------------------------------------
- * RecordTeamResults
- *-------------------------------------------------------------------------
- Purpose:
- Records the results of the team to the database.
- */
- void CFSMission::RecordTeamResults(IsideIGC* pside)
- {
- #if !defined(ALLSRV_STANDALONE)
- // Create the database update query
- CQTeamResults* pquery = new CQTeamResults(NULL);
- CQTeamResultsData* pqd = pquery->GetData();
- // Populate the query parameters
- strncpy(pqd->szGameID , GetIGCMission()->GetContextName(), sizeofArray(pqd->szGameID));
- strncpy(pqd->szName , pside->GetName() , sizeofArray(pqd->szName));
- // make SURE they're NULL-terminated
- pqd->szGameID[sizeofArray(pqd->szGameID) - 1] = '\0';
- pqd->szName[sizeofArray(pqd->szName) - 1] = '\0';
- pside->GetTechs().ToString(pqd->szTechs, sizeofArray(pqd->szTechs));
- pqd->nCivID = pside->GetCivilization()->GetObjectID();
- pqd->nTeamID = pside->GetObjectID();
- pqd->cPlayerKills = pside->GetKills();
- pqd->cBaseKills = pside->GetBaseKills();
- pqd->cBaseCaptures = pside->GetBaseCaptures();
- pqd->cDeaths = pside->GetDeaths();
- pqd->cEjections = pside->GetEjections();
- pqd->cFlags = pside->GetFlags();
- pqd->cArtifacts = pside->GetArtifacts();
- pqd->nConquestPercent = pside->GetConquestPercent();
- pqd->nProsperityPercentBought = pside->GetProsperityPercentBought();
- pqd->nProsperityPercentComplete = pside->GetProsperityPercentComplete();
- if (pside->GetActiveF())
- pqd->nTimeEndured = GetGameDuration();
- else
- pqd->nTimeEndured = pside->GetTimeEndured();
- // Post the query for async completion
- g.sql.PostQuery(pquery);
- // Iterate through each player of the team
- const ShipListIGC* pShips = pside->GetShips();
- for (ShipLinkIGC* itShip = pShips->first(); itShip; itShip = itShip->next())
- {
- IshipIGC* pship = itShip->data();
- assert(pship);
- // Filter-out non-player ships
- if (ISPLAYER(pship))
- {
- // Get the player score object
- CFSPlayer* pfsPlayer = ((CFSShip*)(pship->GetPrivateData()))->GetPlayer();
- PlayerScoreObject* ppso = pfsPlayer->GetPlayerScoreObject();
- // Record the player results
- RecordPlayerResults(pship->GetName(), ppso, pside->GetObjectID());
- }
- }
- #endif // !defined(ALLSRV_STANDALONE)
- }
- /*-------------------------------------------------------------------------
- * RecordPlayerResults
- *-------------------------------------------------------------------------
- Purpose:
- Records the results of the player to the database.
- */
- void CFSMission::RecordPlayerResults(const char* pszName, PlayerScoreObject* ppso, SideID sid)
- {
- #if !defined(ALLSRV_STANDALONE)
- // Create the database update query
- CQPlayerResults* pquery = new CQPlayerResults(NULL);
- CQPlayerResultsData* pqd = pquery->GetData();
- // Populate the query parameters
- strncpy(pqd->szGameID , GetIGCMission()->GetContextName(), sizeofArray(pqd->szGameID));
- strncpy(pqd->szName , pszName , sizeofArray(pqd->szName) );
- // make SURE they're NULL-terminated
- pqd->szGameID[sizeofArray(pqd->szGameID) - 1] = '\0';
- pqd->szName[sizeofArray(pqd->szName) - 1] = '\0';
- pqd->nTeamID = sid;
- pqd->cPlayerKills = ppso->GetPlayerKills();
- pqd->cBuilderKills = ppso->GetBuilderKills();
- pqd->cLayerKills = ppso->GetLayerKills();
- pqd->cMinerKills = ppso->GetMinerKills();
- pqd->cBaseKills = ppso->GetBaseKills();
- pqd->cBaseCaptures = ppso->GetBaseCaptures();
- pqd->cPilotBaseKills = ppso->GetPilotBaseKills();
- pqd->cPilotBaseCaptures = ppso->GetPilotBaseCaptures();
- pqd->cDeaths = ppso->GetDeaths();
- pqd->cEjections = ppso->GetEjections();
- pqd->cRescues = ppso->GetRescues();
- pqd->cFlags = ppso->GetFlags();
- pqd->cArtifacts = ppso->GetArtifacts();
- pqd->cTechsRecovered = ppso->GetTechsRecovered();
- pqd->cAlephsSpotted = ppso->GetWarpsSpotted();
- pqd->cAsteroidsSpotted = ppso->GetAsteroidsSpotted();
- pqd->fCombatRating = ppso->GetCombatRating();
- pqd->fScore = ppso->GetScore();
- pqd->nTimePlayed = ppso->GetTimePlayed();
- // spew the player results that we're writing...
- debugf("Writing player results: %s %s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %g %g %d\n",
- pqd->szGameID,
- pqd->szName,
- pqd->nTeamID,
- pqd->cPlayerKills,
- pqd->cBuilderKills,
- pqd->cLayerKills,
- pqd->cMinerKills,
- pqd->cBaseKills,
- pqd->cBaseCaptures,
- pqd->cPilotBaseKills,
- pqd->cPilotBaseCaptures,
- pqd->cDeaths,
- pqd->cEjections,
- pqd->cRescues,
- pqd->cFlags,
- pqd->cArtifacts,
- pqd->cTechsRecovered,
- pqd->cAlephsSpotted,
- pqd->cAsteroidsSpotted,
- (double)pqd->fCombatRating,
- (double)pqd->fScore,
- pqd->nTimePlayed
- );
- // Post the query for async completion
- g.sql.PostQuery(pquery);
- #endif // !defined(ALLSRV_STANDALONE)
- }
- /*-------------------------------------------------------------------------
- * QueueGameoverMessage
- *-------------------------------------------------------------------------
- Purpose:
- Tell a player or group of players that they are out of the game.
-
- Parameters:
- The winning side is in m_psideWon
- */
- void CFSMission::QueueGameoverMessage()
- {
- // queue the general game over stats and side stats
- BEGIN_PFM_CREATE(g.fm, pfmGameOver, S, GAME_OVER)
- FM_VAR_PARM((const char*)(m_pszReason ? m_pszReason : "Your side has been eliminated."), CB_ZTS)
- END_PFM_CREATE
- for (SideID sideID = 0; sideID < c_cSidesMax; sideID++)
- {
- IsideIGC* pside = m_pMission->GetSide(sideID);
- strcpy(pfmGameOver->rgSides[sideID].sideName, pside ? pside->GetName() : "<bug>");
- pfmGameOver->rgSides[sideID].civID = pside ? pside->GetCivilization()->GetObjectID() : -1;
- pfmGameOver->rgSides[sideID].color = pside ? pside->GetColor() : Color(0.5, 0.5, 0.5);
- pfmGameOver->rgSides[sideID].cKills = pside ? pside->GetKills() : 0;
- pfmGameOver->rgSides[sideID].cDeaths = pside ? pside->GetDeaths() : 0;
- pfmGameOver->rgSides[sideID].cEjections = pside ? pside->GetEjections() : 0;
- pfmGameOver->rgSides[sideID].cBaseKills = pside ? pside->GetBaseKills() : 0;
- pfmGameOver->rgSides[sideID].cBaseCaptures = pside ? pside->GetBaseCaptures() : 0;
- pfmGameOver->rgSides[sideID].cFlags = pside ? pside->GetFlags() : 0;
- pfmGameOver->rgSides[sideID].cArtifacts = pside ? pside->GetArtifacts() : 0;
- };
- pfmGameOver->nNumSides = m_pMission->GetSides()->n();
- pfmGameOver->iSideWinner = m_psideWon ? m_psideWon->GetObjectID() : NA;
- pfmGameOver->bEjectPods = m_misdef.misparms.bEjectPods;
- // queue the player stats
- const ShipListIGC * plistShip = m_pMission->GetShips();
- int nNumPlayers = plistShip->n() + m_oldPlayers.n(); //Worst case estimate
- size_t playerlistSize = nNumPlayers * sizeof(PlayerEndgameInfo);
- PlayerEndgameInfo* playerlist = (PlayerEndgameInfo*)alloca(playerlistSize);
- // get the current stats for all players
- int nPlayerIndex = 0;
- for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- if (ISPLAYER(plinkShip->data()))
- {
- CFSPlayer* pfsPlayer = ((CFSShip *)(plinkShip->data()->GetPrivateData()))->GetPlayer();
- PlayerScoreObject* ppso = pfsPlayer->GetPlayerScoreObject();
- if (ppso->GetTimePlayed() > 0.0f && pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
- {
- strcpy(playerlist[nPlayerIndex].characterName, pfsPlayer->GetName());
- playerlist[nPlayerIndex].scoring.Set(pfsPlayer->GetPlayerScoreObject());
- playerlist[nPlayerIndex].stats = ppso->GetPersist();
- playerlist[nPlayerIndex].sideId = pfsPlayer->GetSide()->GetObjectID();
- nPlayerIndex++;
- }
- }
- }
- for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
- {
- OldPlayerInfo& opi = popl->data();
- if (opi.pso.GetTimePlayed() != 0.0f && opi.sideID != SIDE_TEAMLOBBY)
- {
- strcpy(playerlist[nPlayerIndex].characterName, opi.name);
- playerlist[nPlayerIndex].scoring.Set(&(opi.pso));
- playerlist[nPlayerIndex].stats = opi.pso.GetPersist();
- playerlist[nPlayerIndex].sideId = opi.sideID;
- nPlayerIndex++;
- }
- }
- assert(nPlayerIndex <= nNumPlayers);
- // send the players in chunks of no more than 50 players at a time
- const int nMaxPlayersPerMsg = 50;
- while (nPlayerIndex > 0)
- {
- int nPlayers = min(nPlayerIndex, nMaxPlayersPerMsg);
- nPlayerIndex -= nPlayers;
- BEGIN_PFM_CREATE(g.fm, pfmGameOver, S, GAME_OVER_PLAYERS)
- FM_VAR_PARM(playerlist + nPlayerIndex, nPlayers * sizeof(PlayerEndgameInfo))
- END_PFM_CREATE
- }
- }
- static float GetExpMult(float totalExp, float sideExp, int nSides)
- {
- const float minExpMult = 0.1f;
- if ((nSides < 2) || (sideExp <= 0.0f))
- return 1.0f;
- float avgExp = (totalExp - sideExp) / float(nSides - 1);
- if (sideExp <= avgExp)
- return 1.0f;
- float m = avgExp / sideExp;
- return (m < minExpMult) ? minExpMult : m;
- }
-
- /*-------------------------------------------------------------------------
- * ProcessGameOver
- *-------------------------------------------------------------------------
- Purpose:
- Wrap things up when the game is actually over, not to be confused with
- when the mission is over, which doesn't happen until everyone in it leaves.
-
- Parameters:
- The winning side is in m_psideWon
- */
- void CFSMission::ProcessGameOver()
- {
- const ShipListIGC * pShips = m_pMission->GetShips();
- ShipLinkIGC * pShiplink;
- m_flGameDuration = g.timeNow - m_misdef.misparms.timeStart;
- //Calculate scores for all players and get a running average of time played.
- float totalExperience = 0.0f;
- float sideExperience[c_cSidesMax] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
- float dtPlayed[c_cSidesMax] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
- float scoreEarned[c_cSidesMax] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
- PlayerScoreObject* commander[c_cSidesMax] = {NULL, NULL, NULL, NULL, NULL, NULL};
- {
- for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
- if (ppso->Connected())
- {
- ppso->Disconnect(g.timeNow);
- IsideIGC* pside = pfsShip->GetSide();
- bool bCount = (ppso->GetTimePlayed() > 180.0f) && !m_bDraw;
- ppso->EndGame(m_pMission,
- (pside == m_psideWon) && bCount && (ppso->GetTimePlayed() > GetGameDuration() / 2.0f),
- (pside != m_psideWon) && bCount);
- SideID sid = pside->GetObjectID();
- if (sid >= 0)
- {
- float e = ppso->GetTimePlayed() * ppso->GetPersist().GetScore();
- totalExperience += e;
- sideExperience[sid] += e;
- scoreEarned[sid] += ppso->GetScore();
- dtPlayed[sid] += ppso->GetTimePlayed();
- }
- if ((commander[sid] == NULL) ||
- (commander[sid]->GetTimeCommanded() < ppso->GetTimeCommanded()))
- {
- commander[sid] = ppso;
- }
- }
- }
- }
- }
- {
- SideID sidWin = m_psideWon ? m_psideWon->GetObjectID() : NA;
- for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
- {
- OldPlayerInfo & opi = popl->data();
- bool bCount = (opi.pso.GetTimePlayed() > 180.0f);
- opi.pso.EndGame(m_pMission,
- (opi.sideID == sidWin) && bCount && (opi.pso.GetTimePlayed() > GetGameDuration() / 2.0f),
- (opi.sideID != sidWin) && bCount);
- if (opi.sideID >= 0)
- {
- float e = opi.pso.GetTimePlayed() * opi.pso.GetPersist().GetScore();
- totalExperience += e;
- sideExperience[opi.sideID] += e;
- scoreEarned[opi.sideID] += opi.pso.GetScore();
- dtPlayed[opi.sideID] += opi.pso.GetTimePlayed();
- if ((commander[opi.sideID] == NULL) ||
- (commander[opi.sideID]->GetTimeCommanded() < opi.pso.GetTimeCommanded()))
- {
- commander[opi.sideID] = &(opi.pso);
- }
- }
- }
- }
- //Get average exp/team
- {
- for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- IsideIGC* pside = pfsShip->GetSide();
- if (pside && pside->GetObjectID() != SIDE_TEAMLOBBY)
- {
- SideID sid = pside->GetObjectID();
- float f = GetExpMult(totalExperience, sideExperience[sid], m_pMission->GetSides()->n());
- if (f < 1.0f)
- {
- PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
- ppso->SetScore(ppso->GetScore() * f);
- }
- }
- }
- }
- for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
- {
- OldPlayerInfo & opi = popl->data();
-
- if (opi.sideID != SIDE_TEAMLOBBY)
- {
- SideID sid = opi.sideID;
- float f = GetExpMult(totalExperience, sideExperience[sid], m_pMission->GetSides()->n());
- if (f < 1.0f)
- {
- opi.pso.SetScore(opi.pso.GetScore() * f);
- }
- }
- }
- }
- // award points for commanding
- {
- for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- IsideIGC* pside = psl->data();
- SideID sideID = pside->GetObjectID();
- PlayerScoreObject* ppso = commander[sideID];
- if (ppso)
- {
- assert (dtPlayed[sideID] >= 0.0f);
- //Average points earned per player minute
- float commandScore = scoreEarned[sideID] / dtPlayed[sideID];
- {
- float f = GetExpMult(totalExperience, sideExperience[sideID], m_pMission->GetSides()->n());
- if (f < 1.0f)
- {
- commandScore *= f;
- }
- }
- ppso->SetCommanderScore(commandScore * ppso->GetTimePlayed());
- }
- }
- }
- //Save player scores
- {
- for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- IsideIGC* pside = pfsShip->GetSide();
- if (pside && pside->GetObjectID() != SIDE_TEAMLOBBY)
- {
- PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
- SetCharStats(pfsShip->GetPlayer()->GetCharacterID(), pfsShip->GetPlayer(), pside, *ppso, this);
- }
- }
- }
- }
- {
- for (OldPlayerLink* popl = m_oldPlayers.first(); (popl != NULL); popl = popl->next())
- {
- OldPlayerInfo & opi = popl->data();
-
- if (opi.sideID != SIDE_TEAMLOBBY)
- SetCharStats(opi.characterID, NULL, GetIGCMission()->GetSide(opi.sideID), opi.pso, this);
- }
- }
- // if this was a squads game, record the wins and losses for the squads
- if (m_misdef.misparms.bSquadGame && m_misdef.misparms.bScoresCount && m_psideWon
- && m_misdef.misparms.nTeams == 2
- && m_pMission->GetSide(0)->GetSquadID() != m_pMission->GetSide(1)->GetSquadID())
- {
- RecordSquadGame(m_pMission->GetSides(), m_psideWon);
- }
- // Record the Game Results
- if (m_misdef.misparms.bScoresCount) // Only if scores count
- {
- RecordGameResults();
- }
- // Queue the GameOver message to all connected users
- g.fm.SetDefaultRecipient(GetGroupMission(), FM_GUARANTEED);
- QueueGameoverMessage();
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- {
- for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- pfsShip->GetPlayer()->SetLifepod(NULL, Vector::GetZero());
- PlayerScoreObject* ppso = pfsShip->GetPlayerScoreObject();
- ppso->Reset(true);
- }
- }
- }
- // Purge the old players list
- m_oldPlayers.purge();
- // clear the clusters and destroy the drones
- Vacate();
- // kill any pending votes
- while (!m_ballots.IsEmpty())
- delete m_ballots.PopFront();
- /*GetSite()->SendChatf(NULL, CHAT_EVERYONE, NA,
- NA, "The game is over. %s are victorious!.",
- m_psideWon->GetName());
- */
- // set all of the players to unready
- for (pShiplink = pShips->first(); pShiplink; pShiplink = pShiplink->next())
- {
- CFSShip * pfsShip = (CFSShip *) pShiplink->data()->GetPrivateData();
- assert(pfsShip->IsPlayer());
- // Review: since ready has changed to this cheezy "away from keyboard" thing,
- // set everyone as not away from keyboard.
- if (pfsShip->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
- pfsShip->GetPlayer()->SetReady(true);
- }
- // Restart the game if the server is not paused.
- bool bRestartable = !g.fPaused && m_misdef.misparms.bAllowRestart;
- #if defined(ALLSRV_STANDALONE)
- // HACK: for training missions, end the game and don't let it restart.
- if (m_misdef.misparms.nTotalMaxPlayersPerGame == 1)
- bRestartable = false;
- #endif
- SetStage(bRestartable ? STAGE_NOTSTARTED : STAGE_OVER); // set to STAGE_OVER if game should not restart.
- // set all of the sides to active and not forced ready
- for (SideID sideID = 0; sideID < m_misdef.misparms.nTeams; sideID++)
- {
- IsideIGC* pside = m_pMission->GetSide(sideID);
- // break up teams that no longer have the leadership they need
- if (pside->GetSquadID() != NA)
- MaintainSquadLeadership(sideID);
- m_misdef.rgfReady [sideID] = false;
- m_misdef.rgfForceReady [sideID] = false;
- m_misdef.rgfActive [sideID] = true;
- m_rgMoney [sideID] = 0;
- pside->SetActiveF(true);
- CheckForSideAllReady(pside);
- }
- // reset the clusters, etc.
- for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
- psl->data()->Reset();
- m_pMission->ResetMission();
-
- LPCSTR pszContext = GetIGCMission() ? GetIGCMission()->GetContextName() : NULL;
- _AGCModule.TriggerContextEvent(NULL, AllsrvEventID_GameOver, pszContext,
- "", -1, -1, -1, 0);
- // if the game is an auto-restart game, reset the start time.
- if (bRestartable && m_misdef.misparms.bAutoRestart)
- {
- m_misdef.misparms.timeStart = Time::Now() + m_misdef.misparms.fRestartCountdown;
-
- // forward the new start time to everyone
- BEGIN_PFM_CREATE(g.fm, pfmStartTime, S, SET_START_TIME)
- END_PFM_CREATE
- pfmStartTime->timeStart = m_misdef.misparms.timeStart;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- }
- /*-------------------------------------------------------------------------
- * CheckForVictory
- *-------------------------------------------------------------------------
- * Purpose:
- * See if a side has won and handle it if they have
- */
- IsideIGC* CFSMission::CheckForVictoryByStationBuild(IsideIGC* psideTest)
- {
- return CheckForVictoryByStationKill(NULL, NULL);
- }
- IsideIGC* CFSMission::CheckForVictoryByStationCapture(IsideIGC* psideTest, IsideIGC* psideOld)
- {
- return CheckForVictoryByStationKill(NULL, psideOld);
- }
- IsideIGC* CFSMission::CheckForVictoryByStationKill(IstationIGC* pstationKilled, IsideIGC* psideOld)
- {
- IsideIGC* psideWon = NULL;
- if ((STAGE_STARTED == GetStage()) && (m_psideWon == NULL))
- {
- const SideListIGC* psides = m_pMission->GetSides();
- const MissionParams* pmp = m_pMission->GetMissionParams();
- bool bChange = false;
- if (pmp->IsConquestGame())
- {
- int nStationsTotal = 0;
- assert (c_cSidesMax == 6);
- int nStationsPerSide[c_cSidesMax] = {0, 0, 0, 0, 0, 0};
- {
- for (StationLinkIGC* psl = m_pMission->GetStations()->first();
- (psl != NULL);
- psl = psl->next())
- {
- IstationIGC* pstation = psl->data();
- if ((pstation != pstationKilled) && pstation->GetBaseStationType()->HasCapability(c_sabmFlag))
- {
- nStationsTotal++;
- nStationsPerSide[pstation->GetSide()->GetObjectID()]++;
- }
- }
- }
- if (nStationsTotal != 0)
- {
- const SideListIGC* psides = m_pMission->GetSides();
- for (SideLinkIGC* l = psides->first(); (l != NULL); l = l->next())
- {
- IsideIGC* pside = l->data();
- unsigned char conquest = (unsigned char)(100 * nStationsPerSide[pside->GetObjectID()] / nStationsTotal);
- if (conquest != pside->GetConquestPercent())
- {
- bChange = true;
- pside->SetConquestPercent(conquest);
- if (conquest >= pmp->iGoalConquestPercentage)
- psideWon = pside;
- }
- }
- }
- }
-
- if (pmp->IsTerritoryGame() && (psideWon == NULL))
- {
- assert (c_cSidesMax == 6);
- unsigned char nTerritoriesPerSide[c_cSidesMax] = {0, 0, 0, 0, 0, 0};
- const ClusterListIGC* pclusters = m_pMission->GetClusters();
- for (ClusterLinkIGC* pcl = pclusters->first(); (pcl != NULL); pcl = pcl->next())
- {
- IclusterIGC* pcluster = pcl->data();
- IsideIGC* psideOwner = NULL;
- StationLinkIGC* psl;
- for (psl = pcluster->GetStations()->first(); (psl != NULL); psl = psl->next())
- {
- if (psl->data() != pstationKilled)
- {
- IsideIGC* pside = psl->data()->GetSide();
- if (psideOwner == NULL)
- psideOwner = pside;
- else if (psideOwner != pside)
- break;
- }
- }
- if (psideOwner && (psl == NULL))
- nTerritoriesPerSide[psideOwner->GetObjectID()]++;
- }
- unsigned char nThreashold = (unsigned char)((50 + pclusters->n() * pmp->iGoalTerritoryPercentage) / 100);
- for (SideLinkIGC* l = psides->first(); (l != NULL); l = l->next())
- {
- IsideIGC* pside = l->data();
- SideID sideID = pside->GetObjectID();
-
- if (nTerritoriesPerSide[sideID] != pside->GetTerritoryCount())
- {
- bChange = true;
- pside->SetTerritoryCount(nTerritoriesPerSide[sideID]);
- if (nTerritoriesPerSide[sideID] >= nThreashold)
- psideWon = pside;
- }
- }
- }
- //Broadcast the victory rankings to all sides
- if (bChange)
- {
- BEGIN_PFM_CREATE(g.fm, pfmGameState, S, GAME_STATE)
- END_PFM_CREATE
- SideID sid = 0;
- for (SideLinkIGC* l = psides->first(); (l != NULL); l = l->next())
- {
- assert (sid == l->data()->GetObjectID());
- pfmGameState->conquest[sid] = l->data()->GetConquestPercent();
- pfmGameState->territory[sid] = l->data()->GetTerritoryCount();
- pfmGameState->nFlags[sid] = l->data()->GetFlags();
- pfmGameState->nArtifacts[sid++] = l->data()->GetArtifacts();
- }
- g.fm.SendMessages(GetGroupRealSides(), FM_GUARANTEED, FM_FLUSH);
- }
- //Elimiation of all restart stations of all other sides is always a win
- if ((psideWon == NULL) && psideOld)
- {
- StationLinkIGC* psl;
- for (psl = psideOld->GetStations()->first();
- (psl != NULL);
- psl = psl->next())
- {
- IstationIGC* pstation = psl->data();
- if ((pstation != pstationKilled) && pstation->GetStationType()->HasCapability(c_sabmRestart))
- break;
- }
- if (psl == NULL)
- {
- //NYI last station gone ... need to deactivate side
- DeactivateSide(psideOld);
- }
- }
- }
- return psideWon;
- }
- IsideIGC* CFSMission::CheckForVictoryByKills(IsideIGC* psideTest)
- {
- if ((STAGE_STARTED == GetStage()) && (m_psideWon == NULL))
- {
- const MissionParams* pmp = m_pMission->GetMissionParams();
- if (pmp->IsDeathMatchGame())
- {
- if (psideTest->GetKills() >= pmp->nGoalTeamKills)
- {
- return psideTest;
- }
- }
- }
- return NULL;
- }
- IsideIGC* CFSMission::CheckForVictoryByInactiveSides(bool& bAllSidesInactive)
- {
- bAllSidesInactive = true;
- IsideIGC* pSideWin = NULL;
- const SideListIGC * plistSide = m_pMission->GetSides();
- for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
- {
- IsideIGC * pside = plinkSide->data();
- if (HasPlayers(pside, false) && pside->GetActiveF()) // found one
- {
- bAllSidesInactive = false;
- if (pSideWin)
- {
- pSideWin = NULL;
- break;
- }
- else
- pSideWin = pside;
- }
- }
- #if defined(ALLSRV_STANDALONE)
- // HACK: for training missions, don't end the game before it starts just
- // because a side is inactive.
- if (m_misdef.misparms.nTotalMaxPlayersPerGame == 1 && GetStage() == STAGE_STARTING)
- {
- pSideWin = NULL;
- }
- #endif
- // HACK: for testing purposes, don't end the game before it's started if
- // everyone still playing can cheat.
- if (pSideWin && GetStage() == STAGE_STARTING)
- {
- bool bFoundNormalPlayer = false;
- const ShipListIGC* pships = m_pMission->GetShips();
- for (ShipLinkIGC* psl = pships->first(); (psl != NULL); psl = psl->next())
- {
- CFSShip* pfsShip = (CFSShip *)(psl->data()->GetPrivateData());
-
- if (pfsShip->IsPlayer() && !pfsShip->GetPlayer()->CanCheat())
- {
- bFoundNormalPlayer = true;
- break;
- }
- }
- if (!bFoundNormalPlayer)
- pSideWin = NULL;
- }
- return pSideWin;
- }
- IsideIGC* CFSMission::CheckForVictoryByFlags(IsideIGC* psideTest, SideID sidFlag)
- {
- if ((STAGE_STARTED == GetStage()) && (m_psideWon == NULL))
- {
- const MissionParams* pmp = m_pMission->GetMissionParams();
- if (pmp->IsArtifactsGame() || pmp->IsFlagsGame())
- {
- BEGIN_PFM_CREATE(g.fm, pfmGameState, S, GAME_STATE)
- END_PFM_CREATE
- SideID sid = 0;
- for (SideLinkIGC* l = m_pMission->GetSides()->first(); (l != NULL); l = l->next())
- {
- assert (sid == l->data()->GetObjectID());
- pfmGameState->conquest[sid] = l->data()->GetConquestPercent();
- pfmGameState->territory[sid] = l->data()->GetTerritoryCount();
- pfmGameState->nFlags[sid] = l->data()->GetFlags();
- pfmGameState->nArtifacts[sid++] = l->data()->GetArtifacts();
- }
- g.fm.SendMessages(GetGroupRealSides(), FM_GUARANTEED, FM_FLUSH);
- if (sidFlag != SIDE_TEAMLOBBY)
- {
- if (psideTest->GetFlags() >= pmp->nGoalFlagsCount)
- {
- return psideTest;
- }
- }
- else
- {
- if (psideTest->GetArtifacts() >= pmp->nGoalArtifactsCount)
- {
- return psideTest;
- }
- }
- }
- }
- return NULL;
- }
- /*-------------------------------------------------------------------------
- * CreateDPGroups
- *-------------------------------------------------------------------------
- * Purpose:
- * create the groups for the cluster, and attach it to the IGC cluster
- *
- * Side Effects:
- * These groups must be cleaned up manually before destroying the cluster!
- */
- void CFSMission::CreateDPGroups(IclusterIGC * pcluster)
- {
- ClusterGroups * pcg = new ClusterGroups;
- char szDocked[] = "Everyone docked in sector ";
- char szFlying[] = "Everyone flying in sector ";
- char szBuff[max(sizeof(szDocked), sizeof(szFlying)) + c_cbName + 1];
- wsprintf(szBuff, "%s%s", szDocked, pcluster->GetName());
- pcg->pgrpClusterDocked = g.fm.CreateGroup(szBuff);
- wsprintf(szBuff, "%s%s", szDocked, pcluster->GetName());
- pcg->pgrpClusterFlying = g.fm.CreateGroup(szBuff);
- ((CFSCluster*)pcluster->GetPrivateData())->SetClusterGroups(pcg);
- }
- /*-------------------------------------------------------------------------
- * SendLobbyMissionInfo
- *-------------------------------------------------------------------------
- * Purpose:
- * Send the player only the data they need while in the lobby. This
- * does not include things like station and sector info.
- *
- * Parameters:
- * Who the junk goes to
- */
- void CFSMission::SendLobbyMissionInfo(CFSPlayer * pfsPlayer)
- {
- ImissionIGC * pMission = GetIGCMission();
- g.fm.SetDefaultRecipient((CFMRecipient*)(pfsPlayer->GetConnection()),
- FM_GUARANTEED);
- // tell them about the current mission info
- g.fm.QueueExistingMsg(GetMissionDef());
- // tell them that they have been accepted
- BEGIN_PFM_CREATE(g.fm, pfmJoinedMission, S, JOINED_MISSION)
- END_PFM_CREATE
- pfmJoinedMission->shipID = pfsPlayer->GetShipID();
- pfmJoinedMission->dwCookie = GetCookie();
- // Export sides
- const SideListIGC * pstlist = pMission->GetSides();
- SideLinkIGC * pstlink;
- for (pstlink = pstlist->first(); pstlink; pstlink = pstlink->next())
- ExportObj(pstlink->data(), OT_side, NULL);
- g.fm.SendMessages(NULL, FM_GUARANTEED, FM_FLUSH);
- // tell them about all of the players
- const ShipListIGC * pshiplist = pMission->GetShips();
- for (ShipLinkIGC * pshiplink = pshiplist->first();
- pshiplink;
- pshiplink = pshiplink->next())
- {
- IshipIGC* pship = pshiplink->data();
- CFSShip * pfsShip = (CFSShip *)(pship->GetPrivateData());
-
- SendPlayerInfo(pfsPlayer, pfsShip, this, false);
- }
- g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
- }
- /*-------------------------------------------------------------------------
- * QueueLobbyMissionInfo
- *-------------------------------------------------------------------------
- * Purpose:
- * Queue up a shorter form of the mission def which is used for players
- * who have not yet chosen a game.
- *
- * Parameters:
- */
- void CFSMission::QueueLobbyMissionInfo()
- {
- assert(g.fmLobby.IsConnected());
- SquadID rgSquadIDs[c_cSidesMax];
- int nSquadCount = 0;
- // fill in the squad info for any squads that are playing
- {
- const SideListIGC * plistSide = m_pMission->GetSides();
- for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
- {
- SquadID squadID = plinkSide->data()->GetSquadID();
- if (squadID != NA && 0 != plinkSide->data()->GetShips()->n()
- && (STAGE_STARTED != GetStage() || plinkSide->data()->GetActiveF()))
- {
- rgSquadIDs[nSquadCount] = squadID;
- ++nSquadCount;
- }
- }
- }
- BEGIN_PFM_CREATE(g.fmLobby, pfmLobbyMissionInfo, LS, LOBBYMISSIONINFO)
- FM_VAR_PARM(m_misdef.misparms.strGameName, CB_ZTS)
- FM_VAR_PARM(nSquadCount ? rgSquadIDs : NULL, nSquadCount * sizeof(SquadID))
- FM_VAR_PARM((PCC)m_strDetailsFiles, CB_ZTS)
- END_PFM_CREATE
- pfmLobbyMissionInfo->dwCookie = GetCookie();
- // adjust the clock time to be an offset from the current time (the lobby server will fix this)
- pfmLobbyMissionInfo->dwStartTime = m_misdef.misparms.timeStart.clock() - Time::Now().clock();
- // fill in the information on number of players and slots available
- pfmLobbyMissionInfo->fGuaranteedSlotsAvailable = false;
- pfmLobbyMissionInfo->fAnySlotsAvailable = false;
- pfmLobbyMissionInfo->nNumPlayers = GetCountOfPlayers(NULL, false);
- // if there might be a chance a player can join, check the teams to see if they can
- if ((m_misdef.misparms.bAllowJoiners || STAGE_NOTSTARTED == GetStage())
- && !m_misdef.misparms.bLockLobby && STAGE_OVER != GetStage())
- {
- const SideListIGC * plistSide = m_pMission->GetSides();
- for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
- {
- IsideIGC * pside = plinkSide->data();
- int nNumPlayersOnSide = GetCountOfPlayers(pside, false);
- int nAvailablePositions = m_misdef.misparms.nMaxPlayersPerTeam - nNumPlayersOnSide;
-
- // if it is possible to join this side...
- if ((STAGE_NOTSTARTED == GetStage() || (GetBase(pside) && pside->GetActiveF()))
- && nAvailablePositions && STAGE_OVER != GetStage())
- {
- // track that
- pfmLobbyMissionInfo->fAnySlotsAvailable = true;
-
- // if a player is guaranteed to get in, track that too.
- if (GetAutoAccept(pside)
- || (m_misdef.fAutoAcceptLeaders && !GetLeader(pside->GetObjectID())))
- {
- pfmLobbyMissionInfo->fGuaranteedSlotsAvailable = true;
- }
- }
- }
- }
- pfmLobbyMissionInfo->nTeams = m_misdef.misparms.nTeams;
- pfmLobbyMissionInfo->nMinRank = m_misdef.misparms.iMinRank;
- pfmLobbyMissionInfo->nMaxRank = m_misdef.misparms.iMaxRank;
- pfmLobbyMissionInfo->nMaxPlayersPerGame = min(m_misdef.misparms.nTotalMaxPlayersPerGame,
- m_misdef.misparms.nTeams
- * m_misdef.misparms.nMaxPlayersPerTeam);
- pfmLobbyMissionInfo->nMinPlayersPerTeam = m_misdef.misparms.nMinPlayersPerTeam;
- pfmLobbyMissionInfo->nMaxPlayersPerTeam = m_misdef.misparms.nMaxPlayersPerTeam;
- pfmLobbyMissionInfo->fInProgress = m_misdef.fInProgress;
- pfmLobbyMissionInfo->fCountdownStarted = (GetStage() == STAGE_STARTING
- || (GetStage() == STAGE_NOTSTARTED && m_misdef.misparms.bAutoRestart));
- pfmLobbyMissionInfo->fMSArena = m_misdef.misparms.bObjectModelCreated;
- pfmLobbyMissionInfo->fScoresCount = m_misdef.misparms.bScoresCount;
- pfmLobbyMissionInfo->fInvulnerableStations = m_misdef.misparms.bInvulnerableStations;
- pfmLobbyMissionInfo->fAllowDevelopments = m_misdef.misparms.bAllowDevelopments;
- pfmLobbyMissionInfo->fLimitedLives = m_misdef.misparms.iLives != 0x7fff;
- pfmLobbyMissionInfo->fConquest = m_misdef.misparms.IsConquestGame();
- pfmLobbyMissionInfo->fDeathMatch = m_misdef.misparms.IsDeathMatchGame();
- pfmLobbyMissionInfo->fCountdown = m_misdef.misparms.IsCountdownGame();
- pfmLobbyMissionInfo->fProsperity = m_misdef.misparms.IsProsperityGame();
- pfmLobbyMissionInfo->fArtifacts = m_misdef.misparms.IsArtifactsGame();
- pfmLobbyMissionInfo->fFlags = m_misdef.misparms.IsFlagsGame();
- pfmLobbyMissionInfo->fTerritorial = m_misdef.misparms.IsTerritoryGame();
- pfmLobbyMissionInfo->fSquadGame = m_misdef.misparms.bSquadGame;
- pfmLobbyMissionInfo->fEjectPods = m_misdef.misparms.bEjectPods;
- }
- /*-------------------------------------------------------------------------
- * SendMissionInfo
- *-------------------------------------------------------------------------
- * Purpose:
- * Send the player all the data they need to play in the mission.
- * This is *different* from the info that just defined the mission on the mission board
- *
- * Parameters:
- * Who the junk goes to (if pfsPlayer is NULL, send it to the entire side)
- */
- void CFSMission::SendMissionInfo(CFSPlayer * pfsPlayer, IsideIGC* pside)
- {
- ImissionIGC * pMission = GetIGCMission();
- g.fm.SetDefaultRecipient(pfsPlayer ?
- (CFMRecipient*) pfsPlayer->GetConnection() :
- (CFMRecipient*) CFSSide::FromIGC(pside)->GetGroup(),
- FM_GUARANTEED);
- SideID sideID = pside->GetObjectID();
- // Send all clusters, and what that side sees in them
- const ClusterListIGC * pclstlist = pMission->GetClusters();
- ClusterLinkIGC * pclstlink;
- for (pclstlink = pclstlist->first(); pclstlink; pclstlink = pclstlink->next())
- {
- IclusterIGC * pcluster = pclstlink->data();
- ExportObj(pcluster, OT_cluster, NULL);
- // Export alephs
- {
- const WarpListIGC * pwarplist = pcluster->GetWarps();
- WarpLinkIGC * pwarplink;
- for (pwarplink = pwarplist->first(); pwarplink; pwarplink = pwarplink->next())
- {
- if (pwarplink->data()->SeenBySide(pside))
- ExportObj(pwarplink->data(), OT_warp, NULL);
- }
- // Export aleph bombs (get all alephs first so all alephs have destinations)
- for (pwarplink = pwarplist->first(); pwarplink; pwarplink = pwarplink->next())
- {
- const WarpBombList* plist = pwarplink->data()->GetBombs();
- if (plist->first() && (pwarplink->data()->SeenBySide(pside)))
- for (WarpBombLink* p = plist->first(); (p != NULL); p = p->next())
- {
- BEGIN_PFM_CREATE(g.fm, pfmWB, S, WARP_BOMB)
- END_PFM_CREATE
- pfmWB->timeExplosion = p->data().timeExplosion;
- pfmWB->warpidBombed = pwarplink->data()->GetObjectID();
- pfmWB->expendableidMissile = p->data().pmt->GetObjectID();
- }
- }
- }
- // Export planets
- const AsteroidListIGC * pmdllist = pcluster->GetAsteroids();
- AsteroidLinkIGC * pmdllink;
- for (pmdllink = pmdllist->first(); pmdllink; pmdllink = pmdllink->next())
- {
- if (pmdllink->data()->SeenBySide(pside))
- {
- ExportObj(pmdllink->data(), OT_asteroid, NULL);
- IbuildingEffectIGC* pbe = pmdllink->data()->GetBuildingEffect();
- if (pbe)
- ExportObj(pbe, OT_buildingEffect, NULL);
- }
- }
- // Export stations
- const StationListIGC * pstnlist = pcluster->GetStations();
- StationLinkIGC * pstnlink;
- for (pstnlink = pstnlist->first(); pstnlink; pstnlink = pstnlink->next())
- {
- if (pstnlink->data()->SeenBySide(pside))
- ExportObj(pstnlink->data(), OT_station, NULL);
- }
- // Export treasure
- const TreasureListIGC * ptlist = pcluster->GetTreasures();
- TreasureLinkIGC * ptlink;
- for (ptlink = ptlist->first(); ptlink; ptlink = ptlink->next())
- {
- if (ptlink->data()->SeenBySide(pside))
- ExportObj(ptlink->data(), OT_treasure, NULL);
- }
- // Export mines
- const MineListIGC * pmlist = pcluster->GetMines();
- MineLinkIGC * pmlink;
- for (pmlink = pmlist->first(); pmlink; pmlink = pmlink->next())
- {
- if (pmlink->data()->SeenBySide(pside))
- ExportObj(pmlink->data(), OT_mine, NULL);
- }
- // Export probes
- const ProbeListIGC * pplist = pcluster->GetProbes();
- ProbeLinkIGC * pplink;
- for (pplink = pplist->first(); pplink; pplink = pplink->next())
- {
- if (pplink->data()->SeenBySide(pside))
- ExportObj(pplink->data(), OT_probe, NULL);
- }
- }
- //For the player's side, update the money & completion state of all buckets
- BEGIN_PFM_CREATE(g.fm, pfmCreateBuckets, S, CREATE_BUCKETS)
- END_PFM_CREATE
- pfmCreateBuckets->ttbmDevelopments = pside->GetDevelopmentTechs();
- pfmCreateBuckets->ttbmInitial = pside->GetInitialTechs();
- {
- for (BucketLinkIGC* pbl = pside->GetBuckets()->first(); (pbl != NULL); pbl = pbl->next())
- {
- IbucketIGC* pbucket = pbl->data();
- {
- BEGIN_PFM_CREATE(g.fm, pfmBucketStatus, S, BUCKET_STATUS)
- END_PFM_CREATE
- pfmBucketStatus->timeTotal = pbucket->GetTime();
- pfmBucketStatus->moneyTotal = pbucket->GetMoney();
- pfmBucketStatus->iBucket = pbucket->GetObjectID();
- pfmBucketStatus->sideID = sideID;
- }
- }
- }
- //Tell the player the money & autodonate for every other person on the side
- for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
- {
- IshipIGC* ps = psl->data();
- if (!pfsPlayer || ps != pfsPlayer->GetIGCShip())
- {
- CFSShip* pcs = (CFSShip *)(ps->GetPrivateData());
- if (pcs->IsPlayer())
- {
- CFSPlayer* pcp = pcs->GetPlayer();
- IshipIGC* pshipDonate = ps->GetAutoDonate();
- ShipID shipID = ps->GetObjectID();
- BEGIN_PFM_CREATE(g.fm, pfmDonate, S, AUTODONATE)
- END_PFM_CREATE
- pfmDonate->sidDonateTo = pshipDonate ? pshipDonate->GetObjectID() : NA;
- pfmDonate->sidDonateBy = shipID;
- pfmDonate->amount = 0;
- BEGIN_PFM_CREATE(g.fm, pfmMoney, S, SET_MONEY)
- END_PFM_CREATE
- pfmMoney->shipID = shipID;
- pfmMoney->money = pcp->GetMoney();
- }
- }
- }
- // send the data on all known ships
- {
- const ShipListIGC * plistShip = m_pMission->GetShips();
-
- for (ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- IshipIGC* pship = plinkShip->data();
- if (pship->GetSide()->GetObjectID() >= 0)
- {
- CFSShip* pcs = (CFSShip *)(pship->GetPrivateData());
- ShipStatus* pss = pcs->GetShipStatus(sideID);
- //We know something about the ship, even if it is obsolete info
- BEGIN_PFM_CREATE(g.fm, pfmShipStatus, S, SHIP_STATUS)
- END_PFM_CREATE
- pfmShipStatus->shipID = pship->GetObjectID();
- pfmShipStatus->status = *pss;
- }
- }
- }
- {
- //Broadcast the victory rankings to all sides
- BEGIN_PFM_CREATE(g.fm, pfmGameState, S, GAME_STATE)
- END_PFM_CREATE
- SideID sid = 0;
- for (SideLinkIGC* l = m_pMission->GetSides()->first(); (l != NULL); l = l->next())
- {
- assert (sid == l->data()->GetObjectID());
- pfmGameState->conquest[sid] = l->data()->GetConquestPercent();
- pfmGameState->territory[sid] = l->data()->GetTerritoryCount();
- pfmGameState->nFlags[sid] = l->data()->GetFlags();
- pfmGameState->nArtifacts[sid++] = l->data()->GetArtifacts();
- }
- }
- g.fm.SendMessages(NULL, FM_GUARANTEED, FM_FLUSH); // default recipient
- }
- CFSMission * CFSMission::GetMission(DWORD dwCookie)
- {
- for (LinkFSMission * plinkFSMis = s_list.first(); plinkFSMis; plinkFSMis = plinkFSMis->next())
- {
- CFSMission * pfsMission = plinkFSMis->data();
- if (pfsMission->GetCookie() == dwCookie)
- return pfsMission;
- }
- return NULL;
- }
- CFSMission * CFSMission::GetMissionFromIGCMissionID(DWORD dwIGCMissionID)
- {
- for (LinkFSMission * plinkFSMis = s_list.first(); plinkFSMis; plinkFSMis = plinkFSMis->next())
- {
- CFSMission * pfsMission = plinkFSMis->data();
- if (pfsMission->m_pMission->GetMissionID() == dwIGCMissionID)
- return pfsMission;
- }
- return NULL;
- }
- /*-------------------------------------------------------------------------
- * FAllReady
- *-------------------------------------------------------------------------
- * Purpose:
- * See if all teams are ready, and if so, tell them to start
- */
- bool CFSMission::FAllReady()
- {
- {
- //Not everyone is ready if sides are imbalanced
- int minPlayers;
- int maxPlayers;
- SideLinkIGC* psl = m_pMission->GetSides()->first();
- assert (psl);
- minPlayers = maxPlayers = psl->data()->GetShips()->n();
- while (true)
- {
- psl = psl->next();
- if (psl == NULL)
- break;
- int n = psl->data()->GetShips()->n();
- if (n < minPlayers)
- minPlayers = n;
- if (n > maxPlayers)
- maxPlayers = n;
- }
- if ((minPlayers < m_misdef.misparms.nMinPlayersPerTeam) ||
- (maxPlayers > m_misdef.misparms.nMaxPlayersPerTeam) ||
- (minPlayers + m_misdef.misparms.iMaxImbalance < maxPlayers))
- return false;
- }
- SideID iSide = m_misdef.misparms.nTeams;
- while (iSide-- > 0 && GetReady(iSide))
- ;
- return iSide < 0;
- }
- /*-------------------------------------------------------------------------
- * PickNewSide
- *-------------------------------------------------------------------------
- * Purpose:
- * pick an available side for a new player (may return SIDE_TEAMLOBBY)
- */
- SideID CFSMission::PickNewSide(CFSPlayer* pfsPlayer, bool bAllowTeamLobby, unsigned char bannedSideMask)
- {
- if (bAllowTeamLobby && (GetStage() > STAGE_NOTSTARTED))
- return SIDE_TEAMLOBBY;
- IsideIGC * psideMostAvailablePositions = NULL;
- int nMostAvailablePositions = 0;
- // find the side with the most positions free that will automatically accept the player
- const SideListIGC * plistSide = m_pMission->GetSides();
- for (SideLinkIGC * plinkSide = plistSide->first(); plinkSide; plinkSide = plinkSide->next())
- {
- IsideIGC* pside = plinkSide->data();
- if ((SideMask(pside) & bannedSideMask) == 0)
- {
- int nNumPlayers = GetCountOfPlayers(pside, false);
- int nAvailablePositions = m_misdef.misparms.nMaxPlayersPerTeam - nNumPlayers;
- if ((CheckPositionRequest(pfsPlayer, pside) == NA)
- && nAvailablePositions > nMostAvailablePositions
- && (GetAutoAccept(pside)
- || (m_misdef.fAutoAcceptLeaders && !GetLeader(pside->GetObjectID()))))
- {
- // in a squad game, favor a team with my squad over an empty team
- if (m_misdef.misparms.bSquadGame && nNumPlayers == 0)
- {
- if (psideMostAvailablePositions == NULL)
- psideMostAvailablePositions = pside;
- }
- else
- {
- nMostAvailablePositions = nAvailablePositions;
- psideMostAvailablePositions = pside;
- }
- }
- }
- }
- // place suggest that side, or the team lobby if no side was found that would accept them
- return psideMostAvailablePositions
- ? psideMostAvailablePositions->GetObjectID()
- : SIDE_TEAMLOBBY;
- }
- /*-------------------------------------------------------------------------
- * PickNewCiv
- *-------------------------------------------------------------------------
- * Purpose:
- * pick a civ for a new team, preferably one that is not in use
- CivID CFSMission::PickNewCiv(SideID nSides, CivID rgCivs[])
- {
- //Pick a random, legal, least used civ
- //Go over all civs and get the minimum count
- int nCivMin;
- int cCivMin = 0x7ffffff;
- const int cCivsMax = 20;
- assert (m_pMission->GetCivilizations()->n() < cCivsMax);
- CivID civIDs[cCivsMax];
- for (pcl = m_pMission->GetCivilizations()->first(); (pcl != NULL); pcl = pcl->next())
- {
- CivID civID = pcl->data()->GetObjectID();
- //NYI hack to prevent special civs
- if (civID < 100)
- {
- int cCiv = 0;
- for (int i = nSides - 1; (i >= 0); i--)
- {
- if (civID == rgCivs[i])
- cCiv++;
- }
- if (cCiv < cCivMin)
- {
- cCivMin = cCiv;
- civIDs[0] = civID;
- nCivMin = 0;
- }
- else if (cCiv == cCivMin)
- {
- civIDs[++nCivMin] = civID;
- }
- }
- }
- assert (cCivMin != 0x7ffffff);
- return civIDs[RandomInt(0, nCivMin)];
- }
- */
- DelPositionReqReason CFSMission::CheckPositionRequest(CFSPlayer * pfsPlayer, IsideIGC * pside)
- {
- assert(pside);
- SideID sideID = pside->GetObjectID();
- const MissionParams* pmp = m_pMission->GetMissionParams();
- IsideIGC* psideCurrent = pfsPlayer->GetSide();
- if (psideCurrent && psideCurrent->GetObjectID() != SIDE_TEAMLOBBY)
- {
- if ((!pmp->bAllowDefections) && (GetStage() == STAGE_STARTED))
- return DPR_NoDefections;
- else if (pmp->bLockSides)
- return DPR_SidesLocked;
- }
-
- if (sideID != SIDE_TEAMLOBBY)
- {
- if (GetStage() == STAGE_OVER)
- return DPR_ServerPaused;
- if (pfsPlayer->GetBannedSideMask() & SideMask(sideID))
- return DPR_Banned;
- if (RequiresInvitation() && !CFSSide::FromIGC(pside)->IsInvited(pfsPlayer))
- return DPR_PrivateGame;
- int nNumPlayers = GetCountOfPlayers(pside, false);
- int maxPlayers = pmp->nMaxPlayersPerTeam;
- //Can they join the chosen side?
- if ((STAGE_NOTSTARTED != GetStage()) && (pmp->iMaxImbalance != 0x7fff))
- {
- for (SideLinkIGC* psl = m_pMission->GetSides()->first(); (psl != NULL); psl = psl->next())
- {
- if (psl->data()->GetActiveF())
- {
- int count = GetCountOfPlayers(psl->data(), false) + pmp->iMaxImbalance;
- if (count < maxPlayers)
- maxPlayers = count;
- }
- }
- }
- if (STAGE_NOTSTARTED != GetStage())
- {
- if (!GetBase(pside))
- return DPR_NoBase;
- else if (!pside->GetActiveF())
- return DPR_SideDefeated;
- }
- if (GetCountOfPlayers(pside, false) >= pmp->nMaxPlayersPerTeam)
- return DPR_TeamFull;
- else if (nNumPlayers >= maxPlayers)
- return DPR_TeamBalance;
- if (m_misdef.misparms.bSquadGame)
- {
- if (nNumPlayers > 0)
- {
- if (!pfsPlayer->GetIsMemberOfSquad(pside->GetSquadID()))
- return DPR_WrongSquad;
- }
- else
- {
- if (pfsPlayer->GetPreferredSquadToLead() == NA)
- return DPR_CantLeadSquad;
- }
- }
- }
-
- return (DelPositionReqReason)NA;
- }
- void CFSMission::RequestPosition(CFSPlayer * pfsPlayer, IsideIGC * pside, bool bRejoin)
- {
- assert(pside);
- SideID sideID = pside->GetObjectID();
- const MissionParams* pmp = m_pMission->GetMissionParams();
- DelPositionReqReason reason = CheckPositionRequest(pfsPlayer, pside);
- if (reason != NA)
- {
- //deny the request
- BEGIN_PFM_CREATE(g.fm, pfmDelPosReq, CS, DELPOSITIONREQ)
- END_PFM_CREATE
- pfmDelPosReq->shipID = pfsPlayer->GetShipID();
- pfmDelPosReq->iSide = sideID;
- pfmDelPosReq->reason = reason;
- g.fm.SendMessages(pfsPlayer->GetConnection(), FM_GUARANTEED, FM_FLUSH);
- return;
- }
- if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
- {
- RemovePlayerFromSide(pfsPlayer, QSR_SwitchingSides);
- }
- if (sideID != SIDE_TEAMLOBBY)
- {
- if ((!GetLeader(sideID) && m_misdef.fAutoAcceptLeaders)
- || bRejoin
- || m_misdef.rgfAutoAccept[sideID])
- {
- AddPlayerToSide(pfsPlayer, pside);
- }
- else // need permission
- {
- BEGIN_PFM_CREATE(g.fm, pfmSPositionReq, S, POSITIONREQ)
- END_PFM_CREATE
- pfmSPositionReq->shipID = pfsPlayer->GetShipID();
- pfmSPositionReq->iSide = sideID;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- AddJoinRequest(pfsPlayer, pside);
- }
- }
- }
- /*-------------------------------------------------------------------------
- * VacateStation
- *-------------------------------------------------------------------------
- * Purpose:
- * Kick everyone out of a station, except the people on the owning side
- */
- void CFSMission::VacateStation(IstationIGC * pstation)
- {
- assert (pstation->GetMission() == m_pMission);
- IsideIGC* psideGhost = NULL;
- //Everyone goes (in the event of a capture: the person capturing has not docked yet)
- const ShipListIGC* pships = pstation->GetShips();
- ShipLinkIGC* pshiplink = pships->first();
- while (pshiplink)
- {
- IshipIGC* pship = pshiplink->data();
- if (pship->GetParentShip() == NULL)
- {
- if (pship->IsGhost())
- {
- //Ghosts ... move the ghosts in the next pass
- psideGhost = pship->GetSide();
- pshiplink = pshiplink->next();
- }
- else
- {
- //Force any kids who haven't undocked to undock
- for (ShipLinkIGC* psl = pship->GetChildShips()->first();
- (psl != NULL);
- psl = psl->next())
- {
- psl->data()->SetStation(NULL);
- }
- pship->SetStation(NULL);
- CFSShip* pfsship = (CFSShip*)(pship->GetPrivateData());
- if (pfsship->IsPlayer())
- pfsship->GetPlayer()->ForceLoadoutChange();
- pshiplink = pships->first();
- }
- }
- else
- pshiplink = pshiplink->next();
- }
- if (psideGhost)
- {
- //Find an alternate base for the ghosts ... if they don't have one, don't worry: side
- //will be eliminated
- for (StationLinkIGC* psl = psideGhost->GetStations()->first(); (psl != NULL); psl = psl->next())
- {
- IstationIGC* ps = psl->data();
- if ((ps != pstation) && ps->GetBaseStationType()->HasCapability(c_sabmRestart))
- {
- ShipLinkIGC* pshiplink = pships->first();
- while (pshiplink)
- {
- IshipIGC* pship = pshiplink->data();
- pshiplink = pshiplink->next();
- assert (pship->GetParentShip() == NULL);
- assert (pship->IsGhost());
- pship->SetStation(ps);
- }
- break;
- }
- }
- }
- }
- /*-------------------------------------------------------------------------
- * AddJoinRequest
- *-------------------------------------------------------------------------
- * Purpose:
- * When a player joins a team that has auto-accept off (or other blockers,
- * such as not having a civ yet), a player is added to the join request list.
- */
- void CFSMission::AddJoinRequest(CFSPlayer * pfsPlayer, IsideIGC * pside)
- {
- JoinRequest * pjr = new JoinRequest;
- pjr->pfsPlayer = pfsPlayer;
- pjr->pSide = pside;
- m_listJoinReq.last(pjr);
- // must go through the lobby to change missions
- assert(pfsPlayer->GetMission() == this);
- }
- /*-------------------------------------------------------------------------
- * NotifyPlayerBoot
- *-------------------------------------------------------------------------
- * Purpose:
- * Mark a player as off the side, both the remote player and the local igc player
- *
- * Paremeters:
- * dwSendBootTo as defined next to declaration of this function in fsmission.h
- */
- void CFSMission::NotifyPlayerBoot(CFSPlayer * pfsPlayer, IsideIGC * pSide)
- {
- // Forward the remove request to everyone
- BEGIN_PFM_CREATE(g.fm, pfmDelPosReq, CS, DELPOSITIONREQ)
- END_PFM_CREATE
- pfmDelPosReq->shipID = pfsPlayer->GetShipID();
- pfmDelPosReq->iSide = pSide->GetObjectID();
- pfmDelPosReq->reason = DPR_Rejected;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- /*-------------------------------------------------------------------------
- * RejectSideJoinRequests
- *-------------------------------------------------------------------------
- * Purpose:
- * Any pending requests on a side are rejected
- *
- * Side Effects:
- * Those people are given the boot
- */
- bool CFSMission::RejectSideJoinRequests(IsideIGC * pSide)
- {
- bool fAny = false;
- // Note: almost the same as loop in SetAutoAccept--maybe should combine 'em
- LinkJoinReq* plinkNext;
- for (LinkJoinReq* plinkJR = m_listJoinReq.first(); (plinkJR != NULL); plinkJR = plinkNext)
- {
- plinkNext = plinkJR->next();
- JoinRequest * pjr = plinkJR->data();
- if (pjr->pSide == pSide)
- {
- NotifyPlayerBoot(pjr->pfsPlayer, pjr->pSide);
- delete plinkJR;
- delete pjr;
- fAny = true;
- }
- }
- return fAny;
- }
- /*-------------------------------------------------------------------------
- * RemoveJoinRequest
- *-------------------------------------------------------------------------
- * Purpose:
- * Remove all stored requests for specified player
- * A player comes off the join list when they are added to a team, or log off
- *
- * Parameters:
- * pfsPlayer: Player to remove, or NULL for all players
- * psideDest: Side the player is going to
- *
- * Returns: whether there were any requests to remove
- */
- bool CFSMission::RemoveJoinRequest(CFSPlayer * pfsPlayer, IsideIGC * psideDest)
- {
- bool fAny = false;
- // Note: almost the same as loop in SetAutoAccept--maybe should combine 'em
- LinkJoinReq* plinkNext;
- for (LinkJoinReq* plinkJR = m_listJoinReq.first(); (plinkJR != NULL); plinkJR = plinkNext)
- {
- plinkNext = plinkJR->next();
- JoinRequest * pjr = plinkJR->data();
- if (pjr->pfsPlayer == pfsPlayer || !pfsPlayer)
- {
- // Let's tell everyone that the request is gone if the player isn't going to a team
- if (!psideDest)
- NotifyPlayerBoot(pjr->pfsPlayer, pjr->pSide);
- delete plinkJR;
- delete pjr;
- fAny = true;
- }
- }
- return fAny;
- }
- /*-------------------------------------------------------------------------
- * SetAutoAccept
- *-------------------------------------------------------------------------
- * Purpose:
- * Turn auto-accept on or off for a side.
- * Slightly bastardized use: pass NULL for pside and false for fAccept to
- * reject all pending requests on all sides
- *
- * Side Effects:
- * If turning it on, any requests on the side are accepted.
- */
- void CFSMission::SetAutoAccept(IsideIGC * pside, bool fAccept)
- {
- assert(IMPLIES(!pside, !fAccept));
- SideID sideID = pside ? pside->GetObjectID() : NA;
- if (pside)
- m_misdef.rgfAutoAccept[sideID] = fAccept;
- // else the mission is going away altogether, so it doesn't matter
- if (pside && fAccept || !pside)
- {
- LinkJoinReq* plinkNext;
- for (LinkJoinReq* plinkJR = m_listJoinReq.first(); (plinkJR != NULL); plinkJR = plinkNext)
- {
- plinkNext = plinkJR->next();
- JoinRequest * pjr = plinkJR->data();
- if (pjr->pSide == pside || !pside)
- {
- delete plinkJR;
- // If anyone has more than one request in, then they'll get more than one side change.
- // That shouldn't happen.
- CFSPlayer* pfsPlayer = pjr->pfsPlayer;
- delete pjr;
-
- if (pside)
- {
- // should never add the player back to the list, since autoaccept is on
- RequestPosition(pfsPlayer, pside, false);
- }
- }
- }
- }
- }
- /*-------------------------------------------------------------------------
- * SetLockLobby
- *-------------------------------------------------------------------------
- * Purpose:
- * Lock/unlock the lobby for a game.
- *
- * Notes:
- * Does not send the lock lobby message to the clients here, so you have
- * to do it from the call site. Should we change this?
- */
- void CFSMission::SetLockLobby(bool bLock)
- {
- m_misdef.misparms.bLockLobby = bLock;
- m_pMission->SetMissionParams(&m_misdef.misparms);
- SetLobbyIsDirty();
- }
- /*-------------------------------------------------------------------------
- * SetLockSides
- *-------------------------------------------------------------------------
- * Purpose:
- * Lock/unlock the Sides for a game.
- *
- * Notes:
- * Does not send the lock Sides message to the clients here, so you have
- * to do it from the call site. Should we change this?
- */
- void CFSMission::SetLockSides(bool bLock)
- {
- m_misdef.misparms.bLockSides = bLock;
- m_pMission->SetMissionParams(&m_misdef.misparms);
- }
- /*-------------------------------------------------------------------------
- * RandomizeSides
- *-------------------------------------------------------------------------
- * Purpose:
- * Assigns everyone in the mission to a random team except the team leaders
- */
- void CFSMission::RandomizeSides()
- {
- assert(GetStage() == STAGE_NOTSTARTED);
- // Make sure the sides are not locked
- // (no need to tell the clients, since we tell them when we lock the sides again below)
- SetLockSides(false);
- // turn on auto accept for all sides
- {
- for (SideLinkIGC* psl = m_pMission->GetSides()->first(); psl != NULL; psl = psl->next())
- {
- if (!GetAutoAccept(psl->data()))
- {
- SetAutoAccept(psl->data(), true);
- BEGIN_PFM_CREATE(g.fm, pfmAutoAccept, CS, AUTO_ACCEPT)
- END_PFM_CREATE
- pfmAutoAccept->iSide = psl->data()->GetObjectID();
- pfmAutoAccept->fAutoAccept = true;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_DONT_FLUSH);
- }
- }
- g.fm.PurgeOutBox();
- }
- // move everyone who's not a team leader to the lobby side.
- {
- const ShipListIGC* pships = m_pMission->GetShips();
- ShipLinkIGC* pshipLinkNext;
- for (ShipLinkIGC* pshipLink = pships->first();
- (pshipLink != NULL);
- pshipLink = pshipLinkNext)
- {
- pshipLinkNext = pshipLink->next();
- CFSPlayer* pfsPlayer = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
- SideID sideID = pfsPlayer->GetSide()->GetObjectID();
- // clear their banned side mask (it simplifies life)
- pfsPlayer->SetBannedSideMask(0);
- // if they are not already on the lobby side and not a team leader
- if (sideID != SIDE_TEAMLOBBY && GetLeader(sideID) != pfsPlayer)
- {
- RemovePlayerFromSide(pfsPlayer, QSR_RandomizeSides);
- }
- }
- }
-
- // randomly put everyone back on a team
- {
- IsideIGC* psideLobby = m_pMission->GetSide(SIDE_TEAMLOBBY);
- const ShipListIGC* pshipsLobby = psideLobby->GetShips();
-
- bool bPickTeamFailed = false;
- // this is O(n^2), but I think n is small enough and it's used rarely
- // enough that it won't matter.
- // randomly pick players and asign them to teams until we hit a player
- // that can't be assigned to a team. At that point, the teams should
- // be full.
- while (pshipsLobby->n() > 0 && !bPickTeamFailed)
- {
- // pick a random player from the lobby side
- CFSPlayer* pfsPlayer;
- {
- int nPlayerIndex = (int)random(0, pshipsLobby->n());
- ShipLinkIGC* pshipLink;
- for (pshipLink = pshipsLobby->first();
- nPlayerIndex > 0;
- pshipLink = pshipLink->next(), --nPlayerIndex)
- {
- }
- pfsPlayer = ((CFSShip*)(pshipLink->data()->GetPrivateData()))->GetPlayer();
- }
-
- // try to find a side to assign them to.
- SideID sideID = PickNewSide(pfsPlayer, true, pfsPlayer->GetBannedSideMask());
- if (sideID == SIDE_TEAMLOBBY)
- bPickTeamFailed = true;
- else
- AddPlayerToSide(pfsPlayer, m_pMission->GetSide(sideID));
- }
- }
- // then lock the sides.
- {
- SetLockSides(true);
- BEGIN_PFM_CREATE(g.fm, pfmLockSides, CS, LOCK_SIDES)
- END_PFM_CREATE
- pfmLockSides->fLock = true;
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- }
- void CFSMission::SetSideCiv(IsideIGC * pside, IcivilizationIGC * pciv)
- {
- pside->SetCivilization(pciv);
- CivID civID = pciv->GetObjectID();
- //m_misdef.rgCivID[pside->GetObjectID()] = civID;
- //Go through all players on the team and adjust their persist score objects
- // Their persist score now becomes their current score, and other stuff is reset
- for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
- {
- IshipIGC* pship = psl->data();
- CFSShip* pfsship = (CFSShip*)(pship->GetPrivateData());
- PlayerScoreObject* ppso = pfsship->GetPlayerScoreObject();
- ppso->SetPersist(pfsship->GetPlayer()->GetPersistPlayerScore(civID));
- }
- }
- /*-------------------------------------------------------------------------
- * DeactivateSide
- *-------------------------------------------------------------------------
- * Purpose:
- * Mark a side as inactive and tell everyone about it.
- * Once a side is inactive, no one can join it
- *
- * Parameters:
- * side to deactivate
- */
- void CFSMission::DeactivateSide(IsideIGC * pside)
- {
- if (!m_misdef.misparms.bAllowEmptyTeams)
- {
- assert(pside->GetMission() == m_pMission);
- debugf("DeactivateSide side=%d.\n", pside->GetObjectID());
- pside->SetActiveF(false);
- SideID sideid = pside->GetObjectID();
- m_misdef.rgfActive[sideid] =
- m_misdef.rgfReady[sideid] = false;
- pside->SetTimeEndured(max(0.0f, Time::Now() - m_misdef.misparms.timeStart));
- //Eliminate all of the side's drones
- const ShipListIGC* pships = pside->GetShips();
- {
- ShipLinkIGC* pslNext;
- for (ShipLinkIGC* psl = pships->first(); (psl != NULL); psl = pslNext)
- {
- pslNext = psl->next();
- IshipIGC* pship = psl->data();
- if (pship->GetBaseHullType())
- {
- {
- const PartListIGC* parts = pship->GetParts();
- PartLinkIGC* plink;
- while (plink = parts->first()) //Not ==
- plink->data()->Terminate();
- }
- pship->SetAmmo(0);
- pship->SetFuel(0.0f);
- }
- if (pship->GetPilotType() < c_ptPlayer)
- {
- m_psiteIGC->KillShipEvent(g.timeNow, pship, NULL, 0.0f, pship->GetPosition(), Vector::GetZero());
- }
- else
- {
- if ((pship->GetParentShip() == NULL) && (pship->GetCluster() != NULL))
- m_psiteIGC->KillShipEvent(g.timeNow, pship, NULL, -1.0f, pship->GetPosition(), Vector::GetZero()); //"Negative damage" == force killed
- pship->Reset(false);
- ((CFSShip*)(pship->GetPrivateData()))->ShipStatusExit();
- }
- }
- }
- BEGIN_PFM_CREATE(g.fm, pfmSideInactive, S, SIDE_INACTIVE)
- END_PFM_CREATE
- pfmSideInactive->sideID = pside->GetObjectID();
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- GetSite()->SendChatf(NULL, CHAT_EVERYONE, NA, NA, "%s is no more.", pside->GetName());
- bool bAllSidesInactive;
- IsideIGC* psideWin = CheckForVictoryByInactiveSides(bAllSidesInactive);
- if (bAllSidesInactive)
- {
- // if the game has not started yet, start it so that a side can win.
- if (GetStage() == STAGE_STARTING)
- StartGame();
- GameOver(NULL, "All sides were destroyed");
- }
- else if (psideWin)
- {
- // if the game has not started yet, start it so that a side can win.
- if (GetStage() == STAGE_STARTING)
- StartGame();
- static char szReason[100]; //Make this static so we only need to keep a pointer to it around
- sprintf(szReason, "%s won by outlasting all other sides.", psideWin->GetName());
- GameOver(psideWin, szReason);
- }
- else if ((m_psideWon == NULL) && pships->n())
- {
- //Games not over for anyone but this team (only ships on the team will be players)
- CFMGroup* pgroup = CFSSide::FromIGC(pside)->GetGroup();
- g.fm.SetDefaultRecipient(pgroup, FM_GUARANTEED);
- QueueGameoverMessage();
- g.fm.SendMessages(pgroup, FM_GUARANTEED, FM_FLUSH);
- }
- }
- }
- /*-------------------------------------------------------------------------
- * SetForceReady
- *-------------------------------------------------------------------------
- * Purpose:
- * Set a side's force ready bit
- *
- * Side Effects:
- * Ready state of side may change
- */
- void CFSMission::SetForceReady(SideID iSide, bool fForceReady)
- {
- m_misdef.rgfForceReady[iSide] = fForceReady;
- if (fForceReady)
- SetReady(iSide, true);
- else
- CheckForSideAllReady(m_pMission->GetSide(iSide));
- }
- /*-------------------------------------------------------------------------
- * SetReady
- *-------------------------------------------------------------------------
- * Purpose:
- * Mark a side as ready or not. No checking of player ready states,
- * force ready bits, etc. is done here. That's why it's private
- *
- * Side Effects:
- * If side is now ready, game may start
- */
- void CFSMission::SetReady(SideID iSide, bool fReady)
- {
- if (fReady != GetReady(iSide))
- {
- BEGIN_PFM_CREATE(g.fm, pfmTeamReady, S, TEAM_READY)
- END_PFM_CREATE
- pfmTeamReady->iSide = iSide;
- pfmTeamReady->fReady =
- m_misdef.rgfReady[iSide] = fReady; // dbl assignment
- g.fm.SendMessages(GetGroupMission(), FM_GUARANTEED, FM_FLUSH);
- }
- }
- /*-------------------------------------------------------------------------
- * PlayerReadyChange
- *-------------------------------------------------------------------------
- * Purpose:
- * Notification from a player that their ready status changed. This may
- * change the ready status of the side
- *
- * Side Effects:
- * A side's ready status may change
- */
- void CFSMission::PlayerReadyChange(CFSPlayer * pfsPlayer)
- {
- if (pfsPlayer->GetSide()->GetObjectID() != SIDE_TEAMLOBBY)
- CheckForSideAllReady(pfsPlayer->GetSide());
- }
- /*-------------------------------------------------------------------------
- * CheckForSideAllReady
- *-------------------------------------------------------------------------
- * Purpose:
- * See if everyone on a side is ready. Mark the side as such (if not force ready)
- */
- void CFSMission::CheckForSideAllReady(IsideIGC * pside)
- {
- SideID sideid = pside->GetObjectID();
- if (GetCountOfPlayers(pside, false) < m_misdef.misparms.nMinPlayersPerTeam)
- SetReady(sideid, false);
- else if (GetForceReady(pside->GetObjectID()))
- SetReady(sideid, true);
- else
- {
- bool fReady = true;
- const ShipListIGC * plistShip = pside->GetShips();
- for(ShipLinkIGC * plinkShip = plistShip->first(); plinkShip; plinkShip = plinkShip->next())
- {
- CFSShip * pfsShip = (CFSShip *) plinkShip->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- CFSPlayer * pfsPlayer = pfsShip->GetPlayer();
- if (!pfsPlayer->GetReady())
- {
- fReady = false;
- break;
- }
- }
- }
- SetReady(sideid, fReady);
- }
- }
- /*-------------------------------------------------------------------------
- * CreateCluster()
- *-------------------------------------------------------------------------
- * Purpose:
- * Make a FSCluster.
- */
- void CFSMission::CreateCluster(IclusterIGC * pIclusterIGC)
- {
- CFSCluster * pCFSCluster = new CFSCluster(pIclusterIGC);
- m_pFSClusters.push_back(pCFSCluster);
- }
- /*-------------------------------------------------------------------------
- * DeleteCluster()
- *-------------------------------------------------------------------------
- * Purpose:
- * Destroy a FSCluster, given a pointer to an IclusterIGC.
- */
- void CFSMission::DeleteCluster(IclusterIGC * pIclusterIGC)
- {
- CFSCluster * pFSCluster = (CFSCluster *) pIclusterIGC->GetPrivateData();
- if (pFSCluster)
- {
- std::vector<CFSCluster*>::iterator i = std::find(m_pFSClusters.begin(), m_pFSClusters.end(), pFSCluster);
- assert(i != m_pFSClusters.end()); // assert that we found the pointer to delete
-
- delete static_cast<CFSCluster*>(*i);
- m_pFSClusters.erase(i);
- }
- }
- /*-------------------------------------------------------------------------
- * CreateSide()
- *-------------------------------------------------------------------------
- * Purpose:
- * Make a FSSide.
- */
- void CFSMission::CreateSide(IsideIGC * pIsideIGC)
- {
- CFSSide * pCFSSide = new CFSSide(pIsideIGC, this);
-
- m_pFSSides.push_back(pCFSSide);
- }
- /*-------------------------------------------------------------------------
- * DeleteSide()
- *-------------------------------------------------------------------------
- * Purpose:
- * Destroy a FSSide, given a pointer to an IsideIGC.
- */
- void CFSMission::DeleteSide(IsideIGC * pIsideIGC)
- {
- CFSSide * pFSSide = (CFSSide *) pIsideIGC->GetPrivateData();
- if (pFSSide)
- {
- std::vector<CFSSide*>::iterator i = std::find(m_pFSSides.begin(), m_pFSSides.end(), pFSSide);
- assert(i != m_pFSSides.end()); // assert that we found the pointer to delete
- delete (CFSSide*)(*i);
- m_pFSSides.erase(i);
- }
- }
- void CFSMission::UpdateLobby(Time now)
- {
- if (m_fLobbyDirty && (now - m_timeLastLobbyMissionInfo >= c_flUpdateTimeInterval)
- && (GetCookie() != NULL || !g.fmLobby.IsConnected()))
- {
- m_fLobbyDirty = false;
- if (g.fmLobby.IsConnected())
- {
- QueueLobbyMissionInfo();
- g.fmLobby.SendMessages(g.fmLobby.GetServerConnection(), FM_GUARANTEED, FM_FLUSH);
- }
- m_timeLastLobbyMissionInfo = now;
- // Let's overload this function and also update the session details
- SetSessionDetails();
- }
- }
- void CFSMission::SetLobbyIsDirty()
- {
- m_fLobbyDirty = true;
- UpdateLobby(Time::Now());
- }
- // do any steps needed to update the current ballot. Returns true iff
- // the ballot is no longer needed.
- bool Ballot::Update(const Time& now)
- {
- if (m_bCanceled)
- return true;
- if (m_timeExpiration < now || AllVotesAreIn())
- {
- if (HasPassed())
- OnPassed();
- else
- OnFailed();
- return true;
- }
- else
- return false;
- }
- // cancels the pending vote
- void Ballot::Cancel()
- {
- if (!m_bCanceled)
- {
- m_bCanceled = true;
- // REVIEW: should we send a cancelation message here?
- }
- }
- // records the given vote from a player
- void Ballot::CastVote(CFSPlayer* pfsPlayer, bool bVote)
- {
- // if they are in the list of valid voters
- if (m_vShips.Remove(pfsPlayer->GetShipID()) != -1)
- {
- SideID sideID = pfsPlayer->GetSide()->GetObjectID();
- assert(sideID >= 0);
- // if they are on a valid side, tally the vote
- if (sideID >= 0 && m_cAbstaining[sideID] > 0)
- {
- --m_cAbstaining[sideID];
- if (bVote)
- ++m_cInFavor[sideID];
- else
- ++m_cOpposed[sideID];
- }
- }
- }
- // gets the ID of this ballot
- BallotID Ballot::GetBallotID()
- {
- return m_ballotID;
- }
- // initializes the ballot for a given vote proposed by a player to their team
- void Ballot::Init(CFSPlayer* pfsInitiator, const ZString& strProposalName, const ZString& strBallotText)
- {
- assert(pfsInitiator);
- // store some misc. info about the vote
- float c_fVoteDuration = 30.0f;
- m_pgroup = CFSSide::FromIGC(pfsInitiator->GetSide())->GetGroup();
- m_pmission = pfsInitiator->GetMission();
- m_chattarget = CHAT_TEAM;
- m_groupID = pfsInitiator->GetSide()->GetObjectID();
- m_strProposal = strProposalName;
- m_ballotID = s_ballotIDNext++;
- m_timeExpiration = Time::Now() + c_fVoteDuration;
- m_bCanceled = false;
- // zero out the counts
- for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
- {
- m_cAbstaining[sideID] = 0;
- m_cInFavor[sideID] = 0;
- m_cOpposed[sideID] = 0;
- }
- // add the players
- assert(pfsInitiator->GetSide());
- const ShipListIGC* shipsList = pfsInitiator->GetSide()->GetShips();
- m_vShips.Reserve(shipsList->n());
- SideID sideIDInitiator = m_groupID;
- for (ShipLinkIGC* shipLink = shipsList->first(); shipLink; shipLink = shipLink->next())
- {
- CFSShip * pfsShip = (CFSShip*)shipLink->data()->GetPrivateData();
- if (pfsShip->IsPlayer())
- {
- ++m_cAbstaining[sideIDInitiator];
- m_vShips.PushEnd(pfsShip->GetShipID());
- }
- }
- // tell the clients about the vote
- BEGIN_PFM_CREATE(g.fm, pfmBallot, S, BALLOT)
- FM_VAR_PARM((PCC)(strBallotText), CB_ZTS)
- END_PFM_CREATE
- pfmBallot->ballotID = m_ballotID;
- pfmBallot->timeExpiration = m_timeExpiration;
- pfmBallot->otInitiator = OT_ship;
- pfmBallot->oidInitiator = pfsInitiator->GetShipID();
- g.fm.SendMessages(m_pgroup, FM_GUARANTEED, FM_FLUSH);
- // tally the vote for the initiator
- CastVote(pfsInitiator, true);
- }
- // initializes the ballot for a given vote proposed by a team to all other teams
- void Ballot::Init(CFSSide* pfsideInitiator, const ZString& strProposalName, const ZString& strBallotText)
- {
- assert(pfsideInitiator);
- // store some misc. info about the vote
- float c_fVoteDuration = 30.0f;
- m_pgroup = pfsideInitiator->GetMission()->GetGroupRealSides();
- m_pmission = pfsideInitiator->GetMission();
- m_chattarget = CHAT_EVERYONE;
- m_groupID = NA;
- m_strProposal = strProposalName;
- m_ballotID = s_ballotIDNext++;
- m_timeExpiration = Time::Now() + c_fVoteDuration;
- m_bCanceled = false;
- // zero out the counts
- for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
- {
- m_cAbstaining[sideID] = 0;
- m_cInFavor[sideID] = 0;
- m_cOpposed[sideID] = 0;
- }
- // add the players
- const ShipListIGC* shipsList = pfsideInitiator->GetMission()->GetIGCMission()->GetShips();
- m_vShips.Reserve(shipsList->n());
- SideID sideIDInitiator = pfsideInitiator->GetSideIGC()->GetObjectID();
- assert(sideIDInitiator >= 0);
- for (ShipLinkIGC* shipLink = shipsList->first(); shipLink; shipLink = shipLink->next())
- {
- CFSShip * pfsShip = (CFSShip*)shipLink->data()->GetPrivateData();
- IsideIGC* pside = pfsShip->GetSide();
- SideID sideIDPlayer = pside->GetObjectID();
- if (pfsShip->IsPlayer() && pside->GetActiveF() && sideIDPlayer >= 0 && sideIDPlayer != sideIDInitiator)
- {
- ++m_cAbstaining[sideIDPlayer];
- m_vShips.PushEnd(pfsShip->GetShipID());
- }
- }
- // tell the clients about the vote
- BEGIN_PFM_CREATE(g.fm, pfmBallot, S, BALLOT)
- FM_VAR_PARM((PCC)(strBallotText), CB_ZTS)
- END_PFM_CREATE
- pfmBallot->ballotID = m_ballotID;
- pfmBallot->timeExpiration = m_timeExpiration;
- pfmBallot->otInitiator = OT_side;
- pfmBallot->oidInitiator = pfsideInitiator->GetSideIGC()->GetObjectID();
- g.fm.SendMessages(m_pgroup, FM_GUARANTEED, FM_FLUSH);
- }
- // gets a string describing the tally of votes
- ZString Ballot::GetTallyString()
- {
- ZString strMessage;
- bool bFirst = true;
- for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
- {
- // if there were any votes on this side
- if (m_cAbstaining[sideID] + m_cInFavor[sideID] + m_cOpposed[sideID])
- {
- if (bFirst)
- {
- bFirst = false;
- strMessage += "(";
- }
- else
- strMessage += ", ";
- // only display the team name if more than one team is voting on the issue
- if (m_chattarget != CHAT_TEAM)
- strMessage += ZString(m_pmission->GetIGCMission()->GetSide(sideID)->GetName()) + ":" ;
-
- if (m_cInFavor[sideID])
- strMessage += " " + ZString(m_cInFavor[sideID]) + " for";
- if (m_cOpposed[sideID])
- strMessage += " " + ZString(m_cOpposed[sideID]) + " against";
- if (m_cAbstaining[sideID])
- strMessage += " " + ZString(m_cAbstaining[sideID]) + " abstained";
- }
- }
- if (!bFirst)
- strMessage += ")";
- return strMessage;
- }
- // performs the appropriate result when the vote passes
- void Ballot::OnPassed()
- {
- ZString strMessage = m_strProposal + " has passed. " + GetTallyString();
- m_pmission->GetSite()->SendChat(NULL, m_chattarget, m_groupID, NA,
- strMessage, c_cidNone, NA, NA, NULL, true);
- }
- // performs the appropriate result when the vote passes
- void Ballot::OnFailed()
- {
- ZString strMessage = m_strProposal + " has been defeated. " + GetTallyString();
- m_pmission->GetSite()->SendChat(NULL, m_chattarget, m_groupID, NA,
- strMessage, c_cidNone, NA, NA, NULL, true);
- }
- // tests whether the vote passes
- bool Ballot::HasPassed()
- {
- for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
- {
- // if there were any votes on this side
- if (m_cAbstaining[sideID] + m_cInFavor[sideID] + m_cOpposed[sideID])
- {
- // if it didn't get a majority, it didn't pass.
- if (m_cInFavor[sideID] <= m_cOpposed[sideID] + m_cAbstaining[sideID])
- {
- return false;
- }
- }
- }
- return true;
- }
- // tests to see if we have received all of the votes
- bool Ballot::AllVotesAreIn()
- {
- for (SideID sideID = 0; sideID < c_cSidesMax; ++sideID)
- {
- if (m_cAbstaining[sideID] != 0)
- return false;
- }
- return true;
- }
- BallotID Ballot::s_ballotIDNext = 0;
- // a ballot used when a player suggests resigning
- ResignBallot::ResignBallot(CFSPlayer* pfsInitiator)
- {
- m_pside = pfsInitiator->GetSide();
- Init(pfsInitiator, pfsInitiator->GetName() + ZString("'s proposal to resign"), pfsInitiator->GetName() + ZString(" has proposed resigning. "));
- }
- void ResignBallot::OnPassed()
- {
- Ballot::OnPassed();
- SideID sideID = m_pside->GetObjectID();
- if (sideID >= 0 && STAGE_STARTED == m_pmission->GetStage())
- {
- m_pmission->DeactivateSide(m_pside);
- }
- }
- // a ballot used when a player suggests offering a draw
- OfferDrawBallot::OfferDrawBallot(CFSPlayer* pfsInitiator)
- {
- m_pfside = CFSSide::FromIGC(pfsInitiator->GetSide());
- Init(pfsInitiator, pfsInitiator->GetName() + ZString("'s proposal to offer a draw"), pfsInitiator->GetName() + ZString(" has proposed offering a draw. "));
- }
- void OfferDrawBallot::OnPassed()
- {
- Ballot::OnPassed();
- m_pmission->GetSite()->SendChat(NULL, m_chattarget, m_groupID, NA,
- "A draw is being offered to the other teams.", c_cidNone, NA, NA, NULL, true);
- m_pmission->AddBallot(new AcceptDrawBallot(m_pfside));
- }
- // a ballot used when one team offers a draw
- AcceptDrawBallot::AcceptDrawBallot(CFSSide* pfsideInitiator)
- {
- Init(pfsideInitiator, pfsideInitiator->GetSideIGC()->GetName() + ZString("'s offer of a draw"), pfsideInitiator->GetSideIGC()->GetName() + ZString(" has offered a draw. "));
- }
- void AcceptDrawBallot::OnPassed()
- {
- Ballot::OnPassed();
- m_pmission->GameOver(NULL, "The game was declared a draw");
- }
|