First, a message: There is a time and a place for everything, and understanding what is and is not appropriate is a fundamental aspect of how one should behave in society. I must take steps in correcting my behavior, how I act both through my interactions with others and through my own creations as well. While this is only one step in a very, very long road, it is hopefully a step in the right direction. Various aspects of the story and lore, dialogues, character interactions, etc. have been sanitized to be less explicit. I cannot in good conscience have something like this in a project I'm creating, especially one with such a broad audience as the one it has garnered. A couple other things have been removed, such as direct references to problematic media, and I've decided to forego the H-Doom compatibility that was added "as a joke". These changes will also be later applied to the side mods as well. Should I have still missed anything, I please ask that people notify me and I will address it as soon as I possibly can. Furthermore, if any of the people still credited in this mod wish to have their name and anything they contributed removed from it, I will do so.
344 lines
14 KiB
Text
344 lines
14 KiB
Text
// 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 )
|
|
{
|
|
SWWMDamNum.SpawnFromHandler(self,e.Damage,level.Vec3Offset(e.Thing.pos,SWWMUtility.Vec3FromAngles(FRandom[ScoreBits](0,360),FRandom[ScoreBits](-90,90))*8.+(0,0,e.Thing.Height/2)),e.DamageType);
|
|
// combat tracker updates if either an ally of the player is hit, or an ally hit this enemy
|
|
// (this automatically also does the same for the player itself, of course)
|
|
for ( int i=0; i<MAXPLAYERS; i++ )
|
|
{
|
|
if ( !playeringame[i] || !players[i].mo ) continue;
|
|
if ( players[i].mo.IsFriend(e.Thing) || (e.DamageSource && players[i].mo.IsFriend(e.DamageSource)) )
|
|
SWWMQuickCombatTracker.Update(self,players[i],e.Thing,e.Damage);
|
|
}
|
|
// 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 tracking
|
|
if ( !e.Thing.player && (e.Thing.bFALLDAMAGE || level.monsterfallingdamage) )
|
|
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 is 'SWWMVoodooDoll') || (e.Thing is 'SWWMVoodooDoll') ) return;
|
|
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) )
|
|
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 )
|
|
{
|
|
let inst = SWWMWhoPushedMe.RecallInstigator(e.Thing);
|
|
if ( inst ) src = inst;
|
|
}
|
|
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) && !(e.Thing is 'SWWMVoodooDoll') )
|
|
{
|
|
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) )
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
// no credits unless it's a counted kill or marine (that isn't friendly) or another player in DM
|
|
if ( e.Thing.IsFriend(src) || (!e.Thing.default.bCountKill && !(e.Thing is 'ScriptedMarine') && !(deathmatch && e.Thing.player)) )
|
|
return;
|
|
if ( level.maptime < (lastkill[pnum]+5*GameTicRate) )
|
|
multilevel[pnum]++;
|
|
else multilevel[pnum] = 0;
|
|
if ( s && (multilevel[pnum]+1 > 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);
|
|
}
|
|
}
|