This tutorial was created by Hap of FreeForm Interactive(creators of Future
vs. Fantasy).
In this tutorial we are going to create a new weapon, a shotgun. The shotgun will replace the shredder in Gtest,
however with some modifications you could have it replace any other weapon, or add it as a new weapon altogether.
All modifications take place in the weapons.c file.
First off at the top of the file where we are including external files you need to add the following line:
#include <stdlib.h> // we need this for our random function
Next we must modify our FireWeapon function so that it looks like so:
//=====================================================================================
// FireWeapon
//=====================================================================================
geBoolean FireWeapon(GenVSI *VSI, void *PlayerData, float Time)
{
GPlayer *Player;
assert(PlayerData);
Player = (GPlayer*)PlayerData;
if (GenVSI_GetTime(VSI) < Player->NextWeaponTime)
return GE_TRUE;
ValidateWeapon(VSI, PlayerData);
switch (Player->CurrentWeapon)
{
case 0:
FireBlaster(VSI, Player, Time);
break;
case 1:
FireGrenade(VSI, Player, Time);
break;
case 2:
FireRocket(VSI, Player, Time);
break;
//case 3:
// FireShredder(VSI, Player, Time);
// break;
case 3:
FireCombatShotgun(VSI, Player, Time);
break;
}
return GE_TRUE;
}
Next we need to add the code for our Combat Shotgun. Somewhere in your weapons.c file add the following functions.
//=====================================================================================
// CombatShotgun_Control
//=====================================================================================
geBoolean CombatShotgun_Control(GenVSI *VSI, void *PlayerData, float Time)
{
GPlayer *Player;
static int currentPellet; //number of effective shotgun pellet number
Player = (GPlayer*)PlayerData;
currentPellet++;
if (currentPellet == 1)
{
// Play the sound
//GenVSI_PlaySound(VSI, SOUND_INDEX_SHREDDER, &Player->XForm.Translation);
}
else if (currentPellet >= 3) // max number of shotgun pellets... should be a constant
{
Player->Owner->Weapon = NULL;
GenVSI_DestroyPlayer(VSI, PlayerData);
currentPellet = 0;
return GE_TRUE;
}
Player->XForm.Translation.X += rndSpread(10); //Shotgun spread
Player->XForm.Translation.Y += rndSpread(10);
return GE_TRUE;
}
//=====================================================================================
// FireCombatShotgun
//=====================================================================================
void FireCombatShotgun(GenVSI *VSI, void *PlayerData, float Time)
{
GPlayer *Weapon;
GE_Collision Collision;
geVec3d Front, Back, In;
GPlayer *Player;
geWorld *World;
Player = (GPlayer*)PlayerData;
if (Player->Inventory[ITEM_SHREDDER] <= 0 || !Player->InventoryHas[ITEM_SHREDDER])
{
SwitchToNextBestWeapon(VSI, Player);
return;
}
if (!Player->Weapon) // Check to see if allready firing
{
Weapon = GenVSI_SpawnPlayer(VSI, "Weapon_Shredder");
if (!Weapon)
{
GenVSI_ConsolePrintf(VSI, "FireShredder:
Failed to add player.\n");
return;
}
}
else
return;
if (Player->Inventory[ITEM_SHREDDER] < 0)
{
SwitchToNextBestWeapon(VSI, Player);
Player->Inventory[ITEM_SHREDDER] = 0;
}
// Setup the callbacks for this weapon
Weapon->Control = CombatShotgun_Control;
Weapon->Blocked = NULL;
Weapon->Trigger = NULL;
Weapon->Owner = Player;
Player->Weapon = Weapon;
Weapon->Time = 0.0f;
Weapon->ViewFlags = VIEW_TYPE_NONE;
Weapon->ViewIndex = VIEW_INDEX_NONE;
Weapon->FxFlags = FX_SHREDDER;
Weapon->XForm = Player->XForm;
geVec3d_Add(&Weapon->XForm.Translation, &Player->GunOffset, &Weapon->XForm.Translation);
Front = Weapon->XForm.Translation;
geXForm3d_GetIn(&Weapon->XForm, &In);
geVec3d_AddScaled(&Front, &In, 10000.0f, &Back);
World = GenVSI_GetWorld(VSI);
assert(World);
if (geWorld_Collision(World, NULL, NULL, &Front, &Back, GE_COLLIDE_ACTORS, 0xffffffff,
&Collision))
{
if (Collision.Actor)
{
GPlayer
*PlayerHit;
PlayerHit = GenVSI_ActorToPlayer(VSI, Collision.Actor);
if (PlayerHit)
DammagePlayer(VSI, Weapon,
PlayerHit, 25, 90.0f, Time);
}
if (Collision.Model)
{
GPlayer
*Target;
#pragma message ("Use: GenVSI_ModelToPlayer...")
Target = (GPlayer*)geWorld_ModelGetUserData(Collision.Model);
if (Target && Target->Trigger &&
(Target->ViewFlags & VIEW_TYPE_PHYSOB))
{
geXForm3d_GetIn(&Player->XForm,
&In);
Player->Inertia =
In;
geVec3d_Scale(&In,
1000.f, &Player->Inertia);
Target->Trigger(VSI,
Target, Player, (void*)&Collision);
}
}
}
Player->VPos = Player->XForm.Translation;
Player->NextWeaponTime = GenVSI_GetTime(VSI) + 1.0f; //fire rate
}
Lastly we need to create a few new functions to make our buckshots spread randomly. Add the following code somewhere
inside of your weapons.c file.
//=====================================================================================
// Random Functions added by Hap
//=====================================================================================
// a random float between 0 and n
float rnd(float n)
{
float x;
x = (float)rand();
x = (x/RAND_MAX) * n;
return x;
}
// a random float between -n and n
float rndSpread (float n)
{
float x;
x = (float)rand();
x = (x/RAND_MAX * 2) - 1;
x = x * n;
return x;
}