// WorldThingDamaged and friends Class DeepImpactOnlyToken : Inventory {} extend Class SWWMHandler { bool tookdamage[MAXPLAYERS]; int spreecount[MAXPLAYERS]; int lastkill[MAXPLAYERS]; int multilevel[MAXPLAYERS]; bool dealtdamage[MAXPLAYERS]; bool reallytookdamage[MAXPLAYERS]; int onehpspree[MAXPLAYERS]; // gibbing private void DoGibThing( WorldEvent e ) { // no gib if it was erased or used the kill monsters cheat if ( (e.DamageType == 'Ynykron') || (e.DamageType == 'Massacre') ) return; int gibhealth = e.Thing.GetGibHealth(); bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH)); bool forcegibbed = false; // force gib availability for some vanilla Doom monsters if ( gotgibbed && ((e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "Cacodemon") || (e.Thing.GetClass() == "Revenant") || (e.Thing.GetClass() == "Archvile") || (e.Thing.GetClass() == "Fatso") || (e.Thing.GetClass() == "Arachnotron")) ) forcegibbed = true; if ( !e.Thing.FindState("XDeath",true) && !e.Thing.FindState("Death.Extreme",true) && !forcegibbed ) gotgibbed = false; // only do special handling if they use our blood if ( (e.Thing.GetBloodType(0) != "mkBlood") || e.Thing.bNOBLOOD ) return; CorpseFallTracker.TrackBody(e.Thing); bool b; Actor a; // special handling of some monsters if ( e.Thing.GetClass() == "Cyberdemon" ) { [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); if ( !b ) return; mkGibber(a).gibbed = e.Thing; mkGibber(a).delay = 40; a.special1 = 1; a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); return; } else if ( e.Thing.GetClass() == "SpiderMastermind" ) { [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); if ( !b ) return; mkGibber(a).gibbed = e.Thing; mkGibber(a).delay = 60; a.special1 = 1; a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); } else if ( gotgibbed ) { [b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR); if ( !b ) return; mkGibber(a).gibbed = e.Thing; a.A_SetSize(e.Thing.default.radius,e.Thing.default.height); } } // damage numbers, combat tracking, etc. private void DoDamageHandling( WorldEvent e ) { bool spawnme = true; if ( swwm_accdamage ) { // find existing damage number (slow) for ( SWWMScoreObj d=damnums; d; d=d.next ) { if ( (d.starttic < level.maptime) || (d.acc != e.Thing) ) continue; if ( d.score-e.Damage > d.score ) d.score = int.min; else d.score -= e.Damage; spawnme = false; break; } } if ( spawnme ) SWWMScoreObj.SpawnFromHandler(self,-e.Damage,e.Thing.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+e.Thing.Height/2),ST_Damage,e.Thing); // stats if ( e.Thing.player ) { tookdamage[e.Thing.PlayerNumber()] = true; reallytookdamage[e.Thing.PlayerNumber()] = true; // does not reset on revive let s = SWWMStats.Find(e.Thing.player); if ( s ) // deathmatch telefrag-on-spawn may cause this to be null { s.AddDamageTaken(e.Damage); if ( e.Damage > s.toptaken ) s.toptaken = e.Damage; } } if ( !e.DamageSource || !e.DamageSource.player ) return; // fall dmg SWWMWhoPushedMe.SetInstigator(e.Thing,e.DamageSource); dealtdamage[e.DamageSource.PlayerNumber()] = true; let s = SWWMStats.Find(e.DamageSource.player); if ( s ) // deathmatch telefrag-on-spawn may cause this to be null { s.AddDamageDealt(e.Damage); if ( e.Damage > s.topdealt ) s.topdealt = e.Damage; } SWWMFlyTracker.Track(e.Thing,e.DamageSource); if ( e.Thing.bBOSS || e.Thing.FindInventory("BossMarker") ) { let tk = e.Thing.FindInventory("DeepImpactOnlyToken"); if ( !tk ) { tk = Inventory(Actor.Spawn("DeepImpactOnlyToken")); tk.AttachToOwner(e.Thing); tk.special1 = 0; } Inventory pb; if ( (tk.special1 != -1) && ((e.DamageType == 'Push') || (e.Inflictor && (pb = e.Inflictor.FindInventory("ParriedBuff")) && pb.bAMBUSH)) ) tk.special1 = 1; else tk.special1 = -1; } // barrel destruction if ( (e.Thing is 'ExplosiveBarrel') && (e.Thing.Health <= 0) ) SWWMUtility.AchievementProgressInc("barrel",1,e.DamageSource.player); } // combat hit chatter private void DoCombatHit( WorldEvent e ) { if ( (e.DamageSource.bISMONSTER || e.DamageSource.player || (e.DamageSource is 'ScriptedMarine')) && (e.Thing == players[consoleplayer].mo) && (e.Thing.Health > 0) ) { if ( !lastcombat || (gametic > lastcombat+20) ) { if ( e.Thing.IsFriend(e.DamageSource) ) lastcombat = AddOneliner("friendhit",1,10); else if ( (!lastcombat || (gametic > lastcombat+90)) && !Random[DemoLines](0,(e.DamageSource.bBOSS||e.DamageSource.FindInventory("BossMarker"))?1:4) && !SWWMHDoomHandler.IsCuteGirl(e.DamageSource) ) // [HDoom] don't shout at the girls lastcombat = AddOneliner("gethit",1,15); } highesttic = gametic; } // friendly fire lines only fire up if we didn't kill them right away (because then the teamkill line should take priority) if ( (e.DamageSource == players[consoleplayer].mo) && (e.Thing.bISMONSTER || e.Thing.player || (e.Thing is 'ScriptedMarine')) && (e.Thing.Health > 0) ) { // make sure it's not a moth, because otherwise they won't shut up about accidentally hurting them (it happens a lot) if ( e.Thing.IsFriend(e.DamageSource) && !(e.Thing is 'LampMoth') ) { if ( !lastcombat || (gametic > lastcombat+20) ) { lastcombat = AddOneliner("hitfriend",1,10); if ( Demolitionist(e.DamageSource) ) Demolitionist(e.DamageSource).facesad = true; } highesttic = gametic; } } } // kill scoring private void DoKillScoring( WorldEvent e ) { // fall damage tracking hack let src = e.DamageSource; if ( (e.DamageType == 'Falling') && !e.DamageSource ) src = SWWMWhoPushedMe.RecallInstigator(e.Thing); if ( (!src || !src.player || (src == e.Thing)) ) return; let inflictor = e.Inflictor; if ( inflictor is 'SWWMPuff' ) inflictor = inflictor.master; let s = SWWMStats.Find(src.player); if ( s ) { s.kills++; s.AddWeaponKill(inflictor,e.Thing,e.DamageType); } if ( src == players[consoleplayer].mo ) { highesttic = gametic; if ( !lastcombat || (gametic > lastcombat+20) ) { if ( e.Thing.IsFriend(src) ) { lastcombat = AddOneliner("friendkill",1,5); if ( Demolitionist(e.DamageSource) ) Demolitionist(e.DamageSource).facesad = true; } else if ( (!lastcombat || (gametic > lastcombat+50)) && !SWWMHDoomHandler.IsCuteGirl(e.Thing) ) // [HDoom] don't shout at the girls { int lc = 0; Inventory buff = inflictor?inflictor.FindInventory('ParriedBuff'):null; if ( !Random[DemoLines](0,3) && buff && (e.Thing is 'Cyberdemon') && (inflictor is 'Rocket') && (buff.tracer == e.Thing) ) lc = AddOneliner("cybully",1,15); else if ( !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.FindInventory("BossMarker"))?1:2) && (e.DamageType == 'CriticalConcussion') ) lc = AddOneliner("ballskill",1,15); else if ( !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.FindInventory("BossMarker"))?2:5) && (e.DamageType == 'Buttslam') ) lc = AddOneliner("asskill",1,15); else if ( !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.FindInventory("BossMarker"))?3:6) && ((inflictor is 'HeavyMahSheenGun') || (inflictor is 'SheenTrail')) ) lc = AddOneliner("sheenkill",1,15); if ( !lc ) { if ( !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.FindInventory("BossMarker"))?1:4) ) lastcombat = AddOneliner("scorekill",1,15); } else lastcombat = lc; } } } int pnum = src.PlayerNumber(); // achievement stuff if ( e.Thing.IsHostile(src) && (e.Thing.bISMONSTER || e.Thing.player) ) { if ( (e.Thing.bBOSS||e.Thing.FindInventory("BossMarker")) && ((e.DamageType == 'Dash') || (e.DamageType == 'Buttslam')) ) SWWMUtility.AchievementProgressInc("bossdash",1,src.player); if ( (inflictor is 'DeepImpact') && (e.DamageType == 'Push') ) SWWMUtility.AchievementProgressInc("sneeze",1,src.player); else if ( e.DamageType == 'Buttslam' ) SWWMUtility.AchievementProgressInc("butts",1,src.player); else if ( e.DamageType == 'Jump' ) SWWMUtility.AchievementProgressInc("stomp",1,src.player); else if ( e.DamageType == 'GroundPound' ) SWWMUtility.AchievementProgressInc("thicc",1,src.player); else if ( (e.DamageType == 'Love') && !(e.Thing is 'WolfensteinSS') && (e.Thing.Species != 'WolfensteinSS') ) SWWMUtility.AchievementProgressInc("love",1,src.player); Inventory buff = inflictor?inflictor.FindInventory('ParriedBuff'):null; if ( buff ) { SWWMUtility.AchievementProgressInc("reflect",1,src.player); if ( (e.Thing is 'Cyberdemon') && (inflictor is 'Rocket') && (buff.tracer == e.Thing) ) SWWMUtility.MarkAchievement("cybully",src.player); } Inventory tk; if ( (tk = e.Thing.FindInventory("DeepImpactOnlyToken")) && (tk.special1 == 1) ) SWWMUtility.MarkAchievement("shame",src.player); SWWMUtility.AchievementProgressInc("mega",1,src.player); if ( src.player.Health == 1 ) { onehpspree[pnum]++; SWWMUtility.AchievementProgress("onehp",onehpspree[pnum],src.player); } // tasty treats if ( swwm_demoslayer ) { if ( src.Health < 100 ) { int amt = clamp(e.Thing.SpawnHealth()/20,1,10); if ( e.Thing.Health < (e.Thing.GetGibHealth()*2) ) amt *= 3; else if ( e.Thing.Health < e.Thing.GetGibHealth() ) amt *= 2; for ( int i=0; i s.mkill) ) s.mkill = multilevel[pnum]+1; lastkill[pnum] = level.maptime; // scoring int score = min(1000,int(ceil(e.Thing.GetSpawnHealth()*.05)*10)); // skill multiplier score = int(score*G_SkillPropertyFloat(SKILLP_DamageFactor)); // player score is always the same if ( e.Thing.player ) { score = 1000; // deathmatch frag sound if ( src.player == players[consoleplayer] ) S_StartSound("misc/frag",CHAN_WEAPON,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1.,ATTN_NONE); } SWWMScoreObj scr = null; if ( src.player == players[consoleplayer] ) scr = SWWMScoreObj.SpawnFromHandler(self,score,e.Thing.Vec3Offset(0,0,e.Thing.Height/2)); int ofs = 0; if ( e.DamageType == 'Push' ) { score += 500; if ( scr ) scr.AppendXString(StringTable.Localize("$SWWM_SHAMEFUL")); } else if ( e.DamageType == 'Buttslam' ) { score += 300; if ( scr ) scr.AppendXString(StringTable.Localize("$SWWM_BUTTSLAM")); } else if ( e.DamageType == 'Love' ) { score += 600; if ( scr ) scr.AppendXString(StringTable.Localize(((e.Thing is 'WolfensteinSS')||(e.Thing.Species=='WolfensteinSS'))?"$SWWM_LOVED_ALT":"$SWWM_LOVED"),0,Font.FindFontColor('BlushPink')); } else if ( inflictor is 'FroggyChair' ) { score += 1440; if ( scr ) scr.AppendXString(StringTable.Localize("$SWWM_FROGGED"),0,Font.CR_GREEN); } Inventory pb; if ( inflictor && (pb = inflictor.FindInventory('ParriedBuff')) ) { score += 200; if ( pb.special1&1 ) score += 200; if ( scr ) scr.AppendXString(StringTable.Localize((pb.special1&1)?"$SWWM_PPARRY":"$SWWM_PARRY")); } if ( (e.Damage >= e.Thing.GetSpawnHealth()*2) || (((e.Thing.Health <= e.Thing.GetGibHealth()) || (src.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageType == 'Extreme')) && !src.bNOEXTREMEDEATH && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH)) ) { score *= 2; if ( scr ) scr.AppendXString(StringTable.Localize("$SWWM_OVERKILL")); SWWMUtility.AchievementProgressInc("gib",1,src.player); } score = int(score*(1.+.5*min(multilevel[pnum],16))); if ( (multilevel[pnum] > 0) && scr ) scr.AppendXString(StringTable.Localize("$SWWM_MULTIKILL"),(multilevel[pnum]>=16)?int.max:(multilevel[pnum]+1)); spreecount[pnum]++; if ( s && (spreecount[pnum] > s.skill) && !tookdamage[pnum] ) s.skill = spreecount[pnum]; if ( !tookdamage[pnum] ) { int spreebonus = 10*(spreecount[pnum]); // taper off after 10x (some people go really far with these, holy fuck) if ( spreecount[pnum] > 10 ) spreebonus = int(10*((spreecount[pnum]/10.)**.25)); score += 100+spreebonus; if ( (spreecount[pnum] > 0) && scr ) scr.AppendXString(StringTable.Localize("$SWWM_SPREEKILL"),spreecount[pnum]); } if ( e.Thing.bBOSS || e.Thing.FindInventory("BossMarker") ) { score += 2000; if ( scr ) scr.AppendXString(StringTable.Localize("$SWWM_BOSSKILL")); } SWWMCredits.Give(src.player,score); if ( scr ) scr.score = score; // update final score if ( !deathmatch && !(gameinfo.gametype&GAME_Hexen) && (level.killed_monsters+1 == level.total_monsters) && !allkills ) { allkills = true; SWWMCredits.Give(src.player,1000); if ( src.player == players[consoleplayer] ) Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),1000); else Console.Printf(StringTable.Localize("$SWWM_LASTMONSTERREM"),src.player.GetUserName(),1000); SWWMScoreObj.SpawnFromHandler(self,1000,src.Vec3Offset(0,0,src.Height/2)); SWWMUtility.AchievementProgressInc("allkills",1,src.player); } } override void WorldThingDamaged( WorldEvent e ) { if ( profiling ) ProfileTick(); if ( e.Damage > 0 ) DoDamageHandling(e); if ( e.DamageSource && (e.DamageSource != e.Thing) ) DoCombatHit(e); if ( (e.Thing.Health > 0) || e.Thing.bKilled || e.Thing.bCorpse ) { if ( profiling ) ProfileTock(PT_WORLDTHINGDAMAGED); return; } DoGibThing(e); // death exit hax // could be telefragging Romero, or a voodoo doll telefragging a barrel (death exits in Eviternity) if ( (e.DamageType == 'Telefrag') && e.DamageSource && e.DamageSource.player && ((e.Thing is 'BossBrain') || ((e.Thing is 'ExplosiveBarrel') && (e.DamageSource.player.mo != e.DamageSource))) ) e.DamageSource.DamageMobj(null,null,Actor.TELEFRAG_DAMAGE,'EndLevel'); if ( !e.Thing.player && !e.Thing.bIsMonster && !e.Thing.bCountKill && !(e.Thing is 'ScriptedMarine') ) { if ( profiling ) ProfileTock(PT_WORLDTHINGDAMAGED); return; } DoKillScoring(e); if ( profiling ) ProfileTock(PT_WORLDTHINGDAMAGED); } }