New feature: clothes items allow colouring of your mercs. See http://www.bears-pit.com/board/ubbthreads.php/topics/310208.html#Post310208 for more information.

This feature requires GameDir r1540 or greater to work.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5566 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2012-09-16 02:57:45 +00:00
parent 3d6bc97289
commit 829c3140ae
15 changed files with 525 additions and 272 deletions
+1 -1
View File
@@ -2146,7 +2146,7 @@ void LoadSkillTraitsExternalSettings()
// Flugente: COVERT OPS
gSkillTraitValues.sCOMeleeCTHBonus = iniReader.ReadInteger("Covert Ops","COVERT_MELEE_CTH_BONUS", 40, 0, 200);
gSkillTraitValues.sCoMeleeInstakillBonus = iniReader.ReadInteger("Covert Ops","COVERT_MELEE_INSTAKILL_BONUS", 35, 0, 200);
gSkillTraitValues.sCODisguiseAPReduction = iniReader.ReadInteger("Covert Ops","COVERT_DISGUISE_PERCENT_AP_REDUCTION", 20, 0, 100);
gSkillTraitValues.sCODisguiseAPReduction = iniReader.ReadInteger("Covert Ops","COVERT_DISGUISE_PERCENT_AP_REDUCTION", 20, 0, 50);
gSkillTraitValues.sCOCloseDetectionRange = iniReader.ReadInteger("Covert Ops","COVERT_CLOSE_DETECTION_RANGE", 10, 0, 100);
gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse = iniReader.ReadInteger("Covert Ops","COVERT_CLOSE_DETECTION_RANGE_SOLDIER_CORPSE", 5, 0, 100);
}
+4
View File
@@ -384,6 +384,10 @@ BOOLEAN LoadExternalGameplayData(STR directoryName)
strcat(fileName, FOODFILENAME);
SGP_THROW_IFFALSE(ReadInFoodStats(fileName),FOODFILENAME);
strcpy(fileName, directoryName);
strcat(fileName, CLOTHESFILENAME);
SGP_THROW_IFFALSE(ReadInClothesStats(fileName),CLOTHESFILENAME);
strcpy(fileName, directoryName);
strcat(fileName, ARMOURSFILENAME);
SGP_THROW_IFFALSE(ReadInArmourStats(fileName),ARMOURSFILENAME);
+15 -3
View File
@@ -131,10 +131,12 @@ INT8 gbTrapDifficulty;
BOOLEAN gfJustFoundBoobyTrap = FALSE;
void StartBombMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo );
void StartTacticalFunctionSelectionMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel ); // added by Flugente
void CleanWeapons( BOOLEAN fCleanAll );
void StartCorpseMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel ); // added by Flugente
// added by Flugente
void StartTacticalFunctionSelectionMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel );
void CleanWeapons( BOOLEAN fCleanAll );
void Strip( SOLDIERTYPE * pSoldier );
void StartCorpseMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel );
BOOLEAN HandleCheckForBadChangeToGetThrough( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT32 sTargetGridNo , INT8 bLevel )
{
@@ -4592,6 +4594,12 @@ void CleanWeapons( BOOLEAN fCleanAll )
}
}
// take off custom clothes
void Strip( SOLDIERTYPE * pSoldier )
{
pSoldier->Strip();
}
void BombMessageBoxCallBack( UINT8 ubExitValue )
{
if (gpTempSoldier)
@@ -4710,6 +4718,10 @@ void TacticalFunctionSelectionMessageBoxCallBack( UINT8 ubExitValue )
// clean all weapons
CleanWeapons(TRUE);
break;
case 4:
// take off custom clothes
Strip(gpTempSoldier);
break;
default:
break;
}
+1 -1
View File
@@ -3357,7 +3357,7 @@ void SMInvClickCamoCallback( MOUSE_REGION * pRegion, INT32 iReason )
// Say OK acknowledge....
gpSMCurrentMerc->DoMercBattleSound( BATTLE_SOUND_COOL1 );
}
else if ( ApplySpyKit( gpSMCurrentMerc, gpItemPointer ) )
else if ( ApplyClothes( gpSMCurrentMerc, gpItemPointer ) )
{
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
+5
View File
@@ -859,6 +859,8 @@ extern OBJECTTYPE gTempObject;
#define ITEM_DIRECTION_ANY 0x0000FF00
// ----------------------------------------------------------------
// replaces candamage
//#define ITEM_DAMAGEABLE 0x0001
//// replaces canrepair
@@ -1131,6 +1133,9 @@ typedef struct
// Flugente: a flag that is necessary for transforming action items to objects with new abilities (for now, tripwire networks and directional explosives)
UINT32 usActionItemFlag;
// Flugente: clothes type that 'links' to an entry in Clothes.xml
UINT32 clothestype;
} INVTYPE;
// CHRISL: Added new structures to handle LBE gear and the two new XML files that will be needed to deal
+171 -10
View File
@@ -9191,20 +9191,128 @@ BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAP
return( TRUE );
}
// Flugente: apply disguise
BOOLEAN ApplySpyKit( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj)
{
if (pObj->exists() == false || !HasItemFlag(pObj->usItem, (CLOTHES_CIVILIAN)) )
// Flugente: apply clothes, and eventually disguise
BOOLEAN ApplyClothes( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj)
{
// this will only work with the new trait system
if (!gGameOptions.fNewTraitSystem)
{
return( FALSE );
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_ERROR_OLDTRAITS] );
return FALSE;
}
// we get the civilian disguise. AP costs will be checked and deducted here
if ( !pSoldier->DisguiseAsCivilian() )
return FALSE;
if ( !pSoldier || pObj->exists() == false )
return( FALSE );
UseKitPoints( pObj, 100, pSoldier );
UINT8 skilllevel = NUM_SKILL_TRAITS( pSoldier, COVERT_NT );
INT16 apcost = (APBPConstants[AP_DISGUISE] * ( 100 - gSkillTraitValues.sCODisguiseAPReduction * skilllevel))/100;
if ( !EnoughPoints( pSoldier, apcost, 0, TRUE ) )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NOT_ENOUGH_APS] );
return( FALSE );
}
// determine clothes type
UINT32 clothestype = Item[pObj->usItem].clothestype;
// if not a clothes item, nothing to see here
if ( clothestype == 0 || clothestype > CLOTHES_MAX )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_UNIFORM_FOUND] );
return( FALSE);
}
UINT8 filler = 0;
// if it has a vest, wear it
bool newvest = FALSE;
if ( GetPaletteRepIndexFromID(Clothes[clothestype].vest, &filler) )
newvest = TRUE;
// if it has pants, wear them
bool newpants = FALSE;
if ( GetPaletteRepIndexFromID(Clothes[clothestype].pants, &filler) )
newpants = TRUE;
if ( newvest || newpants )
{
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{
if ( newvest )
{
// if we are already wearing a vest, give us back that item
if ( pSoldier->bSoldierFlagMask & SOLDIER_NEW_VEST )
{
UINT16 vestitem = 0;
if ( GetFirstClothesItemWithSpecificData(&vestitem, pSoldier->VestPal, "blank") )
{
CreateItem( vestitem, 100, &gTempObject );
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
}
SET_PALETTEREP_ID( pSoldier->VestPal, Clothes[clothestype].vest );
pSoldier->bSoldierFlagMask |= SOLDIER_NEW_VEST;
}
if ( newpants )
{
// if we are already wearing a vest, give us back that item
if ( pSoldier->bSoldierFlagMask & SOLDIER_NEW_PANTS )
{
UINT16 pantsitem = 0;
if ( GetFirstClothesItemWithSpecificData(&pantsitem, "blank", pSoldier->PantsPal) )
{
CreateItem( pantsitem, 100, &gTempObject );
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
}
SET_PALETTEREP_ID( pSoldier->PantsPal, Clothes[clothestype].pants );
pSoldier->bSoldierFlagMask |= SOLDIER_NEW_PANTS;
}
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
pSoldier->CreateSoldierPalettes();
UseKitPoints( pObj, 100, pSoldier );
DeductPoints( pSoldier, apcost, 0 );
}
if ( pSoldier->bSoldierFlagMask & SOLDIER_NEW_VEST && pSoldier->bSoldierFlagMask & SOLDIER_NEW_PANTS )
{
// first, remove the covert flags, adn then reapply the correct ones, in case we switch between civilina and military garb
pSoldier->bSoldierFlagMask &= ~(SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER);
// we now have to determine wether we are currently wearing civilian or military clothes
for ( int i = UNIFORM_ENEMY_ADMIN; i <= UNIFORM_ENEMY_ELITE; ++i )
{
if ( pSoldier->VestPal == gUniformColors[ i ].vest && pSoldier->PantsPal == gUniformColors[ i ].pants )
pSoldier->bSoldierFlagMask |= SOLDIER_COVERT_SOLDIER;
}
// if not dressed as a soldier, we must be dressed as a civilian
if ( !(pSoldier->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER) )
pSoldier->bSoldierFlagMask |= SOLDIER_COVERT_CIV;
}
}
return( TRUE );
}
@@ -14529,4 +14637,57 @@ FLOAT GetItemDirtIncreaseFactor( OBJECTTYPE * pObj, BOOLEAN fConsiderAmmo )
dirtincreasefactor = max(0.0f, dirtincreasefactor);
return dirtincreasefactor;
}
}
// Flugente: retrieve a specific clothes item, if such a thing exists
BOOLEAN GetFirstClothesItemWithSpecificData( UINT16* pusItem, PaletteRepID aPalVest, PaletteRepID aPalPants )
{
bool vestok = FALSE;
bool pantsok = FALSE;
UINT8 filler = 0;
if ( !GetPaletteRepIndexFromID(aPalVest, &filler) )
vestok = TRUE;
if ( !GetPaletteRepIndexFromID(aPalPants, &filler) )
pantsok = TRUE;
register UINT16 i;
for (i = 1; i < MAXITEMS; ++i)
{
if ( Item[i].clothestype > 0 )
{
bool tmpvestok = vestok;
bool tmppantsok = pantsok;
UINT8 vestpalid = 0;
GetPaletteRepIndexFromID(aPalVest, &vestpalid);
// if we are looking for vests, do so
if ( !tmpvestok )
{
if ( COMPARE_PALETTEREP_ID(aPalVest, Clothes[Item[i].clothestype].vest) )
{
tmpvestok = TRUE;
}
}
// if we are looking for pants, do so
if ( !tmppantsok )
{
if ( COMPARE_PALETTEREP_ID(aPalPants, Clothes[Item[i].clothestype].pants) )
{
tmppantsok = TRUE;
}
}
if ( tmpvestok && tmppantsok )
{
*pusItem = i;
return( TRUE );
}
}
}
return( FALSE );
}
+4 -1
View File
@@ -196,7 +196,7 @@ void WaterDamage( SOLDIERTYPE *pSoldier );
INT8 FindObj( SOLDIERTYPE * pSoldier, UINT16 usItem, INT8 bLower = 0, INT8 bUpper = NUM_INV_SLOTS );
BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs );
BOOLEAN ApplySpyKit( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj); // Flugente: apply disguise
BOOLEAN ApplyClothes( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj); // Flugente: apply clothes, and eventually disguise
UINT32 ConvertProfileMoneyValueToObjectTypeMoneyValue( UINT8 ubStatus );
UINT8 ConvertObjectTypeMoneyValueToProfileMoneyValue( UINT32 uiMoneyAmount );
@@ -498,6 +498,9 @@ UINT8 GetFirstPocketOnItem(UINT16 usIndex);
INT8 GetNumberAltFireAimLevels( SOLDIERTYPE * pSoldier, INT32 iGridNo );
// Flugente: retrieve a specific clothes item, if such a thing exists
BOOLEAN GetFirstClothesItemWithSpecificData( UINT16* pusItem, PaletteRepID aPalVest, PaletteRepID aPalPants );
#endif
+29 -64
View File
@@ -897,15 +897,7 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
memcpy( &(Corpse.name), &(pSoldier->name), sizeof(CHAR16) * 10 );
Corpse.name[9] = '\0';
#endif
// Flugente: mark if this was an army soldier ( we use this to steal his clothes later on )
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR )
Corpse.usFlags |= ROTTING_CORPSE_FROM_ADMIN;
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY )
Corpse.usFlags |= ROTTING_CORPSE_FROM_TROOP;
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE )
Corpse.usFlags |= ROTTING_CORPSE_FROM_ELITE;
// if this soldier's uniform was damaged (gunfire, blade attacks, explosions) then don't allow to take the uniform. We can't stay hidden if we're covered in blood :-)
if ( pSoldier->bSoldierFlagMask &SOLDIER_DAMAGED_UNIFORM )
Corpse.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
@@ -1962,15 +1954,11 @@ BOOLEAN IsValidStripCorpse( ROTTING_CORPSE *pCorpse )
if ( pCorpse->def.ubType == ROTTING_STAGE2 || (pCorpse->def.usFlags & ROTTING_CORPSE_CLOTHES_TAKEN) )
return( FALSE );
// is there a uniform we can take?
if ( !(pCorpse->def.usFlags & (ROTTING_CORPSE_FROM_ADMIN|ROTTING_CORPSE_FROM_TROOP|ROTTING_CORPSE_FROM_ELITE)) )
return( FALSE );
return( CorpseOkToDress(pCorpse, NULL) );
return( CorpseOkToDress(pCorpse) );
}
// Flugente: take the clothes off a corpse and wear them
// Flugente: take the clothes off a corpse
void StripCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
{
ROTTING_CORPSE *pCorpse = GetCorpseAtGridNo( sGridNo, bLevel );
@@ -1981,20 +1969,35 @@ void StripCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
// can this thing be stripped?
if ( IsValidStripCorpse( pCorpse ) )
{
// if this fits our body, try to wear it
if ( CorpseOkToDress(pCorpse, pSoldier) && pSoldier->DisguiseAsSoldierFromCorpse( pCorpse->def.usFlags ) )
// determine which clothes to spawn
UINT16 vestitem = 0;
if ( GetFirstClothesItemWithSpecificData(&vestitem, pCorpse->def.VestPal, "blank") )
{
// we took the clothes, mark this
pCorpse->def.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
CreateItem( vestitem, 100, &gTempObject );
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCorpseTextStr[STR_CORPSE_NO_STRIPPING_POSSIBLE], pSoldier->name );
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
UINT16 pantsitem = 0;
if ( GetFirstClothesItemWithSpecificData(&pantsitem, "blank", pCorpse->def.PantsPal) )
{
CreateItem( pantsitem, 100, &gTempObject );
if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) )
AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
// we took the clothes, mark this
pCorpse->def.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCorpseTextStr[STR_CORPSE_NO_CLOTHESFOUND] );
}
// Flugente: can clothes be taken off of this corpse?
// Flugente: can this corpse be carried?
BOOLEAN IsValidTakeCorpse( ROTTING_CORPSE *pCorpse )
{
if ( pCorpse->def.ubType >= BLOODCAT_DEAD || pCorpse->def.ubType == NO_CORPSE )
@@ -2271,10 +2274,7 @@ BOOLEAN AddCorpseFromObject(OBJECTTYPE* pObj, INT32 sGridNo, INT8 bLevel )
SET_PALETTEREP_ID( Corpse.PantsPal, "BLUEPANTS" );
else
SET_PALETTEREP_ID( Corpse.PantsPal, "BEIGEPANTS" );
//SET_PALETTEREP_ID( Corpse.VestPal, gUniformColors[ UNIFORM_ENEMY_TROOP ].vest );
//SET_PALETTEREP_ID( Corpse.PantsPal, gUniformColors[ UNIFORM_ENEMY_TROOP ].pants );
Corpse.ubDirection = NORTH;
Corpse.uiTimeOfDeath = GetWorldTotalMin();
@@ -2299,15 +2299,7 @@ BOOLEAN AddCorpseFromObject(OBJECTTYPE* pObj, INT32 sGridNo, INT8 bLevel )
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_STRIPPED )
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
// TODO: change this so it always fits, not dependant these colours
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_YELLOW && (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_GREEN )
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_FROM_ADMIN;
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_RED && (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_GREEN )
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_FROM_TROOP;
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_BLACK && (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_BLACK )
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_FROM_ELITE;
#ifdef ENABLE_ZOMBIES
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_NO_ZOMBIE_RISE )
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_NEVER_RISE_AGAIN;
@@ -2984,7 +2976,7 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo )
// Flugente: can we take the clothes of this corpse?
// calling this with NULL for soldier will give a general answer for any bodytype
BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier )
BOOLEAN CorpseOkToDress( ROTTING_CORPSE* pCorpse )
{
if ( !pCorpse )
return FALSE;
@@ -3007,16 +2999,6 @@ BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier )
case S_DEAD2:
case C_DEAD1:
case C_DEAD2:
if ( pSoldier )
{
if ( pSoldier->ubBodyType == REGMALE )
return TRUE;
}
else
return TRUE;
break;
case MMERC_JFK:
case MMERC_BCK:
case MMERC_FWD:
@@ -3026,17 +3008,7 @@ BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier )
case MMERC_FALL:
case MMERC_FALLF:
case FT_DEAD1:
case FT_DEAD2:
if ( pSoldier )
{
if ( pSoldier->ubBodyType == BIGMALE || pSoldier->ubBodyType == STOCKYMALE )
return TRUE;
}
else
return TRUE;
break;
case FT_DEAD2:
case FMERC_JFK:
case FMERC_BCK:
case FMERC_FWD:
@@ -3047,14 +3019,7 @@ BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier )
case FMERC_FALLF:
case W_DEAD1:
case W_DEAD2:
if ( pSoldier )
{
if ( pSoldier->ubBodyType == REGFEMALE )
return TRUE;
}
else
return TRUE;
return TRUE;
break;
default:
+1 -4
View File
@@ -94,9 +94,6 @@ enum RottingCorpseDefines
#define ROTTING_CORPSE_GUTTED 0x00002000 // corpse has been gutted
#define ROTTING_CORPSE_CLOTHES_TAKEN 0x00004000 // corpse is without clothes (atm not visually)
#define ROTTING_CORPSE_FROM_ADMIN 0x00010000 // corpse is from a admin (used to take his clothes)
#define ROTTING_CORPSE_FROM_TROOP 0x00020000 // corpse is from a regular soldier (used to take his clothes)
#define ROTTING_CORPSE_FROM_ELITE 0x00040000 // corpse is from a elite soldier (used to take his clothes)
typedef struct
{
UINT8 ubType;
@@ -236,6 +233,6 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo );
#endif
// Flugente: can we take the clothes of this corpse?
BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier );
BOOLEAN CorpseOkToDress( ROTTING_CORPSE* pCorpse );
#endif
+31 -175
View File
@@ -15068,7 +15068,38 @@ BOOLEAN SOLDIERTYPE::RecognizeAsCombatant(UINT8 ubTargetID)
// dress up in our natural state
void SOLDIERTYPE::LooseDisguise( void )
{
// loose any covert flags
this->bSoldierFlagMask &= ~(SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER);
}
// take off any clothes item and switch back to original clothes
// no - this function does not want you think it does. Leave Fox alone, you perv.
void SOLDIERTYPE::Strip()
{
// loose any covert and clothes flags
this->bSoldierFlagMask &= ~(SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER|SOLDIER_NEW_VEST|SOLDIER_NEW_PANTS);
UINT16 vestitem = 0;
if ( GetFirstClothesItemWithSpecificData(&vestitem, this->VestPal, "blank") )
{
CreateItem( vestitem, 100, &gTempObject );
if ( !AutoPlaceObject( this, &gTempObject, FALSE ) )
AddItemToPool( this->sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
UINT16 pantsitem = 0;
if ( GetFirstClothesItemWithSpecificData(&pantsitem, "blank", this->PantsPal) )
{
CreateItem( pantsitem, 100, &gTempObject );
if ( !AutoPlaceObject( this, &gTempObject, FALSE ) )
AddItemToPool( this->sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
// show our true colours
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( this, this->usAnimState );
@@ -15093,183 +15124,8 @@ void SOLDIERTYPE::LooseDisguise( void )
this->CreateSoldierPalettes();
}
// loose any covert flags
// if we are disguised as a civilian, remove that flag, and give us back a civilian clothes item
if ( this->bSoldierFlagMask & SOLDIER_COVERT_CIV )
{
this->bSoldierFlagMask &= ~SOLDIER_COVERT_CIV;
UINT16 civilianclothesitem = 0;
if ( GetFirstItemWithFlag(&civilianclothesitem, CLOTHES_CIVILIAN) )
{
CreateItem( civilianclothesitem, 100, &gTempObject );
if ( !AutoPlaceObject( this, &gTempObject, FALSE ) )
AddItemToPool( sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
}
// if we are also disguised as a soldier, remove that flag
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
{
this->bSoldierFlagMask &= ~SOLDIER_COVERT_SOLDIER;
}
}
// dress up like a civilian
BOOLEAN SOLDIERTYPE::DisguiseAsCivilian( void )
{
// this will only work with the new trait system
if (!gGameOptions.fNewTraitSystem)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_ERROR_OLDTRAITS] );
return FALSE;
}
UINT8 skilllevel = NUM_SKILL_TRAITS( this, COVERT_NT );
INT16 apcost = (APBPConstants[AP_DISGUISE] * ( gSkillTraitValues.sCODisguiseAPReduction * skilllevel))/100;
if ( !EnoughPoints( this, apcost, 0, TRUE ) )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NOT_ENOUGH_APS] );
return( FALSE );
}
this->bSoldierFlagMask |= SOLDIER_COVERT_CIV;
// wear an enemy uniform
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( this, this->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{
// wear something random
switch( Random( 7 ) )
{
case 0: SET_PALETTEREP_ID( this->VestPal, "WHITEVEST" ); break;
case 1: SET_PALETTEREP_ID( this->VestPal, "BLACKSHIRT" ); break;
case 2: SET_PALETTEREP_ID( this->VestPal, "PURPLESHIRT" ); break;
case 3: SET_PALETTEREP_ID( this->VestPal, "BLUEVEST" ); break;
case 4: SET_PALETTEREP_ID( this->VestPal, "BROWNVEST" ); break;
case 5: SET_PALETTEREP_ID( this->VestPal, "JEANVEST" ); break;
case 6: SET_PALETTEREP_ID( this->VestPal, "REDVEST" ); break;
}
switch( Random( 3 ) )
{
case 0: SET_PALETTEREP_ID( this->PantsPal, "TANPANTS" ); break;
case 1: SET_PALETTEREP_ID( this->PantsPal, "BEIGEPANTS" ); break;
case 2: SET_PALETTEREP_ID( this->PantsPal, "GREENPANTS" ); break;
}
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( this->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( this->p8BPPPalette ) * 256 );
SetPaletteReplacement( this->p8BPPPalette, this->HeadPal );
SetPaletteReplacement( this->p8BPPPalette, this->VestPal );
SetPaletteReplacement( this->p8BPPPalette, this->PantsPal );
SetPaletteReplacement( this->p8BPPPalette, this->SkinPal );
this->CreateSoldierPalettes();
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_BAD_PALETTE] );
// if we are also disguised as a soldier, remove that flag
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
{
this->bSoldierFlagMask &= ~SOLDIER_COVERT_SOLDIER;
}
DeductPoints( this, apcost, 0 );
return TRUE;
}
// dress up like an enemy soldier
BOOLEAN SOLDIERTYPE::DisguiseAsSoldierFromCorpse( UINT32 usFlag )
{
// this will only work with the new trait system
if (!gGameOptions.fNewTraitSystem)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_ERROR_OLDTRAITS] );
return FALSE;
}
// action is only possible if we have the covert ops trait
UINT8 skilllevel = NUM_SKILL_TRAITS( this, COVERT_NT );
if ( skilllevel < 1)
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_SKILL] );
return FALSE;
}
INT16 apcost = (APBPConstants[AP_DISGUISE] * ( gSkillTraitValues.sCODisguiseAPReduction * skilllevel))/100;
if ( !EnoughPoints( this, apcost, 0, TRUE ) )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NOT_ENOUGH_APS] );
return( FALSE );
}
UINT8 uniformtype = 0;
if ( usFlag & ROTTING_CORPSE_FROM_ADMIN )
uniformtype = UNIFORM_ENEMY_ADMIN;
else if ( usFlag & ROTTING_CORPSE_FROM_TROOP )
uniformtype = UNIFORM_ENEMY_TROOP;
else if ( usFlag & ROTTING_CORPSE_FROM_ELITE )
uniformtype = UNIFORM_ENEMY_ELITE;
else
{
// no uniform here, so nothing to wear
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_UNIFORM_FOUND] );
return FALSE;
}
this->bSoldierFlagMask |= SOLDIER_COVERT_SOLDIER;
// wear an enemy uniform
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( this, this->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{
SET_PALETTEREP_ID(this->VestPal, gUniformColors[ uniformtype ].vest );
SET_PALETTEREP_ID(this->PantsPal, gUniformColors[ uniformtype ].pants );
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( this->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( this->p8BPPPalette ) * 256 );
SetPaletteReplacement( this->p8BPPPalette, this->HeadPal );
SetPaletteReplacement( this->p8BPPPalette, this->VestPal );
SetPaletteReplacement( this->p8BPPPalette, this->PantsPal );
SetPaletteReplacement( this->p8BPPPalette, this->SkinPal );
this->CreateSoldierPalettes();
}
// if we are disguised as a civilian, remove that flag, and give us back a civilian clothes item
if ( this->bSoldierFlagMask & SOLDIER_COVERT_CIV )
{
this->bSoldierFlagMask &= ~SOLDIER_COVERT_CIV;
UINT16 civilianclothesitem = 0;
if ( GetFirstItemWithFlag(&civilianclothesitem, CLOTHES_CIVILIAN) )
{
CreateItem( civilianclothesitem, 100, &gTempObject );
AddItemToPool( sGridNo, &gTempObject, 1, 0, 0, -1 );
}
else
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_NO_CLOTHES_ITEM] );
}
DeductPoints( this, apcost, 0 );
return TRUE;
}
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
{
INT8 bBandaged; //,savedOurTurn;
+20 -10
View File
@@ -349,11 +349,11 @@ enum
#define SOLDIER_COVERT_SOLDIER 0x00000008 //8 // Soldier is currently disguised as an enemy soldier
#define SOLDIER_DAMAGED_UNIFORM 0x00000010 //16 // Soldier's uniform is damged (and thus can't be taken off of his corpse)
#define SOLDIER_COVERT_NPC_SPECIAL 0x00000020 //32 // Special flag for NPCs wehn recruited (used for covert stuff)
/*#define WH40K_JUMPPACK 0x00000040 //64
#define WH40K_DISPLACER 0x00000080 //128
#define SOLDIER_COVERT_NPC_SPECIAL 0x00000020 //32 // Special flag for NPCs when recruited (used for covert stuff)
#define SOLDIER_NEW_VEST 0x00000040 //64 // Soldier is wearing new vest. if having both vest and pants, he can disguise
#define SOLDIER_NEW_PANTS 0x00000080 //128 // Soldier is wearing new pants
#define WH40K_ROSARIUS 0x00000100 //256
/*#define WH40K_ROSARIUS 0x00000100 //256
#define WH40K_SEAL 0x00000200 //512
#define WH40K_POWER_WEAPON 0x00000400 //1024
#define ENEMY_NET_4_LVL_3 0x00000800 //2048
@@ -394,6 +394,19 @@ typedef struct
// HEADROCK HAM 3.6: Uniform colors for the different soldier classes
extern UNIFORMCOLORS gUniformColors[NUM_UNIFORMS];
// Flugente: a structure for clothing items
typedef struct
{
UINT16 uiIndex;
CHAR16 szName[80]; // name of these clothes
PaletteRepID vest;
PaletteRepID pants;
} CLOTHES_STRUCT;
#define CLOTHES_MAX 50
extern CLOTHES_STRUCT Clothes[CLOTHES_MAX];
// This macro should be used whenever we want to see if someone is neutral
// IF WE ARE CONSIDERING ATTACKING THEM. Creatures & bloodcats will attack neutrals
// but they can't attack empty vehicles!!
@@ -1476,13 +1489,10 @@ public:
BOOLEAN RecognizeAsCombatant(UINT8 ubTargetID);
// loose disguise, dress up in our natural state
void LooseDisguise( void );
void LooseDisguise( void );
// dress up like a civilian
BOOLEAN DisguiseAsCivilian( void );
// dress up like an enemy soldier
BOOLEAN DisguiseAsSoldierFromCorpse( UINT32 usFlag );
// take off any clothes item and switch back to original clothes
void Strip();
//////////////////////////////////////////////////////////////////////////////
}; // SOLDIERTYPE;
+5
View File
@@ -67,6 +67,7 @@ typedef PARSE_STAGE;
#define EXPLOSIVESFILENAME "Explosives.xml"
#define DRUGSFILENAME "Drugs.xml"
#define FOODFILENAME "Food.xml"
#define CLOTHESFILENAME "Clothes.xml"
#define AMMOFILENAME "AmmoStrings.xml"
#define AMMOTYPESFILENAME "AmmoTypes.xml"
#define INCOMPATIBLEATTACHMENTSFILENAME "IncompatibleAttachments.xml"
@@ -306,6 +307,10 @@ extern BOOLEAN WriteDrugsStats();
extern BOOLEAN ReadInFoodStats(STR fileName);
extern BOOLEAN WriteFoodStats();
// Flugente: clothes
extern BOOLEAN ReadInClothesStats(STR fileName);
extern BOOLEAN WriteClothesStats();
extern BOOLEAN ReadInAmmoStats(STR fileName);
extern BOOLEAN WriteAmmoStats();
+228
View File
@@ -0,0 +1,228 @@
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "overhead.h"
#include "Debug Control.h"
#include "expat.h"
#include "XML.h"
#endif
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
CLOTHES_STRUCT curClothes;
CLOTHES_STRUCT* curArray;
UINT32 maxArraySize;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef clothesParseData;
// Array to hold clothes data
CLOTHES_STRUCT Clothes[CLOTHES_MAX];
static void XMLCALL
clothesStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
clothesParseData * pData = (clothesParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "CLOTHESLIST") == 0 && pData->curElement == ELEMENT_NONE)
{
pData->curElement = ELEMENT_LIST;
memset(pData->curArray,0,sizeof(CLOTHES_STRUCT)*pData->maxArraySize);
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "CLOTHES") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
memset(&pData->curClothes,0,sizeof(CLOTHES_STRUCT));
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "uiIndex") == 0 ||
strcmp(name, "szName") == 0 ||
strcmp(name, "Vest") == 0 ||
strcmp(name, "Pants") == 0 ))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
clothesCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
clothesParseData * pData = (clothesParseData *)userData;
if( (pData->currentDepth <= pData->maxReadDepth) &&
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
){
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
}
static void XMLCALL
clothesEndElementHandle(void *userData, const XML_Char *name)
{
clothesParseData * pData = (clothesParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "CLOTHESLIST") == 0)
{
pData->curElement = ELEMENT_NONE;
}
else if(strcmp(name, "CLOTHES") == 0)
{
pData->curElement = ELEMENT_LIST;
// we do NOT want to read the first entry -> move stuff by 1
if(pData->curClothes.uiIndex < pData->maxArraySize)
{
pData->curArray[pData->curClothes.uiIndex] = pData->curClothes; //write the clothes into the table
}
}
else if(strcmp(name, "uiIndex") == 0)
{
pData->curElement = ELEMENT;
pData->curClothes.uiIndex = (UINT16) atol(pData->szCharData);
}
else if(strcmp(name, "szName") == 0)
{
pData->curElement = ELEMENT;
// not needed, but it's there for informational purposes
}
else if(strcmp(name, "Vest") == 0 )
{
pData->curElement = ELEMENT;
strcpy(pData->curClothes.vest, pData->szCharData);
}
else if(strcmp(name, "Pants") == 0 )
{
pData->curElement = ELEMENT;
strcpy(pData->curClothes.pants, pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInClothesStats(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
clothesParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading Clothes.xml" );
// Open clothess file
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, clothesStartElementHandle, clothesEndElementHandle);
XML_SetCharacterDataHandler(parser, clothesCharacterDataHandle);
memset(&pData,0,sizeof(pData));
pData.curArray = Clothes;
pData.maxArraySize = CLOTHES_MAX;
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in Clothes.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return( TRUE );
}
BOOLEAN WriteClothesStats()
{
//DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"writeclothessstats");
HWFILE hFile;
//Debug code; make sure that what we got from the file is the same as what's there
// Open a new file
hFile = FileOpen( "TABLEDATA\\Clothes out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE );
if ( !hFile )
return( FALSE );
{
UINT32 cnt;
FilePrintf(hFile,"<CLOTHESLIST>\r\n");
for(cnt = 0; cnt < MAXITEMS; ++cnt)
{
FilePrintf(hFile,"\t<CLOTHES>\r\n");
FilePrintf(hFile,"\t\t<uiIndex>%d</uiIndex>\r\n", cnt );
FilePrintf(hFile,"\t\t<vest>%d</vest>\r\n", Clothes[cnt].vest );
FilePrintf(hFile,"\t\t<pants>%d</pants>\r\n", Clothes[cnt].pants );
FilePrintf(hFile,"\t</CLOTHES>\r\n");
}
FilePrintf(hFile,"</CLOTHESLIST>\r\n");
}
FileClose( hFile );
return( TRUE );
}
+9 -2
View File
@@ -277,7 +277,8 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at
strcmp(name, "CrowbarModifier") == 0 ||
strcmp(name, "DisarmModifier") == 0 ||
strcmp(name, "RepairModifier") == 0 ||
strcmp(name, "usActionItemFlag") == 0 ))
strcmp(name, "usActionItemFlag") == 0 ||
strcmp(name, "clothestype") == 0 ))
{
pData->curElement = ELEMENT_PROPERTY;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("itemStartElementHandle: going into element, name = %s",name) );
@@ -1393,6 +1394,11 @@ itemEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = ELEMENT;
pData->curItem.usActionItemFlag = (UINT32) atol(pData->szCharData);
}
else if(strcmp(name, "clothestype") == 0)
{
pData->curElement = ELEMENT;
pData->curItem.clothestype = (UINT32) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
@@ -2021,12 +2027,13 @@ BOOLEAN WriteItemStats()
FilePrintf(hFile, "\t\t<RepairModifier>%d</RepairModifier>\r\n", Item[cnt].RepairModifier );
// Flugente poison system
FilePrintf(hFile,"\t\t<PoisonPercentage>%d</PoisonPercentage>\r\n", Item[cnt].bPoisonPercentage );
FilePrintf(hFile,"\t\t<PoisonPercentage>%d</PoisonPercentage>\r\n", Item[cnt].bPoisonPercentage );
FilePrintf(hFile,"\t\t<DamageChance>%d</DamageChance>\r\n", Item[cnt].usDamageChance );
FilePrintf(hFile,"\t\t<DirtIncreaseFactor>%4.2f</DirtIncreaseFactor>\r\n", Item[cnt].dirtIncreaseFactor );
FilePrintf(hFile,"\t\t<usActionItemFlag>%d</usActionItemFlag>\r\n", Item[cnt].usActionItemFlag );
FilePrintf(hFile,"\t\t<clothestype>%d</clothestype>\r\n", Item[cnt].clothestype );
FilePrintf(hFile,"\t</ITEM>\r\n");
}
+1 -1
View File
@@ -2900,7 +2900,7 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] =
L"Health: %d/%d\nPoison: %d/%d\nEnergy: %d/%d\nMorale: %s\nWater: %d%s\nFood: %d%s",
// added by Flugente: selection of a function to call in tactical
L"1 - Fill Canteens 2 - Clean one gun 3 - Clean all guns 4 - Nothing",
L"1 - Fill Canteens 2 - Clean one gun 3 - Clean all guns 4 - Take off clothes",
// added by Flugente: decide what to do with the corpses
L"1 - Decapitate 2 - Gut 3 - Take Clothes 4 - Take Body",