// WorldTick functions extend Class SWWMHandler { transient Array combatactors; transient Array combattics; transient int highesttic, lastcombat; int lastitemcount[MAXPLAYERS]; transient String curlang; transient bool curfuntags; SWWMSimpleTracker strackers; bool mnotify; bool allkills, allitems, allsecrets; bool mapclear; int mapclearagain, restartmus, startmus; double musvol; String lastmus; int lastorder; bool lastloop; transient ThinkerIterator cti, qti; private void LangRefresh() { if ( (language != curlang) || (swwm_funtags != curfuntags) ) { // manually refresh some tags if language has changed if ( !qti ) qti = ThinkerIterator.Create("SWWMQuickCombatTracker",Thinker.STAT_INVENTORY); else qti.Reinit(); SWWMQuickCombatTracker qt; while ( qt=SWWMQuickCombatTracker(qti.Next()) ) qt.UpdateTag(self); for ( SWWMInterest p=intpoints; p; p=p.next ) { if ( (p.type != INT_Key) || !p.trackedkey ) continue; p.keytag = p.trackedkey.GetTag(); } for ( int i=0; i lastitemcount[i] ) { int score = 10*(players[i].itemcount-lastitemcount[i]); if ( !deathmatch && !(gameinfo.gametype&GAME_Hexen) && (level.total_items == level.found_items) && !allitems ) { allitems = true; if ( i == consoleplayer ) Console.Printf(StringTable.Localize("$SWWM_LASTITEM"),500); else Console.Printf(StringTable.Localize("$SWWM_LASTITEMREM"),players[i].GetUserName(),500); score += 490; SWWMUtility.AchievementProgressInc("allitems",1,players[i]); } SWWMCredits.Give(players[i],score); SWWMScoreObj.SpawnFromHandler(self,score,players[i].mo.Vec3Offset(0,0,players[i].mo.Height/2)); lastitemcount[i] = players[i].itemcount; let s = SWWMStats.Find(players[i]); s.items++; } } } // combat tracking private void CombatTrack() { // if players are above 1HP, reset the "one hp kill" counter for ( int i=0; i highesttic ) highesttic = combattics[i]; if ( combatactors[i] && (combatactors[i].Health > 0) && !combatactors[i].bKILLED && !combatactors[i].bCORPSE && (combatactors[i].target == players[consoleplayer].mo) && (combattics[i]+2000 > gametic) ) continue; combatactors.Delete(i); combattics.Delete(i); i--; } bool enteredcombat = false; // add new entries if ( !cti ) cti = ThinkerIterator.Create("Actor"); else cti.Reinit(); Actor a, keyactor = null; bool bossfound = false; while ( a = Actor(cti.Next()) ) { if ( !a.player && !a.bISMONSTER ) continue; // ignore the dead if ( (a.Health <= 0) || a.bKILLED || a.bCORPSE ) continue; // ignore if not targetted if ( a.target != players[consoleplayer].mo ) continue; // ignore friends if ( a.IsFriend(players[consoleplayer].mo) ) continue; // [HDoom] ignore cute girls if ( SWWMHDoomHandler.IsCuteGirl(a.target) ) continue; // ignore if player can't see it if ( !SWWMUtility.InPlayerFOV(players[consoleplayer],a) ) continue; // is it already in? bool addme = true; for ( int i=0; i lastcombat+240))) || (!bossfound && (!highesttic || (gametic > highesttic+700)))) && !players[consoleplayer].mo.FindInventory("GhostPower") ) lastcombat = AddOneliner("fightstart",1,10); } private void OneHundredPercentCheck() { // not in DM if ( deathmatch ) return; // not in Hexen, due to its fully hub-based nature if ( gameinfo.gametype&GAME_Hexen ) return; if ( !mapclear && (restartmus > 0) ) { restartmus--; if ( restartmus == 0 ) S_ChangeMusic(lastmus,lastorder,lastloop,true); return; } // ignore levels that have NOTHING if ( (level.total_secrets <= 0) && (level.total_items <= 0) && (level.total_monsters <= 0) ) return; if ( mapclear ) { if ( (musplaying.name != "music/nomusic.ogg") && (musplaying.name != "music/solitary.ogg") ) { lastmus = musplaying.name; lastorder = musplaying.baseorder; lastloop = musplaying.loop; S_ChangeMusic((startmus>0)?"music/nomusic.ogg":"music/solitary.ogg",force:true); } if ( startmus > 0 ) startmus--; else if ( startmus == 0 ) { startmus = -1; S_ChangeMusic("music/solitary.ogg",force:true); } if ( (level.found_secrets < level.total_secrets) || (level.found_items < level.total_items) || (level.killed_monsters < level.total_monsters) ) { restartmus = 25; S_ChangeMusic("music/nomusic.ogg",force:true); S_StartSound("recordscratch",CHAN_VOICE,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); mapclear = false; if ( mapclearagain > 1 ) Console.Printf(StringTable.Localize("$SWWM_NOTCLEARAGAIN")); else Console.Printf(StringTable.Localize("$SWWM_NOTCLEAR")); } return; } if ( (level.found_secrets < level.total_secrets) || (level.found_items < level.total_items) || (level.killed_monsters < level.total_monsters) ) return; restartmus = 0; mapclear = true; if ( mapclearagain ) Console.Printf(StringTable.Localize("$SWWM_ALLCLEARAGAIN"),500); else Console.Printf(StringTable.Localize("$SWWM_ALLCLEAR"),5000); S_StartSound("misc/wow",CHAN_VOICE,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE); lastmus = musplaying.name; lastorder = musplaying.baseorder; lastloop = musplaying.loop; S_ChangeMusic("music/nomusic.ogg",force:true); startmus = 1050; for ( int i=0; i 0 ) return; } SWWMUtility.MarkAchievement("wantdie",players[consoleplayer]); } private void UpdateHUDObjects() { // score objects SWWMScoreObj so = scorenums; SWWMScoreObj soprev = null, sonext; while ( so ) { sonext = so.next; if ( so.Tick() ) { if ( soprev ) soprev.next = sonext; else scorenums = sonext; so.Destroy(); } else soprev = so; so = sonext; } SWWMDamNum dn = damnums; SWWMDamNum dnprev = null, dnnext; while ( dn ) { dnnext = dn.next; if ( dn.Tick() ) { if ( dnprev ) dnprev.next = dnnext; else damnums = dnnext; dn.Destroy(); } else dnprev = dn; dn = dnnext; } // interest markers SWWMInterest ip = intpoints; SWWMInterest ipprev = null, ipnext; while ( ip ) { ipnext = ip.next; if ( ip.Tick() ) { if ( ipprev ) ipprev.next = ipnext; else intpoints = ipnext; ip.Destroy(); } else ipprev = ip; ip = ipnext; } } // "simple" tracking (used by the minimap) private void SimpleTracking() { if ( (gamestate != GS_LEVEL) || !swwm_mm_enable ) { while ( strackers ) { SWWMSimpleTracker next = strackers.next; strackers.Destroy(); strackers = next; } return; } // update trackers for anything around the player double viewdist = SWWMStatusBar.MAPVIEWDIST*swwm_mm_zoom; BlockThingsIterator bt = BlockThingsIterator.Create(players[consoleplayer].Camera,viewdist); while ( bt.Next() ) { let a = bt.Thing; if ( !a ) continue; Vector2 rv = a.pos.xy-players[consoleplayer].Camera.pos.xy; if ( max(abs(rv.x)-a.radius,abs(rv.y)-a.radius) > viewdist ) continue; if ( a == players[consoleplayer].Camera ) continue; if ( a is 'GhostTarget' ) continue; if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) continue; if ( !level.allmap && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !(a.IsFriend(players[consoleplayer].mo) && !(a.player && (a.player.mo != a))) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; if ( a.bKILLED || (a.Health <= 0) || a.bUnmorphed ) continue; if ( (a is 'Inventory') && (!a.bSPECIAL || Inventory(a).Owner) ) continue; if ( (a is 'Chancebox') && (a.CurState != a.SpawnState) ) continue; SWWMSimpleTracker.Track(self,a); } // we need to refer to the suckables array to find missiles for ( int i=0; i viewdist ) continue; if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; SWWMSimpleTracker.Track(self,a); } for ( int i=0; i viewdist ) continue; if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; SWWMSimpleTracker.Track(self,a); } bt.Destroy(); if ( psectors.Size() > 1 ) { // oh boy here we go int thisgroup = players[consoleplayer].Camera.CurSector.portalgroup; for ( int i=0; i viewdist ) continue; if ( a == players[consoleplayer].Camera ) continue; if ( a is 'GhostTarget' ) continue; if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) continue; if ( !level.allmap && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !a.IsFriend(players[consoleplayer].mo) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; if ( a.bKILLED || (a.Health <= 0) || a.bUnmorphed ) continue; if ( (a is 'Inventory') && (!a.bSPECIAL || Inventory(a).Owner) ) continue; if ( (a is 'Chancebox') && (a.CurState != a.SpawnState) ) continue; SWWMSimpleTracker.Track(self,a); } // we need to refer to the suckables array to find missiles for ( int i=0; i viewdist ) continue; if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; SWWMSimpleTracker.Track(self,a); } for ( int i=0; i viewdist ) continue; if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; SWWMSimpleTracker.Track(self,a); } } } SWWMSimpleTracker trk = strackers; SWWMSimpleTracker prev = null, next; while ( trk ) { next = trk.next; // minimize lifespan of destroyed targets if ( !trk.target ) trk.lastupdate = min(trk.lastupdate,level.maptime); else if ( !trk.expired ) { // "last breath" update if ( (trk.target.bKILLED || (trk.target.Health <= 0)) || ((trk.target is 'Inventory') && (!trk.target.bSPECIAL || Inventory(trk.target).Owner)) || ((trk.target is 'Chancebox') && (trk.target.CurState != trk.target.SpawnState)) || (trk.target.default.bMISSILE && !trk.target.bMISSILE) || trk.target.bUnmorphed ) trk.Update(); } // prune expired trackers if ( trk.lastupdate+140 < level.maptime ) { if ( !prev ) strackers = trk.next; else prev.next = trk.next; trk.Destroy(); } else prev = trk; trk = next; } } }