[Français]

NEWS
INTRODUCTION
TERMINOLOGY
THE SOURCE CODE
THE BUGS
TUTORIALS
DOWNLOADS
THE AUTHOR

  THE MODS: ADDING A COMMAND TO SPAWN SENTRY GUNS
Written by Christoffer "Eldritch" Lundberg

1.
Make sure you have the source code open in your favourite C/C++ editor/compiler program. Open the file bh_agun.c.

2.
Locate the function void CastSentrygun(void). If it does not exist, you have to create it. If you already have the function, you will only need to edit it. It should look as follows:

void CastSentrygun(void)
{
#define BOTRANGE 2000

VECTORCH position;

if (AvP.Network!=I_No_Network)
{
NewOnScreenMessage("NO SENTRYGUNS IN MULTIPLAYER MODE");
return;
}
position=Player->ObStrategyBlock->DynPtr->Position;
position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
CreateSentrygun(&position, 1);
}
3.
After that, locate the function void CastSentryGun(VECTORCH *Position,int type). If it does not exist, you have to create it. If you already have the function, you will only need to edit it. It should look as follows:
void CreateSentrygun(VECTORCH *Position,int type)
{
STRATEGYBLOCK* sbPtr;
int i;

/* create and initialise a strategy block */
sbPtr = CreateActiveStrategyBlock();
if (!sbPtr)
{
NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
return; /* failure */
}
InitialiseSBValues(sbPtr);
sbPtr->I_SBtype = I_BehaviourAutoGun;
AssignNewSBName(sbPtr);

/* create, initialise and attach a dynamics block */
sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
if (sbPtr->DynPtr)
{
// Get the dynamic block attached to the player & player's Y coordinate:
DYNAMICSBLOCK *PlayerDyn = Player->ObStrategyBlock->DynPtr;
EULER GunEuler = {0, PlayerDyn->OrientEuler.EulerY, 0};

DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
GLOBALASSERT(dynPtr);

// Safety checks...
if (Player==NULL) return;
if (Player->ObStrategyBlock==NULL) return;


dynPtr->PrevPosition = dynPtr->Position = *Position;
dynPtr->OrientEuler = GunEuler; // Orient the Sentry Gun in front of the player
CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
TransposeMatrixCH(&dynPtr->OrientMat);
dynPtr->UseDisplacement=0;

dynPtr->Mass=10000; /* As opposed to 160. */
}
else
{
/* dynamics block allocation failed... */
RemoveBehaviourStrategy(sbPtr);
NewOnScreenMessage("FAILED TO CREATE GUN: DYNBLOCK CREATION FAILURE");
return;
}
sbPtr->shapeIndex = 0;
sbPtr->maintainVisibility = 1;
sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);

/* create, initialise and attach an alien data block */
sbPtr->SBdataptr = (void *)AllocateMem(sizeof(AUTOGUN_STATUS_BLOCK));
if (sbPtr->SBdataptr)
{
SECTION *root_section;
AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->SBdataptr;

/* Initialise sentry gun's stats */
{
NPC_DATA *NpcData;
NpcData=GetThisNpcData(I_NPC_SentryGun);
LOCALASSERT(NpcData);
sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health< sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour< sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
}
agunStatus->behaviourState=I_inactive; // This sets the Sentry Gun inactive until you use it
agunStatus->Target=NULL;
COPY_NAME(agunStatus->Target_SBname,Null_Name);
agunStatus->targetTrackPos.vx=0;
agunStatus->targetTrackPos.vy=0;
agunStatus->targetTrackPos.vz=0;

agunStatus->stateTimer=0;
agunStatus->Gun_Pan=0;
agunStatus->Gun_Tilt=0;
agunStatus->gunpandir=0;
agunStatus->guntiltdir=0;

agunStatus->IAmFar=1;
agunStatus->Firing=0;
agunStatus->Drama=0;
agunStatus->OnTarget=0;
agunStatus->OnTarget_LastFrame=0;
agunStatus->WhirrSoundOn=0;
agunStatus->GunFlash=NULL;
agunStatus->soundHandle=SOUND_NOACTIVEINDEX;
agunStatus->soundHandle2=SOUND_NOACTIVEINDEX;
agunStatus->ammo=500;
agunStatus->roundsFired=0;
agunStatus->volleyFired=0;
agunStatus->incidentFlag=0;
agunStatus->incidentTimer=0;

agunStatus->HModelController.section_data=NULL;
agunStatus->HModelController.Deltas=NULL;
for(i=0;ideath_target_ID[i] =0;
agunStatus->death_target_sbptr=0;
agunStatus->death_target_request=0;

root_section=GetNamedHierarchyFromLibrary("sentry","gun");

if (!root_section)
{
RemoveBehaviourStrategy(sbPtr);
NewOnScreenMessage("FAILED TO CREATE GUN: NO HMODEL");
return;
}
Create_HModel(&agunStatus->HModelController,root_section);
InitHModelSequence(&agunStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED);

{
DELTA_CONTROLLER *delta;

delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0);
GLOBALASSERT(delta);
delta->timer=32767;
delta->Active=0;

delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0);
GLOBALASSERT(delta);
delta->timer=32767;
delta->Active=0;
}

/* Containment test NOW! */
if(!(sbPtr->containingModule))
{
/* no containing module can be found... abort*/
RemoveBehaviourStrategy(sbPtr);
NewOnScreenMessage("FAILED TO CREATE GUN: MODULE CONTAINMENT FAILURE");
return;
}
LOCALASSERT(sbPtr->containingModule);

MakeSentrygunNear(sbPtr);

NewOnScreenMessage("SENTRYGUN LOADED");
}
else
{
/* no data block can be allocated */
RemoveBehaviourStrategy(sbPtr);
NewOnScreenMessage("FAILED TO CREATE GUN: MALLOC FAILURE");
return;
}
if(AvP.Network != I_No_Network)
{
AddNetGameObjectID(sbPtr);
}
}
4.
Close bh_agun.c and open the file gamecmds.cpp. Locate the entry for "XENOBORG". Add a new console command called SENTRYGUNBOT by adding the following lines to the file after the entry for XENOBORG:
ConsoleCommand :: Make
(
"SENTRYGUNBOT",
"CREATES A SENTRY GUN…",
CastSentrygun,
IsACheat
);
5.
Then locate the line extern void CastXenoborg(void); and add the following prototype:
extern void CastSentrygun(void);
6.
Close gamecmds.cpp and open the file winmain.cpp. Locate the line ForceLoad_PredAlien = TRUE. After the entire case-statement, add another one (if it does not already exist) for Sentry Guns:
case 's':
ForceLoad_SentryGun = TRUE;
break;

What have we done now? We have added a new console command for loading Sentry Guns which is only available if we play the game using the -debug parameter. The command is SENTRYGUNBOT. It will spawn a Sentry Gun in front of the player, facing the same way as the player is facing. This, however, won't work in Multiplayer (see below). We have also added a new parameter for force-loading Sentry Guns into our game. To use this, enter the following parameters when loading avp.exe:

-debug -ls

Why won't the Sentry Gun work in Multiplayer then? Well, the reasons are many and too much for an amateur programmer like myself to figure out. When tried, the entire system crashes for all other players except the one who loaded the Sentry Gun. If someone were to figure out why, it would be warmly welcome.

Hope you enjoyed this little tutorial.

Chris