1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

UE1 - UT Keeping Weapons Despite Death

Discussion in 'Programming' started by Rajada, Aug 10, 2008.

  1. Zur

    Zur surrealistic mad cow

    Joined:
    Jul 8, 2002
    Messages:
    11,702
    Likes Received:
    4
    It may help to look at the source of monsterhunt seeing the gametype usually relays calls to these mutator functions.
     
  2. gopostal

    gopostal Active Member

    Joined:
    Jan 19, 2006
    Messages:
    848
    Likes Received:
    47
    This is from the monsterhunt.uc:

    Code:
    function ScoreKill(pawn Killer, pawn Other)
    {
    	local ScriptedPawn S;
    
    	if ( (Killer == None) || (Killer == Other) || !Other.bIsPlayer 
    		|| (Killer.PlayerReplicationInfo.Team != Other.PlayerReplicationInfo.Team) )
    		Super.ScoreKill(Killer, Other);
    
    	MonstersTotal = 0;
    
    	foreach AllActors(class'ScriptedPawn', S)
    	{
    		if (S.Health >= 1)
    			MonstersTotal ++;
    		if (S.Shadow == None)
    			SetPawnDifficulty(MonsterSkill, S);
    	}
    
    	MonsterReplicationInfo(GameReplicationInfo).Monsters = MonstersTotal;
    
    	if (Other.bIsPlayer && MonsterReplicationInfo(GameReplicationInfo).bUseLives)
    		Other.PlayerReplicationInfo.Deaths -= 1;
    
     	if(!Other.IsA('ScriptedPawn')) return;
    
    	if(Killer!=None)
     	{
        		BroadcastMessage(Killer.GetHumanName()@"killed"$Other.GetHumanName());
     	}
    
    // =========================================================================
    // Score depending on which monster type the player kills
    
    	if ( (Killer.bIsPlayer) && ( (Other.IsA('Titan')) || (Other.IsA('Queen')) || (Other.IsA('WarLord')) ) )
    		Killer.PlayerReplicationInfo.Score += 4;
    	if ( (Killer.bIsPlayer) && ( (Other.IsA('GiantGasBag')) || (Other.IsA('GiantManta')) ) )
    		Killer.PlayerReplicationInfo.Score += 3;
    	if ( (Killer.bIsPlayer) && ( (Other.IsA('SkaarjWarrior')) || (Other.IsA('MercenaryElite')) || (Other.IsA('Brute')) ) )
    		Killer.PlayerReplicationInfo.Score += 2;
    	if ( (Killer.bIsPlayer) && ( (Other.IsA('SkaarjTrooper')) || ( (Other.IsA('Mercenary')) && (!Other.IsA('MercenaryElite')) ) || (Other.IsA('Krall')) || (Other.IsA('Slith')) || ( (Other.IsA('GasBag')) && (!Other.IsA('GiantGasBag')) ) ) )
    		Killer.PlayerReplicationInfo.Score += 1;
    
    	// Lose points for killing innocent creatures. Shame ;-)
    	if ( (Killer.bIsPlayer) && ( (Other.IsA('Nali')) || (Other.IsA('Cow')) || (Other.IsA('NaliRabbit')) ) )
    		Killer.PlayerReplicationInfo.Score -= 6;
    
    	// Get 10 extra points for killing the boss!!
    
    	if (Other.IsA('ScriptedPawn'))
    		S = ScriptedPawn(Other);
    	if ( (Killer.bIsPlayer) && ( S.bIsBoss ) )
    		Killer.PlayerReplicationInfo.Score += 9;
    }
    
    function AddToTeam( int num, Pawn Other )
    {
    	local teaminfo aTeam;
    	local Pawn P;
    	local bool bSuccess;
    	local string SkinName, FaceName;
    
    	if ( Other != None )
    	{
    		aTeam = Teams[0];
    		aTeam.Size++;
    		Other.PlayerReplicationInfo.Team = 0;
    		Other.PlayerReplicationInfo.TeamName = aTeam.TeamName;
    		bSuccess = false;
    		if ( Other.IsA('PlayerPawn') )
    		{
    			Other.PlayerReplicationInfo.TeamID = 0;
    			PlayerPawn(Other).ClientChangeTeam(Other.PlayerReplicationInfo.Team);
    		}
    		else
    			Other.PlayerReplicationInfo.TeamID = 1;
    
    		while ( !bSuccess )
    		{
    			bSuccess = true;
    			for ( P=Level.PawnList; P!=None; P=P.nextPawn )
    				if ( P.bIsPlayer && (P != Other) 
    					&& (P.PlayerReplicationInfo.Team == Other.PlayerReplicationInfo.Team) 
    					&& (P.PlayerReplicationInfo.TeamId == Other.PlayerReplicationInfo.TeamId) )
    			{	
    				Other.PlayerReplicationInfo.TeamID++;
    				bSuccess = False;
    			}
    		}
    
    		if (MonsterReplicationInfo(GameReplicationInfo).bUseLives)
    			Other.PlayerReplicationInfo.Deaths = MonsterReplicationInfo(GameReplicationInfo).Lives;
    
    		if (MonsterReplicationInfo(GameReplicationInfo).bUseTeamSkins)
    		{
    			Other.static.GetMultiSkin(Other, SkinName, FaceName);
    			Other.static.SetMultiSkin(Other, SkinName, FaceName, 0);
    		}
    	}
    }
    
    I'm a bit lost here. Should I try to use Other.PlayerReplicationInfo.Deaths? BTW, thank you for replying:tup:
     
  3. Zur

    Zur surrealistic mad cow

    Joined:
    Jul 8, 2002
    Messages:
    11,702
    Likes Received:
    4
    Code:
    function ScoreKill(pawn Killer, pawn Other)
    {
    	local ScriptedPawn S;
    
    	if ( (Killer == None) || (Killer == Other) || !Other.bIsPlayer 
    		|| (Killer.PlayerReplicationInfo.Team != Other.PlayerReplicationInfo.Team) )
    		Super.ScoreKill(Killer, Other);
    Usually a gametype will pass messages on by either call the super class or calling another class directly.

    The problem you might have here is that a message is only being sent to Scorekill in the Super class under certain conditions. This happens with some standard gametypes so it wouldn't be surprising.

    If Scorekill isn't being called properly you can try to work around this by using other functions relating to Damage (if player health <=0 AND attacker is a monster then ...). Also, if I remember correctly, Monsterhunt places Playerpawns in one team and monsters in another.

    Finally, it might also be worthwhile to see what information monsterreplicationinfo adds.
     
  4. gopostal

    gopostal Active Member

    Joined:
    Jan 19, 2006
    Messages:
    848
    Likes Received:
    47
    I will certainly do my homework with this and see what I can do with it. I'm a bit confused at the moment but that's fine. That's how you learn things.

    Thank you for your time (which is always at a premium, I'm sure). You have given me the nudge to go in the correct direction and I *very* greatly appreciate it sir (or madam?)!
     
  5. Zur

    Zur surrealistic mad cow

    Joined:
    Jul 8, 2002
    Messages:
    11,702
    Likes Received:
    4
    That would be sir Azura ;) (slayer of killer rabbits ?). I don't know about my time being premium but I do try to be helpful despite lack of time.

    I'm back home right now so I have all my files handy. You'll find the source of Mutator.uc below. By browsing through the functions and events you should be able to figure out what's possible with mutators in general. The MutatorTakeDamage function can be used for the alternative approach I described in my last reply.

    If some of the stuff I explained seems like gobbledegook, I'll say it in other terms :
    - Mutator is sent a message by DeathMatchPlus, which in turn represents the game taking place.
    - MonsterHunt is derived from TeamGamePlus which itself is derived from DeathMatchPlus.
    - The scorekill function in a mutator is sent a message on condition that the gametype, like monsterhunt, relays it.
    - The ScoreKill function can be found in a parent or super class of DeathMatchPlus named GameInfo. As you can see below, it calls a function a ScoreKill function in the BaseMutator, or very first mutator in the mutator chain, which in turn passes the message on to mutators after it.

    Code:
    function ScoreKill(pawn Killer, pawn Other)
    {
    	Other.DieCount++;
    	if( (killer == Other) || (killer == None) )
    		Other.PlayerReplicationInfo.Score -= 1;
    	else if ( killer != None )
    	{
    		killer.killCount++;
    		if ( killer.PlayerReplicationInfo != None )
    			killer.PlayerReplicationInfo.Score += 1;
    	}
    
    	BaseMutator.ScoreKill(Killer, Other);
    }
    There. I hope this explains things better. It might be useful to export all the standard classes (such as Mutator) UT uses so you can browse through their code and better understand how it all works.
     

    Attached Files:

    Last edited: Nov 14, 2008
  6. playsax

    playsax New Member

    Joined:
    Feb 20, 2008
    Messages:
    44
    Likes Received:
    0
    I like to use MutatorTakeDamage() to detect deaths and well.. damage! :) Simply make a log() function inside that logs the details of both the Killer (InstigatedBy) and the player that Died (Victim) and you will be well on your way.

    Here is some example code to get you started. It will show you the name of the actor doing damage/being hit and will also tell you if this is a player or not. If you kill yourself, it will be listed as "suicide" (this can be turned around to detect other deaths..).

    Code:
    function PostBeginPlay()
    {
    Level.Game.RegisterDamageMutator( Self ); // In order to receive damage calls, we need to register ourself as a DamageMutator.
    }
    
    function MutatorTakeDamage( out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, 
                            out Vector Momentum, name DamageType)
    {
    
    if(InstigatedBy!=none) BroadcastMessage("Killer:"@InstigatedBy.PlayerReplicationInfo.Playername@InstigatedBy.bIsPlayer);
    if(Victim!=none) BroadcastMessage("Died:"@Victim.PlayerReplicationInfo.Playername@Victim.bIsPlayer);
    if(InstigatedBy!=none && InstigatedBy==Victim && Victim.PlayerReplicationInfo.Health <= 0) BroadcastMessage("A suicide!");
    
        if ( NextDamageMutator != None )
            NextDamageMutator.MutatorTakeDamage( ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType );
    }
     
    Last edited: Nov 14, 2008
  7. Zur

    Zur surrealistic mad cow

    Joined:
    Jul 8, 2002
    Messages:
    11,702
    Likes Received:
    4
    That's the idea.

    Note that it's best to use a Super() instead of NextDamageMutator. That way the call gets sent to the Mutator parent instead of being forced on to the next mutator.

    I just had a quick read through the monsterhunt source. It appears that if Scorekill is only passed on if Other is not a player. If Killer is a player, monsterhunt modifies the score and stops things there.

    Since monsterhunt doesn't seem to override preventdeath, you can also try using it to get the Killed Pawn. From there on, it's a case of cycling through inventory and spawning them at the player location. Pinata should show how to do this.
     
    Last edited: Nov 14, 2008
  8. gopostal

    gopostal Active Member

    Joined:
    Jan 19, 2006
    Messages:
    848
    Likes Received:
    47
    Guys thank you so much! I have decompiled all the classes and now that you have helped me along, I can begin to see the spiderweb of parent-child that is going on. I am looking at prevent death and take damage now and I will concentrate on those to try to get the monster kills to intitiate the pinata effect.

    I can see that this is going to be very important to get right. A lot of the things my group wants to do with monsterhunt will end up working like this. Thank you again for your time and effort in the explanations and code. I am getting ready to insert the log lines to decipher the damage relationships.
     
  9. gopostal

    gopostal Active Member

    Joined:
    Jan 19, 2006
    Messages:
    848
    Likes Received:
    47
    Just a quick update. I got the mod to work by using function bool PreventDeath. It limits the pinata effect to happen only when killed by a monster so as to not litter the ground with pickups underneath some of the tougher bunny track sections. I was hesitant to add a timer to destroy the dropped items because timers can be hard to get right.

    Thank you guys again for taking time to educate me. I promise to pay it forward any chance I get.
     

Share This Page