UE1 - UT Sending parameters from a carcass to a gib chunk

  • 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.
Nov 4, 2001
2,196
0
0
36
The Kitchen
Hi. I'm absolutely retarded, have no idea what I'm doing, and my code sucks balls. \o/

[EDIT] System is now working fully, but needs optimization! See second post

Now with that out of the way, I'm working on making a system that allows me to specify custom blood colors for pawns. So far, I have an enum variable in my custom pawn superclass (EXUScriptedPawn) which works fine; decals and blood spurts are the proper colors.

I also have a new CreatureCarcass subclass (EXUCreatureCarcass) and a new CreatureChunks subclass (EXUCreatureChunks) in order to apply custom blood and decals so they match the originating pawn's blood color. So far, I have managed to get the carcass to inherit the originating pawn's (the instigator's) blood color, but I can't seem to pass this info on to the gib chunks when the carcass inevitably explodes into a shower of little pieces.

The whole system I've designed to handle all this is pretty damn gnarly, but when I started off, I used simpler measures that refused to compile, probably because I'm not fully understanding what I'm doing. For instance, BloodEXU used to have a Hemospectrum enum to match EXUScriptedPawn, but setting BloodEXU's hemospectrum value via EXUScriptedPawn never compiled, so I made a bunch of init functions for each blood type and set up the proper textures and stuff from those. Messy, but functional.

Anyway, here's actual code.

First, relevant chunks of EXUScriptedPawn (click for more readable Pastebin links), including the vars I've set up:

Code:
var(Combat) enum EXUBloodType					// Not in the clinical sense!
{
	BLOOD_Red,
	BLOOD_Green,
	BLOOD_Blue,
	BLOOD_Brown,				// **** blood? What the ****
	BLOOD_White,
	BLOOD_MYBLOODvvvISvvvvvvBLACK,		// UT3 taunts = hilarious
	BLOOD_None				// For vehicles and **** if you don't want, say, an oily black discharge (that sounds really nasty)
}
Hemospectrum;					// Couldn't resist the Homestuck reference because Homestuck ****ing kicks ass

And the functions which use them:
Code:
//======================================================================================================
// HEMOSPECTRUM CODE: Modified hit code to allow for different blood types
//======================================================================================================
function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
{
	local float rnd;
	local Bubble1 bub;
	local bool bOptionalTakeHit;
	local vector BloodOffset;
	local BloodEXU b;

	if (Damage > 1) //spawn some blood
	{
		if (damageType == 'Drowned')
		{
			bub = spawn(class 'Bubble1',,, Location 
				+ 0.7 * CollisionRadius * vector(ViewRotation) + 0.3 * EyeHeight * vect(0,0,1));
			if (bub != None)
				bub.DrawScale = FRand()*0.06+0.04; 
		}
		else if ( damageType != 'Corroded' )
		{
			BloodOffset = 0.2 * CollisionRadius * Normal(HitLocation - Location);
			BloodOffset.Z = BloodOffset.Z * 0.5;

			if( EXUHitEffect!=none && EXUHitEffectScale>0 )
			{
				EHF = spawn(EXUHitEffect,self,'', hitLocation);
				if(EHF!=none)
					EHF.DrawScale = EHF.Default.DrawScale * EXUHitEffectScale;
			}

			// Guess what folks! We have to do this the ****ING STUPID way because UCC is a HUGE BITCH, BLUH BLUH

			if(Hemospectrum!=BLOOD_None)
			{
				b = spawn(class'BloodBurstEXU',self,'', hitLocation);
				if(b!=none)
				{
					if(Hemospectrum==BLOOD_Red)
						b.InitRed();
					if(Hemospectrum==BLOOD_Green)
						b.InitGreen();
					if(Hemospectrum==BLOOD_Blue)
						b.InitBlue();
					if(Hemospectrum==BLOOD_Brown)
						b.InitBrown();
					if(Hemospectrum==BLOOD_White)
						b.InitWhite();
					if(Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
						b.InitBlack();
				}
	
				if ( Level.bHighDetailMode )
				{
					spawn(class'BloodPuff',,, hitLocation + BloodOffset);
				}
			}
		}
	}

	if ( (Weapon != None) && Weapon.bPointing && !bIsPlayer )
	{
		bFire = 0;
		bAltFire = 0;
	}
	
	bOptionalTakeHit = bIsWuss || ( (Level.TimeSeconds - LastPainTime > 0.3 + 0.25 * skill)
						&& (Damage * FRand() > 0.08 * Health) && (Skill < 3)
						&& (GetAnimGroup(AnimSequence) != 'MovingAttack') 
						&& (GetAnimGroup(AnimSequence) != 'Attack') ); 
	if ( (!bIsPlayer || (Weapon == None) || !Weapon.bPointing) 
		&& (bOptionalTakeHit || (Momentum.Z > 140) || (bFirstShot && (Damage > 0.015 * (skill + 6) * Health)) 
			 || (Damage * FRand() > (0.17 + 0.04 * skill) * Health)) ) 
	{
		PlayTakeHitSound(Damage, damageType, 3);
		PlayHitAnim(HitLocation, Damage);
	}
	else if (NextState == 'TakeHit')
	{
		PlayTakeHitSound(Damage, damageType, 2);
		NextState = '';
	}
}

function PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum)
{
	local Bubble1 bub;
	local BloodEXU b;

	if ( Region.Zone.bDestructive && (Region.Zone.ExitActor != None) )
		Spawn(Region.Zone.ExitActor);

	if (HeadRegion.Zone.bWaterZone)
	{
		bub = spawn(class 'Bubble1',,, Location 
			+ 0.3 * CollisionRadius * vector(Rotation) + 0.8 * EyeHeight * vect(0,0,1));
		if (bub != None)
			bub.DrawScale = FRand()*0.08+0.03; 
		bub = spawn(class 'Bubble1',,, Location 
			+ 0.2 * CollisionRadius * VRand() + 0.7 * EyeHeight * vect(0,0,1));
		if (bub != None)
			bub.DrawScale = FRand()*0.08+0.03; 
		bub = spawn(class 'Bubble1',,, Location 
			+ 0.3 * CollisionRadius * VRand() + 0.6 * EyeHeight * vect(0,0,1));
		if (bub != None)
			bub.DrawScale = FRand()*0.08+0.03; 
	}

	if( (damageType != 'Burned') && (damageType != 'Corroded') && (damageType != 'Drowned') && (damageType != 'Fell') )
	{
		if( EXUHitEffect!=none && EXUHitEffectScale>0 )
		{
			EHF = spawn(EXUHitEffect,self,'', hitLocation);
			if(EHF!=none)
				EHF.DrawScale = EHF.Default.DrawScale * EXUHitEffectScale;
		}

		if(Hemospectrum!=BLOOD_None)
		{
			b = spawn(class'BloodBurstEXU',self,'', hitLocation);
			if(b!=none)
			{
				if(Hemospectrum==BLOOD_Red)
					b.InitRed();
				if(Hemospectrum==BLOOD_Green)
					b.InitGreen();
				if(Hemospectrum==BLOOD_Blue)
					b.InitBlue();
				if(Hemospectrum==BLOOD_Brown)
					b.InitBrown();
				if(Hemospectrum==BLOOD_White)
					b.InitWhite();
				if(Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
					b.InitBlack();
			}
		}
	}
}

As you can see, this is all a hilarious mess. I have the exact same Hemospectrum enum in EXUCreatureCarcass and in EXUCreatureChunks, but if I simply put a b.Hemospectrum = Hemospectrum; line, UCC bitches at me with a "incorrect type in '=' " error message. I'm guessing this is because my enums don't exist across the board in Actor like, say, DrawScale or Style or LightType.

Now, for the real fun times disaster, EXUCreatureCarcass:
Code:
var(CreatureCarcass) enum EXUBloodType					// Not in the clinical sense! copied from EXUScriptedPawn
{
	BLOOD_Red,
	BLOOD_Green,
	BLOOD_Blue,
	BLOOD_Brown,				// **** blood? What the ****
	BLOOD_White,
	BLOOD_MYBLOODvvvISvvvvvvBLACK,		// UT3 taunts = hilarious
	BLOOD_None				// For vehicles and **** if you don't want, say, an oily black discharge (that sounds really nasty)
}
Hemospectrum;					// Couldn't resist the Homestuck reference because Homestuck ****ing kicks ass

simulated function PostBeginPlay()
{
	Super.PostBeginPlay();

	if(Instigator!=none && Instigator.IsA('EXUScriptedPawn'))
	{

		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_Red)
			Hemospectrum=BLOOD_Red;
		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_Green)
			Hemospectrum=BLOOD_Green;
		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_Blue)
			Hemospectrum=BLOOD_Blue;
		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_Brown)
			Hemospectrum=BLOOD_Brown;
		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_White)
			Hemospectrum=BLOOD_White;
		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
			Hemospectrum=BLOOD_MYBLOODvvvISvvvvvvBLACK;
		if(EXUScriptedPawn(Instigator).Hemospectrum==BLOOD_None)
			Hemospectrum=BLOOD_None;

	//	broadcastmessage("Post-process: Instigator is: "$Instigator$" and its Hemospectrum is "$EXUScriptedPawn(Instigator).Hemospectrum$". Carcass Hemospectrum is: "$Hemospectrum);
	//	log("Post-process: Instigator is: "$Instigator$" and its Hemospectrum is "$EXUScriptedPawn(Instigator).Hemospectrum$". Carcass Hemospectrum is: "$Hemospectrum);
	}
}

function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, 
						Vector Momentum, name DamageType)
{	
	local BloodSpurtEXU b;

	if(Hemospectrum!=BLOOD_None)
	{
		b = Spawn(class'BloodSpurtEXU',,,HitLocation,rot(16384,0,0));
		if(b!=none)
		{
	//		log("Spawned a "$b);
	//		broadcastmessage("Spawned a "$b);

			if(Hemospectrum==BLOOD_Red)
				b.InitRed();
			if(Hemospectrum==BLOOD_Green)
				b.InitGreen();
			if(Hemospectrum==BLOOD_Blue)
				b.InitBlue();
			if(Hemospectrum==BLOOD_Brown)
				b.InitBrown();
			if(Hemospectrum==BLOOD_White)
				b.InitWhite();
			if(Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
				b.InitBlack();
		}
	}
	if ( !bPermanent )
	{
		if ( (DamageType == 'Corroded') && (Damage >= 100) )
		{
			bCorroding = true;
			GotoState('Corroding');
		}
		else
			Super.TakeDamage(Damage, instigatedBy, HitLocation, Momentum, DamageType);
	}
}

function CreateReplacement()
{
	local EXUCreatureChunks carc;
	
	if (bHidden)
		return;
	if ( bodyparts[0] != None )
		carc = Spawn(class'EXUCreatureChunks',self,, Location + ZOffset[0] * CollisionHeight * vect(0,0,1)); 
	if (carc != None)
	{
		carc.TrailSize = Trails[0];
		carc.Mesh = bodyparts[0];
		carc.bMasterChunk = true;
		carc.Initfor(self);
		carc.Bugs = Bugs;
		if ( Bugs != None )
			Bugs.SetBase(carc);
		Bugs = None;

		if(Hemospectrum==BLOOD_Red)
			carc.Hemospectrum=BLOOD_Red;
		if(Hemospectrum==BLOOD_Green)
			carc.Hemospectrum=BLOOD_Green;
		if(Hemospectrum==BLOOD_Blue)
			carc.Hemospectrum=BLOOD_Blue;
		if(Hemospectrum==BLOOD_Brown)
			carc.Hemospectrum=BLOOD_Brown;
		if(Hemospectrum==BLOOD_White)
			carc.Hemospectrum=BLOOD_White;
		if(Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
			carc.Hemospectrum=BLOOD_MYBLOODvvvISvvvvvvBLACK;
		if(Hemospectrum==BLOOD_None)
			carc.Hemospectrum=BLOOD_None;
	}
	else if ( Bugs != None )
		Bugs.Destroy();
}

simulated function HitWall(vector HitNormal, actor Wall)
{
	local BloodSpurtEXU b;

	if(Hemospectrum!=BLOOD_None)
	{
		b = Spawn(class'BloodspurtEXU',,,,Rotator(HitNormal));
		if(b!=none)
		{
	//		log("Spawned a "$b);
	//		broadcastmessage("Spawned a "$b);

			if(Hemospectrum==BLOOD_Red)
				b.InitRed();
			if(Hemospectrum==BLOOD_Green)
				b.InitGreen();
			if(Hemospectrum==BLOOD_Blue)
				b.InitBlue();
			if(Hemospectrum==BLOOD_Brown)
				b.InitBrown();
			if(Hemospectrum==BLOOD_White)
				b.InitWhite();
			if(Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
				b.InitBlack();

			b.RemoteRole = ROLE_None;
		}
	}
	Velocity = 0.7 * (Velocity - 2 * HitNormal * (Velocity Dot HitNormal));
	Velocity.Z *= 0.9;
	if ( Abs(Velocity.Z) < 120 )
	{
		bBounce = false;
		Disable('HitWall');
	}
}

And finally, EXUCreatureChunks:

Code:
var(CreatureChunks) enum EXUBloodType					// Not in the clinical sense! copied from EXUScriptedPawn
{
	BLOOD_Red,
	BLOOD_Green,
	BLOOD_Blue,
	BLOOD_Brown,				// **** blood? What the ****
	BLOOD_White,
	BLOOD_MYBLOODvvvISvvvvvvBLACK,		// UT3 taunts = hilarious
	BLOOD_None				// For vehicles and **** if you don't want, say, an oily black discharge (that sounds really nasty)
}
Hemospectrum;					// Couldn't resist the Homestuck reference because Homestuck ****ing kicks ass


simulated function PostBeginPlay()
{
	Super.PostBeginPlay();


	broadcastmessage("Initializing: Owner is: "$Owner$" and its Hemospectrum is "$EXUCreatureCarcass(Owner).Hemospectrum$". Chunk Hemospectrum is: "$Hemospectrum);
	log("Initializing: Owner is: "$Owner$" and its Hemospectrum is "$EXUCreatureCarcass(Owner).Hemospectrum$". Chunk Hemospectrum is: "$Hemospectrum);

	if(Owner!=none && Owner.IsA('EXUCreatureCarcass'))
	{

		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_Red)
			Hemospectrum=BLOOD_Red;
		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_Green)
			Hemospectrum=BLOOD_Green;
		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_Blue)
			Hemospectrum=BLOOD_Blue;
		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_Brown)
			Hemospectrum=BLOOD_Brown;
		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_White)
			Hemospectrum=BLOOD_White;
		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
			Hemospectrum=BLOOD_MYBLOODvvvISvvvvvvBLACK;
		if(EXUCreatureCarcass(Owner).Hemospectrum==BLOOD_None)
			Hemospectrum=BLOOD_None;

		broadcastmessage("Post-process: Owner is: "$Owner$" and its Hemospectrum is "$EXUCreatureCarcass(Owner).Hemospectrum$". Chunk Hemospectrum is: "$Hemospectrum);
		log("Post-process: Owner is: "$Owner$" and its Hemospectrum is "$EXUCreatureCarcass(Owner).Hemospectrum$". Chunk Hemospectrum is: "$Hemospectrum);
	}
}
...and there's a lot more ugly horseballs code in there which controls the color of the blood spurts and decals.

The only real problem I'm having with this terrible system is the EXUCreatureChunks phase; Owner always returns none, and trying to change it to Instigator results in compile errors telling me that casting to Pawn will always fail or whatever, probably because the gib class is too far removed from the original pawn that generated the carcass which spawned the gib once destroyed, etc etc etc.

What I don't get is why I can't seem to send these enum values to another class. Being able to write something like Chunk.Hemospectrum = Hemospectrum would save me a lot of ugly lines of code and would be flexible enough to handle modifications to the list of choices in the enum list without requiring tons of code updates every time I add a new color. I guess there's something with enums that doesn't like this? But I also tried setting the enum to a byte value, using numbers in place of a BLOOD_<whatever> choice, and it STILL gave me type mismatch errors when I tried to compile it.

Basically I'm at a loss on where to go from here, and would appreciate any help on either getting this horrific system to work or rewriting it from the ground up so it isn't as ugly!

I also had the same problem with blood decals. Originally, I had all my different colored textures as arrays in a single decal class, set to choose one of the arrays in BeginPlay based on whichever enum choice was sent to the decal, but that never worked. I had to make a dedicated decal class for each blood color, which is just stupid as hell but it worked so whatever. Hopefully I can clean all this crap up because it's really pretty embarrassing.
 
Last edited:
Nov 4, 2001
2,196
0
0
36
The Kitchen
[Edit] HOLY CRAP IT WORKS

It's still a gigantic mess of horror, but it works. It turns out I forgot to force the blood color in EXUCreatureChunk's ClientExtraChunks function, like so:

Code:
if ( CarcLocation == vect(0,0,0) ) CarcLocation = Location; 
			carc = Spawn(class 'EXUCreatureChunks',self,, CarcLocation + CarcassClass.Default.ZOffset[n] * CarcHeight * vect(0,0,1));
	if (carc != None)
	{
		carc.TrailSize = CarcassClass.Default.Trails[n];
		carc.Mesh = CarcassClass.Default.bodyparts[n];
		carc.Initfor(self);
		carc.RemoteRole = ROLE_None;

		if(Hemospectrum==BLOOD_Red)
			carc.Hemospectrum=BLOOD_Red;
		if(Hemospectrum==BLOOD_Green)
			carc.Hemospectrum=BLOOD_Green;
		if(Hemospectrum==BLOOD_Blue)
			carc.Hemospectrum=BLOOD_Blue;
		if(Hemospectrum==BLOOD_Brown)
			carc.Hemospectrum=BLOOD_Brown;
		if(Hemospectrum==BLOOD_White)
			carc.Hemospectrum=BLOOD_White;
		if(Hemospectrum==BLOOD_MYBLOODvvvISvvvvvvBLACK)
			carc.Hemospectrum=BLOOD_MYBLOODvvvISvvvvvvBLACK;
		if(Hemospectrum==BLOOD_None)
			carc.Hemospectrum=BLOOD_None;
	}

This modification got the system working. HOORAY!

That said, this stuff is far from complete. I know there has got to be a much, much better way to accomplish this same thing without all the discord. I'll leave this thread open to optimization discussion!
 
Last edited:

brold9999

New Member
Apr 5, 2009
142
0
0
You can't directly assign the enums because they aren't the same type. You've declared a separate (but identical) enum type in each of the classes. There is syntax for using an enum from another class.
 
Nov 4, 2001
2,196
0
0
36
The Kitchen
You can't directly assign the enums because they aren't the same type. You've declared a separate (but identical) enum type in each of the classes. There is syntax for using an enum from another class.
Indeed, I figured as such. I never expected the enums to be considered the same since I had to define them in three different places; I simply reused the same terms out of laziness.

And that syntax would be...?
 
Nov 4, 2001
2,196
0
0
36
The Kitchen
Maybe I just don't know enough about what I'm doing to search for the proper terms, but I HAVE already looked through the wiki (it's always my first stop when I have questions like this) and have failed to find info about what I'm trying to do. Got any links to specific articles I could check out?

Sorry I'm really bad at code; I'm a designer first and foremost :>
 

brold9999

New Member
Apr 5, 2009
142
0
0
Ah ok, fair enough. I may have been a little off base with that last comment because when I went to find the links it turns out that the information used to be readily available on UnrealWiki but the relevant page has been overhauled since and now lacks most of the info that was there before. :S

You will want to use the DependsOn class modifier. In UE2 you can (maybe you have to?) use a fully qualified name for the variable type, and I assume that UE1 is the same.

Example:

Code:
class Foo extends Object;

var enum Bar
{
   BAR_A,
   BAR_B,
   BAR_C
} Baz;

Code:
class Fizz extends Object
  DependsOn(Foo);

var Foo.Bar Buzz;
 
Nov 4, 2001
2,196
0
0
36
The Kitchen
No problem yo, I know you get a lot of lazy half-assed posts in forums like this! I didn't mean to come across as unwilling to look for answers myself, I'm just dumb :I

Anyway this looks interesting; I'll have to try it out. Some folks on USP.org suggested I try something like this:

Code:
setpropertytext("HemoSpectrum",Owner.GetPropertyText("HemoSpectrum"));

I haven't gone into the heavy-duty optimizing spree yet, as I'm still busy cleaning up kinks and screwballery with the new blood/hit effect classes for all 5 bajillion pawns I have to look after, but hopefully between this and some of the other UScript thingies I wasn't really aware of until recently, I can come up with something that's better than a trillion "if this then do this" checks.

Thanks for the help :)
 

gopostal

Active Member
Jan 19, 2006
848
47
28
Waff have you given thought to how this will effect online play? This looks really laggy if there are many chunks, and you are going to have to set up some replication. (Scratch all that if you are working on more single player stuff :))

Get rid of the CanSeeMe checks if you can too. They can be server crashers.
 
Nov 4, 2001
2,196
0
0
36
The Kitchen
Turns out I managed to optimize the setup quite a bit, but haven't tested online functionality yet. However, UA and I are working on rewriting the entire carcass/gib system almost from scratch for the future, so my new, functional, semi-optimized system is only a placeholder at the moment! Once the even newer, betterer system replaces this one, we'll probably be able to ensure it works smoothlyish online (or at least can be reset to use all one type online).

I'm not sure what CanSeeMe checks you're referring to, though...?
 

gopostal

Active Member
Jan 19, 2006
848
47
28
CanSeeMe is a check that is in carcass chunks, biterfish out of water, wood splinters...stuff like that. It's designed to delete those items that are "out of sight" for a length of time (like if you look away). Somewhere in the native code there is a bug that very occasionally hard-crashes a server when the item is deleted. I add a biterfish replacement without the check to every mod I do but the carcass chunks are just too numerous to replace without lag.