CheckReplacement
UT2004, Version Only.
Ok so you've got your new weapon and you want to use it in a game. To do this, we create a new weapon Mutator and override the CheckReplacement() function. This function is called for every Actor entering the game (whether being loaded with the map, or spawned on-the-fly), and you can use it to make substitutions and modifications as they are initialized.
First: Make a subclass of Mutator
This will allow you to do all the changes before the level starts, and will automatically iterate though all the level actors, allowing to you to look for any instances of the class you wish to replace.
class NewWeaponMutator extends Mutator;
Second: Swap weapon bases/pickups/etc in CheckReplacement()
We use CheckReplacement(), a probing function, to typecast Other to different subclasses to qualify them and to grab extra info and make substitutions, as needed:
Note: The local variables (i and L) are only necessary if your mod is for UT2004 and you want it to work on Onslaught maps.
function bool CheckReplacement( Actor Other, out byte bSuperRelevant ) { local int i; // for UT2004 Onslaught weapon lockers local WeaponLocker L; // for UT2004 Onslaught weapon lockers bSuperRelevant = 0;
Inside the function the first check is to see if Other is the right class (xWeaponBase). This is to stop the second check going wrong:
if (XWeaponBase(Other) != None)
Now that we know that Other is a xWeaponBase and its WeaponType is the class we want to replace, we override it with our new WeaponType:
{ if (XWeaponBase(Other).WeaponType == Class'WeaponClassWantToReplace') XWeaponbase(Other).WeaponType = Class'NewWeaponClass'; else return true; }
As we've only modified weapon bases so far, you need to do the same thing again, checking for the weapon pickup class to grab any stray weapons of that class lying about in the level for whatever reason (e.g. if they are placed on the map itself, or when a player is killed and drops it). Remember the mutator has to work on other people's levels too, so it should be able to cope with any setup they come up with. So we add:
Note: We use "~=" for a case-insensitive string comparison, but rememeber that class names are fully-qualified. You "PickupClassWantToReplace" would be something like "XWeapons.Minigun".
else if (WeaponPickup(Other) != None) { if (String(Other.Class) ~= "PickupClassWantToReplace") ReplaceWith(Other, "NewPickupClass"); else return true; }
This next section is only for UT2004, and adds support for Onslaught mode's WeaponLockers. Basically, it searches through each WeaponLocker's inventory (array), weapon by weapon, replacing the old weapon class with the new:
else if ( WeaponLocker(Other) != None ) { L = WeaponLocker(Other); for (i = 0; i < L.Weapons.Length; i++) if ( string( L.Weapons[i].WeaponClass ) ~= "WeaponClassWantToReplace" ) L.Weapons[i].WeaponClass = Class'NewWeaponClass'; return true; }
And now, finish off CheckReplacement() with the following:
else return true; return false; }
Third: Add default properties to describe the new Mutator
So that the new weapon mutator has a name and description:
defaultproperties { FriendlyName="name in mutator list" Description="new weapon mutator description" }
-VitalOverdose.
Discussion
Geist: Yeah, that's better. I took the liberty of adding the extra return false; at the end, and a section that supports WeaponLockers from UT2004 Onslaught mode. Personally, I would have placed return false; lines where needed, then finish up the function with a return true;, as that would make the logic make more sense... but that doesn't seem to be the style here (or at Epic, as seen in the other weapon mutator scripts).
Btw, I also realize that comments like "if you're making a UT2004 mod" might be redundant, since the top of the page seems to indicate this page is already UT2004-only. So if this page is meant to be UT2004-specific through and through, please remove the extraneous UT2004 comments in the code/text and be more explicit at the top of the page. (how many times can I say "UT2004" in one paragraph?)
_FatalOverdose - thanks , will do that.
Sweavo: Shouldn't there be a call to NextMutator.CheckReplacement rather than a simple return...?
Wormbo: CheckReplacement should never call NextMutator.CheckReplacement(). The function is called by IsRelevant, which also handles the linked list stuff.
AgentBionicman I don't think projectiles are sent through this function anymore. Anyone else notice this?
Bonehed316: Projectiles arent sent through this function because they have bGameRelevant=True. This function only works on those actors which are !bGameRelevant. Maybe there should be a small section which explains how/why this function gets called, and where from?
Sweavo: seconded. This page is hit number one for a search for CheckReplacement, but does not tell us what the out parameter bSuperRelevant does, nor what the return value means.
Neuroflare: None of the CheckReplacement tutorials I have seen here elaborate on changing out ammo, or am I mistaken?
MythOpus: I don't think you can change firemodes/ammo because they're set to only be able to be access by the class the references them.. in this case Weapon.