Higor
05-11-2012, 11:35 PM
This one reduces the processing time of the suppliers when giving ammo and upgrading armor.
It still does not regenerate thrown weapons, that can be added at the expense of losing speed.
First thing first, we need an extra variable in the class sgSupplier:
var int iWeaponClasses;
This adds a lot of flexibility in code by reducing iteration count if a weapon class fails to load (mods?).
Now, when loading the weapon classes, we add a some new code after the function:
static function LoadWeaponClasses()
{
local int i;
local class<Weapon> weaponClass;
default.ClassesLoaded = true;
for ( i = 0; i < 9; i++ )
if ( default.Weapons[i] != "" )
default.WeaponClasses[i] =
class<Weapon>(DynamicLoadObject(default.Weapons[i],
class'Class'));
//Keep array compacted, faster if weapon fails to load
default.iWeaponClasses = 9;
for ( i=0 ; i<default.iWeaponClasses ; i++ )
if ( default.WeaponClasses[i] == none )
{
default.WeaponClasses[i] = default.WeaponClasses[--default.iWeaponClasses];
default.WeaponClasses[default.iWeaponClasses] = none;
--i; //Loop this element again
}
}
That's part of the process of keeping the weapon class table compacted and with a ceiling index (weapon class count), it sorta makes it work like a dynamic array.
Now we go to the main Supply function:
function Supply(Pawn target)
{
local int numWeapons, i, j;
local Inventory inv;
local sgArmor theArmor;
if ( bDisabledByEMP )
return;
if ( !default.ClassesLoaded )
LoadWeaponClasses();
numWeapons = min(GetWeaponCount(), default.iWeaponClasses);
for ( inv=target.Inventory ; inv!=none ; inv=inv.Inventory )
{
if ( (theArmor == none) && (sgArmor(Inv) != none) )
{
theArmor = sgArmor(Inv);
continue;
}
if ( (Weapon(Inv) == none) || (Weapon(Inv).AmmoType == none) )
continue;
for ( i=0 ; i<numWeapons ; i++ )
{
if ( Inv.class == default.WeaponClasses[i] )
{
j++;
if ( Weapon(inv).AmmoType.AmmoAmount < Weapon(inv).PickupAmmoCount / 2 )
Weapon(inv).AmmoType.AmmoAmount = Weapon(inv).PickupAmmoCount / 2;
else if ( FRand() < float(Weapon(inv).AmmoType.MaxAmmo) / 400 )
Weapon(inv).AmmoType.AmmoAmount = FMin(
Weapon(inv).AmmoType.AmmoAmount + 1 +
int(FRand()*Grade/2*EquipRate),
Weapon(inv).AmmoType.MaxAmmo);
if ( j >= numWeapons )
Goto WEAPONS_READY;
break;
}
}
}
WEAPONS_READY:
if ( theArmor != none )
Goto UPGRADE_ARMOR;
while ( inv != none )
{
if ( sgArmor(Inv) != none )
{
theArmor = sgArmor(Inv);
Goto UPGRADE_ARMOR;
}
inv = inv.Inventory;
}
theArmor = Spawn( class'sgArmor');
if ( theArmor == none )
Goto PLAY_SOUND;
theArmor.GiveTo( Target);
UPGRADE_ARMOR:
if ( FRand() < 0.1 + (Grade/15) && inv.Charge < 25 + Grade*25 )
++theArmor.Charge;
PLAY_SOUND:
if ( FRand() < 0.2 )
target.PlaySound(sound'sgMedia.sgStockUp', SLOT_Misc,
target.SoundDampening*2.5);
}
Code here can result illegible to some, it contains jumps to ensure maximum speed, it's also very compacted and adding an extra item to upgrade would require a reformulation of some loops.
Explanation step by step:
- Instead of looping the entire Inventory chain for each weapon/armor, we simply go through the Inventory chain once and start making our weapon checks there.
If we happen to catch the armor we also store it...
Now we check in the first loop if it's a valid suppliable weapon, if it is, we start checking among our weapon table (limited by Supplier level), if weapon is in the table, we add ammo and count J up.
If the J counter reaches the maximum weapons to supply (depends on Supplier level), we immediately leave the main loop and the subloop.
Notice that when we leave both loops, INV variable doesn't change or anything, we're still in the middle of the inventory chain...
- We left the loop, either by having it finished (entire inventory chain) or by jumping out into WEAPONS_READY, let's check if we got the armor during these iterations...
We got it!, skip some code by jumping to UPGRADE_ARMOR.
We didn't get it... remember INV? We continue looping through the Inventor chain in a much simpler loop meant to find this armor.
If we found the armor, we instantly jump to UPGRADE_ARMOR.
If we didn't, we create the armor, if armor fails to be created, we jump to PLAY_SOUND.
- We reach UPGRADE_ARMOR, either by finding it or by making it.
The code difference here? There's already a maximum armor check on the conditional, so using the ++ preoperator to add one is entirely the same and much faster than the previous method.
- Code keeps going, we now reach PLAY_SOUND.
This is the same as before, PLAY_SOUND is added here to skip armor upgrade if we fail to create it.
=======
Super supplier has identical code for both functions, replace them as well, add the extra variable and you're set.
Trivia:
Did you know this works in unrealscript?
if ( aNumber == 6 )
Goto DO_SOMETHING;
if ( false ) //Never enter this code chunk by normal means
{
DO_SOMETHING:
TestFunction();
}
or
if ( aNumber == 6 )
Goto AFTER_FUNCTION;
return;
AFTER_FUNCTION:
TestFunction();
}
It still does not regenerate thrown weapons, that can be added at the expense of losing speed.
First thing first, we need an extra variable in the class sgSupplier:
var int iWeaponClasses;
This adds a lot of flexibility in code by reducing iteration count if a weapon class fails to load (mods?).
Now, when loading the weapon classes, we add a some new code after the function:
static function LoadWeaponClasses()
{
local int i;
local class<Weapon> weaponClass;
default.ClassesLoaded = true;
for ( i = 0; i < 9; i++ )
if ( default.Weapons[i] != "" )
default.WeaponClasses[i] =
class<Weapon>(DynamicLoadObject(default.Weapons[i],
class'Class'));
//Keep array compacted, faster if weapon fails to load
default.iWeaponClasses = 9;
for ( i=0 ; i<default.iWeaponClasses ; i++ )
if ( default.WeaponClasses[i] == none )
{
default.WeaponClasses[i] = default.WeaponClasses[--default.iWeaponClasses];
default.WeaponClasses[default.iWeaponClasses] = none;
--i; //Loop this element again
}
}
That's part of the process of keeping the weapon class table compacted and with a ceiling index (weapon class count), it sorta makes it work like a dynamic array.
Now we go to the main Supply function:
function Supply(Pawn target)
{
local int numWeapons, i, j;
local Inventory inv;
local sgArmor theArmor;
if ( bDisabledByEMP )
return;
if ( !default.ClassesLoaded )
LoadWeaponClasses();
numWeapons = min(GetWeaponCount(), default.iWeaponClasses);
for ( inv=target.Inventory ; inv!=none ; inv=inv.Inventory )
{
if ( (theArmor == none) && (sgArmor(Inv) != none) )
{
theArmor = sgArmor(Inv);
continue;
}
if ( (Weapon(Inv) == none) || (Weapon(Inv).AmmoType == none) )
continue;
for ( i=0 ; i<numWeapons ; i++ )
{
if ( Inv.class == default.WeaponClasses[i] )
{
j++;
if ( Weapon(inv).AmmoType.AmmoAmount < Weapon(inv).PickupAmmoCount / 2 )
Weapon(inv).AmmoType.AmmoAmount = Weapon(inv).PickupAmmoCount / 2;
else if ( FRand() < float(Weapon(inv).AmmoType.MaxAmmo) / 400 )
Weapon(inv).AmmoType.AmmoAmount = FMin(
Weapon(inv).AmmoType.AmmoAmount + 1 +
int(FRand()*Grade/2*EquipRate),
Weapon(inv).AmmoType.MaxAmmo);
if ( j >= numWeapons )
Goto WEAPONS_READY;
break;
}
}
}
WEAPONS_READY:
if ( theArmor != none )
Goto UPGRADE_ARMOR;
while ( inv != none )
{
if ( sgArmor(Inv) != none )
{
theArmor = sgArmor(Inv);
Goto UPGRADE_ARMOR;
}
inv = inv.Inventory;
}
theArmor = Spawn( class'sgArmor');
if ( theArmor == none )
Goto PLAY_SOUND;
theArmor.GiveTo( Target);
UPGRADE_ARMOR:
if ( FRand() < 0.1 + (Grade/15) && inv.Charge < 25 + Grade*25 )
++theArmor.Charge;
PLAY_SOUND:
if ( FRand() < 0.2 )
target.PlaySound(sound'sgMedia.sgStockUp', SLOT_Misc,
target.SoundDampening*2.5);
}
Code here can result illegible to some, it contains jumps to ensure maximum speed, it's also very compacted and adding an extra item to upgrade would require a reformulation of some loops.
Explanation step by step:
- Instead of looping the entire Inventory chain for each weapon/armor, we simply go through the Inventory chain once and start making our weapon checks there.
If we happen to catch the armor we also store it...
Now we check in the first loop if it's a valid suppliable weapon, if it is, we start checking among our weapon table (limited by Supplier level), if weapon is in the table, we add ammo and count J up.
If the J counter reaches the maximum weapons to supply (depends on Supplier level), we immediately leave the main loop and the subloop.
Notice that when we leave both loops, INV variable doesn't change or anything, we're still in the middle of the inventory chain...
- We left the loop, either by having it finished (entire inventory chain) or by jumping out into WEAPONS_READY, let's check if we got the armor during these iterations...
We got it!, skip some code by jumping to UPGRADE_ARMOR.
We didn't get it... remember INV? We continue looping through the Inventor chain in a much simpler loop meant to find this armor.
If we found the armor, we instantly jump to UPGRADE_ARMOR.
If we didn't, we create the armor, if armor fails to be created, we jump to PLAY_SOUND.
- We reach UPGRADE_ARMOR, either by finding it or by making it.
The code difference here? There's already a maximum armor check on the conditional, so using the ++ preoperator to add one is entirely the same and much faster than the previous method.
- Code keeps going, we now reach PLAY_SOUND.
This is the same as before, PLAY_SOUND is added here to skip armor upgrade if we fail to create it.
=======
Super supplier has identical code for both functions, replace them as well, add the extra variable and you're set.
Trivia:
Did you know this works in unrealscript?
if ( aNumber == 6 )
Goto DO_SOMETHING;
if ( false ) //Never enter this code chunk by normal means
{
DO_SOMETHING:
TestFunction();
}
or
if ( aNumber == 6 )
Goto AFTER_FUNCTION;
return;
AFTER_FUNCTION:
TestFunction();
}