diff --git a/Editor/EditorMercs.cpp b/Editor/EditorMercs.cpp index a7f8fb65..11ae2a34 100644 --- a/Editor/EditorMercs.cpp +++ b/Editor/EditorMercs.cpp @@ -1966,7 +1966,7 @@ void InitDetailedPlacementForMerc() Assert( !gpSelected->pDetailedPlacement ); // WDS - Clean up inventory handling - gpSelected->pDetailedPlacement = new (MemAlloc(SIZEOF_SOLDIERCREATE_STRUCT)) SOLDIERCREATE_STRUCT; + gpSelected->pDetailedPlacement = new SOLDIERCREATE_STRUCT; Assert( gpSelected->pDetailedPlacement ); gpSelected->pBasicPlacement->fDetailedPlacement = TRUE; @@ -3710,7 +3710,7 @@ void PasteMercPlacement( INT32 iMapIndex ) gTempBasicPlacement.fDetailedPlacement = TRUE; gTempBasicPlacement.fPriorityExistance = gSaveBufferBasicPlacement.fPriorityExistance; // WDS - Clean up inventory handling - pNode->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; + pNode->pDetailedPlacement = new SOLDIERCREATE_STRUCT; if( !pNode->pDetailedPlacement ) { AssertMsg( 0, "Failed to allocate memory for new detailed placement in PasteMercPlacement." ); diff --git a/GameSettings.cpp b/GameSettings.cpp index 4c49d441..f3270ae5 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -389,8 +389,8 @@ void LoadGameExternalOptions() gGameExternalOptions.iStartAttribute = iniReader.ReadInteger("JA2 Laptop Settings","START_ATTRIBUTE",55); //gGameExternalOptions.fPers_att = iniReader.ReadBoolean("JA2 Laptop Settings","USE_RANDOM_PERSONALITY",FALSE); - gGameExternalOptions.iCustomPersonality = iniReader.ReadInteger("JA2 Laptop Settings","CUSTOM_PERSONALITY",0); - gGameExternalOptions.iCustomAttitude = iniReader.ReadInteger("JA2 Laptop Settings","CUSTOM_ATTITUDE",0); + gGameExternalOptions.iCustomPersonality = (INT8) iniReader.ReadInteger("JA2 Laptop Settings","CUSTOM_PERSONALITY",0); + gGameExternalOptions.iCustomAttitude = (INT8) iniReader.ReadInteger("JA2 Laptop Settings","CUSTOM_ATTITUDE",0); //Merc settings gGameExternalOptions.fMercDayOne = iniReader.ReadBoolean("JA2 Laptop Settings","MERC_AVAILABLE_DAY_ONE",FALSE); @@ -404,7 +404,7 @@ void LoadGameExternalOptions() gGameExternalOptions.giInsaneMercDeaths = iniReader.ReadInteger("JA2 Laptop Settings","INSANE_MERC_DEATHS",4); //################# System Settings ################# - gGameExternalOptions.gubDeadLockDelay = iniReader.ReadInteger("JA2 System Settings","DEAD_LOCK_DELAY",15); + gGameExternalOptions.gubDeadLockDelay = (UINT8) iniReader.ReadInteger("JA2 System Settings","DEAD_LOCK_DELAY",15); gGameExternalOptions.gfEnableEmergencyButton_SkipStrategicEvents = iniReader.ReadBoolean("JA2 System Settings","ENABLE_EMERGENCY_BUTTON_NUMLOCK_TO_SKIP_STRATEGIC_EVENTS",0); @@ -433,11 +433,11 @@ void LoadGameExternalOptions() gGameExternalOptions.fAllowTacticalMilitiaCommand = iniReader.ReadBoolean("JA2 Tactical Settings","ALLOW_TACTICAL_MILITIA_COMMAND",0); // Enemy AP settings - gGameExternalOptions.iEasyAPBonus = iniReader.ReadInteger("JA2 Tactical Settings","NOVICE_AP_BONUS",0); - gGameExternalOptions.iExperiencedAPBonus = iniReader.ReadInteger("JA2 Tactical Settings","EXPERIENCED_AP_BONUS",0); - gGameExternalOptions.iExpertAPBonus = iniReader.ReadInteger("JA2 Tactical Settings","EXPERT_AP_BONUS",0); - gGameExternalOptions.iInsaneAPBonus = iniReader.ReadInteger("JA2 Tactical Settings","INSANE_AP_BONUS",0); - gGameExternalOptions.iPlayerAPBonus = iniReader.ReadInteger("JA2 Tactical Settings","PLAYER_AP_BONUS",0); + gGameExternalOptions.iEasyAPBonus = (INT8) iniReader.ReadInteger("JA2 Tactical Settings","NOVICE_AP_BONUS",0); + gGameExternalOptions.iExperiencedAPBonus = (INT8) iniReader.ReadInteger("JA2 Tactical Settings","EXPERIENCED_AP_BONUS",0); + gGameExternalOptions.iExpertAPBonus = (INT8) iniReader.ReadInteger("JA2 Tactical Settings","EXPERT_AP_BONUS",0); + gGameExternalOptions.iInsaneAPBonus = (INT8) iniReader.ReadInteger("JA2 Tactical Settings","INSANE_AP_BONUS",0); + gGameExternalOptions.iPlayerAPBonus = (INT8) iniReader.ReadInteger("JA2 Tactical Settings","PLAYER_AP_BONUS",0); // Sight range gGameExternalOptions.ubStraightSightRange = iniReader.ReadInteger("JA2 Tactical Settings","BASE_SIGHT_RANGE",13); @@ -451,7 +451,7 @@ void LoadGameExternalOptions() gGameExternalOptions.gfAllowSoldierToolTips = iniReader.ReadBoolean("JA2 Tactical Settings","ALLOW_SOLDIER_TOOL_TIPS",0); // ShadoWarrior: Tooltip changes (start) - gGameExternalOptions.ubSoldierTooltipDetailLevel = iniReader.ReadInteger("JA2 Tactical Settings", "SOLDIER_TOOLTIP_DETAIL_LEVEL", 1); + gGameExternalOptions.ubSoldierTooltipDetailLevel = (UINT8) iniReader.ReadInteger("JA2 Tactical Settings", "SOLDIER_TOOLTIP_DETAIL_LEVEL", 1); gGameExternalOptions.fEnableDynamicSoldierTooltips = iniReader.ReadBoolean("JA2 Tactical Settings", "DYNAMIC_SOLDIER_TOOLTIPS", TRUE); gGameExternalOptions.fEnableSoldierTooltipLocation = iniReader.ReadBoolean("JA2 Tactical Settings", "SOLDIER_TOOLTIP_DISPLAY_LOCATION", TRUE); @@ -531,7 +531,7 @@ void LoadGameExternalOptions() gGameExternalOptions.fSellAll = iniReader.ReadBoolean("JA2 Gameplay Settings","CAN_SELL_ALT_LMB",FALSE); - gGameExternalOptions.iPriceModifier = iniReader.ReadInteger("JA2 Gameplay Settings","PRICE_MODIFIER",10); + gGameExternalOptions.iPriceModifier = (INT16) iniReader.ReadInteger("JA2 Gameplay Settings","PRICE_MODIFIER",10); // WDS - Option to turn off stealing @@ -582,10 +582,10 @@ void LoadGameExternalOptions() gGameExternalOptions.iPercentElitesBonusExpert = iniReader.ReadInteger("JA2 Gameplay Settings","EXPERT_ELITE_BONUS",25); gGameExternalOptions.iPercentElitesBonusInsane = iniReader.ReadInteger("JA2 Gameplay Settings","INSANE_ELITE_BONUS",50); - gGameExternalOptions.ubMinEnemyGroupSizeNovice = iniReader.ReadInteger("JA2 Gameplay Settings","NOVICE_MIN_ENEMY_GROUP_SIZE",3); - gGameExternalOptions.ubMinEnemyGroupSizeExperienced = iniReader.ReadInteger("JA2 Gameplay Settings","EXPERIENCED_MIN_ENEMY_GROUP_SIZE",4); - gGameExternalOptions.ubMinEnemyGroupSizeExpert = iniReader.ReadInteger("JA2 Gameplay Settings","EXPERT_MIN_ENEMY_GROUP_SIZE",6); - gGameExternalOptions.ubMinEnemyGroupSizeInsane = iniReader.ReadInteger("JA2 Gameplay Settings","INSANE_MIN_ENEMY_GROUP_SIZE",12); + gGameExternalOptions.ubMinEnemyGroupSizeNovice = (UINT8) iniReader.ReadInteger("JA2 Gameplay Settings","NOVICE_MIN_ENEMY_GROUP_SIZE",3); + gGameExternalOptions.ubMinEnemyGroupSizeExperienced = (UINT8) iniReader.ReadInteger("JA2 Gameplay Settings","EXPERIENCED_MIN_ENEMY_GROUP_SIZE",4); + gGameExternalOptions.ubMinEnemyGroupSizeExpert = (UINT8) iniReader.ReadInteger("JA2 Gameplay Settings","EXPERT_MIN_ENEMY_GROUP_SIZE",6); + gGameExternalOptions.ubMinEnemyGroupSizeInsane = (UINT8) iniReader.ReadInteger("JA2 Gameplay Settings","INSANE_MIN_ENEMY_GROUP_SIZE",12); gGameExternalOptions.ubEasyEnemyStartingAlertLevel = iniReader.ReadInteger("JA2 Gameplay Settings","NOVICE_ENEMY_STARTING_ALERT_LEVEL", 5); gGameExternalOptions.ubNormalEnemyStartingAlertLevel = iniReader.ReadInteger("JA2 Gameplay Settings","NORMAL_ENEMY_STARTING_ALERT_LEVEL", 20); @@ -717,7 +717,7 @@ BOOLEAN GetCDLocation( ) { UINT32 uiStrngLength = 0; CHAR8 zCdLocation[ SGPFILENAME_LEN ]; - UINT32 uiDriveType=0; + //UINT32 uiDriveType=0; UINT32 uiRetVal=0; //Do a crude check to make sure the Ja2.ini file is the right on @@ -889,7 +889,7 @@ BOOLEAN CheckIfGameCdromIsInCDromDrive() CHAR8 zCdFile[ SGPFILENAME_LEN ]; CHAR8 zCdromRootDrive[512]; - BOOLEAN fFailed = FALSE; + //BOOLEAN fFailed = FALSE; UINT32 uiVolumeReturnValue; UINT32 uiLastError = ERROR_SUCCESS; diff --git a/Standard Gaming Platform/MemMan.h b/Standard Gaming Platform/MemMan.h index de18d627..b9b57282 100644 --- a/Standard Gaming Platform/MemMan.h +++ b/Standard Gaming Platform/MemMan.h @@ -68,6 +68,7 @@ extern void ShutdownMemoryManager( void ); extern PTR MemReallocXDebug( PTR ptr, UINT32 size, const STR8 szCodeString, INT32 iLineNum, void *pSpecial ); #else #ifdef _DEBUG + #include //This is another debug feature. Not as sophistocated, but definately not the pig the extreme system is. //This system reports all memory allocations/deallocations in the debug output. #define MemAlloc( size ) MemAllocReal( (size), __FILE__, __LINE__ ) @@ -76,6 +77,10 @@ extern void ShutdownMemoryManager( void ); extern PTR MemAllocReal( UINT32 size, const STR8 , INT32 ); extern void MemFreeReal( PTR ptr, const STR8 , INT32 ); extern PTR MemReallocReal( PTR ptr, UINT32 size, const STR8 , INT32 ); + //void* ::operator new( size_t sz, const char* file, int line); + //void* ::operator new[]( size_t sz, const char *file, int line); + #define NEW new + #define new NEW(_NORMAL_BLOCK, __FILE__, __LINE__) #else //Release build verison #include diff --git a/Strategic/Auto Resolve.cpp b/Strategic/Auto Resolve.cpp index 77f64fb7..c9b7328e 100644 --- a/Strategic/Auto Resolve.cpp +++ b/Strategic/Auto Resolve.cpp @@ -1958,7 +1958,7 @@ static void ARCreateMilitia( UINT8 mclass, INT32 i, INT16 sX, INT16 sY) ResetMortarsOnTeamCount(); if( !gpBattleGroup ) { - AssertMsg(0, "No battle group set while creating militia"); + //AssertMsg(0, "No battle group set while creating militia"); } if( mclass == SOLDIER_CLASS_ELITE_MILITIA ) diff --git a/Strategic/Scheduling.cpp b/Strategic/Scheduling.cpp index 0b695ace..5520bebb 100644 --- a/Strategic/Scheduling.cpp +++ b/Strategic/Scheduling.cpp @@ -182,6 +182,11 @@ void ProcessTacticalSchedule( UINT8 ubScheduleID ) #endif return; } + if (pSchedule->ubSoldierID == 0) + { + ScreenMsg( FONT_RED, MSG_INTERFACE, L"Schedule callback: Illegal soldier ID of %d.", pSchedule->ubSoldierID ); + return; + } //Validate the existance of the soldier. pSoldier = MercPtrs[ pSchedule->ubSoldierID ]; @@ -661,6 +666,11 @@ void AutoProcessSchedule( SCHEDULENODE *pSchedule, INT32 index ) pSoldier = MercPtrs[ pSchedule->ubSoldierID ]; + if (pSoldier->ubID == 0) + { + ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Soldier %s moved to away slot by schedule ID %d!", pSoldier->name, pSchedule->ubScheduleID ); + } + #ifdef JA2EDITOR if ( pSoldier->ubProfile != NO_PROFILE ) { diff --git a/Tactical/Enemy Soldier Save.cpp b/Tactical/Enemy Soldier Save.cpp index b0a6abe7..5d2b4d4c 100644 --- a/Tactical/Enemy Soldier Save.cpp +++ b/Tactical/Enemy Soldier Save.cpp @@ -282,7 +282,7 @@ BOOLEAN LoadEnemySoldiersFromTempFile() curr->pBasicPlacement->fPriorityExistance = TRUE; if( !curr->pDetailedPlacement ) { //need to upgrade the placement to detailed placement - curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT ); + curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT ); } //now replace the map pristine placement info with the temp map file version.. //memcpy( curr->pDetailedPlacement, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT ); @@ -475,7 +475,7 @@ BOOLEAN SaveEnemySoldiersToTempFile( INT16 sSectorX, INT16 sSectorY, INT8 bSecto { //need to upgrade the placement to detailed placement curr->pBasicPlacement->fDetailedPlacement = TRUE; // WDS - Clean up inventory handling - curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT ); + curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT ); //memset( curr->pDetailedPlacement, 0, SIZEOF_SOLDIERCREATE_STRUCT ); curr->pDetailedPlacement->initialize(); } @@ -1009,7 +1009,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() curr->pBasicPlacement->fPriorityExistance = TRUE; if( !curr->pDetailedPlacement ) { //need to upgrade the placement to detailed placement - curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT ); + curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT; //(SOLDIERCREATE_STRUCT*)MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT ); } //now replace the map pristine placement info with the temp map file version.. //memcpy( curr->pDetailedPlacement, &tempDetailedPlacement, SIZEOF_SOLDIERCREATE_STRUCT ); @@ -1582,7 +1582,7 @@ BOOLEAN NewWayOfSavingEnemyAndCivliansToTempFile( INT16 sSectorX, INT16 sSectorY { //need to upgrade the placement to detailed placement curr->pBasicPlacement->fDetailedPlacement = TRUE; // WDS - Clean up inventory handling - curr->pDetailedPlacement = new (MemAlloc( SIZEOF_SOLDIERCREATE_STRUCT )) SOLDIERCREATE_STRUCT; + curr->pDetailedPlacement = new SOLDIERCREATE_STRUCT; curr->pDetailedPlacement->initialize(); //memset( curr->pDetailedPlacement, 0, SIZEOF_SOLDIERCREATE_STRUCT ); } diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index 59aec155..dda283bd 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -4626,6 +4626,18 @@ BOOLEAN MakeSoldierTurn( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos ) INT16 sFacingDir, sAPCost, sAPCostToReady; UINT16 usAnimState; + // Make sure the merc is not collapsed! + if (!IsValidStance(pSoldier, ANIM_CROUCH) ) + { + if ( pSoldier->bCollapsed && pSoldier->bBreath < OKBREATH ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pSoldier->name ); + } + + return FALSE; + } + + // Get direction from mouse pos sFacingDir = GetDirectionFromXY( sXPos, sYPos, pSoldier ); @@ -4730,7 +4742,8 @@ UINT32 UIHandleLCLook( UI_EVENT *pUIEvent ) if ( MakeSoldierTurn( pSoldier, sXPos, sYPos ) ) { - SetUIBusy( pSoldier->ubID ); + // 0verhaul: Why do we set UI busy for a single soldier but not for a group of selected soldiers? + //SetUIBusy( pSoldier->ubID ); } } return( GAME_SCREEN ); diff --git a/Tactical/Inventory Choosing.cpp b/Tactical/Inventory Choosing.cpp index 03ca11eb..125b4cd6 100644 --- a/Tactical/Inventory Choosing.cpp +++ b/Tactical/Inventory Choosing.cpp @@ -978,33 +978,50 @@ void ChooseGrenadesForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bGrena return; // special mortar shell handling - if (bGrenadeClass == MORTAR_GRENADE_CLASS && itemMortar > 0 ) + if (bGrenadeClass == MORTAR_GRENADE_CLASS) { - usItem = PickARandomLaunchable ( itemMortar ); - if ( usItem > 0 ) + // 0verhaul: itemMortar can be 0 if the previous function + // 1) failed to find a Mortar that the soldier would want to use (due to XML prefs) + // 2) randomly chose not to supply a Mortar (always possible, even if choices exist). + // Since we should not go beyond this point in the case where Mortar Rounds are desired, + // return here in any case + if (itemMortar > 0 ) { - CreateItems( usItem, (INT8) (80 + Random(21)), bGrenades, &Object ); - Object.fFlags |= OBJECT_UNDROPPABLE; - PlaceObjectInSoldierCreateStruct( pp, &Object ); - - return; - } - } - - // special rpg rocket handling - if (bGrenadeClass == RPG_GRENADE_CLASS && itemRPG > 0 ) - { - usItem = PickARandomLaunchable ( itemRPG ); - if ( usItem > 0 ) - { - for ( int i = 0; i < bGrenades; i++ ) + usItem = PickARandomLaunchable ( itemMortar ); + if ( usItem > 0 ) { - CreateItem( usItem, (INT8) (70 + Random(31)), &Object ); + CreateItems( usItem, (INT8) (80 + Random(21)), bGrenades, &Object ); Object.fFlags |= OBJECT_UNDROPPABLE; PlaceObjectInSoldierCreateStruct( pp, &Object ); } - return; } + + return; + } + + // special rpg rocket handling + if (bGrenadeClass == RPG_GRENADE_CLASS) + { + // 0verhaul: itemRPG can be 0 if the previous function + // 1) failed to find an RPG that the soldier would want to use (due to XML prefs) + // 2) randomly chose not to supply an RPG (always possible, even if choices exist). + // Since we should not go beyond this point in the case where RPG grenades are desired, + // return here in any case + if (itemRPG > 0 ) + { + usItem = PickARandomLaunchable ( itemRPG ); + if ( usItem > 0 ) + { + for ( int i = 0; i < bGrenades; i++ ) + { + CreateItem( usItem, (INT8) (70 + Random(31)), &Object ); + Object.fFlags |= OBJECT_UNDROPPABLE; + PlaceObjectInSoldierCreateStruct( pp, &Object ); + } + + } + } + return; } Assert( bGrenadeClass <= 11 ); diff --git a/Tactical/PATHAI.cpp b/Tactical/PATHAI.cpp index d3c68ca3..f5bdb469 100644 --- a/Tactical/PATHAI.cpp +++ b/Tactical/PATHAI.cpp @@ -1096,7 +1096,16 @@ void AStarPathfinder::ExecuteAStarLogic() //movementG = (INT16) CalcG( &prevCost); //movementG = CalcAP( movementG, direction); - movementG = terrainCost * 100; + //movementG = terrainCost * 100; + movementG = terrainCost; + // Favor continuing in the same direction by increasing the cost for changing direction + int ParentParentNode = GetAStarParent( ParentNode); + if ((ParentParentNode != -1 && + ParentNode - ParentParentNode != CurrentNode - ParentNode) || + (ParentParentNode == -1 && (direction & 1) ) ) + { + movementG++; + } INT16 AStarG = baseGCost + movementG; //if the node is more costly in this path than in another open path, continue @@ -1629,7 +1638,7 @@ int AStarPathfinder::CalcH() int x = abs(n1->x - n2->x); int y = abs(n1->y - n2->y); -#if 0 +#if 1 if (x >= y) { return this->travelcostDiag * y + this->travelcostOrth * (x-y); @@ -4703,3 +4712,4 @@ UINT8 DoorTravelCost( SOLDIERTYPE * pSoldier, INT32 iGridNo, UINT8 ubMovementCos return( InternalDoorTravelCost( pSoldier, iGridNo, ubMovementCost, fReturnPerceivedValue, piDoorGridNo, FALSE ) ); } + diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index 476ef846..7c2e0480 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -252,8 +252,11 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) // CODE: SPECIAL MOVE CLIMB UP ROOF EVENT - // re-enable sight - gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT); + // Moved here because this represents "already on the roof", so breath collapses and interrupts should + // keep the soldier on the roof where he belongs + // Move merc up specific height + SetSoldierHeight( pSoldier, (FLOAT)50 ); + { INT16 sXPos, sYPos; @@ -261,6 +264,10 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) ConvertMapPosToWorldTileCenter( pSoldier->sTempNewGridNo, &sXPos, &sYPos ); EVENT_SetSoldierPosition( pSoldier, (FLOAT)sXPos, (FLOAT)sYPos ); } + + // re-enable sight + gTacticalStatus.uiFlags &= (~DISALLOW_SIGHT); + // Move two CC directions EVENT_SetSoldierDirection( pSoldier, gTwoCCDirection[ pSoldier->ubDirection ] ); @@ -273,9 +280,6 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) usUIMovementMode = GetMoveStateBasedOnStance( pSoldier, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); pSoldier->usUIMovementMode = usUIMovementMode; - // Move merc up specific height - SetSoldierHeight( pSoldier, (FLOAT)50 ); - // ATE: Change interface level..... // CJC: only if we are a player merc if (pSoldier->bTeam == gbPlayerNum) @@ -326,6 +330,9 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) // Move two C directions EVENT_SetSoldierDirection( pSoldier, gTwoCDirection[ pSoldier->ubDirection ] ); + // Remove the roof marker + HandlePlacingRoofMarker( pSoldier, pSoldier->sGridNo, FALSE, TRUE ); + EVENT_SetSoldierDesiredDirection( pSoldier, pSoldier->ubDirection ); // Adjust height SetSoldierHeight( pSoldier, (FLOAT)gClimbDownRoofStartDist[ pSoldier->ubBodyType ] ); diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 51589a0a..9fe0ecc0 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -3000,7 +3000,10 @@ void InternalSetSoldierHeight( SOLDIERTYPE *pSoldier, FLOAT dNewHeight, BOOLEAN return; } - if ( pSoldier->sHeightAdjustment > 0 ) + // 0verhaul: Changed this to half the wall height. During a climb up, a soldier's height increases to about 8, then falls + // to near 0 before being set to 50 at the end. The animation offsets should probably be changed to make this unnecessary + // but this is good enough to keep him from bouncing between level 1 and level 0 (and also triggering weird sight bugs). + if ( pSoldier->sHeightAdjustment > 25 ) { pSoldier->bLevel = SECOND_LEVEL; @@ -6084,6 +6087,7 @@ void TurnSoldier( SOLDIERTYPE *pSoldier) else { pSoldier->uiStatusFlags &= (~SOLDIER_TURNINGFROMHIT ); + pSoldier->fGettingHit = FALSE; } } else if ( pSoldier->fGettingHit == 2 ) @@ -6100,7 +6104,7 @@ void TurnSoldier( SOLDIERTYPE *pSoldier) //ReduceAttackBusyCount( ); //FREEUP GETTING HIT FLAG - // pSoldier->fGettingHit = FALSE; + pSoldier->fGettingHit = FALSE; } } @@ -11598,6 +11602,11 @@ void ChangeToFlybackAnimation( SOLDIERTYPE *pSoldier, UINT8 ubDirection ) // Remove any previous actions pSoldier->ubPendingAction = NO_PENDING_ACTION; + // Since we're manually setting our path, we have to reset these @#$@# flags too. Otherwise we don't reach the + // destination a lot of the time + pSoldier->fPastXDest = 0; + pSoldier->fPastYDest = 0; + // Set path.... pSoldier->usPathDataSize = 0; pSoldier->usPathIndex = 0; @@ -11638,6 +11647,11 @@ void ChangeToFallbackAnimation( SOLDIERTYPE *pSoldier, UINT8 ubDirection ) // Remove any previous actions pSoldier->ubPendingAction = NO_PENDING_ACTION; + // Since we're manually setting our path, we have to reset these @#$@# flags too. Otherwise we don't reach the + // destination a lot of the time + pSoldier->fPastXDest = 0; + pSoldier->fPastYDest = 0; + // Set path.... pSoldier->usPathDataSize = 0; pSoldier->usPathIndex = 0; diff --git a/Tactical/Soldier Create.cpp b/Tactical/Soldier Create.cpp index ba1de8bf..08a62456 100644 --- a/Tactical/Soldier Create.cpp +++ b/Tactical/Soldier Create.cpp @@ -751,7 +751,7 @@ SOLDIERTYPE* TacticalCreateSoldier( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 * UINT8 ubSectorID; ubSectorID = GetAutoResolveSectorID(); // WDS - Clean up inventory handling - pSoldier = new (MemAlloc( SIZEOF_SOLDIERTYPE )) SOLDIERTYPE; //(SOLDIERTYPE*)MemAlloc( SIZEOF_SOLDIERTYPE ); + pSoldier = new SOLDIERTYPE; //(SOLDIERTYPE*)MemAlloc( SIZEOF_SOLDIERTYPE ); if( !pSoldier ) return NULL; //memcpy( pSoldier, &Soldier, SIZEOF_SOLDIERTYPE ); @@ -2205,7 +2205,7 @@ SOLDIERTYPE* ReserveTacticalSoldierForAutoresolve( UINT8 ubSoldierClass ) // WDS - Clean up inventory handling //Allocate and copy the soldier - pSoldier = new (MemAlloc( SIZEOF_SOLDIERTYPE )) SOLDIERTYPE; //(SOLDIERTYPE*)MemAlloc( SIZEOF_SOLDIERTYPE ); + pSoldier = new SOLDIERTYPE; //(SOLDIERTYPE*)MemAlloc( SIZEOF_SOLDIERTYPE ); if( !pSoldier ) return NULL; // memcpy( pSoldier, MercPtrs[ i ], SIZEOF_SOLDIERTYPE ); @@ -2360,7 +2360,7 @@ SOLDIERTYPE* ReserveTacticalMilitiaSoldierForAutoresolve( UINT8 ubSoldierClass ) // WDS - Clean up inventory handling //Allocate and copy the soldier - pSoldier = new (MemAlloc( SIZEOF_SOLDIERTYPE )) SOLDIERTYPE; //(SOLDIERTYPE*)MemAlloc( SIZEOF_SOLDIERTYPE ); + pSoldier = new SOLDIERTYPE; //(SOLDIERTYPE*)MemAlloc( SIZEOF_SOLDIERTYPE ); if( !pSoldier ) return NULL; // memcpy( pSoldier, MercPtrs[ i ], SIZEOF_SOLDIERTYPE ); diff --git a/Tactical/Soldier Tile.cpp b/Tactical/Soldier Tile.cpp index 6fbf6577..542b8de3 100644 --- a/Tactical/Soldier Tile.cpp +++ b/Tactical/Soldier Tile.cpp @@ -516,6 +516,12 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) { RESETTIMECOUNTER( pSoldier->NextTileCounter, NEXT_TILE_CHECK_DELAY ); + // ATE: Allow path to exit grid! + if ( pSoldier->ubWaitActionToDo == 1 && gubWaitingForAllMercsToExitCode == WAIT_FOR_MERCS_TO_WALK_TO_GRIDNO ) + { + gfPlotPathToExitGrid = TRUE; + } + // Get direction from gridno... bCauseDirection = (INT8)GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, pSoldier->sDelayedMovementCauseGridNo ); @@ -534,6 +540,7 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) SetFinalTile( pSoldier, pSoldier->sGridNo, TRUE ); pSoldier->fDelayedMovement = FALSE; } + gfPlotPathToExitGrid = FALSE; return( TRUE ); } @@ -595,15 +602,7 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) sCheckGridNo = pSoldier->sFinalDestination; } - // Try another path to destination - // ATE: Allow path to exit grid! - if ( pSoldier->ubWaitActionToDo == 1 && gubWaitingForAllMercsToExitCode == WAIT_FOR_MERCS_TO_WALK_TO_GRIDNO ) - { - gfPlotPathToExitGrid = TRUE; - } - sCost = (INT16) FindBestPath( pSoldier, sCheckGridNo, pSoldier->bLevel, pSoldier->usUIMovementMode, NO_COPYROUTE, fFlags ); - gfPlotPathToExitGrid = FALSE; // Can we get there if ( sCost > 0 ) @@ -617,15 +616,8 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) { // Try to path around everyone except dest person - if ( pSoldier->ubWaitActionToDo == 1 && gubWaitingForAllMercsToExitCode == WAIT_FOR_MERCS_TO_WALK_TO_GRIDNO ) - { - gfPlotPathToExitGrid = TRUE; - } - sCost = (INT16) FindBestPath( pSoldier, sCheckGridNo, pSoldier->bLevel, pSoldier->usUIMovementMode, NO_COPYROUTE, PATH_IGNORE_PERSON_AT_DEST ); - gfPlotPathToExitGrid = FALSE; - // Is the next tile in this new path blocked too? sNewGridNo = NewGridNo( (UINT16)pSoldier->sGridNo, DirectionInc( (UINT8)guiPathingData[ 0 ] ) ); @@ -633,6 +625,7 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) // now working with a path which does not go through people pSoldier->ubDelayedMovementFlags &= (~DELAYED_MOVEMENT_FLAG_PATH_THROUGH_PEOPLE); + } else { @@ -646,12 +639,6 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) // Are we clear? if ( bPathBlocked == MOVE_TILE_CLEAR ) { - // Go for it path! - if ( pSoldier->ubWaitActionToDo == 1 && gubWaitingForAllMercsToExitCode == WAIT_FOR_MERCS_TO_WALK_TO_GRIDNO ) - { - gfPlotPathToExitGrid = TRUE; - } - //pSoldier->fDelayedMovement = FALSE; // ATE: THis will get set in EENT_GetNewSoldierPath.... pSoldier->usActionData = sCheckGridNo; @@ -659,8 +646,8 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) pSoldier->bPathStored = FALSE; EVENT_GetNewSoldierPath( pSoldier, sCheckGridNo, pSoldier->usUIMovementMode ); - gfPlotPathToExitGrid = FALSE; + gfPlotPathToExitGrid = FALSE; return( TRUE ); } } @@ -707,6 +694,7 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) NPCReachedDestination( pSoldier, FALSE ); pSoldier->bNextAction = AI_ACTION_WAIT; pSoldier->usNextActionData = 500; + gfPlotPathToExitGrid = FALSE; return( TRUE ); } } @@ -743,6 +731,8 @@ BOOLEAN HandleNextTileWaiting( SOLDIERTYPE *pSoldier ) } } } + + gfPlotPathToExitGrid = FALSE; return( TRUE ); } diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp index 7b1b6f32..e568dd92 100644 --- a/Tactical/Turn Based Input.cpp +++ b/Tactical/Turn Based Input.cpp @@ -250,7 +250,7 @@ void QueryTBLeftButton( UINT32 *puiNewEvent ) SOLDIERTYPE *pSoldier; UINT16 usMapPos; static BOOLEAN fClickHoldIntercepted = FALSE; - BOOLEAN fOnInterTile = FALSE; + //BOOLEAN fOnInterTile = FALSE; static BOOLEAN fCanCheckForSpeechAdvance = FALSE; static INT16 sMoveClickGridNo = 0; @@ -2347,6 +2347,17 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) BOOLEAN fNearLowerLevel; INT8 bDirection; + // Make sure the merc is not collapsed! + if (!IsValidStance(pjSoldier, ANIM_CROUCH) ) + { + if ( pjSoldier->bCollapsed && pjSoldier->bBreath < OKBREATH ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pjSoldier->name ); + } + + break; + } + GetMercClimbDirection( pjSoldier->ubID, &fNearLowerLevel, &fNearHeigherLevel ); if ( fNearLowerLevel ) diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index c13d0819..52aac376 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -51,6 +51,7 @@ #include "Quests.h" #include "Campaign Types.h" #include "Queen Command.h" +#include "cheats.h" #endif extern void PauseAITemporarily( void ); @@ -1922,6 +1923,11 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier) // to get here, we MUST have an action selected, but not in progress... + if ( CHEATER_CHEAT_LEVEL( ) ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Soldier %d decides action %d with data %d", pSoldier->ubID, pSoldier->bAction, pSoldier->usActionData ); + } + // see if we can afford to do this action if (IsActionAffordable(pSoldier)) { diff --git a/TacticalAI/AIUtils.cpp b/TacticalAI/AIUtils.cpp index 24b9a476..3c894437 100644 --- a/TacticalAI/AIUtils.cpp +++ b/TacticalAI/AIUtils.cpp @@ -2283,7 +2283,8 @@ INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT16 * pusFromGridNo) else { return( 5 ); - } case ONGUARD: return( 5 ); + } + case ONGUARD: return( 5 ); case CLOSEPATROL: return( 15 ); case RNDPTPATROL: case POINTPATROL: return(10 ); // from nextPatrolGrid, not whereIWas @@ -2305,6 +2306,7 @@ INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT16 * pusFromGridNo) } case SEEKENEMY: *pusFromGridNo = pSoldier->sGridNo; // from current position! return(MAX_ROAMING_RANGE); + case SNIPER: return ( 5 ); default: #ifdef BETAVERSION sprintf(tempstr,"%s has invalid orders = %d",pSoldier->name,pSoldier->bOrders); diff --git a/TacticalAI/DecideAction.cpp b/TacticalAI/DecideAction.cpp index 35cead57..652fabde 100644 --- a/TacticalAI/DecideAction.cpp +++ b/TacticalAI/DecideAction.cpp @@ -924,7 +924,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) // CLIMB A BUILDING //////////////////////////////////////////////////////////////////////////// - if (!fCivilian) + if (!fCivilian && pSoldier->bLastAction != AI_ACTION_CLIMB_ROOF) { iChance = 10 + pSoldier->bBypassToGreen; @@ -965,30 +965,40 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) // reduce chance if breath is down //iChance -= (100 - pSoldier->bBreath); // don't care + // This is the chance that we want to be on the roof. If already there, invert the chance to see if we want back + // down + if (pSoldier->bLevel > 0) + { + iChance = 100 - iChance; + } + if ((INT16) PreRandom(100) < iChance) { + BOOLEAN fUp = FALSE; if ( pSoldier->bLevel == 0 ) { - BOOLEAN fUp = TRUE; - if (pSoldier->bLevel > 0 ) - fUp = FALSE; + fUp = TRUE; + } + else if (pSoldier->bLevel > 0 ) + { + fUp = FALSE; + } - if ( CanClimbFromHere ( pSoldier, fUp ) ) + if ( CanClimbFromHere ( pSoldier, fUp ) ) + { + DebugMsg ( TOPIC_JA2AI , DBG_LEVEL_3 , String("Soldier %d is climbing roof",pSoldier->ubID) ); + return( AI_ACTION_CLIMB_ROOF ); + } + else + { + pSoldier->usActionData = FindClosestClimbPoint(pSoldier, fUp ); + // Added the check here because sniper militia who are locked inside of a building without keys + // will still have a >100% chance to want to climb, which means an infinite loop. In fact, any + // time a move is desired, there probably also will be a need to check for a path. + if ( pSoldier->usActionData != NOWHERE && + LegalNPCDestination(pSoldier,pSoldier->usActionData,ENSURE_PATH,WATEROK, 0 )) { - DebugMsg ( TOPIC_JA2AI , DBG_LEVEL_3 , String("Soldier %d is climbing roof",pSoldier->ubID) ); - return( AI_ACTION_CLIMB_ROOF ); - } - else - { - pSoldier->usActionData = FindClosestClimbPoint(pSoldier, fUp ); - // Added the check here because sniper militia who are locked inside of a building without keys - // will still have a >100% chance to want to climb, which means an infinite loop. In fact, any - // time a move is desired, there probably also will be a need to check for a path. - if ( pSoldier->usActionData != NOWHERE && - LegalNPCDestination(pSoldier,pSoldier->usActionData,ENSURE_PATH,WATEROK, 0 )) - { - return( AI_ACTION_MOVE_TO_CLIMB ); - } + return( AI_ACTION_MOVE_TO_CLIMB ); } } } diff --git a/TileEngine/Exit Grids.cpp b/TileEngine/Exit Grids.cpp index 92e4d2d9..736807f9 100644 --- a/TileEngine/Exit Grids.cpp +++ b/TileEngine/Exit Grids.cpp @@ -299,8 +299,6 @@ UINT16 FindGridNoFromSweetSpotCloseToExitGrid( SOLDIERTYPE *pSoldier, INT16 sSwe //(use the fake soldier and the pathing settings) FindBestPath( &soldier, NOWHERE, 0, WALKING, COPYREACHABLE, PATH_THROUGH_PEOPLE ); - gfPlotPathToExitGrid = FALSE; - uiLowestRange = 999999; for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ ) @@ -337,6 +335,8 @@ UINT16 FindGridNoFromSweetSpotCloseToExitGrid( SOLDIERTYPE *pSoldier, INT16 sSwe } } } + + gfPlotPathToExitGrid = FALSE; gubNPCAPBudget = ubSaveNPCAPBudget; gubNPCDistLimit = ubSaveNPCDistLimit; diff --git a/gamescreen.cpp b/gamescreen.cpp index 20feea77..6567fd36 100644 --- a/gamescreen.cpp +++ b/gamescreen.cpp @@ -583,7 +583,7 @@ UINT32 MainGameScreenHandle(void) // Check timer that could have been set to do anything CheckCustomizableTimer(); - // HAndle physics engine + // Handle physics engine SimulateWorld( ); // Handle strategic engine