mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2650 3b4a5df2-a311-0410-b5c6-a8a6f20db521
8886 lines
304 KiB
C++
8886 lines
304 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#else
|
|
#include "items.h"
|
|
#include "Action Items.h"
|
|
#include "weapons.h"
|
|
#include "Interface Cursors.h"
|
|
#include "Soldier Control.h"
|
|
#include "overhead.h"
|
|
#include "Handle UI.h"
|
|
#include "Animation Control.h"
|
|
#include "points.h"
|
|
#include "Sound Control.h"
|
|
#include "Sys globals.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Animation Data.h"
|
|
#include "worldman.h"
|
|
#include "Random.h"
|
|
#include "Campaign.h"
|
|
#include "interface.h"
|
|
#include "interface panels.h"
|
|
#include "explosion control.h"
|
|
#include "Keys.h"
|
|
|
|
#include "wcheck.h"
|
|
#include "soldier profile.h"
|
|
#include "SkillCheck.h"
|
|
#include "los.h"
|
|
#include "message.h"
|
|
#include "text.h"
|
|
|
|
#include "fov.h"
|
|
#include "MessageBoxScreen.h"
|
|
|
|
#include "PathAIDebug.h"
|
|
#include "Interface Control.h"
|
|
#include "ShopKeeper Interface.h"
|
|
#include "Cursors.h"
|
|
|
|
#include "GameSettings.h"
|
|
#include "environment.h"
|
|
#include "Auto Resolve.h"
|
|
#include "Interface Items.h"
|
|
#include "Campaign Types.h"
|
|
#include "history.h"
|
|
#include "Game Clock.h"
|
|
#include "strategicmap.h"
|
|
#include "Inventory Choosing.h"
|
|
#include "Soldier macros.h"
|
|
#include "Smell.h"
|
|
#include "lighting.h"
|
|
#include "utilities.h"
|
|
#include "english.h"
|
|
#endif
|
|
|
|
//forward declarations of common classes to eliminate includes
|
|
class OBJECTTYPE;
|
|
class SOLDIERTYPE;
|
|
|
|
|
|
#define ANY_MAGSIZE 65535
|
|
|
|
void SetNewItem( SOLDIERTYPE *pSoldier, UINT8 ubInvPos, BOOLEAN fNewItem );
|
|
|
|
extern SOLDIERTYPE *gpItemDescSoldier;
|
|
extern BOOLEAN fShowMapInventoryPool;
|
|
extern BOOLEAN AutoPlaceObjectInInventoryStash( OBJECTTYPE *pItemPtr, INT16 sGridNo );
|
|
|
|
// weight units are 100g each
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//ATE: When adding new items, make sure to update text.c with text description
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
INVTYPE Item[MAXITEMS]; //=
|
|
//{
|
|
//// CLASS SOUND GRPH GRA- PER
|
|
////CLASS INDEX CURSOR TYPE TYPE PHIC WT PCKT PRICE COOL DESCRIPTION REL REPAIR FLAGS
|
|
////--------- ----- ------- ------- ---- -- -- ---- ----- ---- ----------- --- ------ -----
|
|
//{ IC_PUNCH, 0, PUNCHCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, ITEM_NOT_BUYABLE , 0, "Nothing"},
|
|
////---WEAPONS---
|
|
//// NB For convenience, in accessing the Weapons table, the class index
|
|
//// of a weapon must be equal to its position in the Item table
|
|
//{ IC_GUN, 1, TARGETCURS, CONDBUL, 0, 1, 6, 1, 350, 2, /* Glock 17 */ +2, +2, IF_STANDARD_GUN },
|
|
//{ IC_GUN, 2, TARGETCURS, CONDBUL, 0, 2, 6, 1, 480, 2, /* Glock 18 */ +1, +1, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 3, TARGETCURS, CONDBUL, 0, 3, 11, 1, 450, 2, /* Beretta 92F */ -1, -1, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 4, TARGETCURS, CONDBUL, 0, 4, 11, 1, 470, 2, /* Beretta 93R */ -2, -2, IF_STANDARD_GUN },
|
|
//{ IC_GUN, 5, TARGETCURS, CONDBUL, 0, 5, 11, 1, 250, 1, /* .38 S&W Special */ +4, +4, IF_STANDARD_GUN },
|
|
//{ IC_GUN, 6, TARGETCURS, CONDBUL, 0, 6, 10, 1, 300, 1, /* .357 Barracuda */ +3, +3, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 7, TARGETCURS, CONDBUL, 0, 7, 17, 1, 300, 1, /* .357 DesertEagle*/ -1, -1, IF_STANDARD_GUN },
|
|
//{ IC_GUN, 8, TARGETCURS, CONDBUL, 0, 8, 11, 1, 400, 2, /* .45 M1911 */ 0, 0, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 9, TARGETCURS, CONDBUL, 0, 9, 21, 0, 980, 3, /* H&K MP5K */ -1, 0, IF_STANDARD_GUN},
|
|
//{ IC_GUN, 10, TARGETCURS, CONDBUL, 0, 10, 28, 0, 1170, 4, /* .45 MAC-10 */ -2, -1, IF_STANDARD_GUN },
|
|
//
|
|
//{ IC_GUN, 11, TARGETCURS, CONDBUL, 0, 11, 48, 0, 700, 3, /* Thompson M1A1 */ +3, -3, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 12, TARGETCURS, CONDBUL, 0, 12, 26, 0, 1330, 5, /* Colt Commando */ 0, -1, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 13, TARGETCURS, CONDBUL, 0, 13, 28, 0, 1000, 4, /* H&K MP53 */ -1, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 14, TARGETCURS, CONDBUL, 0, 14, 39, 0, 1180, 4, /* AKSU-74 */ -2, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 15, TARGETCURS, CONDBUL, 0, 15, 28, 0, 2750, 10, /* 5.7mm FN P90 */ -2, -4, IF_STANDARD_GUN },
|
|
//{ IC_GUN, 16, TARGETCURS, CONDBUL, 0, 16, 19, 0, 620, 3, /* Type-85 */ -4, +2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 17, TARGETCURS, CONDBUL, 0, 17, 39, 0, 1350, 5, /* SKS */ -4, -2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 18, TARGETCURS, CONDBUL, 0, 18, 43, 0, 1930, 6, /* Dragunov */ +2, +2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 19, TARGETCURS, CONDBUL, 0, 19, 55, 0, 1950, 6, /* M24 */ +4, +4, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 20, TARGETCURS, CONDBUL, 0, 20, 36, 0, 2380, 8, /* Steyr AUG */ +1, -2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//
|
|
//{ IC_GUN, 21, TARGETCURS, CONDBUL, 0, 21, 41, 0, 1620, 6, /* H&K G41 */ +1, -1, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 22, TARGETCURS, CONDBUL, 0, 22, 29, 0, 1100, 4, /* Ruger Mini-14 */ 0, -1, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 23, TARGETCURS, CONDBUL, 0, 23, 36, 0, 2680, 8, /* C-7 */ -1, -1, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 24, TARGETCURS, CONDBUL, 0, 24, 36, 0, 1970, 7, /* FA-MAS */ -2, -2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 25, TARGETCURS, CONDBUL, 0, 25, 36, 0, 1830, 6, /* AK-74 */ -1, -2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 26, TARGETCURS, CONDBUL, 0, 26, 43, 0, 1450, 5, /* AKM */ +2, +2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 27, TARGETCURS, CONDBUL, 0, 27, 29, 0, 2120, 7, /* M-14 */ +1, -1, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 28, TARGETCURS, CONDBUL, 0, 28, 43, 0, 2680, 8, /* FN-FAL */ 0, -1, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 29, TARGETCURS, CONDBUL, 0, 29, 44, 0, 1570, 5, /* H&K G3A3 */ +1, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 30, TARGETCURS, CONDBUL, 0, 30, 38, 0, 2530, 8, /* H&K G11 */ +3, -4, IF_TWOHANDED_GUN },
|
|
//
|
|
//{ IC_GUN, 31, TARGETCURS, CONDBUL, 0, 31, 36, 0, 670, 3, /* Remington M870 */ +3, +3, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 32, TARGETCURS, CONDBUL, 0, 32, 38, 0, 980, 4, /* SPAS-15 */ -2, -2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 33, TARGETCURS, CONDBUL, 0, 33, 41, 0, 2900, 9, /* CAWS */ -3, -3, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 34, TARGETCURS, CONDBUL, 0, 34, 68, 0, 3100, 10, /* FN Minimi */ -1, -2, IF_TWOHANDED_GUN },
|
|
//{ IC_GUN, 35, TARGETCURS, CONDBUL, 0, 35, 48, 0, 3180, 10, /* RPK-74 */ -1, -2, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 36, TARGETCURS, CONDBUL, 0, 36, 93, 0, 3420, 10, /* H&K 21E */ +2, +1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_BLADE, 37, KNIFECURS, 0, 1, 79, 9, 2, 100, 2, /* combat knife */ +2, +2, IF_STANDARD_BLADE},
|
|
//{ IC_THROWING_KNIFE,38, TARGETCURS, 0, 1, 53, 1, 4, 50, 3, /* throwing knife */ -1, -1, IF_STANDARD_BLADE},
|
|
//{ IC_THROWN, 39, TOSSCURS, 0, 1, 57, 5, 2, 0, 0, /* rock */ 0, 0, ITEM_NOT_BUYABLE},
|
|
//{ IC_LAUNCHER, 40, TRAJECTORYCURS, 0, 0, 37, 26, 0, 900, 7, /* grenade launcher*/ 0, -1, IF_TWOHANDED_GUN },
|
|
//
|
|
//{ IC_LAUNCHER, 41, TRAJECTORYCURS, 0, 0, 0, 77, 0, 1800, 10, /* mortar */ 0, -2, IF_TWOHANDED_GUN},
|
|
//{ IC_THROWN, 42, TOSSCURS, 0, 1, 60, 4, 3, 0, 0, /* another rock */ 0, 0, ITEM_NOT_BUYABLE},
|
|
//{ IC_BLADE, 43, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* yng male claws */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_BLADE, 44, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* yng fem claws */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_BLADE, 45, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* old male claws */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_BLADE, 46, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* old fem claws */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_TENTACLES, 47, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* queen tentacles*/ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_GUN, 48, TARGETCURS, 0, 0, 0, 0, 1, 0, 0, /* queen spit */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_PUNCH, 49, PUNCHCURS, 0, 1, 102, 1, 4, 20, 2, /* brass knuckles */ 0, 0, IF_STANDARD_BLADE },
|
|
//{ IC_LAUNCHER, 50, INVALIDCURS,0, 0, 39, 13, 0, 500, 8, /* underslung g.l.*/ 0, 0, IF_STANDARD_GUN},
|
|
//
|
|
//{ IC_GUN, 51, TARGETCURS, 0, 0, 38, 21, 0, 500, 9, /* rocket Launcher*/ 0, -3, IF_TWOHANDED_GUN }, // now repairable
|
|
//{ IC_BLADE, 52, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* bloodcat claws*/ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_BLADE, 53, KNIFECURS, 0, 0, 0, 0, 1, 0, 0, /* bloodcat bite */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_BLADE, 54, KNIFECURS, 0, 0, 41, 13, 0, 200, 3, /* machete */ 0, +3, IF_STANDARD_BLADE},
|
|
//{ IC_GUN, 55, TARGETCURS, 0, 0, 45, 40, 0, 5000, 10, /* rocket rifle */ 0, -5, IF_TWOHANDED_GUN | ITEM_ELECTRONIC },
|
|
//{ IC_GUN, 56, TARGETCURS, 0, 0, 40, 12, 0, 1000, 0, /* Automag III */ 0, -2, IF_STANDARD_GUN },
|
|
//{ IC_GUN, 57, TARGETCURS, 0, 0, 0, 0, 0, 0, 0, /* infant spit */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_GUN, 58, TARGETCURS, 0, 0, 0, 0, 0, 0, 0, /* yng male spit */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//
|
|
//{ IC_GUN, 59, TARGETCURS, 0, 0, 0, 0, 0, 0, 0, /* old male spit */ 0, 0, ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE },
|
|
//{ IC_GUN, 60, TARGETCURS, 0, 0, 37, 26, 0, 0, 0, /* tank cannon */ 0, 0, ITEM_NOT_BUYABLE },
|
|
//
|
|
//{ IC_GUN, 61, TARGETCURS, 0, 0, 46, 12, 1, 500, 5, /* dart gun */ 0, +3, IF_STANDARD_GUN },
|
|
//{ IC_THROWING_KNIFE,62, TARGETCURS, 0, 1, 95, 1, 4, 50, 0, /*bloody throw.knife*/0, +4, IF_STANDARD_BLADE | ITEM_NOT_BUYABLE },
|
|
//{ IC_GUN, 63, TARGETCURS, 0, 0, 48, 18, 0, 0, 0, /* flamethrower */ 0, 0, IF_STANDARD_GUN },
|
|
//{ IC_PUNCH, 64, PUNCHCURS, 0, 1, 85, 30, 0, 40, 1, /* Crowbar */ 0, -4, ITEM_METAL | ITEM_DAMAGEABLE },
|
|
//{ IC_GUN, 65, TARGETCURS, 0, 0, 45, 40, 0, 10000, 10, /* rocket rifle */ 0, -5, IF_TWOHANDED_GUN | ITEM_ELECTRONIC },
|
|
//// MADD MARKER
|
|
//{ IC_GUN, 66, TARGETCURS, CONDBUL, 0, 55, 122,0, 6200, 10, /* Barrett */ +1, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 67, TARGETCURS, CONDBUL, 0, 56, 25, 0, 4100, 9, /* VAL Silent */ -3, -3, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 68, TARGETCURS, CONDBUL, 0, 57, 80, 0, 2700, 8, /* PSG */ +4, +4, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 69, TARGETCURS, CONDBUL, 0, 58, 24, 0, 2100, 8, /* TAR 21 */ +3, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
////MAX WEAPONS spot
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////---AMMO---
|
|
//{ IC_AMMO, 0, INVALIDCURS, 0, 1, 32, 2, 8, 15, 2, /* CLIP9_15 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 1, INVALIDCURS, 0, 1, 35, 3, 4, 30, 4, /* CLIP9_30 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 2, INVALIDCURS, 0, 1, 33, 2, 8, 45, 4, /* CLIP9_15_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 3, INVALIDCURS, 0, 1, 36, 3, 4, 90, 6, /* CLIP9_30_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 4, INVALIDCURS, 0, 1, 34, 2, 8, 30, 3, /* CLIP9_15_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 5, INVALIDCURS, 0, 1, 37, 3, 4, 60, 5, /* CLIP9_30_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 6, INVALIDCURS, 0, 1, 24, 1, 8, 5, 1, /* CLIP38_6 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 7, INVALIDCURS, 0, 1, 25, 1, 8, 15, 3, /* CLIP38_6_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 8, INVALIDCURS, 0, 1, 26, 1, 8, 10, 2, /* CLIP38_6_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 9, INVALIDCURS, 0, 1, 14, 2, 8, 10, 2, /* CLIP45_7 */ 0, 0, IF_STANDARD_CLIP},
|
|
//
|
|
//{ IC_AMMO, 10, INVALIDCURS, 0, 1, 4, 10, 4, 45, 3, /* CLIP45_30 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 11, INVALIDCURS, 0, 1, 15, 2, 8, 45, 4, /* CLIP45_7_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 12, INVALIDCURS, 0, 1, 5, 10, 4, 135, 5, /* CLIP45_30_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 13, INVALIDCURS, 0, 1, 16, 2, 8, 30, 3, /* CLIP45_7_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 14, INVALIDCURS, 0, 1, 6, 10, 4, 90, 4, /* CLIP45_30_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 15, INVALIDCURS, 0, 1, 11, 1, 8, 10, 1, /* CLIP357_6 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 16, INVALIDCURS, 0, 1, 17, 3, 8, 15, 1, /* CLIP357_9 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 17, INVALIDCURS, 0, 1, 12, 1, 8, 30, 3, /* CLIP357_6_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 18, INVALIDCURS, 0, 1, 18, 3, 8, 45, 3, /* CLIP357_9_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 19, INVALIDCURS, 0, 1, 13, 1, 8, 20, 2, /* CLIP357_6_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//
|
|
//{ IC_AMMO, 20, INVALIDCURS, 0, 1, 19, 3, 8, 30, 2, /* CLIP357_9_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 21, INVALIDCURS, 0, 1, 9, 6, 4, 150, 5, /* CLIP545_30_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 22, INVALIDCURS, 0, 1, 10, 6, 4, 100, 4, /* CLIP545_30_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 23, INVALIDCURS, 0, 1, 7, 5, 4, 150, 4, /* CLIP556_30_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 24, INVALIDCURS, 0, 1, 8, 5, 4, 100, 3, /* CLIP556_30_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 25, INVALIDCURS, 0, 1, 22, 3, 6, 60, 6, /* CLIP762W_10_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 26, INVALIDCURS, 0, 1, 29, 8, 4, 180, 4, /* CLIP762W_30_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 27, INVALIDCURS, 0, 1, 23, 3, 6, 40, 5, /* CLIP762W_10_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 28, INVALIDCURS, 0, 1, 30, 8, 4, 120, 3, /* CLIP762W_30_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 29, INVALIDCURS, 0, 1, 3, 1, 6, 30, 7, /* CLIP762N_5_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//
|
|
//{ IC_AMMO, 30, INVALIDCURS, 0, 1, 27, 8, 4, 120, 6, /* CLIP762N_20_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 31, INVALIDCURS, 0, 1, 2, 1, 6, 20, 6, /* CLIP762N_5_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 32, INVALIDCURS, 0, 1, 28, 8, 4, 80, 5, /* CLIP762N_20_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 33, INVALIDCURS, 0, 1, 31, 5, 4, 700, 8, /* CLIP47_50_SAP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 34, INVALIDCURS, 0, 1, 20, 9 , 4, 750, 9, /* CLIP57_50_SAP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 35, INVALIDCURS, 0, 1, 21, 9, 4, 500, 9, /* CLIP57_50_HP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 36, INVALIDCURS, 0, 2, 22, 5, 6, 20, 3, /* CLIP12G_7 */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 37, INVALIDCURS, 0, 2, 4, 5, 6, 20, 3, /* CLIP12G_7_BUCKSHOT */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 38, INVALIDCURS, 0, 1, 0, 10, 6, 300, 9, /* CLIPCAWS_10_SAP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 39, INVALIDCURS, 0, 1, 1, 10, 6, 300, 9, /* CLIPCAWS_10_FLECH */ 0, 0, IF_STANDARD_CLIP},
|
|
//
|
|
//{ IC_AMMO, 40, INVALIDCURS, 0, 1, 110, 10, 4, 500, 9, /* CLIPROCKET_AP */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 41, INVALIDCURS, 0, 1, 115, 10, 4, 500, 9, /* CLIPROCKET_HE */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 42, INVALIDCURS, 0, 1, 114, 10, 4, 500, 9, /* CLIPROCKET_HEAT */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 43, INVALIDCURS, 0, 1, 119, 1, 8, 10, 4, /* sleep dart */ 0, 0, IF_STANDARD_CLIP},
|
|
//{ IC_AMMO, 44, INVALIDCURS, 0, 0, 49, 8, 4, 0, 0, /* flameThrwr clip */ 0, 0, IF_STANDARD_CLIP },
|
|
//// MADD MARKER
|
|
//{ IC_AMMO, 45, INVALIDCURS, 0, 1, 138, 9, 4, 300, 10, /* CLIP50_11 */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 46, INVALIDCURS, 0, 1, 139, 4, 4, 50, 9, /* CLIP9H_20 */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 47, INVALIDCURS, 0, 1, 140, 8, 4, 50, 6, /* CLIP9_50 */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 48, INVALIDCURS, 0, 1, 141, 8, 4, 50, 7, /* CLIP9_50_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 49, INVALIDCURS, 0, 1, 142, 8, 4, 60, 7, /* CLIP9_50_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//
|
|
//{ IC_AMMO, 50, INVALIDCURS, 0, 1, 143, 15, 1, 375, 9, /* DRUM545_75_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 51, INVALIDCURS, 0, 1, 144, 15, 1, 250, 9, /* DRUM545_75_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 52, INVALIDCURS, 0, 1, 145, 30, 1, 1000,9, /* BELT556_200_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 53, INVALIDCURS, 0, 1, 146, 30, 1, 650, 9, /* BELT556_200_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 54, INVALIDCURS, 0, 1, 153, 40, 1, 600, 9, /* BELT762N_100_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 55, INVALIDCURS, 0, 1, 154, 40, 1, 400, 9, /* BELT762N_100_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 56, INVALIDCURS, 0, 1, 147, 3, 8, 300, 6, /* CLIP57_20_AP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
//{ IC_AMMO, 57, INVALIDCURS, 0, 1, 148, 3, 8, 200, 6, /* CLIP57_20_HP */ 0, 0, IF_STANDARD_CLIP | ITEM_BIGGUNLIST },
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
////---EXPLOSIVES---
|
|
//
|
|
//{ IC_GRENADE, 0, TOSSCURS, 0, 1, 38, 6, 4, 100, 5, /* stun grenade */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE },
|
|
//{ IC_GRENADE, 1, TOSSCURS, 0, 1, 48, 6, 4, 120, 4, /* tear gas grenade */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 2, TOSSCURS, 0, 1, 41, 6, 4, 500, 7, /* mustard gas grenade*/ 0, -3, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 3, TOSSCURS, 0, 1, 50, 3, 6, 150, 5, /* mini hand grenade */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 4, TOSSCURS, 0, 1, 49, 6, 4, 200, 6, /* reg hand grenade */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 5, INVALIDCURS, 0, 2, 3, 11, 2, 400, 7, /* RDX */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 6, INVALIDCURS, 0, 2, 0, 11, 1, 500, 4, /* TNT (="explosives")*/ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 7, INVALIDCURS, 0, 2, 23, 11, 1, 1000, 8, /* HMX (=RDX+TNT) */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 8, INVALIDCURS, 0, 1, 45, 11, 1, 750, 7, /* C1 (=RDX+min oil) */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 9, INVALIDCURS, 0, 1, 40, 41, 2, 400, 9, /* mortar shell */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//
|
|
//{ IC_BOMB, 10, BOMBCURS, 0, 1, 46, 8, 1, 300, 5, /* mine */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE },
|
|
//{ IC_BOMB, 11, INVALIDCURS, 0, 1, 44, 11, 1, 1500, 9, /* C4 ("plastique") */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 12, BOMBCURS, 0, 1, 42, 4, 2, 0, 0, /* trip flare */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_NOT_BUYABLE | ITEM_REPAIRABLE },
|
|
//{ IC_BOMB, 13, BOMBCURS, 0, 1, 43, 4, 2, 0, 0, /* trip klaxon */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_NOT_BUYABLE | ITEM_REPAIRABLE },
|
|
//{ IC_BOMB, 14, INVALIDCURS, 0, 1, 107, 2, 4, 250, 5, /* shaped charge */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 15, TOSSCURS, 0, 2, 24, 1, 6, 50, 3, /* break light (flare)*/ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 16, INVALIDCURS, 0, 1, 97, 10, 4, 400, 8, /* 40mm HE grenade */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 17, INVALIDCURS, 0, 1, 111, 10, 4, 250, 6, /* 40mm tear gas grnd */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 18, INVALIDCURS, 0, 1, 113, 10, 4, 200, 5, /* 40mm stun grenade */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 19, INVALIDCURS, 0, 1, 112, 10, 4, 100, 7, /* 40mm smoke grenade */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//
|
|
//{ IC_GRENADE, 20, TOSSCURS, 0, 1, 98, 6, 4, 50, 3, /* smoke hand grenade */ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_BOMB, 21, INVALIDCURS, 0, 1, 40, 41, 8, 450, 0, /* tank shell */ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR },
|
|
//{ IC_BOMB, 22, INVALIDCURS, 0, 1, 40, 41, 2, 450, 0, /* fake struct ignite*/ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_NOT_BUYABLE },
|
|
//{ IC_GRENADE, 23, TOSSCURS, 0, 2, 37, 6, 4, 50, 0, /* creature cocktail*/ 0, 0, ITEM_DAMAGEABLE | ITEM_METAL },
|
|
//{ IC_BOMB, 24, INVALIDCURS, 0, 1, 40, 41, 2, 450, 0, /* fake struct xplod*/ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_NOT_BUYABLE },
|
|
//{ IC_BOMB, 25, INVALIDCURS, 0, 1, 40, 41, 2, 450, 0, /* fake vehicle xplod*/ 0, -4, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_NOT_BUYABLE },
|
|
//{ IC_GRENADE, 26, TOSSCURS, 0, 1, 48, 6, 4, 0, 0, /* BIG tear gas grenade*/ 0, -2, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE | ITEM_NOT_BUYABLE },
|
|
//{ IC_GRENADE, 27, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* small creature gas */ 0, 0, 0},
|
|
//{ IC_GRENADE, 28, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* big creature gas */ 0, 0, 0},
|
|
//{ IC_GRENADE, 29, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* very sm creat gas */ 0, 0, 0},
|
|
//
|
|
////---ARMOUR---
|
|
//{ IC_ARMOUR, 0, INVALIDCURS, COND, 1, 66, 20, 0, 300, 2, /* Flak jacket */ 0, +2, IF_STANDARD_ARMOUR},
|
|
//{ IC_ARMOUR, 1, INVALIDCURS, COND, 2, 18, 22, 0, 350, 0, /* Flak jacket w X */ 0, +1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 2, INVALIDCURS, COND, 2, 11, 18, 0, 400, 0, /* Flak jacket w Y */ 0, +3, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 3, INVALIDCURS, COND, 1, 64, 32, 0, 500, 4, /* Kevlar jacket */ 0, 0, IF_STANDARD_ARMOUR},
|
|
//{ IC_ARMOUR, 4, INVALIDCURS, COND, 2, 16, 35, 0, 600, 0, /* Kevlar jack w X */ 0, -1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 5, INVALIDCURS, COND, 2, 9, 29, 0, 700, 0, /* Kevlar jack w Y */ 0, +1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 6, INVALIDCURS, COND, 1, 65, 32, 0, 1000, 8, /* Spectra jacket */ 0, -2, IF_STANDARD_ARMOUR},
|
|
//{ IC_ARMOUR, 7, INVALIDCURS, COND, 2, 17, 35, 0, 1100, 0, /* Spectra jack w X*/ 0, -3, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 8, INVALIDCURS, COND, 2, 10, 29, 0, 1200, 0, /* Spectra jack w Y*/ 0, -1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 9, INVALIDCURS, COND, 1, 67, 39, 0, 650, 5, /* Kevlar leggings */ 0, 0, IF_STANDARD_ARMOUR},
|
|
//
|
|
//{ IC_ARMOUR, 10, INVALIDCURS, COND, 2, 19, 43, 0, 800, 0, /* Kevlar legs w X */ 0, -1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 11, INVALIDCURS, COND, 2, 12, 35, 0, 950, 0, /* Kevlar legs w Y */ 0, +1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 12, INVALIDCURS, COND, 1, 68, 39, 0, 900, 8, /* Spectra leggings*/ 0, -2, IF_STANDARD_ARMOUR},
|
|
//{ IC_ARMOUR, 13, INVALIDCURS, COND, 2, 20, 43, 0, 1100, 0, /* Spectra legs w X*/ 0, -3, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 14, INVALIDCURS, COND, 2, 13, 35, 0, 1300, 0, /* Spectra legs w Y*/ 0, -1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 15, INVALIDCURS, COND, 1, 61, 14, 0, 50, 2, /* Steel helmet */ 0, +2, IF_STANDARD_ARMOUR | ITEM_METAL},
|
|
//{ IC_ARMOUR, 16, INVALIDCURS, COND, 1, 63, 14, 0, 200, 4, /* Kevlar helmet */ 0, 0, IF_STANDARD_ARMOUR},
|
|
//{ IC_ARMOUR, 17, INVALIDCURS, COND, 2, 15, 15, 0, 250, 0, /* Kevlar helm w X */ 0, -1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 18, INVALIDCURS, COND, 2, 8, 13, 0, 300, 0, /* Kevlar helm w Y */ 0, +1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 19, INVALIDCURS, COND, 1, 62, 14, 0, 450, 7, /* Spectra helmet */ 0, -2, IF_STANDARD_ARMOUR},
|
|
//
|
|
//{ IC_ARMOUR, 20, INVALIDCURS, COND, 2, 14, 15, 0, 550, 0, /* Spectra helm w X*/ 0, -3, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 21, INVALIDCURS, COND, 2, 7, 13, 0, 650, 0, /* Spectra helm w Y*/ 0, -1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 22, INVALIDCURS, COND, 1, 81, 12, 2, 250, 5, /* Ceramic plates */ 0, -4, (IF_STANDARD_ARMOUR | ITEM_ATTACHMENT) & (~ITEM_REPAIRABLE) },
|
|
//{ IC_ARMOUR, 23, INVALIDCURS, COND, 1, 0, 0, 0, 0, 0, /* Infant crt hide */ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE},
|
|
//{ IC_ARMOUR, 24, INVALIDCURS, COND, 1, 0, 0, 0, 0, 0, /* Yng male hide */ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE},
|
|
//{ IC_ARMOUR, 25, INVALIDCURS, COND, 1, 0, 0, 0, 0, 0, /* Old male hide */ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE},
|
|
//{ IC_ARMOUR, 26, INVALIDCURS, COND, 1, 0, 0, 0, 0, 0, /* Queen cret hide */ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE},
|
|
//{ IC_ARMOUR, 27, INVALIDCURS, COND, 1, 96, 20, 0, 200, 2, /* Leather jacket */ 0, +4, IF_STANDARD_ARMOUR },
|
|
//// NOTE: THE FOLLOWING ITEM'S PRICE VALUE IS IN DIALOGUE AND SHOULD NOT BE CHANGED
|
|
//{ IC_ARMOUR, 28, INVALIDCURS, COND, 1, 116, 20, 0, 950, 3, /* L jacket w kev */ 0, +2, IF_STANDARD_ARMOUR },
|
|
//{ IC_ARMOUR, 29, INVALIDCURS, COND, 1, 117, 20, 0, 1200, 0, /* L jacket w kev 18*/0, +1, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//
|
|
//{ IC_ARMOUR, 30, INVALIDCURS, COND, 1, 118, 20, 0, 1500, 0, /* L jacket w kev c*/ 0, +3, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 31, INVALIDCURS, COND, 1, 0, 0, 0, 0, 0, /* yng fem hide */ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE},
|
|
//{ IC_ARMOUR, 32, INVALIDCURS, COND, 1, 0, 0, 0, 0, 0, /* old fem hide */ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE | ITEM_NOT_EDITOR | ITEM_DEFAULT_UNDROPPABLE},
|
|
//{ IC_ARMOUR, 33, INVALIDCURS, COND, 2, 25, 3, 1, 10, 1, /* t-shirt */ 0, 0, ITEM_DAMAGEABLE | ITEM_SHOW_STATUS | ITEM_UNAERODYNAMIC},
|
|
//{ IC_ARMOUR, 33, INVALIDCURS, COND, 2, 34, 3, 1, 10, 1, /* t-shirt D. rules*/ 0, 0, ITEM_DAMAGEABLE | ITEM_SHOW_STATUS | ITEM_UNAERODYNAMIC},
|
|
//{ IC_ARMOUR, 34, INVALIDCURS, COND, 1, 137, 32, 0, 700, 6, /* Kevlar2 jacket */ 0, -1, IF_STANDARD_ARMOUR},
|
|
//{ IC_ARMOUR, 35, INVALIDCURS, COND, 2, 40, 35, 0, 800, 0, /* Kevlar2 jack w X*/ 0, -2, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_ARMOUR, 36, INVALIDCURS, COND, 2, 41, 29, 0, 900, 0, /* Kevlar2 jack w Y*/ 0, 0, IF_STANDARD_ARMOUR | ITEM_NOT_BUYABLE },
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
////---MISC---
|
|
//{ IC_MEDKIT, 0, AIDCURS, USAGE, 1, 73, 5, 4, 100, 1, /* First aid kit */ 0, 0, IF_STANDARD_KIT},
|
|
//{ IC_MEDKIT, 0, AIDCURS, USAGE, 1, 86, 18, 0, 300, 1, /* Medical Kit */ 0, 0, IF_STANDARD_KIT | ITEM_METAL},
|
|
//{ IC_KIT, 0, REPAIRCURS, COND, 2, 21, 50, 0, 250, 1, /* Tool Kit */ 0, 0, IF_STANDARD_KIT | ITEM_METAL},
|
|
//{ IC_KIT, 0, INVALIDCURS, COND, 1, 78, 3, 1, 250, 3, /* Locksmith kit */ 0, -2, IF_STANDARD_KIT | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_KIT, 0, INVALIDCURS, COND, 1, 58, 1, 4, 250, 5, /* Camouflage kit*/ 0, 0, IF_STANDARD_KIT},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 52, 5, 4, 300, 4, /* Silencer */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 76, 9, 4, 500, 5, /* Sniper scope */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 69, 5, 2, 50, 3, /* Bipod */ 0, +5, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 1, 77, 9, 1, 400, 7, /* Extended ear */ 0, -3, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 1, 74, 9, 1, 800, 7, /* Night goggles */ 0, -1, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 1, 55, 2, 4, 150, 3, /* Sun goggles */ 0, +3, ITEM_DAMAGEABLE | ITEM_REPAIRABLE },
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 1, 75, 9, 1, 100, 4, /* Gas mask */ 0, +1, ITEM_DAMAGEABLE | ITEM_REPAIRABLE },
|
|
//{ IC_KIT, 0, INVALIDCURS, 0, 2, 5, 10, 4, 10, 1, /* Canteen */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 80, 10, 1, 200, 4, /* Metal detector*/ 0, -2, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 6, 1, 4, 900, 7, /* Compound 18 */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 42, 1, 4, 2500, 0, /* Jar/QueenBlood*/ 0, 0, ITEM_DAMAGEABLE | ITEM_NOT_BUYABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 2, 1, 4, 500, 1, /* Jar/Elixir */ 0, 0, ITEM_DAMAGEABLE },
|
|
//{ IC_MONEY, 0, INVALIDCURS, 0, 2, 1, 1, 1, 0, 0, /* Money */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, JARCURS, COND, 1, 71, 1, 2, 10, 1, /* Glass jar */ 0, 0, ITEM_DAMAGEABLE},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, COND, 1, 72, 5, 2, 50, 1, /* Jar/CreatureBlood*/0, 0, ITEM_DAMAGEABLE | ITEM_NOT_BUYABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 70, 1, 8, 150, 4, /* Adren Booster */ 0, 0, ITEM_DAMAGEABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, COND, 1, 47, 1, 4, 100, 3, /* Detonator */ 0, +1, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_ATTACHMENT | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, COND, 1, 47, 1, 4, 200, 6, /* Rem Detonator */ 0, -1, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_ATTACHMENT | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 93, 1, 8, 0, 0, /* Videotape */ 0, 0, ITEM_NOT_BUYABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 94, 1, 8, 0, 0, /* Deed */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 56, 1, 1, 0, 0, /* Letter */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 59, 1, 1, 0, 0, /* Diskette */ 0, 0, ITEM_NOT_BUYABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 124, 0, 1, 3000, 0, /* Chalice */ 0, 0, ITEM_NOT_BUYABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 120, 1, 4, 50, 0, /* Bloodcat claws*/ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 121, 1, 4, 100, 0, /* Bloodcat teeth*/ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 9, 60, 0, 400, 0, /* Bloodcat pelt */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 54, 0, 99, 0, 0, /* Switch */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 47, 0, 99, 0, 0, /* Action item */ 0, 0, ITEM_NOT_BUYABLE },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 70, 1, 6, 300, 6, /* Regen Booster */ 0, 0, ITEM_DAMAGEABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 70, 0, 99, 0, 0, /* syringe 3 */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 70, 0, 99, 0, 0, /* syringe 4 */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 70, 0, 99, 0, 0, /* syringe 5 */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, COND, 1, 72, 5, 2, 10, 1, /* Jar/Human Blood*/ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 0, 0, 0, 0, 0, /* ownership */ 0, 0, ITEM_NOT_BUYABLE},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 51, 4, 4, 750, 7, /* Laser scope */ 0, -1, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, REMOTECURS, 0, 1, 54, 9, 4, 400, 6, /* Remote bomb trig*/ 0, -2, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, WIRECUTCURS, 0, 1, 88, 4, 2, 20, 2, /* Wirecutters */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 90, 9, 4, 30, 2, /* Duckbill */ 0, +5, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 106, 20, 1, 30, 1, /* Alcohol */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 1, 74, 11, 1, 1500, 9, /* UV goggles */ 0, -1, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 0, 44, 21, 0, 30, 0, /* discarded LAW*/ 0, 0, IF_TWOHANDED_GUN | ITEM_NOT_BUYABLE },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 0, 40, 0, 0, 0, /* head - generic */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 1, 40, 0, 0, 0, /* head - Imposter*/ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 2, 40, 0, 0, 0, /* head - T-Rex */ 0, 0, ITEM_DAMAGEABLE},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 3, 40, 0, 0, 0, /* head - Slay */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 4, 40, 0, 0, 0, /* head - Druggist */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 5, 40, 0, 0, 0, /* head - Matron */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 6, 40, 0, 0, 0, /* head - Tiffany */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 100, 12, 1, 20, 1, /* wine */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 101, 4, 4, 10, 1, /* beer */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 99, 0, 2, 20, 3, /* pornos */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 0, 43, 20, 0, 900, 6, /* video camera */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 0, 42, 5, 1, 2500, 0, /* robot remote */ 0, -5, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 103, 20, 0, 500, 0, /* creature claws */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 7, 40, 0, 250, 0, /* creature flesh */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 104, 10, 0, 1000, 0, /* creature organ */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, REMOTECURS, 0, 1, 54, 9, 4, 400, 6, /* Remote trigger*/ 0, -2, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 0, 47, 2, 8, 500, 2, /* gold watch */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 136, 100, 0, 200, 2, /* golf clubs */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL},
|
|
//{ IC_FACE, 0, INVALIDCURS, 0, 3, 11, 5, 1, 100, 1, /* walkman */ 0, -4, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 8, 50, 0, 300, 2, /* portable tv */ 0, -3, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_ELECTRONIC },
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 3, 10, 10, 1, 30, 1, /* cigars */ 0, 0, ITEM_DAMAGEABLE },
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
//{ IC_KEY, 0, INVALIDCURS, 0, 1, 82, 1, 8, 0, 0, /* dull gold key */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 1, INVALIDCURS, 0, 1, 83, 1, 8, 0, 0, /* silver key */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 2, INVALIDCURS, 0, 1, 84, 1, 8, 0, 0, /* diamond-shpd key */0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 3, INVALIDCURS, 0, 1, 87, 1, 8, 0, 0, /* bright gold key */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 4, INVALIDCURS, 0, 1, 91, 1, 8, 0, 0, /* gold key */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 5, INVALIDCURS, 0, 1, 92, 1, 8, 0, 0, /* small gold key */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 6, INVALIDCURS, 0, 1, 108, 1, 8, 0, 0, /* electronic */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL | ITEM_ELECTRONIC },
|
|
//{ IC_KEY, 7, INVALIDCURS, 0, 1, 109, 1, 8, 0, 0, /* passcard */ 0, 0, ITEM_NOT_BUYABLE | ITEM_METAL},
|
|
//{ IC_KEY, 8, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 9, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 149, 4, 4, 100, 3, /* Flash Suppressor */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
//{ IC_LAUNCHER, 282, TARGETCURS, 0, 0, 68, 79, 0, 1500, 10, /* rpg 7 */ 0, -3, IF_TWOHANDED_GUN },
|
|
//{ IC_GRENADE, 30, INVALIDCURS, 0, 1, 150, 21, 0, 1200, 10, /* HE rpg ammo */ 0, 0, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 31, INVALIDCURS, 0, 1, 152, 21, 0, 2000, 10, /* AP rpg ammo */ 0, 0, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_GRENADE, 32, INVALIDCURS, 0, 1, 151, 21, 0, 1000, 10, /* Frag rpg ammo */ 0, 0, ITEM_DAMAGEABLE | ITEM_METAL | ITEM_REPAIRABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 155, 4, 4, 1200, 6, /* Reflex scoped */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 156, 2, 4, 1200, 6, /* Reflex unscoped */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ATTACHMENT},
|
|
////{ IC_KEY, 10, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
////{ IC_KEY, 11, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
////{ IC_KEY, 12, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
////{ IC_KEY, 13, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
////{ IC_KEY, 14, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
////{ IC_KEY, 15, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
////{ IC_KEY, 16, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 17, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 18, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 19, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//
|
|
//{ IC_KEY, 20, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 21, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 22, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 23, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 24, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 25, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 26, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 27, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 28, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 29, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//
|
|
//{ IC_KEY, 30, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_KEY, 31, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* key */ 0, 0, ITEM_NOT_EDITOR | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 31, 4, 0, 150, 2, /* silver platter */ 0, 0, ITEM_DAMAGEABLE | ITEM_METAL},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 30, 1, 6, 5, 1, /* duct tape */ 0, 0, ITEM_DAMAGEABLE | ITEM_HIDDEN_ADDON },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 28, 3, 1, 20, 0, /* aluminum rod */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE | ITEM_METAL | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 32, 1, 8, 0, 0, /* spring */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE | ITEM_METAL | ITEM_UNAERODYNAMIC | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 33, 4, 1, 25, 0, /* a. rod & spring */ 0, 0, ITEM_NOT_BUYABLE | ITEM_REPAIRABLE | ITEM_DAMAGEABLE | ITEM_METAL | ITEM_INSEPARABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 133, 4, 1, 20, 0, /* steel rod */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE | ITEM_METAL | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 132, 2, 6, 5, 3, /* quick glue */ 0, 0, ITEM_DAMAGEABLE | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 134, 6, 1, 150, 0, /* gun barrel xtndr */0, 0, ITEM_NOT_BUYABLE | ITEM_REPAIRABLE | ITEM_DAMAGEABLE | ITEM_METAL | ITEM_INSEPARABLE},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 35, 1, 8, 0, 0, /* string */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 27, 1, 1, 0, 0, /* tin can */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, TINCANCURS, 0, 2, 36, 2, 4, 0, 0, /* string & tin can */0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 122, 3, 6, 5, 0, /* marbles */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 127, 6, 1, 200, 6, /* lame boy */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_ELECTRONIC | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 128, 1, 8, 5, 1, /* copper wire */ 0, 0, ITEM_METAL | ITEM_HIDDEN_ADDON },
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 126, 7, 1, 50, 0, /* display unit */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_ELECTRONIC | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 130, 1, 1, 100, 5, /* fumble pak */ 0, 0, ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_ELECTRONIC},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 131, 1, 2, 10, 5, /* xray bulb */ 0, 0, ITEM_DAMAGEABLE | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 29, 1, 8, 1, 1, /* chewing gum */ 0, 0, ITEM_DAMAGEABLE | ITEM_HIDDEN_ADDON},
|
|
//
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 129, 3, 1, 100, 0, /* flash device */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC | ITEM_HIDDEN_ADDON},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 2, 26, 1, 6, 5, 1, /* batteries */ 0, 0, ITEM_DAMAGEABLE},
|
|
//{ IC_MISC, 0, INVALIDCURS, 0, 1, 123, 1, 8, 0, 0, /* elastic */ 0, 0, ITEM_NOT_BUYABLE | ITEM_UNAERODYNAMIC},
|
|
//{ IC_MISC, 0, REMOTECURS, 0, 1, 125, 10, 1, 2500, 0, /* xray device */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE | ITEM_REPAIRABLE | ITEM_METAL | ITEM_ELECTRONIC},
|
|
//{ IC_MONEY, 0, INVALIDCURS, 0, 2, 38, 2, 1, 100, 0, /* silver */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//{ IC_MONEY, 0, INVALIDCURS, 0, 1, 135, 2, 1, 300, 0, /* gold */ 0, 0, ITEM_NOT_BUYABLE | ITEM_DAMAGEABLE},
|
|
//{ IC_KIT, 0, REFUELCURS, 0, 2, 39, 20, 0, 250, 0, /* gas can */ 0, 0, ITEM_DAMAGEABLE},
|
|
//
|
|
//{ IC_GUN, 328, TARGETCURS, CONDBUL, 0, 50, 22, 0, 900, 8, /* M900 */ +1, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 329, TARGETCURS, CONDBUL, 0, 51, 10, 0, 400, 6, /* M950 */ +1, -1, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 330, TARGETCURS, CONDBUL, 0, 52, 22, 0, 900, 7, /* M960A */ +1, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 331, TARGETCURS, CONDBUL, 0, 53, 19, 1, 300, 5, /* Micro Uzi */ +1, -1, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 332, TARGETCURS, CONDBUL, 0, 54, 38, 0, 1300, 6, /* Enfield */ 0, +1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 333, TARGETCURS, CONDBUL, 0, 59, 25, 0, 900, 4, /* MP5A2 */ 0, +1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 334, TARGETCURS, CONDBUL, 0, 60, 29, 0, 1000, 4, /* MP5SD */ 0, 0, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 335, TARGETCURS, CONDBUL, 0, 61, 29, 0, 1600, 7, /* MP5N */ +2, 0, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 336, TARGETCURS, CONDBUL, 0, 62, 22, 0, 1300, 6, /* UMP45 */ 0, 0, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 337, TARGETCURS, CONDBUL, 0, 63, 6, 1, 1000, 7, /* FIVE7 */ +1, 0, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 338, TARGETCURS, CONDBUL, 0, 64, 7, 1, 400, 4, /* p7m8 */ +2, +1, IF_STANDARD_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 339, TARGETCURS, CONDBUL, 0, 65, 33, 0, 2500, 9, /* g36k */ +3, 0, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 340, TARGETCURS, CONDBUL, 0, 66, 28, 0, 2400, 9, /* g36c */ +3, 0, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 341, TARGETCURS, CONDBUL, 0, 67, 64, 0, 3000, 10, /* MSG90A1 */ +4, +4, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 342, TARGETCURS, CONDBUL, 0, 69, 32, 0, 1400, 7, /* BENNELLI */ +2, +1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//{ IC_GUN, 343, TARGETCURS, CONDBUL, 0, 70, 34, 0, 2200, 8, /* AK103 */ -1, -1, IF_TWOHANDED_GUN | ITEM_BIGGUNLIST },
|
|
//
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
////{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//{ IC_NONE, 0, INVALIDCURS, 0, 0, 0, 0, 0, 0, 0, /* nothing! */ 0, 0, 0},
|
|
//
|
|
//};
|
|
|
|
|
|
// NB hack: if an item appears in this array with an item class of IC_MISC,
|
|
// it is a slot used for noting the skill check required for a merge or multi-item attachment
|
|
|
|
AttachmentInfoStruct AttachmentInfo[MAXITEMS+1];// =
|
|
//{
|
|
// { SILENCER, IC_GUN, NO_CHECK, 0 },
|
|
// { SNIPERSCOPE, IC_GUN, NO_CHECK, 0 },
|
|
// { LASERSCOPE, IC_GUN, NO_CHECK, 0 },
|
|
// { BIPOD, IC_GUN, NO_CHECK, 0 },
|
|
// { UNDER_GLAUNCHER, IC_GUN, NO_CHECK, 0 },
|
|
// { DUCKBILL, IC_GUN, NO_CHECK, 0 },
|
|
// { SPRING_AND_BOLT_UPGRADE, IC_GUN, ATTACHING_SPECIAL_ITEM_CHECK, 0 },
|
|
// { GUN_BARREL_EXTENDER, IC_GUN, ATTACHING_SPECIAL_ITEM_CHECK, 0 },
|
|
// { DETONATOR, IC_BOMB, ATTACHING_DETONATOR_CHECK, 0 },
|
|
// { REMDETONATOR, IC_BOMB, ATTACHING_REMOTE_DETONATOR_CHECK, -10 },
|
|
// { REMDETONATOR, IC_BOMB, ATTACHING_REMOTE_DETONATOR_CHECK, -10 },
|
|
// { XRAY_BULB, IC_NONE, ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK, -15 },
|
|
// { COPPER_WIRE, IC_NONE, ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK, +20 },
|
|
// { CERAMIC_PLATES, IC_ARMOUR, NO_CHECK, 0 },
|
|
// { FLASH_SUPPRESSOR, IC_GUN, NO_CHECK, 0 },
|
|
// { REFLEX_SCOPED, IC_GUN, NO_CHECK, 0 },
|
|
// { REFLEX_UNSCOPED, IC_GUN, NO_CHECK, 0 },
|
|
// { 0, 0 }
|
|
//};
|
|
|
|
UINT16 Attachment[MAXATTACHMENTS][3];// =
|
|
//{
|
|
// {SILENCER, GLOCK_17},
|
|
// {SILENCER, GLOCK_18},
|
|
// {SILENCER, BERETTA_92F},
|
|
// {SILENCER, BERETTA_93R},
|
|
// {SILENCER, SW38},
|
|
// {SILENCER, BARRACUDA},
|
|
// {SILENCER, DESERTEAGLE},
|
|
// {SILENCER, M1911},
|
|
// {SILENCER, MP5K},
|
|
// {SILENCER, MAC10},
|
|
// {SILENCER, THOMPSON},
|
|
// {SILENCER, P90},
|
|
// {SILENCER, M960},
|
|
// {SILENCER, MICRO_UZI},
|
|
// {SILENCER, M950},
|
|
// {SILENCER, MP5},
|
|
// {SILENCER, MP5N},
|
|
// {SILENCER, FIVE7},
|
|
// {SILENCER, P7M8},
|
|
// {SILENCER, MSG90A1},
|
|
//
|
|
// {SNIPERSCOPE, COMMANDO},
|
|
// {SNIPERSCOPE, SKS},
|
|
// {SNIPERSCOPE, DRAGUNOV},
|
|
// {SNIPERSCOPE, M24},
|
|
// {SNIPERSCOPE, AUG},
|
|
// {SNIPERSCOPE, G41},
|
|
// {SNIPERSCOPE, MINI14},
|
|
// {SNIPERSCOPE, C7},
|
|
// {SNIPERSCOPE, FAMAS},
|
|
// {SNIPERSCOPE, AK74},
|
|
// {SNIPERSCOPE, AKM},
|
|
// {SNIPERSCOPE, M14},
|
|
// {SNIPERSCOPE, FNFAL},
|
|
// {SNIPERSCOPE, G3A3},
|
|
// {SNIPERSCOPE, G11},
|
|
// {SNIPERSCOPE, M900},
|
|
// {SNIPERSCOPE, BARRETT},
|
|
// {SNIPERSCOPE, PSG},
|
|
// {SNIPERSCOPE, VAL_SILENT},
|
|
// {SNIPERSCOPE, TAR21},
|
|
// {SNIPERSCOPE, ENFIELD},
|
|
// {SNIPERSCOPE, G36K},
|
|
// {SNIPERSCOPE, G36C},
|
|
// {SNIPERSCOPE, MSG90A1},
|
|
// {SNIPERSCOPE, AK103},
|
|
//
|
|
// {LASERSCOPE, GLOCK_17},
|
|
// {LASERSCOPE, GLOCK_18},
|
|
// {LASERSCOPE, BERETTA_92F},
|
|
// {LASERSCOPE, BERETTA_93R},
|
|
// {LASERSCOPE, SW38},
|
|
// {LASERSCOPE, BARRACUDA},
|
|
// {LASERSCOPE, DESERTEAGLE},
|
|
// {LASERSCOPE, M1911},
|
|
// {LASERSCOPE, MP5K},
|
|
// {LASERSCOPE, MAC10},
|
|
// {LASERSCOPE, THOMPSON},
|
|
// {LASERSCOPE, COMMANDO},
|
|
// {LASERSCOPE, MP53},
|
|
// {LASERSCOPE, AKSU74},
|
|
// {LASERSCOPE, P90},
|
|
// {LASERSCOPE, TYPE85},
|
|
// {LASERSCOPE, SKS},
|
|
// {LASERSCOPE, DRAGUNOV},
|
|
// {LASERSCOPE, M24},
|
|
// {LASERSCOPE, AUG},
|
|
// {LASERSCOPE, G41},
|
|
// {LASERSCOPE, MINI14},
|
|
// {LASERSCOPE, C7},
|
|
// {LASERSCOPE, FAMAS},
|
|
// {LASERSCOPE, AK74},
|
|
// {LASERSCOPE, AKM},
|
|
// {LASERSCOPE, M14},
|
|
// {LASERSCOPE, FNFAL},
|
|
// {LASERSCOPE, G3A3},
|
|
// {LASERSCOPE, G11},
|
|
// {LASERSCOPE, M870},
|
|
// {LASERSCOPE, SPAS15},
|
|
// {LASERSCOPE, CAWS},
|
|
// {LASERSCOPE, MINIMI},
|
|
// {LASERSCOPE, RPK74},
|
|
// {LASERSCOPE, HK21E},
|
|
// {LASERSCOPE, AUTOMAG_III},
|
|
// {LASERSCOPE, MICRO_UZI},
|
|
// {LASERSCOPE, M900},
|
|
// {LASERSCOPE, M950},
|
|
// {LASERSCOPE, M960},
|
|
// {LASERSCOPE, BARRETT},
|
|
// {LASERSCOPE, PSG},
|
|
// {LASERSCOPE, VAL_SILENT},
|
|
// {LASERSCOPE, TAR21},
|
|
// {LASERSCOPE, ENFIELD},
|
|
// {LASERSCOPE, MP5},
|
|
// {LASERSCOPE, MP5N},
|
|
// {LASERSCOPE, UMP45},
|
|
// {LASERSCOPE, MP5SD},
|
|
// {LASERSCOPE, FIVE7},
|
|
// {LASERSCOPE, P7M8},
|
|
// {LASERSCOPE, G36K},
|
|
// {LASERSCOPE, G36C},
|
|
// {LASERSCOPE, MSG90A1},
|
|
// {LASERSCOPE, BENNELLI},
|
|
// {LASERSCOPE, AK103},
|
|
//
|
|
// {BIPOD, SKS},
|
|
// {BIPOD, DRAGUNOV},
|
|
// {BIPOD, M24},
|
|
// {BIPOD, AUG},
|
|
// {BIPOD, G41},
|
|
// {BIPOD, MINI14},
|
|
// {BIPOD, C7},
|
|
// {BIPOD, FAMAS},
|
|
// {BIPOD, AK74},
|
|
// {BIPOD, AKM},
|
|
// {BIPOD, M14},
|
|
// {BIPOD, FNFAL},
|
|
// {BIPOD, G3A3},
|
|
// {BIPOD, G11},
|
|
// {BIPOD, CAWS},
|
|
// {BIPOD, MINIMI},
|
|
// {BIPOD, RPK74},
|
|
// {BIPOD, HK21E},
|
|
// {BIPOD, M900},
|
|
// {BIPOD, BARRETT},
|
|
// {BIPOD, PSG},
|
|
// {BIPOD, VAL_SILENT},
|
|
// {BIPOD, TAR21},
|
|
// {BIPOD, ENFIELD},
|
|
// {BIPOD, MSG90A1},
|
|
// {BIPOD, AK103},
|
|
//
|
|
// {DUCKBILL, M870},
|
|
// {DUCKBILL, SPAS15},
|
|
// {DUCKBILL, CAWS},
|
|
// {DUCKBILL, BENNELLI},
|
|
//
|
|
// {UNDER_GLAUNCHER, COMMANDO},
|
|
// {UNDER_GLAUNCHER, AKSU74},
|
|
// {UNDER_GLAUNCHER, AUG},
|
|
// {UNDER_GLAUNCHER, G41},
|
|
// {UNDER_GLAUNCHER, MINI14},
|
|
// {UNDER_GLAUNCHER, C7},
|
|
// {UNDER_GLAUNCHER, FAMAS},
|
|
// {UNDER_GLAUNCHER, AK74},
|
|
// {UNDER_GLAUNCHER, AKM},
|
|
// {UNDER_GLAUNCHER, M14},
|
|
// {UNDER_GLAUNCHER, FNFAL},
|
|
// {UNDER_GLAUNCHER, G3A3},
|
|
// {UNDER_GLAUNCHER, TAR21},
|
|
// {UNDER_GLAUNCHER, ENFIELD},
|
|
// {UNDER_GLAUNCHER, M900},
|
|
// {UNDER_GLAUNCHER, G11},
|
|
// {UNDER_GLAUNCHER, SKS},
|
|
// {UNDER_GLAUNCHER, G36K},
|
|
// {UNDER_GLAUNCHER, G36C},
|
|
// {UNDER_GLAUNCHER, AK103},
|
|
//
|
|
// {SPRING_AND_BOLT_UPGRADE, GLOCK_17},
|
|
// {SPRING_AND_BOLT_UPGRADE, GLOCK_18},
|
|
// {SPRING_AND_BOLT_UPGRADE, BERETTA_92F},
|
|
// {SPRING_AND_BOLT_UPGRADE, BERETTA_93R},
|
|
// {SPRING_AND_BOLT_UPGRADE, SW38},
|
|
// {SPRING_AND_BOLT_UPGRADE, BARRACUDA},
|
|
// {SPRING_AND_BOLT_UPGRADE, DESERTEAGLE},
|
|
// {SPRING_AND_BOLT_UPGRADE, M1911},
|
|
// {SPRING_AND_BOLT_UPGRADE, MP5K},
|
|
// {SPRING_AND_BOLT_UPGRADE, MAC10},
|
|
// {SPRING_AND_BOLT_UPGRADE, THOMPSON},
|
|
// {SPRING_AND_BOLT_UPGRADE, COMMANDO},
|
|
// {SPRING_AND_BOLT_UPGRADE, MP53},
|
|
// {SPRING_AND_BOLT_UPGRADE, AKSU74},
|
|
// {SPRING_AND_BOLT_UPGRADE, P90},
|
|
// {SPRING_AND_BOLT_UPGRADE, TYPE85},
|
|
// {SPRING_AND_BOLT_UPGRADE, SKS},
|
|
// {SPRING_AND_BOLT_UPGRADE, DRAGUNOV},
|
|
// {SPRING_AND_BOLT_UPGRADE, M24},
|
|
// {SPRING_AND_BOLT_UPGRADE, AUG},
|
|
// {SPRING_AND_BOLT_UPGRADE, G41},
|
|
// {SPRING_AND_BOLT_UPGRADE, MINI14},
|
|
// {SPRING_AND_BOLT_UPGRADE, C7},
|
|
// {SPRING_AND_BOLT_UPGRADE, FAMAS},
|
|
// {SPRING_AND_BOLT_UPGRADE, AK74},
|
|
// {SPRING_AND_BOLT_UPGRADE, AKM},
|
|
// {SPRING_AND_BOLT_UPGRADE, M14},
|
|
// {SPRING_AND_BOLT_UPGRADE, FNFAL},
|
|
// {SPRING_AND_BOLT_UPGRADE, G3A3},
|
|
// {SPRING_AND_BOLT_UPGRADE, G11},
|
|
// {SPRING_AND_BOLT_UPGRADE, M870},
|
|
// {SPRING_AND_BOLT_UPGRADE, SPAS15},
|
|
// {SPRING_AND_BOLT_UPGRADE, CAWS},
|
|
// {SPRING_AND_BOLT_UPGRADE, MINIMI},
|
|
// {SPRING_AND_BOLT_UPGRADE, RPK74},
|
|
// {SPRING_AND_BOLT_UPGRADE, HK21E},
|
|
// {SPRING_AND_BOLT_UPGRADE, AUTOMAG_III},
|
|
// {SPRING_AND_BOLT_UPGRADE, MICRO_UZI},
|
|
// {SPRING_AND_BOLT_UPGRADE, M900},
|
|
// {SPRING_AND_BOLT_UPGRADE, M950},
|
|
// {SPRING_AND_BOLT_UPGRADE, M960},
|
|
// {SPRING_AND_BOLT_UPGRADE, BARRETT},
|
|
// {SPRING_AND_BOLT_UPGRADE, PSG},
|
|
// {SPRING_AND_BOLT_UPGRADE, VAL_SILENT},
|
|
// {SPRING_AND_BOLT_UPGRADE, TAR21},
|
|
// {SPRING_AND_BOLT_UPGRADE, ENFIELD},
|
|
// {SPRING_AND_BOLT_UPGRADE, MP5},
|
|
// {SPRING_AND_BOLT_UPGRADE, MP5N},
|
|
// {SPRING_AND_BOLT_UPGRADE, UMP45},
|
|
// {SPRING_AND_BOLT_UPGRADE, MP5SD},
|
|
// {SPRING_AND_BOLT_UPGRADE, FIVE7},
|
|
// {SPRING_AND_BOLT_UPGRADE, P7M8},
|
|
// {SPRING_AND_BOLT_UPGRADE, G36K},
|
|
// {SPRING_AND_BOLT_UPGRADE, G36C},
|
|
// {SPRING_AND_BOLT_UPGRADE, MSG90A1},
|
|
// {SPRING_AND_BOLT_UPGRADE, BENNELLI},
|
|
// {SPRING_AND_BOLT_UPGRADE, AK103},
|
|
//
|
|
// {GUN_BARREL_EXTENDER, GLOCK_17},
|
|
// {GUN_BARREL_EXTENDER, GLOCK_18},
|
|
// {GUN_BARREL_EXTENDER, BERETTA_92F},
|
|
// {GUN_BARREL_EXTENDER, BERETTA_93R},
|
|
// {GUN_BARREL_EXTENDER, SW38},
|
|
// {GUN_BARREL_EXTENDER, BARRACUDA},
|
|
// {GUN_BARREL_EXTENDER, DESERTEAGLE},
|
|
// {GUN_BARREL_EXTENDER, M1911},
|
|
// {GUN_BARREL_EXTENDER, MP5K},
|
|
// {GUN_BARREL_EXTENDER, MAC10},
|
|
// {GUN_BARREL_EXTENDER, THOMPSON},
|
|
// {GUN_BARREL_EXTENDER, COMMANDO},
|
|
// {GUN_BARREL_EXTENDER, MP53},
|
|
// {GUN_BARREL_EXTENDER, AKSU74},
|
|
// {GUN_BARREL_EXTENDER, P90},
|
|
// {GUN_BARREL_EXTENDER, TYPE85},
|
|
// {GUN_BARREL_EXTENDER, SKS},
|
|
// {GUN_BARREL_EXTENDER, DRAGUNOV},
|
|
// {GUN_BARREL_EXTENDER, M24},
|
|
// {GUN_BARREL_EXTENDER, AUG},
|
|
// {GUN_BARREL_EXTENDER, G41},
|
|
// {GUN_BARREL_EXTENDER, MINI14},
|
|
// {GUN_BARREL_EXTENDER, C7},
|
|
// {GUN_BARREL_EXTENDER, FAMAS},
|
|
// {GUN_BARREL_EXTENDER, AK74},
|
|
// {GUN_BARREL_EXTENDER, AKM},
|
|
// {GUN_BARREL_EXTENDER, M14},
|
|
// {GUN_BARREL_EXTENDER, FNFAL},
|
|
// {GUN_BARREL_EXTENDER, G3A3},
|
|
// {GUN_BARREL_EXTENDER, G11},
|
|
// {GUN_BARREL_EXTENDER, M870},
|
|
// {GUN_BARREL_EXTENDER, SPAS15},
|
|
// {GUN_BARREL_EXTENDER, CAWS},
|
|
// {GUN_BARREL_EXTENDER, MINIMI},
|
|
// {GUN_BARREL_EXTENDER, RPK74},
|
|
// {GUN_BARREL_EXTENDER, HK21E},
|
|
// {GUN_BARREL_EXTENDER, AUTOMAG_III},
|
|
// {GUN_BARREL_EXTENDER, MICRO_UZI},
|
|
// {GUN_BARREL_EXTENDER, M900},
|
|
// {GUN_BARREL_EXTENDER, M950},
|
|
// {GUN_BARREL_EXTENDER, M960},
|
|
// {GUN_BARREL_EXTENDER, BARRETT},
|
|
// {GUN_BARREL_EXTENDER, PSG},
|
|
// {GUN_BARREL_EXTENDER, VAL_SILENT},
|
|
// {GUN_BARREL_EXTENDER, TAR21},
|
|
// {GUN_BARREL_EXTENDER, ENFIELD},
|
|
// {GUN_BARREL_EXTENDER, MP5},
|
|
// {GUN_BARREL_EXTENDER, MP5N},
|
|
// {GUN_BARREL_EXTENDER, UMP45},
|
|
// {GUN_BARREL_EXTENDER, MP5SD},
|
|
// {GUN_BARREL_EXTENDER, FIVE7},
|
|
// {GUN_BARREL_EXTENDER, P7M8},
|
|
// {GUN_BARREL_EXTENDER, G36K},
|
|
// {GUN_BARREL_EXTENDER, G36C},
|
|
// {GUN_BARREL_EXTENDER, MSG90A1},
|
|
// {GUN_BARREL_EXTENDER, BENNELLI},
|
|
// {GUN_BARREL_EXTENDER, AK103},
|
|
//
|
|
// {FLASH_SUPPRESSOR, MP5K},
|
|
// {FLASH_SUPPRESSOR, MAC10},
|
|
// {FLASH_SUPPRESSOR, THOMPSON},
|
|
// {FLASH_SUPPRESSOR, COMMANDO},
|
|
// {FLASH_SUPPRESSOR, MP53},
|
|
// {FLASH_SUPPRESSOR, AKSU74},
|
|
// {FLASH_SUPPRESSOR, P90},
|
|
// {FLASH_SUPPRESSOR, TYPE85},
|
|
// {FLASH_SUPPRESSOR, SKS},
|
|
// {FLASH_SUPPRESSOR, DRAGUNOV},
|
|
// {FLASH_SUPPRESSOR, M24},
|
|
// {FLASH_SUPPRESSOR, AUG},
|
|
// {FLASH_SUPPRESSOR, G41},
|
|
// {FLASH_SUPPRESSOR, MINI14},
|
|
// {FLASH_SUPPRESSOR, C7},
|
|
// {FLASH_SUPPRESSOR, FAMAS},
|
|
// {FLASH_SUPPRESSOR, AK74},
|
|
// {FLASH_SUPPRESSOR, AKM},
|
|
// {FLASH_SUPPRESSOR, M14},
|
|
// {FLASH_SUPPRESSOR, FNFAL},
|
|
// {FLASH_SUPPRESSOR, G3A3},
|
|
// {FLASH_SUPPRESSOR, G11},
|
|
// {FLASH_SUPPRESSOR, MINIMI},
|
|
// {FLASH_SUPPRESSOR, RPK74},
|
|
// {FLASH_SUPPRESSOR, HK21E},
|
|
// {FLASH_SUPPRESSOR, MICRO_UZI},
|
|
// {FLASH_SUPPRESSOR, M900},
|
|
// {FLASH_SUPPRESSOR, M950},
|
|
// {FLASH_SUPPRESSOR, M960},
|
|
// {FLASH_SUPPRESSOR, BARRETT},
|
|
// {FLASH_SUPPRESSOR, PSG},
|
|
// {FLASH_SUPPRESSOR, VAL_SILENT},
|
|
// {FLASH_SUPPRESSOR, TAR21},
|
|
// {FLASH_SUPPRESSOR, ENFIELD},
|
|
// {FLASH_SUPPRESSOR, MP5},
|
|
// {FLASH_SUPPRESSOR, MP5N},
|
|
// {FLASH_SUPPRESSOR, UMP45},
|
|
// {FLASH_SUPPRESSOR, MP5SD},
|
|
// {FLASH_SUPPRESSOR, G36K},
|
|
// {FLASH_SUPPRESSOR, G36C},
|
|
// {FLASH_SUPPRESSOR, MSG90A1},
|
|
// {FLASH_SUPPRESSOR, AK103},
|
|
//
|
|
// {REFLEX_SCOPED, GLOCK_17},
|
|
// {REFLEX_SCOPED, GLOCK_18},
|
|
// {REFLEX_SCOPED, BERETTA_92F},
|
|
// {REFLEX_SCOPED, BERETTA_93R},
|
|
// {REFLEX_SCOPED, SW38},
|
|
// {REFLEX_SCOPED, BARRACUDA},
|
|
// {REFLEX_SCOPED, DESERTEAGLE},
|
|
// {REFLEX_SCOPED, M1911},
|
|
// {REFLEX_SCOPED, MP5K},
|
|
// {REFLEX_SCOPED, MAC10},
|
|
// {REFLEX_SCOPED, THOMPSON},
|
|
// {REFLEX_SCOPED, COMMANDO},
|
|
// {REFLEX_SCOPED, MP53},
|
|
// {REFLEX_SCOPED, AKSU74},
|
|
// {REFLEX_SCOPED, P90},
|
|
// {REFLEX_SCOPED, TYPE85},
|
|
// {REFLEX_SCOPED, SKS},
|
|
// {REFLEX_SCOPED, AUG},
|
|
// {REFLEX_SCOPED, G41},
|
|
// {REFLEX_SCOPED, MINI14},
|
|
// {REFLEX_SCOPED, C7},
|
|
// {REFLEX_SCOPED, FAMAS},
|
|
// {REFLEX_SCOPED, AK74},
|
|
// {REFLEX_SCOPED, AKM},
|
|
// {REFLEX_SCOPED, M14},
|
|
// {REFLEX_SCOPED, FNFAL},
|
|
// {REFLEX_SCOPED, G3A3},
|
|
// {REFLEX_SCOPED, G11},
|
|
// {REFLEX_SCOPED, M870},
|
|
// {REFLEX_SCOPED, SPAS15},
|
|
// {REFLEX_SCOPED, CAWS},
|
|
// {REFLEX_SCOPED, MINIMI},
|
|
// {REFLEX_SCOPED, RPK74},
|
|
// {REFLEX_SCOPED, HK21E},
|
|
// {REFLEX_SCOPED, AUTOMAG_III},
|
|
// {REFLEX_SCOPED, MICRO_UZI},
|
|
// {REFLEX_SCOPED, M900},
|
|
// {REFLEX_SCOPED, M950},
|
|
// {REFLEX_SCOPED, M960},
|
|
// {REFLEX_SCOPED, TAR21},
|
|
// {REFLEX_SCOPED, ENFIELD},
|
|
// {REFLEX_SCOPED, MP5},
|
|
// {REFLEX_SCOPED, MP5N},
|
|
// {REFLEX_SCOPED, UMP45},
|
|
// {REFLEX_SCOPED, MP5SD},
|
|
// {REFLEX_SCOPED, FIVE7},
|
|
// {REFLEX_SCOPED, P7M8},
|
|
// {REFLEX_SCOPED, G36K},
|
|
// {REFLEX_SCOPED, G36C},
|
|
// {REFLEX_SCOPED, BENNELLI},
|
|
// {REFLEX_SCOPED, AK103},
|
|
//
|
|
// {REFLEX_UNSCOPED, GLOCK_17},
|
|
// {REFLEX_UNSCOPED, GLOCK_18},
|
|
// {REFLEX_UNSCOPED, BERETTA_92F},
|
|
// {REFLEX_UNSCOPED, BERETTA_93R},
|
|
// {REFLEX_UNSCOPED, SW38},
|
|
// {REFLEX_UNSCOPED, BARRACUDA},
|
|
// {REFLEX_UNSCOPED, DESERTEAGLE},
|
|
// {REFLEX_UNSCOPED, M1911},
|
|
// {REFLEX_UNSCOPED, MP5K},
|
|
// {REFLEX_UNSCOPED, MAC10},
|
|
// {REFLEX_UNSCOPED, THOMPSON},
|
|
// {REFLEX_UNSCOPED, COMMANDO},
|
|
// {REFLEX_UNSCOPED, MP53},
|
|
// {REFLEX_UNSCOPED, AKSU74},
|
|
// {REFLEX_UNSCOPED, P90},
|
|
// {REFLEX_UNSCOPED, TYPE85},
|
|
// {REFLEX_UNSCOPED, SKS},
|
|
// {REFLEX_UNSCOPED, DRAGUNOV},
|
|
// {REFLEX_UNSCOPED, M24},
|
|
// {REFLEX_UNSCOPED, AUG},
|
|
// {REFLEX_UNSCOPED, G41},
|
|
// {REFLEX_UNSCOPED, MINI14},
|
|
// {REFLEX_UNSCOPED, C7},
|
|
// {REFLEX_UNSCOPED, FAMAS},
|
|
// {REFLEX_UNSCOPED, AK74},
|
|
// {REFLEX_UNSCOPED, AKM},
|
|
// {REFLEX_UNSCOPED, M14},
|
|
// {REFLEX_UNSCOPED, FNFAL},
|
|
// {REFLEX_UNSCOPED, G3A3},
|
|
// {REFLEX_UNSCOPED, G11},
|
|
// {REFLEX_UNSCOPED, M870},
|
|
// {REFLEX_UNSCOPED, SPAS15},
|
|
// {REFLEX_UNSCOPED, CAWS},
|
|
// {REFLEX_UNSCOPED, MINIMI},
|
|
// {REFLEX_UNSCOPED, RPK74},
|
|
// {REFLEX_UNSCOPED, HK21E},
|
|
// {REFLEX_UNSCOPED, AUTOMAG_III},
|
|
// {REFLEX_UNSCOPED, MICRO_UZI},
|
|
// {REFLEX_UNSCOPED, M900},
|
|
// {REFLEX_UNSCOPED, M950},
|
|
// {REFLEX_UNSCOPED, M960},
|
|
// {REFLEX_UNSCOPED, BARRETT},
|
|
// {REFLEX_UNSCOPED, PSG},
|
|
// {REFLEX_UNSCOPED, VAL_SILENT},
|
|
// {REFLEX_UNSCOPED, TAR21},
|
|
// {REFLEX_UNSCOPED, ENFIELD},
|
|
// {REFLEX_UNSCOPED, MP5},
|
|
// {REFLEX_UNSCOPED, MP5N},
|
|
// {REFLEX_UNSCOPED, UMP45},
|
|
// {REFLEX_UNSCOPED, MP5SD},
|
|
// {REFLEX_UNSCOPED, FIVE7},
|
|
// {REFLEX_UNSCOPED, P7M8},
|
|
// {REFLEX_UNSCOPED, G36K},
|
|
// {REFLEX_UNSCOPED, G36C},
|
|
// {REFLEX_UNSCOPED, MSG90A1},
|
|
// {REFLEX_UNSCOPED, BENNELLI},
|
|
// {REFLEX_UNSCOPED, AK103},
|
|
//
|
|
// {DETONATOR, TNT},
|
|
// {DETONATOR, HMX},
|
|
// {DETONATOR, C1},
|
|
// {DETONATOR, C4},
|
|
//
|
|
// {REMDETONATOR, TNT},
|
|
// {REMDETONATOR, HMX},
|
|
// {REMDETONATOR, C1},
|
|
// {REMDETONATOR, C4},
|
|
//
|
|
// {CERAMIC_PLATES, FLAK_JACKET},
|
|
// {CERAMIC_PLATES, FLAK_JACKET_18},
|
|
// {CERAMIC_PLATES, FLAK_JACKET_Y},
|
|
// {CERAMIC_PLATES, KEVLAR_VEST},
|
|
// {CERAMIC_PLATES, KEVLAR_VEST_18},
|
|
// {CERAMIC_PLATES, KEVLAR_VEST_Y},
|
|
// {CERAMIC_PLATES, SPECTRA_VEST},
|
|
// {CERAMIC_PLATES, SPECTRA_VEST_18},
|
|
// {CERAMIC_PLATES, SPECTRA_VEST_Y},
|
|
// {CERAMIC_PLATES, KEVLAR2_VEST},
|
|
// {CERAMIC_PLATES, KEVLAR2_VEST_18},
|
|
// {CERAMIC_PLATES, KEVLAR2_VEST_Y},
|
|
//
|
|
// {SPRING, ALUMINUM_ROD},
|
|
// {QUICK_GLUE, STEEL_ROD},
|
|
// {DUCT_TAPE, STEEL_ROD},
|
|
// {XRAY_BULB, FUMBLE_PAK},
|
|
// {CHEWING_GUM, FUMBLE_PAK},
|
|
// {BATTERIES, XRAY_DEVICE},
|
|
// {COPPER_WIRE, LAME_BOY},
|
|
// {COPPER_WIRE, GOLDWATCH},
|
|
// {0, 0}
|
|
//};
|
|
|
|
UINT16 Launchable[MAXITEMS+1][2];// =
|
|
//{
|
|
// {GL_HE_GRENADE, GLAUNCHER},
|
|
// {GL_HE_GRENADE, UNDER_GLAUNCHER},
|
|
// {GL_TEARGAS_GRENADE, GLAUNCHER},
|
|
// {GL_TEARGAS_GRENADE, UNDER_GLAUNCHER},
|
|
// {GL_STUN_GRENADE, GLAUNCHER},
|
|
// {GL_STUN_GRENADE, UNDER_GLAUNCHER},
|
|
// {GL_SMOKE_GRENADE, GLAUNCHER},
|
|
// {GL_SMOKE_GRENADE, UNDER_GLAUNCHER},
|
|
// {MORTAR_SHELL, MORTAR},
|
|
// {TANK_SHELL, TANK_CANNON},
|
|
// {RPG_HE_ROCKET, RPG7},
|
|
// {RPG_AP_ROCKET, RPG7},
|
|
// {RPG_FRAG_ROCKET, RPG7},
|
|
// {0, 0}
|
|
//};
|
|
|
|
UINT16 CompatibleFaceItems[MAXITEMS+1][2];// =
|
|
//{
|
|
// {EXTENDEDEAR, NIGHTGOGGLES},
|
|
// {EXTENDEDEAR, UVGOGGLES},
|
|
// {EXTENDEDEAR, SUNGOGGLES},
|
|
// {EXTENDEDEAR, GASMASK},
|
|
// {EXTENDEDEAR, NOTHING},
|
|
// {WALKMAN, NIGHTGOGGLES},
|
|
// {WALKMAN, UVGOGGLES},
|
|
// {WALKMAN, SUNGOGGLES},
|
|
// {WALKMAN, GASMASK},
|
|
// {WALKMAN, NOTHING},
|
|
//
|
|
// {NIGHTGOGGLES, EXTENDEDEAR},
|
|
// {NIGHTGOGGLES, WALKMAN},
|
|
// {NIGHTGOGGLES, ROBOT_REMOTE_CONTROL},
|
|
// {NIGHTGOGGLES, GASMASK},
|
|
// {NIGHTGOGGLES, NOTHING},
|
|
// {SUNGOGGLES, EXTENDEDEAR},
|
|
// {SUNGOGGLES, WALKMAN},
|
|
// {SUNGOGGLES, GASMASK},
|
|
// {SUNGOGGLES, ROBOT_REMOTE_CONTROL},
|
|
// {SUNGOGGLES, NOTHING},
|
|
// {UVGOGGLES, EXTENDEDEAR},
|
|
// {UVGOGGLES, WALKMAN},
|
|
// {UVGOGGLES, GASMASK},
|
|
// {UVGOGGLES, ROBOT_REMOTE_CONTROL},
|
|
// {UVGOGGLES, NOTHING},
|
|
// {GASMASK, EXTENDEDEAR},
|
|
// {GASMASK, WALKMAN},
|
|
// {GASMASK, NIGHTGOGGLES},
|
|
// {GASMASK, UVGOGGLES},
|
|
// {GASMASK, SUNGOGGLES},
|
|
// {GASMASK, ROBOT_REMOTE_CONTROL},
|
|
// {GASMASK, NOTHING},
|
|
//
|
|
// {ROBOT_REMOTE_CONTROL, NIGHTGOGGLES},
|
|
// {ROBOT_REMOTE_CONTROL, UVGOGGLES},
|
|
// {ROBOT_REMOTE_CONTROL, SUNGOGGLES},
|
|
// {ROBOT_REMOTE_CONTROL, GASMASK},
|
|
// {ROBOT_REMOTE_CONTROL, NOTHING},
|
|
// {0, 0},
|
|
//};
|
|
|
|
|
|
UINT16 Merge[MAXITEMS+1][6];// =
|
|
//{ // first item second item resulting item, merge type
|
|
// {FIRSTAIDKIT, FIRSTAIDKIT, FIRSTAIDKIT, COMBINE_POINTS},
|
|
// {MEDICKIT, MEDICKIT, MEDICKIT, COMBINE_POINTS},
|
|
// {CANTEEN, CANTEEN, CANTEEN, COMBINE_POINTS},// Madd Combine canteens
|
|
// {LOCKSMITHKIT, LOCKSMITHKIT, LOCKSMITHKIT, COMBINE_POINTS},
|
|
// {TOOLKIT, TOOLKIT, TOOLKIT, COMBINE_POINTS},
|
|
// {GAS_CAN, GAS_CAN, GAS_CAN, COMBINE_POINTS},
|
|
// {CAMOUFLAGEKIT, CAMOUFLAGEKIT, CAMOUFLAGEKIT, COMBINE_POINTS},
|
|
// {BEER, BEER, BEER, COMBINE_POINTS},
|
|
// {WINE, WINE, WINE, COMBINE_POINTS},
|
|
// {ALCOHOL, ALCOHOL, ALCOHOL, COMBINE_POINTS},
|
|
//
|
|
// {COMPOUND18, FLAK_JACKET, FLAK_JACKET_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, KEVLAR_VEST, KEVLAR_VEST_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, KEVLAR2_VEST, KEVLAR2_VEST_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, SPECTRA_VEST, SPECTRA_VEST_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, LEATHER_JACKET_W_KEVLAR, LEATHER_JACKET_W_KEVLAR_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, KEVLAR_LEGGINGS, KEVLAR_LEGGINGS_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, SPECTRA_LEGGINGS, SPECTRA_LEGGINGS_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, KEVLAR_HELMET, KEVLAR_HELMET_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, SPECTRA_HELMET, SPECTRA_HELMET_18, TREAT_ARMOUR},
|
|
// {COMPOUND18, FLAK_JACKET_Y, NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, KEVLAR_VEST_Y, NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, SPECTRA_VEST_Y, NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, LEATHER_JACKET_W_KEVLAR_Y,NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, KEVLAR_LEGGINGS_Y, NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, SPECTRA_LEGGINGS_Y, NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, KEVLAR_HELMET_Y, NOTHING, DESTRUCTION},
|
|
// {COMPOUND18, SPECTRA_HELMET_Y, NOTHING, DESTRUCTION},
|
|
//
|
|
// {JAR_QUEEN_CREATURE_BLOOD, FLAK_JACKET, FLAK_JACKET_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR_VEST, KEVLAR_VEST_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, SPECTRA_VEST, SPECTRA_VEST_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, LEATHER_JACKET_W_KEVLAR, LEATHER_JACKET_W_KEVLAR_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR2_VEST, KEVLAR2_VEST_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR_LEGGINGS, KEVLAR_LEGGINGS_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, SPECTRA_LEGGINGS, SPECTRA_LEGGINGS_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR_HELMET, KEVLAR_HELMET_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, SPECTRA_HELMET, SPECTRA_HELMET_Y, TREAT_ARMOUR},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, FLAK_JACKET_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR_VEST_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR2_VEST_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, SPECTRA_VEST_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, LEATHER_JACKET_W_KEVLAR_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR_LEGGINGS_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, SPECTRA_LEGGINGS_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, KEVLAR_HELMET_18, NOTHING, DESTRUCTION},
|
|
// {JAR_QUEEN_CREATURE_BLOOD, SPECTRA_HELMET_18, NOTHING, DESTRUCTION},
|
|
//
|
|
// {RDX, TNT, HMX, EXPLOSIVE},
|
|
// {RDX, C1, C4, EXPLOSIVE},
|
|
// {TNT, RDX, HMX, EXPLOSIVE},
|
|
// {C1, RDX, C4, EXPLOSIVE},
|
|
//
|
|
// {STRING, TIN_CAN, STRING_TIED_TO_TIN_CAN, EASY_MERGE},
|
|
// {TIN_CAN, STRING, STRING_TIED_TO_TIN_CAN, EASY_MERGE},
|
|
//
|
|
// {FLASH_DEVICE, DISPLAY_UNIT, XRAY_DEVICE, ELECTRONIC_MERGE},
|
|
// {DISPLAY_UNIT, FLASH_DEVICE, XRAY_DEVICE, ELECTRONIC_MERGE},
|
|
//
|
|
// {0, 0, 0, 0}
|
|
//};
|
|
|
|
|
|
ComboMergeInfoStruct AttachmentComboMerge[MAXITEMS+1];// =
|
|
//{
|
|
// // base item attach 1 attach 2 result
|
|
// {ALUMINUM_ROD, {SPRING, NOTHING}, SPRING_AND_BOLT_UPGRADE },
|
|
// {STEEL_ROD, {QUICK_GLUE, DUCT_TAPE}, GUN_BARREL_EXTENDER },
|
|
// {FUMBLE_PAK, {XRAY_BULB, CHEWING_GUM}, FLASH_DEVICE },
|
|
// {LAME_BOY, {COPPER_WIRE, NOTHING}, DISPLAY_UNIT },
|
|
// {GOLDWATCH, {COPPER_WIRE, NOTHING}, DETONATOR},
|
|
// {NOTHING, {NOTHING, NOTHING}, NOTHING },
|
|
//};
|
|
|
|
|
|
UINT16 IncompatibleAttachments[MAXATTACHMENTS][2];// =
|
|
//{
|
|
// {BIPOD,UNDER_GLAUNCHER},
|
|
// {UNDER_GLAUNCHER,BIPOD},
|
|
// {DETONATOR,REMDETONATOR},
|
|
// {REMDETONATOR,DETONATOR},
|
|
// {SNIPERSCOPE,REFLEX_SCOPED},
|
|
// {REFLEX_SCOPED,SNIPERSCOPE},
|
|
// {REFLEX_SCOPED,REFLEX_UNSCOPED},
|
|
// {REFLEX_UNSCOPED,REFLEX_SCOPED},
|
|
// {SILENCER,FLASH_SUPPRESSOR},
|
|
// {FLASH_SUPPRESSOR,SILENCER},
|
|
// {LASERSCOPE,REFLEX_UNSCOPED},
|
|
// {REFLEX_UNSCOPED,LASERSCOPE},
|
|
//};
|
|
|
|
UINT16 ReplacementGuns[][2] =
|
|
{
|
|
{ BARRACUDA, DESERTEAGLE },
|
|
{ M1911, GLOCK_17 },
|
|
{ GLOCK_18, BERETTA_93R },
|
|
{ BERETTA_92F, GLOCK_17 },
|
|
{ TYPE85, BERETTA_93R },
|
|
{ THOMPSON, MP5K },
|
|
{ MP53, MP5K },
|
|
{ SPAS15, M870 },
|
|
{ AKSU74, MAC10 },
|
|
{ SKS, MINI14 },
|
|
{ AKM, G41 },
|
|
{ G3A3, G41 },
|
|
{ AK74, G41 },
|
|
{ DRAGUNOV, M24 },
|
|
{ FAMAS, M14 },
|
|
{ AUG, C7 },
|
|
{ RPK74, MINIMI },
|
|
{ HK21E, MINIMI },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
UINT16 ReplacementAmmo[][2] =
|
|
{
|
|
{ CLIP545_30_AP, CLIP556_30_AP },
|
|
{ CLIP545_30_HP, CLIP556_30_HP },
|
|
{ CLIP762W_10_AP, CLIP762N_5_AP },
|
|
{ CLIP762W_30_AP, CLIP762N_20_AP },
|
|
{ CLIP762W_10_HP, CLIP762N_5_HP },
|
|
{ CLIP762W_30_HP, CLIP762N_20_HP },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
// CHRISL: Structure Definitions for new inventory system items.
|
|
std::vector<LBETYPE> LoadBearingEquipment;
|
|
//LBETYPE LoadBearingEquipment[MAXITEMS+1];
|
|
//LBETYPE LoadBearingEquipment[] =
|
|
//{
|
|
// // Index Class Pocket Types---------------------------------
|
|
// { 0, /*Blank Entry*/ 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
|
|
// { 1, /*Default Thigh Pack*/ 0, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
|
|
// { 2, /*Default Vest Pack*/ 1, {1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0} },
|
|
// { 3, /*Default Combat Pack*/ 2, {1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0} },
|
|
// { 4, /*Default Back Pack*/ 3, {1, 1, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0} },
|
|
// { 5, /*6P Backpack*/ 3, {1, 1, 1, 1, 0, 0, 0, 0, 3, 3, 0, 0} },
|
|
// { 6, /*6P Combat Pack*/ 2, {1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0} }
|
|
//};
|
|
|
|
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)
|
|
|
|
//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} },
|
|
// { /* Small General Pocket */ 1, 0, 0, {4, 3, 2, 1, 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} },
|
|
// { /* Med General Pocket */ 2, 0, 0, {7, 6, 5, 4, 3, 2, 1, 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} },
|
|
// { /* Lg General Pocket */ 3, 0, 0, {10,9, 8, 7, 6, 5, 4, 3, 2, 1, 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} },
|
|
// { /* Gun Sling */ 4, 0, 1, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 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} },
|
|
// { /* Knife Pocket */ 5, 0, 1, {0, 0, 1, 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} }
|
|
//};
|
|
|
|
BOOLEAN ItemIsLegal( UINT16 usItemIndex )
|
|
{
|
|
//if the user has selected the reduced gun list
|
|
if ( Item[usItemIndex].ubCoolness == 0 )
|
|
return FALSE;
|
|
|
|
if( !gGameOptions.fGunNut )
|
|
{
|
|
//if the item is a gun, or ammo
|
|
//if( (Item[ usItemIndex ].usItemClass == IC_GUN) || (Item[ usItemIndex ].usItemClass == IC_AMMO )) //Madd: restriction removed
|
|
{
|
|
// and the item is only available with the extended guns
|
|
if( Item[usItemIndex].biggunlist )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( gGameOptions.ubGameStyle != STYLE_SCIFI && Item[usItemIndex].scifi )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// CHRISL: Restrict system specific items
|
|
if( (UsingNewInventorySystem() == true) )
|
|
{
|
|
if(Item[usItemIndex].ItemSize == 99)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if(Item[usItemIndex].usItemClass == IC_LBEGEAR || Item[usItemIndex].newinv)
|
|
return FALSE;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// also used for ammo
|
|
BOOLEAN ExtendedGunListGun( UINT16 usGun )
|
|
{
|
|
// return( (Item[ usGun ].fFlags & ITEM_BIGGUNLIST) != 0 );
|
|
return( (Item[ usGun ].biggunlist ) != 0 );
|
|
}
|
|
|
|
UINT16 StandardGunListReplacement( UINT16 usGun )
|
|
{
|
|
UINT8 ubLoop;
|
|
|
|
if ( ExtendedGunListGun( usGun ) )
|
|
{
|
|
ubLoop = 0;
|
|
while ( ReplacementGuns[ ubLoop ][ 0 ] != 0 )
|
|
{
|
|
if ( ReplacementGuns[ ubLoop ][ 0 ] == usGun )
|
|
{
|
|
return( ReplacementGuns[ ubLoop ][ 1 ] );
|
|
}
|
|
ubLoop++;
|
|
}
|
|
// ERROR!
|
|
AssertMsg( 0, String( "Extended gun with no replacement %d, CC:0", usGun ) );
|
|
return( NOTHING );
|
|
}
|
|
else
|
|
{
|
|
return( NOTHING );
|
|
}
|
|
}
|
|
|
|
UINT16 StandardGunListAmmoReplacement( UINT16 usAmmo )
|
|
{
|
|
UINT8 ubLoop;
|
|
|
|
if ( ExtendedGunListGun( usAmmo ) )
|
|
{
|
|
ubLoop = 0;
|
|
while ( ReplacementAmmo[ ubLoop ][ 0 ] != 0 )
|
|
{
|
|
if ( ReplacementAmmo[ ubLoop ][ 0 ] == usAmmo )
|
|
{
|
|
return( ReplacementAmmo[ ubLoop ][ 1 ] );
|
|
}
|
|
ubLoop++;
|
|
}
|
|
// ERROR!
|
|
AssertMsg( 0, String( "Extended gun with no replacement %d, CC:0", usAmmo ) );
|
|
return( NOTHING );
|
|
}
|
|
else
|
|
{
|
|
return( NOTHING );
|
|
}
|
|
}
|
|
|
|
BOOLEAN WeaponInHand( SOLDIERTYPE * pSoldier )
|
|
{
|
|
if ( Item[pSoldier->inv[HANDPOS].usItem].usItemClass & (IC_WEAPON | IC_THROWN) && pSoldier->inv[HANDPOS].exists() == true)
|
|
{
|
|
if (Item[pSoldier->inv[HANDPOS].usItem].fingerprintid )
|
|
{
|
|
if (pSoldier->inv[HANDPOS][0]->data.ubImprintID != NO_PROFILE)
|
|
{
|
|
if (pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile != MADLAB )
|
|
{
|
|
if (pSoldier->inv[HANDPOS][0]->data.ubImprintID != pSoldier->ubProfile)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pSoldier->inv[HANDPOS][0]->data.ubImprintID != (NO_PROFILE + 1) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (pSoldier->inv[HANDPOS][0]->data.gun.bGunStatus >= USABLE)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
// return -1 or some "broken" value if weapon is broken?
|
|
return( FALSE );
|
|
}
|
|
|
|
bool FitsInSmallPocket(OBJECTTYPE* pObj)
|
|
{
|
|
if (UsingNewInventorySystem() == true) {
|
|
return true;
|
|
}
|
|
return Item[pObj->usItem].ubPerPocket != 0;
|
|
}
|
|
|
|
// CHRISL: New definition for this function so that we can look at soldiers LBE pockets.
|
|
UINT8 ItemSlotLimit( OBJECTTYPE * pObject, INT16 bSlot, SOLDIERTYPE *pSoldier, BOOLEAN cntAttach )
|
|
{
|
|
UINT8 ubSlotLimit;
|
|
UINT8 pIndex;
|
|
UINT16 usItem, iSize;
|
|
UINT16 sSize = 0;
|
|
|
|
//doesn't matter what inventory method we are using
|
|
usItem = pObject->usItem;
|
|
if (usItem == MONEY) {
|
|
//need to have money "stackable" in all slots to trick it into merging
|
|
return 2;
|
|
}
|
|
|
|
//doesn't matter what inventory method we are using, "body" slots always have a capacity of 1
|
|
if(bSlot < BODYPOSFINAL)
|
|
return 1;
|
|
|
|
ubSlotLimit = Item[usItem].ubPerPocket;
|
|
if ( ubSlotLimit > MAX_OBJECTS_PER_SLOT ) {
|
|
ubSlotLimit = MAX_OBJECTS_PER_SLOT;
|
|
}
|
|
if (bSlot == STACK_SIZE_LIMIT) {
|
|
//if it is stack size limit we want it to be a big slot or a vehicle slot
|
|
if (UsingNewInventorySystem() == false)
|
|
return (max(1, ubSlotLimit));
|
|
else
|
|
return (max(1, LBEPocketType[VEHICLE_POCKET_TYPE].ItemCapacityPerSize[__min(34,Item[pObject->usItem].ItemSize)]));
|
|
}
|
|
|
|
if (UsingNewInventorySystem() == false) {
|
|
if (ubSlotLimit == 0 && bSlot < BIGPOCKFINAL) {
|
|
return 1;
|
|
}
|
|
if (bSlot >= BIGPOCKFINAL && ubSlotLimit > 1)
|
|
{
|
|
ubSlotLimit /= 2;
|
|
}
|
|
return( ubSlotLimit );
|
|
}
|
|
|
|
|
|
//UsingNewInventorySystem == true
|
|
if (pSoldier != NULL && (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE)) {
|
|
pIndex = VEHICLE_POCKET_TYPE;
|
|
}
|
|
// IC Group Slots
|
|
else if (bSlot == GUNSLINGPOCKPOS) {
|
|
pIndex = GUNSLING_POCKET_TYPE;
|
|
}
|
|
else if (bSlot == KNIFEPOCKPOS) {
|
|
pIndex = KNIFE_POCKET_TYPE;
|
|
}
|
|
else {
|
|
Assert(icLBE[bSlot] != -1 && icDefault[bSlot] != -1 && icPocket[bSlot] != -1);
|
|
//find the class of the LBE, then find what size the pocket of the slot in the LBE is
|
|
if (pSoldier == NULL || pSoldier->inv[icLBE[bSlot]].exists() == false) {
|
|
pIndex = LoadBearingEquipment[Item[icDefault[bSlot]].ubClassIndex].lbePocketIndex[icPocket[bSlot]];
|
|
}
|
|
else {
|
|
pIndex = LoadBearingEquipment[Item[pSoldier->inv[icLBE[bSlot]].usItem].ubClassIndex].lbePocketIndex[icPocket[bSlot]];
|
|
}
|
|
}
|
|
|
|
//We need to actually check the size of the largest stored item as well as the size of the current item
|
|
if(cntAttach == TRUE)
|
|
{
|
|
iSize = CalculateItemSize(pObject);
|
|
if(pSoldier != NULL && pSoldier->inv[bSlot].usItem == pObject->usItem)
|
|
{
|
|
sSize = CalculateItemSize(&pSoldier->inv[bSlot]);
|
|
if(LBEPocketType[pIndex].ItemCapacityPerSize[sSize] < LBEPocketType[pIndex].ItemCapacityPerSize[iSize])
|
|
iSize = sSize;
|
|
}
|
|
}
|
|
else
|
|
iSize = Item[pObject->usItem].ItemSize;
|
|
iSize = __min(iSize,34);
|
|
ubSlotLimit = LBEPocketType[pIndex].ItemCapacityPerSize[iSize];
|
|
|
|
//this could be changed, we know guns are physically able to stack
|
|
//if ( iSize < 10 && ubSlotLimit > 1)
|
|
// ubSlotLimit = 1;
|
|
|
|
if(LBEPocketType[pIndex].pRestriction != 0 && !(LBEPocketType[pIndex].pRestriction & Item[usItem].usItemClass)) {
|
|
return 0;
|
|
}
|
|
|
|
return( ubSlotLimit );
|
|
}
|
|
|
|
UINT32 MoneySlotLimit( INT8 bSlot )
|
|
{
|
|
if ( bSlot >= BIGPOCKFINAL ) /* CHRISL */
|
|
{
|
|
return( MAX_MONEY_PER_SLOT / 2 );
|
|
}
|
|
else
|
|
{
|
|
return( MAX_MONEY_PER_SLOT );
|
|
}
|
|
}
|
|
|
|
INT8 FindBestWeaponIfCurrentIsOutOfRange(SOLDIERTYPE * pSoldier, INT8 bCurrentWeaponIndex, UINT16 bWantedRange)
|
|
{
|
|
//assuming current weapon is in the handpos
|
|
if (GunRange(&pSoldier->inv[bCurrentWeaponIndex]) >= bWantedRange)
|
|
{
|
|
//our current weapon is good enough
|
|
return( bCurrentWeaponIndex );
|
|
}
|
|
|
|
UINT16 range;
|
|
UINT16 bestRange = 0;
|
|
INT8 bestWeaponThatMeetsRange = 0;
|
|
INT8 secondBestWeapon = 0;
|
|
//search for weapons that meet the range, then sort by damage.
|
|
//if there are no weapons that meet the range, then use the longest range we can find
|
|
for (INT8 bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
//if this is a weapon
|
|
if (Item[pSoldier->inv[bLoop].usItem].usItemClass & (IC_WEAPON | IC_THROWN) && pSoldier->inv[bLoop].exists() == true)
|
|
{
|
|
range = GunRange(&pSoldier->inv[bLoop]);
|
|
if (range >= bWantedRange)
|
|
{
|
|
if (bestWeaponThatMeetsRange == 0)
|
|
{
|
|
bestWeaponThatMeetsRange = bLoop;
|
|
}
|
|
else if (GetDamage(&pSoldier->inv[bLoop]) > GetDamage(&pSoldier->inv[bestWeaponThatMeetsRange]))
|
|
{
|
|
//does this weapon have more damage?
|
|
bestWeaponThatMeetsRange = bLoop;
|
|
}
|
|
}
|
|
else if (range > bestRange)
|
|
{
|
|
//weapon does not meet range, but it could be better anyways
|
|
bestRange = range;
|
|
secondBestWeapon = bLoop;
|
|
}
|
|
else if (range == bestRange)
|
|
{
|
|
//weapon ties with secondBestWeapon's range
|
|
if (secondBestWeapon == 0)
|
|
{
|
|
//this if can happen if range of bLoop is 0!
|
|
secondBestWeapon = bLoop;
|
|
}
|
|
else if (GetDamage(&pSoldier->inv[bLoop]) > GetDamage(&pSoldier->inv[secondBestWeapon]))
|
|
{
|
|
secondBestWeapon = bLoop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bestWeaponThatMeetsRange)
|
|
{
|
|
return bestWeaponThatMeetsRange;
|
|
}
|
|
else if (secondBestWeapon)
|
|
{
|
|
return secondBestWeapon;
|
|
}
|
|
return( bCurrentWeaponIndex );
|
|
}
|
|
|
|
INT8 FindMetalDetector( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (Item[pSoldier->inv[bLoop].usItem].metaldetector && pSoldier->inv[bLoop].exists() == true)
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindLockBomb( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (Item[pSoldier->inv[bLoop].usItem].lockbomb && pSoldier->inv[bLoop].exists() == true)
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindUsableObj( SOLDIERTYPE * pSoldier, UINT16 usItem )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].usItem == usItem
|
|
&& pSoldier->inv[bLoop].exists() == true
|
|
&& pSoldier->inv[bLoop][0]->data.objectStatus >= USABLE )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
|
|
INT8 FindObjExcludingSlot( SOLDIERTYPE * pSoldier, UINT16 usItem, INT8 bExcludeSlot )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (bLoop == bExcludeSlot)
|
|
{
|
|
continue;
|
|
}
|
|
if (pSoldier->inv[bLoop].usItem == usItem && pSoldier->inv[bLoop].exists() == true)
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindObj( SOLDIERTYPE * pSoldier, UINT16 usItem, INT8 bLower, INT8 bUpper )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = bLower; bLoop < bUpper; bLoop++)
|
|
{
|
|
//CHRISL: If we check exists() then we can't search for an empty pocket with this function, which is done.
|
|
if (pSoldier->inv[bLoop].usItem == usItem/* && pSoldier->inv[bLoop].exists() == true*/)
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( ITEM_NOT_FOUND );
|
|
}
|
|
|
|
INT8 FindObjInObjRange( SOLDIERTYPE * pSoldier, UINT16 usItem1, UINT16 usItem2 )
|
|
{
|
|
INT8 bLoop;
|
|
UINT16 usTemp;
|
|
|
|
if (usItem1 > usItem2 )
|
|
{
|
|
// swap the two...
|
|
usTemp = usItem2;
|
|
usItem2 = usItem1;
|
|
usItem1 = usTemp;
|
|
}
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
usTemp = pSoldier->inv[bLoop].usItem;
|
|
if ( usTemp >= usItem1 && usTemp <= usItem2 && pSoldier->inv[bLoop].exists() == true)
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
|
|
return( ITEM_NOT_FOUND );
|
|
}
|
|
|
|
|
|
INT8 FindObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (Item[pSoldier->inv[bLoop].usItem].usItemClass & usItemClass && pSoldier->inv[bLoop].exists() == true)
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindAIUsableObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass )
|
|
{
|
|
// finds the first object of the specified class which does NOT have
|
|
// the "unusable by AI" flag set.
|
|
|
|
// uses & rather than == so that this function can search for any weapon
|
|
INT8 bLoop;
|
|
|
|
// This is for the AI only so:
|
|
|
|
// Do not consider tank cannons or rocket launchers to be "guns"
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( (Item[pSoldier->inv[bLoop].usItem].usItemClass & usItemClass) && !(pSoldier->inv[bLoop].fFlags & OBJECT_AI_UNUSABLE) && (pSoldier->inv[bLoop][0]->data.objectStatus >= USABLE ) )
|
|
{
|
|
if ( usItemClass == IC_GUN && EXPLOSIVE_GUN( pSoldier->inv[bLoop].usItem ) )
|
|
{
|
|
continue;
|
|
}
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindAIUsableObjClassWithin( SOLDIERTYPE * pSoldier, UINT32 usItemClass, INT8 bLower, INT8 bUpper )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
// This is for the AI only so:
|
|
// Do not consider tank cannons or rocket launchers to be "guns"
|
|
|
|
for (bLoop = bLower; bLoop < bUpper; bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( (Item[pSoldier->inv[bLoop].usItem].usItemClass & usItemClass) && !(pSoldier->inv[bLoop].fFlags & OBJECT_AI_UNUSABLE) && (pSoldier->inv[bLoop][0]->data.objectStatus >= USABLE ) )
|
|
{
|
|
if ( usItemClass == IC_GUN && EXPLOSIVE_GUN( pSoldier->inv[bLoop].usItem ) )
|
|
{
|
|
continue;
|
|
}
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindEmptySlotWithin( SOLDIERTYPE * pSoldier, INT8 bLower, INT8 bUpper )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = bLower; bLoop < bUpper; bLoop++)
|
|
{
|
|
// CHRISL: Only look at valid pockets
|
|
if((UsingNewInventorySystem() == false) && !oldInv[bLoop])
|
|
continue;
|
|
if((pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) && !vehicleInv[bLoop])
|
|
continue;
|
|
if (pSoldier->inv[bLoop].exists() == false)
|
|
{
|
|
if (bLoop == SECONDHANDPOS && Item[pSoldier->inv[HANDPOS].usItem].twohanded )
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( ITEM_NOT_FOUND );
|
|
}
|
|
|
|
BOOLEAN GLGrenadeInSlot(SOLDIERTYPE *pSoldier, INT8 bSlot )
|
|
{
|
|
if (pSoldier->inv[bSlot].exists() == true) {
|
|
if (Item[pSoldier->inv[bSlot].usItem].glgrenade)
|
|
return TRUE;
|
|
}
|
|
//switch (pSoldier->inv[bSlot].usItem)
|
|
//{
|
|
// case GL_HE_GRENADE:
|
|
// case GL_TEARGAS_GRENADE:
|
|
// case GL_STUN_GRENADE:
|
|
// case GL_SMOKE_GRENADE:
|
|
// return(TRUE);
|
|
// default:
|
|
// return(FALSE);
|
|
//}
|
|
return FALSE;
|
|
}
|
|
|
|
// for grenade launchers
|
|
INT8 FindGLGrenade( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (GLGrenadeInSlot( pSoldier, bLoop ))
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindThrowableGrenade( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
BOOLEAN fCheckForFlares = FALSE;
|
|
|
|
// JA2Gold: give some priority to looking for flares when at night
|
|
// this is AI only so we can put in some customization for night
|
|
if (GetTimeOfDayAmbientLightLevel() == NORMAL_LIGHTLEVEL_NIGHT)
|
|
{
|
|
if (pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 2))
|
|
{
|
|
fCheckForFlares = TRUE;
|
|
}
|
|
}
|
|
if (fCheckForFlares)
|
|
{
|
|
// Do a priority check for flares first
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( Item[pSoldier->inv[ bLoop ].usItem].flare )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( (Item[ pSoldier->inv[ bLoop ].usItem ].usItemClass & IC_GRENADE) && // Try this check instead, to avoid tossing RPG rounds !GLGrenadeInSlot( pSoldier, bLoop ) &&
|
|
GetLauncherFromLaunchable( pSoldier->inv[ bLoop ].usItem) == NOTHING )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
OBJECTTYPE* FindAttachment( OBJECTTYPE * pObj, UINT16 usItem, UINT8 subObject )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
|
if (iter->usItem == usItem)
|
|
{
|
|
return &(*iter);
|
|
}
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
OBJECTTYPE* FindAttachmentByClass( OBJECTTYPE * pObj, UINT32 uiItemClass, UINT8 subObject )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].usItemClass == uiItemClass)
|
|
{
|
|
return &(*iter);
|
|
}
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
INT8 FindLaunchable( SOLDIERTYPE * pSoldier, UINT16 usWeapon )
|
|
{
|
|
INT8 bLoop;
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("FindLaunchable: weapon=%d",usWeapon));
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( ValidLaunchable( pSoldier->inv[ bLoop ].usItem , usWeapon ) )
|
|
{
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("FindLaunchable: returning slot %d",bLoop));
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("FindLaunchable: item not found"));
|
|
return( ITEM_NOT_FOUND );
|
|
}
|
|
|
|
INT8 FindNonSmokeLaunchable( SOLDIERTYPE * pSoldier, UINT16 usWeapon )
|
|
{
|
|
INT8 bLoop;
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("FindNonSmokeLaunchable: weapon=%d",usWeapon));
|
|
for (bLoop = 0; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( ValidLaunchable( pSoldier->inv[ bLoop ].usItem , usWeapon ) && Explosive[Item[pSoldier->inv[ bLoop ].usItem].ubClassIndex].ubType != EXPLOSV_SMOKE )
|
|
{
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("FindNonSmokeLaunchable: returning slot %d",bLoop));
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("FindNonSmokeLaunchable: item not found, so find items including smoke"));
|
|
return( FindLaunchable(pSoldier,usWeapon) );
|
|
}
|
|
|
|
OBJECTTYPE* FindLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (ValidLaunchable( iter->usItem, usWeapon))
|
|
{
|
|
return &(*iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
OBJECTTYPE* FindNonSmokeLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon )
|
|
{
|
|
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (ValidLaunchable( iter->usItem, usWeapon) && Explosive[Item[iter->usItem].ubClassIndex].ubType != EXPLOSV_SMOKE)
|
|
{
|
|
return &(*iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FindLaunchableAttachment(pObj,usWeapon) );
|
|
}
|
|
|
|
|
|
//Simple check to see if the item has any attachments
|
|
BOOLEAN ItemHasAttachments( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier, UINT8 iter )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if(pSoldier != NULL){
|
|
for (iter = 0; iter != pObj->objectStack.size(); ++iter) {
|
|
if((*pObj)[iter]->attachments.empty() == false){
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
if((*pObj)[iter]->attachments.empty() == false){
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Determine if it is possible to add this attachment to the CLASS of this item
|
|
// (i.e. to any item in the class)
|
|
BOOLEAN ValidAttachmentClass( UINT16 usAttachment, UINT16 usItem )
|
|
{
|
|
INT32 iLoop = 0;
|
|
while( 1 )
|
|
{
|
|
// see comment for AttachmentInfo array for why we skip IC_NONE
|
|
if ( AttachmentInfo[ iLoop ].uiItemClass != IC_NONE )
|
|
{
|
|
if ( AttachmentInfo[ iLoop ].usItem == usAttachment )
|
|
{
|
|
if ( AttachmentInfo[ iLoop ].uiItemClass == Item[ usItem ].usItemClass )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
iLoop++;
|
|
if (AttachmentInfo[iLoop].usItem == 0)
|
|
{
|
|
// end of the array
|
|
break;
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
INT8 GetAttachmentInfoIndex( UINT16 usItem )
|
|
{
|
|
INT32 iLoop = 0;
|
|
|
|
while( 1 )
|
|
{
|
|
if ( AttachmentInfo[ iLoop ].usItem == usItem )
|
|
{
|
|
return( (INT8) iLoop );
|
|
}
|
|
iLoop++;
|
|
if (AttachmentInfo[iLoop].usItem == 0)
|
|
{
|
|
// end of the array
|
|
break;
|
|
}
|
|
}
|
|
return( -1 );
|
|
}
|
|
|
|
//Determine if it is possible to add this attachment to the item.
|
|
BOOLEAN ValidAttachment( UINT16 usAttachment, UINT16 usItem, UINT8 * pubAPCost )
|
|
{
|
|
INT32 iLoop = 0;
|
|
if (pubAPCost) {
|
|
*pubAPCost = (UINT8)APBPConstants[AP_RELOAD_GUN]; //default value
|
|
}
|
|
|
|
// look for the section of the array pertaining to this attachment...
|
|
while( 1 )
|
|
{
|
|
if (Attachment[iLoop][0] == usAttachment)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Attachment[iLoop][0] == 0)
|
|
{
|
|
// the proposed item cannot be attached to anything!
|
|
return( FALSE );
|
|
}
|
|
}
|
|
// now look through this section for the item in question
|
|
while( 1 )
|
|
{
|
|
if (Attachment[iLoop][1] == usItem)
|
|
{
|
|
if (pubAPCost) {
|
|
*pubAPCost = (UINT8)Attachment[iLoop][2]; //Madd: get ap cost of attaching items :)
|
|
}
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Attachment[iLoop][0] != usAttachment)
|
|
{
|
|
// the proposed item cannot be attached to the item in question
|
|
return( FALSE );
|
|
}
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
UINT8 AttachmentAPCost( UINT16 usAttachment, UINT16 usItem )
|
|
{
|
|
UINT8 ubAPCost;
|
|
|
|
ValidAttachment( usAttachment, usItem, &ubAPCost);
|
|
|
|
return ubAPCost;
|
|
}
|
|
|
|
//Determine if this item can receive this attachment. This is different, in that it may
|
|
//be possible to have this attachment on this item, but may already have an attachment on
|
|
//it which doesn't work simultaneously with the new attachment (like a silencer and duckbill).
|
|
BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage, UINT8 subObject )
|
|
{
|
|
BOOLEAN fSameItem = FALSE, fSimilarItems = FALSE;
|
|
UINT16 usSimilarItem = NOTHING;
|
|
|
|
if (pObj->exists() == false) {
|
|
return FALSE;
|
|
}
|
|
if ( !ValidAttachment( usAttachment, pObj->usItem ) )
|
|
{
|
|
// check for an underslung grenade launcher attached to the gun
|
|
if ( (IsGrenadeLauncherAttached ( pObj ) ) && ValidLaunchable( usAttachment, GetAttachedGrenadeLauncher( pObj ) ) )
|
|
{
|
|
return ( TRUE );
|
|
/*
|
|
if ( fAttemptingAttachment )
|
|
{
|
|
// if there is no other grenade attached already, then we can attach it
|
|
if (FindAttachmentByClass( pObj, IC_GRENADE) != ITEM_NOT_FOUND)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
// keep going, it can be attached to the grenade launcher
|
|
}
|
|
else
|
|
{
|
|
// logically, can be added
|
|
return( TRUE );
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
if ( fAttemptingAttachment && ValidAttachmentClass( usAttachment, pObj->usItem ) )
|
|
{
|
|
// well, maybe the player thought he could
|
|
CHAR16 zTemp[ 100 ];
|
|
|
|
swprintf( zTemp, Message[ STR_CANT_ATTACH ], ItemNames[ usAttachment ], ItemNames[ pObj->usItem ] );
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, zTemp );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
// special conditions go here
|
|
// can't have two of the same attachment on an item
|
|
/*
|
|
if (FindAttachment( pObj, usAttachment ) != 0)
|
|
{
|
|
fSameItem = TRUE;
|
|
}
|
|
*/
|
|
|
|
for(int i = 0;i<sizeof(IncompatibleAttachments);i++)
|
|
{
|
|
if ( IncompatibleAttachments[i][0] == NONE )
|
|
break;
|
|
|
|
if ( IncompatibleAttachments[i][0] == usAttachment && FindAttachment (pObj,IncompatibleAttachments[i][1],subObject) != 0 )
|
|
{
|
|
fSimilarItems = TRUE;
|
|
usSimilarItem = IncompatibleAttachments[i][1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//// special code for items which won't attach if X is present
|
|
//switch( usAttachment )
|
|
//{
|
|
// case BIPOD:
|
|
// if ( FindAttachment( pObj, UNDER_GLAUNCHER) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = UNDER_GLAUNCHER;
|
|
// }
|
|
// break;
|
|
// case UNDER_GLAUNCHER:
|
|
// if ( FindAttachment( pObj, BIPOD ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = BIPOD;
|
|
// }
|
|
// break;
|
|
///*
|
|
// case LASERSCOPE:
|
|
// if (FindAttachment( pObj, SNIPERSCOPE ) != 0)
|
|
// {
|
|
// return( FALSE );
|
|
// }
|
|
// break;
|
|
// case SNIPERSCOPE:
|
|
// if (FindAttachment( pObj, LASERSCOPE ) != 0)
|
|
// {
|
|
// return( FALSE );
|
|
// }
|
|
// break;
|
|
// */
|
|
// case DETONATOR:
|
|
// if( FindAttachment( pObj, REMDETONATOR ) != 0 )
|
|
// {
|
|
// fSameItem = TRUE;
|
|
// }
|
|
// break;
|
|
// case REMDETONATOR:
|
|
// if( FindAttachment( pObj, DETONATOR ) != 0 )
|
|
// {
|
|
// fSameItem = TRUE;
|
|
// }
|
|
// break;
|
|
// case SNIPERSCOPE:
|
|
// if( FindAttachment( pObj, REFLEX_SCOPED ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = REFLEX_SCOPED;
|
|
// }
|
|
// break;
|
|
// case REFLEX_SCOPED:
|
|
// if( FindAttachment( pObj, SNIPERSCOPE ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = SNIPERSCOPE;
|
|
// }
|
|
// if( FindAttachment( pObj, REFLEX_UNSCOPED ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = REFLEX_UNSCOPED;
|
|
// }
|
|
// break;
|
|
// case REFLEX_UNSCOPED:
|
|
// if( FindAttachment( pObj, REFLEX_SCOPED ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = REFLEX_SCOPED;
|
|
// }
|
|
// break;
|
|
// case SILENCER:
|
|
// if( FindAttachment( pObj, FLASH_SUPPRESSOR ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = FLASH_SUPPRESSOR;
|
|
// }
|
|
// break;
|
|
// case FLASH_SUPPRESSOR:
|
|
// if( FindAttachment( pObj, SILENCER ) != 0 )
|
|
// {
|
|
// fSimilarItems = TRUE;
|
|
// usSimilarItem = SILENCER;
|
|
// }
|
|
// break;
|
|
//}
|
|
|
|
if (fAttemptingAttachment)
|
|
{
|
|
if (fSameItem)
|
|
{
|
|
if (fDisplayMessage) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, Message[ STR_ATTACHMENT_ALREADY ] );
|
|
return( FALSE );
|
|
}
|
|
else if (fSimilarItems)
|
|
{
|
|
if (fDisplayMessage) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, Message[ STR_CANT_USE_TWO_ITEMS ], ItemNames[ usSimilarItem ], ItemNames[ usAttachment ] );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//Determines if it is possible to equip this weapon with this ammo.
|
|
BOOLEAN ValidAmmoType( UINT16 usItem, UINT16 usAmmoType )
|
|
{
|
|
if (Item[usItem].usItemClass == IC_GUN && Item[usAmmoType].usItemClass == IC_AMMO)
|
|
{
|
|
if (Weapon[usItem].ubCalibre == Magazine[Item[usAmmoType].ubClassIndex].ubCalibre)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CompatibleFaceItem( UINT16 usItem1, UINT16 usItem2 )
|
|
{
|
|
INT32 iLoop = 0;
|
|
|
|
//Madd: skip this function if either item is nothing
|
|
//this will let us trim some lines from compatiblefaceitems.xml
|
|
if ( usItem1 == NONE || usItem2 == NONE )
|
|
return TRUE;
|
|
|
|
// look for the section of the array pertaining to this attachment...
|
|
while( 1 )
|
|
{
|
|
if (CompatibleFaceItems[iLoop][0] == usItem1)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (CompatibleFaceItems[iLoop][0] == 0)
|
|
{
|
|
// the proposed item cannot fit with anything!
|
|
return( FALSE );
|
|
}
|
|
}
|
|
// now look through this section for the item in question
|
|
while( 1 )
|
|
{
|
|
if (CompatibleFaceItems[iLoop][1] == usItem2)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (CompatibleFaceItems[iLoop][0] != usItem1)
|
|
{
|
|
// the proposed item cannot be attached to the item in question
|
|
return( FALSE );
|
|
}
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//Determines if this item is a two handed item.
|
|
BOOLEAN TwoHandedItem( UINT16 usItem )
|
|
{
|
|
// if (Item[usItem].fFlags & ITEM_TWO_HANDED)
|
|
if (Item[usItem].twohanded )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN ValidLaunchable( UINT16 usLaunchable, UINT16 usItem )
|
|
{
|
|
INT32 iLoop = 0;
|
|
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("ValidLaunchable: launchable=%d, item=%d",usLaunchable,usItem));
|
|
// look for the section of the array pertaining to this launchable item...
|
|
while( 1 )
|
|
{
|
|
if (Launchable[iLoop][0] == usLaunchable)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Launchable[iLoop][0] == 0)
|
|
{
|
|
// the proposed item cannot be attached to anything!
|
|
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("ValidLaunchable: launchable=%d, item=%d, return FALSE, launchable not found",usLaunchable,usItem));
|
|
return( FALSE );
|
|
}
|
|
}
|
|
// now look through this section for the item in question
|
|
while( 1 )
|
|
{
|
|
if (Launchable[iLoop][1] == usItem)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Launchable[iLoop][0] != usLaunchable)
|
|
{
|
|
// the proposed item cannot be attached to the item in question
|
|
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("ValidLaunchable: launchable=%d, item=%d, return FALSE, item not found",usLaunchable,usItem));
|
|
return( FALSE );
|
|
}
|
|
}
|
|
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("ValidLaunchable: launchable=%d, item=%d, return TRUE",usLaunchable,usItem));
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN ValidItemLaunchable( OBJECTTYPE * pObj, UINT16 usAttachment )
|
|
{
|
|
if (pObj->exists() == false) {
|
|
return FALSE;
|
|
}
|
|
if ( !ValidLaunchable( usAttachment, pObj->usItem ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
// if we can find another of the same class as the attachment, it's not possible
|
|
if ( FindAttachmentByClass( pObj, Item[ usAttachment ].usItemClass ) != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
UINT16 GetLauncherFromLaunchable( UINT16 usLaunchable )
|
|
{
|
|
INT32 iLoop = 0;
|
|
// look for the section of the array pertaining to this launchable item...
|
|
while( 1 )
|
|
{
|
|
if (Launchable[iLoop][0] == usLaunchable)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Launchable[iLoop][0] == 0)
|
|
{
|
|
// the proposed item cannot be attached to anything!
|
|
return( NOTHING );
|
|
}
|
|
}
|
|
|
|
return( Launchable[iLoop][1] );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN EvaluateValidMerge( UINT16 usMerge, UINT16 usItem, UINT16 * pusResult, UINT16 * pusResult2, UINT8 * pubType, UINT8 * pubAPCost )
|
|
{
|
|
// NB "usMerge" is the object being merged with (e.g. compound 18)
|
|
// "usItem" is the item being merged "onto" (e.g. kevlar vest)
|
|
INT32 iLoop = 0;
|
|
|
|
//CHRISL: Update this so we can also merge IC_MONEY like wallets and nuggets.
|
|
if (usMerge == usItem && (Item[ usItem ].usItemClass == IC_AMMO || Item[ usItem ].usItemClass == IC_MONEY))
|
|
{
|
|
*pusResult = usItem;
|
|
*pubType = COMBINE_POINTS;
|
|
return( TRUE );
|
|
}
|
|
// look for the section of the array pertaining to this Merge...
|
|
while( 1 )
|
|
{
|
|
if (Merge[iLoop][0] == usMerge)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Merge[iLoop][0] == 0)
|
|
{
|
|
// the proposed item cannot be merged with anything!
|
|
return( FALSE );
|
|
}
|
|
}
|
|
// now look through this section for the item in question
|
|
while( 1 )
|
|
{
|
|
if (Merge[iLoop][1] == usItem)
|
|
{
|
|
break;
|
|
}
|
|
iLoop++;
|
|
if (Merge[iLoop][0] != usMerge)
|
|
{
|
|
// the proposed item cannot be merged with the item in question
|
|
return( FALSE );
|
|
}
|
|
}
|
|
*pusResult = Merge[iLoop][2];
|
|
*pusResult2 = Merge[iLoop][3];
|
|
*pubType = (UINT8) Merge[iLoop][4];
|
|
*pubAPCost = (UINT8) Merge[iLoop][5];
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN ValidMerge( UINT16 usMerge, UINT16 usItem )
|
|
{
|
|
UINT16 usIgnoreResult, usIgnoreResult2;
|
|
UINT8 ubIgnoreType, ubIgnoreAPCost;
|
|
return( EvaluateValidMerge( usMerge, usItem, &usIgnoreResult, &usIgnoreResult2, &ubIgnoreType, &ubIgnoreAPCost ) );
|
|
}
|
|
|
|
int GetPocketSizeByDimensions(int sizeX, int sizeY)
|
|
{
|
|
static const UINT8 cisPocketSize[6][4] =
|
|
{
|
|
11, 12, 13, 14,
|
|
15, 16, 17, 18,
|
|
19, 20, 21, 22,
|
|
23, 24, 25, 26,
|
|
27, 28, 29, 30,
|
|
31, 32, 33, 34
|
|
};
|
|
return cisPocketSize[sizeX][sizeY];
|
|
}
|
|
|
|
void GetPocketDimensionsBySize(int pocketSize, int& sizeX, int& sizeY)
|
|
{
|
|
static const UINT8 cisPocketSize[6][4] =
|
|
{
|
|
11, 12, 13, 14,
|
|
15, 16, 17, 18,
|
|
19, 20, 21, 22,
|
|
23, 24, 25, 26,
|
|
27, 28, 29, 30,
|
|
31, 32, 33, 34
|
|
};
|
|
|
|
for(sizeX=0; sizeX<6; sizeX++)
|
|
{
|
|
for(sizeY=0; sizeY<4; sizeY++)
|
|
{
|
|
if(pocketSize == cisPocketSize[sizeX][sizeY])
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// CHRISL: New function to dynamically modify ItemSize based on attachments, stack size, etc
|
|
UINT16 CalculateItemSize( OBJECTTYPE *pObject )
|
|
{
|
|
UINT16 iSize;
|
|
UINT16 currentSize = 0;
|
|
UINT32 cisIndex;
|
|
|
|
// Determine default ItemSize based on item and attachments
|
|
cisIndex = pObject->usItem;
|
|
iSize = Item[cisIndex].ItemSize;
|
|
if(iSize>34)
|
|
iSize = 34;
|
|
|
|
//for each object in the stack, hopefully there is only 1
|
|
for (int numStacked = 0; numStacked < pObject->ubNumberOfObjects; ++numStacked) {
|
|
//some weapon attachments can adjust the ItemSize of a weapon
|
|
if(iSize<10) {
|
|
for (attachmentList::iterator iter = (*pObject)[numStacked]->attachments.begin(); iter != (*pObject)[numStacked]->attachments.end(); ++iter) {
|
|
if (iter->exists() == true) {
|
|
iSize += Item[iter->usItem].itemsizebonus;
|
|
// CHRISL: This is to catch things if we try and reduce ItemSize when we're already at 0
|
|
if(iSize > 34 || iSize < 0)
|
|
iSize = 0;
|
|
if(iSize > 9)
|
|
iSize = 9;
|
|
}
|
|
}
|
|
}
|
|
|
|
// LBENODE has it's ItemSize adjusted based on what it's storing
|
|
if(pObject->IsActiveLBE(numStacked) == true) {
|
|
LBENODE* pLBE = pObject->GetLBEPointer(numStacked);
|
|
if(pLBE)
|
|
{
|
|
//start by determining the equivalent number of "small" pockets that this LBENODE has access to. This
|
|
// is based on the pType value in Pockets.xml with 1=Small, 2=Medium and 3=Large
|
|
UINT16 totalPocketValue = 0;
|
|
FLOAT percentOfItemUsed = 0;
|
|
UINT16 pIndex, testSize, maxSize;
|
|
UINT8 pocketCapacity, numberOfSizeIncrements;
|
|
FLOAT currentPocketPercent, currentPocketPartOfTotal;
|
|
for(unsigned int x = 0; x < pLBE->inv.size(); x++)
|
|
{
|
|
if(LoadBearingEquipment[Item[pObject->usItem].ubClassIndex].lbePocketIndex[x] != 0)
|
|
{
|
|
pIndex = LoadBearingEquipment[Item[pObject->usItem].ubClassIndex].lbePocketIndex[x];
|
|
totalPocketValue += LBEPocketType[pIndex].pType;
|
|
}
|
|
}
|
|
//Now, look through each active pocket
|
|
for(unsigned int x = 0; x < pLBE->inv.size(); x++)
|
|
{
|
|
if(pLBE->inv[x].exists() == true)
|
|
{
|
|
pIndex = LoadBearingEquipment[Item[pObject->usItem].ubClassIndex].lbePocketIndex[x];
|
|
testSize = CalculateItemSize(&pLBE->inv[x]);
|
|
pocketCapacity = LBEPocketType[pIndex].ItemCapacityPerSize[testSize];
|
|
currentPocketPercent = (FLOAT)pLBE->inv[x].ubNumberOfObjects / (FLOAT)pocketCapacity;
|
|
currentPocketPartOfTotal = (FLOAT)LBEPocketType[pIndex].pType / (FLOAT)totalPocketValue;
|
|
percentOfItemUsed += currentPocketPartOfTotal * currentPocketPercent;
|
|
}
|
|
}
|
|
maxSize = max(iSize, LoadBearingEquipment[Item[pObject->usItem].ubClassIndex].lbeFilledSize);
|
|
//Now, determine the increments between initial ItemSize and Filled Size, and adjust iSize by percentOfItemUsed
|
|
if(percentOfItemUsed != 0)
|
|
{
|
|
numberOfSizeIncrements = LoadBearingEquipment[Item[pObject->usItem].ubClassIndex].lbeFilledSize - Item[pObject->usItem].ItemSize;
|
|
testSize = (UINT16)((numberOfSizeIncrements * percentOfItemUsed) + .5);
|
|
currentSize = __max(iSize + testSize, currentSize);
|
|
currentSize = __min(currentSize, maxSize);
|
|
}
|
|
#if 0
|
|
//old method
|
|
UINT16 newSize, testSize, maxSize;
|
|
UINT8 cnt=0;
|
|
newSize = 0;
|
|
maxSize = max(iSize, LoadBearingEquipment[Item[pObject->usItem].ubClassIndex].lbeFilledSize);
|
|
// Look for the ItemSize of the largest item in this LBENODE
|
|
for(unsigned int x = 0; x < pLBE->inv.size(); ++x)
|
|
{
|
|
if(pLBE->inv[x].exists() == true)
|
|
{
|
|
testSize = CalculateItemSize(&(pLBE->inv[x]));
|
|
//Now that we have the size of one item, we want to factor in the number of items since two
|
|
// items take up more space then one.
|
|
testSize = testSize + pLBE->inv[x].ubNumberOfObjects - 1;
|
|
testSize = min(testSize,34);
|
|
//We also need to increase the size of guns so they'll fit with the rest of our calculations.
|
|
if(testSize < 5)
|
|
testSize += 10;
|
|
if(testSize < 10)
|
|
testSize += 18;
|
|
//Finally, we want to factor in multiple pockets. We'll do this by counting the number of filled
|
|
// pockets, then add this count total to our newSize when everything is finished.
|
|
cnt++;
|
|
newSize = max(testSize, newSize);
|
|
}
|
|
}
|
|
//Add the total number of filled pockets to our NewSize to account for multiple pockets being used
|
|
newSize += cnt;
|
|
newSize = min(newSize,34);
|
|
// If largest item is smaller then LBE, don't change ItemSize
|
|
if(newSize > 0 && newSize < iSize) {
|
|
iSize = iSize;
|
|
}
|
|
// if largest item is larget then LBE but smaller then max size, partially increase ItemSize
|
|
else if(newSize >= iSize && newSize < maxSize) {
|
|
iSize = newSize;
|
|
}
|
|
// if largest item is larger then max size, reset ItemSize to max size
|
|
else if(newSize >= maxSize) {
|
|
iSize = maxSize;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
//Finally, set the new iSize value
|
|
iSize = __max(iSize, currentSize);
|
|
|
|
return(iSize);
|
|
}
|
|
|
|
UINT16 CalculateAmmoWeight( UINT16 usGunAmmoItem, UINT16 ubShotsLeft )
|
|
{
|
|
if( 0 == usGunAmmoItem ) /* Sergeant_Kolja: 2007-06-11, Fix for Creature Spit. This has no Ammo, so the old code calculated accidentally -1.6 resulting in 0xFFFF */
|
|
{
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "'no ammo weight' FIX for Creatures\r\n" );
|
|
return 0;
|
|
}
|
|
|
|
//Temporary calculation for minWeight. 0.2*ubWeight rounded correctly
|
|
UINT32 uiMinWeight = (UINT32)((Item[usGunAmmoItem].ubWeight / 5.0) + 0.5);
|
|
if( uiMinWeight < 1 || uiMinWeight > Item[usGunAmmoItem].ubWeight)
|
|
{
|
|
uiMinWeight = 1;
|
|
}
|
|
|
|
double weight = 0.0;
|
|
|
|
if(ubShotsLeft > 0)
|
|
{
|
|
if( uiMinWeight == Item[usGunAmmoItem].ubWeight )
|
|
{
|
|
weight += (double)uiMinWeight;
|
|
}
|
|
else
|
|
{
|
|
weight += (double)uiMinWeight + (( (double)ubShotsLeft / (double)Magazine[ Item[usGunAmmoItem].ubClassIndex ].ubMagSize) * ( (double)Item[usGunAmmoItem].ubWeight - (double)uiMinWeight ));
|
|
}
|
|
}
|
|
weight += 0.5; //Pulmu:To round correctly
|
|
return (UINT16)weight;
|
|
//Pulmu end
|
|
}
|
|
|
|
/*CHRISL: Change to a 16bit integer for a max weight of 6553.5kg. Also changed to account for
|
|
new inventory system. */
|
|
UINT16 CalculateObjectWeight( OBJECTTYPE *pObject )
|
|
{
|
|
if (pObject->exists() == false || pObject->ubNumberOfObjects == 0) {
|
|
return 0;
|
|
}
|
|
|
|
UINT16 weight = 0;
|
|
INVTYPE * pItem;
|
|
pItem = &(Item[ pObject->usItem ]);
|
|
//ADB it is much easier and faster to calculate ammo in a lump rather than accumulate a stack's weight
|
|
if ( pItem->usItemClass == IC_AMMO)//Pulmu: added weight allowance for ammo not being full
|
|
{
|
|
if ( gGameExternalOptions.fAmmoDynamicWeight == TRUE ) {
|
|
for( int cnt = 0; cnt < pObject->ubNumberOfObjects; cnt++ )
|
|
{
|
|
weight += CalculateAmmoWeight(pObject->usItem, (*pObject)[cnt]->data.ubShotsLeft);
|
|
}
|
|
}
|
|
else {
|
|
// Start with base weight
|
|
weight = pItem->ubWeight;
|
|
//multiply by the number of objects, can be 0
|
|
weight *= pObject->ubNumberOfObjects;
|
|
}
|
|
}
|
|
else {
|
|
for (int x = 0; x < pObject->ubNumberOfObjects; ++x) {
|
|
weight += pObject->GetWeightOfObjectInStack(x);
|
|
}
|
|
}
|
|
|
|
return( weight );
|
|
}
|
|
|
|
UINT16 OBJECTTYPE::GetWeightOfObjectInStack(unsigned int index)
|
|
{
|
|
//Item does not exist
|
|
if( index >= ubNumberOfObjects )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
INVTYPE * pItem = &(Item[ usItem ]);
|
|
|
|
// Start with base weight
|
|
UINT16 weight = pItem->ubWeight;
|
|
if ( pItem->usItemClass != IC_AMMO )
|
|
{
|
|
// Are we looking at an LBENODE item? New inventory only.
|
|
if(pItem->usItemClass == IC_LBEGEAR && IsActiveLBE(index) && (UsingNewInventorySystem() == true))
|
|
{
|
|
LBENODE* pLBE = GetLBEPointer(index);
|
|
if (pLBE) {
|
|
for ( unsigned int subObjects = 0; subObjects < pLBE->inv.size(); subObjects++)
|
|
{
|
|
if (pLBE->inv[subObjects].exists() == true)
|
|
{
|
|
weight += CalculateObjectWeight(&(pLBE->inv[subObjects]));
|
|
}
|
|
}
|
|
}
|
|
//do not search for attachments to an LBE
|
|
return weight;
|
|
}
|
|
|
|
// account for any attachments
|
|
for (attachmentList::iterator iter = (*this)[index]->attachments.begin(); iter != (*this)[index]->attachments.end(); ++iter) {
|
|
weight += CalculateObjectWeight(&(*iter));
|
|
}
|
|
|
|
// add in weight of ammo
|
|
if (Item[ usItem ].usItemClass == IC_GUN && (*this)[index]->data.gun.ubGunShotsLeft > 0)
|
|
{
|
|
if( gGameExternalOptions.fAmmoDynamicWeight == TRUE )
|
|
{
|
|
weight += CalculateAmmoWeight((*this)[index]->data.gun.usGunAmmoItem, (*this)[index]->data.gun.ubGunShotsLeft);
|
|
}
|
|
else
|
|
{
|
|
weight += Item[ (*this)[index]->data.gun.usGunAmmoItem ].ubWeight;
|
|
}
|
|
}
|
|
}
|
|
else if ( pItem->usItemClass == IC_AMMO && gGameExternalOptions.fAmmoDynamicWeight == TRUE )//Pulmu: added weight allowance for ammo not being full
|
|
{
|
|
weight = CalculateAmmoWeight(usItem, (*this)[index]->data.ubShotsLeft);
|
|
}
|
|
return weight;
|
|
}
|
|
|
|
UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier )
|
|
{
|
|
UINT32 uiTotalWeight = 0;
|
|
UINT32 uiPercent;
|
|
UINT8 ubLoop;
|
|
UINT8 ubStrengthForCarrying;
|
|
|
|
//Pulmu: Changes for dynamic ammo weight
|
|
for( ubLoop = 0; ubLoop < pSoldier->inv.size(); ubLoop++)
|
|
{
|
|
//ADB the weight of the object is already counting stacked objects, attachments, et al
|
|
uiTotalWeight += CalculateObjectWeight(&pSoldier->inv[ubLoop]);
|
|
}
|
|
// for now, assume soldiers can carry 1/2 their strength in KGs without penalty.
|
|
// instead of multiplying by 100 for percent, and then dividing by 10 to account
|
|
// for weight units being in 10ths of kilos, not kilos... we just start with 10 instead of 100!
|
|
ubStrengthForCarrying = EffectiveStrength( pSoldier );
|
|
if ( ubStrengthForCarrying > 80 )
|
|
{
|
|
ubStrengthForCarrying += (ubStrengthForCarrying - 80);
|
|
}
|
|
uiPercent = (10 * uiTotalWeight) / ( ubStrengthForCarrying / 2 );
|
|
return( uiPercent );
|
|
|
|
}
|
|
|
|
void DeleteObj(OBJECTTYPE * pObj )
|
|
{
|
|
pObj->initialize();
|
|
}
|
|
|
|
void SwapObjs( OBJECTTYPE * pObj1, OBJECTTYPE * pObj2 )
|
|
{
|
|
//cannot use gTempObject
|
|
OBJECTTYPE Temp (*pObj1 );
|
|
*pObj1 = *pObj2;
|
|
*pObj2 = Temp;
|
|
}
|
|
|
|
//ADB these 2 functions were created because the code calls SwapObjs all over the place
|
|
//but never handles the effects of that swap!
|
|
void SwapObjs(SOLDIERTYPE* pSoldier, int leftSlot, int rightSlot, BOOLEAN fPermanent)
|
|
{
|
|
SwapObjs(&pSoldier->inv[ leftSlot ], &pSoldier->inv[ rightSlot ]);
|
|
|
|
if (fPermanent)
|
|
{
|
|
//old usItem for the left slot is now stored in the right slot, and vice versa
|
|
HandleTacticalEffectsOfEquipmentChange(pSoldier, leftSlot, pSoldier->inv[ rightSlot ].usItem, pSoldier->inv[ leftSlot ].usItem);
|
|
HandleTacticalEffectsOfEquipmentChange(pSoldier, rightSlot, pSoldier->inv[ leftSlot ].usItem, pSoldier->inv[ rightSlot ].usItem);
|
|
}
|
|
}
|
|
|
|
void SwapObjs(SOLDIERTYPE* pSoldier, int slot, OBJECTTYPE* pObject, BOOLEAN fPermanent)
|
|
{
|
|
SwapObjs(&pSoldier->inv[ slot ], pObject);
|
|
|
|
if (fPermanent)
|
|
{
|
|
HandleTacticalEffectsOfEquipmentChange(pSoldier, slot, pObject->usItem, pSoldier->inv[ slot ].usItem);
|
|
}
|
|
}
|
|
|
|
void DamageObj( OBJECTTYPE * pObj, INT8 bAmount, UINT8 subObject )
|
|
{
|
|
//usually called from AttachObject, where the attachment is known to be a single item,
|
|
//and the attachment is only being attached to the top of the stack
|
|
if (bAmount >= (*pObj)[subObject]->data.objectStatus)
|
|
{
|
|
(*pObj)[subObject]->data.objectStatus = 1;
|
|
}
|
|
else
|
|
{
|
|
(*pObj)[subObject]->data.objectStatus -= bAmount;
|
|
}
|
|
}
|
|
|
|
void DistributeStatus(OBJECTTYPE* pSourceObject, OBJECTTYPE* pTargetObject, INT16 bMaxPoints)
|
|
{
|
|
INT16 bPointsToMove;
|
|
for ( int bLoop = pSourceObject->ubNumberOfObjects - 1; bLoop >= 0; bLoop-- )
|
|
{
|
|
StackedObjectData* pSource = (*pSourceObject)[ bLoop ];
|
|
if ( pSource->data.objectStatus > 0 )
|
|
{
|
|
// take the points here and distribute over the lower #d items
|
|
int bLoop2;
|
|
if (pSourceObject == pTargetObject) {
|
|
//we are averaging out the same object
|
|
bLoop2 = bLoop - 1;
|
|
}
|
|
else {
|
|
//we are moving from the cursor object to this one
|
|
bLoop2 = pTargetObject->ubNumberOfObjects - 1;
|
|
}
|
|
|
|
//for (; bLoop2 >= 0; bLoop2-- )
|
|
for(int i = 0; i<=bLoop2; i++)
|
|
{
|
|
StackedObjectData* pDest = (*pTargetObject)[ i ];
|
|
if ( pDest->data.objectStatus < bMaxPoints )
|
|
{
|
|
bPointsToMove = bMaxPoints - pDest->data.objectStatus;
|
|
bPointsToMove = __min( bPointsToMove, pSource->data.objectStatus );
|
|
|
|
pDest->data.objectStatus += bPointsToMove;
|
|
pSource->data.objectStatus -= bPointsToMove;
|
|
|
|
if ( pSource->data.objectStatus == 0 )
|
|
{
|
|
StackedObjects::iterator iter = pSourceObject->objectStack.begin();
|
|
for (int x = 0; x < bLoop; ++x) {
|
|
++iter;
|
|
}
|
|
pSourceObject->objectStack.erase(iter);
|
|
pSourceObject->ubNumberOfObjects--;
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pSourceObject->ubWeight = CalculateObjectWeight(pSourceObject);
|
|
// done!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN PlaceObjectAtObjectIndex( OBJECTTYPE * pSourceObj, OBJECTTYPE * pTargetObj, UINT8 ubIndex, UINT32 ubCap )
|
|
{
|
|
if (pSourceObj->usItem != pTargetObj->usItem)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
if (ubIndex < pTargetObj->ubNumberOfObjects)
|
|
{
|
|
// swap
|
|
//std::swap??
|
|
StackedObjectData data = *((*pSourceObj)[0]);
|
|
|
|
*((*pSourceObj)[0]) = *((*pTargetObj)[ubIndex]);
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pSourceObj->ubWeight = CalculateObjectWeight(pSourceObj);
|
|
|
|
*((*pTargetObj)[ubIndex]) = data;
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pTargetObj->ubWeight = CalculateObjectWeight(pTargetObj);
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
// add to end
|
|
pTargetObj->AddObjectsToStack( *pSourceObj, 1, NULL, NUM_INV_SLOTS, ubCap );
|
|
if (pSourceObj->exists() == true) {
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define RELOAD_NONE 0
|
|
#define RELOAD_PLACE 1
|
|
#define RELOAD_SWAP 2
|
|
#define RELOAD_TOPOFF 3
|
|
#define RELOAD_AUTOPLACE_OLD 4
|
|
|
|
BOOLEAN ReloadGun( SOLDIERTYPE * pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo, UINT32 subObject )
|
|
{
|
|
UINT16 ubBulletsToMove;
|
|
INT16 bAPs;
|
|
UINT16 usReloadSound;
|
|
BOOLEAN fSameAmmoType;
|
|
BOOLEAN fSameMagazineSize;
|
|
BOOLEAN fReloadingWithStack;
|
|
BOOLEAN fEmptyGun;
|
|
BOOLEAN fEnoughAPs;
|
|
INT8 bReloadType;
|
|
UINT16 usNewAmmoItem;
|
|
UINT16 usLargestMag;
|
|
UINT32 ammoObject = subObject;
|
|
|
|
bAPs = 0;
|
|
|
|
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
//CHRISL: Alter this so we treat clip fed weapons differently from weapons that load with loose rounds
|
|
bAPs = GetAPsToReloadGunWithAmmo( pSoldier, pGun, pAmmo );
|
|
if ( !EnoughPoints( pSoldier, bAPs, 0,TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
if ( Item[ pGun->usItem ].usItemClass == IC_LAUNCHER || Item[pGun->usItem].cannon )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("ReloadGun: Loading launcher - new ammo type = %d, weight = %d", pAmmo->usItem, CalculateObjectWeight(pAmmo) ) );
|
|
(*pGun)[subObject]->data.gun.usGunAmmoItem = pAmmo->usItem;
|
|
if ( pGun->AttachObject( pSoldier, pAmmo ) == FALSE )
|
|
{
|
|
(*pGun)[subObject]->data.gun.usGunAmmoItem = NONE;
|
|
// abort
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fEmptyGun = ((*pGun)[subObject]->data.gun.ubGunShotsLeft == 0);
|
|
fReloadingWithStack = (pAmmo->ubNumberOfObjects > 1);
|
|
fSameAmmoType = ( (*pGun)[subObject]->data.gun.ubGunAmmoType == Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType );
|
|
fSameMagazineSize = ( Magazine[ Item[ pAmmo->usItem ].ubClassIndex ].ubMagSize == GetMagSize( pGun));
|
|
fEnoughAPs = EnoughPoints( pSoldier, GetAPsToReloadGunWithAmmo( pSoldier, pGun, pAmmo, FALSE ), 0,FALSE );
|
|
|
|
if (fEmptyGun)
|
|
{
|
|
bReloadType = RELOAD_PLACE;
|
|
}
|
|
else
|
|
{
|
|
// record old ammo
|
|
CreateAmmo((*pGun)[subObject]->data.gun.usGunAmmoItem, &gTempObject, (*pGun)[subObject]->data.gun.ubGunShotsLeft);
|
|
|
|
if (fSameMagazineSize)
|
|
{
|
|
if (fSameAmmoType)
|
|
{
|
|
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && Weapon[pGun->usItem].swapClips )
|
|
{
|
|
bReloadType = RELOAD_SWAP;
|
|
}
|
|
else
|
|
{
|
|
bReloadType = RELOAD_TOPOFF;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fReloadingWithStack)
|
|
{
|
|
bReloadType = RELOAD_SWAP;
|
|
}
|
|
else
|
|
{
|
|
bReloadType = RELOAD_AUTOPLACE_OLD;
|
|
}
|
|
}
|
|
}
|
|
else // diff sized magazines
|
|
{
|
|
if (fSameAmmoType)
|
|
{
|
|
bReloadType = RELOAD_TOPOFF;
|
|
}
|
|
else
|
|
{
|
|
bReloadType = RELOAD_AUTOPLACE_OLD;
|
|
}
|
|
}
|
|
}
|
|
|
|
//CHRISL: We need to verify that the passed subObject actually exists. We could get passed an empty subObject if we
|
|
// reload a stack of weapons from the stack popup. If this is the case, reset subObject to the last item in the
|
|
// stack
|
|
if(subObject >= pGun->ubNumberOfObjects)
|
|
subObject = ammoObject = pGun->ubNumberOfObjects-1;
|
|
|
|
//CHRISL: If reloading with a stack, we probably want the item with the most ammo still in it
|
|
if (fReloadingWithStack)
|
|
{
|
|
usLargestMag = (*pAmmo)[ammoObject]->data.ubShotsLeft;
|
|
for(int i = 0; i<pAmmo->ubNumberOfObjects; i++)
|
|
{
|
|
if((*pAmmo)[i]->data.ubShotsLeft == Magazine[Item[pAmmo->usItem].ubClassIndex].ubMagSize)
|
|
{
|
|
ammoObject = i;
|
|
break;
|
|
}
|
|
else if((*pAmmo)[i]->data.ubShotsLeft > usLargestMag)
|
|
{
|
|
ammoObject = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fSameMagazineSize)
|
|
{
|
|
// record new ammo item for gun
|
|
usNewAmmoItem = pAmmo->usItem;
|
|
|
|
if (bReloadType == RELOAD_TOPOFF)
|
|
{
|
|
ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) - (*pGun)[subObject]->data.gun.ubGunShotsLeft );
|
|
}
|
|
else
|
|
{
|
|
ubBulletsToMove = (*pAmmo)[ammoObject]->data.ubShotsLeft;
|
|
}
|
|
|
|
}
|
|
else if (Magazine[Item[pAmmo->usItem].ubClassIndex].ubMagSize > GetMagSize(pGun))
|
|
{
|
|
//MADD MARKER
|
|
//usNewAmmoItem = pAmmo->usItem - 1;
|
|
usNewAmmoItem = FindReplacementMagazine(Weapon[pGun->usItem].ubCalibre ,GetMagSize(pGun),Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType);
|
|
if (bReloadType == RELOAD_TOPOFF)
|
|
{
|
|
ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) - (*pGun)[subObject]->data.gun.ubGunShotsLeft );
|
|
}
|
|
else
|
|
{
|
|
ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) );
|
|
}
|
|
}
|
|
else // mag is smaller than weapon mag
|
|
{
|
|
//MADD MARKER
|
|
//usNewAmmoItem = pAmmo->usItem + 1;
|
|
usNewAmmoItem = FindReplacementMagazine(Weapon[pGun->usItem].ubCalibre ,GetMagSize(pGun),Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType);
|
|
if (bReloadType == RELOAD_TOPOFF)
|
|
{
|
|
ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) - (*pGun)[subObject]->data.gun.ubGunShotsLeft );
|
|
}
|
|
else
|
|
{
|
|
ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun));
|
|
}
|
|
}
|
|
|
|
//CHRIS: This should reset the number of bullest moved to what we can actually afford when loading loose rounds
|
|
if(Weapon[pGun->usItem].swapClips == 0 && (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT))
|
|
{
|
|
if(fEnoughAPs)
|
|
{
|
|
bAPs = GetAPsToReloadGunWithAmmo( pSoldier, pGun, pAmmo, FALSE );
|
|
}
|
|
else
|
|
{
|
|
//how many can we reload? remember, bAPs assumes 1 round at this stage
|
|
bAPs = GetAPsToReloadGunWithAmmo( pSoldier, pGun, pAmmo, 2 );
|
|
for(int i = 0; i<ubBulletsToMove; i++)
|
|
{
|
|
if(EnoughPoints(pSoldier, (bAPs+(i*APBPConstants[AP_RELOAD_LOOSE])), 0, FALSE) == FALSE)
|
|
{
|
|
ubBulletsToMove = i+1;
|
|
break;
|
|
}
|
|
}
|
|
bAPs = GetAPsToReloadGunWithAmmo( pSoldier, pGun, pAmmo );
|
|
}
|
|
}
|
|
|
|
switch( bReloadType )
|
|
{
|
|
|
|
case RELOAD_PLACE:
|
|
(*pGun)[subObject]->data.gun.ubGunShotsLeft = ubBulletsToMove;
|
|
(*pGun)[subObject]->data.gun.ubGunAmmoType = Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType;
|
|
(*pGun)[subObject]->data.gun.usGunAmmoItem = usNewAmmoItem;
|
|
break;
|
|
|
|
case RELOAD_SWAP:
|
|
(*pGun)[subObject]->data.gun.ubGunShotsLeft = ubBulletsToMove;
|
|
(*pGun)[subObject]->data.gun.ubGunAmmoType = Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType;
|
|
(*pGun)[subObject]->data.gun.usGunAmmoItem = usNewAmmoItem;
|
|
if (fReloadingWithStack)
|
|
{
|
|
// add to end of stack
|
|
pAmmo->AddObjectsToStack( gTempObject, 1 );
|
|
}
|
|
else
|
|
{
|
|
// Copying the old ammo to the cursor in turnbased could screw up for the player
|
|
// (suppose his inventory is full!)
|
|
|
|
//ADB copying the old ammo to the cursor at any time will screw it up if the cursor ammo is a stack!
|
|
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && !EnoughPoints( pSoldier, (INT8) (bAPs + APBPConstants[AP_PICKUP_ITEM]), 0, FALSE )
|
|
|| pAmmo->ubNumberOfObjects > 1)
|
|
{
|
|
// try autoplace
|
|
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
|
|
{
|
|
// put it on the ground
|
|
AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0 , -1 );
|
|
}
|
|
// delete the object now in the cursor
|
|
pAmmo->RemoveObjectsFromStack(1);
|
|
}
|
|
else
|
|
{
|
|
// copy the old ammo to the cursor
|
|
*pAmmo = gTempObject;
|
|
}
|
|
}
|
|
break;
|
|
case RELOAD_AUTOPLACE_OLD:
|
|
if ( !AutoPlaceObject( pSoldier, &gTempObject, TRUE ) )
|
|
{
|
|
// error msg!
|
|
return( FALSE );
|
|
}
|
|
// place first ammo in gun
|
|
(*pGun)[subObject]->data.gun.ubGunShotsLeft = ubBulletsToMove;
|
|
(*pGun)[subObject]->data.gun.ubGunAmmoType = Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType;
|
|
(*pGun)[subObject]->data.gun.usGunAmmoItem = usNewAmmoItem;
|
|
|
|
break;
|
|
|
|
case RELOAD_TOPOFF:
|
|
// ADD that many bullets to gun
|
|
(*pGun)[subObject]->data.gun.ubGunShotsLeft += ubBulletsToMove;
|
|
break;
|
|
|
|
}
|
|
|
|
// CHRISL: If we don't completely reload a SwapClips==0 weapon, set the "reload" flag
|
|
if(Weapon[pGun->usItem].swapClips == 0 && GetMagSize(pGun) != (*pGun)[0]->data.gun.ubGunShotsLeft)
|
|
{
|
|
(*pGun)[subObject]->data.gun.ubGunState |= GS_WEAPON_BEING_RELOADED;
|
|
(*pGun)[subObject]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER;
|
|
}
|
|
else
|
|
{
|
|
(*pGun)[subObject]->data.gun.ubGunState &= ~GS_WEAPON_BEING_RELOADED;
|
|
(*pGun)[subObject]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
|
}
|
|
|
|
if ( ! ( bReloadType == RELOAD_SWAP && !fReloadingWithStack ) )
|
|
{
|
|
// remove # of bullets, delete 1 object if necessary
|
|
|
|
(*pAmmo)[ammoObject]->data.ubShotsLeft -= ubBulletsToMove;
|
|
if ((*pAmmo)[ammoObject]->data.ubShotsLeft == 0)
|
|
{
|
|
pAmmo->RemoveObjectAtIndex(ammoObject);
|
|
//pAmmo->RemoveObjectsFromStack(1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// OK, let's play a sound of reloading too...
|
|
// If this guy is visible...
|
|
if ( pSoldier->bVisible != -1 )
|
|
{
|
|
// Play some effects!
|
|
usReloadSound = Weapon[ pGun->usItem ].sReloadSound;
|
|
|
|
if ( usReloadSound != 0 && !IsAutoResolveActive() )
|
|
{
|
|
PlayJA2Sample( usReloadSound, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
}
|
|
|
|
if (pSoldier->bTeam == gbPlayerNum)
|
|
{
|
|
// spit out a message if this is one of our folks reloading
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_PLAYER_RELOADS], pSoldier->name );
|
|
}
|
|
|
|
DeductPoints( pSoldier, bAPs, 0 );
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pGun->ubWeight = CalculateObjectWeight( pGun );
|
|
|
|
if ( (*pGun)[subObject]->data.gun.bGunAmmoStatus >= 0 )
|
|
{
|
|
// make sure gun ammo status is 100, if gun isn't jammed
|
|
(*pGun)[subObject]->data.gun.bGunAmmoStatus = 100;
|
|
}
|
|
|
|
//CHRISL: Move this towards the top so that we can leave this flag off if we're in the middle of reloading
|
|
//(*pGun)[subObject]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; // Madd: reloading should automatically put cartridge in chamber
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN EmptyWeaponMagazine( OBJECTTYPE * pWeapon, OBJECTTYPE *pAmmo, UINT32 subObject )
|
|
{
|
|
UINT16 usReloadSound;
|
|
|
|
CHECKF( pAmmo != NULL );
|
|
|
|
if ( (*pWeapon)[subObject]->data.gun.ubGunShotsLeft > 0 )
|
|
{
|
|
CreateAmmo((*pWeapon)[subObject]->data.gun.usGunAmmoItem, pAmmo, (*pWeapon)[subObject]->data.gun.ubGunShotsLeft);
|
|
|
|
(*pWeapon)[subObject]->data.gun.ubGunShotsLeft = 0;
|
|
(*pWeapon)[subObject]->data.gun.ubGunAmmoType = 0;
|
|
//(*pWeapon)[subObject]->data.gun.usGunAmmoItem = 0; // leaving the ammo item the same for auto-reloading purposes
|
|
|
|
// Play some effects!
|
|
usReloadSound = Weapon[ pWeapon->usItem ].sReloadSound;
|
|
|
|
if ( usReloadSound != 0 )
|
|
{
|
|
PlayJA2Sample( usReloadSound, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pWeapon->ubWeight = CalculateObjectWeight( pWeapon );
|
|
// Pulmu bugfix:
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pAmmo->ubWeight = CalculateObjectWeight( pAmmo );
|
|
// Pulmu end:
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
//CHRISL: Clear the contents of pAmmo just in case
|
|
pAmmo->initialize();
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, INT8 bExcludeSlot )
|
|
{
|
|
INT8 bLoop;
|
|
INT8 capLoop = 0;
|
|
UINT16 curCap = 0, stackCap = 0;
|
|
BOOLEAN found = FALSE;
|
|
INVTYPE * pItem;
|
|
|
|
//CHRISL: Update this to search for the largest appropriate mag if ubMagSize = ANY_MAGSIZE
|
|
|
|
for (bLoop = HANDPOS; bLoop < (INT8)pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (bLoop == bExcludeSlot)
|
|
{
|
|
continue;
|
|
}
|
|
pItem = &(Item[pSoldier->inv[bLoop].usItem]);
|
|
if (pItem->usItemClass == IC_AMMO)
|
|
{
|
|
if (Magazine[pItem->ubClassIndex].ubCalibre == ubCalibre)
|
|
{
|
|
if(ubMagSize != ANY_MAGSIZE && Magazine[pItem->ubClassIndex].ubMagSize == ubMagSize)
|
|
{
|
|
found = TRUE;
|
|
// looking for specific size. return if found
|
|
// Find fullest mag
|
|
for(int i = 0; i<pSoldier->inv[bLoop].ubNumberOfObjects; i++)
|
|
{
|
|
stackCap = __max(stackCap, pSoldier->inv[bLoop][i]->data.ubShotsLeft);
|
|
}
|
|
if(stackCap > curCap)
|
|
{
|
|
curCap = stackCap;
|
|
capLoop = bLoop;
|
|
}
|
|
//return( bLoop );
|
|
}
|
|
else if(ubMagSize == ANY_MAGSIZE)
|
|
{
|
|
found = TRUE;
|
|
// looking for any mag size. find the largest
|
|
if(Magazine[pItem->ubClassIndex].ubMagSize > curCap)
|
|
{
|
|
curCap = Magazine[pItem->ubClassIndex].ubMagSize;
|
|
capLoop = bLoop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(found == TRUE)
|
|
return( capLoop );
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
|
|
INT8 FindAmmoToReload( SOLDIERTYPE * pSoldier, INT8 bWeaponIn, INT8 bExcludeSlot )
|
|
{
|
|
OBJECTTYPE * pObj;
|
|
INT8 bSlot;
|
|
|
|
if (pSoldier == NULL)
|
|
{
|
|
return( NO_SLOT );
|
|
}
|
|
pObj = &(pSoldier->inv[bWeaponIn]);
|
|
|
|
//<SB> manual recharge
|
|
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
|
return bWeaponIn;
|
|
//</SB>
|
|
|
|
if ( Item[pObj->usItem].usItemClass == IC_GUN && !Item[pObj->usItem].cannon )
|
|
{
|
|
// look for same ammo as before
|
|
//bSlot = FindObjExcludingSlot( pSoldier, (*pObj)[0]->data.gun.usGunAmmoItem, bExcludeSlot );
|
|
//if (bSlot != NO_SLOT)
|
|
//{
|
|
// reload using this ammo!
|
|
// return( bSlot );
|
|
//}
|
|
// look for any ammo that matches which is of the same calibre and magazine size
|
|
bSlot = FindAmmo( pSoldier, Weapon[pObj->usItem].ubCalibre, GetMagSize(pObj), bExcludeSlot );
|
|
if (bSlot != NO_SLOT)
|
|
{
|
|
return( bSlot );
|
|
}
|
|
else
|
|
{
|
|
// look for any ammo that matches which is of the same calibre (different size okay)
|
|
return( FindAmmo( pSoldier, Weapon[pObj->usItem].ubCalibre, ANY_MAGSIZE, bExcludeSlot ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<MAXITEMS;i++)
|
|
{
|
|
if ( Launchable[i][0] == 0 && Launchable[i][1] == 0)
|
|
break;
|
|
|
|
if ( pObj->usItem == Launchable[i][1] )
|
|
{
|
|
bSlot = FindObj( pSoldier, Launchable[i][0] );
|
|
|
|
if ( bSlot != NO_SLOT )
|
|
return bSlot;
|
|
}
|
|
}
|
|
return NO_SLOT;
|
|
|
|
//switch( pObj->usItem )
|
|
//{
|
|
// case RPG7: // TODO: madd fix this
|
|
// return( FindObjInObjRange( pSoldier, RPG_HE_ROCKET, RPG_FRAG_ROCKET ) );
|
|
// case MORTAR:
|
|
// return( FindObj( pSoldier, MORTAR_SHELL ) );
|
|
// case TANK_CANNON:
|
|
// return( FindObj( pSoldier, TANK_SHELL ) );
|
|
// case GLAUNCHER:
|
|
// case UNDER_GLAUNCHER:
|
|
// return( FindObjInObjRange( pSoldier, GL_HE_GRENADE, GL_SMOKE_GRENADE ) );
|
|
// default:
|
|
// return( NO_SLOT );
|
|
//}
|
|
}
|
|
}
|
|
|
|
BOOLEAN AutoReload( SOLDIERTYPE * pSoldier )
|
|
{
|
|
OBJECTTYPE *pObj, *pObj2;
|
|
INT8 bSlot;
|
|
INT16 bAPCost;
|
|
BOOLEAN fRet;
|
|
|
|
CHECKF( pSoldier );
|
|
pObj = &(pSoldier->inv[HANDPOS]);
|
|
|
|
//<SB> manual recharge
|
|
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
|
{
|
|
(*pObj)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
|
(*pObj)[0]->data.gun.ubGunState &= ~GS_WEAPON_BEING_RELOADED;
|
|
|
|
DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0);
|
|
|
|
PlayJA2Sample( Weapon[ Item[pObj->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
|
|
if ( pSoldier->IsValidSecondHandShot( ) )
|
|
{
|
|
pObj2 = &(pSoldier->inv[SECONDHANDPOS]);
|
|
|
|
if ((*pObj2)[0]->data.gun.ubGunShotsLeft && !((*pObj2)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
|
{
|
|
(*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
|
PlayJA2Sample( Weapon[ Item[pObj2->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->IsValidSecondHandShot( ) )
|
|
{
|
|
pObj2 = &(pSoldier->inv[SECONDHANDPOS]);
|
|
|
|
if ((*pObj2)[0]->data.gun.ubGunShotsLeft && !((*pObj2)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
|
|
{
|
|
(*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER;
|
|
|
|
DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0);
|
|
|
|
PlayJA2Sample( Weapon[ Item[pObj2->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
//</SB>
|
|
|
|
if (Item[pObj->usItem].usItemClass == IC_GUN || Item[pObj->usItem].usItemClass == IC_LAUNCHER)
|
|
{
|
|
bSlot = FindAmmoToReload( pSoldier, HANDPOS, NO_SLOT );
|
|
if (bSlot != NO_SLOT)
|
|
{
|
|
// reload using this ammo!
|
|
fRet = ReloadGun( pSoldier, pObj, &(pSoldier->inv[bSlot]) );
|
|
// if we are valid for two-pistol shooting (reloading) and we have enough APs still
|
|
// then do a reload of both guns!
|
|
if ( (fRet == TRUE) && pSoldier->IsValidSecondHandShotForReloadingPurposes( ) )
|
|
{
|
|
pObj = &(pSoldier->inv[SECONDHANDPOS]);
|
|
bSlot = FindAmmoToReload( pSoldier, SECONDHANDPOS, NO_SLOT );
|
|
if (bSlot != NO_SLOT)
|
|
{
|
|
// ce would reload using this ammo!
|
|
bAPCost = GetAPsToReloadGunWithAmmo( pSoldier, pObj, &(pSoldier->inv[bSlot] ) );
|
|
if ( EnoughPoints( pSoldier, (INT16) bAPCost, 0, FALSE ) )
|
|
{
|
|
// reload the 2nd gun too
|
|
fRet = ReloadGun( pSoldier, pObj, &(pSoldier->inv[bSlot]) );
|
|
}
|
|
else
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_RELOAD_ONLY_ONE_GUN ], pSoldier->name );
|
|
}
|
|
}
|
|
}
|
|
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
return( fRet );
|
|
}
|
|
}
|
|
|
|
// couldn't reload
|
|
return( FALSE );
|
|
}
|
|
|
|
INT8 GetAttachmentComboMerge( OBJECTTYPE * pObj, UINT8 subObject )
|
|
{
|
|
INT8 bIndex = 0;
|
|
INT8 bAttachLoop;
|
|
|
|
/* check the whole Array of possible Attachements, while there are still entries ... */
|
|
while( AttachmentComboMerge[ bIndex ].usItem != NOTHING )
|
|
{
|
|
/* if we found our current Object as "basic hand" item, then
|
|
* we have found at least ONE entry of our item (may be there are more)
|
|
*/
|
|
OBJECTTYPE* pAttachment = 0;
|
|
if ( pObj->usItem == AttachmentComboMerge[ bIndex ].usItem )
|
|
{
|
|
// search for all the appropriate attachments
|
|
/* every ComboMerge must have at least one attachments Field */
|
|
for ( bAttachLoop = 0; bAttachLoop < 2; bAttachLoop++ )
|
|
{
|
|
/* if the none of both Fields contains anything, do not merge */
|
|
if ( AttachmentComboMerge[ bIndex ].usAttachment[ bAttachLoop ] == NOTHING )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* 2007-05-27, Sgt_Kolja:
|
|
* do not return, but break the inner loop moved away, otherwise
|
|
* we can only have ONE attachmentCombo per basic item. F.I. if we want
|
|
* to make a Dart gun from Dart pistol by adding (a buttstock and) wheter a
|
|
* steel tube /or/ a Gun Barrel Extender, the old code wouldn't work for
|
|
* the Gun Barel Extender, since it would never been tested.
|
|
*/
|
|
pAttachment = FindAttachment( pObj, AttachmentComboMerge[ bIndex ].usAttachment[ bAttachLoop ], subObject );
|
|
if ( pAttachment == 0 )
|
|
{
|
|
// didn't find something required
|
|
break;
|
|
}
|
|
}
|
|
// found everything required?
|
|
/* 2007-05-27, Sgt_Kolja: Not-found-condition moved from above, otherwise we can only have ONE attachmentCombo per basic item */
|
|
if ( pAttachment )
|
|
{
|
|
return( bIndex );
|
|
}
|
|
} /* end-if-this-is-our-item */
|
|
|
|
/* try next Attachment Order */
|
|
bIndex++;
|
|
}
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
|
|
|
|
void PerformAttachmentComboMerge( OBJECTTYPE * pObj, INT8 bAttachmentComboMerge )
|
|
{
|
|
INT8 bAttachLoop;
|
|
UINT32 uiStatusTotal = 0;
|
|
INT8 bNumStatusContributors = 0;
|
|
|
|
// This object has been validated as available for an attachment combo merge.
|
|
// - find all attachments in list and destroy them
|
|
// - status of new object should be average of items including attachments
|
|
// - change object
|
|
|
|
for ( bAttachLoop = 0; bAttachLoop < 2; bAttachLoop++ )
|
|
{
|
|
if ( AttachmentComboMerge[ bAttachmentComboMerge ].usAttachment[ bAttachLoop ] == NOTHING )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
OBJECTTYPE* pAttachment = FindAttachment( pObj, AttachmentComboMerge[ bAttachmentComboMerge ].usAttachment[ bAttachLoop ] );
|
|
AssertMsg( pAttachment != 0, String( "Attachment combo merge couldn't find a necessary attachment" ) );
|
|
|
|
uiStatusTotal += (*pAttachment)[0]->data.objectStatus;
|
|
bNumStatusContributors++;
|
|
|
|
pObj->RemoveAttachment(pAttachment);
|
|
}
|
|
|
|
uiStatusTotal += (*pObj)[0]->data.objectStatus;
|
|
bNumStatusContributors++;
|
|
|
|
pObj->usItem = AttachmentComboMerge[ bAttachmentComboMerge ].usResult;
|
|
(*pObj)[0]->data.objectStatus = (INT8) (uiStatusTotal / bNumStatusContributors );
|
|
}
|
|
|
|
BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound, UINT8 subObject )
|
|
{
|
|
//CHRISL: This makes it impossible to add attachments to objects in a stack. Let's remove this and make this possible.
|
|
//if ( this->ubNumberOfObjects > 1 )
|
|
//{
|
|
// return( FALSE );
|
|
//}
|
|
if (pAttachment->exists() == false) {
|
|
return FALSE;
|
|
}
|
|
if ((*this)[subObject]->attachments.size() >= MAX_ATTACHMENTS) {
|
|
return FALSE;
|
|
}
|
|
//CHRISL: If we're adding a loaded UGL, then we have to make sure there are actually 2 open attachment slots instead of 1
|
|
if(Item[pAttachment->usItem].grenadelauncher && (*pAttachment)[0]->attachments.size() > 0) {
|
|
if ((*this)[subObject]->attachments.size() >= (MAX_ATTACHMENTS-1))
|
|
return FALSE;
|
|
}
|
|
|
|
static OBJECTTYPE attachmentObject;
|
|
|
|
UINT16 usResult, usResult2, ubLimit;
|
|
INT8 bLoop;
|
|
UINT8 ubType, ubAPCost;
|
|
INT32 iCheckResult;
|
|
INT8 bAttachInfoIndex = -1, bAttachComboMerge;
|
|
BOOLEAN fValidLaunchable = FALSE;
|
|
|
|
bool canOnlyAttach1 = false;
|
|
|
|
//if this is an attachment or ammo for a launchable item
|
|
fValidLaunchable = ValidLaunchable( pAttachment->usItem, this->usItem );
|
|
//CHRISL: If we don't want to play the sound, it's a good bet we don't want to display any messages either
|
|
if ( fValidLaunchable || ValidItemAttachment( this, pAttachment->usItem, TRUE, playSound, subObject ) )
|
|
{
|
|
//if there is already an attachment of the same type, we want to try swapping / replacing it
|
|
OBJECTTYPE* pAttachmentPosition = 0;
|
|
|
|
// find an attachment position...
|
|
// second half of this 'if' is for attaching GL grenades to a gun w/attached GL
|
|
if ( fValidLaunchable || (Item[pAttachment->usItem].glgrenade && FindAttachmentByClass(this, IC_LAUNCHER, subObject) != 0 ) )
|
|
{
|
|
canOnlyAttach1 = true;
|
|
// try replacing if possible
|
|
pAttachmentPosition = FindAttachmentByClass( this, Item[ pAttachment->usItem ].usItemClass, subObject );
|
|
}
|
|
else
|
|
{
|
|
// try replacing if possible
|
|
pAttachmentPosition = FindAttachment( this, pAttachment->usItem, subObject );
|
|
}
|
|
|
|
if ( pSoldier )
|
|
{
|
|
//did the soldier damage it?
|
|
bAttachInfoIndex = GetAttachmentInfoIndex( pAttachment->usItem );
|
|
// in-game (not behind the scenes) attachment
|
|
if ( bAttachInfoIndex != -1 && AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheck != NO_CHECK )
|
|
{
|
|
iCheckResult = SkillCheck( pSoldier, AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheck, AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod );
|
|
if (iCheckResult < 0)
|
|
{
|
|
// the attach failure damages both items
|
|
DamageObj( this, (INT8) -iCheckResult, subObject );
|
|
DamageObj( pAttachment, (INT8) -iCheckResult, subObject );
|
|
|
|
// there should be a quote here!
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
|
|
if ( gfInItemDescBox )
|
|
{
|
|
DeleteItemDescriptionBox();
|
|
}
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
if ( ValidItemAttachment( this, pAttachment->usItem, TRUE, TRUE, subObject ) && playSound ) // not launchable
|
|
{
|
|
// attachment sounds
|
|
if ( Item[ this->usItem ].usItemClass & IC_WEAPON )
|
|
{
|
|
PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
}
|
|
else if ( Item[ this->usItem ].usItemClass & IC_ARMOUR )
|
|
{
|
|
PlayJA2Sample( ATTACH_CERAMIC_PLATES, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
}
|
|
else if ( Item[ this->usItem ].usItemClass & IC_BOMB )
|
|
{
|
|
PlayJA2Sample( ATTACH_DETONATOR, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pAttachmentPosition) {
|
|
if (canOnlyAttach1 == true) {
|
|
if(pAttachment->ubNumberOfObjects > 1)
|
|
{
|
|
//We don't want to inadvertantly load two rounds during a swap so don't allow a swap if we're holding a stack
|
|
return(FALSE);
|
|
}
|
|
//we have requested to swap the attachment on the cursor with the current attachment
|
|
SwapObjs(pAttachmentPosition,pAttachment);
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
//ADB moved after skill check!
|
|
//lalien: added to make a GL/RL work when reloaded manually
|
|
// the AP costs for reloading GL/RL will be taken from weapons.xml ( wrong place!!! the AP's are deducted in DeleteItemDescriptionBox() )
|
|
//if (pAttachmentPosition) {
|
|
if(pAttachmentPosition || (pAttachmentPosition == NULL && (*this)[subObject]->attachments.size() < MAX_ATTACHMENTS)){
|
|
//we know we are replacing this attachment
|
|
if ( Item[ this->usItem ].usItemClass == IC_LAUNCHER || Item[this->usItem].cannon )
|
|
{
|
|
if ( fValidLaunchable )
|
|
{
|
|
(*this)[subObject]->data.gun.usGunAmmoItem = pAttachment->usItem;
|
|
//we have reloaded a launchable, so the ammo is gone from the original object
|
|
}
|
|
}
|
|
}
|
|
|
|
//unfortunately must come before possible attachment swap
|
|
if (Item[pAttachment->usItem].grenadelauncher )
|
|
{
|
|
// transfer any attachments from the grenade launcher to the gun
|
|
(*this)[subObject]->attachments.splice((*this)[subObject]->attachments.begin(), (*pAttachment)[0]->attachments,
|
|
(*pAttachment)[0]->attachments.begin(), (*pAttachment)[0]->attachments.end());
|
|
}
|
|
|
|
if (pAttachmentPosition) {
|
|
//we are swapping the attachments, and we know we do NOT need to worry about attachment stack size
|
|
//CHRISL: Actually, we do need to worry about attachment stack size since we might have a stack in our cursor.
|
|
// Rather then doing a simple swap, try moving the existing attachment to our cursor stack, then attach one item
|
|
// from the cursor stack.
|
|
|
|
pAttachment->AddObjectsToStack(*pAttachmentPosition,-1,pSoldier,NUM_INV_SLOTS,MAX_OBJECTS_PER_SLOT);
|
|
pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1);
|
|
*pAttachmentPosition = attachmentObject;
|
|
//backup the original attachment
|
|
//attachmentObject = *pAttachmentPosition;
|
|
|
|
//place the new one
|
|
//*pAttachmentPosition = *pAttachment;
|
|
|
|
//whatever pAttachment pointed to is now the original attachment
|
|
//*pAttachment = attachmentObject;
|
|
}
|
|
else {
|
|
//it's a new attachment
|
|
if (canOnlyAttach1 == true) {
|
|
//we only placed one of the stack, pAttachment could have any number of objects
|
|
if (pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1) == 0) {
|
|
(*this)[subObject]->attachments.push_back(attachmentObject);
|
|
}
|
|
}
|
|
else {
|
|
//pAttachment could have any number of objects, they have all been moved over
|
|
//CHRISL: This doesn't work. What if we have a stack of objects in the cursor? We don't want the whole
|
|
// stack to be attached
|
|
//(*this)[subObject]->attachments.push_back(*pAttachment);
|
|
//DeleteObj(pAttachment);
|
|
if (pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1) == 0) {
|
|
(*this)[subObject]->attachments.push_back(attachmentObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Check for attachment merge combos here
|
|
//CHRISL: Only do this if we're looking at a single item. Don't try a combo merge when dealing with a stack
|
|
bAttachComboMerge = GetAttachmentComboMerge( this, subObject );
|
|
if ( bAttachComboMerge != -1 )
|
|
{
|
|
if(this->ubNumberOfObjects == 1)
|
|
{
|
|
PerformAttachmentComboMerge( this, bAttachComboMerge );
|
|
if ( bAttachInfoIndex != -1 && AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod < 20 )
|
|
{
|
|
StatChange( pSoldier, MECHANAMT, (INT8) ( 20 - AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod ), FALSE );
|
|
StatChange( pSoldier, WISDOMAMT, (INT8) ( 20 - AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod ), FALSE );
|
|
}
|
|
}
|
|
//CHRISL: If we're looking at a stack, we need to unattach the object we just attached
|
|
else if(this->RemoveAttachment(&attachmentObject, pAttachmentPosition, subObject))
|
|
{
|
|
pAttachment->AddObjectsToStack(attachmentObject, -1, pSoldier, NUM_INV_SLOTS, MAX_OBJECTS_PER_SLOT);
|
|
}
|
|
}
|
|
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//this->ubWeight = CalculateObjectWeight( this );
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pAttachment->ubWeight = CalculateObjectWeight(pAttachment);
|
|
|
|
if ( pSoldier != NULL )
|
|
ApplyEquipmentBonuses(pSoldier);
|
|
|
|
return( TRUE );
|
|
}
|
|
// check for merges
|
|
else if (EvaluateValidMerge( pAttachment->usItem, this->usItem, &usResult, &usResult2, &ubType, &ubAPCost ))
|
|
{
|
|
//CHRISL: we don't want to try to merge IC_LBEGEAR items that are currently storing items.
|
|
if(Item[this->usItem].usItemClass == IC_LBEGEAR)
|
|
{
|
|
if(this->IsActiveLBE(subObject) == true)
|
|
return( FALSE );
|
|
}
|
|
//CHRISL: We don't want to do any merges if we're looking at a stack of items, with the exception of combines.
|
|
if ( this->ubNumberOfObjects > 1 && ubType != COMBINE_POINTS )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( ubType != COMBINE_POINTS )
|
|
{
|
|
if ( pSoldier )
|
|
{
|
|
if ( !EnoughPoints( pSoldier, ubAPCost, 0, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
//lalien: don't charge AP's for reloading a GL/RL ( wrong place!!! the AP's are deducted in DeleteItemDescriptionBox() )
|
|
//if ( IsAGLorRL == FALSE )
|
|
//{
|
|
DeductPoints( pSoldier, ubAPCost, 0 );
|
|
//}
|
|
}
|
|
}
|
|
|
|
switch( ubType )
|
|
{
|
|
case USE_ITEM:
|
|
case USE_ITEM_HARD:
|
|
// the merge will combine the two items
|
|
if ( pSoldier )
|
|
{
|
|
if ( ubType == USE_ITEM_HARD )
|
|
{
|
|
// requires a skill check, and gives experience
|
|
iCheckResult = SkillCheck( pSoldier, ATTACHING_SPECIAL_ITEM_CHECK, -30 );
|
|
if (iCheckResult < 0)
|
|
{
|
|
// could have a chance of detonation
|
|
// for now, damage both objects
|
|
DamageObj( this, (INT8) -iCheckResult );
|
|
DamageObj( pAttachment, (INT8) -iCheckResult );
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
|
|
return( FALSE );
|
|
}
|
|
StatChange( pSoldier, MECHANAMT, 25, FALSE );
|
|
StatChange( pSoldier, WISDOMAMT, 5, FALSE );
|
|
}
|
|
|
|
|
|
//Madd: note that use_item cannot produce two different items!!! so it doesn't use usResult2
|
|
|
|
//Madd: unload guns after merge if ammo caliber or mag size don't match
|
|
if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[0]->data.gun.usGunAmmoItem != NONE && (*this)[0]->data.gun.ubGunShotsLeft > 0 )
|
|
{
|
|
if ( Item[usResult].usItemClass != IC_GUN || Weapon[Item[usResult].ubClassIndex].ubCalibre != Weapon[Item[this->usItem].ubClassIndex].ubCalibre || (*this)[0]->data.gun.ubGunShotsLeft > Weapon[Item[usResult].ubClassIndex].ubMagSize )
|
|
{ // item types/calibers/magazines don't match, spit out old ammo
|
|
EjectAmmoAndPlace(pSoldier, this);
|
|
}
|
|
}
|
|
|
|
RemoveProhibitedAttachments(pSoldier, this, usResult);
|
|
|
|
this->usItem = usResult;
|
|
//AutoPlaceObject( pAttachment );
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//this->ubWeight = CalculateObjectWeight( this );
|
|
if (pSoldier->bTeam == gbPlayerNum)
|
|
{
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 );
|
|
}
|
|
ApplyEquipmentBonuses(pSoldier);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
case COMBINE_POINTS:
|
|
// transfer points...
|
|
UINT32 combinedAmount;
|
|
UINT32 attachmentAmount;
|
|
//CHRISL: Treat differently if we're combining money items (other then MONEY)
|
|
if(Item[this->usItem].usItemClass != IC_MONEY)
|
|
{
|
|
if ( Item[ this->usItem ].usItemClass == IC_AMMO )
|
|
{
|
|
ubLimit = Magazine[ Item[ this->usItem ].ubClassIndex ].ubMagSize;
|
|
}
|
|
else
|
|
{
|
|
ubLimit = 100;
|
|
}
|
|
|
|
// count down through # of attaching items and add to status of item in position 0
|
|
for (bLoop = 0; bLoop < pAttachment->ubNumberOfObjects; )
|
|
{
|
|
//ADB need to watch for overflow here (thus UINT32), and need to cast to UINT8 before adding
|
|
combinedAmount = (UINT16)(*this)[subObject]->data.objectStatus + (UINT16)(*pAttachment)[0]->data.objectStatus;
|
|
if (combinedAmount <= ubLimit)
|
|
{
|
|
// consume this one totally and continue
|
|
(*this)[subObject]->data.objectStatus = combinedAmount;
|
|
pAttachment->RemoveObjectsFromStack(1);
|
|
}
|
|
else
|
|
{
|
|
// add part of this one and then we're done
|
|
attachmentAmount = (UINT16)(*pAttachment)[0]->data.objectStatus;
|
|
attachmentAmount -= (ubLimit - (UINT16)(*this)[subObject]->data.objectStatus);
|
|
(*pAttachment)[0]->data.objectStatus = attachmentAmount;
|
|
if ((*pAttachment)[0]->data.ubShotsLeft == 0) {
|
|
pAttachment->RemoveObjectsFromStack(1);
|
|
}
|
|
(*this)[subObject]->data.ubShotsLeft = ubLimit;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubLimit = MAX_MONEY_PER_SLOT;
|
|
combinedAmount = (*this)[subObject]->data.money.uiMoneyAmount + (*pAttachment)[0]->data.money.uiMoneyAmount;
|
|
if (combinedAmount <= ubLimit)
|
|
{
|
|
(*this)[subObject]->data.money.uiMoneyAmount = combinedAmount;
|
|
pAttachment->RemoveObjectsFromStack(1);
|
|
}
|
|
else
|
|
{
|
|
attachmentAmount = (*pAttachment)[0]->data.money.uiMoneyAmount;
|
|
attachmentAmount -= (ubLimit - (*this)[subObject]->data.money.uiMoneyAmount);
|
|
(*pAttachment)[0]->data.money.uiMoneyAmount = attachmentAmount;
|
|
if((*pAttachment)[0]->data.money.uiMoneyAmount == 0)
|
|
{
|
|
pAttachment->RemoveObjectsFromStack(1);
|
|
}
|
|
(*this)[subObject]->data.money.uiMoneyAmount = ubLimit;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case DESTRUCTION:
|
|
// the merge destroyed both items!
|
|
this->RemoveObjectsFromStack(1);
|
|
pAttachment->RemoveObjectsFromStack(1);
|
|
if ( pSoldier )
|
|
{
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
|
|
}
|
|
break;
|
|
case ELECTRONIC_MERGE:
|
|
if ( pSoldier )
|
|
{
|
|
iCheckResult = SkillCheck( pSoldier, ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK, -30 );
|
|
if ( iCheckResult < 0 )
|
|
{
|
|
DamageObj( this, (INT8) -iCheckResult );
|
|
DamageObj( pAttachment, (INT8) -iCheckResult );
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
|
|
return( FALSE );
|
|
}
|
|
// grant experience!
|
|
}
|
|
// fall through
|
|
case EXPLOSIVE:
|
|
if ( ubType == EXPLOSIVE ) /// coulda fallen through
|
|
{
|
|
if (pSoldier)
|
|
{
|
|
// requires a skill check, and gives experience
|
|
iCheckResult = SkillCheck( pSoldier, ATTACHING_DETONATOR_CHECK, -30 );
|
|
if (iCheckResult < 0)
|
|
{
|
|
// could have a chance of detonation
|
|
// for now, damage both objects
|
|
DamageObj( this, (INT8) -iCheckResult );
|
|
DamageObj( pAttachment, (INT8) -iCheckResult );
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
|
|
return( FALSE );
|
|
}
|
|
StatChange( pSoldier, EXPLODEAMT, 25, FALSE );
|
|
StatChange( pSoldier, WISDOMAMT, 5, FALSE );
|
|
}
|
|
}
|
|
// fall through
|
|
default:
|
|
// the merge will combine the two items
|
|
//Madd: usResult2 only works for standard merges->item1 + item2 = item3 + item4
|
|
|
|
//Madd: unload guns after merge if ammo caliber or mag size don't match
|
|
if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[subObject]->data.gun.usGunAmmoItem != NONE && (*this)[subObject]->data.gun.ubGunShotsLeft > 0 )
|
|
{
|
|
if ( Item[usResult].usItemClass != IC_GUN || Weapon[Item[usResult].ubClassIndex].ubCalibre != Weapon[Item[this->usItem].ubClassIndex].ubCalibre || (*this)[subObject]->data.gun.ubGunShotsLeft > Weapon[Item[usResult].ubClassIndex].ubMagSize )
|
|
{ // item types/calibers/magazines don't match, spit out old ammo
|
|
EjectAmmoAndPlace(pSoldier, this);
|
|
}
|
|
}
|
|
|
|
RemoveProhibitedAttachments(pSoldier, this, usResult);
|
|
|
|
this->usItem = usResult;
|
|
if ( ubType != TREAT_ARMOUR )
|
|
{
|
|
(*this)[subObject]->data.objectStatus = ((*this)[subObject]->data.objectStatus + (*pAttachment)[0]->data.objectStatus) / 2;
|
|
}
|
|
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//this->ubWeight = CalculateObjectWeight( this );
|
|
|
|
if ( usResult2 != NOTHING )
|
|
{
|
|
//Madd: usResult2 is what the original attachment/source item turns into
|
|
|
|
//Madd: unload guns after merge if ammo caliber or mag size don't match
|
|
if ( Item[pAttachment->usItem].usItemClass == IC_GUN && (*pAttachment)[0]->data.gun.usGunAmmoItem != NONE && (*pAttachment)[0]->data.gun.ubGunShotsLeft > 0 )
|
|
{
|
|
if ( Item[usResult2].usItemClass != IC_GUN || Weapon[Item[usResult2].ubClassIndex].ubCalibre != Weapon[Item[pAttachment->usItem].ubClassIndex].ubCalibre || (*pAttachment)[0]->data.gun.ubGunShotsLeft > Weapon[Item[usResult2].ubClassIndex].ubMagSize )
|
|
{ // item types/calibers/magazines don't match, spit out old ammo
|
|
EjectAmmoAndPlace(pSoldier, pAttachment);
|
|
}
|
|
}
|
|
|
|
RemoveProhibitedAttachments(pSoldier, pAttachment, usResult2);
|
|
|
|
pAttachment->usItem = usResult2;
|
|
if ( ubType != TREAT_ARMOUR )
|
|
{
|
|
(*pAttachment)[0]->data.objectStatus = ((*pAttachment)[0]->data.objectStatus + (*this)[subObject]->data.objectStatus) / 2;
|
|
}
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pAttachment->ubWeight = CalculateObjectWeight( pAttachment );
|
|
}
|
|
else
|
|
pAttachment->RemoveObjectsFromStack(1);
|
|
|
|
if (pSoldier && pSoldier->bTeam == gbPlayerNum)
|
|
{
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 );
|
|
}
|
|
break;
|
|
}
|
|
if ( pSoldier != NULL )
|
|
ApplyEquipmentBonuses(pSoldier);
|
|
return( TRUE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usItem)
|
|
{
|
|
//Madd: remove any prohibited attachments
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (!ValidAttachment(iter->usItem, usItem) && !ValidLaunchable(iter->usItem, usItem) )
|
|
{
|
|
if ( !Item[iter->usItem].inseparable )
|
|
{
|
|
if (pSoldier) {
|
|
if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) )
|
|
{ // put it on the ground
|
|
AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 );
|
|
}
|
|
}
|
|
}
|
|
pObj->RemoveAttachment(&(*iter));
|
|
iter = (*pObj)[0]->attachments.begin();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj)
|
|
{
|
|
CreateAmmo((*pObj)[0]->data.gun.usGunAmmoItem, &gTempObject, (*pObj)[0]->data.gun.ubGunShotsLeft);
|
|
(*pObj)[0]->data.gun.ubGunShotsLeft = 0;
|
|
(*pObj)[0]->data.gun.usGunAmmoItem = NONE;
|
|
if ( pSoldier )
|
|
{
|
|
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
|
|
{ // put it on the ground
|
|
AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0 , -1 );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* CHRISL: This function is edited to handle the new inventory system when we have an item in our cursor.
|
|
Not only do we have to hatch out pockets that the item won't fit in, we also have to hatch out pockets that
|
|
our current LBE gear haven't activated. We'll also need to display the number of items of the type currently
|
|
held in the cursor that each active pocket can hold.*/
|
|
extern BOOLEAN CompatibleAmmoForGun( OBJECTTYPE *pTryObject, OBJECTTYPE *pTestObject );
|
|
BOOLEAN CanItemFitInVehicle( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos, BOOLEAN fDoingPlacement )
|
|
{
|
|
if((UsingNewInventorySystem() == false) || !(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE))
|
|
return(FALSE);
|
|
if(!vehicleInv[bPos])
|
|
return(FALSE);
|
|
|
|
UINT8 ubSlotLimit;
|
|
ubSlotLimit = ItemSlotLimit( pObj, bPos, pSoldier );
|
|
|
|
if ( ubSlotLimit == 0 )
|
|
return ( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos, BOOLEAN fDoingPlacement )
|
|
{
|
|
UINT8 ubSlotLimit, lbePocket=1;
|
|
INT8 bNewPos=ITEM_NOT_FOUND;
|
|
UINT32 pRestrict=0;
|
|
|
|
// CHRISL: Only check valid pockets
|
|
if((UsingNewInventorySystem() == false) && !oldInv[bPos])
|
|
return(FALSE);
|
|
if((pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) && UsingNewInventorySystem() == true)
|
|
return(CanItemFitInVehicle(pSoldier, pObj, bPos, fDoingPlacement));
|
|
|
|
ubSlotLimit = ItemSlotLimit( pObj, bPos, pSoldier );
|
|
|
|
switch( bPos )
|
|
{
|
|
case SECONDHANDPOS:
|
|
if (Item[pSoldier->inv[HANDPOS].usItem].twohanded )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
case HANDPOS:
|
|
if (Item[ pObj->usItem ].twohanded )
|
|
{
|
|
if (pSoldier->inv[HANDPOS].exists() == true && pSoldier->inv[SECONDHANDPOS].exists() == true)
|
|
{
|
|
// two items in hands; try moving the second one so we can swap
|
|
if (FitsInSmallPocket(&pSoldier->inv[SECONDHANDPOS]) == true)
|
|
{
|
|
bNewPos = FindEmptySlotWithin( pSoldier, BIGPOCKSTART, NUM_INV_SLOTS );
|
|
}
|
|
else
|
|
{
|
|
bNewPos = FindEmptySlotWithin( pSoldier, BIGPOCKSTART, MEDPOCKFINAL );
|
|
}
|
|
|
|
if (bNewPos == NO_SLOT)
|
|
{
|
|
// nowhere to put second item
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( fDoingPlacement )
|
|
{
|
|
// otherwise move it, forget about bNewPos!
|
|
PlaceInAnyPocket(pSoldier, &pSoldier->inv[SECONDHANDPOS], FALSE);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case VESTPOS:
|
|
case HELMETPOS:
|
|
case LEGPOS:
|
|
if (Item[pObj->usItem].usItemClass != IC_ARMOUR)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
switch (bPos)
|
|
{
|
|
case VESTPOS:
|
|
if (Armour[Item[pObj->usItem].ubClassIndex].ubArmourClass != ARMOURCLASS_VEST)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
case HELMETPOS:
|
|
if (Armour[Item[pObj->usItem].ubClassIndex].ubArmourClass != ARMOURCLASS_HELMET)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
case LEGPOS:
|
|
if (Armour[Item[pObj->usItem].ubClassIndex].ubArmourClass != ARMOURCLASS_LEGGINGS)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case HEAD1POS:
|
|
case HEAD2POS:
|
|
if (Item[pObj->usItem].usItemClass != IC_FACE)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
case VESTPOCKPOS:
|
|
if (Item[pObj->usItem].usItemClass != IC_LBEGEAR || LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeClass != VEST_PACK)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
case LTHIGHPOCKPOS:
|
|
case RTHIGHPOCKPOS:
|
|
if (Item[pObj->usItem].usItemClass != IC_LBEGEAR || LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeClass != THIGH_PACK)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
break;
|
|
case CPACKPOCKPOS:
|
|
if (Item[pObj->usItem].usItemClass != IC_LBEGEAR || LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeClass != COMBAT_PACK)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if(pSoldier->inv[BPACKPOCKPOS].exists() == true)
|
|
{
|
|
if(LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo != LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo ||
|
|
LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo == 0)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
break;
|
|
case BPACKPOCKPOS:
|
|
if (Item[pObj->usItem].usItemClass != IC_LBEGEAR || LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeClass != BACKPACK)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
// Removed backpack/gunsling restrictions
|
|
//if(pSoldier->inv[GUNSLINGPOCKPOS].exists() == true)
|
|
// return( FALSE );
|
|
if(pSoldier->inv[CPACKPOCKPOS].exists() == true)
|
|
{
|
|
if(LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo != LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo ||
|
|
LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo == 0)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
break;
|
|
case GUNSLINGPOCKPOS: // Gun Sling
|
|
//if (Item[pObj->usItem].usItemClass != IC_GUN && Item[pObj->usItem].usItemClass != IC_BLADE && Item[pObj->usItem].usItemClass != IC_LAUNCHER)
|
|
if(pObj->usItem == MONEY)
|
|
return( FALSE );
|
|
if(Item[pObj->usItem].usItemClass == IC_AMMO || Item[pObj->usItem].usItemClass == IC_GRENADE)
|
|
return(CompatibleAmmoForGun(pObj, &pSoldier->inv[GUNSLINGPOCKPOS]) || ValidAttachment(pObj->usItem, pSoldier->inv[GUNSLINGPOCKPOS].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[GUNSLINGPOCKPOS].usItem));
|
|
//recalc slot limit to exclude ItemSize attachment modifiers
|
|
ubSlotLimit = ItemSlotLimit( pObj, bPos, pSoldier, FALSE );
|
|
// Removed backpack/gunsling restrictions
|
|
//if(pSoldier->inv[BPACKPOCKPOS].exists() == true)
|
|
// return(CompatibleAmmoForGun(pObj, &pSoldier->inv[GUNSLINGPOCKPOS]));
|
|
break;
|
|
case KNIFEPOCKPOS: // Knife sheath
|
|
if(pObj->usItem == MONEY)
|
|
return( FALSE );
|
|
if (Item[pObj->usItem].usItemClass != IC_BLADE && Item[pObj->usItem].usItemClass != IC_THROWING_KNIFE )
|
|
return(CompatibleAmmoForGun(pObj, &pSoldier->inv[KNIFEPOCKPOS]) || ValidAttachment(pObj->usItem, pSoldier->inv[KNIFEPOCKPOS].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[KNIFEPOCKPOS].usItem));
|
|
break;
|
|
// IC Pockets
|
|
case BIGPOCK1POS:
|
|
case BIGPOCK2POS:
|
|
case BIGPOCK3POS:
|
|
case BIGPOCK4POS:
|
|
case BIGPOCK5POS:
|
|
case BIGPOCK6POS:
|
|
case BIGPOCK7POS:
|
|
case MEDPOCK1POS:
|
|
case MEDPOCK2POS:
|
|
case MEDPOCK3POS:
|
|
case MEDPOCK4POS:
|
|
case SMALLPOCK2POS:
|
|
case SMALLPOCK3POS:
|
|
case SMALLPOCK4POS:
|
|
case SMALLPOCK5POS:
|
|
case SMALLPOCK6POS:
|
|
case SMALLPOCK7POS:
|
|
case SMALLPOCK8POS:
|
|
case SMALLPOCK9POS:
|
|
case SMALLPOCK10POS:
|
|
case SMALLPOCK11POS:
|
|
case SMALLPOCK12POS:
|
|
case SMALLPOCK13POS:
|
|
case SMALLPOCK14POS:
|
|
case SMALLPOCK15POS:
|
|
case SMALLPOCK16POS:
|
|
case SMALLPOCK17POS:
|
|
case SMALLPOCK18POS:
|
|
case SMALLPOCK19POS:
|
|
case SMALLPOCK20POS:
|
|
case SMALLPOCK21POS:
|
|
case SMALLPOCK22POS:
|
|
case SMALLPOCK23POS:
|
|
case SMALLPOCK24POS:
|
|
case SMALLPOCK25POS:
|
|
case SMALLPOCK26POS:
|
|
case SMALLPOCK27POS:
|
|
case SMALLPOCK28POS:
|
|
case SMALLPOCK29POS:
|
|
case SMALLPOCK30POS:
|
|
if((UsingNewInventorySystem() == true))
|
|
{
|
|
if(icLBE[bPos] == BPACKPOCKPOS && (!(pSoldier->flags.ZipperFlag) || (pSoldier->flags.ZipperFlag && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_STAND)) && (gTacticalStatus.uiFlags & INCOMBAT))
|
|
return( FALSE );
|
|
lbePocket = (pSoldier->inv[icLBE[bPos]].exists() == false) ? LoadBearingEquipment[Item[icDefault[bPos]].ubClassIndex].lbePocketIndex[icPocket[bPos]] : LoadBearingEquipment[Item[pSoldier->inv[icLBE[bPos]].usItem].ubClassIndex].lbePocketIndex[icPocket[bPos]];
|
|
pRestrict = LBEPocketType[lbePocket].pRestriction;
|
|
if(pRestrict != 0)
|
|
if(!(pRestrict & Item[pObj->usItem].usItemClass))
|
|
lbePocket = 0;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if((UsingNewInventorySystem() == false))
|
|
{
|
|
if (ubSlotLimit == 0 && bPos >= SMALLPOCKSTART )
|
|
{
|
|
// doesn't fit!
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// CHRISL: lbePocket==0 means pocket disabled. ubSlotLimit==0 means pocket can't hold item
|
|
if ( lbePocket == 0 || ubSlotLimit == 0 )
|
|
return ( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) || ValidAttachment(pObj->usItem, pSoldier->inv[bPos].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[bPos].usItem) );
|
|
|
|
// CHRISL: Adjust parameters to include the new inventory system
|
|
if (ubSlotLimit == 0 && bPos >= BIGPOCKFINAL )
|
|
return( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) || ValidAttachment(pObj->usItem, pSoldier->inv[bPos].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[bPos].usItem) );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//CHRISL: Wrote this function to try and clean up possible problems relating to the 16bit change for ammo capacity
|
|
void CleanUpItemStats( OBJECTTYPE * pObj )
|
|
{
|
|
UINT16 magSize;
|
|
|
|
if(Item[pObj->usItem].usItemClass == IC_GUN)
|
|
{
|
|
magSize = GetMagSize(pObj);
|
|
if((*pObj)[0]->data.gun.ubGunShotsLeft > magSize)
|
|
{
|
|
(*pObj)[0]->data.gun.ubGunShotsLeft = magSize;
|
|
}
|
|
return;
|
|
}
|
|
if(Item[pObj->usItem].usItemClass == IC_AMMO)
|
|
{
|
|
magSize = Magazine[Item[pObj->usItem].ubClassIndex].ubMagSize;
|
|
if((*pObj)[0]->data.ubShotsLeft > magSize)
|
|
{
|
|
(*pObj)[0]->data.ubShotsLeft = magSize;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
BOOLEAN FreeUpSlotIfPossibleThenPlaceObject( SOLDIERTYPE * pSoldier, INT8 bPos, OBJECTTYPE * pObj )
|
|
{
|
|
//this gets called if something doesn't fit in bPos, which can happen if something is there
|
|
//or if it simply doesn't fit, if it doesn't fit return false to prevent recursion
|
|
|
|
// try autoplacing item in bSlot elsewhere, excluding the slot it came from, then do a placement
|
|
if ( pSoldier->inv[bPos].exists() == true && AutoPlaceObject( pSoldier, &(pSoldier->inv[bPos]), FALSE , bPos) )
|
|
{
|
|
//the old object has been placed somewhere, it's safe to place this one
|
|
return( PlaceObject( pSoldier, bPos, pObj ) );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
// CHRISL: Use to find best pocket to store item in. Could probably be merged with FitsInSmallPocket
|
|
INT32 PickPocket(SOLDIERTYPE *pSoldier, UINT8 ppStart, UINT8 ppStop, UINT16 usItem, UINT8 iNumber, UINT8 * cap, int bExcludeSlot)
|
|
{
|
|
UINT16 pIndex=0;
|
|
INT32 pocket=0;
|
|
UINT8 capacity=254;
|
|
|
|
for(UINT32 uiPos=ppStart; uiPos<ppStop; uiPos++){
|
|
if(pSoldier->inv[icLBE[uiPos]].exists() == false){
|
|
pIndex=LoadBearingEquipment[Item[icDefault[uiPos]].ubClassIndex].lbePocketIndex[icPocket[uiPos]];
|
|
}
|
|
else {
|
|
pIndex=LoadBearingEquipment[Item[pSoldier->inv[icLBE[uiPos]].usItem].ubClassIndex].lbePocketIndex[icPocket[uiPos]];
|
|
}
|
|
// Here's were we get complicated. We should look for the smallest pocket all items can fit in
|
|
if(LBEPocketType[pIndex].ItemCapacityPerSize[Item[usItem].ItemSize] >= iNumber &&
|
|
LBEPocketType[pIndex].ItemCapacityPerSize[Item[usItem].ItemSize] < capacity &&
|
|
pSoldier->inv[uiPos].exists() == false && uiPos != bExcludeSlot) {
|
|
if((LBEPocketType[pIndex].pRestriction != 0 && (LBEPocketType[pIndex].pRestriction & Item[usItem].usItemClass)) ||
|
|
LBEPocketType[pIndex].pRestriction == 0) {
|
|
capacity = LBEPocketType[pIndex].ItemCapacityPerSize[Item[usItem].ItemSize];
|
|
pocket = uiPos;
|
|
}
|
|
}
|
|
}
|
|
if(pocket!=0){
|
|
*cap=capacity;
|
|
return pocket;
|
|
}
|
|
else{
|
|
*cap=254;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
BOOLEAN PlaceObject( SOLDIERTYPE * pSoldier, INT8 bPos, OBJECTTYPE * pObj, BOOLEAN fNewItem )
|
|
{
|
|
if (PlaceObject(pSoldier, bPos, pObj) == TRUE) {
|
|
SetNewItem(pSoldier, bPos, fNewItem);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN PlaceObject( SOLDIERTYPE * pSoldier, INT8 bPos, OBJECTTYPE * pObj )
|
|
{
|
|
// returns object to have in hand after placement... same as original in the
|
|
// case of error
|
|
|
|
UINT8 ubSlotLimit;
|
|
OBJECTTYPE * pInSlot;
|
|
BOOLEAN fObjectWasRobotRemote = FALSE;
|
|
|
|
if ( Item[pObj->usItem].robotremotecontrol )
|
|
{
|
|
fObjectWasRobotRemote = TRUE;
|
|
}
|
|
|
|
//CHRISL: Failsafe to try and clean up ammo capacity problems
|
|
CleanUpItemStats(pObj);
|
|
|
|
if ( !CanItemFitInPosition( pSoldier, pObj, bPos, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// If the position is either head slot, then the item must be IC_FACE (checked in
|
|
// CanItemFitInPosition).
|
|
if ( bPos == HEAD1POS )
|
|
{
|
|
if ( !CompatibleFaceItem( pObj->usItem, pSoldier->inv[ HEAD2POS ].usItem ) )
|
|
{
|
|
CHAR16 zTemp[ 150 ];
|
|
|
|
swprintf( zTemp, Message[ STR_CANT_USE_TWO_ITEMS ], ItemNames[ pObj->usItem ], ItemNames[ pSoldier->inv[ HEAD2POS ].usItem ] );
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, zTemp );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else if ( bPos == HEAD2POS )
|
|
{
|
|
if ( !CompatibleFaceItem( pObj->usItem, pSoldier->inv[ HEAD1POS ].usItem ) )
|
|
{
|
|
CHAR16 zTemp[ 150 ];
|
|
|
|
swprintf( zTemp, Message[ STR_CANT_USE_TWO_ITEMS ], ItemNames[ pObj->usItem ], ItemNames[ pSoldier->inv[ HEAD1POS ].usItem ] );
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, zTemp );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
if ( Item[ pObj->usItem ].usItemClass == IC_KEY && pSoldier->flags.uiStatusFlags & SOLDIER_PC )
|
|
{
|
|
if ( KeyTable[ (*pObj)[0]->data.key.ubKeyID ].usDateFound == 0 )
|
|
{
|
|
KeyTable[ (*pObj)[0]->data.key.ubKeyID ].usDateFound = (UINT16) GetWorldDay();
|
|
KeyTable[ (*pObj)[0]->data.key.ubKeyID ].usSectorFound = SECTOR( pSoldier->sSectorX, pSoldier->sSectorY );
|
|
}
|
|
}
|
|
|
|
// Lesh: bugfix - replacing weapon in auto with another weapon w/o auto-mode
|
|
if (bPos == HANDPOS && Item[ pObj->usItem ].usItemClass == IC_GUN)
|
|
{
|
|
//Madd: added code for nosemiauto tag
|
|
if (!Weapon[ Item[pObj->usItem].ubClassIndex ].NoSemiAuto)
|
|
{
|
|
pSoldier->bWeaponMode = WM_NORMAL;
|
|
pSoldier->bDoBurst = FALSE;
|
|
pSoldier->bDoAutofire = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->bWeaponMode = WM_AUTOFIRE;
|
|
pSoldier->bDoBurst = TRUE;
|
|
pSoldier->bDoAutofire = TRUE;
|
|
}
|
|
}
|
|
// Lesh: end
|
|
|
|
|
|
pInSlot = &(pSoldier->inv[bPos]);
|
|
|
|
//we are placing an object, how we handle this depends on what is in the slot already
|
|
if (pInSlot->exists() == false)
|
|
{
|
|
//if the object in the slot does not exist it is easy
|
|
pObj->MoveThisObjectTo(*pInSlot, ALL_OBJECTS, pSoldier, bPos);
|
|
if (pObj->exists() == false)
|
|
{
|
|
// dropped everything
|
|
if (bPos == HANDPOS && Item[pInSlot->usItem].twohanded )
|
|
{
|
|
// We just performed a successful drop of a two-handed object into the
|
|
// main hand
|
|
if (pSoldier->inv[SECONDHANDPOS].exists() == true)
|
|
{
|
|
// swap what WAS in the second hand into the cursor
|
|
pSoldier->inv[SECONDHANDPOS].MoveThisObjectTo(*pObj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// replacement/reloading/merging/stacking
|
|
//try to reload first
|
|
switch (Item[pInSlot->usItem].usItemClass)
|
|
{
|
|
case IC_GUN:
|
|
if (Item[pObj->usItem].usItemClass == IC_AMMO)
|
|
{
|
|
if (Weapon[pInSlot->usItem].ubCalibre == Magazine[Item[pObj->usItem].ubClassIndex].ubCalibre)
|
|
{
|
|
//CHRISL: Work differently with ammo crates but only when not in combat
|
|
if(Item[pObj->usItem].ammocrate == TRUE)
|
|
{
|
|
if(!(gTacticalStatus.uiFlags & INCOMBAT))
|
|
{
|
|
INT16 magSize, ubShotsLeft;
|
|
OBJECTTYPE tempClip;
|
|
OBJECTTYPE tempStack;
|
|
bool clipCreated;
|
|
UINT32 newItem = 0;
|
|
INT32 pocket=-1;
|
|
UINT8 capacity=0;
|
|
UINT8 bLoop;
|
|
//find the ammo item we want to try and create
|
|
for(int loop = 0; loop < MAXITEMS; loop++)
|
|
{
|
|
if(Item[loop].usItemClass == IC_AMMO)
|
|
{
|
|
if(Magazine[Item[loop].ubClassIndex].ubCalibre == Weapon[pInSlot->usItem].ubCalibre && Magazine[Item[loop].ubClassIndex].ubAmmoType == Magazine[Item[pObj->usItem].ubClassIndex].ubAmmoType && Magazine[Item[loop].ubClassIndex].ubMagSize == GetMagSize(pInSlot))
|
|
newItem = loop;
|
|
}
|
|
}
|
|
//Create a stack of up to 5 "newItem" clips
|
|
tempStack.initialize();
|
|
clipCreated = false;
|
|
ubShotsLeft = (*pObj)[0]->data.ubShotsLeft;
|
|
for(UINT8 clip = 0; clip < 5; clip++)
|
|
{
|
|
magSize = GetMagSize(pInSlot);
|
|
if(ubShotsLeft < magSize)
|
|
magSize = ubShotsLeft;
|
|
if(CreateAmmo(newItem, &tempClip, magSize))
|
|
{
|
|
tempStack.AddObjectsToStack(tempClip, -1, pSoldier, NUM_INV_SLOTS, MAX_OBJECTS_PER_SLOT);
|
|
ubShotsLeft -= magSize;
|
|
clipCreated = true;
|
|
if(ubShotsLeft < 1)
|
|
break;
|
|
}
|
|
}
|
|
//Try to place the stack somewhere on the active merc
|
|
if(clipCreated == true)
|
|
{
|
|
clipCreated = false;
|
|
bLoop = tempStack.ubNumberOfObjects;
|
|
while(tempStack.ubNumberOfObjects > 0)
|
|
{
|
|
pocket = PickPocket(pSoldier, BIGPOCKSTART, SMALLPOCKFINAL, tempStack.usItem, bLoop, &capacity, -1);
|
|
if(pocket != -1)
|
|
{
|
|
pSoldier->inv[pocket].AddObjectsToStack(tempStack, bLoop, pSoldier, pocket);
|
|
}
|
|
else
|
|
{
|
|
bLoop--;
|
|
}
|
|
if(bLoop < 1)
|
|
break;
|
|
}
|
|
if(tempStack.ubNumberOfObjects < 1)
|
|
clipCreated = true;
|
|
else
|
|
{
|
|
//Try to place stack on ground
|
|
if(guiCurrentScreen == MAP_SCREEN && fShowMapInventoryPool == TRUE)
|
|
{
|
|
if(AutoPlaceObjectInInventoryStash(&tempStack, pSoldier->sGridNo))
|
|
clipCreated = true;
|
|
}
|
|
else
|
|
{
|
|
if(AddItemToPool(pSoldier->sGridNo, &tempStack, 1, pSoldier->pathing.bLevel, WORLD_ITEM_REACHABLE, -1))
|
|
{
|
|
NotifySoldiersToLookforItems( );
|
|
clipCreated = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(clipCreated == true)
|
|
{
|
|
(*pObj)[0]->data.ubShotsLeft = ubShotsLeft;
|
|
}
|
|
if((*pObj)[0]->data.ubShotsLeft < 1)
|
|
pObj->RemoveObjectsFromStack(1);
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMapInventoryErrorString[6] );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
return( ReloadGun( pSoldier, pInSlot, pObj ) );
|
|
}
|
|
}
|
|
break;
|
|
case IC_LAUNCHER:
|
|
if ( ValidLaunchable( pObj->usItem, pInSlot->usItem ) ) {
|
|
return( ReloadGun( pSoldier, pInSlot, pObj ) );
|
|
}
|
|
break;
|
|
}
|
|
//if we didn't reload, then we know we are stacking or swapping!
|
|
|
|
if (IsSlotASmallPocket(bPos) == true && FitsInSmallPocket(pObj) == false) {
|
|
//there is nothing we can do, just return
|
|
return FALSE;
|
|
}
|
|
|
|
// CHRISL: When holding ammo and clicking on an appropriate ammo crate, add ammo to crate
|
|
if(Item[pInSlot->usItem].ammocrate == TRUE && Item[pObj->usItem].usItemClass == IC_AMMO)
|
|
{
|
|
if(Magazine[Item[pInSlot->usItem].ubClassIndex].ubCalibre == Magazine[Item[pObj->usItem].ubClassIndex].ubCalibre &&
|
|
Magazine[Item[pInSlot->usItem].ubClassIndex].ubAmmoType == Magazine[Item[pObj->usItem].ubClassIndex].ubAmmoType)
|
|
{
|
|
UINT16 magSpace = Magazine[Item[pInSlot->usItem].ubClassIndex].ubMagSize-(*pInSlot)[0]->data.ubShotsLeft;
|
|
while(pObj->ubNumberOfObjects > 0)
|
|
{
|
|
if(magSpace >= (*pObj)[0]->data.ubShotsLeft)
|
|
{
|
|
magSpace -= (*pObj)[0]->data.ubShotsLeft;
|
|
(*pInSlot)[0]->data.ubShotsLeft += (*pObj)[0]->data.ubShotsLeft;
|
|
pObj->RemoveObjectsFromStack(1);
|
|
}
|
|
else
|
|
{
|
|
(*pObj)[0]->data.ubShotsLeft -= magSpace;
|
|
(*pInSlot)[0]->data.ubShotsLeft += magSpace;
|
|
break;
|
|
}
|
|
}
|
|
if(pObj->ubNumberOfObjects > 0)
|
|
return( FALSE );
|
|
else
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
// CHRISL:
|
|
ubSlotLimit = ItemSlotLimit( pObj, bPos, pSoldier );
|
|
if (ubSlotLimit == 0)
|
|
{
|
|
//we have tried to stack but the stack is full, or we have tried to swap but the slot is wrong
|
|
return( FreeUpSlotIfPossibleThenPlaceObject( pSoldier, bPos, pObj ) );
|
|
}
|
|
|
|
|
|
if ( pObj->usItem == pInSlot->usItem && ubSlotLimit > 1 && IsSlotAnLBESlot(bPos) == false )
|
|
{
|
|
//we have tried to stack, but remember we can't stack 2 LBEs into 1 LBE slot, they get swapped instead
|
|
pInSlot->AddObjectsToStack( *pObj, ALL_OBJECTS, pSoldier, bPos );
|
|
}
|
|
|
|
else if ( (Item[pObj->usItem].twohanded ) && (bPos == HANDPOS) )
|
|
{
|
|
if (pSoldier->inv[SECONDHANDPOS].exists() == true) {
|
|
// both pockets have something in them, so we can't swap
|
|
return( FALSE );
|
|
}
|
|
else {
|
|
//we swapped a 2 handed object into the main hand
|
|
SwapObjs( pObj, pInSlot );
|
|
}
|
|
}
|
|
|
|
else if (IsSlotAnLBESlot(bPos) == true && Item[pObj->usItem].usItemClass == IC_LBEGEAR)
|
|
{
|
|
/*CHRISL: If we're trying to swap LBE items between IC pockets, we have to be careful that items are moved
|
|
into active pockets or that an LBENODE is properly created.*/
|
|
if(pObj->HasAnyActiveLBEs(pSoldier) == false && !(_KeyDown(SHIFT))){
|
|
std::vector<INT8> LBESlots;
|
|
GetLBESlots(bPos, LBESlots);
|
|
MoveItemsToActivePockets(pSoldier, LBESlots, bPos, pObj);
|
|
}
|
|
pInSlot->MoveThisObjectTo(gTempObject, -1, pSoldier, bPos);
|
|
pObj->MoveThisObjectTo(*pInSlot, -1, pSoldier, bPos);
|
|
gTempObject.MoveThisObjectTo(*pObj, -1);
|
|
}
|
|
|
|
else if (ubSlotLimit < pObj->ubNumberOfObjects)
|
|
{
|
|
//not enough room, so we free up some space
|
|
return( FreeUpSlotIfPossibleThenPlaceObject( pSoldier, bPos, pObj ) );
|
|
}
|
|
|
|
else
|
|
{
|
|
//item fits here, swapping
|
|
SwapObjs( pObj, pInSlot );
|
|
}
|
|
}
|
|
|
|
// ATE: Put this in to see if we should update the robot, if we were given a controller...
|
|
if ( pSoldier->bTeam == gbPlayerNum && fObjectWasRobotRemote )
|
|
{
|
|
pSoldier->UpdateRobotControllerGivenController( );
|
|
}
|
|
|
|
ApplyEquipmentBonuses(pSoldier);
|
|
//Pulmu bugfix
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pInSlot->ubWeight = CalculateObjectWeight(pInSlot);
|
|
//Pulmu end
|
|
return( TRUE );
|
|
}
|
|
|
|
bool TryToStackInSlot(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, int bSlot)
|
|
{
|
|
// CHRISL: Use new ItemSlotLimit function if we're using the new inventory system
|
|
if (pSoldier->inv[bSlot].usItem == pObj->usItem && pSoldier->inv[bSlot].exists() == true)
|
|
{
|
|
if (pSoldier->inv[bSlot].ubNumberOfObjects < ItemSlotLimit( pObj, bSlot, pSoldier ) )
|
|
{
|
|
// NEW: If in SKI, don't auto-PLACE anything into a stackable slot that's currently hatched out! Such slots
|
|
// will disappear in their entirety if sold/moved, causing anything added through here to vanish also!
|
|
if( !( ( guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE ) && ShouldSoldierDisplayHatchOnItem( pSoldier->ubProfile, bSlot ) ) )
|
|
{
|
|
pSoldier->inv[bSlot].AddObjectsToStack(*pObj, -1, pSoldier, bSlot);
|
|
if (pObj->exists() == false) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool TryToPlaceInSlot(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewItem, int& bSlot, int endSlot)
|
|
{
|
|
//bSlot = FindEmptySlotWithin( pSoldier, bSlot, endSlot );
|
|
//CHRISL: If something already exists, we want to fail since we can't place an object in this slot
|
|
if (CanItemFitInPosition(pSoldier, pObj, bSlot, false) == false || pSoldier->inv[bSlot].exists() == true) {
|
|
//bSlot = endSlot;
|
|
return false;
|
|
}
|
|
|
|
if (bSlot == ITEM_NOT_FOUND) {
|
|
bSlot = endSlot;
|
|
return false;
|
|
}
|
|
|
|
if (bSlot == SECONDHANDPOS) {
|
|
if (pSoldier->inv[HANDPOS].exists() == true) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
PlaceObject( pSoldier, bSlot, pObj, fNewItem );
|
|
if (pObj->exists() == false) {
|
|
return( true );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool PlaceInAnySlot(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewItem, int bExcludeSlot)
|
|
{
|
|
//first, try to STACK the item
|
|
//try to STACK in any slot
|
|
for(int bSlot = BODYPOSSTART; bSlot < BIGPOCKSTART; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (FitsInSmallPocket(pObj) == true) {
|
|
//try to STACK in small pockets
|
|
for(int bSlot = SMALLPOCKSTART; bSlot < SMALLPOCKFINAL; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//try to STACK in big pockets, and possibly medium pockets
|
|
int bigPocketEnd = (UsingNewInventorySystem() == true) ? MEDPOCKFINAL : BIGPOCKFINAL;
|
|
for(int bSlot = BIGPOCKSTART; bSlot < bigPocketEnd; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//now try to PLACE
|
|
//try to PLACE in any body slot
|
|
for(int bSlot = BODYPOSSTART; bSlot < BIGPOCKSTART; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, BODYPOSFINAL) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if(UsingNewInventorySystem() == true)
|
|
{
|
|
//CHRISL: Rather then a simple slot search, use PickPocket to find the most appropriate pocket to use
|
|
INT32 sPocket=-1, mPocket=-1, lPocket=-1;
|
|
UINT8 sCapacity=0;
|
|
UINT8 mCapacity=0;
|
|
UINT8 lCapacity=0;
|
|
UINT8 capacity=0;
|
|
int bSlot;
|
|
//Start with active big pockets
|
|
sPocket=PickPocket(pSoldier, SMALLPOCKSTART, SMALLPOCKFINAL, pObj->usItem, pObj->ubNumberOfObjects, &sCapacity, bExcludeSlot);
|
|
//Next search active medium pockets
|
|
mPocket=PickPocket(pSoldier, MEDPOCKSTART, MEDPOCKFINAL, pObj->usItem, pObj->ubNumberOfObjects, &mCapacity, bExcludeSlot);
|
|
//Lastly search active small pockets
|
|
lPocket=PickPocket(pSoldier, BIGPOCKSTART, BIGPOCKFINAL, pObj->usItem, pObj->ubNumberOfObjects, &lCapacity, bExcludeSlot);
|
|
//Finally, compare the three pockets we've found and return the pocket that is most logical to use
|
|
capacity = min(sCapacity, mCapacity);
|
|
capacity = min(lCapacity, capacity);
|
|
if(capacity == 254) { //no pocket found
|
|
return false;
|
|
}
|
|
else if(capacity == sCapacity) {
|
|
bSlot = sPocket;
|
|
}
|
|
else if(capacity == mCapacity) {
|
|
bSlot = mPocket;
|
|
}
|
|
else if(capacity == lCapacity) {
|
|
bSlot = lPocket;
|
|
}
|
|
if(TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, NUM_INV_SLOTS) == true)
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (FitsInSmallPocket(pObj) == true) {
|
|
//try to PLACE in small pockets
|
|
for(int bSlot = SMALLPOCKSTART; bSlot < SMALLPOCKFINAL; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, NUM_INV_SLOTS) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//try to PLACE in big pockets, and possibly medium pockets
|
|
for(int bSlot = BIGPOCKSTART; bSlot < bigPocketEnd; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, bigPocketEnd) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool PlaceInAnyPocket(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewItem, int bExcludeSlot)
|
|
{
|
|
//first, try to STACK the item
|
|
if (FitsInSmallPocket(pObj) == true) {
|
|
//try to STACK in small pockets
|
|
for(int bSlot = SMALLPOCKSTART; bSlot < SMALLPOCKFINAL; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//try to STACK in big pockets, and possibly medium pockets
|
|
int bigPocketEnd = (UsingNewInventorySystem() == true) ? MEDPOCKFINAL : BIGPOCKFINAL;
|
|
for(int bSlot = BIGPOCKSTART; bSlot < bigPocketEnd; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
if (FitsInSmallPocket(pObj) == true) {
|
|
//try to PLACE in small pockets
|
|
for(int bSlot = SMALLPOCKSTART; bSlot < SMALLPOCKFINAL; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, NUM_INV_SLOTS) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
//try to PLACE in big pockets, and possibly medium pockets
|
|
for(int bSlot = BIGPOCKSTART; bSlot < bigPocketEnd; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, bigPocketEnd) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool PlaceInAnyBigOrMediumPocket(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewItem, int bExcludeSlot)
|
|
{
|
|
//a special note, although some items do not fit in small pockets, and under the old system are restricted to big pockets,
|
|
//under the new system they are intended to fit in medium pockets, if the item size and the pocket agree
|
|
//An example would be a SMG fitting in a gun holster, which is medium.
|
|
int bigPocketEnd = (UsingNewInventorySystem() == true) ? MEDPOCKFINAL : BIGPOCKFINAL;
|
|
//first, try to STACK the item
|
|
for(int bSlot = BIGPOCKSTART; bSlot < bigPocketEnd; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//now try to PLACE
|
|
for(int bSlot = BIGPOCKSTART; bSlot < bigPocketEnd; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, bigPocketEnd) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool PlaceInAnySmallPocket(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewItem, int bExcludeSlot)
|
|
{
|
|
if (FitsInSmallPocket(pObj) == false) {
|
|
return false;
|
|
}
|
|
|
|
//first, try to STACK the item
|
|
for(int bSlot = SMALLPOCKSTART; bSlot < SMALLPOCKFINAL; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToStackInSlot(pSoldier, pObj, bSlot) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//try to PLACE in small pockets
|
|
for(int bSlot = SMALLPOCKSTART; bSlot < SMALLPOCKFINAL; bSlot++) {
|
|
if (bSlot != bExcludeSlot && TryToPlaceInSlot(pSoldier, pObj, fNewItem, bSlot, NUM_INV_SLOTS) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// CHRISL: Function needed for LBENODE
|
|
BOOLEAN AutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNewItem, INT8 bExcludeSlot )
|
|
{
|
|
INVTYPE * pItem;
|
|
UINT8 packCombo, backCombo;
|
|
|
|
// statuses of extra objects would be 0 if the # exceeds the maximum
|
|
//Assert( pObj->ubNumberOfObjects <= MAX_OBJECTS_PER_SLOT);
|
|
|
|
//Pulmu bugfix
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pObj->ubWeight = CalculateObjectWeight( pObj);
|
|
pItem = &(Item[pObj->usItem]);
|
|
int lbeClass;
|
|
|
|
// Overrides to the standard system: put guns in hand, armour on body (if slot empty)
|
|
switch (pItem->usItemClass)
|
|
{
|
|
case IC_GUN:
|
|
case IC_THROWING_KNIFE:
|
|
case IC_BLADE:
|
|
case IC_LAUNCHER:
|
|
case IC_BOMB:
|
|
case IC_GRENADE:
|
|
if (pSoldier->inv[HANDPOS].exists() == false)
|
|
{
|
|
// put the one-handed weapon in the guy's hand...
|
|
PlaceObject( pSoldier, HANDPOS, pObj, fNewItem );
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else if ( !(Item[pSoldier->inv[HANDPOS].usItem].twohanded ) && pSoldier->inv[SECONDHANDPOS].exists() == false)
|
|
{
|
|
// put the one-handed weapon in the guy's 2nd hand...
|
|
PlaceObject( pSoldier, SECONDHANDPOS, pObj, fNewItem );
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
// two-handed objects are best handled in the main loop for large objects,
|
|
// which checks the hands first anyhow
|
|
//CHRISL: New switch. Place items into Gunsling or Knife pocket is using NewInv, item is appropriate, and we
|
|
// didn't manage to place in hands.
|
|
if(UsingNewInventorySystem() == true)
|
|
{
|
|
switch (pItem->usItemClass)
|
|
{
|
|
case IC_GUN:
|
|
if(pSoldier->inv[GUNSLINGPOCKPOS].exists() == false) // Long Gun use Gun Sling
|
|
{
|
|
PlaceObject( pSoldier, GUNSLINGPOCKPOS, pObj, fNewItem );
|
|
if (pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
break;
|
|
case IC_THROWING_KNIFE:
|
|
case IC_BLADE:
|
|
if(pSoldier->inv[KNIFEPOCKPOS].exists() == false) // Knife
|
|
{
|
|
PlaceObject( pSoldier, KNIFEPOCKPOS, pObj, fNewItem );
|
|
if (pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case IC_ARMOUR:
|
|
switch (Armour[Item[pObj->usItem].ubClassIndex].ubArmourClass)
|
|
{
|
|
case ARMOURCLASS_VEST:
|
|
if (pSoldier->inv[VESTPOS].exists() == false)
|
|
{
|
|
// put on the armour!
|
|
PlaceObject( pSoldier, VESTPOS, pObj, fNewItem );
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
break;
|
|
case ARMOURCLASS_LEGGINGS:
|
|
/* CHRISL: If we're wearing leg protectors and pick up leggings, we want to leggings to override.
|
|
This is only an issue during merc hiring when leggings will often be placed after leg protectors.
|
|
However, this isn't as big an issue at this point because of the redesigns in the profile item sorting
|
|
functions.*/
|
|
if(Item[pSoldier->inv[LEGPOS].usItem].attachment)
|
|
{
|
|
SwapObjs(pSoldier, LEGPOS, pObj, TRUE);
|
|
pSoldier->inv[LEGPOS].AttachObject(pSoldier, pObj, FALSE);
|
|
}
|
|
if (pSoldier->inv[LEGPOS].exists() == false)
|
|
{
|
|
// put on the armour!
|
|
PlaceObject( pSoldier, LEGPOS, pObj, fNewItem );
|
|
}
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
break;
|
|
case ARMOURCLASS_HELMET:
|
|
if (pSoldier->inv[HELMETPOS].exists() == false)
|
|
{
|
|
// put on the armour!
|
|
PlaceObject( pSoldier, HELMETPOS, pObj, fNewItem );
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// otherwise stuff it in a slot somewhere
|
|
break;
|
|
case IC_FACE:
|
|
if ( (pSoldier->inv[HEAD1POS].exists() == false) && CompatibleFaceItem( pObj->usItem, pSoldier->inv[HEAD2POS].usItem ) )
|
|
{
|
|
PlaceObject( pSoldier, HEAD1POS, pObj, fNewItem );
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else if ( (pSoldier->inv[HEAD2POS].exists() == false) && CompatibleFaceItem( pObj->usItem, pSoldier->inv[HEAD1POS].usItem ) )
|
|
{
|
|
PlaceObject( pSoldier, HEAD2POS, pObj, fNewItem );
|
|
if ( pObj->exists() == false )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
break;
|
|
// CHRISL:
|
|
case IC_LBEGEAR:
|
|
if(UsingNewInventorySystem() == false) {
|
|
break;
|
|
}
|
|
lbeClass = LoadBearingEquipment[pItem->ubClassIndex].lbeClass;
|
|
if(lbeClass == THIGH_PACK) // Thigh pack
|
|
{
|
|
if (pSoldier->inv[LTHIGHPOCKPOS].exists() == false) {
|
|
PlaceObject( pSoldier, LTHIGHPOCKPOS, pObj, fNewItem );
|
|
if(pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
if (pSoldier->inv[RTHIGHPOCKPOS].exists() == false) {
|
|
PlaceObject( pSoldier, RTHIGHPOCKPOS, pObj, fNewItem );
|
|
if(pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else if(pSoldier->inv[VESTPOCKPOS].exists() == false && lbeClass == VEST_PACK) // Vest pack
|
|
{
|
|
PlaceObject( pSoldier, VESTPOCKPOS, pObj, fNewItem );
|
|
if(pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
else if(pSoldier->inv[CPACKPOCKPOS].exists() == false && lbeClass == COMBAT_PACK) // Combat pack
|
|
{
|
|
packCombo = LoadBearingEquipment[pItem->ubClassIndex].lbeCombo;
|
|
backCombo = LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo;
|
|
if((pSoldier->inv[BPACKPOCKPOS].exists() == true && packCombo != 0 && backCombo == packCombo) || pSoldier->inv[BPACKPOCKPOS].exists() == false)
|
|
{
|
|
PlaceObject( pSoldier, CPACKPOCKPOS, pObj, fNewItem );
|
|
if(pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else if(pSoldier->inv[BPACKPOCKPOS].exists() == false && lbeClass == BACKPACK) // Backpack
|
|
{
|
|
//CHRISL: We're no longer restricting backpacks and gunslings from being used together
|
|
//if(pSoldier->inv[GUNSLINGPOCKPOS].exists() == false)
|
|
//{
|
|
packCombo = LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo;
|
|
backCombo = LoadBearingEquipment[pItem->ubClassIndex].lbeCombo;
|
|
if((pSoldier->inv[CPACKPOCKPOS].exists() == true && backCombo != 0 && backCombo == packCombo) || pSoldier->inv[CPACKPOCKPOS].exists() == false)
|
|
{
|
|
PlaceObject( pSoldier, BPACKPOCKPOS, pObj, fNewItem );
|
|
pSoldier->flags.DropPackFlag = FALSE;
|
|
pSoldier->flags.ZipperFlag = FALSE;
|
|
RenderBackpackButtons(0); /* CHRISL: Needed for new inventory backpack buttons */
|
|
if(pObj->exists() == false)
|
|
return( TRUE );
|
|
}
|
|
//}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (PlaceInAnySlot(pSoldier, pObj, (fNewItem == TRUE), bExcludeSlot) == true) {
|
|
return TRUE;
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN RemoveKeyFromSlot( SOLDIERTYPE * pSoldier, INT8 bKeyRingPosition, OBJECTTYPE * pObj )
|
|
{
|
|
UINT8 ubItem = 0;
|
|
|
|
CHECKF( pObj );
|
|
|
|
if( ( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber == 0 ) || ( pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID == INVALID_KEY_NUMBER ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
// create an object
|
|
ubItem = pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID;
|
|
|
|
if( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber > 1 )
|
|
{
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber--;
|
|
}
|
|
else
|
|
{
|
|
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber = 0;
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID = INVALID_KEY_NUMBER;
|
|
}
|
|
|
|
return( CreateKeyObject( pObj, 1, ubItem ) );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN RemoveKeysFromSlot( SOLDIERTYPE * pSoldier, INT8 bKeyRingPosition, UINT8 ubNumberOfKeys ,OBJECTTYPE * pObj )
|
|
{
|
|
UINT8 ubItems = 0;
|
|
|
|
CHECKF( pObj );
|
|
|
|
|
|
if( ( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber == 0 ) || ( pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID == INVALID_KEY_NUMBER ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
//*pObj = pSoldier->inv[bPos];
|
|
|
|
if( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber < ubNumberOfKeys )
|
|
{
|
|
ubNumberOfKeys = pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber;
|
|
}
|
|
|
|
|
|
ubItems = pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID;
|
|
if( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber - ubNumberOfKeys > 0 )
|
|
{
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber--;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber = 0;
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID = INVALID_KEY_NUMBER;
|
|
}
|
|
|
|
// create an object
|
|
return( CreateKeyObject( pObj, ubNumberOfKeys, ubItems ) );
|
|
}
|
|
}
|
|
|
|
// return number added
|
|
UINT8 AddKeysToSlot( SOLDIERTYPE * pSoldier, INT8 bKeyRingPosition, OBJECTTYPE * pObj )
|
|
{
|
|
UINT8 ubNumberNotAdded = 0;
|
|
|
|
if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC ) // redundant but what the hey
|
|
{
|
|
if ( KeyTable[ (*pObj)[0]->data.key.ubKeyID ].usDateFound == 0 )
|
|
{
|
|
KeyTable[ (*pObj)[0]->data.key.ubKeyID ].usDateFound = (UINT16) GetWorldDay();
|
|
KeyTable[ (*pObj)[0]->data.key.ubKeyID ].usSectorFound = SECTOR( pSoldier->sSectorX, pSoldier->sSectorY );
|
|
}
|
|
}
|
|
|
|
// check if we are going to far
|
|
if ( ( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber + pObj->ubNumberOfObjects ) > ItemSlotLimit(pObj, STACK_SIZE_LIMIT) )
|
|
{
|
|
// only take what we can
|
|
ubNumberNotAdded = pObj->ubNumberOfObjects - ( ItemSlotLimit(pObj, STACK_SIZE_LIMIT) - pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber );
|
|
|
|
// set to max
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber = ItemSlotLimit(pObj, STACK_SIZE_LIMIT);
|
|
|
|
if( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber == 0 )
|
|
{
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID = (*pObj)[0]->data.key.ubKeyID;
|
|
}
|
|
|
|
// return number used
|
|
return( pObj->ubNumberOfObjects - ubNumberNotAdded );
|
|
}
|
|
else
|
|
{
|
|
// check
|
|
if( pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber == 0 )
|
|
{
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID = (*pObj)[0]->data.key.ubKeyID;
|
|
}
|
|
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber += pObj->ubNumberOfObjects;
|
|
}
|
|
|
|
return( pObj->ubNumberOfObjects );
|
|
}
|
|
|
|
UINT8 SwapKeysToSlot( SOLDIERTYPE * pSoldier, INT8 bKeyRingPosition, OBJECTTYPE * pObj )
|
|
{
|
|
// swap keys in keyring slot and keys in pocket
|
|
// create temp object to hold keys currently in key ring slot
|
|
CreateKeyObject( &gTempObject, pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber, pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID );
|
|
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubNumber = pObj->ubNumberOfObjects;
|
|
pSoldier->pKeyRing[ bKeyRingPosition ].ubKeyID = (*pObj)[0]->data.key.ubKeyID;
|
|
|
|
// swap params?
|
|
*pObj = gTempObject;
|
|
|
|
return( 1 );
|
|
}
|
|
|
|
|
|
BOOLEAN CreateKeyObject( OBJECTTYPE * pObj , UINT8 ubNumberOfKeys, UINT8 ubKeyID )
|
|
{
|
|
BOOLEAN fRet;
|
|
|
|
pObj->initialize();
|
|
fRet = CreateItems( (UINT16) (FIRST_KEY + LockTable[ ubKeyID ].usKeyItem), 100, ubNumberOfKeys, pObj );
|
|
if (fRet)
|
|
{
|
|
(*pObj)[0]->data.key.ubKeyID = ubKeyID;
|
|
}
|
|
//fRet = CreateItems( (UINT16)(ubKeyIdValue + FIRST_KEY) , 100, ubNumberOfKeys, pObj )
|
|
//return( );
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
BOOLEAN AllocateObject( OBJECTTYPE **pObj )
|
|
{
|
|
// create a key object
|
|
*pObj = new OBJECTTYPE;
|
|
Assert( pObj );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN DeleteKeyObject( OBJECTTYPE * pObj )
|
|
{
|
|
if( pObj == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// free up space
|
|
delete( pObj );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
UINT16 TotalPoints( OBJECTTYPE * pObj )
|
|
{
|
|
UINT16 usPoints = 0;
|
|
UINT8 ubLoop;
|
|
|
|
for (ubLoop = 0; ubLoop < pObj->ubNumberOfObjects; ubLoop++)
|
|
{
|
|
usPoints += (*pObj)[ubLoop]->data.objectStatus;
|
|
}
|
|
return( usPoints );
|
|
}
|
|
|
|
UINT16 UseKitPoints( OBJECTTYPE * pObj, UINT16 usPoints, SOLDIERTYPE *pSoldier )
|
|
{
|
|
// start consuming from the last kit in, so we end up with fewer fuller kits rather than
|
|
// lots of half-empty ones.
|
|
INT8 bLoop;
|
|
UINT16 usOriginalPoints = usPoints;
|
|
|
|
for (bLoop = pObj->ubNumberOfObjects - 1; bLoop >= 0; bLoop--)
|
|
{
|
|
if (Item[pObj->usItem].percentstatusdrainreduction > 0 && ((usPoints * (100 - Item[pObj->usItem].percentstatusdrainreduction))/100) < (*pObj)[bLoop]->data.objectStatus )
|
|
{
|
|
(*pObj)[bLoop]->data.objectStatus -= (INT8) ((usPoints * (100 - Item[pObj->usItem].percentstatusdrainreduction ) )/100);
|
|
return( usOriginalPoints );
|
|
}
|
|
else if (usPoints < (UINT16) (*pObj)[bLoop]->data.objectStatus)
|
|
{
|
|
(*pObj)[bLoop]->data.objectStatus -= (INT8) usPoints;
|
|
return( usOriginalPoints );
|
|
}
|
|
else
|
|
{
|
|
// consume this kit totally
|
|
usPoints -= (*pObj)[bLoop]->data.objectStatus;
|
|
(*pObj)[bLoop]->data.objectStatus = 0;
|
|
|
|
pObj->ubNumberOfObjects--;
|
|
}
|
|
}
|
|
|
|
// check if pocket/hand emptied..update inventory, then update panel
|
|
if( pObj->exists() == false )
|
|
{
|
|
// Delete object
|
|
DeleteObj( pObj );
|
|
|
|
// dirty interface panel
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
|
|
return( usOriginalPoints - usPoints );
|
|
}
|
|
|
|
#ifdef PATHAI_VISIBLE_DEBUG
|
|
|
|
extern BOOLEAN gfDrawPathPoints;
|
|
|
|
#else
|
|
|
|
#ifdef AI_TIMING_TESTS
|
|
extern UINT32 guiGreenTimeTotal, guiYellowTimeTotal, guiRedTimeTotal, guiBlackTimeTotal;
|
|
extern UINT32 guiGreenCounter, guiYellowCounter, guiRedCounter, guiBlackCounter;
|
|
extern UINT32 guiRedSeekTimeTotal, guiRedHelpTimeTotal, guiRedHideTimeTotal;
|
|
extern UINT32 guiRedSeekCounter, guiRedHelpCounter; guiRedHideCounter;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
UINT16 MagazineClassIndexToItemType(UINT16 usMagIndex)
|
|
{
|
|
UINT16 usLoop;
|
|
|
|
// Note: if any ammo items in the item table are separated from the main group,
|
|
// this function will have to be rewritten to scan the item table for an item
|
|
// with item class ammo, which has class index usMagIndex
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "MagazineClassIndexToItemType" ) );
|
|
for (usLoop = FIRST_AMMO; usLoop < MAXITEMS; usLoop++)
|
|
{
|
|
if ( Item[usLoop].usItemClass == 0 )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "MagazineClassIndexToItemType: breaking at index %d", usLoop ) );
|
|
break;
|
|
}
|
|
if (Item[usLoop].ubClassIndex == usMagIndex && Item[usLoop].usItemClass == IC_AMMO )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "MagazineClassIndexToItemType: return %d", usLoop ) );
|
|
return( usLoop );
|
|
}
|
|
}
|
|
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "MagazineClassIndexToItemType: return none, got to %d", usLoop ) );
|
|
return(NONE);
|
|
}
|
|
|
|
|
|
UINT16 DefaultMagazine( UINT16 usItem )
|
|
{
|
|
WEAPONTYPE * pWeapon;
|
|
UINT16 usLoop;
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DefaultMagazine: item = %d",usItem));
|
|
if (!(Item[usItem].usItemClass & IC_GUN))
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
pWeapon = &(Weapon[usItem]);
|
|
usLoop = 0;
|
|
while ( Magazine[usLoop].ubCalibre != NOAMMO )
|
|
{
|
|
if (Magazine[usLoop].ubCalibre == pWeapon->ubCalibre &&
|
|
Magazine[usLoop].ubMagSize == pWeapon->ubMagSize &&
|
|
AmmoTypes[ Magazine[usLoop].ubAmmoType ].standardIssue )
|
|
{
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DefaultMagazine: found at index %d",usLoop));
|
|
return(MagazineClassIndexToItemType(usLoop));
|
|
}
|
|
|
|
usLoop++;
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DefaultMagazine: can't find any"));
|
|
return( 0 );
|
|
}
|
|
|
|
UINT16 FindReplacementMagazine( UINT8 ubCalibre, UINT16 ubMagSize, UINT8 ubAmmoType )
|
|
{
|
|
UINT16 usLoop;
|
|
UINT16 usDefault;
|
|
|
|
usLoop = 0;
|
|
usDefault = NOTHING;
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FindReplacementMagazine: calibre = %d, Mag size = %d, ammo type = %d",ubCalibre,ubMagSize,ubAmmoType));
|
|
|
|
while ( Magazine[usLoop].ubCalibre != NOAMMO )
|
|
{
|
|
if (Magazine[usLoop].ubCalibre == ubCalibre &&
|
|
Magazine[usLoop].ubMagSize == ubMagSize )
|
|
{
|
|
if ( Magazine[usLoop].ubAmmoType == ubAmmoType )
|
|
{
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FindReplacementMagazine: returning item = %d",MagazineClassIndexToItemType( usLoop )));
|
|
return( MagazineClassIndexToItemType( usLoop ) );
|
|
}
|
|
else if ( usDefault == NOTHING )
|
|
{
|
|
// store this one to use if all else fails
|
|
usDefault = MagazineClassIndexToItemType( usLoop );
|
|
}
|
|
|
|
}
|
|
|
|
usLoop++;
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FindReplacementMagazine: returning default item = %d",usDefault));
|
|
return( usDefault );
|
|
|
|
}
|
|
|
|
UINT16 FindReplacementMagazineIfNecessary( UINT16 usOldGun, UINT16 usOldAmmo, UINT16 usNewGun )
|
|
{
|
|
UINT16 usNewAmmo = NOTHING;
|
|
|
|
if ( (Magazine[ Item[ usOldAmmo ].ubClassIndex ].ubCalibre == Weapon[ usOldGun ].ubCalibre) &&
|
|
(Magazine[ Item[ usOldAmmo ].ubClassIndex ].ubMagSize == Weapon[ usOldGun ].ubMagSize) )
|
|
{
|
|
// must replace this!
|
|
usNewAmmo = FindReplacementMagazine( Weapon[ usNewGun ].ubCalibre, Weapon[ usNewGun ].ubMagSize, Magazine[ Item[ usOldAmmo ].ubClassIndex ].ubAmmoType );
|
|
}
|
|
|
|
return( usNewAmmo );
|
|
}
|
|
|
|
// increase this if any gun can have more types that this
|
|
#define MAX_AMMO_TYPES_PER_GUN 24 // MADD MARKER
|
|
|
|
UINT16 RandomMagazine( UINT16 usItem, UINT8 ubPercentStandard, UINT8 maxCoolness )
|
|
{
|
|
// Note: if any ammo items in the item table are separated from the main group,
|
|
// this function will have to be rewritten to scan the item table for an item
|
|
// with item class ammo, which has class index ubLoop
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("RandomMagazine (by index)"));
|
|
|
|
WEAPONTYPE * pWeapon;
|
|
UINT16 usLoop;
|
|
UINT16 loopItem;
|
|
UINT16 usPossibleMagIndex[ MAX_AMMO_TYPES_PER_GUN ];
|
|
UINT16 usPossibleMagCnt = 0;
|
|
UINT8 ubMagChosen;
|
|
|
|
if (!(Item[usItem].usItemClass & IC_GUN))
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
pWeapon = &(Weapon[usItem]);
|
|
|
|
// find & store all possible mag types that fit this gun
|
|
usLoop = 0;
|
|
while ( Magazine[ usLoop ].ubCalibre != NOAMMO )
|
|
{
|
|
loopItem = MagazineClassIndexToItemType(usLoop);
|
|
|
|
if (Magazine[usLoop].ubCalibre == pWeapon->ubCalibre &&
|
|
Magazine[usLoop].ubMagSize == pWeapon->ubMagSize && ItemIsLegal(loopItem)
|
|
&& maxCoolness >= Item[loopItem].ubCoolness )
|
|
{
|
|
// store it! (make sure array is big enough)
|
|
Assert(usPossibleMagCnt < MAX_AMMO_TYPES_PER_GUN);
|
|
// Madd: check to see if allowed by army
|
|
if ( gArmyItemChoices[ENEMYAMMOTYPES].ubChoices > 0 )
|
|
{
|
|
for ( int i=0;i<gArmyItemChoices[ENEMYAMMOTYPES].ubChoices;i++ )
|
|
{
|
|
if ( gArmyItemChoices[ENEMYAMMOTYPES].bItemNo[i] == Magazine[usLoop].ubAmmoType )
|
|
{
|
|
usPossibleMagIndex[usPossibleMagCnt++] = usLoop;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
usPossibleMagIndex[usPossibleMagCnt++] = usLoop;
|
|
}
|
|
}
|
|
|
|
usLoop++;
|
|
}
|
|
|
|
// no matches?
|
|
if (usPossibleMagCnt == 0)
|
|
{
|
|
return( 0 );
|
|
}
|
|
else
|
|
// only one match?
|
|
if (usPossibleMagCnt == 1)
|
|
{
|
|
// use that, no choice
|
|
return(MagazineClassIndexToItemType( usPossibleMagIndex[ 0 ] ));
|
|
}
|
|
else // multiple choices
|
|
{
|
|
// Pick one at random, using supplied probability to pick the default
|
|
if (Random(100) < ubPercentStandard)
|
|
{
|
|
ubMagChosen = 0;
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("RandomMagazine: ubMagChosen = %d",ubMagChosen ));
|
|
return( DefaultMagazine(usItem) );
|
|
}
|
|
else
|
|
{
|
|
// pick a non-standard type instead
|
|
ubMagChosen = ( UINT8 ) (1 + Random(( UINT32 ) ( usPossibleMagCnt - 1 )));
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("RandomMagazine: ubMagChosen = %d",ubMagChosen ));
|
|
return( MagazineClassIndexToItemType(usPossibleMagIndex[ ubMagChosen ] ) );
|
|
}
|
|
}
|
|
|
|
UINT16 RandomMagazine( OBJECTTYPE * pGun, UINT8 ubPercentStandard, UINT8 maxCoolness )
|
|
{
|
|
// Note: if any ammo items in the item table are separated from the main group,
|
|
// this function will have to be rewritten to scan the item table for an item
|
|
// with item class ammo, which has class index ubLoop
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("RandomMagazine"));
|
|
|
|
WEAPONTYPE * pWeapon;
|
|
UINT16 usLoop;
|
|
UINT16 loopItem;
|
|
UINT16 usPossibleMagIndex[ MAX_AMMO_TYPES_PER_GUN ];
|
|
UINT16 usPossibleMagCnt = 0;
|
|
UINT8 ubMagChosen;
|
|
|
|
if (!(Item[pGun->usItem].usItemClass & IC_GUN))
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
pWeapon = &(Weapon[pGun->usItem]);
|
|
|
|
// find & store all possible mag types that fit this gun
|
|
usLoop = 0;
|
|
while ( Magazine[ usLoop ].ubCalibre != NOAMMO )
|
|
{
|
|
loopItem = MagazineClassIndexToItemType(usLoop);
|
|
|
|
if (Magazine[usLoop].ubCalibre == pWeapon->ubCalibre &&
|
|
Magazine[usLoop].ubMagSize == GetMagSize(pGun) && ItemIsLegal(loopItem)
|
|
&& maxCoolness >= Item[loopItem].ubCoolness )
|
|
{
|
|
// store it! (make sure array is big enough)
|
|
Assert(usPossibleMagCnt < MAX_AMMO_TYPES_PER_GUN);
|
|
// Madd: check to see if allowed by army
|
|
if ( gArmyItemChoices[ENEMYAMMOTYPES].ubChoices > 0 )
|
|
{
|
|
for ( int i=0;i<gArmyItemChoices[ENEMYAMMOTYPES].ubChoices;i++ )
|
|
{
|
|
if ( gArmyItemChoices[ENEMYAMMOTYPES].bItemNo[i] == Magazine[usLoop].ubAmmoType )
|
|
{
|
|
usPossibleMagIndex[usPossibleMagCnt++] = usLoop;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
usPossibleMagIndex[usPossibleMagCnt++] = usLoop;
|
|
}
|
|
}
|
|
|
|
usLoop++;
|
|
}
|
|
|
|
// no matches?
|
|
if (usPossibleMagCnt == 0)
|
|
{
|
|
return( 0 );
|
|
}
|
|
else
|
|
// only one match?
|
|
if (usPossibleMagCnt == 1)
|
|
{
|
|
// use that, no choice
|
|
return(MagazineClassIndexToItemType(usPossibleMagIndex[ 0 ] ));
|
|
}
|
|
else // multiple choices
|
|
{
|
|
// Pick one at random, using supplied probability to pick the default
|
|
if (Random(100) < ubPercentStandard)
|
|
{
|
|
ubMagChosen = 0;
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("RandomMagazine: ubMagChosen = %d",ubMagChosen ));
|
|
return( DefaultMagazine(pGun->usItem) );
|
|
}
|
|
else
|
|
{
|
|
// pick a non-standard type instead
|
|
ubMagChosen = ( UINT8 ) (1 + Random(( UINT32 ) ( usPossibleMagCnt - 1 )));
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("RandomMagazine: ubMagChosen = %d",ubMagChosen ));
|
|
return( MagazineClassIndexToItemType(usPossibleMagIndex[ ubMagChosen ] ) );
|
|
}
|
|
}
|
|
|
|
BOOLEAN CreateGun( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj )
|
|
{
|
|
UINT16 usAmmo;
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateGun: usItem = %d",usItem));
|
|
|
|
|
|
Assert( pObj != NULL);
|
|
if ( pObj == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pObj->initialize();
|
|
pObj->usItem = usItem;
|
|
pObj->ubNumberOfObjects = 1;
|
|
//pObj->objectStack.resize(1);//not necessary due to init, here for code commenting
|
|
StackedObjectData* pStackedObject = (*pObj)[0];
|
|
pStackedObject->data.gun.bGunStatus = bStatus;
|
|
pStackedObject->data.ubImprintID = NO_PROFILE;
|
|
|
|
if (Weapon[ usItem ].ubWeaponClass == MONSTERCLASS)
|
|
{
|
|
pStackedObject->data.gun.ubGunShotsLeft = GetMagSize(pObj);
|
|
pStackedObject->data.gun.ubGunAmmoType = AMMO_MONSTER;
|
|
pStackedObject->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; // 0verhaul: Monsters don't have to reload!
|
|
}
|
|
else if ( EXPLOSIVE_GUN( usItem ) )
|
|
{
|
|
if ( Item[usItem].singleshotrocketlauncher )
|
|
{
|
|
pStackedObject->data.gun.ubGunShotsLeft = 1;
|
|
}
|
|
else
|
|
{
|
|
// cannon
|
|
pStackedObject->data.gun.ubGunShotsLeft = 0;
|
|
}
|
|
pStackedObject->data.gun.bGunAmmoStatus = 100;
|
|
pStackedObject->data.gun.ubGunAmmoType = 0;
|
|
}
|
|
else
|
|
{
|
|
usAmmo = DefaultMagazine( usItem );
|
|
//CHRISL: Why do we have an assert here when the very next condition says to return a FALSE if usAmmo is 0?
|
|
//Assert( usAmmo != 0 );
|
|
if (usAmmo == 0)
|
|
{
|
|
// item's calibre & mag size not found in magazine list!
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
pStackedObject->data.gun.usGunAmmoItem = usAmmo;
|
|
pStackedObject->data.gun.ubGunAmmoType = Magazine[ Item[ usAmmo ].ubClassIndex].ubAmmoType;
|
|
pStackedObject->data.gun.bGunAmmoStatus = 100;
|
|
pStackedObject->data.gun.ubGunShotsLeft = Magazine[ Item[ usAmmo ].ubClassIndex ].ubMagSize;
|
|
pStackedObject->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; // Madd: new guns should have cartridge in chamber
|
|
}
|
|
}
|
|
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pObj->ubWeight = CalculateObjectWeight( pObj );
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateGun: Done"));
|
|
// succesful
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN CreateAmmo( UINT16 usItem, OBJECTTYPE * pObj, INT16 ubShotsLeft )
|
|
{
|
|
if (pObj == NULL)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
pObj->initialize();
|
|
pObj->usItem = usItem;
|
|
pObj->ubNumberOfObjects = 1;
|
|
//pObj->objectStack.resize(1);//not necessary due to init, here for code commenting
|
|
if (ubShotsLeft < 0) {
|
|
(*pObj)[0]->data.ubShotsLeft = Magazine[ Item[usItem].ubClassIndex ].ubMagSize;
|
|
}
|
|
else {
|
|
(*pObj)[0]->data.ubShotsLeft = (UINT8)ubShotsLeft;
|
|
}
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pObj->ubWeight = CalculateObjectWeight( pObj );
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateAmmo: done"));
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN CreateItem( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj )
|
|
{
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateItem: usItem = %d",usItem));
|
|
BOOLEAN fRet;
|
|
|
|
if (usItem >= MAXITEMS)
|
|
{
|
|
DebugBreakpoint();
|
|
return( FALSE );
|
|
}
|
|
if (Item[ usItem ].usItemClass == IC_GUN)
|
|
{
|
|
fRet = CreateGun( usItem, bStatus, pObj );
|
|
}
|
|
else if (Item[ usItem ].usItemClass == IC_AMMO)
|
|
{
|
|
fRet = CreateAmmo( usItem, pObj );
|
|
}
|
|
else
|
|
{
|
|
pObj->initialize();
|
|
pObj->usItem = usItem;
|
|
pObj->ubNumberOfObjects = 1;
|
|
//pObj->objectStack.resize(1);//not necessary due to init, here for code commenting
|
|
if (usItem == MONEY || Item[usItem].usItemClass == IC_MONEY )
|
|
{
|
|
// special case... always set status to 100 when creating
|
|
// and use status value to determine amount!
|
|
(*pObj)[0]->data.objectStatus = 100;
|
|
(*pObj)[0]->data.money.uiMoneyAmount = bStatus * 50;
|
|
}
|
|
else
|
|
{
|
|
(*pObj)[0]->data.objectStatus = bStatus;
|
|
}
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pObj->ubWeight = CalculateObjectWeight( pObj );
|
|
fRet = TRUE;
|
|
}
|
|
if (fRet)
|
|
{
|
|
// if (Item[ usItem ].fFlags & ITEM_DEFAULT_UNDROPPABLE)
|
|
if (Item[ usItem ].defaultundroppable )
|
|
{
|
|
(*pObj).fFlags |= OBJECT_UNDROPPABLE;
|
|
}
|
|
if (Item [ usItem ].defaultattachment > 0 )
|
|
{
|
|
//cannot use gTempObject
|
|
static OBJECTTYPE defaultAttachment;
|
|
CreateItem(Item [ usItem ].defaultattachment,100,&defaultAttachment);
|
|
pObj->AttachObject(NULL,&defaultAttachment);
|
|
}
|
|
}
|
|
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateItem: return %d",fRet));
|
|
return( fRet );
|
|
}
|
|
|
|
BOOLEAN CreateItems( UINT16 usItem, INT8 bStatus, UINT8 ubNumber, OBJECTTYPE * pObj )
|
|
{
|
|
BOOLEAN fOk;
|
|
fOk = CreateItem( usItem, bStatus, pObj );
|
|
if (fOk)
|
|
{
|
|
if (ubNumber > 1) {
|
|
//no need to recalc weight if just 1, CreateItem did that.
|
|
for (int x = 1; x < ubNumber; ++x) {
|
|
pObj->objectStack.push_back(pObj->objectStack.front());
|
|
}
|
|
pObj->ubNumberOfObjects = ubNumber;
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pObj->ubWeight = CalculateObjectWeight(pObj);
|
|
}
|
|
return( TRUE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CreateMoney( UINT32 uiMoney, OBJECTTYPE * pObj )
|
|
{
|
|
BOOLEAN fOk;
|
|
|
|
fOk = CreateItem( MONEY, 100, pObj );
|
|
if (fOk)
|
|
{
|
|
(*pObj)[0]->data.money.uiMoneyAmount = uiMoney;
|
|
}
|
|
return( fOk );
|
|
}
|
|
|
|
BOOLEAN ArmBomb( OBJECTTYPE * pObj, INT8 bSetting )
|
|
{
|
|
BOOLEAN fRemote = FALSE;
|
|
BOOLEAN fPressure = FALSE;
|
|
BOOLEAN fTimed = FALSE;
|
|
BOOLEAN fSwitch = FALSE;
|
|
|
|
if (pObj->usItem == ACTION_ITEM)
|
|
{
|
|
switch( (*pObj)[0]->data.misc.bActionValue )
|
|
{
|
|
case ACTION_ITEM_SMALL_PIT:
|
|
case ACTION_ITEM_LARGE_PIT:
|
|
fPressure = TRUE;
|
|
break;
|
|
default:
|
|
fRemote = TRUE;
|
|
break;
|
|
|
|
}
|
|
}
|
|
else if ( IsDetonatorAttached( pObj ) )
|
|
{
|
|
fTimed = TRUE;
|
|
}
|
|
else if ( (IsRemoteDetonatorAttached( pObj ) ) || (pObj->usItem == ACTION_ITEM) )
|
|
{
|
|
fRemote = TRUE;
|
|
}
|
|
else if ( Item[pObj->usItem].mine || pObj->usItem == TRIP_FLARE || pObj->usItem == TRIP_KLAXON || pObj->usItem == ACTION_ITEM )
|
|
{
|
|
fPressure = TRUE;
|
|
}
|
|
else if ( pObj->usItem == SWITCH )
|
|
{
|
|
// this makes a remote detonator into a pressure-sensitive trigger
|
|
if ( bSetting == PANIC_FREQUENCY )
|
|
{
|
|
// panic trigger is only activated by expending APs, not by
|
|
// stepping on it... so don't define a detonator type
|
|
fSwitch = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fPressure = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no sorta bomb at all!
|
|
return( FALSE );
|
|
}
|
|
|
|
if (fRemote)
|
|
{
|
|
(*pObj)[0]->data.misc.bDetonatorType = BOMB_REMOTE;
|
|
(*pObj)[0]->data.misc.bFrequency = bSetting;
|
|
}
|
|
else if (fPressure)
|
|
{
|
|
(*pObj)[0]->data.misc.bDetonatorType = BOMB_PRESSURE;
|
|
(*pObj)[0]->data.misc.bFrequency = 0;
|
|
}
|
|
else if (fTimed)
|
|
{
|
|
(*pObj)[0]->data.misc.bDetonatorType = BOMB_TIMED;
|
|
// In realtime the player could choose to put down a bomb right before a turn expires, SO
|
|
// add 1 to the setting in RT
|
|
(*pObj)[0]->data.misc.bDelay = bSetting;
|
|
if ( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
(*pObj)[0]->data.misc.bDelay++;
|
|
}
|
|
|
|
}
|
|
else if (fSwitch)
|
|
{
|
|
(*pObj)[0]->data.misc.bDetonatorType = BOMB_SWITCH;
|
|
(*pObj)[0]->data.misc.bFrequency = bSetting;
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
(*pObj).fFlags |= OBJECT_ARMED_BOMB;
|
|
(*pObj)[0]->data.misc.usBombItem = pObj->usItem;
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN OBJECTTYPE::RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNewObj, UINT8 subObject )
|
|
{
|
|
BOOLEAN objDeleted = FALSE;
|
|
|
|
if ( pAttachment == 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( Item[ pAttachment->usItem ].inseparable )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
//CHRISL: I know this FOR loop is basically redundant to what the remove() function already does, but
|
|
// this setup includes a failsafe. Now we'll only copy the attachment to our cursor (pNewObj) if
|
|
// iter and pAttachment are the same. This should stop attachment duplication though it doesn't resolve
|
|
// the initial cause of the attachment duplication issue.
|
|
for (std::list<OBJECTTYPE>::iterator iter = (*this)[subObject]->attachments.begin();
|
|
iter != (*this)[subObject]->attachments.end(); ++iter){
|
|
if(*iter == *pAttachment)
|
|
{
|
|
if(pNewObj != NULL)
|
|
{
|
|
*pNewObj = *pAttachment;
|
|
}
|
|
iter = (*this)[subObject]->attachments.erase(iter);
|
|
objDeleted = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(!objDeleted)
|
|
return( FALSE );
|
|
|
|
if (pNewObj && Item[pNewObj->usItem].grenadelauncher )//UNDER_GLAUNCHER)
|
|
{
|
|
// look for any grenade; if it exists, we must make it an
|
|
// attachment of the grenade launcher
|
|
OBJECTTYPE* pGrenade = FindAttachmentByClass( this, IC_GRENADE );
|
|
if (pGrenade)
|
|
{
|
|
(*pNewObj)[subObject]->attachments.push_back(*pGrenade);
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//pNewObj->ubWeight = CalculateObjectWeight( pNewObj );
|
|
this->RemoveAttachment(pGrenade);
|
|
}
|
|
}
|
|
|
|
//ADB ubWeight has been removed, see comments in OBJECTTYPE
|
|
//this->ubWeight = CalculateObjectWeight( this );
|
|
return( TRUE );
|
|
}
|
|
|
|
void SetNewItem( SOLDIERTYPE *pSoldier, UINT8 ubInvPos, BOOLEAN fNewItem )
|
|
{
|
|
if( fNewItem )
|
|
{
|
|
pSoldier->inv.bNewItemCount[ ubInvPos ] = -1;
|
|
pSoldier->inv.bNewItemCycleCount[ ubInvPos ] = NEW_ITEM_CYCLE_COUNT;
|
|
pSoldier->flags.fCheckForNewlyAddedItems = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN PlaceObjectInSoldierProfile( UINT8 ubProfile, OBJECTTYPE *pObject )
|
|
{
|
|
INT8 bLoop;
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT16 usItem;
|
|
INT16 bStatus;
|
|
BOOLEAN fReturnVal = FALSE;
|
|
|
|
usItem = pObject->usItem;
|
|
Assert(pObject->ubNumberOfObjects == 1);
|
|
bStatus = (*pObject)[0]->data.objectStatus;
|
|
pSoldier = FindSoldierByProfileID( ubProfile, FALSE );
|
|
|
|
if ( Item[ usItem ].usItemClass == IC_MONEY && gMercProfiles[ ubProfile ].uiMoney > 0 )
|
|
{
|
|
gMercProfiles[ ubProfile ].uiMoney += (*pObject)[0]->data.money.uiMoneyAmount;
|
|
SetMoneyInSoldierProfile( ubProfile, gMercProfiles[ ubProfile ].uiMoney );
|
|
return( TRUE );
|
|
}
|
|
|
|
// CHRISL:
|
|
for (bLoop = BIGPOCKSTART; bLoop < NUM_INV_SLOTS; bLoop++)
|
|
{
|
|
if ( gMercProfiles[ ubProfile ].bInvNumber[ bLoop ] == 0 && (pSoldier == NULL || pSoldier->inv[ bLoop ].exists() == false ) )
|
|
{
|
|
|
|
// CJC: Deal with money by putting money into # stored in profile
|
|
if ( Item[ usItem ].usItemClass == IC_MONEY )
|
|
{
|
|
gMercProfiles[ ubProfile ].uiMoney += (*pObject)[0]->data.money.uiMoneyAmount;
|
|
// change any gold/silver to money
|
|
usItem = MONEY;
|
|
}
|
|
else
|
|
{
|
|
gMercProfiles[ ubProfile ].inv[ bLoop ] = usItem;
|
|
gMercProfiles[ ubProfile ].bInvStatus[ bLoop ] = bStatus;
|
|
gMercProfiles[ ubProfile ].bInvNumber[ bLoop ] = pObject->ubNumberOfObjects;
|
|
}
|
|
|
|
fReturnVal = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//uiMoneyAmount
|
|
if ( fReturnVal )
|
|
{
|
|
// ATE: Manage soldier pointer as well....
|
|
//pSoldier = FindSoldierByProfileID( ubProfile, FALSE );
|
|
|
|
// Do we have a valid profile?
|
|
if ( pSoldier != NULL )
|
|
{
|
|
// OK, place in soldier...
|
|
if ( usItem == MONEY )
|
|
{
|
|
CreateMoney( gMercProfiles[ ubProfile ].uiMoney, &(pSoldier->inv[ bLoop ] ) );
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->ubProfile == MADLAB )
|
|
{
|
|
// remove ammo and drop
|
|
pSoldier->pTempObject = new OBJECTTYPE;
|
|
EmptyWeaponMagazine( pObject, pSoldier->pTempObject );
|
|
AddItemToPool( pSoldier->sGridNo, pSoldier->pTempObject, 1, 0, 0, 0 );
|
|
pSoldier->pTempObject = NULL;
|
|
// remove attachments and drop them
|
|
for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end();) {
|
|
//CHRISL: Because MADLAB needs to remove all attachments, even inseparable ones, we need to temporarily
|
|
// make all attachments removable.
|
|
BOOLEAN old_inseparable = FALSE;
|
|
UINT32 old_item = iter->usItem;
|
|
// drop it in Madlab's tile
|
|
AddItemToPool( pSoldier->sGridNo, &(*iter), 1, 0, 0, 0 );
|
|
old_inseparable = Item[old_item].inseparable;
|
|
Item[old_item].inseparable = FALSE;
|
|
pObject->RemoveAttachment(&(*iter));
|
|
Item[old_item].inseparable = old_inseparable;
|
|
if ((*pObject)[0]->attachments.empty() == true) {
|
|
break;
|
|
}
|
|
else{
|
|
iter = (*pObject)[0]->attachments.begin();
|
|
}
|
|
}
|
|
}
|
|
|
|
CreateItem( usItem, bStatus, &(pSoldier->inv[ bLoop ] ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( fReturnVal );
|
|
}
|
|
|
|
BOOLEAN RemoveObjectFromSoldierProfile( UINT8 ubProfile, UINT16 usItem )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
BOOLEAN fReturnVal = FALSE;
|
|
|
|
if ( usItem == NOTHING )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
MERCPROFILESTRUCT* pProfile = &gMercProfiles[ ubProfile ];
|
|
for (unsigned int bLoop = 0; bLoop < pProfile->inv.size(); bLoop++)
|
|
{
|
|
if ( pProfile->inv[ bLoop ] == usItem )
|
|
{
|
|
pProfile->inv[ bLoop ] = NOTHING;
|
|
pProfile->bInvStatus[ bLoop ] = 0;
|
|
pProfile->bInvNumber[ bLoop ] = 0;
|
|
|
|
fReturnVal = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ATE: Manage soldier pointer as well....
|
|
pSoldier = FindSoldierByProfileID( ubProfile, FALSE );
|
|
|
|
// Do we have a valid profile?
|
|
if ( pSoldier != NULL )
|
|
{
|
|
// Remove item...
|
|
RemoveInvObject( pSoldier, usItem );
|
|
}
|
|
|
|
return( fReturnVal );
|
|
}
|
|
|
|
|
|
void SetMoneyInSoldierProfile( UINT8 ubProfile, UINT32 uiMoney )
|
|
{
|
|
BOOLEAN fRet;
|
|
|
|
// remove all money from soldier
|
|
do
|
|
{
|
|
fRet = RemoveObjectFromSoldierProfile( ubProfile, MONEY );
|
|
}
|
|
while ( fRet == TRUE );
|
|
|
|
gMercProfiles[ ubProfile ].uiMoney = 0;
|
|
|
|
if (uiMoney > 0)
|
|
{
|
|
// now add the amount specified
|
|
CreateMoney( uiMoney, &gTempObject );
|
|
PlaceObjectInSoldierProfile( ubProfile, &gTempObject );
|
|
}
|
|
}
|
|
|
|
INT8 FindObjectInSoldierProfile( UINT8 ubProfile, UINT16 usItem )
|
|
{
|
|
|
|
MERCPROFILESTRUCT* pProfile = &gMercProfiles[ ubProfile ];
|
|
for (unsigned int bLoop = 0; bLoop < pProfile->inv.size(); bLoop++)
|
|
{
|
|
if ( pProfile->bInvNumber[ bLoop ] > 0 )
|
|
{
|
|
if ( pProfile->inv[ bLoop ] == usItem )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
BOOLEAN ObjectExistsInSoldierProfile( UINT8 ubProfile, UINT16 usItem )
|
|
{
|
|
INT8 bSlot;
|
|
|
|
bSlot = FindObjectInSoldierProfile( ubProfile, usItem );
|
|
return( bSlot != NO_SLOT );
|
|
}
|
|
|
|
void RemoveInvObject( SOLDIERTYPE *pSoldier, UINT16 usItem )
|
|
{
|
|
INT8 bInvPos;
|
|
|
|
// find object
|
|
bInvPos = FindObj( pSoldier, usItem );
|
|
if (bInvPos != NO_SLOT)
|
|
{
|
|
// Erase!
|
|
DeleteObj(&pSoldier->inv[ bInvPos ]);
|
|
|
|
//Dirty!
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
|
|
}
|
|
|
|
INT8 CheckItemForDamage( UINT16 usItem, INT32 iMaxDamage )
|
|
{
|
|
INT8 bDamage = 0;
|
|
|
|
// if the item is protective armour, reduce the amount of damage
|
|
// by its armour value
|
|
if (Item[usItem].usItemClass == IC_ARMOUR)
|
|
{
|
|
iMaxDamage -= (iMaxDamage * Armour[Item[usItem].ubClassIndex].ubProtection) / 100;
|
|
}
|
|
// metal items are tough and will be damaged less
|
|
// if (Item[usItem].fFlags & ITEM_METAL)
|
|
if (Item[usItem].metal )
|
|
{
|
|
iMaxDamage /= 2;
|
|
}
|
|
else if ( usItem == BLOODCAT_PELT )
|
|
{
|
|
iMaxDamage *= 2;
|
|
}
|
|
if (iMaxDamage > 0)
|
|
{
|
|
bDamage = (INT8) PreRandom( iMaxDamage );
|
|
}
|
|
return( bDamage );
|
|
}
|
|
|
|
BOOLEAN CheckForChainReaction( UINT16 usItem, INT16 bStatus, INT16 bDamage, BOOLEAN fOnGround )
|
|
{
|
|
INT32 iChance;
|
|
|
|
iChance = Explosive[Item[usItem].ubClassIndex].ubVolatility;
|
|
if (iChance > 0)
|
|
{
|
|
|
|
// Scale the base chance by the damage caused to the item
|
|
// (bigger the shock, bigger chance) and the condition of
|
|
// the item after being hit!
|
|
if (fOnGround)
|
|
{
|
|
// improve chance to make it practical to blow up explosives on the ground
|
|
iChance = 50 + (iChance - 1) * 10;
|
|
}
|
|
|
|
iChance = iChance * ( 100 + ( (100 - bStatus) + bDamage ) / 2 ) / 100;
|
|
if ((INT32) PreRandom( 100 ) < iChance)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN DamageItem( OBJECTTYPE * pObject, INT32 iDamage, BOOLEAN fOnGround )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 bDamage;
|
|
|
|
if ( (Item[pObject->usItem].damageable || Item[ pObject->usItem ].usItemClass == IC_AMMO) && pObject->exists() == true)
|
|
{
|
|
|
|
for (bLoop = 0; bLoop < pObject->ubNumberOfObjects; bLoop++)
|
|
{
|
|
bool removed = false;
|
|
// if the status of the item is negative then it's trapped/jammed;
|
|
// leave it alone
|
|
if (pObject->exists() == true && (*pObject)[bLoop]->data.objectStatus > 0)
|
|
{
|
|
bDamage = CheckItemForDamage( pObject->usItem, iDamage );
|
|
switch( pObject->usItem )
|
|
{
|
|
case JAR_CREATURE_BLOOD:
|
|
case JAR:
|
|
case JAR_HUMAN_BLOOD:
|
|
case JAR_ELIXIR:
|
|
if ( PreRandom( bDamage ) > 5 )
|
|
{
|
|
// smash!
|
|
bDamage = (*pObject)[bLoop]->data.objectStatus;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ( Item[ pObject->usItem ].usItemClass == IC_AMMO )
|
|
{
|
|
if ( PreRandom( 100 ) < (UINT32) bDamage )
|
|
{
|
|
// destroy clip completely
|
|
(*pObject)[bLoop]->data.objectStatus = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*pObject)[bLoop]->data.objectStatus -= bDamage;
|
|
if ((*pObject)[bLoop]->data.objectStatus < 1)
|
|
{
|
|
(*pObject)[bLoop]->data.objectStatus = 1;
|
|
}
|
|
}
|
|
// I don't think we increase viewrange based on items any more
|
|
// FUN STUFF! Check for explosives going off as a result!
|
|
if (Item[pObject->usItem].usItemClass & IC_EXPLOSV)
|
|
{
|
|
if (CheckForChainReaction( pObject->usItem, (*pObject)[bLoop]->data.objectStatus, bDamage, fOnGround ))
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
// remove item from index AFTER checking explosions because need item data for explosion!
|
|
if ( (*pObject)[bLoop]->data.objectStatus == 1 )
|
|
{
|
|
if ( pObject->ubNumberOfObjects > 1 )
|
|
{
|
|
removed = true;
|
|
pObject->RemoveObjectAtIndex( bLoop );
|
|
// since an item was just removed, the items above the current were all shifted down one;
|
|
// to process them properly, we have to back up 1 in the counter
|
|
--bLoop;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (removed == false) {
|
|
for (attachmentList::iterator iter = (*pObject)[bLoop]->attachments.begin(); iter != (*pObject)[bLoop]->attachments.end();) {
|
|
DamageItem(&(*iter), iDamage, fOnGround);
|
|
//could have removed the object at iter
|
|
if (iter->exists() == true) {
|
|
++iter;
|
|
}
|
|
else {
|
|
iter = (*pObject)[bLoop]->attachments.erase(iter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
void CheckEquipmentForDamage( SOLDIERTYPE *pSoldier, INT32 iDamage )
|
|
{
|
|
INT8 bSlot;
|
|
BOOLEAN fBlowsUp;
|
|
UINT8 ubNumberOfObjects;
|
|
|
|
if ( TANK( pSoldier ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (bSlot = 0; bSlot < (INT8) pSoldier->inv.size(); bSlot++)
|
|
{
|
|
if (pSoldier->inv[bSlot].exists() == false) {
|
|
continue;
|
|
}
|
|
ubNumberOfObjects = pSoldier->inv[bSlot].ubNumberOfObjects;
|
|
fBlowsUp = DamageItem( &(pSoldier->inv[bSlot]), iDamage, FALSE );
|
|
if (fBlowsUp)
|
|
{
|
|
// blow it up!
|
|
if ( gTacticalStatus.ubAttackBusyCount )
|
|
{
|
|
IgniteExplosion( pSoldier->ubAttackerID, CenterX( pSoldier->sGridNo ), CenterY( pSoldier->sGridNo ), 0, pSoldier->sGridNo, pSoldier->inv[ bSlot ].usItem, pSoldier->pathing.bLevel );
|
|
}
|
|
else
|
|
{
|
|
IgniteExplosion( pSoldier->ubID, CenterX( pSoldier->sGridNo ), CenterY( pSoldier->sGridNo ), 0, pSoldier->sGridNo, pSoldier->inv[ bSlot ].usItem, pSoldier->pathing.bLevel );
|
|
}
|
|
|
|
//ADB when something in a stack blows up the whole stack goes, so no need to worry about number of items
|
|
// Remove item!
|
|
DeleteObj( &(pSoldier->inv[ bSlot ]) );
|
|
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
else if ( ubNumberOfObjects != pSoldier->inv[bSlot].ubNumberOfObjects )
|
|
{
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckEquipmentForFragileItemDamage( SOLDIERTYPE *pSoldier, INT32 iDamage )
|
|
{
|
|
// glass jars etc can be damaged by falling over
|
|
INT8 bSlot;
|
|
UINT8 ubNumberOfObjects;
|
|
BOOLEAN fPlayedGlassBreak = FALSE;
|
|
|
|
for (bSlot = 0; bSlot < (INT8) pSoldier->inv.size(); bSlot++)
|
|
{
|
|
if (pSoldier->inv[bSlot].exists() == false) {
|
|
continue;
|
|
}
|
|
switch( pSoldier->inv[bSlot].usItem )
|
|
{
|
|
case JAR_CREATURE_BLOOD:
|
|
case JAR:
|
|
case JAR_HUMAN_BLOOD:
|
|
case JAR_ELIXIR:
|
|
ubNumberOfObjects = pSoldier->inv[bSlot].ubNumberOfObjects;
|
|
DamageItem( &(pSoldier->inv[bSlot]), iDamage, FALSE );
|
|
if ( !fPlayedGlassBreak && (ubNumberOfObjects != pSoldier->inv[bSlot].ubNumberOfObjects) )
|
|
{
|
|
PlayJA2Sample( GLASS_CRACK, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) );
|
|
fPlayedGlassBreak = TRUE;
|
|
// only dirty once
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN DamageItemOnGround( OBJECTTYPE * pObject, INT16 sGridNo, INT8 bLevel, INT32 iDamage, UINT8 ubOwner )
|
|
{
|
|
BOOLEAN fBlowsUp;
|
|
|
|
fBlowsUp = DamageItem( pObject, iDamage, TRUE );
|
|
if ( fBlowsUp )
|
|
{
|
|
// OK, Ignite this explosion!
|
|
IgniteExplosion( ubOwner, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pObject->usItem, bLevel );
|
|
|
|
// Remove item!
|
|
return( TRUE );
|
|
}
|
|
else if ( pObject->exists() == true && (pObject->ubNumberOfObjects < 2) && ((*pObject)[0]->data.objectStatus < USABLE) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
// is the item a medical kit/first aid kit item?
|
|
INT8 IsMedicalKitItem( OBJECTTYPE *pObject )
|
|
{
|
|
// check item id against current medical kits
|
|
if ( Item[pObject->usItem].medicalkit && pObject->exists() == true)
|
|
return 1;
|
|
|
|
//switch( pObject->usItem )
|
|
//{
|
|
// case( MEDICKIT ):
|
|
// // medical bag, return 1
|
|
// return ( 1 );
|
|
// break;
|
|
//}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
void SwapHandItems( SOLDIERTYPE * pSoldier )
|
|
{
|
|
BOOLEAN fOk;
|
|
|
|
CHECKV( pSoldier );
|
|
if (pSoldier->inv[HANDPOS].exists() == false || pSoldier->inv[SECONDHANDPOS].exists() == false)
|
|
{
|
|
// whatever is in the second hand can be swapped to the main hand!
|
|
SwapObjs( pSoldier, HANDPOS, SECONDHANDPOS, TRUE );
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
else
|
|
{
|
|
if (TwoHandedItem( pSoldier->inv[SECONDHANDPOS].usItem ) )
|
|
{
|
|
// must move the item in the main hand elsewhere in the inventory
|
|
fOk = AutoPlaceObject( pSoldier, &(pSoldier->inv[HANDPOS]), FALSE, HANDPOS );
|
|
if (!fOk)
|
|
{
|
|
return;
|
|
}
|
|
// the main hand is now empty so a swap is going to work...
|
|
}
|
|
SwapObjs( pSoldier, HANDPOS, SECONDHANDPOS, TRUE );
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
}
|
|
|
|
void SwapOutHandItem( SOLDIERTYPE * pSoldier )
|
|
{
|
|
BOOLEAN fOk;
|
|
|
|
CHECKV( pSoldier );
|
|
|
|
// puts away the item in the main hand
|
|
if (pSoldier->inv[HANDPOS].exists() == true )
|
|
{
|
|
if (pSoldier->inv[SECONDHANDPOS].exists() == false)
|
|
{
|
|
// just swap the hand item to the second hand
|
|
SwapObjs( pSoldier, HANDPOS, SECONDHANDPOS, TRUE );
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// try placing it somewhere else in our inventory
|
|
fOk = AutoPlaceObject( pSoldier, &(pSoldier->inv[HANDPOS]), FALSE );
|
|
if (fOk)
|
|
{
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
// otherwise there's no room for the item anywhere!
|
|
}
|
|
}
|
|
}
|
|
|
|
void WaterDamage( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// damage guy's equipment and camouflage due to water
|
|
INT8 bLoop, bDamage, bDieSize;
|
|
UINT32 uiRoll;
|
|
|
|
if ( pSoldier->MercInDeepWater( ) )
|
|
{
|
|
for ( bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++ )
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == false) {
|
|
continue;
|
|
}
|
|
// if there's an item here that can get water damaged...
|
|
// if (pSoldier->inv[ bLoop ].usItem && Item[pSoldier->inv[ bLoop ].usItem].fFlags & ITEM_WATER_DAMAGES)
|
|
if (pSoldier->inv[ bLoop ].usItem && Item[pSoldier->inv[ bLoop ].usItem].waterdamages )
|
|
{
|
|
// roll the 'ol 100-sided dice
|
|
uiRoll = PreRandom(100);
|
|
|
|
// 10% chance of getting damage!
|
|
if (uiRoll < 10)
|
|
{
|
|
// lose between 1 and 10 status points each time
|
|
bDamage = (INT8) (10 - uiRoll);
|
|
|
|
// but don't let anything drop lower than 1%
|
|
pSoldier->inv[bLoop][0]->data.objectStatus -= bDamage;
|
|
if (pSoldier->inv[bLoop][0]->data.objectStatus < 1)
|
|
{
|
|
pSoldier->inv[bLoop][0]->data.objectStatus = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
BOOLEAN camoWoreOff = FALSE;
|
|
if (pSoldier->bCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED ) )
|
|
{
|
|
// reduce camouflage by 2% per tile of deep water
|
|
// and 1% for medium water
|
|
if ( pSoldier->MercInDeepWater( ) )
|
|
pSoldier->bCamo = __max( 0, pSoldier->bCamo - 2 );
|
|
else
|
|
pSoldier->bCamo = __max( 0, pSoldier->bCamo - 1 );
|
|
|
|
if ( (pSoldier->bCamo)== 0)
|
|
camoWoreOff = TRUE;
|
|
}
|
|
|
|
if (pSoldier->urbanCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN ) )
|
|
{
|
|
// reduce camouflage by 2% per tile of deep water
|
|
// and 1% for medium water
|
|
if ( pSoldier->MercInDeepWater( ) )
|
|
pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 2 );
|
|
else
|
|
pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 1 );
|
|
|
|
if ( (pSoldier->urbanCamo)== 0)
|
|
camoWoreOff = TRUE;
|
|
}
|
|
|
|
if (pSoldier->desertCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT ) )
|
|
{
|
|
// reduce camouflage by 2% per tile of deep water
|
|
// and 1% for medium water
|
|
if ( pSoldier->MercInDeepWater( ) )
|
|
pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 2 );
|
|
else
|
|
pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 1 );
|
|
|
|
if ( (pSoldier->desertCamo)== 0)
|
|
camoWoreOff = TRUE;
|
|
}
|
|
|
|
if (pSoldier->snowCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_SNOW ) )
|
|
{
|
|
// reduce camouflage by 2% per tile of deep water
|
|
// and 1% for medium water
|
|
if ( pSoldier->MercInDeepWater( ) )
|
|
pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 2 );
|
|
else
|
|
pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 1 );
|
|
|
|
if ( (pSoldier->snowCamo)== 0)
|
|
camoWoreOff = TRUE;
|
|
}
|
|
|
|
if ( camoWoreOff )
|
|
{
|
|
// Reload palettes....
|
|
if ( pSoldier->bInSector )
|
|
{
|
|
pSoldier->CreateSoldierPalettes( );
|
|
}
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WASHED_OFF], pSoldier->name );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( pSoldier->bTeam == gbPlayerNum && pSoldier->aiData.bMonsterSmell > 0 )
|
|
{
|
|
if ( pSoldier->MercInDeepWater( ) )
|
|
{
|
|
bDieSize = 10;
|
|
}
|
|
else
|
|
{
|
|
bDieSize = 20;
|
|
}
|
|
if ( Random( bDieSize ) == 0 )
|
|
{
|
|
pSoldier->aiData.bMonsterSmell--;
|
|
}
|
|
}
|
|
|
|
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
|
|
}
|
|
|
|
BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs )
|
|
{
|
|
INT8 bPointsToUse;
|
|
UINT16 usTotalKitPoints;
|
|
|
|
(*pfGoodAPs) = TRUE;
|
|
|
|
if (!Item[pObj->usItem].camouflagekit || pObj->exists() == false)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!EnoughPoints( pSoldier, APBPConstants[AP_CAMOFLAGE], 0, TRUE ) )
|
|
{
|
|
(*pfGoodAPs) = FALSE;
|
|
return( TRUE );
|
|
}
|
|
|
|
usTotalKitPoints = TotalPoints( pObj );
|
|
if (usTotalKitPoints == 0)
|
|
{
|
|
// HUH???
|
|
return( FALSE );
|
|
}
|
|
|
|
//get total camo bonus for kit -- note that camo kits now require the camobonus tag to be set
|
|
//int itemCamo = Item[pObj->usItem].camobonus + Item[pObj->usItem].urbanCamobonus + Item[pObj->usItem].desertCamobonus + Item[pObj->usItem].snowCamobonus;
|
|
|
|
int totalCamo = pSoldier->bCamo + pSoldier->wornCamo + pSoldier->urbanCamo+pSoldier->wornUrbanCamo+pSoldier->desertCamo+pSoldier->wornDesertCamo+pSoldier->snowCamo+pSoldier->wornSnowCamo;
|
|
if ((totalCamo) >= 100)
|
|
{
|
|
// nothing more to add
|
|
return( FALSE );
|
|
}
|
|
|
|
// points are used up at a rate of 50% kit = 100% cammo on guy
|
|
// add 1 to round off
|
|
bPointsToUse = (100 - (totalCamo) + 1 ) / 2;
|
|
bPointsToUse = __min( bPointsToUse, usTotalKitPoints );
|
|
|
|
//figure out proportions of each to be applied, one item can theoretically have more than one camouflage type this way
|
|
int urban = (int)(Item[pObj->usItem].urbanCamobonus * bPointsToUse * 2 / 100 );
|
|
int jungle = (int)(Item[pObj->usItem].camobonus * bPointsToUse * 2 / 100 );
|
|
int desert = (int)(Item[pObj->usItem].desertCamobonus * bPointsToUse * 2 / 100 );
|
|
int snow = (int)(Item[pObj->usItem].snowCamobonus * bPointsToUse * 2 / 100 );
|
|
|
|
pSoldier->bCamo = __min( 100, pSoldier->bCamo + jungle );
|
|
pSoldier->urbanCamo = __min( 100, pSoldier->urbanCamo + urban );
|
|
pSoldier->desertCamo = __min( 100, pSoldier->desertCamo + desert );
|
|
pSoldier->snowCamo = __min( 100, pSoldier->snowCamo + snow );
|
|
|
|
UseKitPoints( pObj, bPointsToUse, pSoldier );
|
|
|
|
DeductPoints( pSoldier, APBPConstants[AP_CAMOFLAGE], 0 );
|
|
|
|
// Reload palettes....
|
|
if ( pSoldier->bInSector )
|
|
{
|
|
pSoldier->CreateSoldierPalettes( );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN ApplyCanteen( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs )
|
|
{
|
|
INT16 sPointsToUse;
|
|
UINT16 usTotalKitPoints;
|
|
|
|
(*pfGoodAPs) = TRUE;
|
|
|
|
if (!Item[pObj->usItem].canteen || pObj->exists() == false)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
usTotalKitPoints = TotalPoints( pObj );
|
|
if (usTotalKitPoints == 0)
|
|
{
|
|
// HUH???
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!EnoughPoints( pSoldier, APBPConstants[AP_DRINK], 0, TRUE ) )
|
|
{
|
|
(*pfGoodAPs) = FALSE;
|
|
return( TRUE );
|
|
}
|
|
|
|
if ( pSoldier->bTeam == gbPlayerNum )
|
|
{
|
|
if ( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE )
|
|
{
|
|
PlayJA2Sample( DRINK_CANTEEN_MALE, RATE_11025, MIDVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
else
|
|
{
|
|
PlayJA2Sample( DRINK_CANTEEN_FEMALE, RATE_11025, MIDVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
}
|
|
|
|
sPointsToUse = __min( 20, usTotalKitPoints );
|
|
|
|
// CJC Feb 9. Canteens don't seem effective enough, so doubled return from them
|
|
DeductPoints( pSoldier, APBPConstants[AP_DRINK], (INT16) (2 * sPointsToUse * -(100 - pSoldier->bBreath) ) );
|
|
|
|
UseKitPoints( pObj, sPointsToUse, pSoldier );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
#define MAX_HUMAN_CREATURE_SMELL (NORMAL_HUMAN_SMELL_STRENGTH - 1)
|
|
|
|
BOOLEAN ApplyElixir( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs )
|
|
{
|
|
INT16 sPointsToUse;
|
|
UINT16 usTotalKitPoints;
|
|
|
|
(*pfGoodAPs) = TRUE;
|
|
|
|
if (pObj->usItem != JAR_ELIXIR || pObj->exists() == false)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
usTotalKitPoints = TotalPoints( pObj );
|
|
if (usTotalKitPoints == 0)
|
|
{
|
|
// HUH???
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!EnoughPoints( pSoldier, APBPConstants[AP_CAMOFLAGE], 0, TRUE ) )
|
|
{
|
|
(*pfGoodAPs) = FALSE;
|
|
return( TRUE );
|
|
}
|
|
|
|
DeductPoints( pSoldier, APBPConstants[AP_CAMOFLAGE], 0 );
|
|
|
|
sPointsToUse = ( MAX_HUMAN_CREATURE_SMELL - pSoldier->aiData.bMonsterSmell ) * 2;
|
|
sPointsToUse = __min( sPointsToUse, usTotalKitPoints );
|
|
|
|
UseKitPoints( pObj, sPointsToUse, pSoldier );
|
|
|
|
pSoldier->aiData.bMonsterSmell += sPointsToUse / 2;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
UINT32 ConvertProfileMoneyValueToObjectTypeMoneyValue( UINT8 ubStatus )
|
|
{
|
|
return( ubStatus * 50 );
|
|
}
|
|
|
|
UINT8 ConvertObjectTypeMoneyValueToProfileMoneyValue( UINT32 uiMoneyAmount )
|
|
{
|
|
return( (UINT8)( uiMoneyAmount / 50 ) );
|
|
}
|
|
|
|
BOOLEAN ItemIsCool( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == false) {
|
|
return FALSE;
|
|
}
|
|
if ((*pObj)[0]->data.objectStatus < 60)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( Item[ pObj->usItem ].usItemClass & IC_WEAPON )
|
|
{
|
|
if ( Weapon[ pObj->usItem ].ubDeadliness >= 30 )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else if ( Item[ pObj->usItem ].usItemClass & IC_ARMOUR )
|
|
{
|
|
if ( Armour[ Item[ pObj->usItem ].ubClassIndex ].ubProtection >= 20 )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
void ActivateXRayDevice( SOLDIERTYPE * pSoldier )
|
|
{
|
|
SOLDIERTYPE * pSoldier2;
|
|
UINT32 uiSlot;
|
|
|
|
if ( Item[pSoldier->inv[ HANDPOS ].usItem].needsbatteries && pSoldier->inv[ HANDPOS ].exists() == true)
|
|
{
|
|
// check for batteries
|
|
OBJECTTYPE* pBatteries = FindAttachedBatteries( &(pSoldier->inv[HANDPOS]) );
|
|
if ( pBatteries == 0 )
|
|
{
|
|
// doesn't work without batteries!
|
|
return;
|
|
}
|
|
|
|
// use up 8-12 percent of batteries
|
|
if ( Item[pBatteries->usItem].percentstatusdrainreduction > 0 )
|
|
(*pBatteries)[0]->data.objectStatus -= (INT8)( (8 + Random( 5 )) * (100 - Item[(*pBatteries)[0]->data.objectStatus].percentstatusdrainreduction)/100 );
|
|
else
|
|
(*pBatteries)[0]->data.objectStatus -= (INT8)( (8 + Random( 5 )) );
|
|
if ( (*pBatteries)[0]->data.objectStatus <= 0 )
|
|
{
|
|
// destroy batteries
|
|
pBatteries->RemoveObjectsFromStack(1);
|
|
if (pBatteries->exists() == false) {
|
|
pSoldier->inv[HANDPOS].RemoveAttachment(pBatteries);
|
|
}
|
|
}
|
|
}
|
|
// first, scan through all mercs and turn off xrayed flag for anyone
|
|
// previously xrayed by this guy
|
|
for ( uiSlot = 0; uiSlot < guiNumMercSlots; uiSlot++ )
|
|
{
|
|
pSoldier2 = MercSlots[ uiSlot ];
|
|
if ( pSoldier2 )
|
|
{
|
|
if ( (pSoldier2->ubMiscSoldierFlags & SOLDIER_MISC_XRAYED) && (pSoldier2->aiData.ubXRayedBy == pSoldier->ubID) )
|
|
{
|
|
pSoldier2->ubMiscSoldierFlags &= (~SOLDIER_MISC_XRAYED);
|
|
pSoldier2->aiData.ubXRayedBy = NOBODY;
|
|
}
|
|
}
|
|
}
|
|
// now turn on xray for anyone within range
|
|
for ( uiSlot = 0; uiSlot < guiNumMercSlots; uiSlot++ )
|
|
{
|
|
pSoldier2 = MercSlots[ uiSlot ];
|
|
if ( pSoldier2 )
|
|
{
|
|
if ( pSoldier2->bTeam != pSoldier->bTeam && PythSpacesAway( pSoldier->sGridNo, pSoldier2->sGridNo ) < XRAY_RANGE )
|
|
{
|
|
pSoldier2->ubMiscSoldierFlags |= SOLDIER_MISC_XRAYED;
|
|
pSoldier2->aiData.ubXRayedBy = pSoldier->ubID;
|
|
}
|
|
}
|
|
}
|
|
pSoldier->uiXRayActivatedTime = GetWorldTotalSeconds();
|
|
}
|
|
|
|
void TurnOffXRayEffects( SOLDIERTYPE * pSoldier )
|
|
{
|
|
SOLDIERTYPE * pSoldier2;
|
|
UINT32 uiSlot;
|
|
|
|
if ( !pSoldier->uiXRayActivatedTime )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// scan through all mercs and turn off xrayed flag for anyone
|
|
// xrayed by this guy
|
|
for ( uiSlot = 0; uiSlot < guiNumMercSlots; uiSlot++ )
|
|
{
|
|
pSoldier2 = MercSlots[ uiSlot ];
|
|
if ( pSoldier2 )
|
|
{
|
|
if ( (pSoldier2->ubMiscSoldierFlags & SOLDIER_MISC_XRAYED) && (pSoldier2->aiData.ubXRayedBy == pSoldier->ubID) )
|
|
{
|
|
pSoldier2->ubMiscSoldierFlags &= (~SOLDIER_MISC_XRAYED);
|
|
pSoldier2->aiData.ubXRayedBy = NOBODY;
|
|
}
|
|
}
|
|
}
|
|
pSoldier->uiXRayActivatedTime = 0;
|
|
}
|
|
|
|
|
|
|
|
#ifdef JA2TESTVERSION
|
|
void DumpItemsList( void )
|
|
{
|
|
CHAR8 zPrintFileName[60];
|
|
FILE *FDump;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
// open output file
|
|
strcpy(zPrintFileName, "ItemDump.txt");
|
|
FDump = fopen(zPrintFileName, "wt");
|
|
|
|
if (FDump == NULL)
|
|
return;
|
|
|
|
// print headings
|
|
fprintf(FDump, " ITEM COOLNESS VALUE\n");
|
|
fprintf(FDump, "============================ ======== =====\n");
|
|
|
|
for( usItem = 0; usItem < MAXITEMS; usItem++ )
|
|
{
|
|
pItem= &( Item[ usItem ] );
|
|
|
|
if (pItem->ubCoolness > 0 )
|
|
{
|
|
fprintf(FDump, "%28ls %2d $%4d\n", ItemNames[ usItem ], pItem->ubCoolness, pItem->usPrice );
|
|
}
|
|
}
|
|
|
|
fclose(FDump);
|
|
}
|
|
#endif // JA2TESTVERSION
|
|
|
|
|
|
// Snap: status modifiers for various item bonuses:
|
|
|
|
// In JA Gold status above this limit does not affect item performance (for some items)
|
|
const INT8 STANDARD_STATUS_CUTOFF = 85;
|
|
|
|
// Scale bonus with item status
|
|
INT16 BonusReduce( INT16 bonus, INT16 status, INT16 statusCutoff = STANDARD_STATUS_CUTOFF )
|
|
{
|
|
if ( bonus > 0 && status < statusCutoff && statusCutoff > 0 && statusCutoff <= 100 )
|
|
return ( ( status * 100 ) / statusCutoff * bonus ) / 100;
|
|
else // A penalty can't be reduced by status!
|
|
return bonus;
|
|
}
|
|
|
|
// Scale bonus with item status. Status < 50% creates a penalty!
|
|
INT16 BonusReduceMore( INT16 bonus, INT16 status, INT16 statusCutoff = 100 )
|
|
{
|
|
if ( bonus > 0 && status < statusCutoff && statusCutoff > 0 && statusCutoff <= 100 )
|
|
return ( ( ( status * 100 ) / statusCutoff - 50 ) * bonus ) / 50;
|
|
else // A penalty can't be reduced by status!
|
|
return bonus;
|
|
}
|
|
|
|
// Some items either work or they don't...
|
|
INT16 BonusOnOff( INT16 bonus, INT16 status )
|
|
{
|
|
if ( bonus > 0 )
|
|
return (status >= 50) ? bonus : 0;
|
|
else // A penalty can't be reduced by status!
|
|
return bonus;
|
|
}
|
|
|
|
|
|
// Snap: a fast aimbonus check for AI
|
|
BOOLEAN IsScoped( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if ( Item[pObj->usItem].aimbonus > 0 || Item[(*pObj)[0]->data.gun.usGunAmmoItem].aimbonus > 0 )
|
|
return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( Item[iter->usItem].aimbonus > 0 )
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Snap: get aim bonus for a single item
|
|
INT16 GetItemAimBonus( const INVTYPE* pItem, INT32 iRange, INT16 ubAimTime )
|
|
{
|
|
if ( iRange <= pItem->minrangeforaimbonus ) return 0;
|
|
|
|
// reduce effective sight range by aimbonus% per extra aiming time AP
|
|
// of the distance beyond minrangeforaimbonus.
|
|
if ( pItem->aimbonus < 0)
|
|
ubAimTime = 1;
|
|
|
|
//CHRISL: The old system basically allowed scopes to reduce sight range by AimBonus%/click. So a scope with an
|
|
// AimBonus 20, and 8 clicks, would reduce sight range by 160%. In other words, it would effectively reduce sight
|
|
// range to 0 just for using 8 APs to aim.
|
|
//return ( pItem->aimbonus * ubAimTime * ( iRange - pItem->minrangeforaimbonus ) ) / 100;
|
|
// Instead, let's have the bonus reduce each click seperately and base the percentage on the new range.
|
|
INT16 bonus = 0, stepBonus = 0;
|
|
for( UINT8 step = 0; step < ubAimTime; step++)
|
|
{
|
|
stepBonus = (pItem->aimbonus * iRange)/100;
|
|
iRange -= stepBonus;
|
|
bonus += stepBonus;
|
|
if(iRange < pItem->minrangeforaimbonus)
|
|
{
|
|
stepBonus = pItem->minrangeforaimbonus - iRange;
|
|
bonus -= stepBonus;
|
|
break;
|
|
}
|
|
}
|
|
return(bonus);
|
|
}
|
|
|
|
INT16 GetAimBonus( OBJECTTYPE * pObj, INT32 iRange, INT16 ubAimTime )
|
|
{
|
|
INT16 bonus = 0;
|
|
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduceMore( GetItemAimBonus( &Item[pObj->usItem], iRange, ubAimTime ), (*pObj)[0]->data.objectStatus );
|
|
bonus += GetItemAimBonus( &Item[(*pObj)[0]->data.gun.usGunAmmoItem], iRange, ubAimTime );
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( GetItemAimBonus( &Item[iter->usItem], iRange, ubAimTime ), (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// Madd: check equipment for aim bonus (penalties)
|
|
INT16 GetGearAimBonus( SOLDIERTYPE * pSoldier, INT32 iRange, INT16 ubAimTime )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
for (int j = HELMETPOS; j <= HEAD2POS; j++)
|
|
{
|
|
OBJECTTYPE* pObj = &pSoldier->inv[j];
|
|
if (pObj->exists() == true) {
|
|
bonus += GetItemAimBonus( &Item[pSoldier->inv[j].usItem], iRange, ubAimTime );
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += GetItemAimBonus(&Item[iter->usItem],iRange,ubAimTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// Madd: check equipment for to hit bonus (penalties)
|
|
INT16 GetGearToHitBonus( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
for (int j = HELMETPOS; j <= HEAD2POS; j++)
|
|
{
|
|
OBJECTTYPE* pObj = &pSoldier->inv[j];
|
|
if (pObj->exists() == true) {
|
|
bonus += Item[pSoldier->inv[j].usItem].tohitbonus;
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += Item[iter->usItem].tohitbonus;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// Madd: check equipment for AP bonus (penalties)
|
|
INT16 GetGearAPBonus( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
for (int j = HELMETPOS; j <= HEAD2POS; j++)
|
|
{
|
|
if (pSoldier->inv[j].exists() == true) {
|
|
bonus += Item[pSoldier->inv[j].usItem].APBonus;
|
|
OBJECTTYPE* pObj = &pSoldier->inv[j];
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += Item[iter->usItem].APBonus;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
UINT32 FindRangeBonusAttachment( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].rangebonus > 0 )
|
|
{
|
|
return( Item[iter->usItem].uiIndex );
|
|
}
|
|
}
|
|
}
|
|
return( NONE );
|
|
}
|
|
|
|
INT16 GetRangeBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduce( Item[pObj->usItem].rangebonus, (*pObj)[0]->data.objectStatus );
|
|
|
|
if ( (*pObj)[0]->data.gun.ubGunShotsLeft > 0 )
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].rangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( !Item[iter->usItem].duckbill || ( Item[iter->usItem].duckbill && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT ))
|
|
bonus += BonusReduce( Item[iter->usItem].rangebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
INT16 LaserBonus( const INVTYPE * pItem, INT32 iRange, UINT8 bLightLevel )
|
|
{
|
|
// Snap: Reduce laser scope bonus at long ranges and high light levels
|
|
|
|
if ( pItem->bestlaserrange == 0 || iRange <= pItem->bestlaserrange ) {
|
|
// No penalty within this range
|
|
return pItem->tohitbonus;
|
|
}
|
|
else {
|
|
// Figure out max. visible distance for the laser dot:
|
|
// day: 1.5*bestlaserrange, night: 2.5*bestlaserrange
|
|
// iMaxLaserRange = bestlaserrange * ( 1.5 + ( bLightLevel - NORMAL_LIGHTLEVEL_DAY )
|
|
// / ( NORMAL_LIGHTLEVEL_NIGHT - NORMAL_LIGHTLEVEL_DAY ) )
|
|
INT32 iMaxLaserRange = ( pItem->bestlaserrange*( 2*bLightLevel + 3*NORMAL_LIGHTLEVEL_NIGHT - 5*NORMAL_LIGHTLEVEL_DAY ) )
|
|
/ ( 2 * ( NORMAL_LIGHTLEVEL_NIGHT - NORMAL_LIGHTLEVEL_DAY ) );
|
|
|
|
// Beyond bestlaserrange laser bonus drops linearly to 0
|
|
INT16 bonus = ( pItem->tohitbonus * (iMaxLaserRange - iRange) )
|
|
/ ( iMaxLaserRange - pItem->bestlaserrange );
|
|
|
|
return (bonus > 0 ? bonus : 0);
|
|
}
|
|
}
|
|
|
|
INT16 GetToHitBonus( OBJECTTYPE * pObj, INT32 iRange, UINT8 bLightLevel, BOOLEAN fProneStance )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
// Snap: bipod is effective only in the prone stance
|
|
|
|
if (pObj->exists() == true) {
|
|
if ( fProneStance )
|
|
bonus += Item[pObj->usItem].bipod;
|
|
|
|
bonus += BonusReduceMore( LaserBonus( &Item[pObj->usItem], iRange, bLightLevel), (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].tohitbonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( fProneStance )
|
|
bonus += Item[iter->usItem].bipod;
|
|
|
|
bonus += BonusReduceMore( LaserBonus( &Item[iter->usItem], iRange, bLightLevel), (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
// Snap (TODO): add special treatment of laser scopes
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
// Snap: bipod is effective only in the prone stance
|
|
|
|
if (pObj->exists() == true) {
|
|
if ( fProneStance )
|
|
bonus += Item[pObj->usItem].bipod;
|
|
|
|
bonus += BonusReduceMore( Item[pObj->usItem].bursttohitbonus, (*pObj)[0]->data.objectStatus );
|
|
// HEADROCK HAM B2.5: A certain setting in the New Tracer System can turn auto/burst penalties off
|
|
// entirely, to make up for "Tracer Bump".
|
|
if ( gGameExternalOptions.iRealisticTracers != 1 )
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bursttohitbonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( fProneStance )
|
|
bonus += Item[iter->usItem].bipod;
|
|
|
|
bonus += BonusReduceMore( Item[iter->usItem].bursttohitbonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
INT16 GetDamageBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduce( Item[pObj->usItem].damagebonus, (*pObj)[0]->data.objectStatus );
|
|
|
|
if ( (*pObj)[0]->data.gun.ubGunShotsLeft > 0 )
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].damagebonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduce( Item[iter->usItem].damagebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
INT16 GetMeleeDamageBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduce( Item[pObj->usItem].meleedamagebonus, (*pObj)[0]->data.objectStatus);
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].meleedamagebonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduce( Item[iter->usItem].meleedamagebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
INT16 GetPercentAPReduction( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduceMore( Item[pObj->usItem].percentapreduction, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentapreduction;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].percentapreduction,
|
|
(*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetMagSizeBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusOnOff( Item[pObj->usItem].magsizebonus, (*pObj)[0]->data.objectStatus );
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusOnOff( Item[iter->usItem].magsizebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetBurstSizeBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusOnOff( Item[pObj->usItem].burstsizebonus, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].burstsizebonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusOnOff( Item[iter->usItem].burstsizebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetRateOfFireBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
if (pObj->exists() == true) {
|
|
if( (MAXITEMS <= pObj->usItem) || (MAXITEMS <= (*pObj)[0]->data.gun.usGunAmmoItem) )
|
|
{
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_1, String("GetRateOfFireBonus would crash: pObj->usItem=%d or (*pObj)[0]->data.gun.usGunAmmoItem=%d ist higher than max %d", pObj->usItem, (*pObj)[0]->data.gun.usGunAmmoItem, MAXITEMS ));
|
|
ScreenMsg( MSG_FONT_RED, MSG_DEBUG, L"GetRateOfFireBonus would crash: pObj->usItem=%d or (*pObj)[0]->data.gun.usGunAmmoItem=%d ist higher than max %d", pObj->usItem, (*pObj)[0]->data.gun.usGunAmmoItem, MAXITEMS );
|
|
AssertMsg( 0, "GetRateOfFireBonus would crash" );
|
|
return 0; /* cannot calculate Bonus, this only happens sometimes in FULLSCREEN */
|
|
}
|
|
|
|
bonus = BonusReduceMore( Item[pObj->usItem].rateoffirebonus, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].rateoffirebonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].rateoffirebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
// Snap: bipod is effective only in the prone stance
|
|
|
|
if (pObj->exists() == true) {
|
|
if ( fProneStance )
|
|
bonus += Item[pObj->usItem].bipod;
|
|
|
|
bonus += BonusReduceMore( Item[pObj->usItem].autofiretohitbonus, (*pObj)[0]->data.objectStatus );
|
|
|
|
// HEADROCK HAM B2.5: This external setting determines whether autofire penalty is affected by
|
|
// tracer ammo. At setting "1", it is disabled. This goes hand in hand with a new tracer effect that
|
|
// "bumps" CTH up after firing a tracer bullet.
|
|
if ( gGameExternalOptions.iRealisticTracers != 1 )
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].autofiretohitbonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( fProneStance )
|
|
bonus += Item[iter->usItem].bipod;
|
|
|
|
bonus += BonusReduceMore( Item[iter->usItem].autofiretohitbonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetPercentReadyTimeAPReduction( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduceMore( Item[pObj->usItem].percentreadytimeapreduction, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentreadytimeapreduction;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].percentreadytimeapreduction, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetPercentAutofireAPReduction( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = BonusReduceMore( Item[pObj->usItem].percentautofireapreduction, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentautofireapreduction;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].percentautofireapreduction, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetPercentReloadTimeAPReduction( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
BonusReduceMore( Item[pObj->usItem].percentreloadtimeapreduction, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentreloadtimeapreduction;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].percentreloadtimeapreduction, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetPercentBurstFireAPReduction( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
BonusReduceMore( Item[pObj->usItem].percentburstfireapreduction, (*pObj)[0]->data.objectStatus );
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentburstfireapreduction;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].percentburstfireapreduction, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
INT16 GetVisionRangeBonus( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT16 bonus=0;
|
|
OBJECTTYPE *pObj;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
// CHRISL:
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
// Okay, it's time for some optimization here too
|
|
pObj = &( pSoldier->inv[i]);
|
|
if (pObj->exists() == true) {
|
|
usItem = pObj->usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
// Snap (TODO): binoculars and such should not be active by default
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) && (pItem->usItemClass & IC_ARMOUR || pItem->usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!IsWeapon(usItem) || (IsWeapon(usItem) && usingGunScope == true) )
|
|
{
|
|
bonus += BonusReduceMore( pItem->visionrangebonus, (*pObj)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a readied weapon!
|
|
// 0verhaul: Moved this bug fix into WeaponReady so that all CTH modifier functions may benefit from this fix
|
|
//AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
if ( usingGunScope == true )
|
|
{
|
|
pObj = &( pSoldier->inv[HANDPOS]);
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( Item[iter->usItem].visionrangebonus, (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// Snap: Scale night vision bonus with light level
|
|
INT16 NightBonusScale( INT16 bonus, UINT8 bLightLevel )
|
|
{
|
|
if ( bLightLevel > NORMAL_LIGHTLEVEL_NIGHT ) {
|
|
return idiv( bonus * ( SHADE_MIN - bLightLevel ),
|
|
SHADE_MIN - NORMAL_LIGHTLEVEL_NIGHT );
|
|
}
|
|
else if ( bLightLevel > NORMAL_LIGHTLEVEL_DAY ) {
|
|
return idiv( bonus * (bLightLevel - NORMAL_LIGHTLEVEL_DAY),
|
|
NORMAL_LIGHTLEVEL_NIGHT - NORMAL_LIGHTLEVEL_DAY );
|
|
}
|
|
else return 0;
|
|
}
|
|
|
|
INT16 GetNightVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel )
|
|
{
|
|
INT16 bonus=0;
|
|
OBJECTTYPE *pObj;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
// CHRISL:
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
// More optimization
|
|
pObj = &( pSoldier->inv[i]);
|
|
if (pObj->exists() == true) {
|
|
usItem = pObj->usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
// Snap (TODO): binoculars and such should not be active by default
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) && (pItem->usItemClass & IC_ARMOUR || pItem->usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!IsWeapon(usItem) || (IsWeapon(usItem) && usingGunScope == true ) )
|
|
{
|
|
bonus += BonusReduceMore(
|
|
NightBonusScale( pItem->nightvisionrangebonus, bLightLevel ),
|
|
(*pObj)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a raised weapon!
|
|
if ( usingGunScope == true )
|
|
{
|
|
pObj = &( pSoldier->inv[HANDPOS]);
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore(
|
|
NightBonusScale( Item[iter->usItem].nightvisionrangebonus, bLightLevel ),
|
|
(*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetCaveVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel )
|
|
{
|
|
INT16 bonus=0;
|
|
OBJECTTYPE *pObj;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
// CHRISL:
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
// More optimization
|
|
pObj = &( pSoldier->inv[i]);
|
|
if (pObj->exists() == true) {
|
|
usItem = pObj->usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
// Snap (TODO): binoculars and such should not be active by default
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) &&
|
|
(pItem->usItemClass & IC_ARMOUR || pItem->usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!IsWeapon(usItem) || (IsWeapon(usItem) && usingGunScope == true ) )
|
|
{
|
|
bonus += BonusReduceMore(
|
|
NightBonusScale( pItem->cavevisionrangebonus, bLightLevel ),
|
|
(*pObj)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a raised weapon!
|
|
if ( usingGunScope == true )
|
|
{
|
|
pObj = &( pSoldier->inv[HANDPOS]);
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore(
|
|
NightBonusScale( Item[iter->usItem].cavevisionrangebonus, bLightLevel ),
|
|
(*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetDayVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel )
|
|
{
|
|
INT16 bonus=0;
|
|
OBJECTTYPE *pObj;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
// Snap: Scale the bonus with the light level
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
// CHRISL:
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
// More optimization
|
|
pObj = &( pSoldier->inv[i]);
|
|
if (pObj->exists() == true) {
|
|
usItem = pObj->usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
// Snap (TODO): binoculars and such should not be active by default
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) &&
|
|
(pItem->usItemClass & IC_ARMOUR || pItem->usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!IsWeapon(usItem) || (IsWeapon(usItem) && usingGunScope == true ) )
|
|
{
|
|
bonus += BonusReduceMore( idiv( pItem->dayvisionrangebonus
|
|
* (NORMAL_LIGHTLEVEL_NIGHT - bLightLevel), NORMAL_LIGHTLEVEL_NIGHT ),
|
|
(*pObj)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a raised weapon!
|
|
//CHRISL: Since this is a daytime calculation, I think we want the difference between NORMAL_LIGHTLEVEL_NIGHT and
|
|
// NORMAL_LIGHTLEVEL_DAY. To just use NORMAL_LIGHTLEVEL_NIGHT is the same as basing the calculation off of the
|
|
// difference between NORMAL_LIGHTLEVEL_NIGHT and 0, which represent bright light.
|
|
if ( usingGunScope == true )
|
|
{
|
|
pObj = &( pSoldier->inv[HANDPOS]);
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( idiv( Item[iter->usItem].dayvisionrangebonus
|
|
* (NORMAL_LIGHTLEVEL_NIGHT - __max(bLightLevel,NORMAL_LIGHTLEVEL_DAY)), (NORMAL_LIGHTLEVEL_NIGHT-NORMAL_LIGHTLEVEL_DAY) ),
|
|
(*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetBrightLightVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel )
|
|
{
|
|
INT16 bonus=0;
|
|
OBJECTTYPE *pObj;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
// Snap: Scale the bonus with the light level
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
// CHRISL:
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
// More optimization
|
|
pObj = &( pSoldier->inv[i]);
|
|
if (pObj->exists() == true) {
|
|
usItem = pObj->usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
// Snap (TODO): binoculars and such should not be active by default
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) &&
|
|
(pItem->usItemClass & IC_ARMOUR || pItem->usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!IsWeapon(usItem) || (IsWeapon(usItem) && usingGunScope == true ) )
|
|
{
|
|
bonus += BonusReduceMore( idiv( pItem->brightlightvisionrangebonus
|
|
* (NORMAL_LIGHTLEVEL_DAY - bLightLevel), NORMAL_LIGHTLEVEL_DAY ),
|
|
(*pObj)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a raised weapon!
|
|
if ( usingGunScope == true )
|
|
{
|
|
pObj = &( pSoldier->inv[HANDPOS]);
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduceMore( idiv( Item[iter->usItem].brightlightvisionrangebonus
|
|
* (NORMAL_LIGHTLEVEL_DAY - bLightLevel), NORMAL_LIGHTLEVEL_DAY ),
|
|
(*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
INT16 GetTotalVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel )
|
|
{
|
|
INT16 bonus = GetVisionRangeBonus(pSoldier);
|
|
|
|
if ( bLightLevel > NORMAL_LIGHTLEVEL_DAY )
|
|
{
|
|
if ( pSoldier->pathing.bLevel == 0 )
|
|
{
|
|
bonus += GetNightVisionRangeBonus(pSoldier, bLightLevel);
|
|
}
|
|
else
|
|
{
|
|
bonus += GetCaveVisionRangeBonus(pSoldier, bLightLevel);
|
|
}
|
|
}
|
|
|
|
if ( bLightLevel < NORMAL_LIGHTLEVEL_NIGHT )
|
|
{
|
|
bonus += GetDayVisionRangeBonus(pSoldier, bLightLevel);
|
|
}
|
|
|
|
if ( bLightLevel < NORMAL_LIGHTLEVEL_DAY )
|
|
{
|
|
bonus += GetBrightLightVisionRangeBonus(pSoldier, bLightLevel);
|
|
}
|
|
|
|
return bonus;
|
|
}
|
|
|
|
UINT8 GetPercentTunnelVision( SOLDIERTYPE * pSoldier )
|
|
{
|
|
UINT8 bonus = 0;
|
|
UINT16 usItem;
|
|
INVTYPE *pItem;
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
// CHRISL:
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
// Okay, it's time for some optimization here
|
|
if (pSoldier->inv[i].exists() == true) {
|
|
usItem = pSoldier->inv[i].usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) && (pItem->usItemClass & IC_ARMOUR || pItem->usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( !IsWeapon(usItem) )
|
|
{
|
|
bonus = __max( bonus, pItem->percenttunnelvision );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a raised weapon!
|
|
if ( usingGunScope == true )
|
|
{
|
|
OBJECTTYPE *pObj = &(pSoldier->inv[HANDPOS]);
|
|
if (pObj->exists() == true) {
|
|
usItem = pObj->usItem;
|
|
pItem = &(Item[usItem]);
|
|
|
|
if ( IsWeapon(usItem) ) //if not a weapon, then it was added already above
|
|
bonus += Item[usItem].percenttunnelvision;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += Item[iter->usItem].percenttunnelvision;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( PTR_OURTEAM ) // Madd: adjust tunnel vision by difficulty level
|
|
return( bonus );
|
|
else
|
|
return bonus / gGameOptions.ubDifficultyLevel;
|
|
}
|
|
|
|
|
|
BOOLEAN HasThermalOptics( SOLDIERTYPE * pSoldier )
|
|
{
|
|
|
|
//ADB and AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;)
|
|
bool usingGunScope = WeaponReady(pSoldier);
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
if (pSoldier->inv[i].exists() == true) {
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) &&
|
|
(Item[pSoldier->inv[i].usItem].usItemClass & IC_ARMOUR || Item[pSoldier->inv[i].usItem].usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!IsWeapon(pSoldier->inv[i].usItem) || (IsWeapon(pSoldier->inv[i].usItem) && usingGunScope == true) )
|
|
{
|
|
if (Item[pSoldier->inv[i].usItem].thermaloptics)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snap: check only attachments on a raised weapon!
|
|
if ( usingGunScope == true )
|
|
{
|
|
OBJECTTYPE* pObj = &pSoldier->inv[HANDPOS];
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( Item[iter->usItem].thermaloptics )
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
INT8 FindHearingAid( SOLDIERTYPE * pSoldier )
|
|
{
|
|
for (INT8 i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
if (pSoldier->inv[i].exists() == true) {
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) &&
|
|
(Item[pSoldier->inv[i].usItem].usItemClass & IC_ARMOUR || Item[pSoldier->inv[i].usItem].usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( Item[pSoldier->inv[i].usItem].hearingrangebonus > 0 )
|
|
{
|
|
return( i );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT16 GetHearingRangeBonus( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT16 bonus = 0;
|
|
|
|
for (int i = BODYPOSSTART; i < BODYPOSFINAL; i++)
|
|
{
|
|
if (pSoldier->inv[i].exists() == true) {
|
|
if ( (i == HANDPOS || i == SECONDHANDPOS) &&
|
|
(Item[pSoldier->inv[i].usItem].usItemClass & IC_ARMOUR || Item[pSoldier->inv[i].usItem].usItemClass & IC_FACE ))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bonus += BonusReduceMore( Item[pSoldier->inv[i].usItem].hearingrangebonus, pSoldier->inv[i][0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
BOOLEAN IsDuckbill( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if (Item[pObj->usItem].duckbill || Item[(*pObj)[0]->data.gun.usGunAmmoItem].duckbill )
|
|
return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].duckbill )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
UINT16 GetPercentNoiseVolume( OBJECTTYPE * pObj )
|
|
{
|
|
UINT16 mod = 0;
|
|
if (pObj->exists() == true) {
|
|
mod = 100 - BonusReduce( Item[pObj->usItem].percentnoisereduction, (*pObj)[0]->data.objectStatus );
|
|
mod = mod * ( 100 - Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentnoisereduction ) / 100;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
mod = mod * ( 100 - BonusReduce( Item[iter->usItem].percentnoisereduction, (*iter)[0]->data.objectStatus ) ) / 100;
|
|
}
|
|
}
|
|
|
|
return (mod > 0) ? mod : 0;
|
|
}
|
|
|
|
|
|
INT8 FindGasMask( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < HANDPOS; bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( Item[pSoldier->inv[bLoop].usItem].gasmask )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
|
|
BOOLEAN IsDetonatorAttached( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
//if (Item[pObj->usItem].detonator)
|
|
// return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].detonator )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN IsRemoteDetonatorAttached( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
//if (Item[pObj->usItem].remotedetonator)
|
|
// return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].remotedetonator )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN IsFlashSuppressor( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
//Madd: tracers automatically negate any muzzle flash suppression due to inherent lighting effects
|
|
if (Item[pObj->usItem].usItemClass == IC_GUN && AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].tracerEffect && pSoldier->bDoBurst )
|
|
return FALSE;
|
|
|
|
if (Item[pObj->usItem].hidemuzzleflash )
|
|
return TRUE;
|
|
|
|
if ( Item[(*pObj)[0]->data.gun.usGunAmmoItem].hidemuzzleflash )
|
|
return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].hidemuzzleflash )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
INT16 GetFlashSuppressorStatus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 p=100;
|
|
if (pObj->exists() == true) {
|
|
if (Item[pObj->usItem].hidemuzzleflash )
|
|
p=(*pObj)[0]->data.objectStatus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].hidemuzzleflash )
|
|
{
|
|
p =p+ (*iter)[0]->data.objectStatus;
|
|
}
|
|
}
|
|
}
|
|
p = min(p,100);
|
|
return p;
|
|
}
|
|
|
|
BOOLEAN IsGrenadeLauncherAttached( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if (Item[pObj->usItem].grenadelauncher )
|
|
return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].grenadelauncher )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
OBJECTTYPE* FindAttachment_GrenadeLauncher( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if (Item[pObj->usItem].grenadelauncher )
|
|
return pObj;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].grenadelauncher )
|
|
{
|
|
return( &(*iter) );
|
|
}
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
INT16 GetGrenadeLauncherStatus( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if (Item[pObj->usItem].grenadelauncher )
|
|
return (*pObj)[0]->data.objectStatus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].grenadelauncher )
|
|
{
|
|
return( (*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
}
|
|
return( ITEM_NOT_FOUND );
|
|
}
|
|
UINT16 GetAttachedGrenadeLauncher( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
if (Item[pObj->usItem].grenadelauncher )
|
|
return pObj->usItem;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].grenadelauncher )
|
|
{
|
|
return( (UINT16) Item[iter->usItem].uiIndex );
|
|
}
|
|
}
|
|
}
|
|
return( NONE );
|
|
}
|
|
|
|
|
|
INT16 GetAttachedArmourBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += BonusReduce( Armour[Item[iter->usItem].ubClassIndex].ubProtection,
|
|
(*iter)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
|
|
INT16 GetBulletSpeedBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if (pObj->exists() == true) {
|
|
bonus = Item[pObj->usItem].bulletspeedbonus ;
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bulletspeedbonus ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus = bonus +Item[iter->usItem].bulletspeedbonus ;
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|
|
BOOLEAN EXPLOSIVE_GUN ( UINT16 x)
|
|
{
|
|
//DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("EXPLOSIVE_GUN x = %d",x));
|
|
|
|
if ( Item[x].rocketlauncher || Item[x].cannon )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
INT8 FindRocketLauncherOrCannon( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].rocketlauncher || Item[pSoldier->inv[bLoop].usItem].cannon )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindRocketLauncher( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].rocketlauncher )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindCannon( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( Item[pSoldier->inv[bLoop].usItem].cannon )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
INT8 FindUsableCrowbar( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if ( Item[pSoldier->inv[bLoop].usItem].crowbar && pSoldier->inv[bLoop][0]->data.objectStatus >= USABLE )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
OBJECTTYPE* FindAttachedBatteries( OBJECTTYPE * pObj )
|
|
{
|
|
if (pObj->exists() == true) {
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].batteries )
|
|
{
|
|
return( &(*iter) );
|
|
}
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
INT8 FindToolkit( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].toolkit )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindMedKit( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].medicalkit )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindFirstAidKit( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].firstaidkit )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindCamoKit( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].camouflagekit )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindLocksmithKit( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].locksmithkit )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindWalkman( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = BODYPOSSTART; bLoop < BODYPOSFINAL; bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].walkman )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindTrigger( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].remotetrigger )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
INT8 FindRemoteControl( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for (bLoop = BODYPOSSTART; bLoop < BODYPOSFINAL; bLoop++)
|
|
{
|
|
if (pSoldier->inv[bLoop].exists() == true) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].robotremotecontrol )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
UINT16 LowestLaunchableCoolness(UINT16 launcherIndex)
|
|
{
|
|
UINT16 i = 0;
|
|
UINT16 lowestCoolness = 999;
|
|
|
|
for( i = 0; i < MAXITEMS; i++ )
|
|
{
|
|
if ( Item[i].usItemClass == 0 )
|
|
break;
|
|
|
|
if( ValidLaunchable( i, launcherIndex ) && ItemIsLegal(i) && Item[i].ubCoolness <= lowestCoolness )
|
|
{
|
|
lowestCoolness = Item[i].ubCoolness;
|
|
}
|
|
}
|
|
return lowestCoolness;
|
|
}
|
|
|
|
UINT16 PickARandomLaunchable(UINT16 itemIndex)
|
|
{
|
|
UINT16 usNumMatches = 0;
|
|
UINT16 usRandom = 0;
|
|
UINT16 i = 0;
|
|
UINT16 lowestCoolness = LowestLaunchableCoolness(itemIndex);
|
|
//DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("PickARandomLaunchable: itemIndex = %d", itemIndex));
|
|
|
|
while( !usNumMatches )
|
|
{ //Count the number of valid launchables
|
|
for( i = 0; i < MAXITEMS; i++ )
|
|
{
|
|
if ( Item[i].usItemClass == 0 )
|
|
break;
|
|
//Madd: quickfix: make it not choose best grenades right away.
|
|
if( ValidLaunchable( i, itemIndex ) && ItemIsLegal(i) && Item[i].ubCoolness <= max(HighestPlayerProgressPercentage()/10,lowestCoolness) )
|
|
usNumMatches++;
|
|
}
|
|
}
|
|
if( usNumMatches )
|
|
{
|
|
usRandom = (UINT16)Random( usNumMatches );
|
|
for( i = 0; i < MAXITEMS; i++ )
|
|
{
|
|
if ( Item[i].usItemClass == 0 )
|
|
break;
|
|
|
|
if( ValidLaunchable( i, itemIndex ) && ItemIsLegal(i) && Item[i].ubCoolness <= max(HighestPlayerProgressPercentage()/10,lowestCoolness) )
|
|
{
|
|
if( usRandom )
|
|
usRandom--;
|
|
else
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
INT16 GetCamoBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if ( pObj->exists() == true ) {
|
|
bonus = (Item[pObj->usItem].camobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (!Item[iter->usItem].camouflagekit)
|
|
bonus += (INT16) (Item[iter->usItem].camobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
INT16 GetUrbanCamoBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if ( pObj->exists() == true ) {
|
|
bonus = (Item[pObj->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (!Item[iter->usItem].camouflagekit)
|
|
bonus += (INT16) (Item[iter->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
INT16 GetDesertCamoBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if ( pObj->exists() == true ) {
|
|
bonus = (Item[pObj->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (!Item[iter->usItem].camouflagekit)
|
|
bonus += (INT16) (Item[iter->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
INT16 GetSnowCamoBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if ( pObj->exists() == true ) {
|
|
bonus = (Item[pObj->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (!Item[iter->usItem].camouflagekit)
|
|
bonus += (INT16) (Item[iter->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100));
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
INT16 GetWornCamo( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 ttl=0;
|
|
|
|
for (bLoop = HELMETPOS; bLoop <= LEGPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
{
|
|
ttl += GetCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
}
|
|
|
|
// CHRISL: Add additional loop for LBE items while using new inventory system
|
|
if((UsingNewInventorySystem() == true))
|
|
{
|
|
for (bLoop = VESTPOCKPOS; bLoop <= BPACKPOCKPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetCamoBonus(&pSoldier->inv[bLoop]);
|
|
//CHRISL: to prevent camo overlap, don't count armor vest camo if we're weaing an LBE vest that grants a bonus
|
|
if(bLoop == VESTPOCKPOS && pSoldier->inv[VESTPOS].exists() == true && Item[pSoldier->inv[bLoop].usItem].camobonus > 0)
|
|
{
|
|
ttl -= Item[pSoldier->inv[VESTPOS].usItem].camobonus;
|
|
}
|
|
}
|
|
}
|
|
|
|
return __min( ttl, 100 );
|
|
}
|
|
INT16 GetWornUrbanCamo( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 ttl=0;
|
|
|
|
for (bLoop = HELMETPOS; bLoop <= LEGPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetUrbanCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
|
|
// CHRISL: Add additional loop for LBE items while using new inventory system
|
|
if((UsingNewInventorySystem() == true))
|
|
{
|
|
for (bLoop = VESTPOCKPOS; bLoop <= BPACKPOCKPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetUrbanCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
}
|
|
|
|
return __min( ttl, 100 );
|
|
}
|
|
INT16 GetWornDesertCamo( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 ttl=0;
|
|
|
|
for (bLoop = HELMETPOS; bLoop <= LEGPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetDesertCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
|
|
// CHRISL: Add additional loop for LBE items while using new inventory system
|
|
if((UsingNewInventorySystem() == true))
|
|
{
|
|
for (bLoop = VESTPOCKPOS; bLoop <= BPACKPOCKPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetDesertCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
}
|
|
return __min( ttl, 100 );
|
|
}
|
|
INT16 GetWornSnowCamo( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 ttl=0;
|
|
|
|
for (bLoop = HELMETPOS; bLoop <= LEGPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetSnowCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
|
|
// CHRISL: Add additional loop for LBE items while using new inventory system
|
|
if((UsingNewInventorySystem() == true))
|
|
{
|
|
for (bLoop = VESTPOCKPOS; bLoop <= BPACKPOCKPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetSnowCamoBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
}
|
|
return __min( ttl, 100 );
|
|
}
|
|
|
|
void ApplyEquipmentBonuses(SOLDIERTYPE * pSoldier)
|
|
{
|
|
if ( pSoldier == NULL) return;
|
|
|
|
INT16 newCamo = GetWornCamo ( pSoldier );
|
|
INT16 oldCamo = pSoldier->wornCamo;
|
|
if ( oldCamo != newCamo )
|
|
pSoldier->wornCamo = (INT8)newCamo;
|
|
|
|
INT16 newUrbanCamo = GetWornUrbanCamo ( pSoldier );
|
|
INT16 oldUrbanCamo = pSoldier->wornUrbanCamo;
|
|
if ( oldUrbanCamo != newUrbanCamo )
|
|
pSoldier->wornUrbanCamo = (INT8)newUrbanCamo;
|
|
|
|
INT16 newDesertCamo = GetWornDesertCamo ( pSoldier );
|
|
INT16 oldDesertCamo = pSoldier->wornDesertCamo;
|
|
if ( oldDesertCamo != newDesertCamo )
|
|
pSoldier->wornDesertCamo = (INT8)newDesertCamo;
|
|
|
|
INT16 newSnowCamo = GetWornSnowCamo ( pSoldier );
|
|
INT16 oldSnowCamo = pSoldier->wornSnowCamo;
|
|
if ( oldSnowCamo != newSnowCamo )
|
|
pSoldier->wornSnowCamo = (INT8)newSnowCamo;
|
|
|
|
if ( (newCamo > oldCamo || newUrbanCamo > oldUrbanCamo || newDesertCamo > oldDesertCamo || newSnowCamo > oldSnowCamo )&& pSoldier->bTeam == OUR_TEAM )
|
|
{
|
|
//CHRISL: This sound interferes with some RPC hiring in NewInv because of the camo bonus some LBE Vests give
|
|
if(UsingNewInventorySystem() == false)
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 );
|
|
|
|
// WANNE: Only call the method if oldCame != newCamo
|
|
if ( pSoldier->bInSector)
|
|
pSoldier->CreateSoldierPalettes( );
|
|
}
|
|
else if ( (newCamo < oldCamo || newUrbanCamo < oldUrbanCamo || newDesertCamo < oldDesertCamo || newSnowCamo < oldSnowCamo )&& pSoldier->bTeam == OUR_TEAM )
|
|
{
|
|
// WANNE: Only call the method if oldCame != newCamo
|
|
if ( pSoldier->bInSector)
|
|
pSoldier->CreateSoldierPalettes( );
|
|
}
|
|
// WANNE: Madd, I commented this, because this leads to IRAs INVISIBLE BUG!
|
|
// We should only call the CreateSoldierPalettes if oldCamo != newCamo. See above!
|
|
//Madd: do this regardless of camo. This will need to be called to do custom part colours and new overlays anyway.
|
|
//if ( pSoldier->bInSector)
|
|
// pSoldier->CreateSoldierPalettes( );
|
|
|
|
fInterfacePanelDirty = DIRTYLEVEL2;
|
|
}
|
|
|
|
UINT16 GetFirstExplosiveOfType(UINT16 expType)
|
|
{
|
|
for (int i=0;i<MAXITEMS;i++)
|
|
{
|
|
if ( (Item[i].usItemClass == IC_EXPLOSV || Item[i].usItemClass == IC_GRENADE) && Explosive[Item[i].ubClassIndex].ubType == expType )
|
|
return i;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// WDS - Smart goggle switching
|
|
OBJECTTYPE* FindSunGogglesInInv( SOLDIERTYPE * pSoldier, BOOLEAN searchAllInventory )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 bonusToBeat = 0;
|
|
OBJECTTYPE* pGoggles = 0;
|
|
// CHRISL:
|
|
for (bLoop = (searchAllInventory ? HELMETPOS : HANDPOS); bLoop < NUM_INV_SLOTS; bLoop++) {
|
|
if ( pSoldier->inv[bLoop].exists() == true ) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].brightlightvisionrangebonus > bonusToBeat && Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) {
|
|
pGoggles = &(pSoldier->inv[bLoop]);
|
|
bonusToBeat = Item[pSoldier->inv[bLoop].usItem].brightlightvisionrangebonus;
|
|
}
|
|
if (searchAllInventory) {
|
|
OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]);
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( Item[ iter->usItem ].brightlightvisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE ) {
|
|
pGoggles = &(*iter);
|
|
bonusToBeat = Item[ iter->usItem ].brightlightvisionrangebonus;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return( pGoggles );
|
|
}
|
|
|
|
OBJECTTYPE* FindNightGogglesInInv( SOLDIERTYPE * pSoldier, BOOLEAN searchAllInventory )
|
|
{
|
|
INT8 bLoop;
|
|
INT16 bonusToBeat = 0;
|
|
OBJECTTYPE* pGoggles = 0;
|
|
// CHRISL:
|
|
for (bLoop = (searchAllInventory ? HELMETPOS : HANDPOS); bLoop < NUM_INV_SLOTS; bLoop++) {
|
|
if ( pSoldier->inv[bLoop].exists() == true ) {
|
|
if (Item[pSoldier->inv[bLoop].usItem].nightvisionrangebonus > bonusToBeat && Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) {
|
|
pGoggles = &(pSoldier->inv[bLoop]);
|
|
bonusToBeat = Item[pSoldier->inv[bLoop].usItem].nightvisionrangebonus;
|
|
}
|
|
if (searchAllInventory) {
|
|
OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]);
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( Item[ iter->usItem ].nightvisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE ) {
|
|
pGoggles = &(*iter);
|
|
bonusToBeat = Item[ iter->usItem ].nightvisionrangebonus;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return( pGoggles );
|
|
}
|
|
|
|
INT16 GetMinRangeForAimBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
|
|
if ( pObj->exists() == true ) {
|
|
bonus = Item[pObj->usItem].minrangeforaimbonus;
|
|
//bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].minrangeforaimbonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += Item[iter->usItem].minrangeforaimbonus;
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier)
|
|
{
|
|
UINT8 aimLevels = 4;
|
|
float iScopeBonus = 0;
|
|
BOOLEAN allowed = TRUE;
|
|
|
|
// HEADROCK HAM B2.6: Dynamic aiming level restrictions based on gun type and attachments.
|
|
if ( gGameExternalOptions.fDynamicAimingTime )
|
|
{
|
|
UINT16 weaponRange;
|
|
UINT8 weaponType, maxAimForType, maxAimWithoutBipod;
|
|
BOOLEAN fTwoHanded, fUsingBipod;
|
|
|
|
// Read weapon data
|
|
fTwoHanded = Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded;
|
|
weaponRange = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usRange + GetRangeBonus(&pSoldier->inv[pSoldier->ubAttackingHand]);
|
|
weaponType = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType;
|
|
fUsingBipod = FALSE;
|
|
|
|
maxAimWithoutBipod = 4;
|
|
|
|
// Define basic (no attachments), and absolute maximums
|
|
if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || (weaponType == GUN_SMG && fTwoHanded == 0) || fTwoHanded == 0)
|
|
{
|
|
maxAimForType = 2;
|
|
aimLevels = 1;
|
|
maxAimWithoutBipod = 2;
|
|
}
|
|
else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || (weaponType == GUN_SMG && fTwoHanded == 1))
|
|
{
|
|
maxAimForType = 3;
|
|
aimLevels = 2;
|
|
maxAimWithoutBipod = 3;
|
|
}
|
|
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && weaponRange <= 500)
|
|
{
|
|
maxAimForType = 4;
|
|
aimLevels = 2;
|
|
maxAimWithoutBipod = 3;
|
|
}
|
|
else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && weaponRange > 500)
|
|
{
|
|
maxAimForType = 8;
|
|
aimLevels = 3;
|
|
maxAimWithoutBipod = 4;
|
|
}
|
|
else
|
|
{
|
|
return 4;
|
|
}
|
|
|
|
// Determine whether a bipod is being used (prone)
|
|
if (GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])>0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE )
|
|
{
|
|
fUsingBipod = TRUE;
|
|
}
|
|
|
|
iScopeBonus = ( (float)gGameExternalOptions.ubStraightSightRange * GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) / 100 );
|
|
|
|
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
|
|
{
|
|
aimLevels = (UINT8)((float)aimLevels * (float)2);
|
|
}
|
|
|
|
else if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.3) ) // >= 30% of sight range (~4 tiles by default)
|
|
{
|
|
aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5);
|
|
}
|
|
|
|
// Smaller scopes increase by one.
|
|
else if ( iScopeBonus > 0 )
|
|
{
|
|
aimLevels++;
|
|
}
|
|
|
|
// Make sure not over maximum allowed for weapon type.
|
|
if (aimLevels > maxAimForType)
|
|
{
|
|
aimLevels = maxAimForType;
|
|
}
|
|
// Make sure not over maximum allowed without a bipod.
|
|
if (!fUsingBipod)
|
|
{
|
|
aimLevels = __min(aimLevels, maxAimWithoutBipod);
|
|
}
|
|
}
|
|
else // JA2 1.13 Basic aiming restrictions (8 levels for 10x scope, 6 levels for 7x scope)
|
|
{
|
|
if ( gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType != GUN_RIFLE && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType != GUN_SN_RIFLE )
|
|
allowed = FALSE;
|
|
|
|
if ( allowed && IsScoped( &pSoldier->inv[pSoldier->ubAttackingHand] ) )
|
|
{
|
|
iScopeBonus = ( (float)gGameExternalOptions.ubStraightSightRange * GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) / 100 );
|
|
|
|
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.3) ) // >= 30% of sight range (~4 tiles by default)
|
|
{
|
|
aimLevels += 2;
|
|
}
|
|
|
|
if ( iScopeBonus >= ( (float)gGameExternalOptions.ubStraightSightRange * 0.6) ) // >= 60% of sight range (~9 tiles by default)
|
|
{
|
|
aimLevels += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return aimLevels;
|
|
}
|
|
//Madd: added
|
|
INT16 GetStealthBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if ( pObj->exists() == true ) {
|
|
bonus = BonusReduce(Item[pObj->usItem].stealthbonus,(*pObj)[0]->data.objectStatus);
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += (INT16) BonusReduce(Item[iter->usItem].stealthbonus,(*iter)[0]->data.objectStatus);
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
INT16 GetWornStealth( SOLDIERTYPE * pSoldier )
|
|
{
|
|
//note: Stealth bonus is capped at 100
|
|
//note: Stealth is not a perk! Stealth bonus only applies to equipment, and stacks with camouflage
|
|
//note: stealth bonus is not affected by terrain like the camo bonus, otherwise they're very similar
|
|
//note: stealth bonus also affects noise made by characters walking
|
|
INT8 bLoop;
|
|
INT16 ttl=0;
|
|
|
|
for (bLoop = HELMETPOS; bLoop <= LEGPOS; bLoop++)
|
|
{
|
|
if ( pSoldier->inv[bLoop].exists() == true )
|
|
ttl += GetStealthBonus(&pSoldier->inv[bLoop]);
|
|
}
|
|
|
|
return __min( ttl, 100 );
|
|
}
|
|
|
|
|
|
/////////////////////////////
|
|
// HEADROCK: Several functions created for the Enhanced Description Box project, but may generally be useful some
|
|
// day. They calculate item bonuses, ammo bonuses and attachment bonuses, without requiring a SOLDIERTYPE or any
|
|
// other variable.
|
|
////////////////////////////
|
|
|
|
// HEADROCK: Function to get the total aim-bonus from the gun and its attachments
|
|
INT16 GetFlatAimBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
|
|
bonus += Item[pObj->usItem].aimbonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].aimbonus;
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// HEADROCK: Function to get the final Loudness value of a gun, after ammo and attachment reductions
|
|
INT16 GetFinalLoudness( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 loudness = 0;
|
|
INT16 loudnessModifier = 0;
|
|
|
|
loudness = Weapon[Item[pObj->usItem].ubClassIndex].ubAttackVolume;
|
|
|
|
loudnessModifier += Item[pObj->usItem].percentnoisereduction;
|
|
|
|
if ( (*pObj)[0]->data.gun.ubGunShotsLeft > 0 )
|
|
loudnessModifier += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentnoisereduction ;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
loudnessModifier += BonusReduce( Item[iter->usItem].percentnoisereduction, (*iter)[0]->data.objectStatus ) ;
|
|
}
|
|
|
|
loudness = loudness * ( 100 - loudnessModifier ) / 100;
|
|
loudness = __max(loudness, 1);
|
|
|
|
return ( loudness );
|
|
}
|
|
|
|
// HEADROCK: Function to get AP bonus from an item rather than a soldier
|
|
|
|
INT16 GetAPBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
bonus += Item[ pObj->usItem ].APBonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].APBonus;
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// HEADROCK: Alternative function to determine flat to-hit bonus of weapon
|
|
INT16 GetFlatToHitBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
bonus = Item[pObj->usItem].tohitbonus;
|
|
bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].tohitbonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].tohitbonus;
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// HEADROCK: Function to get average of all "best laser range" attributes from weapon and attachments
|
|
INT16 GetAverageBestLaserRange( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus=0;
|
|
INT16 numModifiers=0;
|
|
|
|
if (Item[pObj->usItem].bestlaserrange > 0)
|
|
{
|
|
numModifiers++;
|
|
bonus += Item[pObj->usItem].bestlaserrange;
|
|
}
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
if (Item[iter->usItem].bestlaserrange > 0)
|
|
{
|
|
numModifiers++;
|
|
bonus += Item[iter->usItem].bestlaserrange;
|
|
}
|
|
}
|
|
|
|
if (numModifiers>0)
|
|
{
|
|
bonus = bonus / numModifiers;
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// HEADROCK: This function determines the bipod bonii of the gun or its attachments
|
|
INT16 GetBipodBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus=0;
|
|
|
|
bonus = Item[pObj->usItem].bipod;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].bipod;
|
|
}
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// HEADROCK: Added a function to calculate the vision range bonus of an object and its attachments. Takes an argument which determines what type
|
|
// of vision range bonus we want to get:
|
|
// 0 - Regular
|
|
// 1 - Day
|
|
// 2 - Night
|
|
// 3 - Bright Light
|
|
// 4 - Cave
|
|
INT16 GetItemVisionRangeBonus( OBJECTTYPE * pObj, INT16 VisionType )
|
|
{
|
|
INT16 bonus = 0;
|
|
|
|
if (VisionType == 0)
|
|
{
|
|
bonus += Item[ pObj->usItem ].visionrangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].visionrangebonus;
|
|
}
|
|
}
|
|
else if (VisionType == 1)
|
|
{
|
|
bonus += Item[ pObj->usItem ].dayvisionrangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].dayvisionrangebonus;
|
|
}
|
|
}
|
|
else if (VisionType == 2)
|
|
{
|
|
bonus += Item[ pObj->usItem ].nightvisionrangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].nightvisionrangebonus;
|
|
}
|
|
}
|
|
else if (VisionType == 3)
|
|
{
|
|
bonus += Item[ pObj->usItem ].brightlightvisionrangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].brightlightvisionrangebonus;
|
|
}
|
|
}
|
|
else if (VisionType == 4)
|
|
{
|
|
bonus += Item[ pObj->usItem ].cavevisionrangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].cavevisionrangebonus;
|
|
}
|
|
}
|
|
|
|
return( bonus );
|
|
|
|
}
|
|
|
|
// HEADROCK: function to get Tunnel Vision percent from an item and its attachments
|
|
|
|
UINT8 GetItemPercentTunnelVision( OBJECTTYPE * pObj )
|
|
{
|
|
UINT8 bonus = 0;
|
|
|
|
bonus += Item[ pObj->usItem ].percenttunnelvision;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[iter->usItem].percenttunnelvision;
|
|
}
|
|
|
|
bonus = __min(bonus, 100);
|
|
|
|
return( bonus );
|
|
}
|
|
|
|
// HEADROCK: Function to calculate hearing range bonus without SOLDIERTYPE, from an item and its attachments
|
|
INT16 GetItemHearingRangeBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
|
|
bonus += Item[ pObj->usItem ].hearingrangebonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
|
|
{
|
|
bonus += Item[ iter->usItem ].hearingrangebonus;
|
|
}
|
|
|
|
return( bonus );
|
|
|
|
}
|
|
|
|
// HEADROCK: Flash Suppression Detector function that does not use SOLDIERTYPE.
|
|
BOOLEAN IsFlashSuppressorAlt( OBJECTTYPE * pObj )
|
|
{
|
|
if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].tracerEffect )
|
|
return FALSE;
|
|
|
|
if ( Item[pObj->usItem].hidemuzzleflash )
|
|
return TRUE;
|
|
|
|
if ( Item[(*pObj)[0]->data.gun.usGunAmmoItem].hidemuzzleflash )
|
|
return TRUE;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if (Item[iter->usItem].hidemuzzleflash )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
// HEADROCK: Calculate stealth not based on item status
|
|
INT16 GetBasicStealthBonus( OBJECTTYPE * pObj )
|
|
{
|
|
INT16 bonus = 0;
|
|
if ( pObj->exists() == true ) {
|
|
bonus = Item[pObj->usItem].stealthbonus;
|
|
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
bonus += (INT16) Item[iter->usItem].stealthbonus;
|
|
}
|
|
}
|
|
return( bonus );
|
|
}
|
|
|