mirror of
https://github.com/1dot13/source.git
synced 2026-08-12 14:10:23 +02:00
New feature: Getting and using intel allows for more spy-related roleplay.
For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23643&goto=352475&#msg_352475 Requires GameDir >= r2401. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8522 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include "Scheduling.h"
|
||||
#include "GameSettings.h"
|
||||
#include "Overhead.h" // added by Flugente for MercPtrs[]
|
||||
#include "LuaInitNPCs.h" // added by Flugente
|
||||
#endif
|
||||
|
||||
#ifdef JA2UB
|
||||
@@ -42,6 +43,9 @@
|
||||
|
||||
void ConvertCreatureBloodToElixir( void );
|
||||
|
||||
// Flugente: if we are a lua-based merchant, stop selling items we didn't explicitly want to be sold
|
||||
void RemoveNonIntelItems();
|
||||
|
||||
UINT8 gubLastSpecialItemAddedAtElement = 255;
|
||||
|
||||
// Flugente 2012-12-19: merchant data has been externalised - see XML_Merchants.cpp
|
||||
@@ -237,6 +241,64 @@ void ShutDownArmsDealers()
|
||||
gArmsDealersInventory.clear();
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 usItem;
|
||||
INT16 sIntelPrice;
|
||||
INT16 sOptimalNumber;
|
||||
|
||||
} ARMS_DEALER_ITEM_INTEL;
|
||||
|
||||
std::map<UINT16, std::vector<ARMS_DEALER_ITEM_INTEL> > gArmsDealerAdditionalIntelData;
|
||||
|
||||
void AddArmsDealerAdditionalIntelData( UINT16 ausDealer, UINT16 usItem, INT16 sIntelPrice, INT16 sOptimalNumber )
|
||||
{
|
||||
ARMS_DEALER_ITEM_INTEL data;
|
||||
data.usItem = usItem;
|
||||
data.sIntelPrice = sIntelPrice;
|
||||
data.sOptimalNumber = sOptimalNumber;
|
||||
|
||||
gArmsDealerAdditionalIntelData[ausDealer].push_back( data );
|
||||
}
|
||||
|
||||
void ArmsDealers_ReadIntelData()
|
||||
{
|
||||
gArmsDealerAdditionalIntelData.clear();
|
||||
|
||||
// ask lua on what to use
|
||||
LuaAddArmsDealerAdditionalIntelData();
|
||||
}
|
||||
|
||||
void HandlePossibleArmsDealerIntelRefresh( BOOLEAN aForceReread )
|
||||
{
|
||||
if ( gArmsDealerAdditionalIntelData.empty() || aForceReread )
|
||||
{
|
||||
ArmsDealers_ReadIntelData();
|
||||
|
||||
// replace xml-based possible inventory with what lua gave us
|
||||
for ( std::map<UINT16, std::vector<ARMS_DEALER_ITEM_INTEL> >::iterator it = gArmsDealerAdditionalIntelData.begin(); it != gArmsDealerAdditionalIntelData.end(); ++it)
|
||||
{
|
||||
UINT16 dealerid = ( *it ).first;
|
||||
|
||||
DEALER_POSSIBLE_INV* pDealerInv = GetPointerToDealersPossibleInventory( dealerid );
|
||||
|
||||
memset( pDealerInv, 0, sizeof( DEALER_POSSIBLE_INV )*MAXITEMS );
|
||||
|
||||
int cnt = 0;
|
||||
for ( std::vector<ARMS_DEALER_ITEM_INTEL>::iterator it2 = (*it).second.begin(); it2 != ( *it ).second.end(); ++it2 )
|
||||
{
|
||||
ARMS_DEALER_ITEM_INTEL data = ( *it2 );
|
||||
|
||||
pDealerInv[cnt].uiIndex = cnt;
|
||||
pDealerInv[cnt].sItemIndex = data.usItem;
|
||||
pDealerInv[cnt].ubOptimalNumber = data.sOptimalNumber;
|
||||
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN SaveArmsDealerInventoryToSaveGameFile( HWFILE hFile )
|
||||
{
|
||||
UINT32 uiNumBytesWritten;
|
||||
@@ -313,7 +375,7 @@ void DailyUpdateOfArmsDealersInventory()
|
||||
{
|
||||
// if Gabby has creature blood, start turning it into extra elixir
|
||||
ConvertCreatureBloodToElixir();
|
||||
|
||||
|
||||
//Simulate other customers buying inventory from the dealer
|
||||
SimulateArmsDealerCustomer();
|
||||
|
||||
@@ -323,6 +385,10 @@ void DailyUpdateOfArmsDealersInventory()
|
||||
#else
|
||||
DailyCheckOnItemQuantities();
|
||||
#endif
|
||||
|
||||
// Flugente: if we are a lua-based merchant, stop selling items we didn't explicitly want to be sold
|
||||
RemoveNonIntelItems();
|
||||
|
||||
//make sure certain items are in stock and certain limits are respected
|
||||
AdjustCertainDealersInventory( );
|
||||
}
|
||||
@@ -423,6 +489,8 @@ void DailyCheckOnItemQuantities()
|
||||
UINT32 uiArrivalDay;
|
||||
UINT8 ubReorderDays;
|
||||
|
||||
HandlePossibleArmsDealerIntelRefresh(TRUE);
|
||||
|
||||
//loop through all the arms dealers
|
||||
for( ubArmsDealer=0;ubArmsDealer<NUM_ARMS_DEALERS; ++ubArmsDealer )
|
||||
{
|
||||
@@ -603,6 +671,32 @@ void ConvertCreatureBloodToElixir( void )
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: if we are a lua-based merchant, stop selling items we didn't explicitly want to be sold
|
||||
void RemoveNonIntelItems()
|
||||
{
|
||||
for ( UINT8 ubArmsDealer = 0; ubArmsDealer<NUM_ARMS_DEALERS; ++ubArmsDealer )
|
||||
{
|
||||
if ( gArmsDealerStatus[ubArmsDealer].fOutOfBusiness )
|
||||
continue;
|
||||
|
||||
if ( armsDealerInfo[ubArmsDealer].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
{
|
||||
std::vector<UINT16> baditemsvector;
|
||||
|
||||
for ( DealerItemList::iterator iter = gArmsDealersInventory[ubArmsDealer].begin(); iter != gArmsDealersInventory[ubArmsDealer].end(); ++iter )
|
||||
{
|
||||
if ( iter->ItemIsInInventory() == true && CalcValueOfItemToDealer( ubArmsDealer, iter->object.usItem, TRUE ) < 1 )
|
||||
baditemsvector.push_back( iter->object.usItem );
|
||||
}
|
||||
|
||||
for ( std::vector<UINT16>::iterator it2 = baditemsvector.begin(); it2 != baditemsvector.end(); ++it2 )
|
||||
{
|
||||
RemoveItemFromArmsDealerInventory( ubArmsDealer, (*it2), 100 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN AdjustCertainDealersInventory( )
|
||||
{
|
||||
//Adjust Tony's items (this restocks *instantly* 1/day, doesn't use the reorder system)
|
||||
@@ -2083,15 +2177,15 @@ UINT32 CalculateSimpleItemRepairCost( UINT8 ubArmsDealer, UINT16 usItemIndex, IN
|
||||
|
||||
BOOLEAN DoesItemAppearInDealerInventoryList( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN fPurchaseFromPlayer )
|
||||
{
|
||||
DEALER_POSSIBLE_INV *pDealerInv=NULL;
|
||||
UINT16 usCnt;
|
||||
// Flugente: a dealer's inventory is defined in lua if they deal in intel
|
||||
HandlePossibleArmsDealerIntelRefresh(FALSE);
|
||||
|
||||
// the others will buy only things that appear in their own "for sale" inventory lists
|
||||
pDealerInv = GetPointerToDealersPossibleInventory( ubArmsDealer );
|
||||
DEALER_POSSIBLE_INV* pDealerInv = GetPointerToDealersPossibleInventory( ubArmsDealer );
|
||||
Assert( pDealerInv != NULL );
|
||||
|
||||
// loop through the dealers' possible inventory and see if the item exists there
|
||||
usCnt = 0;
|
||||
UINT16 usCnt = 0;
|
||||
while( pDealerInv[ usCnt ].sItemIndex != LAST_DEALER_ITEM )
|
||||
{
|
||||
//if the initial dealer inv contains the required item, the dealer can sell the item
|
||||
@@ -2119,6 +2213,22 @@ UINT16 CalcValueOfItemToDealer( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN
|
||||
|
||||
usBasePrice = Item[ usItemIndex ].usPrice;
|
||||
|
||||
// Flugente: if we deal with intel, get the price of an item straight from LUA
|
||||
if ( ( armsDealerInfo[ubArmsDealer].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
||||
{
|
||||
if ( !gArmsDealerAdditionalIntelData[ubArmsDealer].empty() )
|
||||
{
|
||||
for ( std::vector<ARMS_DEALER_ITEM_INTEL>::iterator it = gArmsDealerAdditionalIntelData[ubArmsDealer].begin(); it != gArmsDealerAdditionalIntelData[ubArmsDealer].end(); ++it )
|
||||
{
|
||||
if ( ( *it ).usItem == usItemIndex )
|
||||
return ( *it ).sIntelPrice;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ( usBasePrice == 0 )
|
||||
{
|
||||
// worthless to any dealer
|
||||
|
||||
@@ -101,6 +101,7 @@ enum
|
||||
#define ARMS_DEALER_HARDWARE 0x00400000 | ARMS_DEALER_KIT
|
||||
#define ARMS_DEALER_MEDICAL 0x00800000 | ARMS_DEALER_MEDKIT
|
||||
|
||||
#define ARMS_DEALER_DEALWITHINTEL 0x01000000 // 16777216 // Flugente: this dealer does not accept money, only intel
|
||||
#define ARMS_DEALER_CREATURE_PARTS 0x02000000 // 33554432
|
||||
#define ARMS_DEALER_ROCKET_RIFLE 0x04000000 // 67108864
|
||||
#define ARMS_DEALER_ONLY_USED_ITEMS 0x08000000 // 134217728
|
||||
@@ -348,6 +349,9 @@ void RemoveItemFromArmsDealerInventory( UINT8 ubArmsDealer, UINT16 usItemIndex,
|
||||
BOOLEAN IsMercADealer( UINT8 ubMercID );
|
||||
INT8 GetArmsDealerIDFromMercID( UINT8 ubMercID );
|
||||
|
||||
// Flugente: update possible intel data
|
||||
void HandlePossibleArmsDealerIntelRefresh(BOOLEAN aForceReread);
|
||||
|
||||
BOOLEAN SaveArmsDealerInventoryToSaveGameFile( HWFILE hFile );
|
||||
|
||||
void DailyUpdateOfArmsDealersInventory();
|
||||
|
||||
@@ -1128,7 +1128,6 @@ void HandleDialogue( )
|
||||
|
||||
if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SHOPKEEPER )
|
||||
{
|
||||
|
||||
if( QItem->uiSpecialEventData < 3 )
|
||||
{
|
||||
// post a notice if the player wants to withdraw money from thier account to cover the difference?
|
||||
@@ -1136,8 +1135,14 @@ void HandleDialogue( )
|
||||
InsertCommasForDollarFigure( zMoney );
|
||||
InsertDollarSignInToString( zMoney );
|
||||
}
|
||||
else if ( QItem->uiSpecialEventData > 7 )
|
||||
{
|
||||
// post a notice if the player wants to withdraw money from thier account to cover the difference?
|
||||
swprintf( zMoney, L"%d", QItem->uiSpecialEventData2 );
|
||||
InsertCommasForDollarFigure( zMoney );
|
||||
}
|
||||
|
||||
switch( QItem->uiSpecialEventData )
|
||||
switch( QItem->uiSpecialEventData )
|
||||
{
|
||||
case( 0 ):
|
||||
swprintf( zText, SkiMessageBoxText[ SKI_SHORT_FUNDS_TEXT ], zMoney );
|
||||
@@ -1184,6 +1189,22 @@ void HandleDialogue( )
|
||||
EnableButton( guiSKI_TransactionButton );
|
||||
}
|
||||
break;
|
||||
|
||||
case8:
|
||||
//if the player is trading items
|
||||
swprintf( zText, SkiMessageBoxText[SKI_QUESTION_TO_DEDUCT_INTEL_FROM_PLAYERS_ACCOUNT_TO_COVER_DIFFERENCE], zMoney );
|
||||
|
||||
//ask them if we should deduct money out the players account to cover the difference
|
||||
DoSkiMessageBox( MSG_BOX_BASIC_STYLE, zText, SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmToDeductIntelFromPlayersAccountMessageBoxCallBack );
|
||||
|
||||
break;
|
||||
|
||||
case 9:
|
||||
swprintf( zText, SkiMessageBoxText[SKI_QUESTION_TO_DEDUCT_INTEL_FROM_PLAYERS_ACCOUNT_TO_COVER_COST], zMoney );
|
||||
|
||||
//ask them if we should deduct money out the players account to cover the difference
|
||||
DoSkiMessageBox( MSG_BOX_BASIC_STYLE, zText, SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmToDeductIntelFromPlayersAccountMessageBoxCallBack );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+43
-22
@@ -1647,9 +1647,10 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
FLOAT bPtsAvailable = 0.0; // Flugente: sometimes, we want to display float values...
|
||||
UINT16 usMaximumPts = 0;
|
||||
CHAR16 sString[ 32 ];
|
||||
UINT16 usTextWidth;
|
||||
UINT16 usTextWidth = 0;
|
||||
BOOLEAN fShowNumber = FALSE;
|
||||
BOOLEAN fShowMaximum = FALSE;
|
||||
BOOLEAN fShowCustomText = FALSE;
|
||||
SOLDIERTYPE *pSoldier;
|
||||
INT16 sFontX, sFontY;
|
||||
INT16 sX1, sY1, sY2, sX2;
|
||||
@@ -1670,9 +1671,7 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
UINT32 uiFaceTwo=0;
|
||||
|
||||
BOOLEAN drawOpponentCount = FALSE;
|
||||
|
||||
CHAR16 wShortText[ 8 ]; // added by Flugente to display sector names
|
||||
|
||||
|
||||
// If we are using an extern buffer...
|
||||
if ( fUseExternBuffer )
|
||||
{
|
||||
@@ -2375,11 +2374,10 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
{
|
||||
sIconIndex_Assignment = 15;
|
||||
fDoIcon_Assignment = TRUE;
|
||||
|
||||
GetShortSectorString( SECTORX(pSoldier->usItemMoveSectorID), SECTORY(pSoldier->usItemMoveSectorID), wShortText );
|
||||
|
||||
fShowNumber = TRUE;
|
||||
fShowMaximum = TRUE;
|
||||
fShowCustomText = TRUE;
|
||||
|
||||
GetShortSectorString( SECTORX(pSoldier->usItemMoveSectorID), SECTORY(pSoldier->usItemMoveSectorID), sString );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2467,6 +2465,27 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
usMaximumPts = (INT16)(pSectorInfo->dFortification_MaxPossible);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONCEALED:
|
||||
case GATHERINTEL:
|
||||
sIconIndex_Assignment = 34;
|
||||
fDoIcon_Assignment = TRUE;
|
||||
fShowCustomText = TRUE;
|
||||
|
||||
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
|
||||
{
|
||||
swprintf( sString, L"Hide %dh", pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] );
|
||||
}
|
||||
else
|
||||
{
|
||||
bPtsAvailable = MercPtrs[pFace->ubSoldierID]->GetIntelGain();
|
||||
usMaximumPts = (UINT16)( MercPtrs[pFace->ubSoldierID]->GetUncoverRisk() );
|
||||
|
||||
swprintf( sString, L"%4.2f/%d%%%%", bPtsAvailable, usMaximumPts );
|
||||
|
||||
usTextWidth = StringPixLength( sString, FONT10ARIAL ) - 10;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -2494,30 +2513,32 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
BltVideoObjectFromIndex( uiRenderBuffer, guiASSIGNMENTICONS, sIconIndex_Assignment, sIconX, sIconY, VO_BLT_SRCTRANSPARENCY, NULL );
|
||||
|
||||
// ATE: Show numbers only in mapscreen
|
||||
if( fShowNumber )
|
||||
if ( fShowNumber || fShowCustomText )
|
||||
{
|
||||
if ( fShowNumber )
|
||||
{
|
||||
if ( fShowMaximum )
|
||||
{
|
||||
swprintf( sString, L"%d/%d", sPtsAvailable, usMaximumPts );
|
||||
}
|
||||
else
|
||||
{
|
||||
swprintf( sString, L"%d", sPtsAvailable );
|
||||
}
|
||||
}
|
||||
|
||||
SetFontDestBuffer( uiRenderBuffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
||||
|
||||
if ( fShowMaximum )
|
||||
{
|
||||
if ( pSoldier->bAssignment == MOVE_EQUIPMENT )
|
||||
swprintf( sString, L"%s", wShortText );
|
||||
else
|
||||
swprintf( sString, L"%d/%d", sPtsAvailable, usMaximumPts );
|
||||
}
|
||||
else
|
||||
{
|
||||
swprintf( sString, L"%d", sPtsAvailable );
|
||||
}
|
||||
if ( !usTextWidth )
|
||||
usTextWidth = StringPixLength( sString, FONT10ARIAL );
|
||||
|
||||
usTextWidth = StringPixLength( sString, FONT10ARIAL );
|
||||
usTextWidth += 1;
|
||||
|
||||
SetFont( FONT10ARIAL );
|
||||
SetFontForeground( FONT_YELLOW );
|
||||
SetFontBackground( FONT_BLACK );
|
||||
|
||||
mprintf( sFaceX + pFace->usFaceWidth - usTextWidth, ( INT16 )( sFaceY + 3 ), sString );
|
||||
mprintf( sFaceX + pFace->usFaceWidth - usTextWidth, (INT16)( sFaceY + 3 ), sString );
|
||||
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,6 +1421,30 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: camera
|
||||
if ( HasItemFlag( usHandItem, CAMERA ) )
|
||||
{
|
||||
sAPCost = APBPConstants[AP_CAMERA];
|
||||
|
||||
if ( EnoughPoints( pSoldier, sAPCost, 0, fFromUI ) )
|
||||
{
|
||||
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, gsInterfaceLevel, 0, TRUE, CALC_FROM_WANTED_DIR, TRUE ) )
|
||||
{
|
||||
TakePhoto( pSoldier, usMapPos, gsInterfaceLevel );
|
||||
|
||||
return( ITEM_HANDLE_OK );
|
||||
}
|
||||
else
|
||||
{
|
||||
return( ITEM_HANDLE_CANNOT_GETTO_LOCATION );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return( ITEM_HANDLE_NOAPS );
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: apply misc items to other soldiers
|
||||
if ( ItemCanBeAppliedToOthers( usHandItem ) )
|
||||
{
|
||||
@@ -9238,6 +9262,9 @@ void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
|
||||
// the temperature of the water in this sector (temperature reflects the quality)
|
||||
FLOAT wateraddtemperature = OVERHEATING_MAX_TEMPERATURE;
|
||||
|
||||
// if we try to add an attachment that cannot be added by this function (we don't perform skill checks here), warn the player of the offending item
|
||||
UINT16 attachmenttowarnabout = NOTHING;
|
||||
|
||||
// 1. loop over the gear we should pick up and remove mismatching items if we can find a fitting one in the sector
|
||||
for (std::vector<GEAR_NODE>::iterator it = vec.begin(); it != vec.end(); ++it)
|
||||
@@ -9381,7 +9408,7 @@ void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( item_attachment, 0, poolslot, index ) )
|
||||
{
|
||||
(pInventoryPoolList[poolslot].object).RemoveObjectAtIndex( index, &gItemPointer );
|
||||
( pInventoryPoolList[poolslot].object ).RemoveObjectAtIndex( index, &gItemPointer );
|
||||
|
||||
BOOLEAN isAttachedNow = pObj->AttachObject( pSoldier, &gItemPointer, FALSE, i ); //do the actual attaching
|
||||
|
||||
@@ -9396,6 +9423,10 @@ void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attachmenttowarnabout = item_attachment;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9657,7 +9688,11 @@ void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
DeleteObj( &gItemPointer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attachmenttowarnabout = item_attachment;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9809,6 +9844,12 @@ void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
else if ( attachmentsound )
|
||||
PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
||||
|
||||
// warn us if we tried to attach something we can't attach
|
||||
if ( attachmenttowarnabout != NOTHING )
|
||||
{
|
||||
ScreenMsg( color, MSG_INTERFACE, szGearTemplateText[5], Item[attachmenttowarnabout].szItemName, attachmenttowarnabout );
|
||||
}
|
||||
|
||||
// 6. redraw inventory
|
||||
fTeamPanelDirty = TRUE;
|
||||
fMapPanelDirty = TRUE;
|
||||
@@ -9820,3 +9861,48 @@ void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
MarkAButtonDirty( giItemDescAmmoButton ); // Required for tactical screen
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: intel
|
||||
void TakePhoto(SOLDIERTYPE* pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
if ( !pSoldier || TileIsOutOfBounds( sGridNo ) )
|
||||
return;
|
||||
|
||||
// if we take a photo, take note of all rooms & NPC we see. We then send that to LUA, where we store anything worthwhile
|
||||
// later on, we can then sell worthwhile information 'gathered' this way for intel
|
||||
|
||||
// to make this simple, check only tiles in a radius around the gridno we targetted
|
||||
INT16 sBaseX, sBaseY;
|
||||
ConvertGridNoToXY( sGridNo, &sBaseX, &sBaseY );
|
||||
|
||||
int radius = 3;
|
||||
|
||||
for ( int x = -radius; x < radius; ++x )
|
||||
{
|
||||
int diff = sqrt( radius*radius - x*x );
|
||||
|
||||
for ( int y = -diff; y < diff; ++y )
|
||||
{
|
||||
INT32 newgridno = MAPROWCOLTOPOS( (sBaseY + y), ( sBaseX + x ));
|
||||
|
||||
// can we see this gridno?
|
||||
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, newgridno, bLevel, 0, TRUE, CALC_FROM_WANTED_DIR, TRUE ) )
|
||||
{
|
||||
// check if this is a room
|
||||
UINT16 room = NO_ROOM;
|
||||
if ( !bLevel )
|
||||
InARoom( newgridno, &room );
|
||||
|
||||
// check if there is someone here
|
||||
UINT16 ubid = WhoIsThere2( newgridno, bLevel );
|
||||
|
||||
LuaAddPhotoData( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, newgridno, bLevel, pSoldier->ubProfile, room, ( ubid == NOBODY ) ? NO_PROFILE : MercPtrs[ubid]->ubProfile );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeductPoints( pSoldier, APBPConstants[AP_CAMERA], 0, 0 );
|
||||
|
||||
// Play sound
|
||||
PlayJA2SampleFromFile( "Sounds\\camera1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
||||
}
|
||||
|
||||
@@ -305,4 +305,8 @@ extern ITEM_POOL *gpItemPool;//dnl ch26 210909
|
||||
void DoInteractiveAction( INT32 sGridNo, SOLDIERTYPE *pSoldier );
|
||||
void DoInteractiveActionDefaultResult( INT32 sGridNo, UINT8 ubID, BOOLEAN aSuccess );
|
||||
BOOLEAN SpendMoney( SOLDIERTYPE *pSoldier, UINT32 aAmount ); // character spends money - either from inventory or the account
|
||||
|
||||
// Flugente: intel
|
||||
void TakePhoto( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT8 bLevel );
|
||||
|
||||
#endif
|
||||
@@ -4660,6 +4660,14 @@ BOOLEAN UIMouseOnValidAttackLocation( SOLDIERTYPE *pSoldier )
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
if ( ubItemCursor == CAMERACURS )
|
||||
{
|
||||
if ( HasItemFlag( ( &( pSoldier->inv[HANDPOS] ) )->usItem, CAMERA ) && SoldierTo3DLocationLineOfSightTest( pSoldier, usMapPos, gsInterfaceLevel, 0, TRUE, CALC_FROM_WANTED_DIR, TRUE ) )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ubItemCursor == APPLYITEMCURS )
|
||||
{
|
||||
if ( ItemCanBeAppliedToOthers( (&(pSoldier->inv[HANDPOS]))->usItem ) )
|
||||
|
||||
@@ -233,6 +233,9 @@ UICursor gUICursors[ NUM_UI_CURSORS ] =
|
||||
MINIGAME_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_MINIGAME, 0,
|
||||
MINIGAME_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_MINIGAME_RED, 0,
|
||||
|
||||
CAMERA_GREY_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_CAMERA, 0,
|
||||
CAMERA_RED_UICURSOR, UICURSOR_FREEFLOWING, CURSOR_CAMERA_RED, 0,
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -210,6 +210,9 @@ typedef enum
|
||||
MINIGAME_GREY_UICURSOR,
|
||||
MINIGAME_RED_UICURSOR,
|
||||
|
||||
CAMERA_GREY_UICURSOR,
|
||||
CAMERA_RED_UICURSOR,
|
||||
|
||||
NUM_UI_CURSORS
|
||||
|
||||
} UICursorDefines;
|
||||
|
||||
@@ -2720,6 +2720,15 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
|
||||
MSYS_EnableRegion( &gUDBFasthelpRegions[iFirstDataRegion + cnt] );
|
||||
++cnt;
|
||||
}
|
||||
|
||||
//////////////////// CAMERA
|
||||
if ( HasItemFlag( gpItemDescObject->usItem, CAMERA ) )
|
||||
{
|
||||
swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[41], szUDBGenSecondaryStatsExplanationsTooltipText[41] );
|
||||
SetRegionFastHelpText( &( gUDBFasthelpRegions[iFirstDataRegion + cnt] ), pStr );
|
||||
MSYS_EnableRegion( &gUDBFasthelpRegions[iFirstDataRegion + cnt] );
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
@@ -6256,6 +6265,14 @@ void DrawSecondaryStats( OBJECTTYPE * gpItemDescObject )
|
||||
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 38, gItemDescGenSecondaryRegions[cnt].sLeft + sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
|
||||
++cnt;
|
||||
}
|
||||
|
||||
//////////////////// CAMERA
|
||||
if ( ( HasItemFlag( gpItemDescObject->usItem, CAMERA ) && !fComparisonMode ) ||
|
||||
( fComparisonMode && HasItemFlag( gpComparedItemDescObject->usItem, CAMERA ) ) )
|
||||
{
|
||||
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 39, gItemDescGenSecondaryRegions[cnt].sLeft + sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawPropertyValueInColour( INT16 iValue, UINT8 ubNumLine, UINT8 ubNumRegion, BOOLEAN fComparisonMode, BOOLEAN fModifier, BOOLEAN fHigherBetter, UINT16 uiOverwriteColour = 0, BOOLEAN fPercentSign = FALSE )
|
||||
|
||||
@@ -737,7 +737,7 @@ extern OBJECTTYPE gTempObject;
|
||||
//#define EMPTY_SANDBAG 0x00000001 //1
|
||||
#define MANPAD 0x00000002 //2 // this item is a MAn-Portable Air-Defense System
|
||||
#define BEARTRAP 0x00000004 //4 // a mechanical trap that does no explosion, but causes leg damage to whoever activates it
|
||||
//#define CONCERTINA 0x00000008 //8
|
||||
#define CAMERA 0x00000008 //8
|
||||
|
||||
#define WATER_DRUM 0x00000010 //16 // water drums allow to refill canteens in the sector they are in
|
||||
#define MEAT_BLOODCAT 0x00000020 //32 // retrieve this by gutting a bloodcat
|
||||
|
||||
@@ -373,6 +373,7 @@ enum
|
||||
FACTORY_GROUP,
|
||||
ADMINISTRATIVE_STAFF_GROUP,
|
||||
LOYAL_CIV_GROUP, // civil population deeply loyal to the queen
|
||||
BLACKMARKET_GROUP, // black market dealer and bodyguards
|
||||
UNNAMED_CIV_GROUP_34,
|
||||
UNNAMED_CIV_GROUP_35,
|
||||
UNNAMED_CIV_GROUP_36,
|
||||
|
||||
+58
-41
@@ -6774,51 +6774,53 @@ BOOLEAN GetPlayerControlledPrisonList( std::vector<UINT8>& arSectorIDVector )
|
||||
return ( !arSectorIDVector.empty() );
|
||||
}
|
||||
|
||||
extern INT32 giReinforcementPool;
|
||||
extern void DoInterrogation( INT16 sMapX, INT16 sMapY, FLOAT aChanceModifier, INT16 aPrisoners[] );
|
||||
|
||||
// we cannot simply move all prisoners of a sector. It might be a prison we are already using, so we would move all inmates, not just the new ones
|
||||
INT16 gsNumPrisoner[PRISONER_MAX] = {0};
|
||||
|
||||
void PrisonerMessageBoxCallBack( UINT8 ubExitValue )
|
||||
{
|
||||
UINT8 usSectorID = (UINT8)(DropDownTemplate<DROPDOWNNR_MSGBOX_1>::getInstance( ).GetSelectedEntryKey( ));
|
||||
|
||||
// if sector is still not set, then we did not select one - release prisoners
|
||||
if ( usSectorID == 0 )
|
||||
if ( DropDownTemplate<DROPDOWNNR_MSGBOX_1>::getInstance().GetSelectedEntryKey() < 0 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_RELEASED] );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[PRISONER_FIELDINTERROGATION_STR] );
|
||||
|
||||
DoInterrogation( gWorldSectorX, gWorldSectorY, 0.5f, gsNumPrisoner );
|
||||
}
|
||||
|
||||
BOOLEAN success = FALSE;
|
||||
INT16 prisonerstobemoved = 0;
|
||||
for ( int i = PRISONER_ADMIN; i < PRISONER_MAX; ++i )
|
||||
prisonerstobemoved += gsNumPrisoner[i];
|
||||
|
||||
if ( usSectorID > 0 )
|
||||
else
|
||||
{
|
||||
SECTORINFO *pPrisonSectorInfo = &(SectorInfo[usSectorID]);
|
||||
UINT8 usSectorID = (UINT8)( DropDownTemplate<DROPDOWNNR_MSGBOX_1>::getInstance().GetSelectedEntryKey() );
|
||||
|
||||
if ( pPrisonSectorInfo )
|
||||
// if sector is still not set, then we did not select one - release prisoners
|
||||
if ( usSectorID == 0 )
|
||||
{
|
||||
success = TRUE;
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_RELEASED] );
|
||||
}
|
||||
|
||||
ChangeNumberOfPrisoners( pPrisonSectorInfo, gsNumPrisoner );
|
||||
BOOLEAN success = FALSE;
|
||||
INT16 prisonerstobemoved = 0;
|
||||
for ( int i = PRISONER_ADMIN; i < PRISONER_MAX; ++i )
|
||||
prisonerstobemoved += gsNumPrisoner[i];
|
||||
|
||||
CHAR16 wString[128];
|
||||
GetSectorIDString( SECTORX( usSectorID ), SECTORY( usSectorID ), 0, wString, TRUE );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_SENTTOSECTOR], prisonerstobemoved, wString );
|
||||
if ( usSectorID > 0 )
|
||||
{
|
||||
SECTORINFO *pPrisonSectorInfo = &( SectorInfo[usSectorID] );
|
||||
|
||||
if ( pPrisonSectorInfo )
|
||||
{
|
||||
success = TRUE;
|
||||
|
||||
ChangeNumberOfPrisoners( pPrisonSectorInfo, gsNumPrisoner );
|
||||
|
||||
CHAR16 wString[128];
|
||||
GetSectorIDString( SECTORX( usSectorID ), SECTORY( usSectorID ), 0, wString, TRUE );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_SENTTOSECTOR], prisonerstobemoved, wString );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = PRISONER_ADMIN; i < PRISONER_MAX; ++i )
|
||||
gsNumPrisoner[i] = 0;
|
||||
|
||||
if ( !success )
|
||||
{
|
||||
// send some prisoners back to queen's pool
|
||||
// there is a chance that escaped prisoners may return to the queen...
|
||||
giReinforcementPool += (prisonerstobemoved * gGameExternalOptions.ubPrisonerReturntoQueenChance) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6960,7 +6962,7 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
||||
gsNumPrisoner[i] = sNumPrisoner[i];
|
||||
|
||||
std::vector<std::pair<INT16, STR16> > dropdownvector_1;
|
||||
|
||||
|
||||
std::vector<UINT8>::iterator itend = prisonsectorvector.end( );
|
||||
for ( std::vector<UINT8>::iterator it = prisonsectorvector.begin( ); it != itend; ++it )
|
||||
{
|
||||
@@ -6970,6 +6972,9 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
||||
|
||||
dropdownvector_1.push_back( std::make_pair( (INT16)(usSectorID), gPrisonSectorNamesStr[usSectorID] ) );
|
||||
}
|
||||
|
||||
// field interogation is always possible
|
||||
dropdownvector_1.push_back( std::make_pair( -1, TacticalStr[PRISONER_FIELDINTERROGATION_SHORT_STR] ) );
|
||||
|
||||
DropDownTemplate<DROPDOWNNR_MSGBOX_1>::getInstance( ).SetEntries( dropdownvector_1 );
|
||||
|
||||
@@ -6978,22 +6983,12 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
||||
|
||||
DoMessageBox( MSG_BOX_BASIC_MEDIUM_BUTTONS, sString, GAME_SCREEN, (MSG_BOX_FLAG_OK | MSG_BOX_FLAG_DROPDOWN_1), PrisonerMessageBoxCallBack, NULL );
|
||||
}
|
||||
// if we control no prison, we have to let them go...
|
||||
// if we control no prison, do a field interrogation
|
||||
else
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[PRISONER_NO_PRISONS_STR] );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[PRISONER_FIELDINTERROGATION_STR] );
|
||||
|
||||
// some prisoners volunteer to work for us
|
||||
UINT16 volunteers = Random( ubNumPrisoners / 3 );
|
||||
|
||||
if ( volunteers )
|
||||
{
|
||||
AddVolunteers( volunteers );
|
||||
|
||||
// we add the volunteers anyway, but only show the message if this feature is on
|
||||
if ( gGameExternalOptions.fMilitiaVolunteerPool )
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_TURN_VOLUNTEER], volunteers );
|
||||
}
|
||||
DoInterrogation( sMapX, sMapY, 0.5f, sNumPrisoner );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10089,6 +10084,28 @@ BOOLEAN HostileZombiesPresent( )
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
BOOLEAN HostileCreaturesPresent()
|
||||
{
|
||||
SOLDIERTYPE* pSoldier;
|
||||
|
||||
if ( gTacticalStatus.Team[CREATURE_TEAM].bTeamActive == FALSE )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
for ( INT32 iLoop = gTacticalStatus.Team[CREATURE_TEAM].bFirstID; iLoop <= gTacticalStatus.Team[CREATURE_TEAM].bLastID; ++iLoop )
|
||||
{
|
||||
pSoldier = MercPtrs[iLoop];
|
||||
|
||||
if ( pSoldier && pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
|
||||
{
|
||||
return( TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
void HandleCreatureTenseQuote( )
|
||||
{
|
||||
// WDS - make number of mercenaries, etc. be configurable
|
||||
|
||||
@@ -319,6 +319,7 @@ BOOLEAN HostileCiviliansWithGunsPresent( );
|
||||
BOOLEAN HostileCiviliansPresent( );
|
||||
BOOLEAN HostileBloodcatsPresent( );
|
||||
BOOLEAN HostileZombiesPresent( );
|
||||
BOOLEAN HostileCreaturesPresent();
|
||||
|
||||
UINT8 NumPCsInSector( );
|
||||
void SetSoldierNonNeutral( SOLDIERTYPE * pSoldier );
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "InterfaceItemImages.h"
|
||||
#include "Encyclopedia_new.h"
|
||||
#include "Animation Control.h" // added by Flugente
|
||||
#include "Town Militia.h" // added by Flugente
|
||||
#endif
|
||||
|
||||
#ifdef JA2UB
|
||||
@@ -555,7 +556,6 @@ BOOLEAN RemoveRepairItemFromDealersOfferArea( INT16 bSlot );
|
||||
INT8 GetInvSlotOfUnfullMoneyInMercInventory( SOLDIERTYPE *pSoldier );
|
||||
void ClearPlayersOfferSlot( INT32 ubSlotToClear );
|
||||
void ClearArmsDealerOfferSlot( INT32 ubSlotToClear );
|
||||
void ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue );
|
||||
|
||||
BOOLEAN DoSkiMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback );
|
||||
|
||||
@@ -1551,8 +1551,14 @@ BOOLEAN RenderShopKeeperInterface()
|
||||
swprintf( zMoney, L"%d", gArmsDealerStatus[gbSelectedArmsDealerID].uiArmsDealersCash );
|
||||
|
||||
InsertCommasForDollarFigure( zMoney );
|
||||
InsertDollarSignInToString( zMoney );
|
||||
DrawTextToScreen( zMoney, SKI_BUDGET_X, SKI_BUDGET_OFFSET_TO_VALUE, SKI_BUDGET_WIDTH, FONT10ARIAL, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, TRUE, CENTER_JUSTIFIED );
|
||||
|
||||
CHAR16 zTemp2[64];
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
swprintf( zTemp2, L"%s Intel", zMoney );
|
||||
else
|
||||
swprintf( zTemp2, L"$%s", zMoney );
|
||||
|
||||
DrawTextToScreen( zTemp2, SKI_BUDGET_X, SKI_BUDGET_OFFSET_TO_VALUE, SKI_BUDGET_WIDTH, FONT10ARIAL, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, TRUE, CENTER_JUSTIFIED );
|
||||
|
||||
//if the dealer repairs
|
||||
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
||||
@@ -1570,11 +1576,20 @@ BOOLEAN RenderShopKeeperInterface()
|
||||
DisplayWrappedString( SKI_PLAYERS_CURRENT_BALANCE_X, SKI_PLAYERS_CURRENT_BALANCE_Y, SKI_PLAYERS_CURRENT_BALANCE_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SkiMessageBoxText[ SKI_PLAYERS_CURRENT_BALANCE ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
|
||||
//Display the players current balance value
|
||||
swprintf( zMoney, L"%d", LaptopSaveInfo.iCurrentBalance );
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
{
|
||||
swprintf( zMoney, L"%d", (int)(GetIntel()) );
|
||||
InsertCommasForDollarFigure( zMoney );
|
||||
swprintf( zTemp2, L"%s Intel", zMoney );
|
||||
}
|
||||
else
|
||||
{
|
||||
swprintf( zMoney, L"%d", LaptopSaveInfo.iCurrentBalance );
|
||||
InsertCommasForDollarFigure( zMoney );
|
||||
swprintf( zTemp2, L"$%s", zMoney );
|
||||
}
|
||||
|
||||
InsertCommasForDollarFigure( zMoney );
|
||||
InsertDollarSignInToString( zMoney );
|
||||
DrawTextToScreen( zMoney, SKI_PLAYERS_CURRENT_BALANCE_X, SKI_PLAYERS_CURRENT_BALANCE_OFFSET_TO_VALUE, SKI_PLAYERS_CURRENT_BALANCE_WIDTH, FONT10ARIAL, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, TRUE, CENTER_JUSTIFIED );
|
||||
DrawTextToScreen( zTemp2, SKI_PLAYERS_CURRENT_BALANCE_X, SKI_PLAYERS_CURRENT_BALANCE_OFFSET_TO_VALUE, SKI_PLAYERS_CURRENT_BALANCE_WIDTH, FONT10ARIAL, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, TRUE, CENTER_JUSTIFIED );
|
||||
|
||||
//Display the total value text
|
||||
DisplayWrappedString( SKI_TOTAL_VALUE_X, SKI_TOTAL_VALUE_Y, SKI_TOTAL_VALUE_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[SKI_TEXT_TOTAL_VALUE], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
@@ -1734,10 +1749,11 @@ void DisplayAllDealersCash()
|
||||
{
|
||||
UINT16 usPosY=0;
|
||||
CHAR16 zTemp[512];
|
||||
CHAR16 zTemp2[64];
|
||||
UINT8 ubForeColor;
|
||||
|
||||
//loop through all the shopkeeper's and display their money
|
||||
for ( INT8 bArmsDealer = 0; bArmsDealer<NUM_ARMS_DEALERS; bArmsDealer++ )
|
||||
for ( INT8 bArmsDealer = 0; bArmsDealer<NUM_ARMS_DEALERS; ++bArmsDealer )
|
||||
{
|
||||
//Display the shopkeeper's name
|
||||
DrawTextToScreen( gMercProfiles[ armsDealerInfo[ bArmsDealer ].ubShopKeeperID ].zNickname, SCREEN_X_OFFSET + 540, SCREEN_Y_OFFSET + usPosY, 0, FONT10ARIAL, SKI_TITLE_COLOR, FONT_MCOLOR_BLACK, TRUE, LEFT_JUSTIFIED );
|
||||
@@ -1746,9 +1762,14 @@ void DisplayAllDealersCash()
|
||||
swprintf( zTemp, L"%d", gArmsDealerStatus[ bArmsDealer ].uiArmsDealersCash );
|
||||
|
||||
InsertCommasForDollarFigure( zTemp );
|
||||
InsertDollarSignInToString( zTemp );
|
||||
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
swprintf( zTemp2, L"%s Intel", zTemp );
|
||||
else
|
||||
swprintf( zTemp2, L"$%s", zTemp );
|
||||
|
||||
ubForeColor = ( UINT8 ) ( ( bArmsDealer == gbSelectedArmsDealerID ) ? SKI_BUTTON_COLOR : SKI_TITLE_COLOR );
|
||||
DrawTextToScreen( zTemp, SCREEN_X_OFFSET + 590, SCREEN_Y_OFFSET + usPosY, 0, FONT10ARIAL, ubForeColor, FONT_MCOLOR_BLACK, TRUE, LEFT_JUSTIFIED );
|
||||
DrawTextToScreen( zTemp2, SCREEN_X_OFFSET + 590, SCREEN_Y_OFFSET + usPosY, 0, FONT10ARIAL, ubForeColor, FONT_MCOLOR_BLACK, TRUE, LEFT_JUSTIFIED );
|
||||
usPosY += 17;
|
||||
}
|
||||
}
|
||||
@@ -2376,7 +2397,7 @@ void SelectPlayersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason
|
||||
SetSkiCursor( EXTERN_CURSOR );
|
||||
|
||||
//if the item we are adding is money
|
||||
if( Item[ PlayersOfferArea[ ubSelectedInvSlot ].sItemIndex ].usItemClass == IC_MONEY )
|
||||
if( Item[ PlayersOfferArea[ ubSelectedInvSlot ].sItemIndex ].usItemClass == IC_MONEY && !( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
||||
{
|
||||
//Since money is always evaluated
|
||||
PlayersOfferArea[ ubSelectedInvSlot ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
|
||||
@@ -2491,6 +2512,8 @@ void InitializeShopKeeper( BOOLEAN fResetPage )
|
||||
|
||||
gpTempDealersInventory.clear();
|
||||
|
||||
HandlePossibleArmsDealerIntelRefresh(FALSE);
|
||||
|
||||
//Get the number of distinct items in the inventory
|
||||
//Create the shopkeeper's temp inventory
|
||||
DetermineArmsDealersSellingInventory( );
|
||||
@@ -2794,8 +2817,14 @@ UINT32 DisplayInvSlot( UINT16 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT
|
||||
{
|
||||
swprintf( zTemp, L"%d", uiItemCost );
|
||||
InsertCommasForDollarFigure( zTemp );
|
||||
InsertDollarSignInToString( zTemp );
|
||||
DrawTextToScreen( zTemp, (UINT16)(usPosX+SKI_INV_PRICE_OFFSET_X), (UINT16)(usPosY+SKI_INV_PRICE_OFFSET_Y), SKI_INV_SLOT_WIDTH, SKI_ITEM_DESC_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
|
||||
CHAR16 zTemp2[64];
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
swprintf( zTemp2, L"%s Intel", zTemp );
|
||||
else
|
||||
swprintf( zTemp2, L"$%s", zTemp );
|
||||
|
||||
DrawTextToScreen( zTemp2, (UINT16)(usPosX+SKI_INV_PRICE_OFFSET_X), (UINT16)(usPosY+SKI_INV_PRICE_OFFSET_Y), SKI_INV_SLOT_WIDTH, SKI_ITEM_DESC_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
}
|
||||
|
||||
//if the there is more then 1 or if the item is stackable and some of it has been bought and only 1 remains
|
||||
@@ -3453,8 +3482,14 @@ void DisplayArmsDealerOfferArea()
|
||||
//Display the total cost text
|
||||
swprintf( zTemp, L"%d", uiTotalCost );
|
||||
InsertCommasForDollarFigure( zTemp );
|
||||
InsertDollarSignInToString( zTemp );
|
||||
DrawTextToScreen( zTemp, SKI_ARMS_DEALER_TOTAL_COST_X, (UINT16)(SKI_ARMS_DEALER_TOTAL_COST_Y+5), SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
|
||||
CHAR16 zTemp2[64];
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
swprintf( zTemp2, L"%s Intel", zTemp );
|
||||
else
|
||||
swprintf( zTemp2, L"$%s", zTemp );
|
||||
|
||||
DrawTextToScreen( zTemp2, SKI_ARMS_DEALER_TOTAL_COST_X, (UINT16)(SKI_ARMS_DEALER_TOTAL_COST_Y+5), SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3586,7 +3621,7 @@ INT8 AddItemToPlayersOfferArea( UINT8 ubProfileID, INVENTORY_IN_SLOT* pInvSlot,
|
||||
SetSkiFaceRegionHelpText( &PlayersOfferArea[bCnt], &gPlayersOfferSlotsSmallFaceMouseRegions[ bCnt ], PLAYERS_OFFER_AREA );
|
||||
|
||||
//if the item we are adding is money
|
||||
if( Item[ PlayersOfferArea[ bCnt ].sItemIndex ].usItemClass == IC_MONEY )
|
||||
if( Item[ PlayersOfferArea[ bCnt ].sItemIndex ].usItemClass == IC_MONEY && !( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
||||
{
|
||||
//Since money is always evaluated
|
||||
PlayersOfferArea[ bCnt ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
|
||||
@@ -3716,8 +3751,14 @@ void DisplayPlayersOfferArea()
|
||||
//Display the total cost text
|
||||
swprintf( zTemp, L"%d", uiTotalCost );
|
||||
InsertCommasForDollarFigure( zTemp );
|
||||
InsertDollarSignInToString( zTemp );
|
||||
DrawTextToScreen( zTemp, SKI_TOTAL_VALUE_X, SKI_TOTAL_VALUE_OFFSET_TO_VALUE, SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
|
||||
CHAR16 zTemp2[64];
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
swprintf( zTemp2, L"%s Intel", zTemp );
|
||||
else
|
||||
swprintf( zTemp2, L"$%s", zTemp );
|
||||
|
||||
DrawTextToScreen( zTemp2, SKI_TOTAL_VALUE_X, SKI_TOTAL_VALUE_OFFSET_TO_VALUE, SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3779,6 +3820,10 @@ UINT32 CalculateTotalArmsDealerCost()
|
||||
|
||||
UINT32 CalculateTotalPlayersValue()
|
||||
{
|
||||
// we can't substitute money for intel
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
return 0;
|
||||
|
||||
UINT32 uiTotal = 0;
|
||||
|
||||
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++ubCnt )
|
||||
@@ -3850,13 +3895,17 @@ void PerformTransaction( UINT32 uiMoneyFromPlayersAccount )
|
||||
//if the player doesn't have enough money to pay for what he's buying
|
||||
if( uiArmsDealersItemsCost > uiPlayersTotalMoneyValue )
|
||||
{
|
||||
INT32 balance = LaptopSaveInfo.iCurrentBalance;
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
balance = GetIntel();
|
||||
|
||||
//if the player doesn't have enough money in his account to pay the rest
|
||||
if( uiArmsDealersItemsCost > uiPlayersTotalMoneyValue + LaptopSaveInfo.iCurrentBalance )
|
||||
if( uiArmsDealersItemsCost > uiPlayersTotalMoneyValue + balance )
|
||||
{
|
||||
// tell player he can't possibly afford this
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 6,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SKIP_A_FRAME, 0,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 0, ( uiArmsDealersItemsCost - ( LaptopSaveInfo.iCurrentBalance + uiPlayersTotalMoneyValue ) ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 0, ( uiArmsDealersItemsCost - ( balance + uiPlayersTotalMoneyValue ) ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3865,10 +3914,20 @@ void PerformTransaction( UINT32 uiMoneyFromPlayersAccount )
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SKIP_A_FRAME, 0,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 6,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
|
||||
if( uiPlayersTotalMoneyValue )
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 1, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
{
|
||||
if ( uiPlayersTotalMoneyValue )
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 8, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
else
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 9, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
}
|
||||
else
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 2, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
{
|
||||
if ( uiPlayersTotalMoneyValue )
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 1, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
else
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 2, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
}
|
||||
}
|
||||
|
||||
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 7,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
||||
@@ -4649,7 +4708,7 @@ INT16 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT16 ubSpotLocation,
|
||||
IfMercOwnedCopyItemToMercInv( pInv );
|
||||
|
||||
//if the item is money
|
||||
if( Item[ PlayersOfferArea[ ubSpotLocation ].sItemIndex ].usItemClass == IC_MONEY )
|
||||
if( Item[ PlayersOfferArea[ ubSpotLocation ].sItemIndex ].usItemClass == IC_MONEY && !(armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL) )
|
||||
{
|
||||
//Since money is always evaluated
|
||||
PlayersOfferArea[ ubSpotLocation ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
|
||||
@@ -5304,7 +5363,9 @@ void EnableDisableEvaluateAndTransactionButtons()
|
||||
fItemEvaluated = TRUE;
|
||||
|
||||
//else if it is not a repair dealer, and the item is money
|
||||
else if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS && Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass == IC_MONEY )
|
||||
else if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS &&
|
||||
Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass == IC_MONEY &&
|
||||
!( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
||||
fItemEvaluated = TRUE;
|
||||
}
|
||||
}
|
||||
@@ -5354,8 +5415,12 @@ void EnableDisableEvaluateAndTransactionButtons()
|
||||
{
|
||||
DisableButton( guiSKI_TransactionButton );
|
||||
}
|
||||
|
||||
if( uiArmsDealerTotalCost > uiPlayersOfferAreaTotalCost + LaptopSaveInfo.iCurrentBalance )
|
||||
|
||||
INT32 balance = LaptopSaveInfo.iCurrentBalance;
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
balance = GetIntel();
|
||||
|
||||
if( uiArmsDealerTotalCost > uiPlayersOfferAreaTotalCost + balance )
|
||||
{
|
||||
DisableButton( guiSKI_TransactionButton );
|
||||
}
|
||||
@@ -5415,6 +5480,10 @@ void AddItemToPlayersOfferAreaAfterShopKeeperOpen( OBJECTTYPE *pItemObject)
|
||||
|
||||
BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( )
|
||||
{
|
||||
// we can't substitute money for intel
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
return FALSE;
|
||||
|
||||
BOOLEAN fFoundMoney = FALSE;
|
||||
|
||||
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++ubCnt )
|
||||
@@ -5438,6 +5507,10 @@ BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( )
|
||||
|
||||
UINT32 CalculateHowMuchMoneyIsInPlayersOfferArea( )
|
||||
{
|
||||
// we can't substitute money for intel
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
return 0;
|
||||
|
||||
UINT32 uiTotalMoneyValue=0;
|
||||
|
||||
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++ubCnt )
|
||||
@@ -5868,6 +5941,27 @@ void ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue
|
||||
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
||||
}
|
||||
|
||||
void ConfirmToDeductIntelFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue )
|
||||
{
|
||||
// yes, deduct the money
|
||||
if ( bExitValue == MSG_BOX_RETURN_YES )
|
||||
{
|
||||
UINT32 uiPlayersOfferAreaValue = CalculateTotalPlayersValue();
|
||||
UINT32 uiArmsDealersItemsCost = CalculateTotalArmsDealerCost();
|
||||
INT32 iMoneyToDeduct = (INT32)( uiArmsDealersItemsCost - uiPlayersOfferAreaValue );
|
||||
|
||||
//Perform the transaction with the extra money from the players account
|
||||
PerformTransaction( iMoneyToDeduct );
|
||||
|
||||
AddIntel( -iMoneyToDeduct, TRUE );
|
||||
}
|
||||
|
||||
// done, re-enable calls to PerformTransaction()
|
||||
gfPerformTransactionInProgress = FALSE;
|
||||
|
||||
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
||||
}
|
||||
|
||||
// run through what the player has on the table and see if the shop keep will aceept it or not
|
||||
BOOLEAN WillShopKeeperRejectItemFromPlayer( INT8 bDealerId, UINT16 usItem )
|
||||
{
|
||||
@@ -5875,13 +5969,16 @@ BOOLEAN WillShopKeeperRejectItemFromPlayer( INT8 bDealerId, UINT16 usItem )
|
||||
|
||||
if ( Item[usItem].usItemClass == IC_MONEY )
|
||||
{
|
||||
fRejected = FALSE;
|
||||
// we can't substitute money for intel
|
||||
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
||||
fRejected = TRUE;
|
||||
else
|
||||
fRejected = FALSE;
|
||||
}
|
||||
else if ( CanDealerTransactItem( gbSelectedArmsDealerID, usItem, TRUE ) )
|
||||
{
|
||||
fRejected = FALSE;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fRejected = TRUE;
|
||||
|
||||
@@ -106,6 +106,7 @@ void DrawHatchOnInventory_MilitiaAccess( UINT32 uiSurface, UINT16 usPosX, UINT
|
||||
BOOLEAN ShouldSoldierDisplayHatchOnItem( UINT8 ubProfileID, INT16 sSlotNum );
|
||||
INT8 AddItemToPlayersOfferArea( UINT8 ubProfileID, INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation );
|
||||
void ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue );
|
||||
void ConfirmToDeductIntelFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue );
|
||||
void ConfirmDontHaveEnoughForTheDealerMessageBoxCallBack( UINT8 bExitValue );
|
||||
|
||||
void SkiHelpTextDoneCallBack( void );
|
||||
|
||||
@@ -200,12 +200,18 @@ INT8 EffectiveExpLevel( SOLDIERTYPE * pSoldier, BOOLEAN fTactical )
|
||||
if (pSoldier->ubProfile != NO_PROFILE)
|
||||
{
|
||||
// Flugente: drugs can temporarily cause a merc to be claustrophobic
|
||||
if ( DoesMercHaveDisability( pSoldier, CLAUSTROPHOBIC ) && pSoldier->bActive && pSoldier->bInSector && gbWorldSectorZ > 0 )
|
||||
if ( DoesMercHaveDisability( pSoldier, CLAUSTROPHOBIC ) && pSoldier->bActive && pSoldier->bInSector )
|
||||
{
|
||||
INT8 sectorz = pSoldier->bSectorZ;
|
||||
if ( SPY_LOCATION( pSoldier->bAssignment ) )
|
||||
sectorz -= 10;
|
||||
|
||||
// claustrophobic!
|
||||
iEffExpLevel -= 2;
|
||||
if ( sectorz > 0 )
|
||||
iEffExpLevel -= 2;
|
||||
}
|
||||
else if ( DoesMercHaveDisability( pSoldier, FEAR_OF_INSECTS ) && MercIsInTropicalSector( pSoldier ) )
|
||||
|
||||
if ( DoesMercHaveDisability( pSoldier, FEAR_OF_INSECTS ) && MercIsInTropicalSector( pSoldier ) )
|
||||
{
|
||||
// SANDRO - fear of insects, and we are in tropical sector
|
||||
iEffExpLevel -= 1;
|
||||
|
||||
+32
-2
@@ -139,10 +139,11 @@ TraitSelection::Setup( UINT32 aVal )
|
||||
CHAR16 pStr[300];
|
||||
|
||||
// create entries for the sub-menus for each trait
|
||||
const UINT8 num = 2;
|
||||
const UINT8 num = 3;
|
||||
UINT8 traitarray[num];
|
||||
traitarray[0] = RADIO_OPERATOR_NT;
|
||||
traitarray[1] = VARIOUSSKILLS;
|
||||
traitarray[1] = INTEL;
|
||||
traitarray[2] = VARIOUSSKILLS;
|
||||
for ( int i = 0; i < num; ++i)
|
||||
{
|
||||
swprintf( pStr, gzMercSkillTextNew[traitarray[i]] );
|
||||
@@ -239,6 +240,26 @@ SkillSelection::Setup( UINT32 aVal )
|
||||
}
|
||||
break;
|
||||
|
||||
case INTEL:
|
||||
{
|
||||
for ( UINT32 uiCounter = SKILLS_INTEL_FIRST; uiCounter <= SKILLS_INTEL_LAST; ++uiCounter )
|
||||
{
|
||||
swprintf( pStr, pTraitSkillsMenuStrings[uiCounter] );
|
||||
|
||||
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 ) ) )
|
||||
{
|
||||
// Set this option off.
|
||||
pOption->setAvail( new popupCallbackFunction<bool, void*>( &Popup_OptionOff, NULL ) );
|
||||
}
|
||||
|
||||
GetPopup()->addOption( *pOption );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VARIOUSSKILLS:
|
||||
{
|
||||
for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter)
|
||||
@@ -293,6 +314,15 @@ SkillSelection::Setup( UINT32 aVal )
|
||||
}
|
||||
break;
|
||||
|
||||
case INTEL:
|
||||
{
|
||||
for ( UINT32 uiCounter = SKILLS_INTEL_FIRST; uiCounter <= SKILLS_INTEL_LAST; ++uiCounter )
|
||||
{
|
||||
SetRegionFastHelpText( &( GetPopup()->MenuRegion[cnt++] ), pSoldier->PrintSkillDesc( uiCounter ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VARIOUSSKILLS:
|
||||
{
|
||||
for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter)
|
||||
|
||||
@@ -1228,7 +1228,7 @@ BOOLEAN InternalAddSoldierToSector( UINT8 ubID, BOOLEAN fCalculateDirection, BOO
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_client && (pSoldier->ubStrategicInsertionCode == INSERTION_CODE_GRIDNO))
|
||||
if ( ( is_client && (pSoldier->ubStrategicInsertionCode == INSERTION_CODE_GRIDNO) ) || ( pSoldier->usSoldierFlagMask2 & SOLDIER_CONCEALINSERTION ) )
|
||||
{
|
||||
sGridNo = pSoldier->sInsertionGridNo;
|
||||
ubCalculatedDirection = pSoldier->ubDirection;
|
||||
@@ -1625,14 +1625,15 @@ void AddSoldierToSectorGridNo( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDir
|
||||
{
|
||||
if ( pSoldier->bTeam == gbPlayerNum )
|
||||
{
|
||||
RevealRoofsAndItems( pSoldier, TRUE, FALSE, pSoldier->pathing.bLevel, TRUE );
|
||||
if ( !( pSoldier->usSoldierFlagMask2 & SOLDIER_CONCEALINSERTION ) )
|
||||
RevealRoofsAndItems( pSoldier, TRUE, FALSE, pSoldier->pathing.bLevel, TRUE );
|
||||
|
||||
// ATE: Patch fix: If we are in an non-interruptable animation, stop!
|
||||
if ( pSoldier->usAnimState == HOPFENCE )
|
||||
{
|
||||
pSoldier->flags.fInNonintAnim = FALSE;
|
||||
pSoldier->SoldierGotoStationaryStance( );
|
||||
}
|
||||
// ATE: Patch fix: If we are in an non-interruptable animation, stop!
|
||||
if ( pSoldier->usAnimState == HOPFENCE )
|
||||
{
|
||||
pSoldier->flags.fInNonintAnim = FALSE;
|
||||
pSoldier->SoldierGotoStationaryStance( );
|
||||
}
|
||||
|
||||
pSoldier->EVENT_StopMerc( sGridNo, ubDirection );
|
||||
}
|
||||
|
||||
+329
-92
@@ -15725,15 +15725,11 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
|
||||
// 0 - civilians are always ok
|
||||
// 1 - civilians are suspicious at night
|
||||
// 2 - civilians are always suspicious
|
||||
// if underground, we still use the surface value
|
||||
|
||||
UINT8 sectordata = 0;
|
||||
UINT8 ubSectorId = SECTOR( gWorldSectorX, gWorldSectorY );
|
||||
if ( gbWorldSectorZ > 0 )
|
||||
// underground we are always suspicious
|
||||
sectordata = 2;
|
||||
else if ( ubSectorId >= 0 && ubSectorId < 256 )
|
||||
sectordata = SectorExternalData[ubSectorId][gbWorldSectorZ].usCurfewValue;
|
||||
|
||||
UINT8 ubSectorId = SECTOR( this->sSectorX, this->sSectorY );
|
||||
UINT8 sectordata = SectorExternalData[ubSectorId][0].usCurfewValue;
|
||||
|
||||
if ( sectordata > 1 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_CURFEW_BROKEN], this->GetName( ) );
|
||||
@@ -15746,83 +15742,15 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check wether we are around a fresh corpse - this will make us much more suspicious
|
||||
INT32 cnt;
|
||||
ROTTING_CORPSE * pCorpse;
|
||||
for ( cnt = 0; cnt < giNumRottingCorpse; ++cnt )
|
||||
{
|
||||
pCorpse = &(gRottingCorpse[cnt]);
|
||||
|
||||
if ( pCorpse && pCorpse->fActivated && pCorpse->def.ubAIWarningValue > 0 && PythSpacesAway( this->sGridNo, pCorpse->def.sGridNo ) <= 5 )
|
||||
{
|
||||
// check: is this corpse that of an ally of the observing soldier?
|
||||
BOOLEAN fCorpseOFAlly = FALSE;
|
||||
if ( pSoldier->bTeam == ENEMY_TEAM )
|
||||
{
|
||||
// check wether corpse was one of soldier's allies
|
||||
for ( UINT8 i = UNIFORM_ENEMY_ADMIN; i <= UNIFORM_ENEMY_ELITE; ++i )
|
||||
{
|
||||
if ( COMPARE_PALETTEREP_ID( pCorpse->def.VestPal, gUniformColors[i].vest ) && COMPARE_PALETTEREP_ID( pCorpse->def.PantsPal, gUniformColors[i].pants ) )
|
||||
{
|
||||
fCorpseOFAlly = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( pSoldier->bTeam == OUR_TEAM || pSoldier->bTeam == MILITIA_TEAM )
|
||||
{
|
||||
// check wether corpse was one of soldier's allies
|
||||
for ( UINT8 i = UNIFORM_MILITIA_ROOKIE; i <= UNIFORM_MILITIA_ELITE; ++i )
|
||||
{
|
||||
if ( COMPARE_PALETTEREP_ID( pCorpse->def.VestPal, gUniformColors[i].vest ) && COMPARE_PALETTEREP_ID( pCorpse->def.PantsPal, gUniformColors[i].pants ) )
|
||||
{
|
||||
fCorpseOFAlly = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a corpse was found near our position. If the soldier observing us can see it, he will be alarmed
|
||||
if ( fCorpseOFAlly && SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pCorpse->def.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NEAR_CORPSE], this->GetName( ) );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
{
|
||||
// if our equipment is too good, that is suspicious... not covert!
|
||||
if ( this->EquipmentTooGood( (distance < discoverrange) ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_SUSPICIOUS_EQUIPMENT], this->GetName( ) );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// are we targeting a buddy of our observer?
|
||||
if ( this->ubTargetID != NOBODY && MercPtrs[this->ubTargetID] && MercPtrs[this->ubTargetID]->bTeam == pSoldier->bTeam )
|
||||
{
|
||||
// if we are aiming at a soldier, others will notice our intent... not covert!
|
||||
if ( WeaponReady( this ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_TARGETTING_SOLDIER], this->GetName( ), MercPtrs[this->ubTargetID]->GetName( ) );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// even as a soldier, we will be caught around fresh corpses
|
||||
// assassins will not be uncovered around corpses, as the AI cannot willingly evade them... one could 'ward' against assassins by surrounding yourself with fresh corpses
|
||||
if ( distance < gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse && !this->IsAssassin( ) )
|
||||
// do this check only if we are in the currently loaded sector
|
||||
if ( this->sSectorX == gWorldSectorX && this->sSectorY == gWorldSectorY && this->bSectorZ == gbWorldSectorZ )
|
||||
{
|
||||
// check wether we are around a fresh corpse - this will make us much more suspicious
|
||||
// I deem this necessary, to avoid cheap exploits by nefarious players :-)
|
||||
INT32 cnt;
|
||||
ROTTING_CORPSE * pCorpse;
|
||||
for ( cnt = 0; cnt < giNumRottingCorpse; ++cnt )
|
||||
{
|
||||
pCorpse = &(gRottingCorpse[cnt]);
|
||||
pCorpse = &( gRottingCorpse[cnt] );
|
||||
|
||||
if ( pCorpse && pCorpse->fActivated && pCorpse->def.ubAIWarningValue > 0 && PythSpacesAway( this->sGridNo, pCorpse->def.sGridNo ) <= 5 )
|
||||
{
|
||||
@@ -15856,7 +15784,7 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
|
||||
// a corpse was found near our position. If the soldier observing us can see it, he will be alarmed
|
||||
if ( fCorpseOFAlly && SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pCorpse->def.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NEAR_CORPSE], this->GetName( ) );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NEAR_CORPSE], this->GetName() );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -15864,13 +15792,89 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
{
|
||||
// if our equipment is too good, that is suspicious... not covert!
|
||||
if ( this->EquipmentTooGood( (distance < discoverrange) ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_SUSPICIOUS_EQUIPMENT], this->GetName( ) );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// do this check only if we are in the currently loaded sector
|
||||
if ( this->sSectorX == gWorldSectorX && this->sSectorY == gWorldSectorY && this->bSectorZ == gbWorldSectorZ )
|
||||
{
|
||||
// are we targeting a buddy of our observer?
|
||||
if ( this->ubTargetID != NOBODY && MercPtrs[this->ubTargetID] && MercPtrs[this->ubTargetID]->bTeam == pSoldier->bTeam )
|
||||
{
|
||||
// if we are aiming at a soldier, others will notice our intent... not covert!
|
||||
if ( WeaponReady( this ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_TARGETTING_SOLDIER], this->GetName(), MercPtrs[this->ubTargetID]->GetName() );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// even as a soldier, we will be caught around fresh corpses
|
||||
// assassins will not be uncovered around corpses, as the AI cannot willingly evade them... one could 'ward' against assassins by surrounding yourself with fresh corpses
|
||||
if ( distance < gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse && !this->IsAssassin() )
|
||||
{
|
||||
// check wether we are around a fresh corpse - this will make us much more suspicious
|
||||
// I deem this necessary, to avoid cheap exploits by nefarious players :-)
|
||||
INT32 cnt;
|
||||
ROTTING_CORPSE * pCorpse;
|
||||
for ( cnt = 0; cnt < giNumRottingCorpse; ++cnt )
|
||||
{
|
||||
pCorpse = &( gRottingCorpse[cnt] );
|
||||
|
||||
if ( pCorpse && pCorpse->fActivated && pCorpse->def.ubAIWarningValue > 0 && PythSpacesAway( this->sGridNo, pCorpse->def.sGridNo ) <= 5 )
|
||||
{
|
||||
// check: is this corpse that of an ally of the observing soldier?
|
||||
BOOLEAN fCorpseOFAlly = FALSE;
|
||||
if ( pSoldier->bTeam == ENEMY_TEAM )
|
||||
{
|
||||
// check wether corpse was one of soldier's allies
|
||||
for ( UINT8 i = UNIFORM_ENEMY_ADMIN; i <= UNIFORM_ENEMY_ELITE; ++i )
|
||||
{
|
||||
if ( COMPARE_PALETTEREP_ID( pCorpse->def.VestPal, gUniformColors[i].vest ) && COMPARE_PALETTEREP_ID( pCorpse->def.PantsPal, gUniformColors[i].pants ) )
|
||||
{
|
||||
fCorpseOFAlly = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( pSoldier->bTeam == OUR_TEAM || pSoldier->bTeam == MILITIA_TEAM )
|
||||
{
|
||||
// check wether corpse was one of soldier's allies
|
||||
for ( UINT8 i = UNIFORM_MILITIA_ROOKIE; i <= UNIFORM_MILITIA_ELITE; ++i )
|
||||
{
|
||||
if ( COMPARE_PALETTEREP_ID( pCorpse->def.VestPal, gUniformColors[i].vest ) && COMPARE_PALETTEREP_ID( pCorpse->def.PantsPal, gUniformColors[i].pants ) )
|
||||
{
|
||||
fCorpseOFAlly = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a corpse was found near our position. If the soldier observing us can see it, he will be alarmed
|
||||
if ( fCorpseOFAlly && SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pCorpse->def.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NEAR_CORPSE], this->GetName() );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// uncover if merc is using flashlight and alert is raised
|
||||
if ( pSoldier->bTeam == ENEMY_TEAM &&
|
||||
pSoldier->aiData.bAlertStatus >= STATUS_RED &&
|
||||
(NightTime( ) || gbWorldSectorZ > 0) &&
|
||||
(NightTime( ) || this->bSectorZ > 0) &&
|
||||
this->GetBestEquippedFlashLightRange( ) > 0 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s has flashlight!", this->GetName( ) );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s has a flashlight!", this->GetName( ) );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -16045,7 +16049,7 @@ void SOLDIERTYPE::ApplyCovert( BOOLEAN aWithMessage )
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_DISGUISED_AS_CIVILIAN], this->GetName( ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// reevaluate sight - otherwise we could hide by changing clothes in plain sight!
|
||||
OtherTeamsLookForMan( this );
|
||||
}
|
||||
@@ -17458,7 +17462,22 @@ void SOLDIERTYPE::SoldierPropertyUpkeep( )
|
||||
{
|
||||
// these effects last only one turn
|
||||
this->usSoldierFlagMask &= ~(SOLDIER_AIRDROP_TURN | SOLDIER_ASSAULT_BONUS | SOLDIER_RAISED_REDALERT);
|
||||
|
||||
this->usSoldierFlagMask2 &= ~SOLDIER_CONCEALINSERTION;
|
||||
|
||||
// this looks bizarre, but is required
|
||||
if ( this->usSoldierFlagMask2 & SOLDIER_CONCEALINSERTION_DISCOVERED )
|
||||
{
|
||||
this->usSoldierFlagMask2 &= ~SOLDIER_CONCEALINSERTION_DISCOVERED;
|
||||
|
||||
// we loose our disguise
|
||||
this->LooseDisguise();
|
||||
|
||||
if ( gSkillTraitValues.fCOStripIfUncovered )
|
||||
this->Strip();
|
||||
|
||||
HandleInitialRedAlert( ENEMY_TEAM, FALSE );
|
||||
}
|
||||
|
||||
if ( HasBackgroundFlag( BACKGROUND_EXP_UNDERGROUND ) && this->bSectorZ )
|
||||
++bExtraExpLevel;
|
||||
|
||||
@@ -17550,6 +17569,63 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck, INT32 sGridNo )
|
||||
canuse = TRUE;
|
||||
break;
|
||||
|
||||
case SKILLS_INTEL_CONCEAL:
|
||||
case SKILLS_INTEL_GATHERINTEL:
|
||||
// in order to conceal, we need:
|
||||
// - enemy team not aware of us (otherwise we could use this skill to instantly escape from combat)
|
||||
// - an enemy presence (otherwise, why bother)
|
||||
// - we must be alone (otherwise player could start combat again, at which point we'd need to appear from thin air)
|
||||
// - no militia present (same reason)
|
||||
// - no hostile civilians or creatures
|
||||
// - valid disguise
|
||||
{
|
||||
canuse = TRUE;
|
||||
|
||||
// we might already be on assignment, so be careful here
|
||||
INT8 sectorz = this->bSectorZ;
|
||||
if ( SPY_LOCATION( this->bAssignment ) )
|
||||
sectorz = max( 0, sectorz - 10 );
|
||||
|
||||
// if we are disguised as a civilian, but there is a curfew here, don't allow that
|
||||
if ( ( this->usSoldierFlagMask & SOLDIER_COVERT_CIV ) )
|
||||
{
|
||||
// civilians are suspicious if they are found in certain sectors. Especially at night
|
||||
// sector specific value:
|
||||
// 0 - civilians are always ok
|
||||
// 1 - civilians are suspicious at night
|
||||
// 2 - civilians are always suspicious
|
||||
// if underground, we still use the surface value
|
||||
|
||||
UINT8 ubSectorId = SECTOR( this->sSectorX, this->sSectorY );
|
||||
UINT8 sectordata = SectorExternalData[ubSectorId][sectorz].usCurfewValue;
|
||||
|
||||
if ( sectordata > 1 )
|
||||
canuse = FALSE;
|
||||
// is it night?
|
||||
else if ( sectordata == 1 && GetTimeOfDayAmbientLightLevel() < NORMAL_LIGHTLEVEL_DAY + 2 )
|
||||
canuse = FALSE;
|
||||
}
|
||||
|
||||
if ( canuse && NumEnemiesInAnySector( this->sSectorX, this->sSectorY, sectorz ) > 0 &&
|
||||
NumPlayerTeamMembersInSector( this->sSectorX, this->sSectorY, this->bSectorZ ) == 1 &&
|
||||
( sectorz || NumNonPlayerTeamMembersInSector( this->sSectorX, this->sSectorY, MILITIA_TEAM ) == 0 ) &&
|
||||
SeemsLegit( this->ubID ) )
|
||||
{
|
||||
// additional checks if we are in the currently loaded sector
|
||||
if ( this->sSectorX == gWorldSectorX && this->sSectorY == gWorldSectorY && this->bSectorZ == gbWorldSectorZ )
|
||||
{
|
||||
if ( gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition ||
|
||||
( gTacticalStatus.uiFlags & INCOMBAT ) ||
|
||||
HostileCiviliansPresent() ||
|
||||
HostileCreaturesPresent() )
|
||||
{
|
||||
canuse = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SKILLS_SPOTTER:
|
||||
if ( (!fAPCheck || EnoughPoints( this, APBPConstants[AP_SPOTTER], 0, FALSE )) && CanSpot( ) )
|
||||
canuse = TRUE;
|
||||
@@ -17623,6 +17699,33 @@ BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT32 ID )
|
||||
return SwitchOffRadio( );
|
||||
break;
|
||||
|
||||
case SKILLS_INTEL_CONCEAL:
|
||||
case SKILLS_INTEL_GATHERINTEL:
|
||||
{
|
||||
// ATE: Patch fix If in a vehicle, remove from vehicle...
|
||||
TakeSoldierOutOfVehicle( this );
|
||||
|
||||
// we store our location and later retrieve it, as the gridno will be set to NOWHERE
|
||||
this->sMTActionGridNo = this->sGridNo;
|
||||
|
||||
// remove from squad
|
||||
RemoveCharacterFromSquads( this );
|
||||
|
||||
ChangeSoldiersAssignment( this, CONCEALED + iSkill - SKILLS_INTEL_CONCEAL );
|
||||
|
||||
// Remove soldier's graphic
|
||||
this->RemoveSoldierFromGridNo();
|
||||
|
||||
UpdateMercsInSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
|
||||
|
||||
CheckForEndOfBattle( FALSE );
|
||||
|
||||
CheckAndHandleUnloadingOfCurrentWorld();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SKILLS_SPOTTER:
|
||||
return BecomeSpotter( usMapPos );
|
||||
break;
|
||||
@@ -17704,6 +17807,26 @@ STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
|
||||
|
||||
break;
|
||||
|
||||
case SKILLS_INTEL_CONCEAL:
|
||||
case SKILLS_INTEL_GATHERINTEL:
|
||||
|
||||
//swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_COVERTTRAIT] );
|
||||
//wcscat( skilldescarray, atStr );
|
||||
|
||||
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_ENEMYSECTOR] );
|
||||
wcscat( skilldescarray, atStr );
|
||||
|
||||
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_SINGLEMERC] );
|
||||
wcscat( skilldescarray, atStr );
|
||||
|
||||
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_NOALARM] );
|
||||
wcscat( skilldescarray, atStr );
|
||||
|
||||
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_DISGUISE_CIV_OR_MIL] );
|
||||
wcscat( skilldescarray, atStr );
|
||||
|
||||
break;
|
||||
|
||||
case SKILLS_SPOTTER:
|
||||
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_X_AP], APBPConstants[AP_SPOTTER] );
|
||||
wcscat( skilldescarray, atStr );
|
||||
@@ -19734,6 +19857,117 @@ void SOLDIERTYPE::CancelDrag()
|
||||
this->sDragCorpseID = -1;
|
||||
}
|
||||
|
||||
// Flugente: spy assignments
|
||||
extern UINT32 gCoolnessBySector[256];
|
||||
|
||||
UINT8 SOLDIERTYPE::GetUncoverRisk()
|
||||
{
|
||||
if ( this->stats.bLife < OKLIFE || ( this->usSoldierFlagMask & SOLDIER_POW ) )
|
||||
return 0;
|
||||
|
||||
if ( !SPY_LOCATION(this->bAssignment) )
|
||||
return 100;
|
||||
|
||||
// base value:
|
||||
// 15% level
|
||||
// 15% stealth
|
||||
// 70% covert trait
|
||||
UINT32 val = 15 * EffectiveExpLevel ( this, FALSE )
|
||||
+ 1.5f * GetWornStealth( this )
|
||||
+ 350 * NUM_SKILL_TRAITS( this, COVERT_NT );
|
||||
|
||||
ReducePointsForFatigue( this, &val );
|
||||
|
||||
// personality/disability modifiers
|
||||
FLOAT modifier = 1.0f;
|
||||
if ( DoesMercHaveDisability( this, NERVOUS ) ) modifier -= 0.05f;
|
||||
|
||||
if ( DoesMercHavePersonality( this, CHAR_TRAIT_SOCIABLE ) ) modifier += 0.05f;
|
||||
if ( DoesMercHavePersonality( this, CHAR_TRAIT_COWARD ) ) modifier -= 0.05f;
|
||||
|
||||
// personal value in [0; 100]
|
||||
int personalvalue = (FLOAT)(val * modifier) / 10.0f;
|
||||
personalvalue = min( 100, max( 0, personalvalue ) );
|
||||
|
||||
// if we do this disguised as a soldier, risk will be much higer, as we are under much more scrutiny. This makes up for the increased gain in soldier disguise
|
||||
// less risk if we are asleep, just hiding or forced to hide
|
||||
UINT8 typemultiplier = ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER ) ? 5 : 2;
|
||||
if ( ( this->bAssignment == CONCEALED ) || this->flags.fMercAsleep || this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
|
||||
typemultiplier = 1;
|
||||
|
||||
// we now take the sector coolness as a measurement of how important the sector is, and thus how intel we gain
|
||||
// correct outliers - value in[0; 100]
|
||||
UINT32 sectorvalue = typemultiplier * min( 20, gCoolnessBySector[SECTOR( this->sSectorX, this->sSectorY )] );
|
||||
|
||||
UINT8 totalvalue = sectorvalue * ( 110 - personalvalue ) / 100;
|
||||
totalvalue = min(100, max(0, totalvalue ) );
|
||||
|
||||
// A most awesome merc in Meduna palace, disguised as a soldier, would have a value of 1.05 * 4. 63 * 4 = 10.649 at this point.
|
||||
// This would be the place where we modify our intel gain rate.
|
||||
|
||||
return totalvalue;
|
||||
}
|
||||
|
||||
FLOAT SOLDIERTYPE::GetIntelGain()
|
||||
{
|
||||
if ( this->stats.bLife < OKLIFE || ( this->usSoldierFlagMask & SOLDIER_POW ) )
|
||||
return 0.0f;
|
||||
|
||||
// if not on correct assignments, no gain
|
||||
if ( this->bAssignment != GATHERINTEL )
|
||||
return 0.0f;
|
||||
|
||||
// if we're asleep, or on a penalty, we accomplish nothing
|
||||
if ( this->flags.fMercAsleep || this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
|
||||
return 0.0f;
|
||||
|
||||
// the covert trait isn't that important in determining the intel gain. It is much more important in mitigating the risk of exposure, however
|
||||
// base value:
|
||||
// 50% wisdom
|
||||
// 10% level
|
||||
// 5% scout trait
|
||||
// 15% covert trait
|
||||
// 20% snitch trait
|
||||
UINT32 val = 5 * EffectiveWisdom( this )
|
||||
+ 10 * EffectiveExpLevel ( this, FALSE )
|
||||
+ 50 * NUM_SKILL_TRAITS( this, SCOUTING_NT )
|
||||
+ 75 * NUM_SKILL_TRAITS( this, COVERT_NT )
|
||||
+ 200 * NUM_SKILL_TRAITS( this, SNITCH_NT );
|
||||
|
||||
ReducePointsForFatigue( this, &val );
|
||||
|
||||
// personality/disability modifiers
|
||||
FLOAT modifier = 1.0f;
|
||||
if ( DoesMercHaveDisability( this, FORGETFUL ) ) modifier -= 0.15f;
|
||||
if ( DoesMercHaveDisability( this, PSYCHO ) ) modifier -= 0.05f;
|
||||
|
||||
if ( DoesMercHavePersonality( this, CHAR_TRAIT_SOCIABLE ) ) modifier += 0.10f;
|
||||
if ( DoesMercHavePersonality( this, CHAR_TRAIT_LONER ) ) modifier -= 0.10f;
|
||||
if ( DoesMercHavePersonality( this, CHAR_TRAIT_ASSERTIVE ) ) modifier += 0.05f;
|
||||
if ( DoesMercHavePersonality( this, CHAR_TRAIT_PRIMITIVE ) ) modifier -= 0.10f;
|
||||
|
||||
FLOAT personalvalue = (FLOAT)(val * modifier) / 1000.0f;
|
||||
|
||||
// we now take the sector coolness as a measurement of how important the sector is, and thus how intel we gain
|
||||
// correct outliers
|
||||
UINT32 ubLocationModifier = 1 + max(2, min(20, gCoolnessBySector[SECTOR( this->sSectorX, this->sSectorY )] ) );
|
||||
|
||||
// in order not to make the differences to great, alter these values - will now be in [0.6; 4.63]
|
||||
FLOAT sectorvalue = log( ubLocationModifier );
|
||||
sectorvalue *= sectorvalue / 2.0f;
|
||||
|
||||
FLOAT totalvalue = personalvalue * sectorvalue;
|
||||
|
||||
// if we do this disguised as a soldier, we get more info
|
||||
if ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
totalvalue *= 2;
|
||||
|
||||
// A most awesome merc in Meduna palace, disguised as a soldier, would have a value of 1.15 * 4.63 * 2 = 10.649 at this point.
|
||||
// This would be the place where we modify our intel gain rate.
|
||||
|
||||
return totalvalue;
|
||||
}
|
||||
|
||||
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
INT8 bBandaged; //,savedOurTurn;
|
||||
@@ -21807,11 +22041,10 @@ void DebugValidateSoldierData( )
|
||||
|
||||
// reset frame counter
|
||||
uiFrameCount = 0;
|
||||
|
||||
|
||||
|
||||
// Loop through our team...
|
||||
cnt = gTacticalStatus.Team[gbPlayerNum].bFirstID;
|
||||
for ( pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[gbPlayerNum].bLastID; cnt++, pSoldier++ )
|
||||
for ( pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[gbPlayerNum].bLastID; ++cnt, pSoldier++ )
|
||||
{
|
||||
if ( pSoldier->bActive )
|
||||
{
|
||||
@@ -21820,7 +22053,11 @@ void DebugValidateSoldierData( )
|
||||
if ( pSoldier->stats.bLife > 0 && !(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) )
|
||||
{
|
||||
// Alive -- now check for proper group IDs
|
||||
if ( pSoldier->ubGroupID == 0 && pSoldier->bAssignment != IN_TRANSIT && pSoldier->bAssignment != ASSIGNMENT_POW && !(pSoldier->flags.uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER)) )
|
||||
if ( pSoldier->ubGroupID == 0 &&
|
||||
!SPY_LOCATION( pSoldier->bAssignment ) &&
|
||||
pSoldier->bAssignment != IN_TRANSIT &&
|
||||
pSoldier->bAssignment != ASSIGNMENT_POW &&
|
||||
!(pSoldier->flags.uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER)) )
|
||||
{
|
||||
// This is bad!
|
||||
swprintf( sString, L"Soldier Data Error: Soldier %d is alive but has a zero group ID.", cnt );
|
||||
@@ -21833,9 +22070,9 @@ void DebugValidateSoldierData( )
|
||||
fProblemDetected = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
//else
|
||||
{
|
||||
if ( pSoldier->ubGroupID != 0 && (pSoldier->flags.uiStatusFlags & SOLDIER_DEAD) )
|
||||
//if ( pSoldier->ubGroupID != 0 && (pSoldier->flags.uiStatusFlags & SOLDIER_DEAD) )
|
||||
{
|
||||
// Dead guys should have 0 group IDs
|
||||
//swprintf( sString, L"GroupID Error: Soldier %d is dead but has a non-zero group ID.", cnt );
|
||||
@@ -21847,7 +22084,7 @@ void DebugValidateSoldierData( )
|
||||
if ( (pSoldier->bAssignment != IN_TRANSIT) &&
|
||||
((pSoldier->sSectorX <= 0) || (pSoldier->sSectorX >= 17) ||
|
||||
(pSoldier->sSectorY <= 0) || (pSoldier->sSectorY >= 17) ||
|
||||
(pSoldier->bSectorZ < 0) || (pSoldier->bSectorZ > 3)) )
|
||||
(pSoldier->bSectorZ < 0) || (pSoldier->bSectorZ > (SPY_LOCATION( pSoldier->bAssignment ) ? 13 : 3) ) ) )
|
||||
{
|
||||
swprintf( sString, L"Soldier Data Error: Soldier %d is located at %d/%d/%d.", cnt, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
|
||||
fProblemDetected = TRUE;
|
||||
@@ -22051,7 +22288,7 @@ BOOLEAN HAS_SKILL_TRAIT( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber )
|
||||
return FALSE;
|
||||
|
||||
// Flugente: compatibility with skills
|
||||
if ( uiSkillTraitNumber == VARIOUSSKILLS )
|
||||
if ( uiSkillTraitNumber == INTEL || uiSkillTraitNumber == VARIOUSSKILLS )
|
||||
return TRUE;
|
||||
|
||||
INT8 bNumMajorTraitsCounted = 0;
|
||||
|
||||
@@ -414,6 +414,10 @@ 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_BAYONET_RUNBONUS 0x00004000 // we are performing a bayonet attack after transitioning from running, giving our attack extra force
|
||||
#define SOLDIER_CONCEALINSERTION 0x00008000 // we enteri a sector by transition from concealed state (which causes us to spawn at the location we left the sector in)
|
||||
|
||||
#define SOLDIER_CONCEALINSERTION_DISCOVERED 0x00010000 // we enter a sector by transition from concealed state, but as we were 'discovered', set red alert
|
||||
#define SOLDIER_MERC_POW_LOCATIONKNOWN 0x00020000 // we are a POW, but the player has discovered our location
|
||||
|
||||
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
|
||||
// ----------------------------------------------------------------
|
||||
@@ -584,6 +588,12 @@ enum{
|
||||
SKILLS_RADIO_TURNOFF,
|
||||
SKILLS_RADIO_LAST = SKILLS_RADIO_TURNOFF,
|
||||
|
||||
// spy
|
||||
SKILLS_INTEL_FIRST,
|
||||
SKILLS_INTEL_CONCEAL = SKILLS_INTEL_FIRST, // assignment: spy hides among the population
|
||||
SKILLS_INTEL_GATHERINTEL, // assignment: spy gathers information while disguised
|
||||
SKILLS_INTEL_LAST = SKILLS_INTEL_GATHERINTEL,
|
||||
|
||||
// various
|
||||
SKILLS_VARIOUS_FIRST,
|
||||
SKILLS_SPOTTER = SKILLS_VARIOUS_FIRST,
|
||||
@@ -608,6 +618,7 @@ enum {
|
||||
SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_SECONDS = 0,
|
||||
SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS,
|
||||
SOLDIER_COOLDOWN_CRYO, // counts how many turns character will be frozen
|
||||
SOLDIER_COOLDOWN_INTEL_PENALTY, // after being discovered, we can't gain intel from the assignment for this many hours
|
||||
|
||||
SOLDIER_COOLDOWN_MAX = 20, // enough space for fillers
|
||||
};
|
||||
@@ -1964,6 +1975,10 @@ public:
|
||||
void SetDragOrderPerson( UINT16 usID );
|
||||
void SetDragOrderCorpse( UINT32 usID );
|
||||
void CancelDrag();
|
||||
|
||||
// Flugente: spy assignments
|
||||
UINT8 GetUncoverRisk();
|
||||
FLOAT GetIntelGain();
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}; // SOLDIERTYPE;
|
||||
|
||||
@@ -4170,7 +4170,7 @@ void CopyProfileItems( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCreateStruc
|
||||
//NOTE: We don't want to add Mike or Iggy if this is being called from autoresolve!
|
||||
void OkayToUpgradeEliteToSpecialProfiledEnemy( SOLDIERCREATE_STRUCT *pp )
|
||||
{
|
||||
if( !gfProfiledEnemyAdded && gubEnemyEncounterCode != ENEMY_ENCOUNTER_CODE && gubEnemyEncounterCode != ENEMY_INVASION_CODE )
|
||||
if( !gfProfiledEnemyAdded && GetEnemyEncounterCode() != ENEMY_ENCOUNTER_CODE && GetEnemyEncounterCode() != ENEMY_INVASION_CODE )
|
||||
{
|
||||
if( gubFact[ FACT_MIKE_AVAILABLE_TO_ARMY ] == 1 && !pp->fOnRoof )
|
||||
{
|
||||
|
||||
@@ -775,8 +775,8 @@ BOOLEAN AddPlacementToWorld( SOLDIERINITNODE *curr, GROUP *pGroup = NULL )
|
||||
}
|
||||
|
||||
// Flugente: if this is an enemy, and we are using ambush code, place us somewhat away from the map center, where the player will be
|
||||
if ( (tempDetailedPlacement.bTeam == ENEMY_TEAM && (gubEnemyEncounterCode == ENEMY_AMBUSH_CODE || gubEnemyEncounterCode == ENEMY_AMBUSH_DEPLOYMENT_CODE) ) ||
|
||||
(tempDetailedPlacement.bTeam == CREATURE_TEAM && gubEnemyEncounterCode == BLOODCAT_AMBUSH_CODE) )
|
||||
if ( (tempDetailedPlacement.bTeam == ENEMY_TEAM && ( GetEnemyEncounterCode() == ENEMY_AMBUSH_CODE || GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE) ) ||
|
||||
(tempDetailedPlacement.bTeam == CREATURE_TEAM && GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE) )
|
||||
{
|
||||
if ( (gGameExternalOptions.uAmbushEnemyEncircle == 1 && PythSpacesAway( tempDetailedPlacement.sInsertionGridNo, gMapInformation.sCenterGridNo ) <= gAmbushRadiusModifier * gGameExternalOptions.usAmbushEnemyEncircleRadius1) ||
|
||||
( gGameExternalOptions.uAmbushEnemyEncircle == 2) )
|
||||
|
||||
@@ -397,6 +397,10 @@ BOOLEAN AddCharacterToSquad( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
|
||||
SetCurrentSquad( bSquadValue, TRUE );
|
||||
}
|
||||
|
||||
if ( SPY_LOCATION( pCharacter->bOldAssignment ) )
|
||||
{
|
||||
pCharacter->usSoldierFlagMask2 |= SOLDIER_CONCEALINSERTION;
|
||||
}
|
||||
|
||||
return ( TRUE );
|
||||
}
|
||||
|
||||
+30
-8
@@ -51,6 +51,7 @@ UINT8 HandleWirecutterCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCur
|
||||
UINT8 HandleRepairCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
||||
UINT8 HandleRefuelCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
||||
UINT8 HandleRemoteCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
||||
UINT8 HandleCameraCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
||||
UINT8 HandleBombCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
||||
UINT8 HandleJarCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
||||
UINT8 HandleTinCanCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
||||
@@ -238,14 +239,14 @@ UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos
|
||||
|
||||
if ( fActivated )
|
||||
{
|
||||
if ( !gfUIHandlePhysicsTrajectory )
|
||||
{
|
||||
ubCursorID = HandleNonActivatedTossCursor( pSoldier, sTargetGridNo, fRecalc, uiCursorFlags, ubItemCursor );
|
||||
}
|
||||
else
|
||||
{
|
||||
ubCursorID = HandleActivatedTossCursor( pSoldier, sTargetGridNo, ubItemCursor );
|
||||
}
|
||||
if ( !gfUIHandlePhysicsTrajectory )
|
||||
{
|
||||
ubCursorID = HandleNonActivatedTossCursor( pSoldier, sTargetGridNo, fRecalc, uiCursorFlags, ubItemCursor );
|
||||
}
|
||||
else
|
||||
{
|
||||
ubCursorID = HandleActivatedTossCursor( pSoldier, sTargetGridNo, ubItemCursor );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -278,6 +279,10 @@ UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos
|
||||
ubCursorID = HandleBombCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
||||
break;
|
||||
|
||||
case CAMERACURS:
|
||||
ubCursorID = HandleCameraCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
||||
break;
|
||||
|
||||
case REMOTECURS:
|
||||
|
||||
ubCursorID = HandleRemoteCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
||||
@@ -2184,6 +2189,19 @@ UINT8 HandleRemoteCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivat
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 HandleCameraCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
||||
{
|
||||
// DRAW PATH TO GUY
|
||||
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_HANDCUFF );
|
||||
|
||||
// do we have handcuffs in our hand?
|
||||
if ( HasItemFlag( ( &( pSoldier->inv[HANDPOS] ) )->usItem, CAMERA ) && SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, gsInterfaceLevel, 0, TRUE, CALC_FROM_WANTED_DIR, TRUE ) )
|
||||
{
|
||||
return CAMERA_GREY_UICURSOR;
|
||||
}
|
||||
|
||||
return CAMERA_RED_UICURSOR;
|
||||
}
|
||||
|
||||
UINT8 HandleBombCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
||||
{
|
||||
@@ -2847,6 +2865,10 @@ UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier )
|
||||
if ( gGameExternalOptions.fAllowPrisonerSystem && HasItemFlag(usInHand, HANDCUFFS) )
|
||||
ubCursor = HANDCUFFCURS;
|
||||
|
||||
// Flugente: camera cursor
|
||||
if ( HasItemFlag( usInHand, CAMERA ) )
|
||||
ubCursor = CAMERACURS;
|
||||
|
||||
// Flugente: interactive actions
|
||||
// we only check whether an action is possible in principle, not whether this particular guy can do it. That way we know an action is possible here even if we can't perform it at the moment.
|
||||
// only do this if the item doesn't already allow us to do something else
|
||||
|
||||
@@ -179,8 +179,9 @@ typedef enum
|
||||
#define NEWTRAIT_MERCSKILL_EXPERTOFFSET (NUM_MAJOR_TRAITS + NUM_MINOR_TRAITS)
|
||||
#define NEWTRAIT_MERCSKILL_OFFSET_ALL (NEWTRAIT_MERCSKILL_EXPERTOFFSET + NUM_MAJOR_TRAITS)
|
||||
|
||||
// Flugente: various skills that do not need a trait still need a number
|
||||
#define VARIOUSSKILLS (2 * NEWTRAIT_MERCSKILL_EXPERTOFFSET + 2)
|
||||
// Flugente: these aren't really traits, but it is convenient to pretend so
|
||||
#define INTEL (2 * NEWTRAIT_MERCSKILL_EXPERTOFFSET + 2)
|
||||
#define VARIOUSSKILLS (INTEL + 1)
|
||||
|
||||
// SANDRO - new set of character traits
|
||||
typedef enum
|
||||
|
||||
Reference in New Issue
Block a user