mirror of
https://github.com/1dot13/source.git
synced 2026-07-29 13:52:17 +02:00
New feature: delayed grenade explosions:
- use transformation menu to change explosion mode - only Normal/Stun/Flashbang type grenades can be delayed - AI soldiers will avoid staying close to armed grenades\explosives - use option DELAYED_GRENADE_EXPLOSION to make all hand\GL grenades work as delayed - new value AP_GRENADE_MODE = 4 in APBPConstants.ini - new item flag DELAYED_GRENADE_EXPLOSION Other changes: - fixed call to sqrt in DrawExplosionWarning() that prevented compiling in VS2010 - correctly update interface after transformations - PATHAI: AI soldiers will skip gassed tiles if not in gas already - InGas check: AI soldiers will avoid mustard gas even when wearing gas mask - Yellow AI: added check to avoid gas/water/bomb using FindNearestUngassedLand - gas/flare grenades will always explode instantly even when in bad state - LegalNPCDestination: locations near armed bombs are not legal - FindBestNearbyCover: avoid locations near armed bombs git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8324 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -1478,6 +1478,8 @@ void LoadGameExternalOptions()
|
||||
// <GasCan>, <Marbles> and <Alcohol> add special bonuses to explosion
|
||||
gGameExternalOptions.bAllowSpecialExplosiveAttachments = iniReader.ReadBoolean("Tactical Interface Settings","ALLOW_SPECIAL_EXPLOSIVE_ATTACHMENTS",FALSE);
|
||||
|
||||
gGameExternalOptions.fDelayedGrenadeExplosion = iniReader.ReadBoolean("Tactical Interface Settings","DELAYED_GRENADE_EXPLOSION",FALSE);
|
||||
|
||||
// Chance to Say Annoying Phrase (you can just turn of it by button in game)
|
||||
gGameExternalOptions.iChanceSayAnnoyingPhrase = iniReader.ReadInteger("Tactical Interface Settings","CHANCE_SAY_ANNOYING_PHRASE",100);
|
||||
|
||||
@@ -3263,6 +3265,7 @@ void LoadGameAPBPConstants()
|
||||
APBPConstants[BAD_AP_COST] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","BAD_AP_COST",36),36);
|
||||
APBPConstants[AP_RELOAD_LOOSE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_RELOAD_LOOSE",8),8);
|
||||
APBPConstants[AP_UNJAM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_UNJAM",2),2);
|
||||
APBPConstants[AP_GRENADE_MODE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_GRENADE_MODE",4),4);
|
||||
|
||||
// WANNE: APs needed when you jump through a window
|
||||
APBPConstants[AP_JUMPWINDOW] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_JUMPWINDOW",40),40);
|
||||
|
||||
@@ -867,6 +867,7 @@ typedef struct
|
||||
BOOLEAN bAddSmokeAfterExplosion;
|
||||
BOOLEAN bAllowExplosiveAttachments;
|
||||
BOOLEAN bAllowSpecialExplosiveAttachments;
|
||||
BOOLEAN fDelayedGrenadeExplosion;
|
||||
INT16 iChanceSayAnnoyingPhrase;
|
||||
BOOLEAN bNewTacticalAIBehavior;
|
||||
BOOLEAN fAIYellowFlanking;
|
||||
|
||||
@@ -99,6 +99,7 @@ AP_SEVENTH_CLICK_AIM_SCOPE,
|
||||
AP_EIGHTH_CLICK_AIM_SCOPE,
|
||||
AP_RELOAD_LOOSE,
|
||||
AP_UNJAM,
|
||||
AP_GRENADE_MODE,
|
||||
|
||||
AP_JUMPWINDOW, //WANNE: jump window APs
|
||||
|
||||
|
||||
@@ -636,7 +636,7 @@ void DrawExplosionWarning( INT32 sGridno, INT8 usLevel, INT8 usDelay )
|
||||
{
|
||||
for ( INT32 y = yl; y <= yh; ++y )
|
||||
{
|
||||
FLOAT diff = std::sqrt( (sScreenX - x) * (sScreenX - x) + 2 * (sScreenY - y) * (sScreenY - y) );
|
||||
FLOAT diff = std::sqrt( (FLOAT)((sScreenX - x) * (sScreenX - x) + 2 * (sScreenY - y) * (sScreenY - y)) );
|
||||
|
||||
if ( radius_inner <= diff && diff <= radius_outer )
|
||||
{
|
||||
|
||||
@@ -82,6 +82,9 @@
|
||||
#include "Explosion Control.h" // added by Flugente
|
||||
#include "Food.h" // added by Flugente
|
||||
#include "Encyclopedia_new.h" //Moa: enc. item visibility
|
||||
// sevenfm:
|
||||
#include "Soldier Control.h"
|
||||
#include "Sound Control.h"
|
||||
#endif
|
||||
|
||||
#include "Multi Language Graphic Utils.h"
|
||||
@@ -341,6 +344,11 @@ BOOLEAN TransformationMenuPopup_Arm_TestValid(OBJECTTYPE * pObj);
|
||||
void BombInventoryMessageBoxCallBack( UINT8 ubExitValue );
|
||||
void BombInventoryDisArmMessageBoxCallBack( UINT8 ubExitValue );
|
||||
|
||||
// sevenfm:
|
||||
// delayed grenade explosion
|
||||
BOOLEAN TransformationMenuPopup_DelayedGrenadeExplosion_TestValid(OBJECTTYPE* pObj);
|
||||
void TransformationMenuPopup_DelayedGrenadeExplosion();
|
||||
|
||||
// HEADROCK HAM 5: The maximum number of attachment asterisks shown for an item.
|
||||
UINT32 guiAttachmentAsterisks;
|
||||
#define MAX_NUM_ASTERISKS 10
|
||||
@@ -4266,6 +4274,26 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec
|
||||
gprintfinvalidate( sNewX, sNewY, pStr );
|
||||
}
|
||||
|
||||
// sevenfm: display asterisk if grenade is delayed
|
||||
if( Item[pObject->usItem].usItemClass == IC_GRENADE && (*pObject)[0]->data.sObjectFlag & DELAYED_GRENADE_EXPLOSION )
|
||||
{
|
||||
sNewY = sY + sHeight - 10;
|
||||
SetRGBFontForeground( 120, 120, 120 );
|
||||
swprintf( pStr, L"*" );
|
||||
|
||||
// Get length of string
|
||||
uiStringLength=StringPixLength(pStr, ITEM_FONT );
|
||||
|
||||
sNewX = sX + sWidth - uiStringLength - 4;
|
||||
|
||||
if ( uiBuffer == guiSAVEBUFFER )
|
||||
{
|
||||
RestoreExternBackgroundRect( sNewX, sNewY, 15, 15 );
|
||||
}
|
||||
mprintf( sNewX, sNewY, pStr );
|
||||
gprintfinvalidate( sNewX, sNewY, pStr );
|
||||
}
|
||||
|
||||
// Flugente: if ammo is used to feed a gun externally, show ammo count left on this ammo
|
||||
if ( gGameExternalOptions.ubExternalFeeding > 0 && (Item[pObject->usItem].usItemClass & (IC_AMMO)) && ObjectIsExternalFeeder(pSoldier, pObject) )
|
||||
{
|
||||
@@ -6844,8 +6872,9 @@ void RenderItemDescriptionBox( )
|
||||
// - the item is a bomb and has a detonator or remote detonator attached
|
||||
BOOLEAN renderTransformIcon = FALSE;
|
||||
if ( ((guiCurrentScreen == GAME_SCREEN || guiCurrentScreen == MAP_SCREEN) && gpItemDescObject->ubNumberOfObjects == 1) &&
|
||||
((Item[gpItemDescObject->usItem].usItemClass == IC_GRENADE) ||
|
||||
((Item[gpItemDescObject->usItem].usItemClass == IC_BOMB) && HasAttachmentOfClass( gpItemDescObject, (AC_DETONATOR | AC_REMOTEDET) ))) )
|
||||
((Item[gpItemDescObject->usItem].usItemClass == IC_GRENADE) ||
|
||||
((Item[gpItemDescObject->usItem].usItemClass == IC_BOMB) && HasAttachmentOfClass( gpItemDescObject, (AC_DETONATOR | AC_REMOTEDET) )) ||
|
||||
CanDelayGrenadeExplosion(gpItemDescObject->usItem) && Item[ gpItemDescObject->usItem ].ubCursor == TOSSCURS) )
|
||||
{
|
||||
renderTransformIcon = TRUE;
|
||||
}
|
||||
@@ -13400,6 +13429,37 @@ void ItemDescTransformRegionCallback( MOUSE_REGION *pRegion, INT32 reason )
|
||||
// onyl allow transformations if the item is not an armed bomb
|
||||
if ( !fHaveToDisarm )
|
||||
{
|
||||
// Check if grenade can be delayed
|
||||
// don't allow this transformation if player selected option to make all grenades work in delayed mode
|
||||
if( !gGameExternalOptions.fDelayedGrenadeExplosion &&
|
||||
CanDelayGrenadeExplosion(gpItemDescObject->usItem) &&
|
||||
Item[ gpItemDescObject->usItem ].ubCursor == TOSSCURS )
|
||||
{
|
||||
UINT16 usAPCost = APBPConstants[AP_GRENADE_MODE];
|
||||
CHAR16 MenuRowText[300];
|
||||
|
||||
if ( usAPCost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED )
|
||||
{
|
||||
if( (*gpItemDescObject)[0]->data.sObjectFlag & DELAYED_GRENADE_EXPLOSION )
|
||||
swprintf (MenuRowText, gzTransformationMessage[13], usAPCost );
|
||||
else
|
||||
swprintf (MenuRowText, gzTransformationMessage[14], usAPCost );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (*gpItemDescObject)[0]->data.sObjectFlag & DELAYED_GRENADE_EXPLOSION )
|
||||
swprintf (MenuRowText, gzTransformationMessage[11]);
|
||||
else
|
||||
swprintf (MenuRowText, gzTransformationMessage[12]);
|
||||
}
|
||||
|
||||
// Add option
|
||||
POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction<void,void>( &TransformationMenuPopup_DelayedGrenadeExplosion ));
|
||||
pOption->setAvail(new popupCallbackFunction<bool,OBJECTTYPE*>( &TransformationMenuPopup_DelayedGrenadeExplosion_TestValid, gpItemDescObject ));
|
||||
gItemDescTransformPopup->addOption( *pOption );
|
||||
fFoundTransformations = true;
|
||||
}
|
||||
|
||||
for ( INT32 x = 0; x < gMAXITEMS_READ; ++x )
|
||||
{
|
||||
if (Transform[x].usItem == (UINT16)-1)
|
||||
@@ -13564,6 +13624,12 @@ BOOLEAN TransformationMenuPopup_TestValid(TransformInfoStruct * Transform)
|
||||
// Flugente: This function handles callback when the 'ARM' option in the item transformation menu is clicked
|
||||
void TransformationMenuPopup_Arm( OBJECTTYPE* pObj )
|
||||
{
|
||||
// sevenfm: hide transformation menu
|
||||
if (gItemDescTransformPopup != NULL && gfItemDescTransformPopupInitialized == TRUE)
|
||||
{
|
||||
gItemDescTransformPopup->hide();
|
||||
}
|
||||
|
||||
// cant handle item stacks here
|
||||
if (gpItemDescObject->ubNumberOfObjects > 1)
|
||||
{
|
||||
@@ -13625,6 +13691,11 @@ void TransformationMenuPopup_Arm( OBJECTTYPE* pObj )
|
||||
|
||||
DeleteObj( pObj );
|
||||
|
||||
// sevenfm: correctly update interface
|
||||
gfSkipDestroyTransformPopup = TRUE;
|
||||
DeleteItemDescriptionBox();
|
||||
gfSkipDestroyTransformPopup = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13779,6 +13850,11 @@ void BombInventoryMessageBoxCallBack( UINT8 ubExitValue )
|
||||
|
||||
DeleteObj( gpItemDescObject );
|
||||
|
||||
// sevenfm: correctly update interface
|
||||
gfSkipDestroyTransformPopup = TRUE;
|
||||
DeleteItemDescriptionBox();
|
||||
gfSkipDestroyTransformPopup = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -13957,6 +14033,11 @@ void BombInventoryDisArmMessageBoxCallBack( UINT8 ubExitValue )
|
||||
|
||||
DeleteObj( gpItemDescObject );
|
||||
|
||||
// sevenfm: correctly update interface
|
||||
gfSkipDestroyTransformPopup = TRUE;
|
||||
DeleteItemDescriptionBox();
|
||||
gfSkipDestroyTransformPopup = FALSE;
|
||||
|
||||
#ifdef JA2TESTVERSION
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Arming failed, explosion here" );
|
||||
#endif
|
||||
@@ -14461,4 +14542,56 @@ void UpdateMercBodyRegionHelpText( )
|
||||
|
||||
SetRegionFastHelpText( &gSMInvCamoRegion, sString );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN TransformationMenuPopup_DelayedGrenadeExplosion_TestValid(OBJECTTYPE* pObj)
|
||||
{
|
||||
if (pObj == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT16 usAPCost = APBPConstants[AP_GRENADE_MODE];
|
||||
INT32 iBPCost = 0;
|
||||
|
||||
if (EnoughPoints( gpItemDescSoldier, usAPCost, iBPCost, false ))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sevenfm: change status of delayed grenade explosion
|
||||
void TransformationMenuPopup_DelayedGrenadeExplosion()
|
||||
{
|
||||
UINT16 usAPCost = APBPConstants[AP_GRENADE_MODE];
|
||||
INT32 iBPCost = 0;
|
||||
|
||||
if (gItemDescTransformPopup != NULL && gfItemDescTransformPopupInitialized == TRUE)
|
||||
{
|
||||
gItemDescTransformPopup->hide();
|
||||
}
|
||||
|
||||
if(EnoughPoints(gpItemDescSoldier, usAPCost, iBPCost, FALSE))
|
||||
{
|
||||
DeductPoints(gpItemDescSoldier, usAPCost, iBPCost);
|
||||
|
||||
if( (*gpItemDescObject)[0]->data.sObjectFlag & DELAYED_GRENADE_EXPLOSION )
|
||||
{
|
||||
(*gpItemDescObject)[0]->data.sObjectFlag &= ~DELAYED_GRENADE_EXPLOSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*gpItemDescObject)[0]->data.sObjectFlag |= DELAYED_GRENADE_EXPLOSION;
|
||||
}
|
||||
PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, SoundVolume( MIDVOLUME, gpItemDescSoldier->sGridNo ), 1, SoundDir( gpItemDescSoldier->sGridNo ) );
|
||||
|
||||
RenderItemDescriptionBox();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -820,6 +820,7 @@ extern OBJECTTYPE gTempObject;
|
||||
#define TAKEN_BY_MILITIA_TABOO_BLUE 0x0000000800000000 // 34359738368 // this item is taboo for blue militia (have to reset flag for world item upon dropping it)
|
||||
|
||||
#define INFECTED 0x0000001000000000 // // this item is infected with disease 0, getting damaged by this will infect you
|
||||
#define DELAYED_GRENADE_EXPLOSION 0x0000002000000000 // // grenade will blow up on next turn
|
||||
|
||||
// Flugente TODO 2012-09-17: next time we break savegame compatibility, extend the flagmasks from UINT32 to UINT64. I didn't do it this time (see double-used flag above), as we try to minimise those breaks. But it is needed.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
+27
-1
@@ -15568,4 +15568,30 @@ FLOAT GetAttackAPTraitMultiplier( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, UINT8
|
||||
}
|
||||
|
||||
return fMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
// check if item is grenade and it can use delayed explosion
|
||||
BOOLEAN CanDelayGrenadeExplosion( UINT16 usItem )
|
||||
{
|
||||
// check that item is a grenade
|
||||
if( Item[ usItem ].usItemClass != IC_GRENADE )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check that grenade type is not gas/smoke/fire or flare
|
||||
if( Explosive[Item[ usItem ].ubClassIndex].ubType != EXPLOSV_NORMAL &&
|
||||
Explosive[ Item[ usItem ].ubClassIndex ].ubType != EXPLOSV_STUN &&
|
||||
Explosive[ Item[ usItem ].ubClassIndex ].ubType != EXPLOSV_FLASHBANG )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check if grenade should always explode on impact
|
||||
if( Explosive[Item[ usItem ].ubClassIndex].fExplodeOnImpact )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+3
-3
@@ -548,7 +548,7 @@ BOOLEAN ObjectIsMilitiaRelevant( OBJECTTYPE *pObj );
|
||||
|
||||
FLOAT GetAttackAPTraitMultiplier( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, UINT8 ubMode);
|
||||
|
||||
// sevenfm: check if this type of grenade can use delayed mode
|
||||
BOOLEAN CanDelayGrenadeExplosion( UINT16 usItem );
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ class SOLDIERTYPE;
|
||||
|
||||
extern UINT16 gubAnimSurfaceIndex[ TOTALBODYTYPES ][ NUMANIMATIONSTATES ];
|
||||
|
||||
// sevenfm:
|
||||
extern BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
|
||||
//extern UINT8 gubDiagCost[20];
|
||||
// skiplist has extra level of pointers every 4 elements, so a level 5is optimized for
|
||||
// 4 to the power of 5 elements, or 2 to the power of 10, 1024
|
||||
@@ -3128,6 +3131,14 @@ if(!GridNoOnVisibleWorldTile(iDestination))
|
||||
goto NEXTDIR;
|
||||
}
|
||||
|
||||
// sevenfm: skip gas if not in gas already
|
||||
if( !(s->flags.uiStatusFlags & SOLDIER_PC) &&
|
||||
InGas(s, newLoc) &&
|
||||
!InGas(s, s->sGridNo) )
|
||||
{
|
||||
goto NEXTDIR;
|
||||
}
|
||||
|
||||
// WANNE: Know mines (for enemy or player) do not explode - BEGIN
|
||||
if ( gpWorldLevelData[newLoc].uiFlags & (MAPELEMENT_ENEMY_MINE_PRESENT | MAPELEMENT_PLAYER_MINE_PRESENT) )
|
||||
{
|
||||
|
||||
+50
-3
@@ -2011,7 +2011,8 @@ INT16 InWaterOrGas(SOLDIERTYPE *pSoldier, INT32 sGridNo)
|
||||
}
|
||||
|
||||
BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
||||
{//WarmSteel - One square away from gas is still considered in gas, because it could expand any moment.
|
||||
{
|
||||
//WarmSteel - One square away from gas is still considered in gas, because it could expand any moment.
|
||||
//Note: this only works for gas that expands with one tile, but hey it's better than nothing!
|
||||
int iNeighbourGridNo;
|
||||
for(int iDir = 0; iDir < NUM_WORLD_DIRECTIONS; ++iDir)
|
||||
@@ -2020,12 +2021,13 @@ BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
||||
if(!TileIsOutOfBounds(iNeighbourGridNo))
|
||||
{
|
||||
// tear/mustard gas
|
||||
if((gpWorldLevelData[iNeighbourGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_TEARGAS|MAPELEMENT_EXT_MUSTARDGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 200909
|
||||
if((gpWorldLevelData[iNeighbourGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_TEARGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 200909
|
||||
{
|
||||
return(TRUE);
|
||||
}
|
||||
// sevenfm: avoid mustard gas even when wearing gas mask
|
||||
// fire/creature gas
|
||||
if(gpWorldLevelData[iNeighbourGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_BURNABLEGAS|MAPELEMENT_EXT_CREATUREGAS))//dnl ch62 240813
|
||||
if(gpWorldLevelData[iNeighbourGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_MUSTARDGAS|MAPELEMENT_EXT_BURNABLEGAS|MAPELEMENT_EXT_CREATUREGAS))//dnl ch62 240813
|
||||
{
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -3979,3 +3981,48 @@ UINT8 CountTeamSeeSoldier( INT8 bTeam, SOLDIERTYPE *pSoldier )
|
||||
|
||||
return ubFriends;
|
||||
}
|
||||
|
||||
BOOLEAN FindBombNearby( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDistance )
|
||||
{
|
||||
UINT32 uiBombIndex;
|
||||
INT32 sCheckGridno;
|
||||
OBJECTTYPE *pObj;
|
||||
|
||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||
|
||||
// determine maximum horizontal limits
|
||||
sMaxLeft = min( ubDistance, (sGridNo % MAXCOL));
|
||||
sMaxRight = min( ubDistance, MAXCOL - ((sGridNo % MAXCOL) + 1));
|
||||
|
||||
// determine maximum vertical limits
|
||||
sMaxUp = min( ubDistance, (sGridNo / MAXROW));
|
||||
sMaxDown = min( ubDistance, MAXROW - ((sGridNo / MAXROW) + 1));
|
||||
|
||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||
{
|
||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||
{
|
||||
sCheckGridno = sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
|
||||
if( TileIsOutOfBounds(sCheckGridno) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// search all bombs that we can see
|
||||
for (uiBombIndex = 0; uiBombIndex < guiNumWorldBombs; uiBombIndex++)
|
||||
{
|
||||
if (gWorldBombs[ uiBombIndex ].fExists &&
|
||||
gWorldItems[ gWorldBombs[ uiBombIndex ].iItemIndex ].sGridNo == sCheckGridno &&
|
||||
gWorldItems[ gWorldBombs[ uiBombIndex ].iItemIndex ].ubLevel == pSoldier->pathing.bLevel &&
|
||||
gWorldItems[ gWorldBombs[ uiBombIndex ].iItemIndex ].bVisible == VISIBLE &&
|
||||
gWorldItems[ gWorldBombs[ uiBombIndex ].iItemIndex ].usFlags & WORLD_ITEM_ARMED_BOMB )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1084,7 +1084,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
|
||||
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: get out of water and gas"));
|
||||
|
||||
if (bInWater || bInGas)
|
||||
if (bInWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8))
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
@@ -1543,11 +1543,11 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
BOOLEAN fReachable;
|
||||
#ifdef DEBUGDECISIONS
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Flugente: to prevent an accidental call
|
||||
if ( pSoldier->IsZombie() )
|
||||
return( ZombieDecideActionYellow(pSoldier) );
|
||||
return( ZombieDecideActionYellow(pSoldier) );
|
||||
|
||||
if (fCivilian || (gGameExternalOptions.fAllNamedNpcsDecideAction && pSoldier->ubProfile != NO_PROFILE))
|
||||
{
|
||||
@@ -1602,6 +1602,20 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// WHEN IN GAS, GO TO NEAREST REACHABLE SPOT OF UNGASSED LAND
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if ( InGas(pSoldier, pSoldier->sGridNo) || DeepWater( pSoldier->sGridNo, pSoldier->pathing.bLevel ) || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8) )
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||
{
|
||||
return(AI_ACTION_LEAVE_WATER_GAS);
|
||||
}
|
||||
}
|
||||
|
||||
// determine the most important noise heard, and its relative value
|
||||
sNoiseGridNo = MostImportantNoiseHeard(pSoldier,&iNoiseValue, &fClimb, &fReachable);
|
||||
//NumMessage("iNoiseValue = ",iNoiseValue);
|
||||
@@ -2537,7 +2551,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
||||
// WHEN IN GAS, GO TO NEAREST REACHABLE SPOT OF UNGASSED LAND
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (bInGas && ubCanMove)
|
||||
if (ubCanMove && (bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8)))
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
@@ -4712,7 +4726,7 @@ INT16 ubMinAPCost;
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// if soldier in water/gas has enough APs left to move at least 1 square
|
||||
if ( ( bInDeepWater || bInGas ) && ubCanMove)
|
||||
if ( ( bInDeepWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8) ) && ubCanMove)
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
|
||||
@@ -987,6 +987,12 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
continue;
|
||||
}
|
||||
|
||||
// sevenfm: avoid tiles near bombs
|
||||
if( FindBombNearby(pSoldier, sGridNo, DAY_VISION_RANGE / 8))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
iPathCost = gubAIPathCosts[AI_PATHCOST_RADIUS + sXOffset][AI_PATHCOST_RADIUS + sYOffset];
|
||||
/*
|
||||
// water is OK, if the only good hiding place requires us to get wet, OK
|
||||
|
||||
+13
-22
@@ -59,28 +59,19 @@ int LegalNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubPathMode,
|
||||
// skip mercs if turnbased and adjacent AND not doing an IGNORE_PATH check (which is used almost exclusively by GoAsFarAsPossibleTowards)
|
||||
fSkipTilesWithMercs = (gfTurnBasedAI && ubPathMode != IGNORE_PATH && SpacesAway( pSoldier->sGridNo, sGridNo ) == 1 );
|
||||
|
||||
// if this gridno is an OK destination
|
||||
// AND the gridno is NOT in a tear-gassed tile when we have no gas mask
|
||||
// AND someone is NOT already standing there
|
||||
// AND we're NOT already standing at that gridno
|
||||
// AND the gridno hasn't been black-listed for us
|
||||
|
||||
// Nov 28 98: skip people in destination tile if in turnbased
|
||||
if ( ( NewOKDestination(pSoldier, sGridNo, fSkipTilesWithMercs, pSoldier->pathing.bLevel ) ) &&
|
||||
( !InGas( pSoldier, sGridNo ) ) &&
|
||||
( sGridNo != pSoldier->sGridNo ) &&
|
||||
( sGridNo != pSoldier->pathing.sBlackList ) )
|
||||
/*
|
||||
if ( ( NewOKDestination(pSoldier, sGridno, FALSE, pSoldier->pathing.bLevel ) ) &&
|
||||
( !(gpWorldLevelData[ sGridno ].ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS)) || ( pSoldier->inv[ HEAD1POS ].usItem == GASMASK || pSoldier->inv[ HEAD2POS ].usItem == GASMASK ) ) &&
|
||||
( sGridno != pSoldier->sGridNo ) &&
|
||||
( sGridno != pSoldier->pathing.sBlackList ) )*/
|
||||
/*
|
||||
if ( ( NewOKDestination(pSoldier,sGridno,ALLPEOPLE, pSoldier->pathing.bLevel ) ) &&
|
||||
( !(gpWorldLevelData[ sGridno ].ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS)) || ( pSoldier->inv[ HEAD1POS ].usItem == GASMASK || pSoldier->inv[ HEAD2POS ].usItem == GASMASK ) ) &&
|
||||
( sGridno != pSoldier->sGridNo ) &&
|
||||
( sGridno != pSoldier->pathing.sBlackList ) )
|
||||
*/
|
||||
// if this gridno is an OK destination
|
||||
// AND the gridno is NOT in a tear-gassed tile when we have no gas mask
|
||||
// AND someone is NOT already standing there
|
||||
// AND we're NOT already standing at that gridno
|
||||
// AND the gridno hasn't been black-listed for us
|
||||
|
||||
// Nov 28 98: skip people in destination tile if in turnbased
|
||||
// sevenfm: also check for bomb nearby
|
||||
if ( NewOKDestination(pSoldier, sGridNo, fSkipTilesWithMercs, pSoldier->pathing.bLevel ) &&
|
||||
!InGas( pSoldier, sGridNo ) &&
|
||||
!FindBombNearby(pSoldier, sGridNo, DAY_VISION_RANGE/8 ) &&
|
||||
sGridNo != pSoldier->sGridNo &&
|
||||
sGridNo != pSoldier->pathing.sBlackList )
|
||||
{
|
||||
// if water's a problem, and gridno is in a water tile (bridges are OK)
|
||||
if (!ubWaterOK && Water(sGridNo, pSoldier->pathing.bLevel))
|
||||
|
||||
@@ -295,6 +295,8 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN ProneSightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
|
||||
BOOLEAN SightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
|
||||
|
||||
BOOLEAN FindBombNearby( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDistance );
|
||||
|
||||
#define MAX_FLANKS_RED 25
|
||||
#define MAX_FLANKS_YELLOW 25
|
||||
|
||||
|
||||
+59
-49
@@ -2567,18 +2567,21 @@ BOOLEAN DoCatchObject( REAL_OBJECT *pObject )
|
||||
}
|
||||
|
||||
|
||||
//#define TESTDUDEXPLOSIVES
|
||||
|
||||
void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
{
|
||||
INT16 sZ;
|
||||
BOOLEAN fDoImpact = FALSE;
|
||||
BOOLEAN fCheckForDuds = FALSE;
|
||||
bool fIsDud = FALSE;
|
||||
INT16 sZ;
|
||||
BOOLEAN fDoImpact = FALSE;
|
||||
BOOLEAN fCheckForDuds = FALSE;
|
||||
bool fIsDud = FALSE;
|
||||
OBJECTTYPE *pObj;
|
||||
INT32 iTrapped = 0;
|
||||
UINT16 usFlags = 0;
|
||||
INT8 bLevel = 0;
|
||||
INT32 iTrapped = 0;
|
||||
UINT16 usFlags = 0;
|
||||
INT8 bLevel = 0;
|
||||
|
||||
// sevenfm: can delay explosion for normal, stun and flashbang type grenades
|
||||
BOOLEAN fCanDelayExplosion = FALSE;
|
||||
BOOLEAN fGoodStatus = FALSE;
|
||||
BOOLEAN fDelayedExplosion = FALSE;
|
||||
|
||||
if (is_networked && is_client)
|
||||
{
|
||||
@@ -2600,6 +2603,16 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
if ( Item[ pObj->usItem ].usItemClass & IC_GRENADE )
|
||||
{
|
||||
fCheckForDuds = TRUE;
|
||||
|
||||
if( CanDelayGrenadeExplosion(pObj->usItem) && ( Item[pObj->usItem].ubCursor == TOSSCURS || Item[pObj->usItem].glgrenade ))
|
||||
{
|
||||
fCanDelayExplosion = TRUE;
|
||||
}
|
||||
|
||||
if( (*pObj)[0]->data.sObjectFlag & DELAYED_GRENADE_EXPLOSION )
|
||||
{
|
||||
fDelayedExplosion = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// if ( pObj->usItem == MORTAR_SHELL )
|
||||
@@ -2617,6 +2630,12 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
|
||||
if ( fCheckForDuds && (*pObj)[0]->data.misc.bDetonatorType != BOMB_TIMED )
|
||||
{
|
||||
if( (*pObj)[0]->data.objectStatus >= USABLE &&
|
||||
PreRandom(100) < (UINT32) (*pObj)[0]->data.objectStatus + PreRandom( 50 ) )
|
||||
{
|
||||
fGoodStatus = TRUE;
|
||||
}
|
||||
|
||||
// OJW - 20021002 - MP Explosives
|
||||
if (is_networked && is_client && pObject->mpIsFromRemoteClient && pObject->mpHaveClientResult)
|
||||
{
|
||||
@@ -2624,13 +2643,11 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// If we landed on anything other than the floor, always! go off...
|
||||
#ifdef TESTDUDEXPLOSIVES
|
||||
if ( sZ != 0 || pObject->fInWater )
|
||||
#else
|
||||
if ( sZ != 0 || pObject->fInWater || ( (*pObj)[0]->data.objectStatus >= USABLE && ( PreRandom( 100 ) < (UINT32) (*pObj)[0]->data.objectStatus + PreRandom( 50 ) ) ) )
|
||||
#endif
|
||||
if( sZ != 0 ||
|
||||
pObject->fInWater ||
|
||||
!fCanDelayExplosion ||
|
||||
fGoodStatus && !gGameExternalOptions.fDelayedGrenadeExplosion && !fDelayedExplosion )
|
||||
{
|
||||
fDoImpact = TRUE;
|
||||
fIsDud = false;
|
||||
@@ -2643,24 +2660,32 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
|
||||
if (fIsDud)
|
||||
{
|
||||
#ifdef TESTDUDEXPLOSIVES
|
||||
if ( 1 )
|
||||
#else
|
||||
if ( (*pObj)[0]->data.objectStatus >= USABLE && PreRandom(100) < (UINT32) (*pObj)[0]->data.objectStatus + PreRandom( 50 ) )
|
||||
#endif
|
||||
{
|
||||
iTrapped = PreRandom( 4 ) + 2;
|
||||
}
|
||||
// Start timed bomb...
|
||||
usFlags |= WORLD_ITEM_ARMED_BOMB;
|
||||
|
||||
if ( iTrapped )
|
||||
(*pObj)[0]->data.misc.bDetonatorType = BOMB_TIMED;
|
||||
if( !fGoodStatus )
|
||||
{
|
||||
// Start timed bomb...
|
||||
usFlags |= WORLD_ITEM_ARMED_BOMB;
|
||||
|
||||
(*pObj)[0]->data.misc.bDetonatorType = BOMB_TIMED;
|
||||
(*pObj)[0]->data.misc.bDelay = (INT8)( 1 + PreRandom( 2 ) );
|
||||
(*pObj)[0]->data.misc.usBombItem = pObj->usItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*pObj)[0]->data.misc.bDelay = 1;
|
||||
|
||||
// for non-player grenades, add turn so player could disarm grenade or run away
|
||||
if ( pObject->ubOwner != NOBODY && MercPtrs[pObject->ubOwner]->bTeam != gbPlayerNum )
|
||||
{
|
||||
(*pObj)[0]->data.misc.bDelay++;
|
||||
}
|
||||
}
|
||||
|
||||
(*pObj)[0]->data.misc.usBombItem = pObj->usItem;
|
||||
|
||||
(*pObj).fFlags |= OBJECT_ARMED_BOMB;
|
||||
(*pObj).fFlags |= OBJECT_KNOWN_TO_BE_TRAPPED;
|
||||
|
||||
// set high trap level
|
||||
(*pObj)[0]->data.bTrap = 10;
|
||||
|
||||
// ATE: If we have collided with roof last...
|
||||
if ( pObject->iOldCollisionCode == COLLISION_ROOF )
|
||||
@@ -2669,12 +2694,12 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
}
|
||||
|
||||
// Add item to pool....
|
||||
AddItemToPool( pObject->sGridNo, pObj, INVISIBLE, bLevel, usFlags, 0 );
|
||||
AddItemToPool( pObject->sGridNo, pObj, VISIBLE, bLevel, usFlags, 0 );
|
||||
|
||||
// All teams lok for this...
|
||||
// All teams look for this...
|
||||
NotifySoldiersToLookforItems( );
|
||||
|
||||
if ( pObject->ubOwner != NOBODY )
|
||||
if ( pObject->ubOwner != NOBODY && !fGoodStatus )
|
||||
{
|
||||
MercPtrs[ pObject->ubOwner ]->DoMercBattleSound( (INT8)( BATTLE_SOUND_CURSE1 ) );
|
||||
}
|
||||
@@ -2689,7 +2714,7 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
{
|
||||
if ( Item[pObject->Obj.usItem].flare )
|
||||
{
|
||||
//if the light object will ber created OFF the ground
|
||||
//if the light object will be created OFF the ground
|
||||
if( pObject->Position.z > 0 && FindBuilding(pObject->sGridNo) )
|
||||
{
|
||||
//we cannot create the light source above the ground, or on a roof. The system doesnt support it.
|
||||
@@ -2698,30 +2723,17 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
else
|
||||
{
|
||||
// Add a light effect...
|
||||
|
||||
NewLightEffect( pObject->sGridNo, (UINT8)Explosive[Item[pObject->Obj.usItem].ubClassIndex].ubDuration , (UINT8)Explosive[Item[pObject->Obj.usItem].ubClassIndex].ubStartRadius );
|
||||
}
|
||||
}
|
||||
else if ( Item[ pObject->Obj.usItem ].usItemClass & IC_GRENADE )
|
||||
{
|
||||
/* ARM: Removed. Rewards even missed throws, and pulling a pin doesn't really teach anything about explosives
|
||||
if ( MercPtrs[ pObject->ubOwner ]->bTeam == gbPlayerNum && gTacticalStatus.uiFlags & INCOMBAT )
|
||||
{
|
||||
// tossed grenade, not a dud, so grant xp
|
||||
// EXPLOSIVES GAIN (10): Tossing grenade
|
||||
if ( pObject->ubOwner != NOBODY )
|
||||
{
|
||||
StatChange( MercPtrs[ pObject->ubOwner ], EXPLODEAMT, 10, FALSE );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if( (*pObj)[0]->data.misc.bDetonatorType != BOMB_TIMED )
|
||||
{
|
||||
IgniteExplosion( pObject->ubOwner, (INT16)pObject->Position.x, (INT16)pObject->Position.y, sZ, pObject->sGridNo, pObject->Obj.usItem, GET_OBJECT_LEVEL( pObject->Position.z - CONVERT_PIXELS_TO_HEIGHTUNITS( gpWorldLevelData[ pObject->sGridNo ].sHeight ) ), DIRECTION_IRRELEVANT, &pObject->Obj );
|
||||
}
|
||||
}
|
||||
else if ( Item[ pObject->Obj.usItem ].usItemClass == IC_BOMB ) //if ( pObject->Obj.usItem == MORTAR_SHELL )
|
||||
else if ( Item[ pObject->Obj.usItem ].usItemClass == IC_BOMB )
|
||||
{
|
||||
sZ = (INT16)CONVERT_HEIGHTUNITS_TO_PIXELS( (INT16)pObject->Position.z );
|
||||
|
||||
@@ -2738,8 +2750,6 @@ void HandleArmedObjectImpact( REAL_OBJECT *pObject )
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOLEAN SavePhysicsTableToSaveGameFile( HWFILE hFile )
|
||||
{
|
||||
UINT32 uiNumBytesWritten=0;
|
||||
|
||||
@@ -7424,6 +7424,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s被拆分成%d个弹夹每个有%d发子弹", //L"%s was split into %d Magazines containing %d rounds each.",
|
||||
L"%s拆分完成并放入%s的背包", //L"%s was split into %s's inventory.",
|
||||
L"%s的背包空间不足,放不下这个口径的弹夹了", //L"There is insufficient room in %s's inventory to fit any magazines of this caliber!",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This hardcoded text should not be used anymore in the game, because we now have those texts externalized in the "TableData\Email\EmailMercLevelUp.xml" file!
|
||||
|
||||
@@ -7439,6 +7439,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s was split into %d Magazines containing %d rounds each.",
|
||||
L"%s was split into %s's inventory.",
|
||||
L"There is insufficient room in %s's inventory to fit any magazines of this caliber!",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
|
||||
|
||||
@@ -7425,6 +7425,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s was split into %d Magazines containing %d rounds each.",
|
||||
L"%s was split into %s's inventory.",
|
||||
L"There is insufficient room in %s's inventory to fit any magazines of this caliber!",
|
||||
L"Instant mode",
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This hardcoded text should not be used anymore in the game, because we now have those texts externalized in the "TableData\Email\EmailMercLevelUp.xml" file!
|
||||
|
||||
@@ -7434,6 +7434,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s a été conditionné en %d chargeurs %d coups.",
|
||||
L"%s a été réparti dans l'inventaire de : %s.",
|
||||
L"%s n'a plus de place dans son inventaire pour des chargeurs de ce calibre !",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
|
||||
|
||||
@@ -7261,6 +7261,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s wurde aufgeteilt in %d Magazine, wobei jedes davon %d Schuss enthält.",
|
||||
L"%s wurde aufgeteilt in %s's Inventar.",
|
||||
L"Es ist nicht genügend Platz in %s's Inventar um die Magazine dieses Kalibers abzulegen!",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: These are the email texts Speck sends when one of the 4 new 1.13 MERC mercs have levelled up
|
||||
|
||||
@@ -7430,6 +7430,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s was split into %d Magazines containing %d rounds each.",
|
||||
L"%s was split into %s's inventory.",
|
||||
L"There is insufficient room in %s's inventory to fit any magazines of this caliber!",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
|
||||
|
||||
@@ -7438,6 +7438,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s was split into %d Magazines containing %d rounds each.",
|
||||
L"%s was split into %s's inventory.",
|
||||
L"There is insufficient room in %s's inventory to fit any magazines of this caliber!",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends
|
||||
|
||||
@@ -7425,6 +7425,10 @@ STR16 gzTransformationMessage[] =
|
||||
L"%s был разделен на %d магазинов по %d патронов в каждом.",
|
||||
L"%s был разделен и помещен в инвентарь %s.",
|
||||
L"Недостаточно места в инвентаре %s для магазинов данного калибра!",
|
||||
L"Instant mode", // TODO.Translate
|
||||
L"Delayed mode",
|
||||
L"Instant mode (%d AP)",
|
||||
L"Delayed mode (%d AP)",
|
||||
};
|
||||
|
||||
// WANNE: This hardcoded text should not be used anymore in the game, because we now have those texts externalized in the "TableData\Email\EmailMercLevelUp.xml" file!
|
||||
|
||||
Reference in New Issue
Block a user