1.1 release:

- Hexen compatibility (Combiner Patch will be updated soon).
 - Environment Map shader fixes from Doom Tournament.
 - Buffed Stunner so it's actually useful. This goes against what the Unreal
   Bible indicated but whatever, the weapon would be useless otherwise.
 - "Superweapons" now have +ALWAYSPICKUP for consistency.
 - Sneaky Strife stuff:
   - Dispersion Pistol and Stunner have reduced alert radius.
   - Rename Peacemaker sprites to avoid conflict with peasant sprites.
This commit is contained in:
Marisa the Magician 2019-12-15 14:39:11 +01:00
commit 1207748311
16 changed files with 339 additions and 281 deletions

View file

@ -536,7 +536,7 @@ Class Automag : UnrealWeapon
{
invoker.clipout = true;
A_Overlay(-9999,null);
A_PlaySound("automag/click",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
A_PlaySound("automag/click",CHAN_ITEM,!Dampener.Active(self)?1.:.1);
}
AUTR ABCDEFGHIJKLMNOPQRSTUVWXY 1;
AUTD ABCD 1;

View file

@ -432,6 +432,7 @@ Class BigGun : UnrealWeapon
Weapon.AmmoGive 4;
Inventory.RespawnTics 2100;
+INVENTORY.IGNORESKILL;
+INVENTORY.ALWAYSPICKUP;
UTWeapon.DropAmmo 4;
BigGun.ClipCount 4;
+EXTREMEDEATH;

View file

@ -323,7 +323,7 @@ Class DispersionAmmo : Actor
action void A_DispExpl()
{
UTMainHandler.DoKnockback(tracer,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)),6000);
A_AlertMonsters();
A_AlertMonsters(gameinfo.gametype&GAME_Strife?100:0);
A_SprayDecal("RazorBlast",20);
Spawn(invoker.LightClass,pos);
Actor a;
@ -344,6 +344,12 @@ Class DispersionAmmo : Actor
UTMainHandler.DoBlast(self,80,6000);
A_Explode(GetMissileDamage(0,0),80);
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( gameinfo.gametype&GAME_Strife )
target.DaggerAlert(self.target);
return damage;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
@ -542,7 +548,7 @@ Class DispersionPistol : UnrealWeapon
A_OverlayFlags(PSP_FLASH,PSPF_RenderStyle,true);
A_OverlayRenderstyle(PSP_FLASH,STYLE_Add);
UTMainHandler.DoSwing(self,(FRandom[DPistol](-0.1,-0.3),FRandom[DPistol](-0.1,0.3)),2+invoker.upgradelevel*0.5,-0.3,3,SWING_Spring,0,3+invoker.upgradelevel);
if ( !Dampener.Active(self) ) A_AlertMonsters();
if ( !Dampener.Active(self) ) A_AlertMonsters(gameinfo.gametype&GAME_Strife?120:0);
A_QuakeEx(2,2,2,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
@ -615,7 +621,7 @@ Class DispersionPistol : UnrealWeapon
A_OverlayRenderstyle(PSP_FLASH,STYLE_Add);
double ss = 0.5+invoker.chargesize*0.3;
UTMainHandler.DoSwing(self,(FRandom[DPistol](-0.1,-0.3)*ss,FRandom[DPistol](-0.1,0.3))*ss,2+invoker.upgradelevel*0.5,-0.3,3,SWING_Spring,0,3+invoker.upgradelevel);
if ( !Dampener.Active(self) ) A_AlertMonsters();
if ( !Dampener.Active(self) ) A_AlertMonsters(gameinfo.gametype&GAME_Strife?120:0);
int qs = int(1+invoker.chargesize*0.3);
A_QuakeEx(qs,qs,qs,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
Vector3 x, y, z;

View file

@ -250,6 +250,7 @@ Class SMiniGun : UnrealWeapon
Weapon.AmmoGive 32;
Inventory.RespawnTics 2100;
+INVENTORY.IGNORESKILL;
+INVENTORY.ALWAYSPICKUP;
UTWeapon.DropAmmo 4;
}
States

View file

@ -1,90 +1,6 @@
// Backpack that only gives ammo for valid weapons
Class UnrealBackpack : BackpackItem replaces Backpack
Class UnrealBackpack : UTBackpack
{
override Inventory CreateCopy( Actor other )
{
// Find every unique type of ammoitem. Give it to the player if
// he doesn't have it already, and double its maximum capacity.
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
let type = (class<Ammo>)(AllActorClasses[i]);
if ( !type || (type.GetParentClass() != 'Ammo') ) continue;
// check that it's for a valid weapon
bool isvalid = false;
for ( int j=0; j<AllActorClasses.Size(); j++ )
{
let type2 = (class<Weapon>)(AllActorClasses[j]);
if ( !type2 ) continue;
let rep = GetReplacement(type2);
if ( (rep != type2) && !(rep is "DehackedPickup") ) continue;
readonly<Weapon> weap = GetDefaultByType(type2);
if ( !other.player || !other.player.weapons.LocateWeapon(type2) || weap.bCheatNotWeapon ) continue;
if ( (weap.AmmoType1 == type) || (weap.AmmoType2 == type) )
{
isvalid = true;
break;
}
}
if ( !isvalid ) continue;
let ammoitem = Ammo(other.FindInventory(type));
int amount = GetDefaultByType(type).BackpackAmount;
// don't give these at all
if ( (amount <= 0) && (GetDefaultByType(type).BackpackMaxAmount == GetDefaultByType(type).MaxAmount) ) continue;
// extra ammo in baby mode and nightmare mode
if ( !bIgnoreSkill ) amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
if ( amount < 0 ) amount = 0;
if ( !ammoitem )
{
// The player did not have the ammoitem. Add it.
ammoitem = Ammo(Spawn(type));
ammoitem.Amount = bDepleted?0:amount;
if ( ammoitem.BackpackMaxAmount > ammoitem.MaxAmount )
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
if ( ammoitem.Amount > ammoitem.MaxAmount )
ammoitem.Amount = ammoitem.MaxAmount;
ammoitem.AttachToOwner(other);
}
else
{
// The player had the ammoitem. Give some more.
if ( ammoitem.MaxAmount < ammoitem.BackpackMaxAmount )
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
if ( !bDepleted && (ammoitem.Amount < ammoitem.MaxAmount) )
{
ammoitem.Amount += amount;
if ( ammoitem.Amount > ammoitem.MaxAmount )
ammoitem.Amount = ammoitem.MaxAmount;
}
}
}
return Inventory.CreateCopy(other);
}
override bool HandlePickup( Inventory item )
{
// Since you already have a backpack, that means you already have every
// kind of ammo in your inventory, so we don't need to look at the
// entire PClass list to discover what kinds of ammo exist, and we don't
// have to alter the MaxAmount either.
if ( item is 'BackpackItem' )
{
for ( let probe = Owner.Inv; probe; probe = probe.Inv )
{
if ( probe.GetParentClass() != 'Ammo' ) continue;
if ( probe.Amount >= probe.MaxAmount && !sv_unlimited_pickup ) continue;
int amount = Ammo(probe).Default.BackpackAmount;
// extra ammo in baby mode and nightmare mode
if ( !bIgnoreSkill )
amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
probe.Amount += amount;
if ( (probe.Amount > probe.MaxAmount) && !sv_unlimited_pickup )
probe.Amount = probe.MaxAmount;
}
// The pickup always succeeds, even if you didn't get anything
item.bPickupGood = true;
return true;
}
return false;
}
override void DoPickupSpecial( Actor toucher )
{
Super.DoPickupSpecial(toucher);
@ -114,18 +30,6 @@ Class UnrealBackpack : BackpackItem replaces Backpack
}
}
}
Default
{
Tag "$T_BACKPACK";
Inventory.PickupMessage "$I_BACKPACK";
Inventory.RespawnTics 2100;
}
States
{
Spawn:
BPAK A -1;
Stop;
}
}
Class UTranslator : UnrealInventory

View file

@ -245,6 +245,7 @@ Class OLSMP : UnrealWeapon
UTWeapon.DropAmmo 50;
OLSMP.ClipCount 100;
+UNREALWEAPON.NOFIRSTGIVE;
+INVENTORY.ALWAYSPICKUP;
}
States
{
@ -337,7 +338,7 @@ Class OLSMP : UnrealWeapon
invoker.clipout = true;
A_Overlay(-9999,null);
A_WeaponOffset(0,32); // fix sudden psprite lowering
A_PlaySound("automag/click",CHAN_WEAPON,!Dampener.Active(self)?1.:.1,pitch:0.8);
A_PlaySound("automag/click",CHAN_ITEM,!Dampener.Active(self)?1.:.1,pitch:0.8);
}
AUTR ABCDEFGHIJKLMNOPQRSTUVWXY 1;
AUTD ABCD 1;

View file

@ -157,7 +157,7 @@ Class PeaceRocket : Actor
States
{
Spawn:
PEAR A 1
PEMR A 1
{
roll += 5.;
A_SeekTargets();
@ -340,10 +340,10 @@ Class PeaceBarrel : Actor
States
{
Spawn:
PEAM A -1;
PEMM A -1;
Stop;
Bounce:
PEAM A 0
PEMM A 0
{
if ( BlockingFloor ) A_AlignSelf();
else pitch = roll = 0;
@ -351,59 +351,59 @@ Class PeaceBarrel : Actor
}
Goto Spawn;
Death:
PEAM A 1 A_CheckFloor(1);
PEMM A 1 A_CheckFloor(1);
Wait;
PEAM A 4 A_AlignSelf();
PEAM A 35
PEMM A 4 A_AlignSelf();
PEMM A 35
{
A_PlaySound((special1<=0)?"eightball/seeklost":"eightball/seeklock",CHAN_AUTO);
A_AlertMonsters();
return A_JumpIf(--special1<0,1);
}
Wait;
PEAM A 0 A_JumpIf(bAMBUSH,"Detonate");
PEAM A 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM B 3;
PEAM C 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM D 3 A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM E 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM F 3
PEMM A 0 A_JumpIf(bAMBUSH,"Detonate");
PEMM A 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM B 3;
PEMM C 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM D 3 A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM E 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM F 3
{
A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEAM G 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEAM H 3
PEMM G 3 A_PlaySound("peace/open",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
PEMM H 3
{
A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEAM I 3;
PEAM J 3
PEMM I 3;
PEMM J 3
{
A_PlaySound("transloc/bounce",CHAN_AUTO,.8,pitch:FRandom[Peace](0.8,1.2));
A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
}
PEAM K 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEAM L 3 A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
PEAM M 3;
PEAM N 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEAM OPQ 3;
PEAM R 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEAM STU 3;
PEAM V 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEAM XYZ[\] 3;
PEAM ] 35;
PEAM ] 0 A_FireRocket(0);
PEAL A 20;
PEAL A 0 A_FireRocket(1);
PEAL B 20;
PEAL B 0 A_FireRocket(2);
PEAL C 20;
PEAL C 0 A_FireRocket(3);
PEAL D 20;
PEMM K 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEMM L 3 A_PlaySound("transloc/bounce",CHAN_AUTO,.5,pitch:FRandom[Peace](0.8,1.2));
PEMM M 3;
PEMM N 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEMM OPQ 3;
PEMM R 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEMM STU 3;
PEMM V 3 A_PlaySound("eightball/rotate",CHAN_AUTO,.1);
PEMM XYZ[\] 3;
PEMM ] 35;
PEMM ] 0 A_FireRocket(0);
PEML A 20;
PEML A 0 A_FireRocket(1);
PEML B 20;
PEML B 0 A_FireRocket(2);
PEML C 20;
PEML C 0 A_FireRocket(3);
PEML D 20;
Detonate:
PEAM A 20;
PEMM A 20;
BlowUp:
TNT1 A 0 A_BlowUp();
SSMX ABCDEFGHIJ 2 Bright;
@ -492,19 +492,19 @@ Class Peacemaker : UnrealWeapon
States
{
Spawn:
PEAP A -1;
PEMP A -1;
Stop;
PEAP B -1;
PEMP B -1;
Stop;
Select:
PEAS A 1 A_Raise(int.max);
PEMS A 1 A_Raise(int.max);
Wait;
Ready:
PEAS ABCDEFGHIJ 2 A_WeaponReady(WRF_NOFIRE);
PEAS K 0 A_PlaySound("peace/up",CHAN_ITEM,.4);
PEAS KLMNOPQRST 2 A_WeaponReady(WRF_NOFIRE);
PEMS ABCDEFGHIJ 2 A_WeaponReady(WRF_NOFIRE);
PEMS K 0 A_PlaySound("peace/up",CHAN_ITEM,.4);
PEMS KLMNOPQRST 2 A_WeaponReady(WRF_NOFIRE);
Idle:
PEAI A 1
PEMI A 1
{
A_CheckReload();
A_WeaponReady();
@ -522,45 +522,45 @@ Class Peacemaker : UnrealWeapon
}
Wait;
Fire:
PEAC A 1 A_StartCount();
PEAC # 1 A_CountUp(1);
PEMC A 1 A_StartCount();
PEMC # 1 A_CountUp(1);
Wait;
PEAF ABCD 2;
PEAF E 0
PEMF ABCD 2;
PEMF E 0
{
A_PlaySound("peace/down",CHAN_ITEM,.4);
UTMainHandler.DoSwing(self,(FRandom[Peace](-0.1,-0.04),FRandom[Peace](0.4,0.6)),3,0,7,SWING_Spring,3,0.8);
}
PEAF EFG 2;
PEAF H 0
PEMF EFG 2;
PEMF H 0
{
UTMainHandler.DoSwing(self,(FRandom[Peace](0.08,0.12),FRandom[Peace](-1.2,-0.9)),4,0,6,SWING_Spring,3,1.5);
}
PEAF HI 2; // hello
PEAF I -1 A_PeacemakerThrow();
PEMF HI 2; // hello
PEMF I -1 A_PeacemakerThrow();
Stop;
AltFire:
PEAC A 1 A_StartCount();
PEAC # 1 A_CountUp(1);
PEMC A 1 A_StartCount();
PEMC # 1 A_CountUp(1);
Wait;
PEAF ABCD 2;
PEAF E 0
PEMF ABCD 2;
PEMF E 0
{
A_PlaySound("peace/down",CHAN_ITEM,.4);
UTMainHandler.DoSwing(self,(FRandom[Peace](-0.1,-0.04),FRandom[Peace](0.4,0.6)),3,0,7,SWING_Spring,3,0.8);
}
PEAF EFG 2;
PEAF H 0
PEMF EFG 2;
PEMF H 0
{
UTMainHandler.DoSwing(self,(FRandom[Peace](0.08,0.12),FRandom[Peace](-1.2,-0.9)),4,0,6,SWING_Spring,3,1.5);
}
PEAF HI 2; // howdy
PEAF I -1 A_PeacemakerThrow(true);
PEMF HI 2; // howdy
PEMF I -1 A_PeacemakerThrow(true);
Stop;
Deselect:
PEAD A 0 A_JumpIfNoAmmo("EmptyDeselect");
PEAD ABCDEFGHI 1;
PEAD J 1 A_Lower(int.max);
PEMD A 0 A_JumpIfNoAmmo("EmptyDeselect");
PEMD ABCDEFGHI 1;
PEMD J 1 A_Lower(int.max);
EmptyDeselect:
TNT1 A 1 A_Lower(int.max);
Wait;

View file

@ -167,7 +167,7 @@ Class StunProj : Actor
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,false);
StunExplode();
Actor a = t.Results.HitActor;
a.DamageMobj(self,target,max(1,int(4*specialf1)),'jolted',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
a.DamageMobj(self,target,max(1,int(10*specialf1)),'jolted',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
if ( !a.bDONTTHRUST )
{
UTMainHandler.DoKnockback(a,t.Results.HitVector,(bAMBUSH?-22000:26000)*specialf1);
@ -208,10 +208,9 @@ Class StunProj : Actor
{
moving = false;
SetStateLabel("Death");
A_Explode(int(0.6*specialf1),50);
A_QuakeEx(1,1,1,3,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollintensity:0.2);
A_PlaySound("stun/hit",CHAN_VOICE,pitch:FRandom[Stunner](1.5,1.9)-0.08*specialf1);
UTMainHandler.DoBlast(self,50,(bAMBUSH?-7000:11000)*specialf1);
A_AlertMonsters(gameinfo.gametype&GAME_Strife?100:0);
Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
int numpt = Random[ExploS](10,15);
for ( int i=0; i<numpt; i++ )
@ -223,6 +222,12 @@ Class StunProj : Actor
s.vel = pvel;
}
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( gameinfo.gametype&GAME_Strife )
target.DaggerAlert(self.target);
return damage;
}
Default
{
Obituary "$O_STUNNER";
@ -237,6 +242,7 @@ Class StunProj : Actor
+NODAMAGETHRUST;
+NOTELEPORT;
+FORCEXYBILLBOARD;
+NOEXTREMEDEATH;
}
States
{
@ -368,7 +374,7 @@ Class Stunner : UnrealWeapon
LineTrace(angle,60,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
if ( d.HitType == TRACE_HitActor )
{
int dmg = int(5*invoker.chargesize);
int dmg = int(12*invoker.chargesize);
if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.81) )
dmg = d.HitActor.DamageMobj(invoker,self,dmg*2,'Decapitated',DMG_THRUSTLESS);
else dmg = d.HitActor.DamageMobj(invoker,self,dmg,'impact',DMG_THRUSTLESS);
@ -405,7 +411,7 @@ Class Stunner : UnrealWeapon
A_OverlayFlags(-2,PSPF_RenderStyle,true);
A_OverlayRenderStyle(-2,STYLE_Add);
StunnerAmmo(weap.Ammo1).rechargephase = 0;
if ( !Dampener.Active(self) ) A_AlertMonsters();
if ( !Dampener.Active(self) && !(gameinfo.gametype&GAME_Strife) ) A_AlertMonsters();
}
action State A_ChargeUp()
{
@ -416,7 +422,7 @@ Class Stunner : UnrealWeapon
StunnerAmmo(weap.Ammo1).rechargephase = 0;
UTMainHandler.DoSwing(self,(FRandom[Stunner](-1,1),FRandom[Stunner](-1,1)),0.02*invoker.chargesize,0,2,SWING_Spring);
A_WeaponOffset(FRandom[Stunner](-1,1)*1.2*invoker.chargesize,32+FRandom[Stunner](-1,1)*1.2*invoker.chargesize);
if ( !Dampener.Active(self) ) A_AlertMonsters();
if ( !Dampener.Active(self) && !(gameinfo.gametype&GAME_Strife) ) A_AlertMonsters();
if ( invoker.chargesize >= 5. )
{
invoker.count += 1./35.;
@ -451,6 +457,7 @@ Class Stunner : UnrealWeapon
Weapon.AmmoGive 50;
UTWeapon.DropAmmo 50;
+WEAPON.WIMPY_WEAPON;
+NOEXTREMEDEATH;
}
States
{

View file

@ -682,7 +682,8 @@ Class UnrealInventory : Inventory
Super.AttachToOwner(other);
if ( !Charge ) Charge = DefaultCharge;
// it's annoying to set this per-subclass
InterHubAmount = bUNLIMITEDCOPIES?int.max:MaxAmount;
if ( !(gameinfo.gametype&GAME_Hexen) )
InterHubAmount = bUNLIMITEDCOPIES?int.max:MaxAmount;
}
override bool HandlePickup( Inventory item )
{
@ -950,6 +951,52 @@ Class UNothing : Actor
}
}
Class HexenEitherOrSession : Thinker
{
Array<Class<Actor> > done;
private bool IsAvailable( Class<Actor> item )
{
let ti = ThinkerIterator.Create(item);
Actor a;
while ( a = Actor(ti.Next()) ) return true;
for ( int i=0; i<done.Size(); i++ ) if ( done[i] == item ) return true;
return false;
}
void MarkDone( Class<Actor> item )
{
for ( int i=0; i<done.Size(); i++ ) if ( done[i] == item ) return;
done.Push(item);
}
void MarkUnDone( Class<Actor> item )
{
for ( int i=0; i<done.Size(); i++ )
{
if ( done[i] != item ) continue;
done.Delete(i);
i--;
}
}
Class<Actor> EitherOr( Class<Actor> a, Class<Actor> b, bool allowed = true )
{
if ( !allowed ) return a;
if ( IsAvailable(a) )
{
MarkDone(a);
if ( IsAvailable(b) )
{
MarkDone(b);
if ( Random[Replacements](0,1) ) return b;
return a;
}
return b;
}
return a;
}
}
Class UnrealMainHandler : EventHandler
{
Array<AmmoUsedInSlot> AmmoSlots;
@ -971,6 +1018,25 @@ Class UnrealMainHandler : EventHandler
break;
}
}
private bool IsAvailable( Class<Actor> item )
{
let ti = ThinkerIterator.Create(item);
Actor a;
while ( a = Actor(ti.Next()) ) return true;
return false;
}
private Class<Actor> EitherOr( Class<Actor> a, Class<Actor> b, bool allowed = true )
{
let ti = ThinkerIterator.Create("HexenEitherOrSession",Thinker.STAT_STATIC);
HexenEitherOrSession hs = HexenEitherOrSession(ti.Next());
if ( !hs )
{
hs = new("HexenEitherOrSession");
hs.ChangeStatNum(Thinker.STAT_STATIC);
hs.done.Clear();
}
return hs.EitherOr(a,b,allowed);
}
override void CheckReplacement( ReplaceEvent e )
{
if ( e.IsFinal ) return;
@ -1140,16 +1206,16 @@ Class UnrealMainHandler : EventHandler
else if ( Random[Replacements](0,1) ) e.Replacement = 'UBioAmmo';
else e.Replacement = 'URifleAmmo';
}
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') ) e.Replacement = 'PowerShield';
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') || (e.Replacee == 'ArtiInvulnerability2') ) e.Replacement = 'PowerShield';
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') )
{
if ( sting_msentry && !Random[Replacements](0,9) ) e.Replacement = 'SentryItem';
else if ( ((sting_proto && sting_dubious) || sting_olsmp) && !Random[Replacements](0,2) ) e.Replacement = 'WeaponPowerUp';
else e.Replacement = 'Amplifier';
}
else if ( e.Replacee == 'ArtiEgg' ) e.Replacement = 'VoiceBox';
else if ( (e.Replacee == 'ArtiEgg') || (e.Replacee == 'ArtiPork') ) e.Replacement = 'VoiceBox';
else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') ) e.Replacement = 'SuperHealth';
else if ( e.Replacee == 'Megasphere' ) e.Replacement = 'ShieldBelt';
else if ( (e.Replacee == 'Megasphere') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'ShieldBelt';
else if ( (e.Replacee == 'Allmap') || (e.Replacee == 'SuperMap') )
{
if ( sting_proto && Random[Replacements](0,2) ) e.Replacement = 'MotionDetector';
@ -1158,16 +1224,18 @@ Class UnrealMainHandler : EventHandler
else if ( (e.Replacee == 'BlurSphere') || (e.Replacee == 'ArtiInvisibility') ) e.Replacement = 'UInvisibility';
else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') ) e.Replacement = 'UFlashlight';
else if ( e.Replacee == 'RadSuit' ) e.Replacement = 'UJumpBoots';
else if ( e.Replacee == 'ArtiFly' ) e.Replacement = 'UJumpBoots';
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') ) e.Replacement = 'UnrealBackpack';
else if ( (e.Replacee == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') )
else if ( (e.Replacee == 'ArtiFly') || (e.Replacee == 'ArtiSpeedBoots') ) e.Replacement = 'UJumpBoots';
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') || (e.Replacee == 'ArtiHealingRadius') ) e.Replacement = 'UnrealBackpack';
else if ( (e.Replacee == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') || (e.Replacee is 'ArtiPoisonBag') || (e.Replacee is 'ArtiBlastRadius') )
{
if ( sting_abonus && Random[Replacements](0,3) ) e.Replacement = 'UArmorBonus';
else e.Replacement = 'Flare';
}
else if ( (e.Replacee == 'HealthBonus') || (e.Replacee == 'CrystalVial') ) e.Replacement = 'Bandages';
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'Silvershield') ) e.Replacement = 'KevlarSuit';
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'UArmor';
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'Silvershield') || (e.Replacee == 'PlatinumHelm') ) e.Replacement = 'KevlarSuit';
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'EnchantedShield') || (e.Replacee == 'MeshArmor') ) e.Replacement = 'UArmor';
else if ( e.Replacee == 'AmuletOfWarding' ) e.Replacement = 'AsbestosSuit';
else if ( e.Replacee == 'FalconShield' ) e.Replacement = 'ToxinSuit';
else if ( (e.Replacee == 'Stimpack') || (e.Replacee == 'ArtiHealth') )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'UHealth';
@ -1175,7 +1243,7 @@ Class UnrealMainHandler : EventHandler
else e.Replacement = 'Seeds';
}
else if ( e.Replacee == 'Medikit' ) e.Replacement = 'UHealth';
else if ( e.Replacee == 'ArtiTeleport' )
else if ( (e.Replacee == 'ArtiTeleport') || (e.Replacee == 'ArtiTeleportOther') || (e.Replacee == 'ArtiDarkServant') )
{
// I have no idea what to replace this with, so just have some random stuff
switch( Random[Replacements](0,sting_proto?7:5) )
@ -1207,6 +1275,40 @@ Class UnrealMainHandler : EventHandler
}
}
else if ( e.Replacee == 'TeleportFog' ) e.Replacement = 'UTeleportFog';
// Doomreal's weapon progression for Hexen is a bit more... involved when it comes to including proto content
else if ( (e.Replacee == 'FWeapFist') || (e.Replacee == 'CWeapMace') || (e.Replacee == 'MWeapWand') )
e.Replacement = 'DispersionPistol';
else if ( e.Replacee == 'FWeapAxe' ) e.Replacement = EitherOr('Automag','Betamag',sting_proto);
else if ( e.Replacee == 'CWeapStaff' ) e.Replacement = EitherOr('Stinger','Quadshot',sting_proto);
else if ( e.Replacee == 'MWeapFrost' ) e.Replacement = EitherOr('ASMD','Stunner',sting_proto);
else if ( (e.Replacee == 'FWeaponPiece3') || (e.Replacee == 'FWeapQuietus') || (e.Replacee.GetClassName() == 'mkFullQuietus') ) e.Replacement = 'Eightball';
else if ( e.Replacee == 'CWeaponPiece3' ) e.Replacement = 'WeaponPowerUp';
else if ( e.Replacee == 'MWeaponPiece3' ) e.Replacement = EitherOr('Automag','Betamag',sting_proto);
else if ( e.Replacee == 'FWeapHammer' ) e.Replacement = EitherOr('UFlakCannon','FlameGun',sting_proto);
else if ( e.Replacee == 'CWeapFlame' ) e.Replacement = EitherOr('Razorjack','UFlamethrower',sting_proto);
else if ( e.Replacee == 'MWeapLightning' ) e.Replacement = EitherOr('UBioRifle','Impaler',sting_proto);
else if ( e.Replacee == 'FWeaponPiece2' )
{
if ( sting_proto && sting_dubious ) e.Replacement = 'Bonesaw';
else e.Replacement = 'WeaponPowerUp';
}
else if ( (e.Replacee == 'CWeaponPiece2') || (e.Replacee == 'CWeapWraithverge') || (e.Replacee.GetClassName() == 'mkFullWraithverge') ) e.Replacement = 'URifle';
else if ( e.Replacee == 'MWeaponPiece2' ) e.Replacement = 'WeaponPowerUp';
else if ( e.Replacee == 'FWeaponPiece1' )
{
if ( sting_proto && sting_dubious ) e.Replacement = 'BigGun';
else e.Replacement = 'UnrealBackpack';
}
else if ( e.Replacee == 'CWeaponPiece1' )
{
if ( sting_proto && sting_dubious ) e.Replacement = 'SMiniGun';
else e.Replacement = 'UnrealBackpack';
}
else if ( (e.Replacee == 'MWeaponPiece1') || (e.Replacee == 'MWeapBloodscourge') || (e.Replacee.GetClassName() == 'mkFullBloodscourge') )
{
if ( sting_olsmp ) e.Replacement = 'OLSMP';
else e.Replacement = 'UnrealBackpack';
}
// replace UT items (prevents them from being cheated in)
else if ( e.Replacee is 'ImpactHammer' ) e.Replacement = 'DispersionPistol';
else if ( e.Replacee is 'Translocator' ) e.Replacement = 'UTranslocator';
@ -1252,7 +1354,7 @@ Class UnrealMainHandler : EventHandler
else if ( e.Replacee is 'UTHealthPack' ) e.Replacement = 'SuperHealth';
else if ( e.Replacee is 'UTHealthBonus' ) e.Replacement = 'Bandages';
else if ( e.Replacee is 'UTJumpBoots' ) e.Replacement = 'UJumpBoots';
else if ( e.Replacee is 'UTActivatable' ) e.Replacement = 'UNothing';
else if ( (e.Replacee is 'UTActivatable') && (!(e.Replacee is 'ActUTFullAmmoBox') || !(gameinfo.gametype&GAME_Hexen)) ) e.Replacement = 'UNothing';
else if ( e.Replacee is 'UTActivatableHealth' ) e.Replacement = 'UNothing';
}

View file

@ -593,7 +593,39 @@ Class UnrealHUD : BaseStatusBar
private void DrawKeys( double x, double y, bool leftright = false )
{
if ( deathmatch ) return; // no need to draw in DM
if ( gameinfo.gametype&(GAME_Hexen|GAME_Strife) ) return; // no key display for these ATM (will do eventually)
if ( gameinfo.gametype&(GAME_Hexen|GAME_Strife) )
{
if ( !automapactive ) return;
int kw = (gameinfo.gametype&GAME_Strife)?20:30,
kh = (gameinfo.gametype&GAME_Strife)?20:40;
int nkeys = 0;
Array<int> rows;
Array<Inventory> keys;
keys.Clear();
rows.Clear();
rows.Push(0);
for ( Inventory i=CPlayer.mo.inv; i; i=i.inv )
{
if ( !(i is 'Key') ) continue;
keys.Push(i);
if ( rows[rows.Size()-1] >= 6 ) rows.Push(1);
else rows[rows.Size()-1]++;
}
int j = 0;
CurX = (ClipX-kw);
for ( int i=0; i<rows.Size(); i++ )
{
CurY = (ClipY-rows[i]*kh)*0.5;
for ( int k=0; k<rows[i]; k++ )
{
Screen.DrawTexture(keys[j].Icon,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
j++;
CurY += kh;
}
CurX -= kw;
}
return;
}
CurX = x;
CurY = y;
int cnt = 0;
@ -768,10 +800,14 @@ Class UnrealHUD : BaseStatusBar
DrawString(mOldDigitsSmall,FormatNumber(sec,3),(633,378),DI_TEXT_ALIGN_RIGHT);
if ( sec2 != -1 )
DrawString(mOldDigitsSmall,FormatNumber(sec2,3),(556,378),DI_TEXT_ALIGN_LEFT);
for ( int i=0; i<6; i++ )
if ( gameinfo.gametype&(GAME_Hexen|GAME_Strife) ) DrawKeys(0,0);
else
{
if ( !CPlayer.mo.CheckKeys(i+1,false,true) ) continue;
DrawImage(OldKeys[((i==0)&&(gameinfo.gametype&GAME_Heretic))?6:i],(keyofs[i],366),DI_ITEM_OFFSETS);
for ( int i=0; i<6; i++ )
{
if ( !CPlayer.mo.CheckKeys(i+1,false,true) ) continue;
DrawImage(OldKeys[((i==0)&&(gameinfo.gametype&GAME_Heretic))?6:i],(keyofs[i],366),DI_ITEM_OFFSETS);
}
}
if ( HudMode > 5 ) return;
// Draw frags in DM