- New Feature: Tactical recruitment allows recruiting civilians as volunteers.

See http://thepit.ja-galaxy-forum.com/index.php?t=msg&goto=341335&#msg_341335

This is fully savegame compatible.
GameDir <= r2250 is recommended.
- Fix: prisoners do not talk.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7886 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2015-06-03 21:04:06 +00:00
parent 6c9d75480f
commit 962393d170
7 changed files with 125 additions and 4 deletions
+5 -1
View File
@@ -438,6 +438,10 @@ typedef enum
PRISONER_MAX,
} PrisonerType;
// -------- added by Flugente: sector info flags --------
// easier than adding 32 differently named variables. DO NOT CHANGE THEM, UNLESS YOU KNOW WHAT YOU ARE DOING!!!
#define SECTORINFO_VOLUNTEERS_RECENTLY_RECRUITED 0x01 //1 // we recruited volunteers here. Until this flag is removed, newly created civilians wont be potential volunteers anymore
typedef struct SECTORINFO
{
//information pertaining to this sector
@@ -495,7 +499,7 @@ typedef struct SECTORINFO
// HEADROCK HAM 3.6: Flag to determine whether enemy units in this sector can be seen, and whether their numbers
// should be displayed. One filler was replaced to make room.
UINT8 ubDetectionLevel;
UINT8 bFiller2;
UINT8 usSectorInfoFlag; // a flagmask
UINT8 bFiller3;
UINT32 uiNumberOfWorldItemsInTempFileThatCanBeSeenByPlayer;
+17
View File
@@ -824,6 +824,23 @@ void HandleNPCSystemEvent( UINT32 uiEvent )
void HandleEarlyMorningEvents( void )
{
// Flugente: no reason to put this into LUA
for ( UINT8 sX = 1; sX < MAP_WORLD_X - 1; ++sX )
{
for ( UINT8 sY = 1; sY < MAP_WORLD_X - 1; ++sY )
{
UINT8 sector = SECTOR( sX, sY );
SECTORINFO *pSectorInfo = &(SectorInfo[sector]);
// A flag prevents us from exploiting the civilian recruitment mechanic. Every x hours, we reset it
if ( pSectorInfo )
{
pSectorInfo->usSectorInfoFlag &= ~SECTORINFO_VOLUNTEERS_RECENTLY_RECRUITED;
}
}
}
#ifdef LUA_STRATEGY_EVENT_HANDLER
LetLuaHandleEarlyMorningEvents(0);
#else
+1 -1
View File
@@ -361,7 +361,7 @@ enum
UNNAMED_CIV_GROUP_19,
ASSASSIN_CIV_GROUP, // Flugente: enemy assassins belong to this group
POW_PRISON_CIV_GROUP, // Flugente: prisoners of war the player caught are in this group
UNNAMED_CIV_GROUP_22,
VOLUNTEER_CIV_GROUP, // Flugente: civilians that the player recruited
UNNAMED_CIV_GROUP_23,
UNNAMED_CIV_GROUP_24,
UNNAMED_CIV_GROUP_25,
+4
View File
@@ -3839,6 +3839,10 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld )
// Flugente: if this was a prisoner of war, reduce their sector count by 1
if ( pSoldierOld->usSoldierFlagMask & SOLDIER_POW_PRISON )
KillOnePrisoner( &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ] );
// If this was a volunteer, then we definetly reduce our volunteer pool
if ( pSoldierOld->bTeam == CIV_TEAM && pSoldierOld->ubCivilianGroup == VOLUNTEER_CIV_GROUP )
AddVolunteers( -1 );
}
else if ( pSoldierOld->bTeam == MILITIA_TEAM )
{
+79 -2
View File
@@ -118,6 +118,7 @@
#include "Tactical Save.h" // added by Flugente for AddItemsToUnLoadedSector()
#include "LightEffects.h" // added by Flugente for CreatePersonalLight()
#include "DynamicDialogue.h" // added by Flugente for HandleDynamicOpinions()
#include "strategic town loyalty.h" // added by Flugente for gTownLoyalty
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
@@ -20437,14 +20438,16 @@ BOOLEAN SOLDIERTYPE::PlayerSoldierStartTalking( UINT8 ubTargetID, BOOLEAN fValid
apsDeducted = TRUE;
// Flugente: if we are talking to an enemy, we have the option to offer them surrender...
if ( (pTSoldier->bTeam == ENEMY_TEAM || (pTSoldier->bTeam == CIV_TEAM && zCivGroupName[pTSoldier->ubCivilianGroup].fCanBeCaptured) )
&& (gGameExternalOptions.fEnemyCanSurrender || gGameExternalOptions.fPlayerCanAsktoSurrender) )
if ( (gGameExternalOptions.fEnemyCanSurrender || gGameExternalOptions.fPlayerCanAsktoSurrender) && pTSoldier->CanBeCaptured( ) )
{
HandleSurrenderOffer( pTSoldier );
return(FALSE);
}
else
{
// Flugente: if this guy is a potential volunteer, we might be able to sway him
HandleVolunteerRecruitment( this, pTSoldier );
StartCivQuote( pTSoldier );
return(FALSE);
}
@@ -22806,3 +22809,77 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB
return uiMedcost;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Flugente: decide whether pRecruiter can successfully recruit pTarget to be a volunteer
void HandleVolunteerRecruitment( SOLDIERTYPE* pRecruiter, SOLDIERTYPE* pTarget )
{
if ( !pRecruiter || pRecruiter->bTeam != OUR_TEAM )
return;
// potential recruit must be a civilain NPC of no other affilation, no kids
if ( !pTarget || pTarget->bTeam != CIV_TEAM || pTarget->ubProfile != NO_PROFILE || pTarget->ubCivilianGroup != NON_CIV_GROUP || pTarget->ubBodyType > DRESSCIV )
return;
// target must unharmed
if ( pTarget->bCollapsed || pTarget->bBreathCollapsed || pTarget->stats.bLife < pTarget->stats.bLifeMax )
return;
// target must be friendly
if ( !pTarget->aiData.bNeutral )
return;
// Set a flag in this sector. This flag is removed every x hours. As long as it exists, newly created civilians won't be potential volunteers
// this is simply there to prevent the exploit of reloading the sector repeatedly and 'harvesting' volunteers.
// we do this even if we do not recruit this guy - otherwise the player could reload the sector over and over again until he find a volunteer
UINT8 sector = SECTOR( pTarget->sSectorX, pTarget->sSectorY );
SECTORINFO *pSectorInfo = &(SectorInfo[sector]);
if ( pSectorInfo )
{
pSectorInfo->usSectorInfoFlag |= SECTORINFO_VOLUNTEERS_RECENTLY_RECRUITED;
}
// can we recruit him in the first place?
if ( pTarget->usSoldierFlagMask2 & SOLDIER_POTENTIAL_VOLUNTEER )
{
// if sector not under our control, has enemies in it, or is currently in combat mode
if ( !SectorOursAndPeaceful( pTarget->sSectorX, pTarget->sSectorY, pTarget->bSectorZ ) )
return;
// if this a town sector, min loyalty is required
// other sectors do not have a loyalty rating. This is okay here, as then the player has an incentive to try his luck outside of towns
UINT8 ubTownID = StrategicMap[CALCULATE_STRATEGIC_INDEX( pTarget->sSectorX, pTarget->sSectorY )].bNameId;
if ( ubTownID != BLANK_SECTOR )
{
if ( gTownLoyalty[ubTownID].ubRating < gGameExternalOptions.iMinLoyaltyToTrain )
return;
}
// recruiter ability
FLOAT leadershipfactor = EffectiveLeadership( pRecruiter ) / 100.0;
// bonus for assertive characters
if ( gMercProfiles[pRecruiter->ubProfile].bCharacterTrait == CHAR_TRAIT_ASSERTIVE )
leadershipfactor *= 1.05;
FLOAT recruitmodifier = (100 + pRecruiter->GetBackgroundValue( BG_PERC_APPROACH_RECRUIT )) / 100.0;
FLOAT rating = leadershipfactor * recruitmodifier * gMercProfiles[pRecruiter->ubProfile].usApproachFactor[3];
// hard check. We do not use Chance()-base functions, as then the player would have to repeat this over and over again to be sure that someone is not a volunteer
if ( rating > 70.0 )
{
// success! remove the flag, put this guy in a new group, and add one volunteer
pTarget->usSoldierFlagMask2 &= ~SOLDIER_POTENTIAL_VOLUNTEER;
pTarget->ubCivilianGroup = VOLUNTEER_CIV_GROUP;
AddVolunteers( 1 );
// the recruiter gets a bit of experience
StatChange( pRecruiter, LDRAMT, 8, TRUE );
StatChange( pRecruiter, EXPERAMT, 5, TRUE );
}
}
}
+4
View File
@@ -408,6 +408,7 @@ enum
#define SOLDIER_INTERROGATE_GENERAL 0x00000080 //128 // interrogate generals
#define SOLDIER_INTERROGATE_CIVILIAN 0x00000100 //256 // interrogate civilian
#define SOLDIER_POTENTIAL_VOLUNTEER 0x00000200 //512 // this civilian _might_ join us as a volunteer if conditions are right
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
// ----------------------------------------------------------------
@@ -2724,6 +2725,9 @@ void SetDamageDisplayCounter(SOLDIERTYPE* pSoldier);
// SANDRO - This whole procedure was merged with the surgery ability of the doctor trait
UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OBJECTTYPE *pKit, INT16 sKitPts, INT16 sStatus, BOOLEAN fOnSurgery );
// Flugente: decide whether pRecruiter can successfully recruit pTarget to be a volunteer
void HandleVolunteerRecruitment( SOLDIERTYPE* pRecruiter, SOLDIERTYPE* pTarget );
#endif
+15
View File
@@ -1137,7 +1137,22 @@ SOLDIERTYPE* TacticalCreateSoldier( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 *
default:
Soldier.aiData.bNormalSmell = NORMAL_HUMAN_SMELL_STRENGTH;
break;
}
// Flugente: under certain conditions, we can recruit civilians
if ( Soldier.bTeam == CIV_TEAM && Soldier.ubProfile == NO_PROFILE && Soldier.ubCivilianGroup == NON_CIV_GROUP && Soldier.ubBodyType <= DRESSCIV )
{
// there has to officially be an outbreak in this sector - if we don't know of a disease, we cannot treat it!
UINT8 sector = SECTOR( Soldier.sSectorX, Soldier.sSectorY );
SECTORINFO *pSectorInfo = &(SectorInfo[sector]);
// only allow us to be a volunteer if this isn't blocked
if ( pSectorInfo && !(pSectorInfo->usSectorInfoFlag & SECTORINFO_VOLUNTEERS_RECENTLY_RECRUITED) )
{
if ( Chance(10) )
Soldier.usSoldierFlagMask2 |= SOLDIER_POTENTIAL_VOLUNTEER;
}
}
if( guiCurrentScreen != AUTORESOLVE_SCREEN )