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; } }