New feature: mercs can drag people and corpses

Requires GameDir >= r2386.

For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23508&goto=350989&#msg_350989

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8474 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2017-09-17 22:16:30 +00:00
parent 5becfe9004
commit 6031257dcd
26 changed files with 621 additions and 97 deletions
+8 -1
View File
@@ -2267,7 +2267,14 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 28 );
bNumRightIcons++;
}
// Flugente: drag stuff
if ( MercPtrs[pFace->ubSoldierID]->IsDraggingSomeone() )
{
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 31 );
++bNumRightIcons;
}
switch( pSoldier->bAssignment )
{
CASE_DOCTOR:
+19 -1
View File
@@ -3087,9 +3087,27 @@ UINT32 GetTotalWeight( SOLDIERTYPE* pSoldier )
return uiTotalWeight;
}
UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier )
UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier, BOOLEAN fConsiderDragging)
{
UINT32 uiTotalWeight = GetTotalWeight( pSoldier );
// Flugente: if we drag someone, add their weight to ours
if ( fConsiderDragging && pSoldier->IsDraggingSomeone() )
{
if (pSoldier->usDragPersonID != NOBODY)
{
SOLDIERTYPE* pOtherSoldier = MercPtrs[pSoldier->usDragPersonID];
uiTotalWeight += GetTotalWeight( pOtherSoldier );
uiTotalWeight += pOtherSoldier->GetBodyWeight();
}
else if (pSoldier->sDragCorpseID >= 0)
{
// just give corpses a flat weight
uiTotalWeight += 100.0f;
}
}
UINT32 uiPercent;
UINT32 ubStrengthForCarrying;
+1 -1
View File
@@ -52,7 +52,7 @@ extern BOOLEAN PlaceObjectAtObjectIndex( OBJECTTYPE * pSourceObj, OBJECTTYPE * p
UINT16 CalculateAmmoWeight( UINT16 usGunAmmoItem, UINT16 ubShotsLeft );
UINT16 CalculateObjectWeight( OBJECTTYPE *pObject );
UINT32 GetTotalWeight( SOLDIERTYPE* pSoldier );
UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier );
UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier, BOOLEAN fConsiderDragging = FALSE );
// CHRISL:
UINT16 CalculateItemSize( OBJECTTYPE *pObject );
+7 -9
View File
@@ -1767,21 +1767,19 @@ BOOLEAN ExecuteOverhead( )
// dAngle = (FLOAT)atan2( dDeltaX, dDeltaY );
dAngle = gdRadiansForAngle[ pSoldier->bMovementDirection ];
FLOAT movementchange = gAnimControl[pSoldier->usAnimState].dMovementChange;
// For walking, base it on body type!
if ( pSoldier->usAnimState == WALKING ||
pSoldier->usAnimState == WALKING_WEAPON_RDY ||
pSoldier->usAnimState == WALKING_DUAL_RDY ||
pSoldier->usAnimState == WALKING_ALTERNATIVE_RDY )
{
pSoldier->MoveMerc( gubAnimWalkSpeeds[ pSoldier->ubBodyType ].dMovementChange, dAngle, TRUE );
movementchange = gubAnimWalkSpeeds[pSoldier->ubBodyType].dMovementChange;
}
else
{
pSoldier->MoveMerc( gAnimControl[ pSoldier->usAnimState ].dMovementChange, dAngle, TRUE );
}
}
pSoldier->MoveMerc( movementchange, dAngle, TRUE );
}
}
// Check for direction change
if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_TURNING )
@@ -2007,8 +2005,8 @@ void HandleLocateToGuyAsHeWalks( SOLDIERTYPE *pSoldier )
}
}
#pragma optimize("gpt",on)
__forceinline
//#pragma optimize("gpt",on)
// __forceinline
BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLEAN fInitialMove, UINT16 usAnimState )
{
INT16 sAPCost;
+27
View File
@@ -1410,6 +1410,12 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction)
movementAPCost *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: dragging someone
if ( pSoldier->IsDraggingSomeone( ) )
{
movementAPCost *= gItemSettings.fDragAPCostModifier;
}
if (terrainCost == TRAVELCOST_FENCE)
{
switch( movementModeToUseForAPs )
@@ -3641,6 +3647,12 @@ if(!GridNoOnVisibleWorldTile(iDestination))
ubAPCost *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: dragging someone
if ( s->IsDraggingSomeone( ) )
{
ubAPCost *= gItemSettings.fDragAPCostModifier;
}
// SANDRO - moved backpack check to here
// Moa: backpack penalty
//if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND )
@@ -4717,6 +4729,12 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
{
sMovementAPsCost *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: dragging someone
if ( pSold->IsDraggingSomeone( ) )
{
sMovementAPsCost *= gItemSettings.fDragAPCostModifier;
}
// Check for backpack
//if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
@@ -4849,6 +4867,15 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
sPointsRun *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: dragging someone
if ( pSold->IsDraggingSomeone() )
{
sPointsWalk *= gItemSettings.fDragAPCostModifier;
sPointsCrawl *= gItemSettings.fDragAPCostModifier;
sPointsSwat *= gItemSettings.fDragAPCostModifier;
sPointsRun *= gItemSettings.fDragAPCostModifier;
}
// Check for backpack
//if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
//{
+12 -5
View File
@@ -216,7 +216,7 @@ INT16 BreathPointAdjustmentForCarriedWeight( SOLDIERTYPE * pSoldier )
UINT32 uiCarriedPercent;
UINT32 uiPercentCost;
uiCarriedPercent = CalculateCarriedWeight( pSoldier );
uiCarriedPercent = CalculateCarriedWeight( pSoldier, TRUE );
if (uiCarriedPercent < 101)
{
// normal BP costs
@@ -476,9 +476,11 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 u
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
{
sPoints *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: dragging someone
if ( pSoldier->IsDraggingSomeone( ) )
sPoints *= gItemSettings.fDragAPCostModifier;
// Flugente: scuba fins reduce movement cost in water, but increase cost on land
if ( pSoldier->inv[LEGPOS].exists() && HasItemFlag( pSoldier->inv[LEGPOS].usItem, SCUBA_FINS ) )
@@ -724,9 +726,11 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir,
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
{
sPoints *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: dragging someone
if ( pSoldier->IsDraggingSomeone( ) )
sPoints *= gItemSettings.fDragAPCostModifier;
// Check if doors if not player's merc (they have to open them manually)
if ( sSwitchValue == TRAVELCOST_DOOR && pSoldier->bTeam != gbPlayerNum )
@@ -4228,6 +4232,9 @@ INT16 GetAPsStartRun( SOLDIERTYPE *pSoldier )
if ( pSoldier->IsRiotShieldEquipped( ) )
val *= gItemSettings.fShieldMovementAPCostModifier;
if ( pSoldier->IsDraggingSomeone( ) )
val *= gItemSettings.fDragAPCostModifier;
// Athletics trait
if( HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT ) && gGameOptions.fNewTraitSystem )
val = max( 1, (INT16)((val * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5) );
+43 -2
View File
@@ -557,8 +557,19 @@ INT32 AddRottingCorpse( ROTTING_CORPSE_DEFINITION *pCorpseDef )
AniParams.sDelay = (INT16)( 150 );
AniParams.sStartFrame = 0;
AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_PAUSED | ANITILE_OPTIMIZEFORSLOWMOVING | ANITILE_ANIMATE_Z | ANITILE_ERASEITEMFROMSAVEBUFFFER | uiDirectionUseFlag;
AniParams.sX = CenterX( pCorpse->def.sGridNo );
AniParams.sY = CenterY( pCorpse->def.sGridNo );
// use the x,y coordinates provided in the definition when adding a corpse
if (pCorpse->def.usFlags |= ROTTING_CORPSE_USE_XY_PROVIDED)
{
AniParams.sX = pCorpse->def.dXPos;
AniParams.sY = pCorpse->def.dYPos;
}
else
{
AniParams.sX = CenterX(pCorpse->def.sGridNo);
AniParams.sY = CenterY(pCorpse->def.sGridNo);
}
AniParams.sZ = (INT16)pCorpse->def.sHeightAdjustment;
AniParams.uiUserData3 = pCorpse->def.ubDirection;
@@ -2575,6 +2586,36 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo )
return( ubHighestWarning );
}
ROTTING_CORPSE* GetRottingCorpse( INT16 aNum )
{
if ( aNum < giNumRottingCorpse )
return &(gRottingCorpse[aNum]);
return NULL;
}
std::vector<INT16> GetCorpseIDsNearGridNo( INT32 sGridNo, INT8 bLevel, INT8 sRadius )
{
std::vector<INT16> idvec;
ROTTING_CORPSE* pCorpse;
for ( INT32 cnt = 0; cnt < giNumRottingCorpse; ++cnt )
{
pCorpse = &(gRottingCorpse[cnt]);
if ( pCorpse->fActivated && pCorpse->def.bLevel == bLevel )
{
if ( PythSpacesAway( sGridNo, pCorpse->def.sGridNo ) <= sRadius )
{
idvec.push_back(cnt);
}
}
}
return idvec;
}
// Flugente Zombies: resurrect zombies
void RaiseZombies( void )
{
+5
View File
@@ -94,6 +94,8 @@ enum RottingCorpseDefines
#define ROTTING_CORPSE_NO_VEST 0x00004000 // corpse has no vest (atm not visually)
#define ROTTING_CORPSE_NO_PANTS 0x00008000 // corpse has no vest (atm not visually)
#define ROTTING_CORPSE_USE_XY_PROVIDED 0x00010000 // use the x,y coordinates provided in the definition when adding a corpse
typedef struct
{
UINT8 ubType;
@@ -220,6 +222,9 @@ INT32 GetGridNoOfCorpseGivenProfileID( UINT8 ubProfileID );
void DecayRottingCorpseAIWarnings( void );
UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo );
ROTTING_CORPSE* GetRottingCorpse( INT16 aNum );
std::vector<INT16> GetCorpseIDsNearGridNo( INT32 sGridNo, INT8 bLevel, INT8 sRadius );
// Flugente: Raise zombies
void RaiseZombies( void );
+92 -1
View File
@@ -13,6 +13,8 @@
#include "Queen Command.h"
#include "strategicmap.h"
#include "Map Screen Interface.h"
#include "Rotting Corpses.h"
extern void GetEquipmentTemplates( );
@@ -109,6 +111,13 @@ void Wrapper_Setup_SoldierSelection( UINT32 aVal) { gSoldierSelection.Setup(aVa
void Wrapper_Cancel_SoldierSelection( UINT32 aVal ) { gSoldierSelection.Cancel(); }
/////////////////////////////// Soldier Target Selection ////////////////////////////////////////////
/////////////////////////////// Drag Selection ////////////////////////////////////////////
DragSelection gDragSelection;
void Wrapper_Function_DragSelection( UINT32 aVal) { gDragSelection.Functions(aVal); }
void Wrapper_Setup_DragSelection( UINT32 aVal ) { gDragSelection.Setup( aVal ); }
void Wrapper_Cancel_DragSelection( UINT32 aVal ) { gDragSelection.Cancel( ); }
/////////////////////////////// Drag Selection ////////////////////////////////////////////
/////////////////////////////// Trait Selection ////////////////////////////////////////////
void
@@ -236,7 +245,10 @@ SkillSelection::Setup( UINT32 aVal )
{
swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] );
pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &Wrapper_Function_SkillSelection, uiCounter ) );
if ( uiCounter == SKILLS_DRAG )
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Setup_DragSelection, uiCounter ) );
else
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Function_SkillSelection, uiCounter ) );
// if we cannot perform this skill, grey it out
if ( !(pSoldier->CanUseSkill( uiCounter, TRUE, sTraitsMenuTargetGridNo )) )
@@ -738,6 +750,85 @@ SoldierSelection::Functions( UINT32 aVal )
}
/////////////////////////////// Soldier Target Selection ////////////////////////////////////////////
/////////////////////////////// Drag Selection ////////////////////////////////////////////
void
DragSelection::Setup( UINT32 aVal )
{
Destroy( );
SOLDIERTYPE * pSoldier = NULL;
GetSoldier( &pSoldier, gusSelectedSoldier );
if ( pSoldier == NULL )
return;
if ( pSoldier->CanUseSkill( aVal ) )
{
usSkill = aVal;
SetupPopup( "DragSelection" );
POPUP_OPTION *pOption;
CHAR16 pStr[300];
// pretty simple: we find every soldier in a radius around the target position and add him to the list
// loop through all soldiers around
for ( UINT32 cnt = gTacticalStatus.Team[OUR_TEAM].bFirstID; cnt <= gTacticalStatus.Team[CIV_TEAM].bLastID; ++cnt )
{
if ( cnt != pSoldier->ubID && pSoldier->CanDragPerson(cnt) )
{
swprintf( pStr, L"%s", MercPtrs[cnt]->GetName( ) );
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Function_DragSelection, cnt ) );
GetPopup( )->addOption( *pOption );
}
}
// corpses
std::vector<INT16> corpseids = GetCorpseIDsNearGridNo( pSoldier->sGridNo, pSoldier->pathing.bLevel, 1 );
for ( std::vector<INT16>::iterator it = corpseids.begin(); it != corpseids.end(); ++it )
{
ROTTING_CORPSE* pCorpse = GetRottingCorpse( (*it) );
swprintf( pStr, pSkillMenuStrings[SKILLMENU_CORPSES], pCorpse->name );
// we have to use an offset of NOBODY in order to differentiate between person and corpse
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Function_DragSelection, (*it) + NOBODY ) );
GetPopup( )->addOption( *pOption );
}
// cancel option
swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] );
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Cancel_SoldierSelection, 0 ) );
GetPopup( )->addOption( *pOption );
}
// same y, different x
SetPos( gSkillSelection.GetMaxPosX( ), usTraitMenuPosY );
}
void
DragSelection::Functions( UINT32 aVal )
{
SOLDIERTYPE * pSoldier = NULL;
GetSoldier( &pSoldier, gusSelectedSoldier );
if ( pSoldier )
{
pSoldier->UseSkill( usSkill, sTraitsMenuTargetGridNo, aVal );
}
Cancel( );
gSkillSelection.Cancel();
gTraitSelection.Cancel( );
}
/////////////////////////////// Drag Selection ////////////////////////////////////////////
/**
* Flugente: traits menu popup box
+11
View File
@@ -155,6 +155,17 @@ private:
UINT32 usSkill;
};
class DragSelection : public SkillMenuItem
{
public:
DragSelection( ) {}
void Setup( UINT32 aVal );
void Functions( UINT32 aVal );
private:
UINT32 usSkill;
};
/**
* Flugente: traits menu popup box
+277 -6
View File
@@ -101,6 +101,7 @@
#include "MilitiaIndividual.h" // added by Flugente
#include "Arms Dealer Init.h" // added by Flugente for armsDealerInfo[]
#include "LuaInitNPCs.h" // added by Flugente
#include "SaveLoadMap.h" // added by Flugente
#endif
#include "ub_config.h"
@@ -1027,6 +1028,8 @@ SOLDIERTYPE& SOLDIERTYPE::operator=(const OLDSOLDIERTYPE_101& src)
this->bScopeMode = USE_BEST_SCOPE;
this->ubMilitiaAssists = 0;
this->CancelDrag();
this->bFoodLevel = 0;
this->bDrinkLevel = 0;
@@ -11193,12 +11196,10 @@ InternalpSoldier->GivingSoldierCancelServices(, FALSE );
void SOLDIERTYPE::MoveMerc( FLOAT dMovementChange, FLOAT dAngle, BOOLEAN fCheckRange )
{
//INT16 dDegAngle;
FLOAT dDeltaPos;
FLOAT dXPos, dYPos;
BOOLEAN fStop = FALSE;
BOOLEAN fStop = FALSE;
//dDegAngle = (INT16)( dAngle * 180 / PI );
//sprintf( gDebugStr, "Move Angle: %d", (int)dDegAngle );
@@ -11306,11 +11307,104 @@ void SOLDIERTYPE::MoveMerc( FLOAT dMovementChange, FLOAT dAngle, BOOLEAN fCheckR
}
}
// Flugente: as we move a tile, we would now be too far away to drag someone.
// So remember whether we were dragging (we have to set our position now, otherwise the person we drag woul soon occupy our gridno).
BOOLEAN currentlydragging = this->IsDraggingSomeone();
INT32 sOldGridNo = this->sGridNo;
// OK, set new position
this->EVENT_InternalSetSoldierPosition( dXPos, dYPos, FALSE, FALSE, FALSE );
// Flugente: drag people
if ( currentlydragging )
{
if ( this->usDragPersonID != NOBODY )
{
SOLDIERTYPE* pSoldier = MercPtrs[this->usDragPersonID];
// while it would be neat to take the opposite direction (which would make it look like we drag the other person by the legs),
// this causes problems, as a prone person needs additional space for the legs. So just take the same direction
//pSoldier->ubDirection = (this->ubDirection + 4 ) % NUM_WORLD_DIRECTIONS;
pSoldier->ubDirection = this->ubDirection;
FLOAT dx = 0;
FLOAT dy = 0;
INT32 gridnotouse = pSoldier->sGridNo;
if ( sOldGridNo != this->sGridNo )
{
gridnotouse = sOldGridNo;
}
else
{
INT16 this_base_x = 0;
INT16 this_base_y = 0;
ConvertMapPosToWorldTileCenter(this->sGridNo, &this_base_x, &this_base_y);
dx = this->dXPos - this_base_x;
dy = this->dYPos - this_base_y;
}
INT16 base_x = 0;
INT16 base_y = 0;
ConvertMapPosToWorldTileCenter( gridnotouse, &base_x, &base_y );
pSoldier->EVENT_InternalSetSoldierPosition( base_x + dx, base_y + dy, FALSE, FALSE, FALSE );
}
else if ( this->sDragCorpseID >= 0 )
{
ROTTING_CORPSE* pCorpse = GetRottingCorpse( this->sDragCorpseID );
if ( pCorpse )
{
// move corpse to new location. We have to actually delete and recreate the corpse, otherwise direction changes will only be visible after saving the game
ROTTING_CORPSE_DEFINITION CorpseDef;
// Copy corpse definition...
memcpy(&CorpseDef, &(pCorpse->def), sizeof(ROTTING_CORPSE_DEFINITION));
// Remove old one...
RemoveCorpse(pCorpse->iID);
// drop blood at old location
InternalDropBlood(pCorpse->def.sGridNo, this->pathing.bLevel, 0, 5, 1);
// adjust both gridno and x,y coordinates
if (sOldGridNo != this->sGridNo)
{
CorpseDef.sGridNo = sOldGridNo;
CorpseDef.dXPos = CenterX(CorpseDef.sGridNo);
CorpseDef.dYPos = CenterY(CorpseDef.sGridNo);
}
else
{
// move corpse a bit
INT16 this_base_x = 0;
INT16 this_base_y = 0;
ConvertMapPosToWorldTileCenter(this->sGridNo, &this_base_x, &this_base_y);
FLOAT dx = this->dXPos - this_base_x;
FLOAT dy = this->dYPos - this_base_y;
INT16 base_x = 0;
INT16 base_y = 0;
ConvertMapPosToWorldTileCenter(pCorpse->def.sGridNo, &base_x, &base_y);
CorpseDef.sGridNo = pCorpse->def.sGridNo;
CorpseDef.dXPos = CenterX(CorpseDef.sGridNo) + dx;
CorpseDef.dYPos = CenterY(CorpseDef.sGridNo) + dy;
}
CorpseDef.usFlags |= ROTTING_CORPSE_USE_XY_PROVIDED;
CorpseDef.ubDirection = this->ubDirection;
this->sDragCorpseID = AddRottingCorpse(&CorpseDef);
}
}
}
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("X: %f Y: %f", dXPos, dYPos ) );
}
BOOLEAN GetDirectionChangeAmount( INT32 sGridNo, SOLDIERTYPE *pSoldier, UINT8 uiTurnAmount )
@@ -17361,6 +17455,13 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck, INT32 sGridNo )
canuse = TRUE;
break;
case SKILLS_DRAG:
// TODO: a better check would be whether we can drag anything at the moment - CanDrag is more used for a specific person
if ( CanDragInPrinciple() )
canuse = TRUE;
break;
default:
break;
}
@@ -17369,7 +17470,7 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck, INT32 sGridNo )
}
// use a skill. For safety reasons, this calls CanUseSkill again
BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID )
BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT32 ID )
{
if ( !CanUseSkill( iSkill, TRUE, usMapPos ) )
{
@@ -17430,6 +17531,13 @@ BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID )
}
break;
case SKILLS_DRAG:
if ( ID < NOBODY )
SetDragOrderPerson( ID );
else
SetDragOrderCorpse( ID - NOBODY );
break;
default:
break;
}
@@ -17507,6 +17615,19 @@ STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
break;
case SKILLS_DRAG:
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_PRONEPERSONORCORPSE] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_CROUCH] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_FREEHANDS] );
wcscat( skilldescarray, atStr );
break;
default:
break;
}
@@ -19353,6 +19474,156 @@ void SOLDIERTYPE::RiotShieldTakeDamage( INT32 sDamage )
}
}
// Flugente: drag people
BOOLEAN SOLDIERTYPE::CanDragInPrinciple()
{
// only prone while crouched
if ( gAnimControl[this->usAnimState].ubEndHeight != ANIM_CROUCH )
return FALSE;
// not in water
if ( TERRAIN_IS_HIGH_WATER( this->sGridNo ) )
return FALSE;
// main hand must be free
if ( this->inv[HANDPOS].exists( ) )
return FALSE;
return TRUE;
}
BOOLEAN SOLDIERTYPE::CanDragPerson( UINT8 usID )
{
if ( !CanDragInPrinciple() )
return FALSE;
// check whether this guy exists etc.
SOLDIERTYPE* pSoldier = MercPtrs[usID];
if ( pSoldier && pSoldier->bActive && pSoldier->bInSector )
{
// must be on same level
if ( pSoldier->pathing.bLevel != this->pathing.bLevel )
return FALSE;
// only prone people can be dragged
if ( gAnimControl[pSoldier->usAnimState].ubEndHeight != ANIM_PRONE )
return FALSE;
// not in water
if ( TERRAIN_IS_HIGH_WATER( pSoldier->sGridNo ) )
return FALSE;
// don't drag nonsense around
if ( pSoldier->ubBodyType >= COW || pSoldier->ubBodyType == QUEENMONSTER )
return FALSE;
// must be near us
if ( PythSpacesAway( pSoldier->sGridNo, this->sGridNo ) > 1 )
return FALSE;
// we must be able to see the other guy even if if both would be prone. This is to stop the player from dragging someone through solid structures
if ( !LocationToLocationLineOfSightTest(pSoldier->sGridNo, pSoldier->pathing.bLevel, this->sGridNo, this->pathing.bLevel, TRUE, CALC_FROM_ALL_DIRS, PRONE_LOS_POS, PRONE_LOS_POS))
return FALSE;
return TRUE;
}
return FALSE;
}
BOOLEAN SOLDIERTYPE::CanDragCorpse( UINT16 usCorpseNum )
{
if ( !CanDragInPrinciple( ) )
return FALSE;
ROTTING_CORPSE* pCorpse = GetRottingCorpse( usCorpseNum );
if ( pCorpse )
{
// must be on same level
if ( pCorpse->def.bLevel != this->pathing.bLevel )
return FALSE;
// don't drag nonsense around
if ( pCorpse->def.ubBodyType >= COW || pCorpse->def.ubBodyType == QUEENMONSTER )
return FALSE;
// must be near us
if ( PythSpacesAway( pCorpse->def.sGridNo, this->sGridNo ) > 2 )
return FALSE;
// we must be able to see the other guy even if if both would be prone. This is to stop the player from dragging someone through solid structures
if (!LocationToLocationLineOfSightTest(pCorpse->def.sGridNo, this->pathing.bLevel, this->sGridNo, this->pathing.bLevel, TRUE, CALC_FROM_ALL_DIRS, PRONE_LOS_POS, PRONE_LOS_POS))
return FALSE;
return TRUE;
}
return FALSE;
}
BOOLEAN SOLDIERTYPE::IsDraggingSomeone( )
{
if ( this->sDragCorpseID >= 0 )
{
if ( this->CanDragCorpse(this->sDragCorpseID) )
return TRUE;
else
CancelDrag();
}
else if ( this->usDragPersonID != NOBODY )
{
if ( this->CanDragPerson(this->usDragPersonID) )
return TRUE;
else
CancelDrag();
}
return FALSE;
}
void SOLDIERTYPE::SetDragOrderPerson( UINT16 usID )
{
if ( CanDragPerson( usID ) )
{
CancelDrag();
this->usDragPersonID = usID;
}
}
void SOLDIERTYPE::SetDragOrderCorpse( UINT32 usID )
{
if ( CanDragCorpse( usID ) )
{
CancelDrag();
this->sDragCorpseID = usID;
}
}
void SOLDIERTYPE::CancelDrag()
{
// if we are dragging a person, set them to the center of their gridno, otherwise their position might be off
if (this->usDragPersonID != NOBODY)
{
SOLDIERTYPE* pSoldier = MercPtrs[this->usDragPersonID];
if ( pSoldier && !TileIsOutOfBounds(pSoldier->sGridNo) )
{
INT16 base_x = 0;
INT16 base_y = 0;
ConvertMapPosToWorldTileCenter(pSoldier->sGridNo, &base_x, &base_y);
pSoldier->EVENT_InternalSetSoldierPosition(base_x, base_y, FALSE, FALSE, FALSE);
}
}
this->usDragPersonID = NOBODY;
this->sDragCorpseID = -1;
}
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
{
INT8 bBandaged; //,savedOurTurn;
+19 -6
View File
@@ -416,6 +416,7 @@ enum
#define SOLDIER_COVERT_NOREDISGUISE 0x00001000 // this soldier does not want to be redisguised
#define SOLDIER_TRAIT_FOCUS 0x00002000 // 'focus' skill is active
#define SOLDIER_DRAG_CORPSE 0x00004000 // we are dragging a corpse, not a person
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
// ----------------------------------------------------------------
@@ -590,7 +591,8 @@ enum{
SKILLS_VARIOUS_FIRST,
SKILLS_SPOTTER = SKILLS_VARIOUS_FIRST,
SKILLS_FOCUS,
SKILLS_VARIOUS_LAST = SKILLS_FOCUS,
SKILLS_DRAG,
SKILLS_VARIOUS_LAST = SKILLS_DRAG,
SKILLS_MAX,
};
@@ -1485,12 +1487,14 @@ public:
// Flugente: this was the location of required variables required for the now removed poison feature. They can be used again
UINT8 ubMilitiaAssists; // Flugente: stores militia assists
INT8 sNonNPCTraderID; // Flugente: we can set up non-NPC soldiers to be merchants, we store their dealer id here (value > 0 means arms dealer entry x)
INT8 bUnusedINT8_3;
//INT8 bUnusedINT8_3;
UINT8 usDragPersonID; // Flugente: id of person we are dragging
//INT16 bUnusedINT16_4;
INT16 sDragCorpseID; // Flugente: id of corpse we are dragging
INT16 bUnusedINT16_4;
INT16 bUnusedINT16_5;
///////////////////////////////////////////////////////
// Flugente: new variables for extra stats
INT16 bExtraStrength; // additional strength gained via power armor
INT16 bExtraDexterity; // additional dexterity gained via drugs
@@ -1866,7 +1870,7 @@ public:
BOOLEAN CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck = TRUE, INT32 sGridNo = -1 );
// use a skill. For safety reasons, this calls CanUseSkill again (it is possible to switch the soldier while the menu is open)
BOOLEAN UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID );
BOOLEAN UseSkill( UINT8 iSkill, INT32 usMapPos, UINT32 ID );
// is the AI allowed to use a skill? we have to check how much breath and life using this skill would cost, as otherwise the AI might commit suicide by casting
BOOLEAN IsAIAllowedtoUseSkill( INT8 iSkill );
@@ -1949,6 +1953,15 @@ public:
BOOLEAN IsRiotShieldEquipped();
void DestroyEquippedRiotShield();
void RiotShieldTakeDamage(INT32 sDamage);
// Flugente: drag people
BOOLEAN CanDragInPrinciple();
BOOLEAN CanDragPerson( UINT8 usID );
BOOLEAN CanDragCorpse( UINT16 usCorpseNum );
BOOLEAN IsDraggingSomeone();
void SetDragOrderPerson( UINT16 usID );
void SetDragOrderCorpse( UINT32 usID );
void CancelDrag();
//////////////////////////////////////////////////////////////////////////////
}; // SOLDIERTYPE;