From 3651ef29e73ff818c90ff787561a40ecfcd72d10 Mon Sep 17 00:00:00 2001 From: MaddMugsy Date: Wed, 6 Jun 2012 18:20:03 +0000 Subject: [PATCH] Guns attaching to tripwire feature has been moved from an xml-enabled feature to a hardcoded feature. This is because there are so many guns in the game (esp. in various mods) that the required xml changes are huge. Not to mention things like this -- http://i50.tinypic.com/zjxoat.jpg ATTACHING_DETONATOR skill check is used and the usual gun attachment sound is played instead of the detonator beep. Additionally, this resolves the issue with being able to attach lasers, etc to tripwire. Instead, guns retain their attachments, as would be expected. Transformations on attached guns have also been disabled. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5332 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Tactical/Interface Items.cpp | 262 ++++++++++++++++++----------------- Tactical/Items.cpp | 127 ++++++++++++----- 2 files changed, 228 insertions(+), 161 deletions(-) diff --git a/Tactical/Interface Items.cpp b/Tactical/Interface Items.cpp index e7a3eba0d..a10e4d4ee 100644 --- a/Tactical/Interface Items.cpp +++ b/Tactical/Interface Items.cpp @@ -12111,158 +12111,162 @@ void ItemDescTransformRegionCallback( MOUSE_REGION *pRegion, INT32 reason ) } */ - // Ammocrates may be split into magazines of any size available in the game. But not in combat. - if ( Item[gpItemDescObject->usItem].usItemClass == IC_AMMO && Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubMagType >= AMMO_BOX && !(gTacticalStatus.uiFlags & INCOMBAT) ) + //Madd: override - if this item is a gun attached to something then forget about it -- attachments of attachments and any loaded ammo get lost otherwise + if ((gpItemDescPrevObject == NULL && Item[gpItemDescObject->usItem].usItemClass & IC_GUN) || !(Item[gpItemDescObject->usItem].usItemClass & IC_GUN) ) { - BOOLEAN fCrateInPool = FALSE; - - // Before we continue, lets check whether our object is in the sector inventory. - // Is the sector inventory open? - if (fShowMapInventoryPool) + // Ammocrates may be split into magazines of any size available in the game. But not in combat. + if ( Item[gpItemDescObject->usItem].usItemClass == IC_AMMO && Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubMagType >= AMMO_BOX && !(gTacticalStatus.uiFlags & INCOMBAT) ) { - // Is our object currently in the pool? - for (UINT32 x = 0; x < pInventoryPoolList.size(); x++) + BOOLEAN fCrateInPool = FALSE; + + // Before we continue, lets check whether our object is in the sector inventory. + // Is the sector inventory open? + if (fShowMapInventoryPool) { - if (pInventoryPoolList[x].object.exists()) + // Is our object currently in the pool? + for (UINT32 x = 0; x < pInventoryPoolList.size(); x++) { - if (&(pInventoryPoolList[x].object) == gpItemDescObject) + if (pInventoryPoolList[x].object.exists()) { - // Aha! In that case, all transformations will be done directly at the sector pool, - // with multiple results ending on the ground rather than in the inventory. - fCrateInPool = TRUE; - break; + if (&(pInventoryPoolList[x].object) == gpItemDescObject) + { + // Aha! In that case, all transformations will be done directly at the sector pool, + // with multiple results ending on the ground rather than in the inventory. + fCrateInPool = TRUE; + break; + } } } } - } - if (fCrateInPool) - { - for (UINT16 x = 0; x < MAXITEMS; x++) + if (fCrateInPool) { - if ( Item[x].usItemClass & IC_AMMO ) + for (UINT16 x = 0; x < MAXITEMS; x++) { - // If this magazine has the same caliber and ammotype as the crate, has a smaller size, and is - // not an ammo crate itself... - if ( Magazine[Item[x].ubClassIndex].ubCalibre == Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubCalibre && - Magazine[Item[x].ubClassIndex].ubAmmoType == Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubAmmoType && - Magazine[Item[x].ubClassIndex].ubMagSize <= Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubMagSize && - Magazine[Item[x].ubClassIndex].ubMagType < AMMO_BOX ) + if ( Item[x].usItemClass & IC_AMMO ) { - UINT16 usMagSize = Magazine[Item[x].ubClassIndex].ubMagSize; + // If this magazine has the same caliber and ammotype as the crate, has a smaller size, and is + // not an ammo crate itself... + if ( Magazine[Item[x].ubClassIndex].ubCalibre == Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubCalibre && + Magazine[Item[x].ubClassIndex].ubAmmoType == Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubAmmoType && + Magazine[Item[x].ubClassIndex].ubMagSize <= Magazine[Item[gpItemDescObject->usItem].ubClassIndex].ubMagSize && + Magazine[Item[x].ubClassIndex].ubMagType < AMMO_BOX ) + { + UINT16 usMagSize = Magazine[Item[x].ubClassIndex].ubMagSize; - CHAR16 MenuRowText[300]; - swprintf( MenuRowText, gzTransformationMessage[ 7 ], usMagSize ); - // Generate a new option for the menu - POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction( TransformationMenuPopup_SplitCrate, x ) ); - // Add the option to the menu. - gItemDescTransformPopup->addOption( *pOption ); - // Set this flag so we know we have at least one Transformation available. - fFoundTransformations = true; + CHAR16 MenuRowText[300]; + swprintf( MenuRowText, gzTransformationMessage[ 7 ], usMagSize ); + // Generate a new option for the menu + POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction( TransformationMenuPopup_SplitCrate, x ) ); + // Add the option to the menu. + gItemDescTransformPopup->addOption( *pOption ); + // Set this flag so we know we have at least one Transformation available. + fFoundTransformations = true; + } } } } - } - else - { - POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( gzTransformationMessage[ 6 ] ), new popupCallbackFunction( TransformationMenuPopup_SplitCrateInInventory ) ); - gItemDescTransformPopup->addOption( *pOption ); - fFoundTransformations = true; - } - } - - // Scan the Transformation list for the current item. Create pop-up options as required. - INT32 iTransformIndex = -1; - - // Flugente: we can also arm/disarm bombs in our inventory via this menu - BOOLEAN fHaveToDisarm = FALSE; // important check: if item is an armed bomb, we have to disarm it prior to any transformation - if ( ( (guiCurrentScreen == GAME_SCREEN) || (guiCurrentScreen == MAP_SCREEN) ) && Item[gpItemDescObject->usItem].usItemClass == IC_BOMB && gpItemDescObject->ubNumberOfObjects == 1 && HasAttachmentOfClass( gpItemDescObject, (AC_DETONATOR | AC_REMOTEDET) ) ) - { - iTransformIndex++; - - UINT16 apcost = 20; - - if ( (guiCurrentScreen == GAME_SCREEN) || (guiCurrentScreen == MAP_SCREEN) ) - apcost = 15; - - // test wether item is already armed - INT8 detonatortype; - INT8 setting; - INT8 defusefrequency; - CheckBombSpecifics( gpItemDescObject, &detonatortype, &setting, &defusefrequency ); - - CHAR16 MenuRowText[300]; - - if ( detonatortype == BOMB_TIMED || detonatortype == BOMB_REMOTE ) - { - fHaveToDisarm = TRUE; - - if ( apcost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED ) - { - swprintf (MenuRowText, L"Disarm (%d AP)", apcost ); - } else { - swprintf (MenuRowText, L"Disarm"); - } - } - else - { - if ( apcost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED ) - { - swprintf (MenuRowText, L"Arm (%d AP)", apcost ); - } - else - { - swprintf (MenuRowText, L"Arm"); - } - } - - // Generate a new option for the menu - POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction( &TransformationMenuPopup_Arm, gpItemDescObject ) ); - // Set the function that tests whether it's valid at the moment. - pOption->setAvail(new popupCallbackFunction( &TransformationMenuPopup_Arm_TestValid, gpItemDescObject )); - // Add the option to the menu. - gItemDescTransformPopup->addOption( *pOption ); - // Set this flag so we know we have at least one Transformation available. - fFoundTransformations = true; - } - - // onyl allow transformations if the item is not an armed bomb - if ( !fHaveToDisarm ) - { - for (INT32 x = 0; x < MAXITEMS; x++) - { - if (Transform[x].usItem == -1) - { - break; - } - if (Transform[x].usItem == gpItemDescObject->usItem) - { - iTransformIndex++; - - CHAR16 MenuRowText[300]; - if ( Transform[x].usAPCost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED ) - { - swprintf (MenuRowText, L"%s (%d AP)", Transform[x].szMenuRowText, Transform[x].usAPCost ); - } - else - { - swprintf (MenuRowText, Transform[x].szMenuRowText); - } - - // Generate a new option for the menu - POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction( &TransformationMenuPopup_Transform, &Transform[x] ) ); - // Set the function that tests whether it's valid at the moment. - pOption->setAvail(new popupCallbackFunction( &TransformationMenuPopup_TestValid, &Transform[x] )); - // Add the option to the menu. + POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( gzTransformationMessage[ 6 ] ), new popupCallbackFunction( TransformationMenuPopup_SplitCrateInInventory ) ); gItemDescTransformPopup->addOption( *pOption ); - // Set this flag so we know we have at least one Transformation available. fFoundTransformations = true; } } - } + + // Scan the Transformation list for the current item. Create pop-up options as required. + INT32 iTransformIndex = -1; + + // Flugente: we can also arm/disarm bombs in our inventory via this menu + BOOLEAN fHaveToDisarm = FALSE; // important check: if item is an armed bomb, we have to disarm it prior to any transformation + if ( ( (guiCurrentScreen == GAME_SCREEN) || (guiCurrentScreen == MAP_SCREEN) ) && Item[gpItemDescObject->usItem].usItemClass == IC_BOMB && gpItemDescObject->ubNumberOfObjects == 1 && HasAttachmentOfClass( gpItemDescObject, (AC_DETONATOR | AC_REMOTEDET) ) ) + { + iTransformIndex++; + + UINT16 apcost = 20; + + if ( (guiCurrentScreen == GAME_SCREEN) || (guiCurrentScreen == MAP_SCREEN) ) + apcost = 15; + + // test wether item is already armed + INT8 detonatortype; + INT8 setting; + INT8 defusefrequency; + CheckBombSpecifics( gpItemDescObject, &detonatortype, &setting, &defusefrequency ); + + CHAR16 MenuRowText[300]; + + if ( detonatortype == BOMB_TIMED || detonatortype == BOMB_REMOTE ) + { + fHaveToDisarm = TRUE; + + if ( apcost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED ) + { + swprintf (MenuRowText, L"Disarm (%d AP)", apcost ); + } + else + { + swprintf (MenuRowText, L"Disarm"); + } + } + else + { + if ( apcost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED ) + { + swprintf (MenuRowText, L"Arm (%d AP)", apcost ); + } + else + { + swprintf (MenuRowText, L"Arm"); + } + } + + // Generate a new option for the menu + POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction( &TransformationMenuPopup_Arm, gpItemDescObject ) ); + // Set the function that tests whether it's valid at the moment. + pOption->setAvail(new popupCallbackFunction( &TransformationMenuPopup_Arm_TestValid, gpItemDescObject )); + // Add the option to the menu. + gItemDescTransformPopup->addOption( *pOption ); + // Set this flag so we know we have at least one Transformation available. + fFoundTransformations = true; + } + // onyl allow transformations if the item is not an armed bomb + if ( !fHaveToDisarm ) + { + for (INT32 x = 0; x < MAXITEMS; x++) + { + if (Transform[x].usItem == -1) + { + break; + } + if (Transform[x].usItem == gpItemDescObject->usItem) + { + iTransformIndex++; + + CHAR16 MenuRowText[300]; + if ( Transform[x].usAPCost > 0 && gTacticalStatus.uiFlags & INCOMBAT && gTacticalStatus.uiFlags & TURNBASED ) + { + swprintf (MenuRowText, L"%s (%d AP)", Transform[x].szMenuRowText, Transform[x].usAPCost ); + } + else + { + swprintf (MenuRowText, Transform[x].szMenuRowText); + } + + // Generate a new option for the menu + POPUP_OPTION *pOption = new POPUP_OPTION(&std::wstring( MenuRowText ), new popupCallbackFunction( &TransformationMenuPopup_Transform, &Transform[x] ) ); + // Set the function that tests whether it's valid at the moment. + pOption->setAvail(new popupCallbackFunction( &TransformationMenuPopup_TestValid, &Transform[x] )); + // Add the option to the menu. + gItemDescTransformPopup->addOption( *pOption ); + // Set this flag so we know we have at least one Transformation available. + fFoundTransformations = true; + } + } + } + } + if (!fFoundTransformations) { POPUP_OPTION * pOption = new POPUP_OPTION( &std::wstring( gzTransformationMessage[ 0 ] ), new popupCallbackFunction( &TransformationMenuPopup_Transform, NULL ) ); diff --git a/Tactical/Items.cpp b/Tactical/Items.cpp index 40513551b..471fe1e20 100644 --- a/Tactical/Items.cpp +++ b/Tactical/Items.cpp @@ -2107,6 +2107,10 @@ BOOLEAN ValidAttachment( UINT16 usAttachment, UINT16 usItem, UINT8 * pubAPCost ) *pubAPCost = (UINT8)APBPConstants[AP_RELOAD_GUN]; //default value } + //Madd: all guns can be attached to tripwires + if ( Item[usItem].tripwire && Item[usAttachment].usItemClass & IC_GUN ) + return TRUE; + //Madd: Common Attachment Framework if ( IsAttachmentPointAvailable(usItem, usAttachment)) { @@ -2257,20 +2261,30 @@ BOOLEAN ValidItemAttachmentSlot( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN return FALSE; //Search for incompatible attachments - for(int i = 0;iusItem].tripwire && Item[usAttachment].usItemClass & IC_GUN && FindAttachmentByClass(pObj,IC_GUN,subObject) != 0 ) { - if ( FindAttachment(pObj, usAttachment, subObject) != 0 && !IsAttachmentClass(usAttachment, AC_GRENADE|AC_ROCKET ) ) - {//Search for identical attachments unless we're dealing with rifle grenades - fSameItem = TRUE; - break; - } - if ( IncompatibleAttachments[i][0] == NONE ) - break; - if ( IncompatibleAttachments[i][0] == usAttachment && FindAttachment (pObj,IncompatibleAttachments[i][1],subObject) != 0 ) + fSimilarItems = TRUE; + OBJECTTYPE * tmpObj = FindAttachmentByClass(pObj,IC_GUN,subObject); + usSimilarItem = tmpObj->usItem; + } + if ( !fSameItem ) + { + for(int i = 0;iusItem].tripwire)) && (ValidItemAttachment(pObj,usAttachment,fAttemptingAttachment,fDisplayMessage,subObject,usAttachmentSlotIndexVector) || ValidLaunchable(usAttachment, GetAttachedGrenadeLauncher(pObj)) || ValidLaunchable(usAttachment, pObj->usItem))) @@ -2323,7 +2338,8 @@ BOOLEAN ValidItemAttachmentSlot( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN //Search for any valid attachments in this slot //CHRISL: Valid attachments are determined by the old "ValidItemAttachment" function and comparing the attachment class of the item and slot - if(AttachmentSlots[ubSlotIndex].nasAttachmentClass & Item[usAttachment].nasAttachmentClass && + //Madd: gun on tripwire always allowed + if((AttachmentSlots[ubSlotIndex].nasAttachmentClass & Item[usAttachment].nasAttachmentClass || (Item[usAttachment].usItemClass & IC_GUN && Item[pObj->usItem].tripwire)) && (ValidItemAttachment(pObj,usAttachment,FALSE,FALSE,subObject,usAttachmentSlotIndexVector) || ValidLaunchable(usAttachment, GetAttachedGrenadeLauncher(pObj)) || ValidLaunchable(usAttachment, pObj->usItem))) @@ -2414,23 +2430,33 @@ BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAt fSameItem = TRUE; } */ - - for(int i = 0;iusItem].tripwire && Item[usAttachment].usItemClass & IC_GUN && FindAttachmentByClass(pObj,IC_GUN,subObject) != 0 ) { - if ( FindAttachment(pObj, usAttachment, subObject) != 0 ) - { - fSameItem = TRUE; - break; - } + fSimilarItems = TRUE; + OBJECTTYPE * tmpObj = FindAttachmentByClass(pObj,IC_GUN,subObject); + usSimilarItem = tmpObj->usItem; + } - if ( IncompatibleAttachments[i][0] == NONE ) - break; - - if ( IncompatibleAttachments[i][0] == usAttachment && FindAttachment (pObj,IncompatibleAttachments[i][1],subObject) != 0 ) + if ( !fSameItem ) + { + for(int i = 0;iusItem].tripwire && Item[pAttachment->usItem].usItemClass & IC_GUN ) // Madd: gun on tripwire + { + iCheckResult = SkillCheck( pSoldier, ATTACHING_DETONATOR_CHECK, 0 ); + if (iCheckResult < 0) + { + // the attach failure damages both items + DamageObj( this, (INT8) -iCheckResult, subObject ); + DamageObj( pAttachment, (INT8) -iCheckResult, subObject ); + + // there should be a quote here! + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + if ( gfInItemDescBox ) + { + DeleteItemDescriptionBox(); + } + return( FALSE ); + } + } if ( ValidItemAttachment( this, pAttachment->usItem, TRUE, TRUE, subObject ) && playSound ) // not launchable { // attachment sounds - if ( Item[ this->usItem ].usItemClass & IC_WEAPON ) + if ( Item[ this->usItem ].usItemClass & IC_WEAPON || Item[this->usItem].tripwire ) //Madd: attaching items to tripwire makes gun attach sound { PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } @@ -4591,11 +4635,29 @@ BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttac return( FALSE ); } } + else if ( Item[this->usItem].tripwire && Item[pAttachment->usItem].usItemClass & IC_GUN ) // Madd: gun on tripwire + { + iCheckResult = SkillCheck( pSoldier, ATTACHING_DETONATOR_CHECK, 0 ); + if (iCheckResult < 0) + { + // the attach failure damages both items + DamageObj( this, (INT8) -iCheckResult, subObject ); + DamageObj( pAttachment, (INT8) -iCheckResult, subObject ); + + // there should be a quote here! + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + if ( gfInItemDescBox ) + { + //DeleteItemDescriptionBox(); + } + return( FALSE ); + } + } if (fValidItemAttachment && playSound ) // not launchable { // attachment sounds - if ( Item[ this->usItem ].usItemClass & IC_WEAPON ) + if ( Item[ this->usItem ].usItemClass & IC_WEAPON || Item[this->usItem].tripwire ) //Madd: attaching items to tripwire makes gun attach sound { PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } @@ -5313,8 +5375,9 @@ std::vector GetItemSlots(OBJECTTYPE* pObj, UINT8 subObject, BOOLEAN fAtt } //Now that we've setup tempItemSlots for the main item, let's look at the individual attachments + //Madd: Only record these extra slots if the item has its attachment flag set! for(attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter){ - if(iter->exists() && (*iter)[0]->attachments.size() > 0){ + if(iter->exists() && Item[iter->usItem].attachment && (*iter)[0]->attachments.size() > 0){ OBJECTTYPE* pAttachment = &(*iter); tempSlots = GetItemSlots(pAttachment,0,TRUE); for(UINT8 x = 0; x < tempSlots.size(); x++) @@ -13852,7 +13915,7 @@ UINT64 GetAvailableAttachmentPoint (OBJECTTYPE * pObject, UINT8 subObject) point = Item[pObject->usItem].ulAvailableAttachmentPoint; for (attachmentList::iterator iter = (*pObject)[subObject]->attachments.begin(); iter != (*pObject)[subObject]->attachments.end(); ++iter) { - if(iter->exists() && Item[iter->usItem].ulAvailableAttachmentPoint > 0 ) + if(iter->exists() && Item[iter->usItem].ulAvailableAttachmentPoint > 0 && Item[iter->usItem].attachment ) point |= Item[iter->usItem].ulAvailableAttachmentPoint; } }