HAM5.5b2 merged in!

Notes:
-There may still be bugs!! (In fact, I almost guarantee it -- there's
-Ammo box code added to HR's crate code
-Splitting a crate/box also automatically refills half empty magazines
-new pathing arrows for map screen not included
-code for scouts to know where enemies are going doesn't appear to work... but i'm not sure it was completed.
-lots of gobledy gook (chinese?) comments turned back to english
-also added Bob's popups
-other languages besides english still need to have there language.cpp files updated with array changes
-AI enhancements by Warmsteel (reloading, suppression, roaming, avoiding gas, and other fixes)

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5181 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
MaddMugsy
2012-04-10 23:45:46 +00:00
parent ab3412e5ed
commit c845f9f117
72 changed files with 10737 additions and 2362 deletions
+12 -13
View File
@@ -50,17 +50,17 @@ static UINT16 CrouchedShootRocketScript[MAX_FRAMES_PER_ANIM] =
{757,1,2,3,4,5,6,7,8,9,10,11,12,470,430,13,14,15,16,477,17,18,19,20,753,499,999,0,0,0,0};
static UINT16 SwatWithKnifeScript[MAX_FRAMES_PER_ANIM] =
//{1,2,3,4,5,6,7,703,8,9,10,11,704,12,13,14,15,16,17,18,19,501,999,0,0,0,0};
{5,703,6,7,8,9,10,11,704,12,13,14,15,16,501,999,0,0,0,0};//òàêàÿ ïîñëåäîâàòåëüíîñòü ïðåäëàãàåòñÿ â äæà2áèí
{5,703,6,7,8,9,10,11,704,12,13,14,15,16,501,999,0,0,0,0};//such a sequence is available in dzha2bin
static UINT16 SwatBackWithKnifeScript[MAX_FRAMES_PER_ANIM] =
{16,15,14,13,12,704,11,10,9,8,7,6,703,5,501,999,0,0,0,0};
static UINT16 SwatBackWithNothingScript[MAX_FRAMES_PER_ANIM] =
{16,15,14,13,12,704,11,10,9,8,7,6,703,5,501,999,0,0,0,0};
//õç, ìîæåò ïîíàäîáèòñÿ ïðàâèòü öèôðû. ñêðèïò êèäàíèÿ ãðàíàò
//xs, may need to edit the numbers. throwing grenades script
static UINT16 ThrowGrenadeStanceAnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,460,11,12,13,14,15,16,17,18,19,442,601,999,0,0,0,0 };
static UINT16 LobGrenadeStanceAnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,460,11,12,13,14,15,16,17,18,19,442,601,999,0,0,0,0 };
//ïåðåêàò
//Rolls
static UINT16 ROLL_L_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,501,999,0,0,0,0 };
static UINT16 ROLL_R_AnimationScript[MAX_FRAMES_PER_ANIM] = { 14,13,12,11,10,9,8,7,6,5,4,3,2,1,501,999,0,0,0,0 };
@@ -1781,10 +1781,10 @@ void InitAnimationSurfacesPerBodytype( )
gubAnimSurfaceIndex[ BIGMALE ][ SWATTING_WK ] = BGMSWKNIFE;
gubAnimSurfaceIndex[ BIGMALE ][ SWAT_BACKWARDS_WK ] = BGMSWKNIFE;
gubAnimSurfaceIndex[ BIGMALE ][ SWAT_BACKWARDS_NOTHING ] = BGMNOTHING_SWAT;
//êèäàíèå ãðàíàòû
//Throwing Grenades
gubAnimSurfaceIndex[ BIGMALE ][ THROW_GRENADE_STANCE ] = BGMSTHRG;
gubAnimSurfaceIndex[ BIGMALE ][ LOB_GRENADE_STANCE ] = BGMSLOBG;
//ïåðåêàò
//Rolling
gubAnimSurfaceIndex[ BIGMALE ][ ROLL_PRONE_L ] = BGMROLL_PR;
gubAnimSurfaceIndex[ BIGMALE ][ ROLL_PRONE_R ] = BGMROLL_PR;
@@ -2182,10 +2182,10 @@ void InitAnimationSurfacesPerBodytype( )
gubAnimSurfaceIndex[ STOCKYMALE ][ SWATTING_WK ] = RGMSWKNIFE;
gubAnimSurfaceIndex[ STOCKYMALE ][ SWAT_BACKWARDS_WK ] = RGMSWKNIFE;
gubAnimSurfaceIndex[ STOCKYMALE ][ SWAT_BACKWARDS_NOTHING ] = RGMNOTHING_SWAT;
//êèäàíèå ãðàíàòû
//Throwing Grenades
gubAnimSurfaceIndex[ STOCKYMALE ][ THROW_GRENADE_STANCE ] = RGMSTHRG;
gubAnimSurfaceIndex[ STOCKYMALE ][ LOB_GRENADE_STANCE ] = RGMSLOBG;
//ïåðåêàò
//Rolling
gubAnimSurfaceIndex[ STOCKYMALE ][ ROLL_PRONE_L ] = RGMROLL_PR;
gubAnimSurfaceIndex[ STOCKYMALE ][ ROLL_PRONE_R ] = RGMROLL_PR;
@@ -2562,10 +2562,10 @@ void InitAnimationSurfacesPerBodytype( )
gubAnimSurfaceIndex[ REGFEMALE ][ SWAT_BACKWARDS_NOTHING ] = RGFNOTHING_SWAT;
gubAnimSurfaceIndex[ REGFEMALE ][ SWATTING_WK ] = RGFSWKNIFE;
gubAnimSurfaceIndex[ REGFEMALE ][ SWAT_BACKWARDS_WK ] = RGFSWKNIFE;
//êèäàíèå ãðàíàòû
//Throwing Grenades
gubAnimSurfaceIndex[ REGFEMALE ][ THROW_GRENADE_STANCE ] = RGFSTHRG;
gubAnimSurfaceIndex[ REGFEMALE ][ LOB_GRENADE_STANCE ] = RGFSLOBG;
//ïåðåêòà
//Rolling
gubAnimSurfaceIndex[ REGFEMALE ][ ROLL_PRONE_L ] = RGFROLL_PR;
gubAnimSurfaceIndex[ REGFEMALE ][ ROLL_PRONE_R ] = RGFROLL_PR;
@@ -3247,8 +3247,7 @@ BOOLEAN LoadAnimationStateInstructions( )
return( FALSE );
}
//ddd ïàòàìóøòà âûëåòàåò ïðè ïðåâûøåíèè 320 çíà÷åíèÿ ;(
//ïðèäåòñÿ ìàñòåðèòü âñïîìîãàòåëüíûé ìàññèâ, ïîòîì êîïèðîâàòü åãî ñîäåðæèìîå â ãóñàíèìèíñò
//ddd Trick for loading more than 320 animation files (?)
UINT16 fuckTheBoundz[320][100];
//Read in block
@@ -3265,7 +3264,7 @@ BOOLEAN LoadAnimationStateInstructions( )
memcpy(gusAnimInst[i],fuckTheBoundz[i],sizeof(fuckTheBoundz[i]));
//gusAnimInst[i][0] = fuckTheBoundz[i][0];
//! äëÿ ïåðåãîíêè äæà2áèí â ÷èòàåìûé âèä
// For conversion into readable format (?)
// char gS[22];
// UINT32 uiNumBytesWritten = 64000;
// int ggg[MAX_ANIMATIONS][MAX_FRAMES_PER_ANIM];
@@ -3837,7 +3836,7 @@ UINT16 DetermineSoldierAnimationSurface( SOLDIERTYPE *pSoldier, UINT16 usAnimSta
if ( usAltAnimSurface != INVALID_ANIMATION )
{
//ddd{ ñþäà ñòàâèòü àëüòåðíàòèâíóþ àíèìàøêó äëÿ âûñòðåëà èç ïèñòîëåòà
//ddd Put alternative pistol-shot animations here
/*if ( usAnimSurface == BGMSTANDAIM2 )
{
+3 -3
View File
@@ -7,7 +7,7 @@
// Defines
// #######################################################
#define MAX_ANIMATIONS 350 //!!!!!ddd ïîêà äîáàâèë 30 ëèøíèõ ñëîâòîâ ïîä àíèìàøêè.
#define MAX_ANIMATIONS 350 //!!!!!ddd added 30 new animations
#define MAX_FRAMES_PER_ANIM 100
#define MAX_RANDOM_ANIMS_PER_BODYTYPE 8
@@ -548,9 +548,9 @@ enum AnimationStates
SWATTING_WK,
SWAT_BACKWARDS_WK,
SWAT_BACKWARDS_NOTHING,
THROW_GRENADE_STANCE, //ddd äëÿ áàáû àíèìàöèè íåò - èñïîëüçóåì ñòàíäàðòíóþ
THROW_GRENADE_STANCE, //ddd Currently no animation for women. Using the standard.
LOB_GRENADE_STANCE,
//ïåðåêàòòû
//Prone rolls
ROLL_PRONE_R,
ROLL_PRONE_L,
+3 -3
View File
@@ -518,15 +518,15 @@ BGMWITHSTONE,
BGMSWKNIFE,
RGFSWKNIFE,
RGMSWKNIFE,
//êèäàíèå ãðàíàòû ñòîÿ ñ âûä. ÷åêè
//Launch grenade (?)
BGMSTHRG,
RGFSTHRG,
RGMSTHRG,
//êèäàíèå ãðàíàòû ñòîÿ ñ âûä. ÷åêè áëèçêîå ðàññò
//Lob grenade
BGMSLOBG,
RGFSLOBG,
RGMSLOBG,
//âíàãëóþ ñòûðèë êîä ó òåðàïåâòà!
//Roll while prone
RGMROLL_PR,
BGMROLL_PR,
RGFROLL_PR,
+5
View File
@@ -57,6 +57,7 @@ typedef struct
UINT8 ubTilesPerUpdate;
UINT16 usClockTicksPerUpdate;
SOLDIERTYPE *pFirer;
INT32 sOrigGridNo; // HEADROCK HAM 5.1: Original tile does not necessarily have to be the pFirer's tile
INT32 sTargetGridNo;
INT16 sHitBy;
INT32 iImpact;
@@ -73,6 +74,8 @@ typedef struct
// the bullet animation functions to create a lightpath for this bullet. This means now all bullets in a tracer
// magazine will cause a lightshow (that's the intended result).
BOOLEAN fTracer;
// HEADROCK HAM 5: Fragments. They are handled slightly differently by the bullet functions.
BOOLEAN fFragment;
} BULLET;
extern UINT32 guiNumBullets;
@@ -82,6 +85,8 @@ void RemoveBullet( INT32 iBullet );
void StopBullet( INT32 iBullet );
void UpdateBullets( );
BULLET *GetBulletPtr( INT32 iBullet );
INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iImpact, INT16 sHitBy, UINT8 * pubSpecial );
void DeleteAllBullets( );
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+44
View File
@@ -169,6 +169,19 @@ public:
OBJECTTYPE ItemPointerInfo;
};
// HEADROCK HAM 5: Enums for big-item display attachment asterisks.
enum
{
ATTACHMENT_NONE,
ATTACHMENT_GENERAL,
ATTACHMENT_GL,
ATTACHMENT_RECOILREDUCTION,
ATTACHMENT_OPTICAL,
};
// HEADROCK HAM 5: Asterisks for use with big item images
extern UINT32 guiAttachmentAsterisks;
// Itempickup stuff
BOOLEAN InitializeItemPickupMenu( SOLDIERTYPE *pSoldier, INT32 sGridNo, ITEM_POOL *pItemPool, INT16 sScreenX, INT16 sScreenY, INT8 bZLevel );
void RenderItemPickupMenu( );
@@ -211,6 +224,8 @@ BOOLEAN HandleCompatibleAmmoUI( SOLDIERTYPE *pSoldier, INT8 bInvPos, BOOLEAN fOn
void RenderBulletIcon(OBJECTTYPE *pObject, UINT32 ubStatusIndex = 0);
void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObject, INT16 sX, INT16 sY, INT16 sWidth, INT16 sHeight, UINT8 fDirtyLevel, UINT8 *pubHighlightCounter, UINT8 ubStatusIndex, BOOLEAN fOutline, INT16 sOutlineColor, UINT8 iter = 0 );
// HEADROCK HAM 5: Drawing a large item pic with extra data.
void MAPINVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObject, UINT32 uiItemGraphicNum, INT16 sX, INT16 sY, INT16 sWidth, INT16 sHeight, BOOLEAN fOutline, INT16 sOutlineColor );
// CHRISL: Add a new function that will be used to render a pocket silhouette
void INVRenderSilhouette( UINT32 uiBugger, INT16 PocketIndex, INT16 SilIndex, INT16 sX, INT16 sY, INT16 sWideth, INT16 sHeight);
// CHRISL: New function to handle display of inventory quantities based on item current in cursor
@@ -313,7 +328,36 @@ extern INT32 giActiveAttachmentPopup; // the attachment popup to display in maps
extern POPUP* gEquipPopups[NUM_INV_SLOTS]; // popup list for attachment slots
extern INT32 giActiveEquipPopup; // the attachment popup to display in mapscreen
// HEADROCK HAM 5: Item Transformation Popup
extern POPUP* gItemDescTransformPopup;
extern BOOLEAN gfItemDescTransformPopupInitialized;
extern BOOLEAN gfItemDescTransformPopupVisible;
// BOB : duh...
void DoAttachment( UINT8 subObject, INT32 iItemPos );
// THE_BOB (AKA BOB): ammo box/mag popups
void PocketPopupFull( SOLDIERTYPE *pSoldier, INT16 sPocket ); // displays all suported options
void PocketPopupDefault( SOLDIERTYPE *pSoldier, INT16 sPocket ); // displays only pocket-specific (predefined) options
POPUP * createPopupForPocket( SOLDIERTYPE *pSoldier, INT16 sPocket ); // creates a popup positioned next to the pocket
// THE_BOB
extern UINT16 gsPocketUnderCursor;
void addArmorToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addLBEToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addWeaponsToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addWeaponGroupsToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addGrenadesToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addBombsToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addFaceGearToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addAmmoToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addRifleGrenadesToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addRocketAmmoToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addMiscToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
void addKitsToPocketPopup( SOLDIERTYPE *pSoldier, INT16 sPocket, POPUP* popup );
#endif
+9 -1
View File
@@ -2531,7 +2531,15 @@ void RenderSMPanel( BOOLEAN *pfDirty )
}
}
RenderItemDescriptionBox( );
// HEADROCK HAM 5: Test for active Transform Popup
if (gfItemDescTransformPopupVisible)
{
gItemDescTransformPopup->show();
}
else
{
RenderItemDescriptionBox( );
}
}
else
{
+12
View File
@@ -545,4 +545,16 @@ void RenderSoldierFace( SOLDIERTYPE *pSoldier, INT16 sFaceX, INT16 sFaceY, BOOLE
}
// HEADROCK HAM 5: This function draws a rectangle around the item image in the zoomed inventory
void DrawItemOutlineZoomedInventory( INT16 sX, INT16 sY, INT16 sWidth, INT16 sHeight, INT16 sColor, UINT32 uiBuffer )
{
UINT32 uiDestPitchBYTES;
UINT8 *pDestBuf;
pDestBuf = LockVideoSurface( uiBuffer, &uiDestPitchBYTES );
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
RectangleDraw( TRUE, sX, sY, sWidth, sHeight, sColor, pDestBuf );
UnLockVideoSurface( uiBuffer );
}
+3
View File
@@ -23,5 +23,8 @@ BOOLEAN LoadCarPortraitValues( void );
// get rid of the loaded portraits for cars
void UnLoadCarPortraits( void );
// HEADROCK HAM 5: Helper for zoomed inventory
void DrawItemOutlineZoomedInventory( INT16 sX, INT16 sY, INT16 sWidth, INT16 sHeight, INT16 sColor, UINT32 uiBuffer );
#endif
+1
View File
@@ -128,6 +128,7 @@ void DestroyLBE(OBJECTTYPE* pObj)
void MoveItemsInSlotsToLBE( SOLDIERTYPE *pSoldier, std::vector<INT8>& LBESlots, LBENODE* pLBE, OBJECTTYPE* pObj)
{
for(unsigned int i=0; i<LBESlots.size(); i++) // Go through default pockets one by one
{
if(pSoldier->inv[LBESlots[i]].exists() == false) // No item in this pocket
+37
View File
@@ -4,6 +4,9 @@
#include "types.h"
#include <vector>
#include <list>
// THE_BOB : added for pocket popup definitions
#include <map>
#include "popup_definition.h"
//if the number of slots are ever changed, the loading / saving checksum should use this value to make conversion easier
#define NUM_ORIGINAL_INV_SLOTS 19
@@ -264,6 +267,20 @@ extern std::list<LBENODE> LBEArray;
#define OLD_MAX_ATTACHMENTS_101 4
#define OLD_MAX_OBJECTS_PER_SLOT_101 8
// HEADROCK HAM 5: Define Self-Transformations
// Have to define this early on, because this struct is used in OBJECTTYPE
#define MAX_NUM_TRANSFORMATION_RESULTS 10
typedef struct
{
UINT16 usItem;
UINT16 usResult[MAX_NUM_TRANSFORMATION_RESULTS];
UINT16 usAPCost;
INT32 iBPCost;
CHAR16 szMenuRowText[50];
CHAR16 szTooltipText[300];
} TransformInfoStruct;
namespace Version101
{
//union was originally unnamed
@@ -526,6 +543,8 @@ public:
BOOLEAN AttachObjectOAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound = TRUE, UINT8 subObject = 0);
BOOLEAN AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound = TRUE, UINT8 subObject = 0, INT32 iItemPos = -1, BOOLEAN fRemoveProhibited = TRUE, std::vector<UINT16> usAttachmentSlotIndexVector = std::vector<UINT16>());
BOOLEAN RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNewObj = NULL, UINT8 subObject = 0, SOLDIERTYPE * pSoldier = NULL, BOOLEAN fForceInseperable = FALSE, BOOLEAN fRemoveProhibited = TRUE);
// HEADROCK HAM 5: Object Transformation
BOOLEAN TransformObject( SOLDIERTYPE * pSoldier, UINT8 ubStatusIndex, TransformInfoStruct * Transform, OBJECTTYPE *pParent );
//see comments in .cpp
static void DeleteMe(OBJECTTYPE** ppObject);
@@ -590,6 +609,17 @@ extern OBJECTTYPE gTempObject;
#define IC_BOBBY_GUN ( IC_GUN | IC_LAUNCHER )
#define IC_BOBBY_MISC ( IC_GRENADE | IC_BOMB | IC_MISC | IC_MEDKIT | IC_KIT | IC_BLADE | IC_THROWING_KNIFE | IC_PUNCH | IC_FACE | IC_LBEGEAR )
// HEADROCK HAM 5: Inventory Filter Types
#define IC_MAPFILTER_GUN ( IC_GUN | IC_LAUNCHER )
#define IC_MAPFILTER_AMMO ( IC_AMMO )
#define IC_MAPFILTER_EXPLOSV ( IC_GRENADE | IC_BOMB )
#define IC_MAPFILTER_MELEE ( IC_BLADE | IC_PUNCH | IC_THROWN | IC_THROWING_KNIFE )
#define IC_MAPFILTER_KIT ( IC_KIT | IC_MEDKIT | IC_APPLIABLE )
#define IC_MAPFILTER_LBE ( IC_LBEGEAR | IC_BELTCLIP )
#define IC_MAPFILTER_ARMOR ( IC_ARMOUR | IC_FACE )
#define IC_MAPFILTER_MISC ( IC_TENTACLES | IC_KEY | IC_MISC | IC_MONEY | IC_NONE )
#define IC_MAPFILTER_ALL ( IC_MAPFILTER_GUN | IC_MAPFILTER_AMMO | IC_MAPFILTER_EXPLOSV | IC_MAPFILTER_MELEE | IC_MAPFILTER_KIT | IC_MAPFILTER_LBE | IC_MAPFILTER_ARMOR | IC_MAPFILTER_MISC )
// Chrisl: Define attachment classes
#define AC_DEFAULT1 0x00000001 //1
#define AC_BARREL 0x00000002 //2
@@ -904,6 +934,10 @@ public:
};
#define SIZEOF_POCKETTYPE offsetof( POCKETTYPE, POD )
extern std::vector<POCKETTYPE> LBEPocketType;
// THE_BOB : added for pocket popup definitions
extern std::map<UINT8,popupDef> LBEPocketPopup;
typedef enum ePOCKET_TYPE
{
NO_POCKET_TYPE = 0,
@@ -1445,6 +1479,9 @@ typedef struct
UINT32 uiIndex;
} ComboMergeInfoStruct;
// HEADROCK HAM 5: Defining this here because we need MAXITEMS. The struct is defined earlier.
extern TransformInfoStruct Transform[MAXITEMS+1];
extern ComboMergeInfoStruct AttachmentComboMerge[MAXITEMS+1];
BOOLEAN EXPLOSIVE_GUN(UINT16 x );
+384 -19
View File
@@ -55,6 +55,9 @@
#include "debug control.h"
#include "math.h"
// THE_BOB : added for pocket popup definitions
#include <map>
#include "popup_definition.h"
#endif
#ifdef JA2UB
@@ -72,9 +75,19 @@ class SOLDIERTYPE;
void SetNewItem( SOLDIERTYPE *pSoldier, UINT8 ubInvPos, BOOLEAN fNewItem );
extern SOLDIERTYPE *gpItemDescSoldier;
// HEADROCK HAM 5: We need access to these values for item transformation purposes
extern BOOLEAN gfItemDescObjectIsAttachment;
extern OBJECTTYPE *gpItemDescObject;
extern OBJECTTYPE *gpItemDescPrevObject;
extern OBJECTTYPE *gpItemDescOrigAttachmentObject;
extern OBJECTTYPE gCloneItemDescObject;
extern BOOLEAN fShowMapInventoryPool;
extern UINT32 guiCurrentItemDescriptionScreen;
extern BOOLEAN AutoPlaceObjectInInventoryStash( OBJECTTYPE *pItemPtr, INT32 sGridNo );
// HEADROCK HAM 5: Also need these to trigger Map Inventory changes appropriately.
extern BOOLEAN fMapInventoryZoom;
// HEADROCK HAM 5: And this, for checking whether an item is in the pool.
extern std::vector<WORLDITEM> pInventoryPoolList;
UINT16 OldWayOfCalculatingScopeBonus(SOLDIERTYPE *pSoldier);
// weight units are 100g each
@@ -1154,6 +1167,8 @@ ComboMergeInfoStruct AttachmentComboMerge[MAXITEMS+1];// =
// {NOTHING, {NOTHING, NOTHING}, NOTHING },
//};
// HEADROCK HAM 5: Item Transformations table, containing all possible Transformations.
TransformInfoStruct Transform[MAXITEMS+1];
UINT16 IncompatibleAttachments[MAXATTACHMENTS][2];// =
//{
@@ -1223,6 +1238,9 @@ std::vector<LBETYPE> LoadBearingEquipment;
std::vector<POCKETTYPE> LBEPocketType;
//TODO make the indices of this a define, because I do not know what is a large pocket (I guess 3)
// THE_BOB : added for pocket popup definitions
std::map<UINT8,popupDef> LBEPocketPopup;
//POCKETTYPE LBEPocketType[MAXITEMS+1]; //=
//{
// { /* Blank Entry */ 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
@@ -4761,7 +4779,8 @@ BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttac
//WarmSteel - Replaced this with one that also checks default attachments, otherwise you could not replace built-in bonuses with default inseperable attachments.
//RemoveProhibitedAttachments(pSoldier, this, usResult);
ReInitMergedItem(pSoldier, this, usOldItem);
// HEADROCK HAM 5: Added argument for statusindex.
ReInitMergedItem(pSoldier, this, usOldItem, 0);
//AutoPlaceObject( pAttachment );
//ADB ubWeight has been removed, see comments in OBJECTTYPE
@@ -4866,7 +4885,7 @@ BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttac
//WarmSteel - Replaced this with one that also checks default attachments, otherwise you could not replace built-in bonuses with default inseperable attachments.
//RemoveProhibitedAttachments(pSoldier, this, usResult);
ReInitMergedItem(pSoldier, this, usOldItem);
ReInitMergedItem(pSoldier, this, usOldItem, 0);
}
break;
@@ -4923,7 +4942,8 @@ BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttac
//WarmSteel - Replaced this with one that also checks default attachments, otherwise you could not replace built-in bonuses with default inseperable attachments.
//RemoveProhibitedAttachments(pSoldier, this, usResult);
ReInitMergedItem(pSoldier, this, usOldItem);
// HEADROCK HAM 5: Added argument for statusindex.
ReInitMergedItem(pSoldier, this, usOldItem, subObject);
if ( ubType != TREAT_ARMOUR )
{
@@ -5296,7 +5316,9 @@ void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16
//WarmSteel - Needed for merges, because the new items don't get their new default attachments.
//This does the same as RemoveProhibitedAttachments but is a bit more thorough at it.
//This is at the risk that items move around if more than one slot is valid, but since this is used for "new" guns after merges, that's acceptable.
void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem){
// HEADROCK HAM 5: Added argument for statusindex.
void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem, UINT8 ubStatusIndex)
{
attachmentList tempAttachList;
attachmentList tempSlotChangingAttachList;
@@ -5304,18 +5326,18 @@ void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem)
UINT8 slotCount;
std::vector<UINT16> usAttachmentSlotIndexVector = GetItemSlots(pObj);
if( !(*pObj)[0]->attachments.empty() ){
if( !(*pObj)[ubStatusIndex]->attachments.empty() ){
//Have to take all attachments off, because of possible incompatibilities with the default attachments (can't NOT attach a default attachment because some stupid item already attached is incompatible with it).
//Delete all default inseperable attachments from the old gun.
//This is safe UNLESS the inseparable default attachments is not the only attachment of the same kind on the gun.
//I can't think of any reason why this would happen, and if it does the worst that can happen is your attachment disappearing.
for(slotCount = 0; slotCount < (*pObj)[0]->attachments.size(); slotCount++){
UINT16 usAttach = (*pObj)[0]->GetAttachmentAtIndex(slotCount)->usItem;
for(slotCount = 0; slotCount < (*pObj)[ubStatusIndex]->attachments.size(); slotCount++){
UINT16 usAttach = (*pObj)[ubStatusIndex]->GetAttachmentAtIndex(slotCount)->usItem;
if(Item[usAttach].inseparable){
for(UINT16 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS && Item[usOldItem].defaultattachments[cnt] != 0; cnt++){
if(Item[usOldItem].defaultattachments[cnt] == usAttach){
(*pObj)[0]->RemoveAttachmentAtIndex(slotCount);
(*pObj)[ubStatusIndex]->RemoveAttachmentAtIndex(slotCount);
break;
}
}
@@ -5323,36 +5345,38 @@ void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem)
}
slotCount = 0;
//Put all other attachments into a temporary storage, so we can try to re-attach later.
for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); iter++, slotCount++) {
for(attachmentList::iterator iter = (*pObj)[ubStatusIndex]->attachments.begin(); iter != (*pObj)[ubStatusIndex]->attachments.end(); iter++, slotCount++) {
if(iter->exists()){
UINT16 cnt = 0;
tempAttachList.push_back((*iter));
}
}
}
//clear the attachment list, we've saved the attachments somewhere safe now.
(*pObj)[0]->attachments.clear();
(*pObj)[ubStatusIndex]->attachments.clear();
//Make sure the attachment slot data is correct.
//std::vector<UINT16> tempItemSlots = GetItemSlots(pObj);
(*pObj)[0]->attachments.resize(usAttachmentSlotIndexVector.size());
(*pObj)[ubStatusIndex]->attachments.resize(usAttachmentSlotIndexVector.size());
//pObj->usAttachmentSlotIndexVector = tempItemSlots;
//Now add all default attachments, but add them with the same status as the gun. We don't want to make repairing guns easy :)
for(UINT16 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS && Item[pObj->usItem].defaultattachments[cnt] != 0; cnt++){
//Only add inseparable default attachments, because they are likely "part" of the gun.
if(Item[Item[pObj->usItem].defaultattachments[cnt]].inseparable){
static OBJECTTYPE defaultAttachment;
CreateItem(Item [ pObj->usItem ].defaultattachments[cnt],(*pObj)[0]->data.objectStatus,&defaultAttachment);
AssertMsg(pObj->AttachObject(NULL,&defaultAttachment, FALSE, 0, -1, FALSE), "A default attachment could not be attached after merging, this should not be possible.");
CreateItem(Item [ pObj->usItem ].defaultattachments[cnt],(*pObj)[ubStatusIndex]->data.objectStatus,&defaultAttachment);
AssertMsg(pObj->AttachObject(NULL,&defaultAttachment, FALSE, ubStatusIndex, -1, FALSE), "A default attachment could not be attached after merging, this should not be possible.");
}
}
//First re-attach any slot-changing attachments.
for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end();) {
if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE )){
if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, ubStatusIndex )){
//This seems to be rather valid. Can't be 100% sure though.
if(pObj->AttachObject(NULL, &(*iter), FALSE)){
if(pObj->AttachObject(NULL, &(*iter), FALSE, ubStatusIndex)){
//Ok now we can be sure, lets remove this object so we don't try to drop it later.
iter = tempSlotChangingAttachList.erase(iter);
} else {
@@ -5365,9 +5389,9 @@ void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem)
//Time to re-attach the other attachments, if we can. I am the king of copy pasta.
for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) {
if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE)){
if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, ubStatusIndex)){
//This seems to be rather valid. Can't be 100% sure though.
if(pObj->AttachObject(NULL, &(*iter), FALSE)){
if(pObj->AttachObject(NULL, &(*iter), FALSE, ubStatusIndex)){
//Ok now we can be sure, lets remove this object so we don't try to drop it later.
iter = tempAttachList.erase(iter);
} else {
@@ -5385,7 +5409,9 @@ void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem)
if (pSoldier) {
if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) )
{ // put it on the ground
AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 );
// HEADROCK HAM 5: A much more suitable function. Works in both tactical and mapscreen!
AutoPlaceObjectToWorld( pSoldier, &(*iter), true );
//AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 );
}
}
}
@@ -5397,11 +5423,14 @@ void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem)
if (pSoldier) {
if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) )
{ // put it on the ground
AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 );
// HEADROCK HAM 5: A much more suitable function. Works in both tactical and mapscreen!
AutoPlaceObjectToWorld( pSoldier, &(*iter), true );
//AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 );
}
}
}
}
}
void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT8 subObject)
@@ -12597,3 +12626,339 @@ FLOAT GetItemCooldownFactor( OBJECTTYPE * pObj )
return cooldownfactor;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 5: Item Transformation.
// Item Transformation is a new way to interact with items. Where Merges combine two items into one, a Transformation
// can turn one item into another item, or into more than one item.
// To instigate a Transformation, the player uses a menu to choose the desired effect. Then the program comes here to
// see how it's done.
// The instructions for performing a specific transformation are drawn from XML and fed into this function as a pointer.
// They tell us what items will result from this transformation, as well as the APBP cost.
BOOLEAN OBJECTTYPE::TransformObject( SOLDIERTYPE * pSoldier, UINT8 ubStatusIndex, TransformInfoStruct * Transform, OBJECTTYPE *pParent )
{
// The argument "Transform" is a pointer to an entry in the Transformation Data array. By looking at the pointer we
// can determine all the data we need. Therefore, this pointer must not be null!
AssertMsg( Transform != NULL, String( "OBJECTTYPE::TransformObject attempt with invalid Transformation data." ) );
// Booleans to track what happened during the transformation.
BOOLEAN fSplit = FALSE;
BOOLEAN fDropped = FALSE;
BOOLEAN fRemoved = FALSE;
BOOLEAN fItemInPool = FALSE;
// This boolean tracks whether we've managed to place an item in a soldier's inventory.
BOOLEAN fFoundPlaceInInventory = FALSE;
// Constants for storing details about the original item.
OBJECTTYPE TempItem;
UINT16 usOrigItem = this->usItem;
UINT32 uiOrigClass = Item[this->usItem].usItemClass;
UINT8 ubOrigNumObjects = this->ubNumberOfObjects;
UINT16 usAPCost = 0;
INT32 iBPCost = 0;
// An array to store all result items.
UINT16 usResult[MAX_NUM_TRANSFORMATION_RESULTS];
UINT32 iNumResults = 0;
// Start reading transformation data with APBP costs.
usAPCost = Transform->usAPCost;
iBPCost = Transform->iBPCost;
// Check whether our soldier can afford this transformation!
if (!EnoughPoints( pSoldier, (INT16)usAPCost, iBPCost, true ))
{
return false;
}
else
{
// Soldier can afford the transformation. Deduct APBP as necessary.
DeductPoints( pSoldier, (INT16)usAPCost, iBPCost, false );
}
// Read all result items for this transformation. Record them into an array.
for (UINT32 curResult = 0; curResult < MAX_NUM_TRANSFORMATION_RESULTS; curResult++)
{
if (Transform->usResult[curResult] > 0)
{
usResult[curResult] = Transform->usResult[curResult];
// Count the number of valid result items
iNumResults++;
}
}
// If there are no result items, the Transformation is illegal - we need at least one resulting item!
AssertMsg( iNumResults, String( "OBJECTTYPE::TransformObject attempting to transform an object which has no resulting items defined!" ) );
if (iNumResults > 1)
{
fSplit = TRUE;
}
// Play a gun-cocking sound, it's the best one we've got ATM.
PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
// Before we continue, lets check whether our object is in the sector inventory.
// Is the sector inventory open?
if (fShowMapInventoryPool)
{
// Is our object currently in the pool?
for (UINT32 x = 0; x < pInventoryPoolList.size(); x++)
{
if (pInventoryPoolList[x].object.exists())
{
if (&(pInventoryPoolList[x].object) == this)
{
// Aha! In that case, all transformations will be done directly at the sector pool,
// with multiple results ending on the ground rather than in the inventory.
fItemInPool = TRUE;
break;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// The Transformation itself
////////////////////////////////////////////////////////////////////////////////////////////////////
// We're going to do the transformation in steps, going hierarchially down from the item's own attachments,
// to itsself, then its parents, and finally resulting items and unrelated inventory.
// Note that we'll need to change the item's usItem property several times during this process, so lets
// record its original usItem now.
UINT16 usOldItem = this->usItem;
// STEP 1: Attachments and subsidiary objects.
// First of all, if the original item is a gun, we'll need to see if it can hold the same magazine after the
// transformation. If it can't, the magazine will be ejected immediately into the soldier's inventory.
// Is this a gun, AND does it have any ammo loaded?
if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[ubStatusIndex]->data.gun.usGunAmmoItem != NONE && (*this)[ubStatusIndex]->data.gun.ubGunShotsLeft > 0 )
{
// Is the resulting item not a gun, OR is the resulting item of a different caliber, OR is the resulting item's
// magazine too small?
if ( Item[usResult[0]].usItemClass != IC_GUN || Weapon[Item[usResult[0]].ubClassIndex].ubCalibre != Weapon[Item[this->usItem].ubClassIndex].ubCalibre || (*this)[ubStatusIndex]->data.gun.ubGunShotsLeft > Weapon[Item[usResult[0]].ubClassIndex].ubMagSize )
{
// item types/calibers/magazines don't match, spit out old ammo
EjectAmmoAndPlace(pSoldier, this);
}
}
// STEP 2: Check the item's attachments to see whether they still fit.
// We'll have to fool this function into thinking we've already changed the item.
// Note that this function automatically drops invalid attachments to the ground.
this->usItem = usResult[0];
// Repeat for each object in the stack.
for ( UINT8 x = 0; x < this->ubNumberOfObjects; x++ )
{
ReInitMergedItem(pSoldier, this, usOldItem, x);
}
this->usItem = usOldItem;
//RemoveProhibitedAttachments(pSoldier, this, usOldItem);
///////////////////////////////////////////////////////////////
// TRANSFORM
this->usItem = usResult[0];
// Record the new itemclass
UINT32 uiNewClass = Item[this->usItem].usItemClass;
// Make a clone of this object, so that we can point the DescBox to it later if we run into any problems.
gCloneItemDescObject = *(this);
///////////////////////////////////////////////////////////////
////////////////////
// Placement checks
// Is the item an attachment? If so, check its parent to see if it's still compatible.
if (pParent != NULL)
{
// When transforming an attachment, "THIS" is actually a copy of the object, called Object2. So transforming
// "this" would only yield, at most, a superficial change (Description Box will change). The attachment item
// itself will not change at all.
// Lets change the attachment item directly, then.
gpItemDescOrigAttachmentObject->usItem = usResult[0];
// Make a copy of it, so we know what data it contained.
OBJECTTYPE pClone = *gpItemDescOrigAttachmentObject;
// Test the parent now. See whether all attachments are still valid on it.
ReInitMergedItem(pSoldier, pParent, pParent->usItem, ubStatusIndex);
gpItemDescOrigAttachmentObject = NULL;
// After reiniting the attachments on the parent, "this" still exists, but the actual object is gone.
// Lets look through the parent's attachments list, and see if we can find it again.
UINT8 ubNewAttachmentsIndex = 0;
for(attachmentList::iterator iter = (*pParent)[ubStatusIndex]->attachments.begin(); iter != (*pParent)[ubStatusIndex]->attachments.end(); iter++, ubNewAttachmentsIndex++)
{
if(iter->exists())
{
// Compare it to the clone we made earlier.
if (*(iter) == pClone)
{
// Yes, here it is!
gpItemDescOrigAttachmentObject = (*pParent)[ubStatusIndex]->GetAttachmentAtIndex( ubNewAttachmentsIndex );
break;
}
}
}
// Have we failed to find our item on the reinited parent?
if (gpItemDescOrigAttachmentObject == NULL)
{
// It has been removed. Lets reset all the Description Box extra variables.
// Note that by doing this, we actually trigger closing the description box later down the line.
pParent = NULL;
gfItemDescObjectIsAttachment = NULL;
gpItemDescPrevObject = NULL;
fRemoved = TRUE;
}
}
// Our object is not an attachment. If it is on a soldier, it may still not fit in the pocket where
// it is currently placed, so lets see if we have to move it.
else if (!fItemInPool)
{
for (INT8 bPocket = HELMETPOS; bPocket < NUM_INV_SLOTS; bPocket++)
{
if (&(pSoldier->inv[bPocket]) == this)
{
// Found our item. Does it fit in this slot?
if (!CanItemFitInPosition(pSoldier, this, bPocket, FALSE) )
{
if (!AutoPlaceObject( pSoldier, this, TRUE ))
{
fDropped = TRUE;
AutoPlaceObjectToWorld( pSoldier, this, TRUE );
//Unfortunately the above function will not erase the item in tactical mode, so lets
//double-check.
if (pSoldier->inv[bPocket].exists() )
{
DeleteObj( &(pSoldier->inv[bPocket]) );
}
}
// Whatever we've done with it, THIS is no longer a valid item, so lets
// fool the desc box by switching it with the clone.
gpItemDescObject = &gCloneItemDescObject;
}
break;
}
}
}
// If either the new or old items were LBEs, lets check the entire LBE inventory for item-size compatibility!
//if (uiOrigClass & IC_LBEGEAR || uiNewClass & IC_LBEGEAR )
if (!fItemInPool)
{
for (INT8 bPocket = HELMETPOS; bPocket < NUM_INV_SLOTS; bPocket++)
{
if (pSoldier->inv[bPocket].exists())
{
// Found an item. Does it still fit inside its own slot?
if (!CanItemFitInPosition(pSoldier, &(pSoldier->inv[bPocket]), bPocket, FALSE) )
{
if (!AutoPlaceObject( pSoldier, &(pSoldier->inv[bPocket]), TRUE ))
{
fDropped = TRUE;
AutoPlaceObjectToWorld( pSoldier, &(pSoldier->inv[bPocket]), TRUE );
//Unfortunately the above function will not erase the item in tactical mode, so lets
//double-check.
if (pSoldier->inv[bPocket].exists() )
{
DeleteObj( &(pSoldier->inv[bPocket]) );
}
}
}
}
}
}
//////////////////////////////
// Multiple Results
//
// If the item has several transformation results defined, that means we're going to split it into two or
// more items.
// We actually start with any results above the first. This occurs if the item is split into two or more other
// items. We'll try to place them in the pSoldier's inventory if possible, otherwise they are dumped to the
// sector pool.
// Iterate through the results array we've constructed earlier.
for (UINT32 x = 1; x < iNumResults; x++)
{
for (UINT32 y = 0; y < ubOrigNumObjects; y++)
{
// Create the result item. Set its condition to match that of the original.
CreateItem( usResult[x], (*this)[ubStatusIndex]->data.objectStatus, &gTempObject );
if (!fItemInPool)
{
// Try placing it in the soldier's invnetory.
if (!AutoPlaceObject( pSoldier, &gTempObject, TRUE ))
{
// Failed to find a place in the inventory. Dump to sector pool.
AutoPlaceObjectToWorld( pSoldier, &gTempObject, true );
fDropped = TRUE;
}
}
else
{
AutoPlaceObjectToWorld( pSoldier, &gTempObject, true );
}
// Cleanup after the autoplace has to occur in tactical mode.
if (gTempObject.exists())
{
DeleteObj( &(gTempObject) );
}
}
}
// Check the soldier to see how his stats have changed as a result of altering his gear.
ApplyEquipmentBonuses(pSoldier);
if (fItemInPool && fSplit)
{
CHAR16 pStr[500];
// Item was split apart. Since it was in the sector inventory, it's common sense that all results
// are in the sector inventory as well, so no need to report anything extra.
swprintf( pStr, gzTransformationMessage[ 1 ], Item[usOrigItem].szItemName, pSoldier->name );
ScreenMsg( FONT_ORANGE, MSG_INTERFACE, pStr );
}
else if (fSplit || fDropped)
{
CHAR16 pStr[500];
if (fSplit && !fDropped)
{
// Item was split apart, but all subitems remained in the inventory.
swprintf( pStr, gzTransformationMessage[ 2 ], Item[usOrigItem].szItemName, pSoldier->name );
ScreenMsg( FONT_ORANGE, MSG_INTERFACE, pStr );
}
else if (fDropped && !fSplit)
{
// Either the item itself or another item has been dropped to the sector inventory due to lack of
// space.
swprintf( pStr, gzTransformationMessage[ 3 ], pSoldier->name );
DoScreenIndependantMessageBox( pStr, MSG_BOX_FLAG_OK, NULL );
}
else if (fDropped && fSplit)
{
// Item was split apart. Either the item itself or another item has been dropped to the sector
// inventory due to lack of space.
swprintf( pStr, gzTransformationMessage[ 4 ], Item[usOrigItem].szItemName, pSoldier->name );
DoScreenIndependantMessageBox( pStr, MSG_BOX_FLAG_OK, NULL );
}
}
// Signal a successful transformation.
return TRUE;
}
+2 -1
View File
@@ -111,7 +111,8 @@ void RemoveInvObject( SOLDIERTYPE *pSoldier, UINT16 usItem );
void InitItemAttachments(OBJECTTYPE* pObj);
std::vector<UINT16> GetItemSlots(OBJECTTYPE* pObj, UINT8 subObject = 0, BOOLEAN fAttachment = FALSE);
void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usItem, BOOLEAN fOnlyRemoveWhenSlotsChange = 1);
void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem);
// HEADROCK HAM 5: Added argument for statusindex.
void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem, UINT8 ubStatusIndex);
void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT8 subObject = 0);
BOOLEAN CanItemFitInVehicle( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos, BOOLEAN fDoingPlacement );
+997 -360
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -67,6 +67,8 @@ INT8 ChanceToGetThrough( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT d
INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sHitBy, BOOLEAN fBuckshot, BOOLEAN fFake );
// HEADROCK HAM 4: Changed the name of one argument to avoid confusion with the new CTH system.
INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sApertureRatio, BOOLEAN fBuckshot, BOOLEAN fFake );
// HEADROCK HAM 5: Function for fragments ejected from an explosion.
INT8 FireFragmentGivenTarget( SOLDIERTYPE * pThrower, FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usExplosiveItem );
#define CALC_FROM_ALL_DIRS -1
#define CALC_FROM_WANTED_DIR -2
@@ -223,11 +225,14 @@ void CalcMuzzleSway( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzl
FLOAT CalcBulletDeviation( SOLDIERTYPE *pShooter, FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange );
void LimitImpactPointByFacing( SOLDIERTYPE *pShooter, SOLDIERTYPE *pTarget, FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, FLOAT *dEndX, FLOAT *dEndY );
void LimitImpactPointToMaxAperture( FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, FLOAT dDistanceAperture );
UINT32 CalcCounterForceFrequency(SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon);
// HEADROCK HAM 5: Removed and replaced by continuously-variable CF
// UINT32 CalcCounterForceFrequency(SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon);
FLOAT CalcCounterForceMax(SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, UINT8 uiStance = 0);
UINT32 CalcCounterForceAccuracy(SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, UINT32 uiRange, BOOLEAN fTracer, bool fAnticipate = false);
void CalcPreRecoilOffset( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, UINT32 uiRange );
void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange );
// HEADROCK HAM 5: New function, completely replaces the Counter Force Frequency check.
FLOAT CalcCounterForceChange( SOLDIERTYPE * pShooter, UINT32 uiCounterForceAccuracy, FLOAT dCounterForceMax, FLOAT dMuzzleOffset, INT8 bRecoil, FLOAT dPrevCounterForce, UINT32 uiIntendedBullets );
// HEADROCK HAM 4: Required for shooting mechanic
extern INT8 EffectiveMarksmanship( SOLDIERTYPE * pSoldier );
+2 -2
View File
@@ -1077,8 +1077,8 @@ BOOLEAN CheckIfRadioIsEquipped( void )
if ( GetSoldier( &pSoldier, gusSelectedSoldier ) )
{
bSlot = FindObj( pSoldier, EXTENDEDEAR );
//bSlot = FindHearingAid(pSoldier);
//bSlot = FindObj( pSoldier, EXTENDEDEAR );
bSlot = FindHearingAid(pSoldier);
//ScreenMsg( FONT_WHITE, MSG_INTERFACE, L"Position: %d", bSlot );
}
-1
View File
@@ -2692,7 +2692,6 @@ INT16 GetAPsToAutoReload( SOLDIERTYPE * pSoldier )
{
// Flugente: check for underbarrel weapons and use that object if necessary
pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[SECONDHANDPOS]) );
bExcludeSlot = NO_SLOT;
bSlot2 = NO_SLOT;
+25 -11
View File
@@ -80,10 +80,11 @@ class SOLDIERTYPE;
#define DROP_LENGTH_CHANGE_RATE 0.1f
#define DROP_LENGTH_RAND 2.0f
#define BASE_DROP_SPEED 7.0f
#define DROP_SPEED_RANGE 3.5f
#define DROP_SPEED_CHANGE_RATE 0.1f
#define DROP_SPEED_RAND 5.0f
// HEADROCK HAM 5 X: Externalized for snow.
FLOAT BASE_DROP_SPEED;
FLOAT DROP_SPEED_RANGE;
FLOAT DROP_SPEED_CHANGE_RATE;
FLOAT DROP_SPEED_RAND;
UINT32 guiMaxRainDrops = 79;
@@ -203,11 +204,18 @@ void ResetRain()
pRainDrops = NULL;
}
// Rain
BASE_DROP_SPEED = 7.0f;
DROP_SPEED_RANGE = 3.5f;
DROP_SPEED_CHANGE_RATE = 0.1f;
DROP_SPEED_RAND = 5.0f;
guiCurrMaxAmountOfRainDrops = 0;
}
void GenerateRainDropsList()
{
// HEADROCK HAM 5 XMAS: More snow than rain.
guiCurrMaxAmountOfRainDrops = (UINT32)(BASE_MAXIMUM_DROPS) * gbCurrentRainIntensity;
pRainDrops = (TRainDrop *)MemAlloc( sizeof( TRainDrop ) * guiCurrMaxAmountOfRainDrops );
@@ -415,6 +423,7 @@ void RenderRainOnSurface()
if( !pCurr->fAlive )continue;
// Rain
LineDraw( TRUE, (int)pCurr->fpX, (int)pCurr->fpY, (int)pCurr->fpX + (int)pCurr->fpEndRelX, (int)(pCurr->fpY + pCurr->fpEndRelY), sDropsColor, pDestBuf );
}
@@ -427,14 +436,19 @@ void GenerateRainMaximums()
{
fpMinDropAngleOfFalling = 45;
fpMaxDropAngleOfFalling = 135;
}else
if( Random( 2 ) )
}
else
{
fpMinDropAngleOfFalling = 20;
fpMaxDropAngleOfFalling = 70;
}else{
fpMinDropAngleOfFalling = 110;
fpMaxDropAngleOfFalling = 160;
if( Random( 2 ) )
{
fpMinDropAngleOfFalling = 20;
fpMaxDropAngleOfFalling = 70;
}
else
{
fpMinDropAngleOfFalling = 110;
fpMaxDropAngleOfFalling = 160;
}
}
fpCurrDropAngleOfFalling = fpMinDropAngleOfFalling + Random( (UINT32)(fpMaxDropAngleOfFalling - fpMinDropAngleOfFalling) );
+13 -2
View File
@@ -74,6 +74,8 @@
#define MAX_PALACE_DISTANCE 20
INT8 bNumSquadleadersInArmy = 0; // added by SANDRO
// HEADROCK HAM 5: Read target coolness by sector
UINT32 gCoolnessBySector[256];
OLD_SOLDIERCREATE_STRUCT_101::OLD_SOLDIERCREATE_STRUCT_101() {
initialize();
@@ -3237,8 +3239,8 @@ UINT8 GetLocationModifier( UINT8 ubSoldierClass )
INT16 sSectorX, sSectorY, sSectorZ;
#ifdef JA2UB
#else
INT8 bTownId;
UINT8 ubPalaceDistance;
//INT8 bTownId;
//UINT8 ubPalaceDistance;
#endif
BOOLEAN fSuccess;
@@ -3372,6 +3374,13 @@ UINT8 GetLocationModifier( UINT8 ubSoldierClass )
break;
}
#else
// HEADROCK HAM 5:
// The calculation has been replaced with an XML table.
ubLocationModifier = gCoolnessBySector[SECTOR(sSectorX, sSectorY)];
/*
// ignore sSectorZ - treat any underground enemies as if they were on the surface!
bTownId = GetTownIdForSector( sSectorX, sSectorY );
@@ -3401,6 +3410,8 @@ UINT8 GetLocationModifier( UINT8 ubSoldierClass )
// adjust for distance from Queen's palace (P3) (0 to +30)
ubLocationModifier = ( ( MAX_PALACE_DISTANCE - ubPalaceDistance ) * DIFF_FACTOR_PALACE_DISTANCE ) / MAX_PALACE_DISTANCE;
*/
#endif
return( ubLocationModifier );
}
+2
View File
@@ -207,8 +207,10 @@
<ClCompile Include="XML_HiddenNames.cpp" />
<ClCompile Include="XML_IMPItemChoices.cpp" />
<ClCompile Include="XML_IncompatibleAttachments.cpp" />
<ClCompile Include="XML_ItemAdjustments.cpp" />
<ClCompile Include="XML_Launchable.cpp" />
<ClCompile Include="XML_LBEPocket.cpp" />
<ClCompile Include="XML_LBEPocketPopup.cpp" />
<ClCompile Include="XML_LoadBearingEquipment.cpp" />
<ClCompile Include="XML_Magazine.cpp" />
<ClCompile Include="XML_MercStartingGear.cpp" />
+6
View File
@@ -611,5 +611,11 @@
<ClCompile Include="Ja25_Tactical.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XML_LBEPocketPopup.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XML_ItemAdjustments.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+251 -102
View File
@@ -1747,9 +1747,19 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
OBJECTTYPE* pA= &(*iter);
if ( (*pA)[0]->data.objectStatus >=USABLE)
{
INT8 bAmmoReliability = Item[(*pObjAttHand)[0]->data.gun.usGunAmmoItem].bReliability;
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 *
(Item[ iter->usItem ].bReliability + bAmmoReliability), 0);
INT16 ammoReliability = Item[(*pObjAttHand)[0]->data.gun.usGunAmmoItem].bReliability;
// HEADROCK HAM 5: Variable base chance
if ( UsingNewCTHSystem() == true)
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * (Item[ iter->usItem ].bReliability + ammoReliability) );
uiDepreciateTest = max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = max(0,BASIC_DEPRECIATE_CHANCE + 3 * (Item[ iter->usItem ].bReliability + ammoReliability));
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjAttHand)[0]->data.objectStatus > 1) )
(*pA)[0]->data.objectStatus--;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"rel =%d ",Item[ iter->usItem ].bReliability );
@@ -2107,8 +2117,18 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
//}
// Flugente FTW 1: Added a malus to reliability for overheated guns
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * GetReliability( pObjAttHand ) - iOverheatReliabilityMalus, 0);
// HEADROCK HAM 5: Variable NCTH base change
if ( UsingNewCTHSystem() == true)
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * GetReliability( &(pSoldier->inv[pSoldier->ubAttackingHand]) - iOverheatReliabilityMalus) );
uiDepreciateTest = max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * GetReliability( pObjAttHand ) - iOverheatReliabilityMalus, 0);
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjAttHand)[0]->data.objectStatus > 1) )
{
(*pObjAttHand)[0]->data.objectStatus--;
@@ -2284,9 +2304,19 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
OBJECTTYPE* pA= &(*iter);
if ( (*pA)[0]->data.objectStatus >=USABLE)
{
INT8 bAmmoReliability = Item[(*pObjUsed)[0]->data.gun.usGunAmmoItem].bReliability;
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 *
(Item[ iter->usItem ].bReliability + bAmmoReliability), 0);
INT16 ammoReliability = Item[(*pObjUsed)[0]->data.gun.usGunAmmoItem].bReliability;
// HEADROCK HAM 5: Variable base chance
if ( UsingNewCTHSystem() == true )
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * (Item[ iter->usItem ].bReliability + ammoReliability) );
uiDepreciateTest = __max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = __max(0,BASIC_DEPRECIATE_CHANCE + 3 * (Item[ iter->usItem ].bReliability + ammoReliability));
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjUsed)[0]->data.objectStatus > 1) )
(*pA)[0]->data.objectStatus--;
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"rel =%d ",Item[ iter->usItem ].bReliability );
@@ -2675,7 +2705,17 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
*/
// Flugente FTW 1: Added a malus to reliability for overheated guns
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( pObjUsed ) ) - iOverheatReliabilityMalus, 0);
if ( UsingNewCTHSystem() == true )
{
UINT16 usBaseChance = gGameCTHConstants.BASIC_RELIABILITY_ODDS;
FLOAT dReliabilityRatio = 3.0f * ((FLOAT)usBaseChance / (FLOAT)BASIC_DEPRECIATE_CHANCE); // Compare original odds to new odds.
uiDepreciateTest = usBaseChance + (INT16)( dReliabilityRatio * GetReliability( &(pSoldier->inv[ pSoldier->ubAttackingHand ])) - iOverheatReliabilityMalus);
uiDepreciateTest = max(0, uiDepreciateTest);
}
else
{
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( pObjUsed ) ) - iOverheatReliabilityMalus, 0);
}
if ( !PreRandom( uiDepreciateTest ) && ( (*pObjUsed)[0]->data.objectStatus > 1) )
{
@@ -4003,14 +4043,27 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s
MakeNoise( ubAttackerID, pTargetSoldier->sGridNo, pTargetSoldier->pathing.bLevel, gpWorldLevelData[pTargetSoldier->sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
// CALLAHAN START BUGFIX
if ( EXPLOSIVE_GUN( usWeaponIndex ) || AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
// Provisions for Fragments, which are resulting from a different weapon than the one we are holding in our hand.
UINT8 ubAmmoType = 0;
if ( pObj->usItem == usWeaponIndex )
{
ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType;
}
else
{
// Must be a fragment.
ubAmmoType = Explosive[Item[usWeaponIndex].ubClassIndex].ubFragType;
usWeaponIndex = 1; // Set to default gun.
}
if ( EXPLOSIVE_GUN( usWeaponIndex ) || AmmoTypes[ubAmmoType].explosionSize > 1)
// CALLAHAN END BUGFIX
{
// Reduce attacker count!
//TODO: Madd --- I don't think this code will ever get called for the HE ammo -- the EXPLOSIVE_GUN check filters out regular guns
// marke test mag ammo type: pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType
// 2cond 'or' added
if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1 )
if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[ubAmmoType].explosionSize > 1 )
{
if ( Item[usWeaponIndex].singleshotrocketlauncher )
{
@@ -4032,15 +4085,16 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s
pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
else if ( AmmoTypes[ubAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , pTargetSoldier->pathing.bLevel );
IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), AmmoTypes[ubAmmoType].highExplosive , pTargetSoldier->pathing.bLevel );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else // tank cannon
{
// HEADROCK HAM 5 TODO: TANK_SHELL!
IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), TANK_SHELL, pTargetSoldier->pathing.bLevel );
}
@@ -4088,10 +4142,29 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
// Flugente: check for underbarrel weapons and use that object if necessary
pObj = MercPtrs[ ubAttackerID ]->GetUsedWeapon( &MercPtrs [ ubAttackerID ]->inv[MercPtrs[ubAttackerID]->ubAttackingHand] );
if ( fStopped && ubAttackerID != NOBODY )
// Get attacker
if (ubAttackerID != NOBODY)
{
pAttacker = MercPtrs[ ubAttackerID ];
}
// HEADROCK HAM 5: Define differently for fragments
UINT8 ubHitVolume = 0;
UINT8 ubAmmoType = 0;
if (pBullet->fFragment)
{
ubHitVolume = 1;
ubAmmoType = Explosive[Item[pBullet->fromItem].ubClassIndex].ubFragType;
}
else
{
ubHitVolume = Weapon[usWeaponIndex].ubHitVolume;
ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType;
}
if ( fStopped && ubAttackerID != NOBODY )
{
if ( pAttacker->ubOppNum != NOBODY )
{
// if it was another team shooting at someone under our control
@@ -4124,11 +4197,11 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
if (sZPos > WALL_HEIGHT)
{
MakeNoise( ubAttackerID, sGridNo, 1, gpWorldLevelData[sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
MakeNoise( ubAttackerID, sGridNo, 1, gpWorldLevelData[sGridNo].ubTerrainID, ubHitVolume, NOISE_BULLET_IMPACT );
}
else
{
MakeNoise( ubAttackerID, sGridNo, 0, gpWorldLevelData[sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
MakeNoise( ubAttackerID, sGridNo, 0, gpWorldLevelData[sGridNo].ubTerrainID, ubHitVolume, NOISE_BULLET_IMPACT );
}
}
@@ -4146,30 +4219,35 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
// Reduce attacker count!
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of LAW fire") );
// FreeUpAttacker( ubAttackerID );
if ( Item[usWeaponIndex].singleshotrocketlauncher )
// HEADROCK HAM 5: Fragments fired by such weapons should not explode.
if ( pBullet->fFragment == false)
{
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, C1, (INT8)( sZPos >= WALL_HEIGHT ) );
}
// changed too to use 2 flag to determine
else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher)
//there shouldn't be a way to enter here with an UnderBarrel weapon, so retaining original code :JMich
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pAttacker->inv[HANDPOS].usItem , pAttacker->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) );
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem , (INT8)( sZPos >= WALL_HEIGHT ) );
//This is just to make multishot launchers work in semi auto. It's not really a permanent solution because it still doesn't allow autofire, but it will do for now.
OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pAttacker->inv[pAttacker->ubAttackingHand ]), pAttacker->inv[pAttacker->ubAttackingHand ].usItem );
if(pLaunchable){
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem;
} else {
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
if ( Item[usWeaponIndex].singleshotrocketlauncher )
{
// HEADROCK HAM 5 TODO: C1!!!
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, C1, (INT8)( sZPos >= WALL_HEIGHT ) );
}
// changed too to use 2 flag to determine
else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher)
//there shouldn't be a way to enter here with an UnderBarrel weapon, so retaining original code :JMich
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pAttacker->inv[HANDPOS].usItem , pAttacker->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) );
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem , (INT8)( sZPos >= WALL_HEIGHT ) );
//This is just to make multishot launchers work in semi auto. It's not really a permanent solution because it still doesn't allow autofire, but it will do for now.
OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pAttacker->inv[pAttacker->ubAttackingHand ]), pAttacker->inv[pAttacker->ubAttackingHand ].usItem );
if(pLaunchable){
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem;
} else {
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, AmmoTypes[ (*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , (INT8)( sZPos >= WALL_HEIGHT ) );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, AmmoTypes[ (*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , (INT8)( sZPos >= WALL_HEIGHT ) );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
// Moved here to make sure ABC stays >0 until everything done
@@ -4184,6 +4262,7 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
//DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - end of TANK fire") );
//FreeUpAttacker( ubAttackerID );
// HEADROCK HAM 5 TODO: Tank shell!!
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, TANK_SHELL, (INT8)( sZPos >= WALL_HEIGHT ) );
//FreeUpAttacker( (UINT8) ubAttackerID );
@@ -4202,67 +4281,83 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN
DamageStructure( pStructure, (UINT8)iImpact, STRUCTURE_DAMAGE_GUNFIRE, sGridNo, sXPos, sYPos, ubAttackerID );
}
switch( Weapon[ usWeaponIndex ].ubWeaponClass )
// HEADROCK HAM 5: Fragments are not fired from guns, so they need a special case.
if (pBullet->fFragment == false)
{
case HANDGUNCLASS:
case RIFLECLASS:
case SHOTGUNCLASS:
case SMGCLASS:
case MGCLASS:
switch( Weapon[ usWeaponIndex ].ubWeaponClass )
{
case HANDGUNCLASS:
case RIFLECLASS:
case SHOTGUNCLASS:
case SMGCLASS:
case MGCLASS:
// Guy has missed, play random sound
if ( MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum )
{
if ( !MercPtrs[ ubAttackerID ]->bDoBurst )
// Guy has missed, play random sound
if ( MercPtrs[ ubAttackerID ]->bTeam == gbPlayerNum )
{
if ( Random( 40 ) == 0 )
if ( !MercPtrs[ ubAttackerID ]->bDoBurst )
{
MercPtrs[ ubAttackerID ]->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
if ( Random( 40 ) == 0 )
{
MercPtrs[ ubAttackerID ]->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
}
}
}
}
//fDoMissForGun = TRUE;
//break;
fDoMissForGun = TRUE;
break;
//fDoMissForGun = TRUE;
//break;
fDoMissForGun = TRUE;
break;
case MONSTERCLASS:
case MONSTERCLASS:
DoSpecialEffectAmmoMiss( ubAttackerID, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet );
RemoveBullet( iBullet );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - monster attack hit structure") );
// FreeUpAttacker( (UINT8) ubAttackerID );
//PlayJA2Sample( SPIT_RICOCHET , RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
break;
case KNIFECLASS:
// When it hits the ground, leave on map...
if ( Item[ usWeaponIndex ].usItemClass == IC_THROWING_KNIFE )
{
// OK, have we hit ground?
if ( usStructureID == INVALID_STRUCTURE_ID )
{
// Add item
CreateItem( usWeaponIndex, bWeaponStatus, &gTempObject );
AddItemToPool( sGridNo, &gTempObject, -1 , 0, 0, -1 );
// Make team look for items
NotifySoldiersToLookforItems( );
}
if ( !fHitSameStructureAsBefore )
{
PlayJA2Sample( MISS_KNIFE, RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
}
DoSpecialEffectAmmoMiss( ubAttackerID, sGridNo, sXPos, sYPos, sZPos, FALSE, TRUE, iBullet );
RemoveBullet( iBullet );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - knife attack hit structure") );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - monster attack hit structure") );
// FreeUpAttacker( (UINT8) ubAttackerID );
}
//PlayJA2Sample( SPIT_RICOCHET , RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
break;
case KNIFECLASS:
// When it hits the ground, leave on map...
if ( Item[ usWeaponIndex ].usItemClass == IC_THROWING_KNIFE )
{
// OK, have we hit ground?
if ( usStructureID == INVALID_STRUCTURE_ID )
{
// Add item
CreateItem( usWeaponIndex, bWeaponStatus, &gTempObject );
AddItemToPool( sGridNo, &gTempObject, -1 , 0, 0, -1 );
// Make team look for items
NotifySoldiersToLookforItems( );
}
if ( !fHitSameStructureAsBefore )
{
PlayJA2Sample( MISS_KNIFE, RATE_11025, uiMissVolume, 1, SoundDir( sGridNo ) );
}
RemoveBullet( iBullet );
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - knife attack hit structure") );
// FreeUpAttacker( (UINT8) ubAttackerID );
}
}
}
else
{
if ( sZPos == 0 )
{
PlayJA2Sample( MISS_G2 , RATE_11025, 5, 1, SoundDir( sGridNo ) );
}
else
{
PlayJA2Sample( MISS_1 + Random(8), RATE_11025, 5, 1, SoundDir( sGridNo ) );
}
RemoveBullet( iBullet );
}
if ( fDoMissForGun )
@@ -8442,8 +8537,24 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u
return( iTotalProtection );
}
INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iOrigImpact, INT16 sHitBy, UINT8 * pubSpecial )
// HEADROCK HAM 5: Added argument the bullet!
INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iOrigImpact, INT16 sHitBy, UINT8 * pubSpecial )
{
UINT16 usAttackingWeapon = 0;
INT32 sOrigGridNo = 0;
BOOLEAN fFragment = FALSE;
if (pBullet == NULL)
{
usAttackingWeapon = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType;
sOrigGridNo = pFirer->sGridNo;
}
else
{
usAttackingWeapon = pBullet->fromItem;
sOrigGridNo = pBullet->sOrigGridNo;
fFragment = pBullet->fFragment;
}
INT32 iImpact, iFluke, iBonus, iImpactForCrits = 0;
INT8 bStatLoss = 0;
UINT8 ubAmmoType;
@@ -8452,17 +8563,21 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// in MoveBullet.
// Set a few things up:
if ( Item[ pFirer->usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE )
if ( Item[ usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE )
{
ubAmmoType = AMMO_KNIFE;
}
else
// HEADROCK HAM 5: Added provisions for fragments, which are not fired from the weapon in your hand.
else if ( fFragment == FALSE )
{
// Flugente: check for underbarrel weapons and use that object if necessary
OBJECTTYPE* pObj = pFirer->GetUsedWeapon( &pFirer->inv[pFirer->ubAttackingHand] );
ubAmmoType = (*pObj)[0]->data.gun.ubGunAmmoType;
}
else
{
ubAmmoType = Explosive[Item[usAttackingWeapon].ubClassIndex].ubFragType;
}
if ( TANK( pTarget ) )
{
@@ -8569,7 +8684,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
}
// Sniper trait adds bonus damage per aim click
if (HAS_SKILL_TRAIT( pFirer, SNIPER_NT ) && (pFirer->aiData.bAimTime >= gSkillTraitValues.ubSNDamageBonusFromNumClicks))
if (HAS_SKILL_TRAIT( pFirer, SNIPER_NT ) && (pFirer->aiData.bAimTime >= gSkillTraitValues.ubSNDamageBonusFromNumClicks) && !fFragment)
{
iImpact += (INT32)(iImpact * (pFirer->aiData.bAimTime - gSkillTraitValues.ubSNDamageBonusFromNumClicks + 1) * gSkillTraitValues.ubSNDamageBonusPerClick * NUM_SKILL_TRAITS( pFirer, SNIPER_NT ))/100; // +5% per trait
}
@@ -8593,8 +8708,15 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0)
iImpact -= ((iImpact * gGameExternalOptions.sEnemyEliteDamageResistance) /100);
iImpact = max( 1, iImpact);
// HEADROCK HAM 5.1: Oh sandro, you rendered zerominimumdamage moot...
if ( AmmoTypes[ubAmmoType].zeroMinimumDamage )
{
iImpact = __max( 0, iImpact );
}
else
{
iImpact = __max( 1, iImpact);
}
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -8622,7 +8744,15 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
case MIKE:
// Only 1/2 of the bonus
iImpact -= (INT32)(iImpact * gGameExternalOptions.usSpecialNPCStronger / 200);
iImpact = max( 1, iImpact);
// HEADROCK HAM 5.1: Oh sandro, you rendered zerominimumdamage moot...
if ( AmmoTypes[ubAmmoType].zeroMinimumDamage )
{
iImpact = __max( 0, iImpact );
}
else
{
iImpact = __max( 1, iImpact);
}
break;
}
}
@@ -8631,7 +8761,16 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
////////////////////////////////////////////////////////////////////////////////////
// STOMP traits - Bodybuilding damage resistance
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pTarget, BODYBUILDING_NT ) )
iImpact = max( 1, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
// HEADROCK HAM 5.1: Oh sandro, you rendered zerominimumdamage moot...
if ( AmmoTypes[ubAmmoType].zeroMinimumDamage )
{
iImpact = __max( 0, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
}
else
{
iImpact = __max( 1, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
}
////////////////////////////////////////////////////////////////////////////////////
AdjustImpactByHitLocation( iImpact, ubHitLocation, &iImpact, &iImpactForCrits );
@@ -8642,7 +8781,8 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// is the blow deadly enough for an instant kill?
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= Weapon[ pFirer->usAttackingWeapon ].maxdistformessydeath )
// HEADROCK HAM 5.1: Using usAttackingWeapon
if ( PythSpacesAway( sOrigGridNo, pTarget->sGridNo ) <= Weapon[ usAttackingWeapon ].maxdistformessydeath )
{
if (iImpactForCrits > MIN_DAMAGE_FOR_INSTANT_KILL && iImpactForCrits < pTarget->stats.bLife)
{
@@ -8695,7 +8835,8 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
// since this value is much lower than the others, it only applies at short range...
// HEADROCK HAM 3.6: Reattached "Max Distance For Messy Death" tag from the XML! God knows why it wasn't attached when they MADE THAT TAG.
//if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_DISTANCE_FOR_MESSY_DEATH || (PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= MAX_BARRETT_DISTANCE_FOR_MESSY_DEATH && pFirer->usAttackingWeapon == BARRETT ))
if ( PythSpacesAway( pFirer->sGridNo, pTarget->sGridNo ) <= Weapon[ pFirer->usAttackingWeapon ].maxdistformessydeath )
// HEADROCK HAM 5.1: Using usAttackingWeapon
if ( PythSpacesAway( sOrigGridNo, pTarget->sGridNo ) <= Weapon[ usAttackingWeapon ].maxdistformessydeath )
{
if (iImpact > MIN_DAMAGE_FOR_INSTANT_KILL && iImpact < pTarget->stats.bLife)
{
@@ -8741,7 +8882,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
if( !IsAutoResolveActive() )
{
if ( AmmoTypes[ubAmmoType].knife && pFirer->aiData.bOppList[ pTarget->ubID ] == SEEN_CURRENTLY )
if ( AmmoTypes[ubAmmoType].knife && pFirer->aiData.bOppList[ pTarget->ubID ] == SEEN_CURRENTLY && !fFragment )
{
// is this a stealth attack?
if ( pTarget->aiData.bOppList[ pFirer->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget )
@@ -8793,10 +8934,18 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat
if (iImpactForCrits > 0 && iImpactForCrits < pTarget->stats.bLife && !(pTarget->flags.uiStatusFlags & SOLDIER_MONSTER) ) // not to monsters - SANDRO
{
UINT32 uiCritChance = (iImpactForCrits / 2) + (pFirer->aiData.bAimTime * 5);
UINT32 uiCritChance = 0;
if (fFragment)
{
uiCritChance = (iImpactForCrits / 2);
}
else
{
uiCritChance = (iImpactForCrits / 2) + (pFirer->aiData.bAimTime * 5);
}
BOOLEAN fMaliciousHit = FALSE;
// SANDRO - Malicious characters inflict stat loss more often
if ( gGameOptions.fNewTraitSystem && pFirer->ubProfile != NO_PROFILE )
if ( gGameOptions.fNewTraitSystem && pFirer->ubProfile != NO_PROFILE && !fFragment)
{
if ( gMercProfiles[ pFirer->ubProfile ].bCharacterTrait == CHAR_TRAIT_MALICIOUS )
{
+6 -1
View File
@@ -358,6 +358,11 @@ typedef struct
UINT16 ubDuration;
UINT16 ubStartRadius;
UINT8 ubMagSize;
BOOLEAN fExplodeOnImpact; // HEADROCK HAM 5: Flag for impact explosives.
UINT16 usNumFragments; // HEADROCK HAM 5.1: Fragmenting Explosive Data
UINT8 ubFragType;
UINT16 ubFragDamage;
UINT16 ubFragRange;
} EXPLOSIVETYPE;
//GLOBALS
@@ -381,7 +386,7 @@ extern BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
extern void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 sBreathLoss, UINT16 usDirection, INT16 sXPos, INT16 sYPos, INT16 sZPos, INT16 sRange , UINT8 ubAttackerID, BOOLEAN fHit, UINT8 ubSpecial, UINT8 ubHitLocation );
extern void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UINT8 ubAttackerID, UINT16 sXPos, INT16 sYPos, INT16 sZPos, UINT16 usStructureID, INT32 iImpact, BOOLEAN fStopped );
extern void WindowHit( INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, BOOLEAN fLargeForce );
extern INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iImpact, INT16 sHitBy, UINT8 * pubSpecial );
// HEADROCK HAM 5.1: Moved to Bullets.h
extern BOOLEAN InRange( SOLDIERTYPE *pSoldier, INT32 sGridNo );
extern void ShotMiss( UINT8 ubAttackerID, INT32 iBullet );
extern UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos );
+16
View File
@@ -60,6 +60,8 @@ typedef PARSE_STAGE;
#define COMPATIBLEFACEITEMSFILENAME "CompatibleFaceItems.xml"
#define MERGESFILENAME "Merges.xml"
#define ATTACHMENTCOMBOMERGESFILENAME "AttachmentComboMerges.xml"
// HEADROCK HAM 5: Item Transformations Filename
#define ITEMTRANSFORMATIONSFILENAME "Item_Transformations.xml"
#define MAGAZINESFILENAME "Magazines.xml"
#define ARMOURSFILENAME "Armours.xml"
#define EXPLOSIVESFILENAME "Explosives.xml"
@@ -74,6 +76,9 @@ typedef PARSE_STAGE;
// CHRISL:
#define LOADBEARINGEQUIPMENTFILENAME "LoadBearingEquipment.xml"
#define LBEPOCKETFILENAME "Pockets.xml"
// THE_BOB : added for pocket popup definitions
#define LBEPOCKETPOPUPFILENAME "PocketPopups.xml"
#define MERCSTARTINGGEARFILENAME "MercStartingGear.xml"
#ifdef JA2UB
@@ -161,6 +166,8 @@ typedef PARSE_STAGE;
#define FACILITYTYPESFILENAME "Map\\FacilityTypes.xml"
// HEADROCK HAM 3.6: Sector Names [2009-07-27]
#define SECTORNAMESFILENAME "Map\\SectorNames.xml"
// HEADROCK HAM 5: Coolness by Sector [2011-11-19]
#define COOLNESSBYSECTORFILENAME "Map\\CoolnessBySector.xml"
// HEADROCK PROFEX: Merc Profiles [2009-07-27]
#define MERCPROFILESFILENAME "MercProfiles.xml"
// HEADROCK PROFEX: Merc Opinions [2009-07-27]
@@ -267,6 +274,9 @@ extern BOOLEAN WriteMergeStats();
extern BOOLEAN ReadInAttachmentComboMergeStats(STR fileName);
extern BOOLEAN WriteAttachmentComboMergeStats();
// HEADROCK HAM 5: Item Transformation XML reader
extern BOOLEAN ReadInTransformationStats(STR fileName);
extern BOOLEAN ReadInArmourStats(STR fileName);
extern BOOLEAN WriteArmourStats();
@@ -277,6 +287,9 @@ extern BOOLEAN WritelbeEquipmentStats();
extern BOOLEAN ReadInLBEPocketStats(STR fileName, BOOLEAN localizedVersion);
extern BOOLEAN WriteLBEPocketEquipmentStats();
// THE_BOB : added for pocket popup definitions
extern BOOLEAN ReadInLBEPocketPopups(STR fileName);
extern BOOLEAN ReadInMercStartingGearStats(STR fileName);
extern BOOLEAN WriteMercStartingGearStats();
@@ -391,6 +404,9 @@ extern BOOLEAN ReadInFacilityTypes(STR fileName, BOOLEAN localizedVersion);
// HEADROCK HAM 3.6: Customized Sector Names
extern BOOLEAN ReadInSectorNames(STR fileName, BOOLEAN localizedVersion, INT8 Level );
// HEADROCK HAM 5: Coolness by Sectors
extern BOOLEAN ReadInCoolnessBySector(STR fileName );
// HEADROCK PROFEX: Merc Profiles
extern BOOLEAN ReadInMercProfiles(STR fileName, BOOLEAN localizedVersion);
+38 -1
View File
@@ -57,7 +57,12 @@ explosiveStartElementHandle(void *userData, const XML_Char *name, const XML_Char
strcmp(name, "ubStartRadius") == 0 ||
strcmp(name, "ubMagSize") == 0 ||
strcmp(name, "ubDuration") == 0 ||
strcmp(name, "ubAnimationID") == 0 ))
strcmp(name, "ubAnimationID") == 0 ||
strcmp(name, "fExplodeOnImpact") == 0 ||// HEADROCK HAM 5: Explode on impact flag
strcmp(name, "usNumFragments") == 0 || // HEADROCK HAM 5.1: Fragmenting explosive data
strcmp(name, "ubFragType") == 0 ||
strcmp(name, "ubFragDamage") == 0 ||
strcmp(name, "ubFragRange") == 0 ))
{
pData->curElement = ELEMENT_PROPERTY;
@@ -159,6 +164,37 @@ explosiveEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = ELEMENT;
pData->curExplosive.ubDuration = (UINT8) atol(pData->szCharData);
}
// HEADROCK HAM 5: Flag for "Explosion on Impact"
else if(strcmp(name, "fExplodeOnImpact") == 0)
{
pData->curElement = ELEMENT;
pData->curExplosive.fExplodeOnImpact = (BOOLEAN) atol(pData->szCharData);
}
// HEADROCK HAM 5.1: Four tags for Fragmenting Explosives
else if(strcmp(name, "usNumFragments") == 0)
{
pData->curElement = ELEMENT;
pData->curExplosive.usNumFragments = (UINT16) atol(pData->szCharData);
}
else if(strcmp(name, "ubFragType") == 0)
{
pData->curElement = ELEMENT;
pData->curExplosive.ubFragType = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubFragDamage") == 0)
{
pData->curElement = ELEMENT;
pData->curExplosive.ubFragDamage = (UINT16) atol(pData->szCharData);
}
else if(strcmp(name, "ubFragRange") == 0)
{
pData->curElement = ELEMENT;
pData->curExplosive.ubFragRange = (UINT16) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
@@ -262,6 +298,7 @@ BOOLEAN WriteExplosiveStats()
FilePrintf(hFile,"\t\t<ubDuration>%d</ubDuration>\r\n", Explosive[cnt].ubDuration );
FilePrintf(hFile,"\t\t<ubStartRadius>%d</ubStartRadius>\r\n", Explosive[cnt].ubStartRadius );
FilePrintf(hFile,"\t\t<ubMagSize>%d</ubMagSize>\r\n", Explosive[cnt].ubMagSize );
FilePrintf(hFile,"\t\t<fExplodeOnImpact>%d</fExplodeOnImpact>\r\n", (UINT8)Explosive[cnt].fExplodeOnImpact );
FilePrintf(hFile,"\t</EXPLOSIVE>\r\n");
}
+238
View File
@@ -0,0 +1,238 @@
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "overhead.h"
#include "weapons.h"
#include "Debug Control.h"
#include "expat.h"
#include "gamesettings.h"
#include "XML.h"
#include "Item Types.h"
#endif
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
TransformInfoStruct curTransform;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 curResultIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef transformParseData;
static void XMLCALL
transformStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
transformParseData * pData = (transformParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "TRANSFORMATIONS_LIST") == 0 && pData->curElement == ELEMENT_NONE)
{
pData->curElement = ELEMENT_LIST;
// Reset all transformation indexes to -1, indicating they are "Not Taken"
for (UINT16 x = 0; x < MAXITEMS; x++)
{
Transform[x].usItem = -1;
}
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "TRANSFORM") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
// Reset values
pData->curTransform.usItem = -1;
for (UINT8 x = 0; x < MAX_NUM_TRANSFORMATION_RESULTS; x++)
{
pData->curTransform.usResult[x] = 0;
}
pData->curTransform.usAPCost = 0;
swprintf(pData->curTransform.szMenuRowText, L"");
swprintf(pData->curTransform.szTooltipText, L"");
pData->maxReadDepth++; //we are not skipping this element
pData->curIndex++;
pData->curResultIndex = 0;
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "usItem") == 0 ||
strcmp(name, "usResult") == 0 ||
strcmp(name, "usAPCost") == 0 ||
strcmp(name, "iBPCost") == 0 ||
strcmp(name, "szMenuRowText") == 0 ||
strcmp(name, "szTooltipText") == 0))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
transformCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
transformParseData * pData = (transformParseData *)userData;
if( (pData->currentDepth <= pData->maxReadDepth) &&
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
){
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
}
static void XMLCALL
transformEndElementHandle(void *userData, const XML_Char *name)
{
transformParseData * pData = (transformParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "TRANSFORMATIONS_LIST") == 0)
{
pData->curElement = ELEMENT_NONE;
}
else if(strcmp(name, "TRANSFORM") == 0)
{
pData->curElement = ELEMENT_LIST;
if(pData->curIndex < pData->maxArraySize)
{
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3,"MergeStartElementHandle: writing merge to array");
Transform[pData->curIndex].usItem = pData->curTransform.usItem; //write the merge into the table
for (INT32 x = 0; x < MAX_NUM_TRANSFORMATION_RESULTS; x++)
{
Transform[pData->curIndex].usResult[x] = pData->curTransform.usResult[x];
}
Transform[pData->curIndex].usAPCost = pData->curTransform.usAPCost;
Transform[pData->curIndex].iBPCost = pData->curTransform.iBPCost;
wcscpy( Transform[pData->curIndex].szMenuRowText, pData->curTransform.szMenuRowText );
wcscpy( Transform[pData->curIndex].szTooltipText, pData->curTransform.szTooltipText );
}
}
else if(strcmp(name, "usItem") == 0)
{
pData->curElement = ELEMENT;
INT16 usItem = (INT16) atol(pData->szCharData);
if (usItem <= 0)
{
AssertMsg( 0, String( "Item_Transformations.XML error: Entry #%d missing proper <usItem> tag!", pData->curIndex ) );
}
pData->curTransform.usItem = usItem;
}
else if(strcmp(name, "usResult") == 0)
{
pData->curElement = ELEMENT;
pData->curTransform.usResult[pData->curResultIndex] = (UINT16) atol(pData->szCharData);
pData->curResultIndex++;
}
else if(strcmp(name, "usAPCost") == 0)
{
pData->curElement = ELEMENT;
pData->curTransform.usAPCost = (UINT16) atol(pData->szCharData);
pData->curTransform.usAPCost = (UINT16)DynamicAdjustAPConstants(pData->curTransform.usAPCost, pData->curTransform.usAPCost);
}
else if(strcmp(name, "iBPCost") == 0)
{
pData->curElement = ELEMENT;
pData->curTransform.iBPCost = (INT32) atol(pData->szCharData);
}
else if(strcmp(name, "szMenuRowText") == 0)
{
pData->curElement = ELEMENT;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curTransform.szMenuRowText, sizeof(pData->curTransform.szMenuRowText)/sizeof(pData->curTransform.szMenuRowText[0]) );
pData->curTransform.szMenuRowText[sizeof(pData->curTransform.szMenuRowText)/sizeof(pData->curTransform.szMenuRowText[0]) - 1] = '\0';
}
else if(strcmp(name, "szTooltipText") == 0)
{
pData->curElement = ELEMENT;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curTransform.szTooltipText, sizeof(pData->curTransform.szTooltipText)/sizeof(pData->curTransform.szTooltipText[0]) );
pData->curTransform.szTooltipText[sizeof(pData->curTransform.szTooltipText)/sizeof(pData->curTransform.szTooltipText[0]) - 1] = '\0';
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInTransformationStats(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
transformParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading Item_Transformations.xml" );
// Open merges file
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, transformStartElementHandle, transformEndElementHandle);
XML_SetCharacterDataHandler(parser, transformCharacterDataHandle);
memset(&pData,0,sizeof(pData));
pData.maxArraySize = MAXITEMS;
pData.curIndex = -1;
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in Item_Transformations.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return( TRUE );
}
+496
View File
@@ -0,0 +1,496 @@
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "popup_class.h"
#include "popup_definition.h"
#include "Debug Control.h"
#include "expat.h"
#include "XML.h"
#include "GameSettings.h"
#endif
// namespace'd because of name collision with POPUP class def
namespace POPUP_PARSE {
enum
{
OUTSIDE_POCKET_LIST = 0,
POCKET_LIST,
POCKET,
POCKET_PROPERTY, // for reading pocket id
POPUP,
POPUP_PROPERTY, // unused
// for root-level popup
OPTION,
OPTION_PROPERTY,
GENERATOR,
GENERATOR_PROPERTY,
SUBMENU,
SUBMENU_PROPERTY,
// for submenus
SUBMENU_OPTION,
SUBMENU_OPTION_PROPERTY,
SUBMENU_GENERATOR,
SUBMENU_GENERATOR_PROPERTY
}
typedef POPUP_PARSE_STAGE;
}
struct
{
POPUP_PARSE::POPUP_PARSE_STAGE curElement;
UINT8 curSubPopupLevel;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
// popupDef and its pocket number
UINT8 curPocketId;
popupDef *curPocketPopup;
// for reading in options to popups and subPopups
//popupDefOption *curPocketPopupOption; // not really used
WCHAR curPocketPopupOptionName[128];
UINT16 curPocketPopupOptionCallback;
UINT16 curPocketPopupOptionAvail;
// for reading in subPopups
popupDefSubPopupOption *curPocketSubPopupOption[POPUP_MAX_SUB_POPUPS];
WCHAR curPocketSubPopupOptionName[POPUP_MAX_SUB_POPUPS][128];
// for reading in content generator references
popupDefContentGenerator *curPocketPopupGenerator; // not really used
UINT16 curPocketPopupGeneratorId;
popupDef * curArray;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef pocketPopupParseData;
// maps generator name strings found in XML to generator IDs used by the function that binds them
static UINT16 mapGeneratorNameToId( CHAR8 * name ){
if( strcmp(name,"dummy") == 0 ){
return popupGenerators::dummy;
} else if( strcmp(name,"addArmor") == 0 ){
return popupGenerators::addArmor;
} else if( strcmp(name,"addLBE") == 0 ){
return popupGenerators::addLBE;
} else if( strcmp(name,"addWeapons") == 0 ){
return popupGenerators::addWeapons;
} else if( strcmp(name,"addWeaponGroups") == 0 ){
return popupGenerators::addWeaponGroups;
} else if( strcmp(name,"addGrenades") == 0 ){
return popupGenerators::addGrenades;
} else if( strcmp(name,"addBombs") == 0 ){
return popupGenerators::addBombs;
} else if( strcmp(name,"addFaceGear") == 0 ){
return popupGenerators::addFaceGear;
} else if( strcmp(name,"addAmmo") == 0 ){
return popupGenerators::addAmmo;
} else if( strcmp(name,"addRifleGrenades") == 0 ){
return popupGenerators::addRifleGrenades;
} else if( strcmp(name,"addRocketAmmo") == 0 ){
return popupGenerators::addRocketAmmo;
} else if( strcmp(name,"addMisc") == 0 ){
return popupGenerators::addMisc;
} else if( strcmp(name,"addKits") == 0 ){
return popupGenerators::addKits;
} else return 0; // includes 'none'
}
// maps option callback name strings found in XML to callback IDs used by the function that binds them
static UINT16 mapCallbackNameToId( CHAR8 * name ){
if( strcmp(name,"dummy") == 0 ){
return 1;
} else return 0; // includes 'none'
}
// maps option availability check function name strings found in XML to their IDs used by the function that binds them
static UINT16 mapAvailNameToId( CHAR8 * name ){
if( strcmp(name,"dummy") == 0 ){
return 1;
} else return 0; // includes 'none'
}
static void XMLCALL
pocketPopupStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
pocketPopupParseData * pData = (pocketPopupParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "POCKETPOPUPS") == 0 && pData->curElement == ELEMENT_NONE)
{
pData->curElement = POPUP_PARSE::POCKET_LIST;
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "POCKET") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = POPUP_PARSE::POCKET;
pData->maxReadDepth++; //we are not skipping this element
// TODO: assert if there's no dangling subpopup here, broken XML might cause trouble
pData->curSubPopupLevel = 0; // we're in a new pocket now, so reset the subpopup level
}
else if(pData->curElement == POPUP_PARSE::POCKET &&
(strcmp(name, "pIndex") == 0 ))
{
pData->curElement = POPUP_PARSE::POCKET_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::POCKET &&
(strcmp(name, "popup") == 0 ))
{
pData->curElement = POPUP_PARSE::POPUP;
pData->maxReadDepth++; //we are not skipping this element
pData->curPocketPopup = new popupDef();
}
else if(pData->curElement == POPUP_PARSE::POPUP && // popup options (not in submenu)
(strcmp(name, "option") == 0 ))
{
pData->curElement = POPUP_PARSE::OPTION;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::OPTION && // popup option attributes (not in submenu)
( strcmp(name, "name") == 0
|| strcmp(name, "action") == 0
|| strcmp(name, "availCheck") == 0 ))
{
pData->curElement = POPUP_PARSE::OPTION_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::POPUP && // content generators (not in submenu)
(strcmp(name, "generator") == 0 ))
{
pData->curElement = POPUP_PARSE::GENERATOR;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::GENERATOR && // content generator attributes (not in submenu)
( strcmp(name, "id") == 0 ) )
{
pData->curElement = POPUP_PARSE::GENERATOR_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::POPUP && // submenu (first)
(strcmp(name, "subMenu") == 0 ))
{
pData->curElement = POPUP_PARSE::SUBMENU;
// TODO: assert that this is the first submenu
pData->curSubPopupLevel = 1; // we're still at popup level so this must be the first subpopup
pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ] = new popupDefSubPopupOption();
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::SUBMENU && // submenu (deep)
(strcmp(name, "subMenu") == 0 ))
{
pData->curElement = POPUP_PARSE::SUBMENU;
pData->curSubPopupLevel++;
pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ] = new popupDefSubPopupOption();
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::SUBMENU && // submenu attributes
( strcmp(name, "name") == 0 ) )
{
pData->curElement = POPUP_PARSE::SUBMENU_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::SUBMENU && // popup options (submenu)
(strcmp(name, "option") == 0 ))
{
pData->curElement = POPUP_PARSE::SUBMENU_OPTION;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::SUBMENU_OPTION && // popup option attributes (submenu)
( strcmp(name, "name") == 0
|| strcmp(name, "action") == 0
|| strcmp(name, "availCheck") == 0 ))
{
pData->curElement = POPUP_PARSE::SUBMENU_OPTION_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::SUBMENU && // content generators (submenu)
(strcmp(name, "generator") == 0 ))
{
pData->curElement = POPUP_PARSE::SUBMENU_GENERATOR;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == POPUP_PARSE::SUBMENU_GENERATOR && // content generator attributes (submenu)
( strcmp(name, "id") == 0 ) )
{
pData->curElement = POPUP_PARSE::SUBMENU_GENERATOR_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
pocketPopupCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
pocketPopupParseData * pData = (pocketPopupParseData *)userData;
if( (pData->currentDepth <= pData->maxReadDepth) &&
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
){
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
}
static void XMLCALL
pocketPopupEndElementHandle(void *userData, const XML_Char *name)
{
pocketPopupParseData * pData = (pocketPopupParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth)
{
if(strcmp(name, "POCKETPOPUPS") == 0)
{
pData->curElement = POPUP_PARSE::OUTSIDE_POCKET_LIST;
}
else if(strcmp(name, "POCKET") == 0)
{
pData->curElement = POPUP_PARSE::POCKET_LIST;
// done with the pocket
// nothing to do because we already saved the popup when closing <popup> tag
}
else if(strcmp(name, "pIndex") == 0)
{
pData->curElement = POPUP_PARSE::POCKET;
pData->curPocketId = (UINT8) atol(pData->szCharData); // got pocket index
}
else if(strcmp(name, "popup") == 0)
{
pData->curElement = POPUP_PARSE::POCKET;
// done with the popup definition
LBEPocketPopup[ pData->curPocketId ] = *pData->curPocketPopup; // place the popup definition in pocket popup index
}
else if(strcmp(name, "subMenu") == 0)
{
// done with the subpopup definition
// rename the current option, we should've collected a name for it by now
pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ]->rename( new std::wstring( pData->curPocketSubPopupOptionName[ pData->curSubPopupLevel-1 ] ) );
if( pData->curSubPopupLevel == 1 ){ // at first submenu level, add the current menu to the base popup
pData->curElement = POPUP_PARSE::POPUP;
pData->curPocketPopup->addSubPopup( pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ] );
pData->curSubPopupLevel = 0;
} else { // deep in submenu tree, add the current submenu to the one above
pData->curElement = POPUP_PARSE::SUBMENU;
pData->curPocketSubPopupOption[ pData->curSubPopupLevel - 2 ]->getSubDef()->addSubPopup( pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ] );
pData->curSubPopupLevel--;
}
}
else if( pData->curElement == POPUP_PARSE::OPTION && strcmp(name, "option") == 0) // option (popup)
{
pData->curElement = POPUP_PARSE::POPUP;
// done with the option
pData->curPocketPopup->addOption( new std::wstring( pData->curPocketPopupOptionName ), pData->curPocketPopupOptionCallback, pData->curPocketPopupOptionAvail );
}
else if( pData->curElement == POPUP_PARSE::SUBMENU_OPTION && strcmp(name, "option") == 0) // option (sub-popup)
{
pData->curElement = POPUP_PARSE::SUBMENU;
// done with the option
pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ]->getSubDef()->addOption( new std::wstring( pData->curPocketPopupOptionName ), pData->curPocketPopupOptionCallback, pData->curPocketPopupOptionAvail );
}
else if( pData->curElement == POPUP_PARSE::GENERATOR && strcmp(name, "generator") == 0) // generator (popup)
{
pData->curElement = POPUP_PARSE::POPUP;
// done with the generator
pData->curPocketPopup->addGenerator( pData->curPocketPopupGeneratorId );
}
else if( pData->curElement == POPUP_PARSE::SUBMENU_GENERATOR && strcmp(name, "generator") == 0) // generator (sub-popup)
{
pData->curElement = POPUP_PARSE::SUBMENU;
// done with the generator
pData->curPocketSubPopupOption[ pData->curSubPopupLevel-1 ]->getSubDef()->addGenerator( pData->curPocketPopupGeneratorId );
}
else if(strcmp(name, "name") == 0)
{
switch( pData->curElement ){
case POPUP_PARSE::OPTION_PROPERTY:
pData->curElement = POPUP_PARSE::OPTION;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curPocketPopupOptionName, sizeof(pData->curPocketPopupOptionName)/sizeof(pData->curPocketPopupOptionName[0]) );
pData->curPocketPopupOptionName[sizeof(pData->curPocketPopupOptionName)/sizeof(pData->curPocketPopupOptionName[0]) - 1] = '\0';
break;
case POPUP_PARSE::SUBMENU_OPTION_PROPERTY:
pData->curElement = POPUP_PARSE::SUBMENU_OPTION;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curPocketPopupOptionName, sizeof(pData->curPocketPopupOptionName)/sizeof(pData->curPocketPopupOptionName[0]) );
pData->curPocketPopupOptionName[sizeof(pData->curPocketPopupOptionName)/sizeof(pData->curPocketPopupOptionName[0]) - 1] = '\0';
break;
case POPUP_PARSE::SUBMENU_PROPERTY:
pData->curElement = POPUP_PARSE::SUBMENU;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curPocketSubPopupOptionName[pData->curSubPopupLevel-1], sizeof(pData->curPocketSubPopupOptionName[pData->curSubPopupLevel-1])/sizeof(pData->curPocketSubPopupOptionName[pData->curSubPopupLevel-1][0]) );
pData->curPocketSubPopupOptionName[pData->curSubPopupLevel-1][sizeof(pData->curPocketSubPopupOptionName[pData->curSubPopupLevel-1])/sizeof(pData->curPocketSubPopupOptionName[pData->curSubPopupLevel-1][0]) - 1] = '\0';
break;
}
}
else if(strcmp(name, "action") == 0)
{
switch( pData->curElement ){
case POPUP_PARSE::OPTION_PROPERTY:
pData->curElement = POPUP_PARSE::OPTION;
break;
case POPUP_PARSE::SUBMENU_OPTION_PROPERTY:
pData->curElement = POPUP_PARSE::SUBMENU_OPTION;
break;
}
pData->curPocketPopupOptionCallback = mapCallbackNameToId(pData->szCharData);
}
else if(strcmp(name, "availCheck") == 0)
{
switch( pData->curElement ){
case POPUP_PARSE::OPTION_PROPERTY:
pData->curElement = POPUP_PARSE::OPTION;
break;
case POPUP_PARSE::SUBMENU_OPTION_PROPERTY:
pData->curElement = POPUP_PARSE::SUBMENU_OPTION;
break;
}
pData->curPocketPopupOptionAvail = mapAvailNameToId(pData->szCharData);
}
else if(strcmp(name, "id") == 0)
{
switch( pData->curElement ){
case POPUP_PARSE::GENERATOR_PROPERTY:
pData->curElement = POPUP_PARSE::GENERATOR;
break;
case POPUP_PARSE::SUBMENU_GENERATOR_PROPERTY:
pData->curElement = POPUP_PARSE::SUBMENU_GENERATOR;
break;
}
pData->curPocketPopupGeneratorId = mapGeneratorNameToId(pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInLBEPocketPopups(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
pocketPopupParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading pocketPopups.xml" );
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, pocketPopupStartElementHandle, pocketPopupEndElementHandle);
XML_SetCharacterDataHandler(parser, pocketPopupCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in Pocket.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
/*
// dummy popup
popupDef* popup = new popupDef();
popup->addOption(new std::wstring(L"Option one"),NULL,NULL);
popup->addOption(new std::wstring(L"Option two"),NULL,NULL);
popup->addOption(new std::wstring(L"Option three"),NULL,NULL);
LBEPocketPopup[5] = *popup;
*/
MemFree(lpcBuffer);
XML_ParserFree(parser);
return( TRUE );
}
+17 -5
View File
@@ -31,7 +31,8 @@
#endif
// Defines
#define NUM_BULLET_SLOTS 50
// HEADROCK HAM 5: Increasing... with the hope of making spectacular fragmenting explosives.
#define NUM_BULLET_SLOTS 200
// GLOBAL FOR FACES LISTING
@@ -105,7 +106,11 @@ INT32 CreateBullet( UINT8 ubFirerID, BOOLEAN fFake, UINT16 usFlags,UINT16 fromIt
{
pBullet->fReal = TRUE;
// gBullets[ iBullet ].pFirer->bBulletsLeft++;
gTacticalStatus.ubAttackBusyCount++;
// HEADROCK HAM 5: Do not create for explosives.
if (!(Item[fromItem].usItemClass & IC_EXPLOSV))
{
gTacticalStatus.ubAttackBusyCount++;
}
DebugAttackBusy( String( "Creating a new bullet for %d. ABC now %d\n", ubFirerID, gTacticalStatus.ubAttackBusyCount) );
}
@@ -201,7 +206,11 @@ void RemoveBullet( INT32 iBullet )
// DebugAttackBusy( String( "Deleting a bullet for %d. Total count now %d\n", gBullets[ iBullet].ubFirerID, gBullets[ iBullet ].pFirer->bBulletsLeft) );
// Nah, just decrement the attack busy count and be done with it
DebugAttackBusy( String( "Deleting a bullet for %d.\n", gBullets[ iBullet].ubFirerID ) );
ReduceAttackBusyCount( );
// HEADROCK HAM 5: Fragments do not need reducing.
if (gBullets[iBullet].fFragment == false)
{
ReduceAttackBusyCount( );
}
// if ( gBullets[ iBullet ].usFlags & ( BULLET_FLAG_KNIFE ) )
// {
@@ -233,7 +242,8 @@ void RemoveBullet( INT32 iBullet )
void LocateBullet( INT32 iBulletIndex )
{
if ( gGameSettings.fOptions[ TOPTION_SHOW_MISSES ] )
// HEADROCK HAM 5: Do not track fragments. There are too many of them.
if ( gGameSettings.fOptions[ TOPTION_SHOW_MISSES ] && gBullets[ iBulletIndex ].fFragment == false)
{
// Check if a bad guy fired!
if ( gBullets[ iBulletIndex ].ubFirerID != NOBODY )
@@ -353,6 +363,7 @@ void UpdateBullets( )
ManLooksForOtherTeams(gBullets[ uiCount ].pFirer);
}
*/
else
{
pNode = AddStructToTail( gBullets[ uiCount ].sGridNo, BULLETTILE1 );
@@ -364,7 +375,8 @@ void UpdateBullets( )
pNode->sRelativeZ = (INT16) CONVERT_HEIGHTUNITS_TO_PIXELS( FIXEDPT_TO_INT32( gBullets[ uiCount ].qCurrZ ) );
//afp-start - add new tail /tracer
if (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS])
// HEADROCK HAM 5: No tail for fragments.
if (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS] && gBullets[ uiCount ].fFragment == false)
{
if ((lastX != 0) || (lastY != 0))
{