[Logo]
 
  [Search] Search   [Recent Topics] Recent Topics   [Members]  Member Listing   [Groups] Back to home page 
[Register] Register / 
[Login] Login 
Denial & Ghost Issues  XML
Forum Index -> Druids RPG
Author Message
Wail

Rampage

Joined: 09/20/2007 21:14:41
Messages: 183
Offline

Continuing from over in this thread...

I've made a modified DruidNoWeaponDrop class for the Monster Mash server which is based on the Druids214 DruidNoWeaponDrop class. Our server is still running Druids200, but because of frequent glitching behavior (stacking multiple copies of the starting weapon) with the Druids200 version of Denial I decided it was necessary to roll in the fixes introduced in later versions.

However, since introducing the new version of the Denial ability I have been getting reports of unusual behavior related to Ghost.

Example:

Character 1 has two copies of a weapon. One he picked up from a weapon pickup, and another that he picked up from Character 2, who left the server. Lets say he's got a freezing and a poison weapon. Now Character 1 ghosts, and when he returns to play he now only has one copy of that weapon, and it's vampiric.

I have heard several reports of this behavior since rolling in the new version of Denial, but I am perplexed because I don't see how Denial can be affecting the behavior of Ghost.


For references' sake, the current version of Denial we're running looks like...
Code:
class Ability_DWDenial extends RPGAbility
 	abstract
 	config(DWRPG);
 
 var config int Level1Cost, Level2Cost, Level3Cost;
 
 static simulated function int Cost(RPGPlayerDataObject Data, int CurrentLevel)
 {
    local int i;
 	 local int MyReturnValue;
 	 local bool bOK;
 
 	 for (i = 0; i < Data.Abilities.length; i++)
 		   if (Data.Abilities[i] == class'ClassAdrenalineMaster' || Data.Abilities[i] == class'ClassWeaponsMaster')
 	 bOK = true;
 
 	 if (Data.Level < 25)
 		  return 0;
    if (CurrentLevel == 0)
 		  MyReturnValue = default.Level1Cost;
 	 if (CurrentLevel == 1)
 		  MyReturnValue = default.Level2Cost;
 	 if (CurrentLevel == 2)
 	 {
 		  for (i = 0; i < Data.Abilities.length; i++)
 			    if (Data.Abilities[i] == class'ClassAdrenalineMaster')
 				     MyReturnValue = default.Level3Cost;
 	 }
 	 if (MyReturnValue > 0)
 	 {
 		  if (!bOK)
 		  {
 			   if (CurrentLevel > 0)
 				    log("Warning:"@data.Name@"has"@default.class@"Level"@CurrentLevel@"but does not have an associated Class to allow them to purchase it");
 			   return 0;
 		  }
 		  else
 			   return MyReturnValue;
 	 }
 	 return 0;
 }
 
 static function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> DamageType, vector HitLocation, int AbilityLevel, bool bAlreadyPrevented)
 {
 	 local DruidOldWeaponHolder OldWeaponHolder;
 	 local Inventory inv;
 	 local int x;
 	 local Array<Weapon> Weapons;
 
 	 if (Killed.isA('Vehicle'))
 	 {
 		  Killed = Vehicle(Killed).Driver;
 	 }
    // Wierdness - looks like sometimes PD called twice, particularly in VINV?
    // Killed can become "None" somewhere along the line.
 	 if (Killed == None)
 	 {
 		  return false;
 	 }
 
 	 if (Killed.Controller == Killer)
 		  return false;
 
 	 if (DamageType == class'Suicided')
 		  return false;
 
 	 if (Killed.Controller != None && Killed.Weapon != None)
 	 {
 		  if (RPGWeapon(Killed.Weapon) != None)
 			   Killed.Controller.LastPawnWeapon = RPGWeapon(Killed.Weapon).ModifiedWeapon.Class;
 		  else
 			   Killed.Controller.LastPawnWeapon = Killed.Weapon.Class;
 	 }
 
 	 if (AbilityLevel == 2)
 	 {
 		  if (Killed.Weapon != None)
 		  {
 			   OldWeaponHolder = Killed.spawn(class'DruidOldWeaponHolder',Killed.Controller);
 			   storeOldWeapon(Killed, Killed.Weapon, OldWeaponHolder);
 		  }
 	 }
 	 else if (AbilityLevel == 3)
 	 {
 		  for (Inv = Killed.Inventory; Inv != None; Inv = Inv.Inventory)
 			    if (Weapon(Inv) != None)
 				     Weapons[Weapons.length] = Weapon(Inv);
 
 		  OldWeaponHolder = Killed.spawn(class'DruidOldWeaponHolder',Killed.Controller);
 
 		  for (x = 0; x < Weapons.length; x++)
 			    storeOldWeapon(Killed, Weapons[x], OldWeaponHolder);
 	 }
 
 	 Killed.Weapon = None;
 
 	 return false;
 }
 
 static function storeOldWeapon(Pawn Killed, Weapon Weapon, DruidOldWeaponHolder OldWeaponHolder)
 {
    local DruidOldWeaponHolder.WeaponHolder holder;
 
 	 if (Weapon == None)
 		  return;
 
 	 if (RPGWeapon(Weapon) != None)
 	 {
 		  if (instr(caps(string(RPGWeapon(Weapon).ModifiedWeapon.class)), "TRANSLAUNCHER") > -1)
 			   return;
 	 }
 	 else
 	 {
 		  if (instr(caps(string(Weapon.class)), "TRANSLAUNCHER") > -1)
 			   return;
 	 }
 
 	 Weapon.DetachFromPawn(Killed);
 	 holder.Weapon = Weapon;
 	 holder.AmmoAmounts1 = Weapon.AmmoAmount(0);
 	 holder.AmmoAmounts2 = Weapon.AmmoAmount(1);
 
 	 OldWeaponHolder.WeaponHolders[OldWeaponHolder.WeaponHolders.length] = holder;
 
 	 Killed.DeleteInventory(holder.Weapon);
 	 //this forces the weapon to stay relevant to the player who will soon reclaim it
 	 holder.Weapon.SetOwner(Killed.Controller);
 	 if (RPGWeapon(holder.Weapon) != None)
 		  RPGWeapon(holder.Weapon).ModifiedWeapon.SetOwner(Killed.Controller);
 }
 
 static simulated function ModifyPawn(Pawn Other, int AbilityLevel)
 {
 	 local DruidOldWeaponHolder OldWeaponHolder;
 	 local DruidOldWeaponHolder.WeaponHolder Holder;
 	 local Inventory OInv;
 	 local Inventory SG;
 	 //local Inventory AR;
    local Inventory MP4;
 	 local Inventory MP5;
 
 	 local bool bOK;
 
 	 if (Other.Role != ROLE_Authority || AbilityLevel < 2)
 		  return;
 
 	 foreach Other.DynamicActors(class'DruidOldWeaponHolder', OldWeaponHolder)
 	    if (OldWeaponHolder.Owner == Other.Controller)
 		  {
 			   while (OldWeaponHolder.WeaponHolders.length > 0)
 			   {
 				    Holder = oldWeaponHolder.WeaponHolders[0];
 				    if (Holder.Weapon != None)
 				    {
 					     if (instr(caps(Holder.Weapon.ItemName), "SHIELD GUN") > -1 || instr(caps(Holder.Weapon.ItemName), "MP4") > -1 || instr(caps(Holder.Weapon.ItemName), "MP5") > -1 )  //instr(caps(Holder.Weapon.ItemName), "ASSAULT RIFLE") > -1 ||
 					     {
 
                  // Go ahead and find them both in the Other's inventory.  This way if we end up
                  // having to do them both, we'll only have to do the loop once. However, we use
                  // a bool instead of the double check (see DruidLoaded) as we'd end up making
                  // SG or AR None again when we destroy the first one and doing the loop again.
                  for (OInv=Other.Inventory ; OInv != None && !bok ; OInv=OInv.Inventory)
                  {
   	                if (instr(caps(OInv.ItemName), "SHIELD GUN") > -1)
   		                 SG=OInv;
   	                //if (instr(caps(OInv.ItemName), "ASSAULT RIFLE") > -1)
   		              //   AR=OInv;
                     if (instr(caps(OInv.ItemName), "MP4") > -1)
   		                 MP4=OInv;
   	                if (instr(caps(OInv.ItemName), "MP5") > -1)
   	                   MP5=OInv;
   	                if (SG != None && MP4 != None && MP5 != None) //&& AR != None
   	                   bOK = true;
                  }
 
                  if (instr(caps(Holder.Weapon.ItemName), "SHIELD GUN") > -1 && SG != None)
                     Other.DeleteInventory(SG);
                  //if (instr(caps(Holder.Weapon.ItemName), "ASSAULT RIFLE") > -1 && AR != None)
                  //   Other.DeleteInventory(AR);
                  if (instr(caps(Holder.Weapon.ItemName), "MP4") > -1 && MP4 != None)
                     Other.DeleteInventory(MP4);
                  if (instr(caps(Holder.Weapon.ItemName), "MP5") > -1 && MP5 != None)
                     Other.DeleteInventory(MP5);
 					     }
 
 					  Holder.Weapon.GiveTo(Other); //somehow it can be destroyed.
 					  if (Holder.Weapon == None)
 						   Continue;
 					  Holder.Weapon.AddAmmo (Holder.AmmoAmounts1 - Holder.Weapon.AmmoAmount(0),0);
 					  Holder.Weapon.AddAmmo	(Holder.AmmoAmounts2 - Holder.Weapon.AmmoAmount(1),1);
 				    }
 
 				OldWeaponHolder.WeaponHolders.remove(0, 1);
 			  }
 
 			OldWeaponHolder.Destroy();
 			return;
 		}
 }
 
 defaultproperties
 {
      Level1Cost=15
      Level2Cost=20
      Level3Cost=20
      AbilityName="Denial"
      Description="The first level of this ability prevents you from dropping a weapon when you die.|The second level allows you to respawn with the weapon and ammo you were using when you died.|If you are an Adrenaline Master you may buy Level 3 of this ability, which will save all your weapons when you die.|You need to be at least Level 25 to purchase this ability. (Max Level: 2 or 3)|This ability does not trigger for self-inflicted death.|You must be an Adrenaline Master or a Weapons Master to purchase this skill.|Cost (per level): 15,20,20"
      MaxLevel=3
 }
 


The only differences of note being
-Instead of checking for the Assault Rifle we check for weapons named the MP4 or MP5 (due to a weapon replacement mutator we run for the assault rifle)
-The class extends RPGAbility (instead of RPGDeathAbility)
-Currently we're using PreventDeath instead of GenuineDeath (since we're not extending RPGDeathAbility)

Any ideas?
Szlat

Wicked Sick!

Joined: 05/18/2005 18:32:41
Messages: 2124
Location: UK
Offline

BotFodder has looked into this code in a lot greater detail than I have, so do not treat me as an authority on this.

I think when BotFodder did the changes to fix Denial, at the same time other changes were made by BotFodder and/or Druid to the Ghost ability, and the whole dying execution sequence - including adding DruidRPGGameRules and modifying DruidLoaded. The RPGDeathAbility class was introduced to get around all sorts of problems with classes getting executed in the wrong order as you die.

I am not sure that just taking the Denial bit will get around all the other problems.

So, it is probably related to ModifyPawn on DruidLoaded or Ghost getting called out of sequence. It might even depend on what order the player bought Ghost and Denial. Sorry, no ideas.
Wail

Rampage

Joined: 09/20/2007 21:14:41
Messages: 183
Offline

Thanks Szlat, that actually was pretty helpful to know. I guess that means this is going to be a more extensive change than I had hoped, but at least this isn't an unprecedented thing. Hopefully BotFodder can chime in with some more info.
Szlat

Wicked Sick!

Joined: 05/18/2005 18:32:41
Messages: 2124
Location: UK
Offline

Looking again at the thread you linked to, Roadkill says that he has experienced the merge problem on DC earlier this month.
This means that the bug is still in the latest DruidsRPG code. So it is not something you have introduced by copying BotFodder's denial code, it was probably already there, and is still there in the latest version.
Wail

Rampage

Joined: 09/20/2007 21:14:41
Messages: 183
Offline

Well, the merge issue is not really related (IMO) except insofar as bugs in the Druids200 versions of abilities result in players receiving additional copies of weapons on a regular basis.

Investigating why two of the same weapon may "merge" if you use the Magic Weapon Maker on one is something that may be worth looking into in the future, but it's only become a common complaint due to the frequency with which multiple copies of a weapon are occurring (erroneously). If it's only happening to one person every few maps, rather than 5 or more Adren Masters every map, it puts the problem into a totally different perspective.
 
Forum Index -> Druids RPG
Go to: