Soldier Profile.c 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480
  1. #ifdef PRECOMPILEDHEADERS
  2. #include "Tactical All.h"
  3. #else
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include "wcheck.h"
  7. #include "stdlib.h"
  8. #include "debug.h"
  9. #include "math.h"
  10. #include "worlddef.h"
  11. #include "worldman.h"
  12. #include "renderworld.h"
  13. #include "Soldier Control.h"
  14. #include "Animation Control.h"
  15. #include "Animation Data.h"
  16. #include "Isometric Utils.h"
  17. #include "Event Pump.h"
  18. #include "Timer Control.h"
  19. #include "Render Fun.h"
  20. #include "Render Dirty.h"
  21. #include "mousesystem.h"
  22. #include "interface.h"
  23. #include "sysutil.h"
  24. #include "FileMan.h"
  25. #include "points.h"
  26. #include "Random.h"
  27. #include "ai.h"
  28. #include "Interactive Tiles.h"
  29. #include "soldier ani.h"
  30. #include "english.h"
  31. #include "overhead.h"
  32. #include "Soldier Profile.h"
  33. #include "Game Clock.h"
  34. #include "assignments.h"
  35. #include "Dialogue Control.h"
  36. #include "soldier create.h"
  37. #include "soldier add.h"
  38. #include "opplist.h"
  39. #include "weapons.h"
  40. #include "Strategic Town Loyalty.h"
  41. #include "squads.h"
  42. #include "Tactical Save.h"
  43. #include "Quests.h"
  44. #include "aim.h"
  45. #include "Interface Dialogue.h"
  46. #include "GameSettings.h"
  47. #include "strategic town reputation.h"
  48. #endif
  49. #ifdef JA2EDITOR
  50. extern BOOLEAN gfProfileDataLoaded;
  51. #endif
  52. BOOLEAN gfPotentialTeamChangeDuringDeath = FALSE;
  53. #define MIN_BLINK_FREQ 3000
  54. #define MIN_EXPRESSION_FREQ 2000
  55. #define SET_PROFILE_GAINS2 500, 500, 500, 500, 500, 500, 500, 500, 500
  56. MERCPROFILESTRUCT gMercProfiles[ NUM_PROFILES ];
  57. INT8 gbSkillTraitBonus[NUM_SKILLTRAITS] =
  58. {
  59. 0, //NO_SKILLTRAIT
  60. 25, //LOCKPICKING
  61. 15, //HANDTOHAND
  62. 15, //ELECTRONICS
  63. 15, //NIGHTOPS
  64. 12, //THROWING
  65. 15, //TEACHING
  66. 15, //HEAVY_WEAPS
  67. 0, //AUTO_WEAPS
  68. 15, //STEALTHY
  69. 0, //AMBIDEXT
  70. 0, //THIEF // UNUSED!
  71. 30, //MARTIALARTS
  72. 30, //KNIFING
  73. 15, //ONROOF
  74. 0, //CAMOUFLAGED
  75. };
  76. UINT8 gubBasicInventoryPositions[] = {
  77. HELMETPOS,
  78. VESTPOS,
  79. LEGPOS,
  80. HANDPOS,
  81. BIGPOCK1POS,
  82. BIGPOCK2POS,
  83. BIGPOCK3POS,
  84. BIGPOCK4POS
  85. };
  86. #define NUM_TERRORISTS 6
  87. UINT8 gubTerrorists[NUM_TERRORISTS + 1] =
  88. {
  89. DRUGGIST,
  90. SLAY,
  91. ANNIE,
  92. CHRIS,
  93. TIFFANY,
  94. T_REX,
  95. 0
  96. };
  97. UINT8 gubNumTerrorists = 0;
  98. #define NUM_TERRORIST_POSSIBLE_LOCATIONS 5
  99. INT16 gsTerroristSector[NUM_TERRORISTS][NUM_TERRORIST_POSSIBLE_LOCATIONS][2] =
  100. {
  101. // Elgin... preplaced
  102. {
  103. { 0, 0 },
  104. { 0, 0 },
  105. { 0, 0 },
  106. { 0, 0 },
  107. { 0, 0 }
  108. },
  109. // Slay
  110. {
  111. { 9, MAP_ROW_F },
  112. { 14, MAP_ROW_I },
  113. { 1, MAP_ROW_G },
  114. { 2, MAP_ROW_G },
  115. { 8, MAP_ROW_G }
  116. },
  117. // Matron
  118. {
  119. { 14, MAP_ROW_I },
  120. { 6, MAP_ROW_C },
  121. { 2, MAP_ROW_B },
  122. { 11, MAP_ROW_L },
  123. { 8, MAP_ROW_G }
  124. },
  125. // Imposter
  126. {
  127. { 1, MAP_ROW_G },
  128. { 9, MAP_ROW_F },
  129. { 11, MAP_ROW_L },
  130. { 8, MAP_ROW_G },
  131. { 2, MAP_ROW_G }
  132. },
  133. // Tiffany
  134. {
  135. { 14, MAP_ROW_I },
  136. { 2, MAP_ROW_G },
  137. { 14, MAP_ROW_H },
  138. { 6, MAP_ROW_C },
  139. { 2, MAP_ROW_B }
  140. },
  141. // Rexall
  142. {
  143. { 9, MAP_ROW_F },
  144. { 14, MAP_ROW_H },
  145. { 2, MAP_ROW_H },
  146. { 1, MAP_ROW_G },
  147. { 2, MAP_ROW_B }
  148. }
  149. };
  150. INT16 gsRobotGridNo;
  151. #define NUM_ASSASSINS 6
  152. UINT8 gubAssassins[NUM_ASSASSINS] =
  153. {
  154. JIM,
  155. JACK,
  156. OLAF,
  157. RAY,
  158. OLGA,
  159. TYRONE
  160. };
  161. #define NUM_ASSASSIN_POSSIBLE_TOWNS 5
  162. INT8 gbAssassinTown[NUM_ASSASSINS][NUM_ASSASSIN_POSSIBLE_TOWNS] =
  163. {
  164. // Jim
  165. { CAMBRIA, DRASSEN, ALMA, BALIME, GRUMM },
  166. // Jack
  167. { CHITZENA, ESTONI, ALMA, BALIME, GRUMM },
  168. // Olaf
  169. { DRASSEN, ESTONI, ALMA, CAMBRIA, BALIME },
  170. // Ray
  171. { CAMBRIA, OMERTA, BALIME, GRUMM, DRASSEN },
  172. // Olga
  173. { CHITZENA, OMERTA, CAMBRIA, ALMA, GRUMM },
  174. // Tyrone
  175. { CAMBRIA, BALIME, ALMA, GRUMM, DRASSEN },
  176. };
  177. UINT16 CalcCompetence( MERCPROFILESTRUCT * pProfile );
  178. INT16 CalcMedicalDeposit( MERCPROFILESTRUCT * pProfile );
  179. extern void HandleEndDemoInCreatureLevel( );
  180. void DecideActiveTerrorists( void );
  181. extern SOLDIERTYPE *gpSMCurrentMerc;
  182. extern BOOLEAN gfRerenderInterfaceFromHelpText;
  183. BOOLEAN LoadMercProfiles(void)
  184. {
  185. // FILE *fptr;
  186. HWFILE fptr;
  187. char *pFileName = "BINARYDATA\\Prof.dat";
  188. UINT32 uiLoop, uiLoop2, uiLoop3;
  189. UINT16 usItem, usNewGun, usAmmo, usNewAmmo;
  190. UINT32 uiNumBytesRead;
  191. fptr = FileOpen(pFileName, FILE_ACCESS_READ, FALSE );
  192. if( !fptr )
  193. {
  194. DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("FAILED to LoadMercProfiles from file %s", pFileName) );
  195. return(FALSE);
  196. }
  197. for(uiLoop=0; uiLoop< NUM_PROFILES; uiLoop++)
  198. {
  199. if( JA2EncryptedFileRead( fptr, &gMercProfiles[uiLoop], sizeof( MERCPROFILESTRUCT ), &uiNumBytesRead ) != 1)
  200. {
  201. DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("FAILED to Read Merc Profiles from File %d %s",uiLoop, pFileName) );
  202. FileClose( fptr );
  203. return(FALSE);
  204. }
  205. //if the Dialogue exists for the merc, allow the merc to be hired
  206. if( DialogueDataFileExistsForProfile( (UINT8)uiLoop, 0, FALSE, NULL ) )
  207. {
  208. gMercProfiles[uiLoop].bMercStatus = 0;
  209. }
  210. else
  211. gMercProfiles[uiLoop].bMercStatus = MERC_HAS_NO_TEXT_FILE;
  212. // if the merc has a medical deposit
  213. if( gMercProfiles[ uiLoop ].bMedicalDeposit )
  214. {
  215. gMercProfiles[uiLoop].sMedicalDepositAmount = CalcMedicalDeposit( &gMercProfiles[uiLoop]);
  216. }
  217. else
  218. gMercProfiles[uiLoop].sMedicalDepositAmount = 0;
  219. // ATE: New, face display indipendent of ID num now
  220. // Setup face index value
  221. // Default is the ubCharNum
  222. gMercProfiles[uiLoop].ubFaceIndex = (UINT8)uiLoop;
  223. #ifndef JA2DEMO
  224. if ( !gGameOptions.fGunNut )
  225. {
  226. // CJC: replace guns in profile if they aren't available
  227. for ( uiLoop2 = 0; uiLoop2 < NUM_INV_SLOTS; uiLoop2++ )
  228. {
  229. usItem = gMercProfiles[uiLoop].inv[ uiLoop2 ];
  230. if ( ( Item[ usItem ].usItemClass & IC_GUN ) && ExtendedGunListGun( usItem ) )
  231. {
  232. usNewGun = StandardGunListReplacement( usItem );
  233. if ( usNewGun != NOTHING )
  234. {
  235. gMercProfiles[uiLoop].inv[ uiLoop2 ] = usNewGun;
  236. // must search through inventory and replace ammo accordingly
  237. for ( uiLoop3 = 0; uiLoop3 < NUM_INV_SLOTS; uiLoop3++ )
  238. {
  239. usAmmo = gMercProfiles[ uiLoop ].inv[ uiLoop3 ];
  240. if ( (Item[ usAmmo ].usItemClass & IC_AMMO) )
  241. {
  242. usNewAmmo = FindReplacementMagazineIfNecessary( usItem, usAmmo, usNewGun );
  243. if (usNewAmmo != NOTHING );
  244. {
  245. // found a new magazine, replace...
  246. gMercProfiles[ uiLoop ].inv[ uiLoop3 ] = usNewAmmo;
  247. }
  248. }
  249. }
  250. }
  251. }
  252. }
  253. } // end of if not gun nut
  254. #endif
  255. //ATE: Calculate some inital attractiveness values for buddy's inital equipment...
  256. // Look for gun and armour
  257. gMercProfiles[uiLoop].bMainGunAttractiveness = -1;
  258. gMercProfiles[uiLoop].bArmourAttractiveness = -1;
  259. for ( uiLoop2 = 0; uiLoop2 < NUM_INV_SLOTS; uiLoop2++ )
  260. {
  261. usItem = gMercProfiles[uiLoop].inv[ uiLoop2 ];
  262. if ( usItem != NOTHING )
  263. {
  264. // Check if it's a gun
  265. if ( Item[ usItem ].usItemClass & IC_GUN )
  266. {
  267. gMercProfiles[uiLoop].bMainGunAttractiveness = Weapon[ usItem ].ubDeadliness;
  268. }
  269. // If it's armour
  270. if ( Item[ usItem ].usItemClass & IC_ARMOUR )
  271. {
  272. gMercProfiles[uiLoop].bArmourAttractiveness = Armour[ Item[ usItem ].ubClassIndex ].ubProtection;
  273. }
  274. }
  275. }
  276. // OK, if we are a created slot, this will get overriden at some time..
  277. //add up the items the merc has for the usOptionalGearCost
  278. gMercProfiles[ uiLoop ].usOptionalGearCost = 0;
  279. for ( uiLoop2 = 0; uiLoop2< NUM_INV_SLOTS; uiLoop2++ )
  280. {
  281. if ( gMercProfiles[ uiLoop ].inv[ uiLoop2 ] != NOTHING )
  282. {
  283. //get the item
  284. usItem = gMercProfiles[ uiLoop ].inv[ uiLoop2 ];
  285. //add the cost
  286. gMercProfiles[ uiLoop ].usOptionalGearCost += Item[ usItem ].usPrice;
  287. }
  288. }
  289. //These variables to get loaded in
  290. gMercProfiles[ uiLoop ].fUseProfileInsertionInfo = FALSE;
  291. gMercProfiles[ uiLoop ].sGridNo = 0;
  292. // ARM: this is also being done inside the profile editor, but put it here too, so this project's code makes sense
  293. gMercProfiles[ uiLoop ].bHatedCount[0] = gMercProfiles[ uiLoop ].bHatedTime[0];
  294. gMercProfiles[ uiLoop ].bHatedCount[1] = gMercProfiles[ uiLoop ].bHatedTime[1];
  295. gMercProfiles[ uiLoop ].bLearnToHateCount = gMercProfiles[ uiLoop ].bLearnToHateTime;
  296. gMercProfiles[ uiLoop ].bLearnToLikeCount = gMercProfiles[ uiLoop ].bLearnToLikeTime;
  297. }
  298. // SET SOME DEFAULT LOCATIONS FOR STARTING NPCS
  299. FileClose( fptr );
  300. // decide which terrorists are active
  301. #ifndef JA2DEMO
  302. DecideActiveTerrorists();
  303. #endif
  304. // initialize mercs' status
  305. StartSomeMercsOnAssignment( );
  306. // initial recruitable mercs' reputation in each town
  307. InitializeProfilesForTownReputation( );
  308. #ifdef JA2EDITOR
  309. gfProfileDataLoaded = TRUE;
  310. #endif
  311. // no better place..heh?.. will load faces for profiles that are 'extern'.....won't have soldiertype instances
  312. InitalizeStaticExternalNPCFaces( );
  313. // car portrait values
  314. LoadCarPortraitValues( );
  315. return(TRUE);
  316. }
  317. #define MAX_ADDITIONAL_TERRORISTS 4
  318. void DecideActiveTerrorists( void )
  319. {
  320. UINT8 ubLoop, ubLoop2;
  321. UINT8 ubTerrorist;
  322. UINT8 ubNumAdditionalTerrorists, ubNumTerroristsAdded = 0;
  323. UINT32 uiChance, uiLocationChoice;
  324. BOOLEAN fFoundSpot;
  325. INT16 sTerroristPlacement[MAX_ADDITIONAL_TERRORISTS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
  326. #ifdef CRIPPLED_VERSION
  327. return;
  328. #endif
  329. // one terrorist will always be Elgin
  330. // determine how many more terrorists - 2 to 4 more
  331. // using this stochastic process(!), the chances for terrorists are:
  332. // EASY: 3, 9% 4, 42% 5, 49%
  333. // MEDIUM: 3, 25% 4, 50% 5, 25%
  334. // HARD: 3, 49% 4, 42% 5, 9%
  335. switch( gGameOptions.ubDifficultyLevel )
  336. {
  337. case DIF_LEVEL_EASY:
  338. uiChance = 70;
  339. break;
  340. case DIF_LEVEL_HARD:
  341. uiChance = 30;
  342. break;
  343. default:
  344. uiChance = 50;
  345. break;
  346. }
  347. // add at least 2 more
  348. ubNumAdditionalTerrorists = 2;
  349. for (ubLoop = 0; ubLoop < (MAX_ADDITIONAL_TERRORISTS - 2); ubLoop++)
  350. {
  351. if (Random( 100 ) < uiChance)
  352. {
  353. ubNumAdditionalTerrorists++;
  354. }
  355. }
  356. // ifdefs added by CJC
  357. #ifdef JA2TESTVERSION
  358. ubNumAdditionalTerrorists = 4;
  359. #endif
  360. while ( ubNumTerroristsAdded < ubNumAdditionalTerrorists )
  361. {
  362. ubLoop = 1; // start at beginning of array (well, after Elgin)
  363. // NB terrorist ID of 0 indicates end of array
  364. while ( ubNumTerroristsAdded < ubNumAdditionalTerrorists && gubTerrorists[ ubLoop ] != 0 )
  365. {
  366. ubTerrorist = gubTerrorists[ ubLoop ];
  367. // random 40% chance of adding this terrorist if not yet placed
  368. if ( ( gMercProfiles[ ubTerrorist ].sSectorX == 0 ) && ( Random( 100 ) < 40 ) )
  369. {
  370. fFoundSpot = FALSE;
  371. // Since there are 5 spots per terrorist and a maximum of 5 terrorists, we
  372. // are guaranteed to be able to find a spot for each terrorist since there
  373. // aren't enough other terrorists to use up all the spots for any one
  374. // terrorist
  375. do
  376. {
  377. // pick a random spot, see if it's already been used by another terrorist
  378. uiLocationChoice = Random( NUM_TERRORIST_POSSIBLE_LOCATIONS );
  379. for (ubLoop2 = 0; ubLoop2 < ubNumTerroristsAdded; ubLoop2++)
  380. {
  381. if (sTerroristPlacement[ubLoop2][0] == gsTerroristSector[ubLoop][uiLocationChoice][0] )
  382. {
  383. if (sTerroristPlacement[ubLoop2][1] == gsTerroristSector[ubLoop][uiLocationChoice][1] )
  384. {
  385. continue;
  386. }
  387. }
  388. }
  389. fFoundSpot = TRUE;
  390. } while( !fFoundSpot );
  391. // place terrorist!
  392. gMercProfiles[ ubTerrorist ].sSectorX = gsTerroristSector[ ubLoop ][ uiLocationChoice ][ 0 ];
  393. gMercProfiles[ ubTerrorist ].sSectorY = gsTerroristSector[ ubLoop ][ uiLocationChoice ][ 1 ];
  394. gMercProfiles[ ubTerrorist ].bSectorZ = 0;
  395. sTerroristPlacement[ ubNumTerroristsAdded ][ 0 ] = gMercProfiles[ ubTerrorist ].sSectorX;
  396. sTerroristPlacement[ ubNumTerroristsAdded ][ 1 ] = gMercProfiles[ ubTerrorist ].sSectorY;
  397. ubNumTerroristsAdded++;
  398. }
  399. ubLoop++;
  400. }
  401. // start over if necessary
  402. }
  403. // set total terrorists outstanding in Carmen's info byte
  404. gMercProfiles[ 78 ].bNPCData = 1 + ubNumAdditionalTerrorists;
  405. // store total terrorists
  406. gubNumTerrorists = 1 + ubNumAdditionalTerrorists;
  407. }
  408. void MakeRemainingTerroristsTougher( void )
  409. {
  410. UINT8 ubRemainingTerrorists = 0, ubLoop;
  411. UINT16 usNewItem, usOldItem;
  412. OBJECTTYPE Object;
  413. UINT8 ubRemainingDifficulty;
  414. for ( ubLoop = 0; ubLoop < NUM_TERRORISTS; ubLoop++ )
  415. {
  416. if ( gMercProfiles[ gubTerrorists[ ubLoop ] ].bMercStatus != MERC_IS_DEAD && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorX != 0 && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorY != 0 )
  417. {
  418. if ( gubTerrorists[ ubLoop ] == SLAY )
  419. {
  420. if ( FindSoldierByProfileID( SLAY, TRUE ) != NULL )
  421. {
  422. // Slay on player's team, doesn't count towards remaining terrorists
  423. continue;
  424. }
  425. }
  426. ubRemainingTerrorists++;
  427. }
  428. }
  429. ubRemainingDifficulty = (60 / gubNumTerrorists) * (gubNumTerrorists - ubRemainingTerrorists);
  430. switch( gGameOptions.ubDifficultyLevel )
  431. {
  432. case DIF_LEVEL_MEDIUM:
  433. ubRemainingDifficulty = (ubRemainingDifficulty * 13) / 10;
  434. break;
  435. case DIF_LEVEL_HARD:
  436. ubRemainingDifficulty = (ubRemainingDifficulty * 16) / 10;
  437. break;
  438. default:
  439. break;
  440. }
  441. if ( ubRemainingDifficulty < 14 )
  442. {
  443. // nothing
  444. return;
  445. }
  446. else if ( ubRemainingDifficulty < 28 )
  447. {
  448. // mini grenade
  449. usOldItem = NOTHING;
  450. usNewItem = MINI_GRENADE;
  451. }
  452. else if ( ubRemainingDifficulty < 42)
  453. {
  454. // hand grenade
  455. usOldItem = MINI_GRENADE;
  456. usNewItem = HAND_GRENADE;
  457. }
  458. else if ( ubRemainingDifficulty < 56)
  459. {
  460. // mustard
  461. usOldItem = HAND_GRENADE;
  462. usNewItem = MUSTARD_GRENADE;
  463. }
  464. else if ( ubRemainingDifficulty < 70)
  465. {
  466. // LAW
  467. usOldItem = MUSTARD_GRENADE;
  468. usNewItem = ROCKET_LAUNCHER;
  469. }
  470. else
  471. {
  472. // LAW and hand grenade
  473. usOldItem = NOTHING;
  474. usNewItem = HAND_GRENADE;
  475. }
  476. DeleteObj( &Object );
  477. Object.usItem = usNewItem;
  478. Object.bStatus[ 0 ] = 100;
  479. for ( ubLoop = 0; ubLoop < NUM_TERRORISTS; ubLoop++ )
  480. {
  481. if ( gMercProfiles[ gubTerrorists[ ubLoop ] ].bMercStatus != MERC_IS_DEAD && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorX != 0 && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorY != 0 )
  482. {
  483. if ( gubTerrorists[ ubLoop ] == SLAY )
  484. {
  485. if ( FindSoldierByProfileID( SLAY, TRUE ) != NULL )
  486. {
  487. // Slay on player's team, doesn't count towards remaining terrorists
  488. continue;
  489. }
  490. }
  491. if ( usOldItem != NOTHING )
  492. {
  493. RemoveObjectFromSoldierProfile( gubTerrorists[ ubLoop ], usOldItem );
  494. }
  495. PlaceObjectInSoldierProfile( gubTerrorists[ ubLoop ], &Object );
  496. }
  497. }
  498. }
  499. void DecideOnAssassin( void )
  500. {
  501. UINT8 ubAssassinPossibility[NUM_ASSASSINS] = { NO_PROFILE, NO_PROFILE, NO_PROFILE, NO_PROFILE, NO_PROFILE, NO_PROFILE };
  502. UINT8 ubAssassinsPossible = 0;
  503. UINT8 ubLoop, ubLoop2;
  504. UINT8 ubTown;
  505. #ifdef CRIPPLED_VERSION
  506. return;
  507. #endif
  508. ubTown = GetTownIdForSector( gWorldSectorX, gWorldSectorY );
  509. for ( ubLoop = 0; ubLoop < NUM_ASSASSINS; ubLoop++ )
  510. {
  511. // make sure alive and not placed already
  512. if ( gMercProfiles[ gubAssassins[ ubLoop ] ].bMercStatus != MERC_IS_DEAD && gMercProfiles[ gubAssassins[ ubLoop ] ].sSectorX == 0 && gMercProfiles[ gubAssassins[ ubLoop ] ].sSectorY == 0 )
  513. {
  514. // check this merc to see if the town is a possibility
  515. for ( ubLoop2 = 0; ubLoop2 < NUM_ASSASSIN_POSSIBLE_TOWNS; ubLoop2++ )
  516. {
  517. if ( gbAssassinTown[ ubLoop ][ ubLoop2 ] == ubTown )
  518. {
  519. ubAssassinPossibility[ ubAssassinsPossible ] = gubAssassins[ ubLoop ];
  520. ubAssassinsPossible++;
  521. }
  522. }
  523. }
  524. }
  525. if ( ubAssassinsPossible != 0 )
  526. {
  527. ubLoop = ubAssassinPossibility[ Random( ubAssassinsPossible ) ];
  528. gMercProfiles[ ubLoop ].sSectorX = gWorldSectorX;
  529. gMercProfiles[ ubLoop ].sSectorY = gWorldSectorY;
  530. AddStrategicEvent( EVENT_REMOVE_ASSASSIN, GetWorldTotalMin() + 60 * ( 3 + Random( 3 ) ), ubLoop );
  531. }
  532. }
  533. void MakeRemainingAssassinsTougher( void )
  534. {
  535. UINT8 ubRemainingAssassins = 0, ubLoop;
  536. UINT16 usNewItem, usOldItem;
  537. OBJECTTYPE Object;
  538. UINT8 ubRemainingDifficulty;
  539. for ( ubLoop = 0; ubLoop < NUM_ASSASSINS; ubLoop++ )
  540. {
  541. if ( gMercProfiles[ gubAssassins[ ubLoop ] ].bMercStatus != MERC_IS_DEAD )
  542. {
  543. ubRemainingAssassins++;
  544. }
  545. }
  546. ubRemainingDifficulty = (60 / NUM_ASSASSINS) * (NUM_ASSASSINS - ubRemainingAssassins);
  547. switch( gGameOptions.ubDifficultyLevel )
  548. {
  549. case DIF_LEVEL_MEDIUM:
  550. ubRemainingDifficulty = (ubRemainingDifficulty * 13) / 10;
  551. break;
  552. case DIF_LEVEL_HARD:
  553. ubRemainingDifficulty = (ubRemainingDifficulty * 16) / 10;
  554. break;
  555. default:
  556. break;
  557. }
  558. if ( ubRemainingDifficulty < 14 )
  559. {
  560. // nothing
  561. return;
  562. }
  563. else if ( ubRemainingDifficulty < 28 )
  564. {
  565. // mini grenade
  566. usOldItem = NOTHING;
  567. usNewItem = MINI_GRENADE;
  568. }
  569. else if ( ubRemainingDifficulty < 42)
  570. {
  571. // hand grenade
  572. usOldItem = MINI_GRENADE;
  573. usNewItem = HAND_GRENADE;
  574. }
  575. else if ( ubRemainingDifficulty < 56)
  576. {
  577. // mustard
  578. usOldItem = HAND_GRENADE;
  579. usNewItem = MUSTARD_GRENADE;
  580. }
  581. else if ( ubRemainingDifficulty < 70)
  582. {
  583. // LAW
  584. usOldItem = MUSTARD_GRENADE;
  585. usNewItem = ROCKET_LAUNCHER;
  586. }
  587. else
  588. {
  589. // LAW and hand grenade
  590. usOldItem = NOTHING;
  591. usNewItem = HAND_GRENADE;
  592. }
  593. DeleteObj( &Object );
  594. Object.usItem = usNewItem;
  595. Object.bStatus[ 0 ] = 100;
  596. for ( ubLoop = 0; ubLoop < NUM_ASSASSINS; ubLoop++ )
  597. {
  598. if ( gMercProfiles[ gubAssassins[ ubLoop ] ].bMercStatus != MERC_IS_DEAD )
  599. {
  600. if ( usOldItem != NOTHING )
  601. {
  602. RemoveObjectFromSoldierProfile( gubAssassins[ ubLoop ], usOldItem );
  603. }
  604. PlaceObjectInSoldierProfile( gubAssassins[ ubLoop ], &Object );
  605. }
  606. }
  607. }
  608. void StartSomeMercsOnAssignment(void)
  609. {
  610. UINT32 uiCnt;
  611. MERCPROFILESTRUCT *pProfile;
  612. UINT32 uiChance;
  613. // some randomly picked A.I.M. mercs will start off "on assignment" at the beginning of each new game
  614. for( uiCnt = 0; uiCnt < AIM_AND_MERC_MERCS; uiCnt++)
  615. {
  616. pProfile = &(gMercProfiles[ uiCnt ]);
  617. // calc chance to start on assignment
  618. uiChance = 5 * pProfile->bExpLevel;
  619. if (Random(100) < uiChance)
  620. {
  621. pProfile->bMercStatus = MERC_WORKING_ELSEWHERE;
  622. pProfile->uiDayBecomesAvailable = 1 + Random(6 + (pProfile->bExpLevel / 2) ); // 1-(6 to 11) days
  623. }
  624. else
  625. {
  626. pProfile->bMercStatus = MERC_OK;
  627. pProfile->uiDayBecomesAvailable = 0;
  628. }
  629. pProfile->uiPrecedentQuoteSaid = 0;
  630. pProfile->ubDaysOfMoraleHangover = 0;
  631. }
  632. }
  633. void SetProfileFaceData( UINT8 ubCharNum, UINT8 ubFaceIndex, UINT16 usEyesX, UINT16 usEyesY, UINT16 usMouthX, UINT16 usMouthY )
  634. {
  635. gMercProfiles[ ubCharNum ].ubFaceIndex = ubFaceIndex;
  636. gMercProfiles[ ubCharNum ].usEyesX = usEyesX;
  637. gMercProfiles[ ubCharNum ].usEyesY = usEyesY;
  638. gMercProfiles[ ubCharNum ].usMouthX = usMouthX;
  639. gMercProfiles[ ubCharNum ].usMouthY = usMouthY;
  640. }
  641. UINT16 CalcCompetence( MERCPROFILESTRUCT * pProfile )
  642. {
  643. UINT32 uiStats, uiSkills, uiActionPoints, uiSpecialSkills;
  644. UINT16 usCompetence;
  645. // count life twice 'cause it's also hit points
  646. // mental skills are halved 'cause they're actually not that important within the game
  647. uiStats = ((2 * pProfile->bLifeMax) + pProfile->bStrength + pProfile->bAgility + pProfile->bDexterity + ((pProfile->bLeadership + pProfile->bWisdom) / 2)) / 3;
  648. // marksmanship is very important, count it double
  649. uiSkills = (UINT32) ((2 * (pow(pProfile->bMarksmanship, 3) / 10000)) +
  650. 1.5 * (pow(pProfile->bMedical, 3) / 10000) +
  651. (pow(pProfile->bMechanical, 3) / 10000) +
  652. (pow(pProfile->bExplosive, 3) / 10000));
  653. // action points
  654. uiActionPoints = 5 + (((10 * pProfile->bExpLevel +
  655. 3 * pProfile->bAgility +
  656. 2 * pProfile->bLifeMax +
  657. 2 * pProfile->bDexterity) + 20) / 40);
  658. // count how many he has, don't care what they are
  659. uiSpecialSkills = ((pProfile->bSkillTrait != 0) ? 1 : 0) + ((pProfile->bSkillTrait2 != 0) ? 1 : 0);
  660. usCompetence = (UINT16) ((pow(pProfile->bExpLevel, 0.2) * uiStats * uiSkills * (uiActionPoints - 6) * (1 + (0.05 * (FLOAT)uiSpecialSkills))) / 1000);
  661. // this currently varies from about 10 (Flo) to 1200 (Gus)
  662. return(usCompetence);
  663. }
  664. INT16 CalcMedicalDeposit( MERCPROFILESTRUCT * pProfile )
  665. {
  666. UINT16 usDeposit;
  667. // this rounds off to the nearest hundred
  668. usDeposit = (((5 * CalcCompetence(pProfile)) + 50) / 100) * 100;
  669. return(usDeposit);
  670. }
  671. SOLDIERTYPE * FindSoldierByProfileID( UINT8 ubProfileID, BOOLEAN fPlayerMercsOnly )
  672. {
  673. UINT8 ubLoop, ubLoopLimit;
  674. SOLDIERTYPE * pSoldier;
  675. if (fPlayerMercsOnly)
  676. {
  677. ubLoopLimit = gTacticalStatus.Team[0].bLastID;
  678. }
  679. else
  680. {
  681. ubLoopLimit = MAX_NUM_SOLDIERS;
  682. }
  683. for (ubLoop = 0, pSoldier = MercPtrs[0]; ubLoop < ubLoopLimit; ubLoop++, pSoldier++)
  684. {
  685. if (pSoldier->bActive && pSoldier->ubProfile == ubProfileID)
  686. {
  687. return( pSoldier );
  688. }
  689. }
  690. return( NULL );
  691. }
  692. SOLDIERTYPE *ChangeSoldierTeam( SOLDIERTYPE *pSoldier, UINT8 ubTeam )
  693. {
  694. UINT8 ubID;
  695. SOLDIERTYPE *pNewSoldier = NULL;
  696. SOLDIERCREATE_STRUCT MercCreateStruct;
  697. UINT32 cnt;
  698. INT16 sOldGridNo;
  699. UINT8 ubOldID;
  700. UINT32 uiOldUniqueId;
  701. UINT32 uiSlot;
  702. SOLDIERTYPE *pGroupMember;
  703. if (gfInTalkPanel)
  704. {
  705. DeleteTalkingMenu();
  706. }
  707. // Save merc id for this guy...
  708. ubID = pSoldier->ubID;
  709. ubOldID = ubID;
  710. uiOldUniqueId = pSoldier->uiUniqueSoldierIdValue;
  711. sOldGridNo = pSoldier->sGridNo;
  712. // Remove him from the game!
  713. InternalTacticalRemoveSoldier( ubID, FALSE );
  714. // Create a new one!
  715. memset( &MercCreateStruct, 0, sizeof( MercCreateStruct ) );
  716. MercCreateStruct.bTeam = ubTeam;
  717. MercCreateStruct.ubProfile = pSoldier->ubProfile;
  718. MercCreateStruct.bBodyType = pSoldier->ubBodyType;
  719. MercCreateStruct.sSectorX = pSoldier->sSectorX;
  720. MercCreateStruct.sSectorY = pSoldier->sSectorY;
  721. MercCreateStruct.bSectorZ = pSoldier->bSectorZ;
  722. MercCreateStruct.sInsertionGridNo = pSoldier->sGridNo;
  723. MercCreateStruct.bDirection = pSoldier->bDirection;
  724. if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
  725. {
  726. MercCreateStruct.ubProfile = NO_PROFILE;
  727. MercCreateStruct.fUseGivenVehicle = TRUE;
  728. MercCreateStruct.bUseGivenVehicleID = pSoldier->bVehicleID;
  729. }
  730. if ( ubTeam == gbPlayerNum )
  731. {
  732. MercCreateStruct.fPlayerMerc = TRUE;
  733. }
  734. if ( TacticalCreateSoldier( &MercCreateStruct, &ubID ) )
  735. {
  736. pNewSoldier = MercPtrs[ ubID ];
  737. // Copy vital stats back!
  738. pNewSoldier->bLife = pSoldier->bLife;
  739. pNewSoldier->bLifeMax = pSoldier->bLifeMax;
  740. pNewSoldier->bAgility = pSoldier->bAgility;
  741. pNewSoldier->bLeadership = pSoldier->bLeadership;
  742. pNewSoldier->bDexterity = pSoldier->bDexterity;
  743. pNewSoldier->bStrength = pSoldier->bStrength;
  744. pNewSoldier->bWisdom = pSoldier->bWisdom;
  745. pNewSoldier->bExpLevel = pSoldier->bExpLevel;
  746. pNewSoldier->bMarksmanship = pSoldier->bMarksmanship;
  747. pNewSoldier->bMedical = pSoldier->bMedical;
  748. pNewSoldier->bMechanical = pSoldier->bMechanical;
  749. pNewSoldier->bExplosive = pSoldier->bExplosive;
  750. pNewSoldier->bScientific = pSoldier->bScientific;
  751. pNewSoldier->bLastRenderVisibleValue = pSoldier->bLastRenderVisibleValue;
  752. pNewSoldier->bVisible = pSoldier->bVisible;
  753. if ( ubTeam == gbPlayerNum )
  754. {
  755. pNewSoldier->bVisible = 1;
  756. }
  757. // Copy over any items....
  758. for ( cnt = 0; cnt < NUM_INV_SLOTS; cnt++ )
  759. {
  760. pNewSoldier->inv[ cnt ] = pSoldier->inv[ cnt ];
  761. }
  762. // OK, loop through all active merc slots, change
  763. // Change ANY attacker's target if they were once on this guy.....
  764. for ( uiSlot = 0; uiSlot < guiNumMercSlots; uiSlot++ )
  765. {
  766. pGroupMember = MercSlots[ uiSlot ];
  767. if ( pGroupMember != NULL )
  768. {
  769. if ( pGroupMember->ubTargetID == pSoldier->ubID )
  770. {
  771. pGroupMember->ubTargetID = pNewSoldier->ubID;
  772. }
  773. }
  774. }
  775. // Set insertion gridNo
  776. pNewSoldier->sInsertionGridNo = sOldGridNo;
  777. if ( gfPotentialTeamChangeDuringDeath )
  778. {
  779. HandleCheckForDeathCommonCode( pSoldier );
  780. }
  781. if ( gfWorldLoaded && pSoldier->bInSector
  782. //pSoldier->sSectorX == gWorldSectorX && pSoldier->sSectorY == gWorldSectorY && pSoldier->bSectorZ == gbWorldSectorZ
  783. )
  784. {
  785. AddSoldierToSectorNoCalculateDirectionUseAnimation( ubID, pSoldier->usAnimState, pSoldier->usAniCode );
  786. HandleSight(pNewSoldier, SIGHT_LOOK | SIGHT_RADIO);
  787. }
  788. // fix up the event queue...
  789. // ChangeSoldierIDInQueuedEvents( ubOldID, uiOldUniqueId, pNewSoldier->ubID, pNewSoldier->uiUniqueSoldierIdValue );
  790. if ( pNewSoldier->ubProfile != NO_PROFILE )
  791. {
  792. if ( ubTeam == gbPlayerNum )
  793. {
  794. gMercProfiles[ pNewSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED;
  795. }
  796. else
  797. {
  798. gMercProfiles[ pNewSoldier->ubProfile ].ubMiscFlags &= (~PROFILE_MISC_FLAG_RECRUITED);
  799. }
  800. }
  801. }
  802. // AT the low level check if this poor guy is in inv panel, else
  803. // remove....
  804. if ( gsCurInterfacePanel == SM_PANEL && gpSMCurrentMerc == pSoldier )
  805. {
  806. // Switch....
  807. SetCurrentInterfacePanel( TEAM_PANEL );
  808. }
  809. return( pNewSoldier );
  810. }
  811. BOOLEAN RecruitRPC( UINT8 ubCharNum )
  812. {
  813. SOLDIERTYPE *pSoldier, *pNewSoldier;
  814. // Get soldier pointer
  815. pSoldier = FindSoldierByProfileID( ubCharNum, FALSE );
  816. if (!pSoldier)
  817. {
  818. return( FALSE );
  819. }
  820. // OK, set recruit flag..
  821. gMercProfiles[ ubCharNum ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED;
  822. // Add this guy to our team!
  823. pNewSoldier = ChangeSoldierTeam( pSoldier, gbPlayerNum );
  824. // handle set up any RPC's that will leave us in time
  825. if ( ubCharNum == SLAY )
  826. {
  827. // slay will leave in a week
  828. pNewSoldier->iEndofContractTime = GetWorldTotalMin() + ( 7 * 24 * 60 );
  829. KickOutWheelchair( pNewSoldier );
  830. }
  831. else if ( ubCharNum == DYNAMO && gubQuest[ QUEST_FREE_DYNAMO ] == QUESTINPROGRESS )
  832. {
  833. EndQuest( QUEST_FREE_DYNAMO, pSoldier->sSectorX, pSoldier->sSectorY );
  834. }
  835. // handle town loyalty adjustment
  836. HandleTownLoyaltyForNPCRecruitment( pNewSoldier );
  837. // Try putting them into the current squad
  838. if ( AddCharacterToSquad( pNewSoldier, (INT8)CurrentSquad( ) ) == FALSE )
  839. {
  840. AddCharacterToAnySquad( pNewSoldier );
  841. }
  842. ResetDeadSquadMemberList( pNewSoldier->bAssignment );
  843. DirtyMercPanelInterface( pNewSoldier, DIRTYLEVEL2 );
  844. if ( pNewSoldier->inv[ HANDPOS ].usItem == NOTHING )
  845. {
  846. // empty handed - swap in first available weapon
  847. INT8 bSlot;
  848. bSlot = FindObjClass( pNewSoldier, IC_WEAPON );
  849. if ( bSlot != NO_SLOT )
  850. {
  851. if ( Item[ pNewSoldier->inv[ bSlot ].usItem ].fFlags & ITEM_TWO_HANDED )
  852. {
  853. if ( bSlot != SECONDHANDPOS && pNewSoldier->inv[ SECONDHANDPOS ].usItem != NOTHING )
  854. {
  855. // need to move second hand item out first
  856. AutoPlaceObject( pNewSoldier, &(pNewSoldier->inv[ SECONDHANDPOS ]), FALSE );
  857. }
  858. }
  859. // swap item to hand
  860. SwapObjs( &(pNewSoldier->inv[ bSlot ]), &(pNewSoldier->inv[ HANDPOS ]) );
  861. }
  862. }
  863. #ifdef JA2DEMO
  864. HandleEndDemoInCreatureLevel( );
  865. #endif
  866. if ( ubCharNum == IRA )
  867. {
  868. // trigger 0th PCscript line
  869. TriggerNPCRecord( IRA, 0 );
  870. }
  871. // Set whatkind of merc am i
  872. pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__NPC;
  873. //
  874. //add a history log that tells the user that a npc has joined the team
  875. //
  876. // ( pass in pNewSoldier->sSectorX cause if its invalid, -1, n/a will appear as the sector in the history log )
  877. AddHistoryToPlayersLog( HISTORY_RPC_JOINED_TEAM, pNewSoldier->ubProfile, GetWorldTotalMin(), pNewSoldier->sSectorX, pNewSoldier->sSectorY );
  878. //remove the merc from the Personnel screens departed list ( if they have never been hired before, its ok to call it )
  879. RemoveNewlyHiredMercFromPersonnelDepartedList( pSoldier->ubProfile );
  880. return( TRUE );
  881. }
  882. BOOLEAN RecruitEPC( UINT8 ubCharNum )
  883. {
  884. SOLDIERTYPE *pSoldier, *pNewSoldier;
  885. // Get soldier pointer
  886. pSoldier = FindSoldierByProfileID( ubCharNum, FALSE );
  887. if (!pSoldier)
  888. {
  889. return( FALSE );
  890. }
  891. // OK, set recruit flag..
  892. gMercProfiles[ ubCharNum ].ubMiscFlags |= PROFILE_MISC_FLAG_EPCACTIVE;
  893. gMercProfiles[ ubCharNum ].ubMiscFlags3 &= ~PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE;
  894. // Add this guy to our team!
  895. pNewSoldier = ChangeSoldierTeam( pSoldier, gbPlayerNum );
  896. pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__EPC;
  897. // Try putting them into the current squad
  898. if ( AddCharacterToSquad( pNewSoldier, (INT8)CurrentSquad( ) ) == FALSE )
  899. {
  900. AddCharacterToAnySquad( pNewSoldier );
  901. }
  902. ResetDeadSquadMemberList( pNewSoldier->bAssignment );
  903. DirtyMercPanelInterface( pNewSoldier, DIRTYLEVEL2 );
  904. // Make the interface panel dirty..
  905. // This will dirty the panel next frame...
  906. gfRerenderInterfaceFromHelpText = TRUE;
  907. // If we are a robot, look to update controller....
  908. if ( pNewSoldier->uiStatusFlags & SOLDIER_ROBOT )
  909. {
  910. UpdateRobotControllerGivenRobot( pNewSoldier );
  911. }
  912. // Set whatkind of merc am i
  913. pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__EPC;
  914. UpdateTeamPanelAssignments( );
  915. return( TRUE );
  916. }
  917. BOOLEAN UnRecruitEPC( UINT8 ubCharNum )
  918. {
  919. SOLDIERTYPE *pSoldier, *pNewSoldier;
  920. // Get soldier pointer
  921. pSoldier = FindSoldierByProfileID( ubCharNum, FALSE );
  922. if (!pSoldier)
  923. {
  924. return( FALSE );
  925. }
  926. if (pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__EPC)
  927. {
  928. return( FALSE );
  929. }
  930. if ( pSoldier->bAssignment < ON_DUTY )
  931. {
  932. ResetDeadSquadMemberList( pSoldier->bAssignment );
  933. }
  934. // Rmeove from squad....
  935. RemoveCharacterFromSquads( pSoldier );
  936. // O< check if this is the only guy in the sector....
  937. if ( gusSelectedSoldier == pSoldier->ubID )
  938. {
  939. gusSelectedSoldier = NOBODY;
  940. }
  941. // OK, UN set recruit flag..
  942. gMercProfiles[ ubCharNum ].ubMiscFlags &= (~PROFILE_MISC_FLAG_EPCACTIVE);
  943. // update sector values to current
  944. // check to see if this person should disappear from the map after this
  945. if ( (ubCharNum == JOHN || ubCharNum == MARY) && pSoldier->sSectorX == 13 && pSoldier->sSectorY == MAP_ROW_B && pSoldier->bSectorZ == 0 )
  946. {
  947. gMercProfiles[ ubCharNum ].sSectorX = 0;
  948. gMercProfiles[ ubCharNum ].sSectorY = 0;
  949. gMercProfiles[ ubCharNum ].bSectorZ = 0;
  950. }
  951. else
  952. {
  953. gMercProfiles[ ubCharNum ].sSectorX = pSoldier->sSectorX;
  954. gMercProfiles[ ubCharNum ].sSectorY = pSoldier->sSectorY;
  955. gMercProfiles[ ubCharNum ].bSectorZ = pSoldier->bSectorZ;
  956. }
  957. // how do we decide whether or not to set this?
  958. gMercProfiles[ ubCharNum ].fUseProfileInsertionInfo = TRUE;
  959. gMercProfiles[ ubCharNum ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE;
  960. // Add this guy to CIV team!
  961. pNewSoldier = ChangeSoldierTeam( pSoldier, CIV_TEAM );
  962. UpdateTeamPanelAssignments( );
  963. return( TRUE );
  964. }
  965. INT8 WhichBuddy( UINT8 ubCharNum, UINT8 ubBuddy )
  966. {
  967. MERCPROFILESTRUCT * pProfile;
  968. INT8 bLoop;
  969. pProfile = &( gMercProfiles[ ubCharNum ] );
  970. for (bLoop = 0; bLoop < 3; bLoop++)
  971. {
  972. if ( pProfile->bBuddy[bLoop] == ubBuddy )
  973. {
  974. return( bLoop );
  975. }
  976. }
  977. return( -1 );
  978. }
  979. INT8 WhichHated( UINT8 ubCharNum, UINT8 ubHated )
  980. {
  981. MERCPROFILESTRUCT * pProfile;
  982. INT8 bLoop;
  983. pProfile = &( gMercProfiles[ ubCharNum ] );
  984. for (bLoop = 0; bLoop < 3; bLoop++)
  985. {
  986. if ( pProfile->bHated[bLoop] == ubHated )
  987. {
  988. return( bLoop );
  989. }
  990. }
  991. return( -1 );
  992. }
  993. BOOLEAN IsProfileATerrorist( UINT8 ubProfile )
  994. {
  995. if ( ubProfile == 83 || ubProfile == 111 ||
  996. ubProfile == 64 || ubProfile == 112 ||
  997. ubProfile == 82 || ubProfile == 110 )
  998. {
  999. return( TRUE );
  1000. }
  1001. else
  1002. {
  1003. return( FALSE );
  1004. }
  1005. }
  1006. BOOLEAN IsProfileAHeadMiner( UINT8 ubProfile )
  1007. {
  1008. if ( ubProfile == 106 || ubProfile == 148 ||
  1009. ubProfile == 156 || ubProfile == 157 ||
  1010. ubProfile == 158 )
  1011. {
  1012. return( TRUE );
  1013. }
  1014. else
  1015. {
  1016. return( FALSE );
  1017. }
  1018. }
  1019. void UpdateSoldierPointerDataIntoProfile( BOOLEAN fPlayerMercs )
  1020. {
  1021. UINT32 uiCount;
  1022. SOLDIERTYPE *pSoldier = NULL;
  1023. MERCPROFILESTRUCT * pProfile;
  1024. BOOLEAN fDoCopy = FALSE;
  1025. for( uiCount=0; uiCount < guiNumMercSlots; uiCount++)
  1026. {
  1027. pSoldier = MercSlots[ uiCount ];
  1028. if ( pSoldier != NULL )
  1029. {
  1030. if ( pSoldier->ubProfile != NO_PROFILE )
  1031. {
  1032. fDoCopy = FALSE;
  1033. // If we are above player mercs
  1034. if ( fPlayerMercs )
  1035. {
  1036. if ( pSoldier->ubProfile < FIRST_RPC )
  1037. {
  1038. fDoCopy = TRUE;
  1039. }
  1040. }
  1041. else
  1042. {
  1043. if ( pSoldier->ubProfile >= FIRST_RPC )
  1044. {
  1045. fDoCopy = TRUE;
  1046. }
  1047. }
  1048. if ( fDoCopy )
  1049. {
  1050. // get profile...
  1051. pProfile = &( gMercProfiles[ pSoldier->ubProfile ] );
  1052. // Copy....
  1053. pProfile->bLife = pSoldier->bLife;
  1054. pProfile->bLifeMax = pSoldier->bLifeMax;
  1055. pProfile->bAgility = pSoldier->bAgility;
  1056. pProfile->bLeadership = pSoldier->bLeadership;
  1057. pProfile->bDexterity = pSoldier->bDexterity;
  1058. pProfile->bStrength = pSoldier->bStrength;
  1059. pProfile->bWisdom = pSoldier->bWisdom;
  1060. pProfile->bExpLevel = pSoldier->bExpLevel;
  1061. pProfile->bMarksmanship = pSoldier->bMarksmanship;
  1062. pProfile->bMedical = pSoldier->bMedical;
  1063. pProfile->bMechanical = pSoldier->bMechanical;
  1064. pProfile->bExplosive = pSoldier->bExplosive;
  1065. pProfile->bScientific = pSoldier->bScientific;
  1066. }
  1067. }
  1068. }
  1069. }
  1070. }
  1071. BOOLEAN DoesMercHaveABuddyOnTheTeam( UINT8 ubMercID )
  1072. {
  1073. UINT8 ubCnt;
  1074. INT8 bBuddyID;
  1075. // loop through the list of people the merc is buddies with
  1076. for(ubCnt=0; ubCnt< 3; ubCnt++)
  1077. {
  1078. //see if the merc has a buddy on the team
  1079. bBuddyID = gMercProfiles[ ubMercID ].bBuddy[ubCnt];
  1080. //If its not a valid 'buddy'
  1081. if( bBuddyID < 0 )
  1082. continue;
  1083. if( IsMercOnTeam( bBuddyID ) )
  1084. {
  1085. if( !IsMercDead( bBuddyID ) )
  1086. {
  1087. return( TRUE );
  1088. }
  1089. }
  1090. }
  1091. return( FALSE );
  1092. }
  1093. BOOLEAN MercIsHot( SOLDIERTYPE * pSoldier )
  1094. {
  1095. if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == HEAT_INTOLERANT )
  1096. {
  1097. if ( SectorTemperature( GetWorldMinutesInDay(), pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 0 )
  1098. {
  1099. return( TRUE );
  1100. }
  1101. }
  1102. return( FALSE );
  1103. }
  1104. SOLDIERTYPE * SwapLarrysProfiles( SOLDIERTYPE * pSoldier )
  1105. {
  1106. UINT8 ubSrcProfile;
  1107. UINT8 ubDestProfile;
  1108. MERCPROFILESTRUCT * pNewProfile;
  1109. ubSrcProfile = pSoldier->ubProfile;
  1110. if ( ubSrcProfile == LARRY_NORMAL)
  1111. {
  1112. ubDestProfile = LARRY_DRUNK;
  1113. }
  1114. else if ( ubSrcProfile == LARRY_DRUNK )
  1115. {
  1116. ubDestProfile = LARRY_NORMAL;
  1117. }
  1118. else
  1119. {
  1120. // I don't think so!
  1121. return( pSoldier );
  1122. }
  1123. pNewProfile = &gMercProfiles[ ubDestProfile ];
  1124. pNewProfile->ubMiscFlags2 = gMercProfiles[ ubSrcProfile ].ubMiscFlags2;
  1125. pNewProfile->ubMiscFlags = gMercProfiles[ ubSrcProfile ].ubMiscFlags;
  1126. pNewProfile->sSectorX = gMercProfiles[ ubSrcProfile ].sSectorX;
  1127. pNewProfile->sSectorY = gMercProfiles[ ubSrcProfile ].sSectorY;
  1128. pNewProfile->uiDayBecomesAvailable = gMercProfiles[ ubSrcProfile ].uiDayBecomesAvailable;
  1129. pNewProfile->usKills = gMercProfiles[ ubSrcProfile ].usKills;
  1130. pNewProfile->usAssists = gMercProfiles[ ubSrcProfile ].usAssists;
  1131. pNewProfile->usShotsFired = gMercProfiles[ ubSrcProfile ].usShotsFired;
  1132. pNewProfile->usShotsHit = gMercProfiles[ ubSrcProfile ].usShotsHit;
  1133. pNewProfile->usBattlesFought = gMercProfiles[ ubSrcProfile ].usBattlesFought;
  1134. pNewProfile->usTimesWounded = gMercProfiles[ ubSrcProfile ].usTimesWounded;
  1135. pNewProfile->usTotalDaysServed = gMercProfiles[ ubSrcProfile ].usTotalDaysServed;
  1136. pNewProfile->bResigned = gMercProfiles[ ubSrcProfile ].bResigned;
  1137. pNewProfile->bActive = gMercProfiles[ ubSrcProfile ].bActive;
  1138. pNewProfile->fUseProfileInsertionInfo = gMercProfiles[ ubSrcProfile ].fUseProfileInsertionInfo;
  1139. pNewProfile->sGridNo = gMercProfiles[ ubSrcProfile ].sGridNo;
  1140. pNewProfile->ubQuoteActionID = gMercProfiles[ ubSrcProfile ].ubQuoteActionID;
  1141. pNewProfile->ubLastQuoteSaid = gMercProfiles[ ubSrcProfile ].ubLastQuoteSaid;
  1142. pNewProfile->ubStrategicInsertionCode = gMercProfiles[ ubSrcProfile ].ubStrategicInsertionCode;
  1143. pNewProfile->bMercStatus = gMercProfiles[ ubSrcProfile ].bMercStatus;
  1144. pNewProfile->bSectorZ = gMercProfiles[ ubSrcProfile ].bSectorZ;
  1145. pNewProfile->usStrategicInsertionData = gMercProfiles[ ubSrcProfile ].usStrategicInsertionData;
  1146. pNewProfile->sTrueSalary = gMercProfiles[ ubSrcProfile ].sTrueSalary;
  1147. pNewProfile->ubMiscFlags3 = gMercProfiles[ ubSrcProfile ].ubMiscFlags3;
  1148. pNewProfile->ubDaysOfMoraleHangover = gMercProfiles[ ubSrcProfile ].ubDaysOfMoraleHangover;
  1149. pNewProfile->ubNumTimesDrugUseInLifetime = gMercProfiles[ ubSrcProfile ].ubNumTimesDrugUseInLifetime;
  1150. pNewProfile->uiPrecedentQuoteSaid = gMercProfiles[ ubSrcProfile ].uiPrecedentQuoteSaid;
  1151. pNewProfile->sPreCombatGridNo = gMercProfiles[ ubSrcProfile ].sPreCombatGridNo;
  1152. // CJC: this is causing problems so just skip the transfer of exp...
  1153. /*
  1154. pNewProfile->sLifeGain = gMercProfiles[ ubSrcProfile ].sLifeGain;
  1155. pNewProfile->sAgilityGain = gMercProfiles[ ubSrcProfile ].sAgilityGain;
  1156. pNewProfile->sDexterityGain = gMercProfiles[ ubSrcProfile ].sDexterityGain;
  1157. pNewProfile->sStrengthGain = gMercProfiles[ ubSrcProfile ].sStrengthGain;
  1158. pNewProfile->sLeadershipGain = gMercProfiles[ ubSrcProfile ].sLeadershipGain;
  1159. pNewProfile->sWisdomGain = gMercProfiles[ ubSrcProfile ].sWisdomGain;
  1160. pNewProfile->sExpLevelGain = gMercProfiles[ ubSrcProfile ].sExpLevelGain;
  1161. pNewProfile->sMarksmanshipGain = gMercProfiles[ ubSrcProfile ].sMarksmanshipGain;
  1162. pNewProfile->sMedicalGain = gMercProfiles[ ubSrcProfile ].sMedicalGain;
  1163. pNewProfile->sMechanicGain = gMercProfiles[ ubSrcProfile ].sMechanicGain;
  1164. pNewProfile->sExplosivesGain = gMercProfiles[ ubSrcProfile ].sExplosivesGain;
  1165. pNewProfile->bLifeDelta = gMercProfiles[ ubSrcProfile ].bLifeDelta;
  1166. pNewProfile->bAgilityDelta = gMercProfiles[ ubSrcProfile ].bAgilityDelta;
  1167. pNewProfile->bDexterityDelta = gMercProfiles[ ubSrcProfile ].bDexterityDelta;
  1168. pNewProfile->bStrengthDelta = gMercProfiles[ ubSrcProfile ].bStrengthDelta;
  1169. pNewProfile->bLeadershipDelta = gMercProfiles[ ubSrcProfile ].bLeadershipDelta;
  1170. pNewProfile->bWisdomDelta = gMercProfiles[ ubSrcProfile ].bWisdomDelta;
  1171. pNewProfile->bExpLevelDelta = gMercProfiles[ ubSrcProfile ].bExpLevelDelta;
  1172. pNewProfile->bMarksmanshipDelta = gMercProfiles[ ubSrcProfile ].bMarksmanshipDelta;
  1173. pNewProfile->bMedicalDelta = gMercProfiles[ ubSrcProfile ].bMedicalDelta;
  1174. pNewProfile->bMechanicDelta = gMercProfiles[ ubSrcProfile ].bMechanicDelta;
  1175. pNewProfile->bExplosivesDelta = gMercProfiles[ ubSrcProfile ].bExplosivesDelta;
  1176. */
  1177. memcpy( pNewProfile->bInvStatus, gMercProfiles[ ubSrcProfile ].bInvStatus , sizeof( UINT8) * 19 );
  1178. memcpy( pNewProfile->bInvStatus, gMercProfiles[ ubSrcProfile ].bInvStatus , sizeof( UINT8) * 19 );
  1179. memcpy( pNewProfile->inv , gMercProfiles[ ubSrcProfile ].inv , sizeof( UINT16 ) * 19 );
  1180. memcpy( pNewProfile->bMercTownReputation , gMercProfiles[ ubSrcProfile ].bMercTownReputation , sizeof( UINT8 ) * 20 );
  1181. // remove face
  1182. DeleteSoldierFace( pSoldier );
  1183. pSoldier->ubProfile = ubDestProfile;
  1184. // create new face
  1185. pSoldier->iFaceIndex = InitSoldierFace( pSoldier );
  1186. // replace profile in group
  1187. ReplaceSoldierProfileInPlayerGroup( pSoldier->ubGroupID, ubSrcProfile, ubDestProfile );
  1188. pSoldier->bStrength = pNewProfile->bStrength + pNewProfile->bStrengthDelta;
  1189. pSoldier->bDexterity = pNewProfile->bDexterity + pNewProfile->bDexterityDelta;
  1190. pSoldier->bAgility = pNewProfile->bAgility + pNewProfile->bAgilityDelta;
  1191. pSoldier->bWisdom = pNewProfile->bWisdom + pNewProfile->bWisdomDelta;
  1192. pSoldier->bExpLevel = pNewProfile->bExpLevel + pNewProfile->bExpLevelDelta;
  1193. pSoldier->bLeadership = pNewProfile->bLeadership + pNewProfile->bLeadershipDelta;
  1194. pSoldier->bMarksmanship = pNewProfile->bMarksmanship + pNewProfile->bMarksmanshipDelta;
  1195. pSoldier->bMechanical = pNewProfile->bMechanical + pNewProfile->bMechanicDelta;
  1196. pSoldier->bMedical = pNewProfile->bMedical + pNewProfile->bMedicalDelta;
  1197. pSoldier->bExplosive = pNewProfile->bExplosive + pNewProfile->bExplosivesDelta;
  1198. if ( pSoldier->ubProfile == LARRY_DRUNK )
  1199. {
  1200. SetFactTrue( FACT_LARRY_CHANGED );
  1201. }
  1202. else
  1203. {
  1204. SetFactFalse( FACT_LARRY_CHANGED );
  1205. }
  1206. DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
  1207. return( pSoldier );
  1208. }
  1209. BOOLEAN DoesNPCOwnBuilding( SOLDIERTYPE *pSoldier, INT16 sGridNo )
  1210. {
  1211. UINT8 ubRoomInfo;
  1212. // Get room info
  1213. ubRoomInfo = gubWorldRoomInfo[ sGridNo ];
  1214. if ( ubRoomInfo == NO_ROOM )
  1215. {
  1216. return( FALSE );
  1217. }
  1218. // Are we an NPC?
  1219. if ( pSoldier->bTeam != CIV_TEAM )
  1220. {
  1221. return( FALSE );
  1222. }
  1223. // OK, check both ranges
  1224. if ( ubRoomInfo >= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeStart[ 0 ] &&
  1225. ubRoomInfo <= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeEnd[ 0 ] )
  1226. {
  1227. return( TRUE );
  1228. }
  1229. if ( ubRoomInfo >= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeStart[ 1 ] &&
  1230. ubRoomInfo <= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeEnd[ 1 ] )
  1231. {
  1232. return( TRUE );
  1233. }
  1234. return( FALSE );
  1235. }