From 1c5765f9ebe15fb800f34f48d249beaa32161b77 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Mon, 22 Mar 2021 21:38:52 -0400 Subject: [PATCH 01/20] Enable installing item to device slot by id --- Mammoth/Include/TSEDevices.h | 3 +++ Mammoth/Include/TSEShipClass.h | 1 + Mammoth/TSE/CCExtensions.cpp | 19 ++++++++++++- Mammoth/TSE/CDeviceTable.cpp | 49 +++++++++++++++++++++++++++++++++- Mammoth/TSE/CShipClass.cpp | 24 +++++++++++++++++ 5 files changed, 94 insertions(+), 2 deletions(-) diff --git a/Mammoth/Include/TSEDevices.h b/Mammoth/Include/TSEDevices.h index c43356e4b..c993789ef 100644 --- a/Mammoth/Include/TSEDevices.h +++ b/Mammoth/Include/TSEDevices.h @@ -546,8 +546,11 @@ class IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, DeviceNames iDev, SDeviceDesc *retDesc) const { return false; } virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceObject *pSource, const CItem &Item, SDeviceDesc *retDesc) const { return false; } + virtual bool FindDefaultDesc (SDeviceGenerateCtx& Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc* retDesc) const { return false; }; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const { return false; } virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const { return false; } + virtual int GetNumberOfDescs () const { return 1; } + virtual const int GetDescIndexGivenId (const CString& sID) const { return -1; } static ALERROR InitDeviceDescFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, SDeviceDesc *retDesc); }; diff --git a/Mammoth/Include/TSEShipClass.h b/Mammoth/Include/TSEShipClass.h index 80649081e..ee8d0fad6 100644 --- a/Mammoth/Include/TSEShipClass.h +++ b/Mammoth/Include/TSEShipClass.h @@ -396,6 +396,7 @@ class CShipClass : public CDesignType bool CreateWreck (CShip *pShip, CSpaceObject **retpWreck = NULL); bool FindDeviceSlotDesc (DeviceNames iDev, SDeviceDesc *retDesc) const; bool FindDeviceSlotDesc (CShip *pShip, const CItem &Item, SDeviceDesc *retDesc) const; + bool FindDeviceSlotDesc (CShip *pShip, const CString& sID, SDeviceDesc *retDesc) const; static const DWORD GDFLAG_NO_DEVICE_SLOT_SEARCH = 0x00000001; void GenerateDevices (int iLevel, CDeviceDescList &Devices, DWORD dwFlags = 0) const; diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 8bafbeeba..c4ef89655 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -629,6 +629,7 @@ ICCItem *fnXMLGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData); #define FIELD_RADIUS_OFFSET CONSTLIT("radiusOffset") #define FIELD_REMOVE CONSTLIT("remove") #define FIELD_ROTATION CONSTLIT("rotation") +#define FIELD_SLOT_ID CONSTLIT("slotID") #define FIELD_SLOT_POS_INDEX CONSTLIT("slotPosIndex") #define FIELD_SOURCE_ONLY CONSTLIT("sourceOnly") #define FIELD_TYPE CONSTLIT("type") @@ -1287,7 +1288,12 @@ static PRIMITIVEPROCDEF g_Extensions[] = "ivi", PPFLAG_SIDEEFFECTS, }, { "shpInstallDevice", fnShipSet, FN_SHIP_INSTALL_DEVICE, - "(shpInstallDevice ship item [deviceSlot]) -> itemStruct (or Nil)", + "(shpInstallDevice ship item [deviceSlot]) -> itemStruct (or Nil)\n\n" + + "deviceSlot can be an int or struct with these parameters:\n\n" + " deviceSlot: device slot number\n" + " slotID: device slot ID\n" + " slotPosIndex: device slot pos index\n", "iv*", PPFLAG_SIDEEFFECTS, }, { "shpIsBlind", fnShipGetOld, FN_SHIP_BLINDNESS, @@ -11100,15 +11106,26 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) int iSlotPosIndex = -1; if (pArgs->GetCount() >= 3) { + IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); + int numSlots = pDevSlots->GetNumberOfDescs(); ICCItem *pOptions = pArgs->GetElement(2); if (pOptions->IsInteger()) iDeviceSlot = pOptions->GetIntegerValue(); else { ICCItem *pDeviceSlot = pOptions->GetElement(FIELD_DEVICE_SLOT); + ICCItem *pDeviceSlotID = pOptions->GetElement(FIELD_SLOT_ID); if (pDeviceSlot && !pDeviceSlot->IsNil()) iDeviceSlot = pDeviceSlot->GetIntegerValue(); + if (pDeviceSlotID && !pDeviceSlotID->IsNil()) + { + CString sDeviceSlotID = pDeviceSlotID->GetStringValue(); + iDeviceSlot = pDevSlots->GetDescIndexGivenId(sDeviceSlotID); + if (iDeviceSlot == -1) + return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); + } + ICCItem *pSlotPosIndex = pOptions->GetElement(FIELD_SLOT_POS_INDEX); if (pSlotPosIndex && !pSlotPosIndex->IsNil()) iSlotPosIndex = pSlotPosIndex->GetIntegerValue(); diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index 990107acc..f07ea3d60 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -181,8 +181,11 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, DeviceNames iDev, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceObject *pObj, const CItem &Item, SDeviceDesc *retDesc) const override; + virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const override; + virtual int GetNumberOfDescs () const override { return m_SlotDesc.GetCount(); } + virtual const int GetDescIndexGivenId (const CString& sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *(m_SlotDescIndicesByID.GetAt(sID)) : -1; } private: struct SEntry @@ -204,6 +207,7 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator TArray m_Table; TArray m_SlotDesc; + TSortMap m_SlotDescIndicesByID; }; ALERROR IDeviceGenerator::CreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, IDeviceGenerator **retpGenerator) @@ -1208,7 +1212,7 @@ bool CGroupOfDeviceGenerators::FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceO if (!Item.MatchesCriteria(m_SlotDesc[i].Criteria)) continue; - // If this slot has an ID and maximum counts and if we've already + // If this slot has an ID and maximum counts and if we've already // exceeded those counts, then skip. if (m_SlotDesc[i].iMaxCount != -1 @@ -1242,6 +1246,44 @@ bool CGroupOfDeviceGenerators::FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceO return true; } +bool CGroupOfDeviceGenerators::FindDefaultDesc(SDeviceGenerateCtx& Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc* retDesc) const + +// FindDefaultDesc +// +// Looks for a slot descriptor that matches the given ID and returns it. + + { + int i; + + // Look for a matching slot + + for (i = 0; i < m_SlotDesc.GetCount(); i++) + { + // Skip if not the desired id + + if (!strEquals(m_SlotDesc[i].DefaultDesc.sID, sID)) + continue; + + // If this slot has an ID and maximum counts and if we've already + // exceeded those counts, then skip. + + if (m_SlotDesc[i].iMaxCount != -1 + && !m_SlotDesc[i].DefaultDesc.sID.IsBlank() + && pObj + && pObj->GetDeviceSystem().GetCountByID(m_SlotDesc[i].DefaultDesc.sID) >= m_SlotDesc[i].iMaxCount) + continue; + + // If we get this far, then this is a valid slot. + + *retDesc = m_SlotDesc[i].DefaultDesc; + return true; + } + + // Not found + + return false; + } + bool CGroupOfDeviceGenerators::FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const // FindDefaultDesc @@ -1418,6 +1460,11 @@ ALERROR CGroupOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement if (pSlotDesc->iMaxCount == -1 && !pSlotDesc->DefaultDesc.sID.IsBlank()) pSlotDesc->iMaxCount = 1; + + if (!pSlotDesc->DefaultDesc.sID.IsBlank()) + { + m_SlotDescIndicesByID.Insert(pSlotDesc->DefaultDesc.sID, m_SlotDesc.GetCount()); + } } else { diff --git a/Mammoth/TSE/CShipClass.cpp b/Mammoth/TSE/CShipClass.cpp index 704d48b36..be5e2d00f 100644 --- a/Mammoth/TSE/CShipClass.cpp +++ b/Mammoth/TSE/CShipClass.cpp @@ -2082,6 +2082,30 @@ bool CShipClass::FindDeviceSlotDesc (CShip *pShip, const CItem &Item, SDeviceDes return false; } +bool CShipClass::FindDeviceSlotDesc (CShip *pShip, const CString& sID, SDeviceDesc *retDesc) const + +// FindDeviceSlotDesc +// +// Looks for a device slot descriptor + + { + SDeviceGenerateCtx Ctx(GetUniverse()); + + // If we have a dedicated device slot object, then use that. + + if (m_pDeviceSlots) + return m_pDeviceSlots->FindDefaultDesc(Ctx, pShip, sID, retDesc); + + // Otherwise, for backwards compatibility we check the device generator. + + else if (m_pDevices) + return m_pDevices->FindDefaultDesc(Ctx, pShip, sID, retDesc); + + // Otherwise, not found + + return false; + } + void CShipClass::GenerateDevices (int iLevel, CDeviceDescList &Devices, DWORD dwFlags) const // GenerateDevices From 1607c6e8558fcd65ffb98f5f9bebeb0335cbd5d8 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Thu, 25 Mar 2021 22:56:39 -0400 Subject: [PATCH 02/20] WIP commit for new device slot changes --- Mammoth/TSE/CDeviceTable.cpp | 34 ++++++++++++++++++++++++++++++++++ Mammoth/TSE/ShipProperties.cpp | 12 ++++++++++++ 2 files changed, 46 insertions(+) diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index f07ea3d60..e0cedeca9 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -23,6 +23,7 @@ #define COUNT_ATTRIB CONSTLIT("count") #define CRITERIA_ATTRIB CONSTLIT("criteria") #define DAMAGED_ATTRIB CONSTLIT("damaged") +#define DESCRIPTION_ATTRIB CONSTLIT("description") #define DEVICE_ID_ATTRIB CONSTLIT("deviceID") #define ENHANCED_ATTRIB CONSTLIT("enhanced") #define ENHANCEMENT_ATTRIB CONSTLIT("enhancement") @@ -41,6 +42,9 @@ #define MAX_FIRE_ARC_ATTRIB CONSTLIT("maxFireArc") #define MIN_FIRE_ARC_ATTRIB CONSTLIT("minFireArc") #define MAX_FIRE_RANGE_ATTRIB CONSTLIT("maxFireRange") +#define MAX_MASS_ATTRIB CONSTLIT("maxMass") +#define MAX_POWER_ATTRIB CONSTLIT("maxPower") +#define MAX_POWER_PERCENT_ATTRIB CONSTLIT("maxPowerPercentage") #define MISSILE_DEFENSE_ATTRIB CONSTLIT("missileDefense") #define OMNIDIRECTIONAL_ATTRIB CONSTLIT("omnidirectional") #define SECONDARY_WEAPON_ATTRIB CONSTLIT("secondaryWeapon") @@ -199,9 +203,14 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator CItemCriteria Criteria; SDeviceDesc DefaultDesc; int iMaxCount; + int iMaxMass = -1; + CString Description; + int iMaxPower = -1; + Metric fMaxPowerPercent = -1.0; }; const SSlotDesc *FindSlotDesc (CSpaceObject *pObj, const CItem &Item) const; + bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const; DiceRange m_Count; @@ -253,6 +262,8 @@ ALERROR IDeviceGenerator::InitDeviceDescFromXML (SDesignLoadCtx &Ctx, CXMLElemen // InitDeviceDescFromXML // // Loads a device desc from XML. +// TODO(heliogenesis): Add support for attribute list, weapon target definition, and description, and possibly max mass? +// See https://discord.com/channels/265561663741100043/265561663741100043/823740088294703156 { ALERROR error; @@ -1389,6 +1400,25 @@ const CGroupOfDeviceGenerators::SSlotDesc *CGroupOfDeviceGenerators::FindSlotDes return NULL; } +bool CGroupOfDeviceGenerators::ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const + +// ItemFitsSlot +// +// Returns TRUE if the item fits the slot specified by iSlotIndex, otherwise FALSE + + { + CItemCtx ItemCtx(&Item); + int iPowerUse = Item.IsDevice() ? Item.AsDeviceItem().GetDeviceClass().GetPowerRating(ItemCtx) : 0; // TODO: Move this outside of this function; this is a slow operation + int iMass = Item.GetMassKg(); + const SSlotDesc Slot = m_SlotDesc[iSlotIndex]; + bool bMatchesCriteria = Item.MatchesCriteria(Slot.Criteria); + bool bMeetsPowerLimits = Slot.iMaxPower > 0 ? Slot.iMaxPower >= iPowerUse : true; + bool bMeetsPowerPercentLimits = Slot.fMaxPowerPercent > 0.0 ? (pObj->GetMaxPower() * Slot.fMaxPowerPercent) >= iPowerUse : true; + bool bMeetsMassLimits = Slot.iMaxMass > 0 ? Slot.iMaxMass >= iMass : true; + + return (bMatchesCriteria && bMeetsPowerLimits && bMeetsPowerPercentLimits && bMeetsMassLimits); + } + bool CGroupOfDeviceGenerators::HasItemAttribute (const CString &sAttrib) const // HasItemAttribute @@ -1450,6 +1480,10 @@ ALERROR CGroupOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement SSlotDesc *pSlotDesc = m_SlotDesc.Insert(); pSlotDesc->Criteria.Init(pEntry->GetAttribute(CRITERIA_ATTRIB)); + pSlotDesc->Description = pEntry->GetAttribute(DESCRIPTION_ATTRIB); + pSlotDesc->iMaxPower = pEntry->GetAttributeInteger(MAX_POWER_ATTRIB); + pSlotDesc->fMaxPowerPercent = pEntry->GetAttributeFloat(MAX_POWER_PERCENT_ATTRIB); + pSlotDesc->iMaxMass = pEntry->GetAttributeInteger(MAX_MASS_ATTRIB); if (error = IDeviceGenerator::InitDeviceDescFromXML(Ctx, pEntry, &pSlotDesc->DefaultDesc)) return error; diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index cfd2e07af..955202463 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -25,6 +25,18 @@ #define PROPERTY_CHARACTER_NAME CONSTLIT("characterName") #define PROPERTY_DEVICE_DAMAGE_IMMUNE CONSTLIT("deviceDamageImmune") #define PROPERTY_DEVICE_DISRUPT_IMMUNE CONSTLIT("deviceDisruptImmune") +#define PROPERTY_DEVICE_SLOT_COUNT CONSTLIT("deviceSlotCount") +#define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("deviceSlotCriteria") +#define PROPERTY_DEVICE_SLOT_FIREARC CONSTLIT("deviceSlotFireArc") +#define PROPERTY_DEVICE_SLOT_IDS CONSTLIT("deviceSlotIDs") +#define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("deviceSlotMaxMass") +#define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("deviceSlotMaxPower") +#define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("deviceSlotMaxPowerPercent") +#define PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL CONSTLIT("deviceSlotOmnidirectional") +#define PROPERTY_DEVICE_SLOT_POS CONSTLIT("deviceSlotPos") +#define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("deviceSlotPosAngle") +#define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("deviceSlotPosRadius") +#define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("deviceSlotSecondaryWeapon") #define PROPERTY_DISINTEGRATION_IMMUNE CONSTLIT("disintegrationImmune") #define PROPERTY_DOCKED_AT_ID CONSTLIT("dockedAtID") #define PROPERTY_DOCKING_ENABLED CONSTLIT("dockingEnabled") From f3974e6f35bbb0fb04c4d02f1915425f83c13dc2 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Thu, 1 Apr 2021 02:07:04 -0400 Subject: [PATCH 03/20] Implement force use of device slot for install and install check --- Mammoth/Include/TSEDevices.h | 1 + Mammoth/Include/TSESpaceObjectsImpl.h | 2 + Mammoth/TSE/CCExtensions.cpp | 86 +++++++++++++++++++++++---- Mammoth/TSE/CDeviceTable.cpp | 8 +-- Mammoth/TSE/ShipProperties.cpp | 43 ++++++++++++++ 5 files changed, 126 insertions(+), 14 deletions(-) diff --git a/Mammoth/Include/TSEDevices.h b/Mammoth/Include/TSEDevices.h index c993789ef..8ec97997c 100644 --- a/Mammoth/Include/TSEDevices.h +++ b/Mammoth/Include/TSEDevices.h @@ -549,6 +549,7 @@ class IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx& Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc* retDesc) const { return false; }; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const { return false; } virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const { return false; } + virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const { return false; }; virtual int GetNumberOfDescs () const { return 1; } virtual const int GetDescIndexGivenId (const CString& sID) const { return -1; } diff --git a/Mammoth/Include/TSESpaceObjectsImpl.h b/Mammoth/Include/TSESpaceObjectsImpl.h index af2c55b04..105778a8c 100644 --- a/Mammoth/Include/TSESpaceObjectsImpl.h +++ b/Mammoth/Include/TSESpaceObjectsImpl.h @@ -1019,6 +1019,7 @@ class CShip : public TSpaceObjectImpl bool FindDeviceAtPos (const CVector &vPos, CInstalledDevice **retpDevice); int GetAmmoForSelectedLinkedFireWeapons(CInstalledDevice *pDevice); DeviceNames GetDeviceNameForCategory (ItemCategories iCategory); + ICCItem* GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName) const; int GetItemDeviceName (const CItem &Item) const; CItem GetNamedItem (DeviceNames iDev) const; bool HasNamedDevice (DeviceNames iDev) const; @@ -1345,6 +1346,7 @@ class CShip : public TSpaceObjectImpl Metric GetItemMass (void) const; int GetTotalArmorHP (int *retiMaxHP = NULL) const; void InvalidateItemMass (void) const { m_fRecalcItemMass = true; } + bool IsDeviceSlotProperty (const CString& sName) const; bool IsSingletonDevice (ItemCategories iItemCat); void PaintMapShipCompartments (CG32bitImage &Dest, int x, int y, CMapViewportCtx &Ctx); void PaintShipCompartments (CG32bitImage &Dest, SViewportPaintCtx &Ctx); diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index c4ef89655..e16c9dd00 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -287,7 +287,7 @@ ICCItem *fnObjGetArmor (CEvalContext *pEvalCtx, ICCItem *pArguments, DWORD dwDat #define FN_SHIP_DEVICE_SLOT_AVAIL 1 #define FN_SHIP_INSTALL_AUTOPILOT 2 #define FN_SHIP_HAS_AUTOPILOT 3 -// spare +#define FN_SHIP_DEV_SLOT_PROPERTY 4 #define FN_SHIP_INSTALL_TARGETING 5 #define FN_SHIP_HAS_TARGETING 6 #define FN_SHIP_CLASS 7 @@ -1210,6 +1210,32 @@ static PRIMITIVEPROCDEF g_Extensions[] = "(shpGetClassName class flags) -> class name", "ii", 0, }, + { "shpGetDeviceSlotProperty", fnShipGet, FN_SHIP_DEV_SLOT_PROPERTY, + "(shpGetDeviceSlotProperty ship property [deviceSlot]) -> angle\n\n" + + "deviceSlot can be an int or struct with these parameters:\n\n" + " deviceSlot: device slot number\n" + " slotID: device slot ID\n" + " slotPosIndex: device slot pos index\n" + + "property:\n\n" + " 'deviceSlotAttributes\n" + " 'deviceSlotCount\n" + " 'deviceSlotCriteria\n" + " 'deviceSlotFireArc\n" + " 'deviceSlotIDs\n" + " 'deviceSlotMaxMass\n" + " 'deviceSlotMaxPower\n" + " 'deviceSlotMaxPowerPercent\n" + " 'deviceSlotOmnidirectional\n" + " 'deviceSlotPos\n" + " 'deviceSlotPosAngle\n" + " 'deviceSlotPosRadius\n" + " 'deviceSlotSecondaryWeapon\n" + " 'deviceSlotTargetCriteria\n", + + "is*", 0, }, + { "shpGetDirection", fnShipGetOld, FN_SHIP_DIRECTION, "(shpGetDirection ship) -> angle", NULL, 0, }, @@ -1288,7 +1314,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = "ivi", PPFLAG_SIDEEFFECTS, }, { "shpInstallDevice", fnShipSet, FN_SHIP_INSTALL_DEVICE, - "(shpInstallDevice ship item [deviceSlot]) -> itemStruct (or Nil)\n\n" + "(shpInstallDevice ship item [deviceSlot] [forceUseOfDeviceSlot]) -> itemStruct (or Nil)\n\n" "deviceSlot can be an int or struct with these parameters:\n\n" " deviceSlot: device slot number\n" @@ -1594,7 +1620,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = "ii", 0, }, { "objCanInstallItem", fnObjGet, FN_OBJ_CAN_INSTALL_ITEM, - "(objCanInstallItem obj item [armorSeg|deviceSlot]) -> (True/Nil resultCode resultString [itemToReplace])\n\n" + "(objCanInstallItem obj item [armorSeg|deviceSlot] [forceUseOfDeviceSlot]) -> (True/Nil resultCode resultString [itemToReplace])\n\n" "resultCode\n\n" @@ -6843,24 +6869,52 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) case FN_OBJ_CAN_INSTALL_ITEM: { - CItem Item(pCtx->AsItem(pArgs->GetElement(1))); + CItem Item = (pCtx->AsItem(pArgs->GetElement(1))); if (Item.GetType() == NULL) return pCC->CreateError(CONSTLIT("Invalid item"), pArgs->GetElement(1)); - int iSlot = ((pArgs->GetCount() > 2 && !pArgs->GetElement(2)->IsNil()) ? pArgs->GetElement(2)->GetIntegerValue() : -1); + int iSlot = -1; + if (pArgs->GetCount() > 2 && !pArgs->GetElement(2)->IsNil()) + { + ICCItem* pOptions = pArgs->GetElement(2); + CShip* pShip = pObj->AsShip(); + if (pOptions->IsInteger()) + iSlot = pOptions->GetIntegerValue(); + else if (pShip != nullptr) + { + IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); + ICCItem* pDeviceSlot = pOptions->GetElement(FIELD_DEVICE_SLOT); + ICCItem* pDeviceSlotID = pOptions->GetElement(FIELD_SLOT_ID); + if (pDeviceSlot && !pDeviceSlot->IsNil()) + iSlot = pDeviceSlot->GetIntegerValue(); - // Validate the slot + if (pDeviceSlotID && !pDeviceSlotID->IsNil()) + { + CString sDeviceSlotID = pDeviceSlotID->GetStringValue(); + iSlot = pDevSlots->GetDescIndexGivenId(sDeviceSlotID); + if (iSlot == -1) + return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); + } + } + } + + bool bForceUseOfDeviceSlot = pArgs->GetCount() > 3 ? !(pArgs->GetElement(3)->IsNil()) : false; + // Validate the slot + // TODO(heliogenesis): Add an option to force use of device slot - see https://github.com/kronosaur/TranscendenceDev/pull/75 + bool bCanInstallToDeviceSlot = true; if (iSlot != -1) { CShip *pShip = pObj->AsShip(); + IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); + bCanInstallToDeviceSlot = bForceUseOfDeviceSlot ? pDevSlots->ItemFitsSlot(pObj, Item, iSlot) : true; if (Item.IsArmor() && pShip && (iSlot < 0 || iSlot >= pShip->GetArmorSectionCount())) return pCC->CreateError(CONSTLIT("Invalid armor segment"), pArgs->GetElement(2)); if (Item.IsDevice() && pShip - && (iSlot < 0 || iSlot >= pShip->GetDeviceCount() || pShip->GetDevice(iSlot)->IsEmpty())) + && (iSlot < 0 || iSlot >= pShip->GetDeviceCount() || (!(bForceUseOfDeviceSlot) && pShip->GetDevice(iSlot)->IsEmpty()))) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } @@ -6869,7 +6923,7 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) CSpaceObject::InstallItemResults iResult; CString sResult; CItem ItemToReplace; - bool bCanInstall = pObj->CanInstallItem(Item, iSlot, &iResult, &sResult, &ItemToReplace); + bool bCanInstall = pObj->CanInstallItem(Item, iSlot, &iResult, &sResult, &ItemToReplace) && bCanInstallToDeviceSlot; // TODO(heliogenesis): Move this into CanInstallItem in ShipClass // Generate the result @@ -10574,6 +10628,13 @@ ICCItem *fnShipGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) } } + case FN_SHIP_DEV_SLOT_PROPERTY: + { + IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); + CString sProperty = pArgs->GetElement(1)->GetStringValue(); + return pShip->GetDeviceSlotProperty(pCC, *pCtx, sProperty); + } + case FN_SHIP_DOCK_OBJ: { CSpaceObject *pObj = pShip->GetDockedObj(); @@ -11101,7 +11162,7 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) return pCC->CreateNil(); // See if we passed in a device slot - + // TODO(heliogenesis): Add option to force use of device slot - see https://github.com/kronosaur/TranscendenceDev/pull/75 int iDeviceSlot = -1; int iSlotPosIndex = -1; if (pArgs->GetCount() >= 3) @@ -11109,6 +11170,7 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); int numSlots = pDevSlots->GetNumberOfDescs(); ICCItem *pOptions = pArgs->GetElement(2); + bool bForceUseOfDeviceSlot = pArgs->GetCount() >= 4 ? !(pArgs->GetElement(3)->IsNil()) : false; if (pOptions->IsInteger()) iDeviceSlot = pOptions->GetIntegerValue(); else @@ -11134,9 +11196,13 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) if (iDeviceSlot != -1) { if (Item.IsDevice() - && (iDeviceSlot < 0 || iDeviceSlot >= pShip->GetDeviceCount() || pShip->GetDevice(iDeviceSlot)->IsEmpty())) + && (iDeviceSlot < 0 || iDeviceSlot >= pShip->GetDeviceCount() || (!(bForceUseOfDeviceSlot) && pShip->GetDevice(iDeviceSlot)->IsEmpty()))) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } + else if (iDeviceSlot == -1 && bForceUseOfDeviceSlot) + { + return pCC->CreateNil(); + } } // Otherwise, install or remove diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index e0cedeca9..d67a0d2b9 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -188,6 +188,7 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const override; + virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const override; virtual int GetNumberOfDescs () const override { return m_SlotDesc.GetCount(); } virtual const int GetDescIndexGivenId (const CString& sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *(m_SlotDescIndicesByID.GetAt(sID)) : -1; } @@ -210,7 +211,6 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator }; const SSlotDesc *FindSlotDesc (CSpaceObject *pObj, const CItem &Item) const; - bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const; DiceRange m_Count; @@ -1220,7 +1220,7 @@ bool CGroupOfDeviceGenerators::FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceO { // Skip if this slot does not meet criteria - if (!Item.MatchesCriteria(m_SlotDesc[i].Criteria)) + if (!ItemFitsSlot(pObj, Item, i)) continue; // If this slot has an ID and maximum counts and if we've already @@ -1257,7 +1257,7 @@ bool CGroupOfDeviceGenerators::FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceO return true; } -bool CGroupOfDeviceGenerators::FindDefaultDesc(SDeviceGenerateCtx& Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc* retDesc) const +bool CGroupOfDeviceGenerators::FindDefaultDesc (SDeviceGenerateCtx& Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc* retDesc) const // FindDefaultDesc // @@ -1394,7 +1394,7 @@ const CGroupOfDeviceGenerators::SSlotDesc *CGroupOfDeviceGenerators::FindSlotDes int i; for (i = 0; i < m_SlotDesc.GetCount(); i++) - if (Item.MatchesCriteria(m_SlotDesc[i].Criteria)) + if (ItemFitsSlot(pObj, Item, i)) return &m_SlotDesc[i]; return NULL; diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index 955202463..a625e80c6 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -4,6 +4,7 @@ // Copyright (c) 2021 Kronosaur Productions, LLC. All Rights Reserved. #include "PreComp.h" +#include #define PROPERTY_ALWAYS_LEAVE_WRECK CONSTLIT("alwaysLeaveWreck") #define PROPERTY_ARMOR_COUNT CONSTLIT("armorCount") @@ -25,6 +26,7 @@ #define PROPERTY_CHARACTER_NAME CONSTLIT("characterName") #define PROPERTY_DEVICE_DAMAGE_IMMUNE CONSTLIT("deviceDamageImmune") #define PROPERTY_DEVICE_DISRUPT_IMMUNE CONSTLIT("deviceDisruptImmune") +#define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("deviceSlotAttributes") #define PROPERTY_DEVICE_SLOT_COUNT CONSTLIT("deviceSlotCount") #define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("deviceSlotCriteria") #define PROPERTY_DEVICE_SLOT_FIREARC CONSTLIT("deviceSlotFireArc") @@ -37,6 +39,7 @@ #define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("deviceSlotPosAngle") #define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("deviceSlotPosRadius") #define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("deviceSlotSecondaryWeapon") +#define PROPERTY_DEVICE_SLOT_TARGET_CRITERIA CONSTLIT("deviceSlotTargetCriteria") #define PROPERTY_DISINTEGRATION_IMMUNE CONSTLIT("disintegrationImmune") #define PROPERTY_DOCKED_AT_ID CONSTLIT("dockedAtID") #define PROPERTY_DOCKING_ENABLED CONSTLIT("dockingEnabled") @@ -248,6 +251,44 @@ ICCItemPtr CShip::OnFindProperty (CCodeChainCtx &CCX, const CString &sProperty) return ICCItemPtr(); } +bool CShip::IsDeviceSlotProperty(const CString& sName) const + +// IsDeviceSlotProperty +// +// Returns TRUE if the property is a device slot property + + { + std::set deviceSlotProperties = { + PROPERTY_DEVICE_SLOT_ATTRIBUTES, + PROPERTY_DEVICE_SLOT_COUNT, + PROPERTY_DEVICE_SLOT_CRITERIA, + PROPERTY_DEVICE_SLOT_FIREARC, + PROPERTY_DEVICE_SLOT_IDS, + PROPERTY_DEVICE_SLOT_MAX_MASS, + PROPERTY_DEVICE_SLOT_MAX_POWER, + PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT, + PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL, + PROPERTY_DEVICE_SLOT_POS, + PROPERTY_DEVICE_SLOT_POS_ANGLE, + PROPERTY_DEVICE_SLOT_POS_RADIUS, + PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON, + PROPERTY_DEVICE_SLOT_TARGET_CRITERIA + }; + return deviceSlotProperties.find(sName) != deviceSlotProperties.end(); + } + +ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName) const + +// GetDeviceSlotProperty +// +// Returns a device slot property +// TODO(heliogenesis): Complete this function + + { + // Device slot properties + return pCC->CreateError(CONSTLIT("Unimplemented function")); + } + ICCItem *CShip::GetPropertyCompatible (CCodeChainCtx &Ctx, const CString &sName) const // GetProperty @@ -258,6 +299,8 @@ ICCItem *CShip::GetPropertyCompatible (CCodeChainCtx &Ctx, const CString &sName) CCodeChain &CC = GetUniverse().GetCC(); ICCItem *pResult; + // Device slot properties + if (strEquals(sName, PROPERTY_ALWAYS_LEAVE_WRECK)) return CC.CreateBool(m_fAlwaysLeaveWreck || m_pClass->GetWreckChance() >= 100); From f0e99ac8bbca889500a8c9f854aeb4f2c8749059 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Fri, 16 Apr 2021 21:35:47 -0400 Subject: [PATCH 04/20] More WIP on device slot functions --- Mammoth/Include/TSE.h | 2 +- Mammoth/Include/TSESpaceObjectsImpl.h | 4 +- Mammoth/TSE/CCExtensions.cpp | 12 ++--- Mammoth/TSE/CDeviceTable.cpp | 15 +++++- Mammoth/TSE/CShip.cpp | 8 ++- Mammoth/TSE/CSpaceObject.cpp | 2 +- Mammoth/TSE/ShipProperties.cpp | 78 +++++++++++++++------------ 7 files changed, 74 insertions(+), 47 deletions(-) diff --git a/Mammoth/Include/TSE.h b/Mammoth/Include/TSE.h index 9953127fd..e94a32d18 100644 --- a/Mammoth/Include/TSE.h +++ b/Mammoth/Include/TSE.h @@ -628,7 +628,7 @@ class CSpaceObject // Devices - virtual bool CanInstallItem (const CItem &Item, int iSlot = -1, InstallItemResults *retiResult = NULL, CString *retsResult = NULL, CItem *retItemToReplace = NULL); + virtual bool CanInstallItem (const CItem &Item, int iSlot = -1, bool bForceUseOfDeviceSlot = false, InstallItemResults *retiResult = NULL, CString *retsResult = NULL, CItem *retItemToReplace = NULL); virtual void DamageExternalDevice (int iDev, SDamageCtx &Ctx) { } virtual void DisableDevice (CInstalledDevice *pDevice) { } bool FindDevice (const CItem &Item, CInstalledDevice **retpDevice, CString *retsError); diff --git a/Mammoth/Include/TSESpaceObjectsImpl.h b/Mammoth/Include/TSESpaceObjectsImpl.h index 105778a8c..2b351066a 100644 --- a/Mammoth/Include/TSESpaceObjectsImpl.h +++ b/Mammoth/Include/TSESpaceObjectsImpl.h @@ -1019,7 +1019,7 @@ class CShip : public TSpaceObjectImpl bool FindDeviceAtPos (const CVector &vPos, CInstalledDevice **retpDevice); int GetAmmoForSelectedLinkedFireWeapons(CInstalledDevice *pDevice); DeviceNames GetDeviceNameForCategory (ItemCategories iCategory); - ICCItem* GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName) const; + ICCItem* GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName, const ICCItem* pArgs) const; int GetItemDeviceName (const CItem &Item) const; CItem GetNamedItem (DeviceNames iDev) const; bool HasNamedDevice (DeviceNames iDev) const; @@ -1114,7 +1114,7 @@ class CShip : public TSpaceObjectImpl virtual bool CanAttack (void) const override; virtual bool CanBeAttacked (void) const override { return CanAttack(); } virtual bool CanBeDestroyedBy (CSpaceObject &Attacker) const override; - virtual bool CanInstallItem (const CItem &Item, int iSlot = -1, InstallItemResults *retiResult = NULL, CString *retsResult = NULL, CItem *retItemToReplace = NULL) override; + virtual bool CanInstallItem (const CItem& Item, int iSlot = -1, bool bForceUseOfDeviceSlot = false, InstallItemResults* retiResult = NULL, CString* retsResult = NULL, CItem* retItemToReplace = NULL) override; virtual bool CanMove (void) const override { return true; } virtual RequestDockResults CanObjRequestDock (CSpaceObject *pObj = NULL) const override; virtual bool CanThrust (void) const override { return (GetThrust() > 0.0); } diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index e16c9dd00..32bb6284e 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -6878,11 +6878,11 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) { ICCItem* pOptions = pArgs->GetElement(2); CShip* pShip = pObj->AsShip(); + const IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); if (pOptions->IsInteger()) iSlot = pOptions->GetIntegerValue(); else if (pShip != nullptr) { - IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); ICCItem* pDeviceSlot = pOptions->GetElement(FIELD_DEVICE_SLOT); ICCItem* pDeviceSlotID = pOptions->GetElement(FIELD_SLOT_ID); if (pDeviceSlot && !pDeviceSlot->IsNil()) @@ -6901,13 +6901,11 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) bool bForceUseOfDeviceSlot = pArgs->GetCount() > 3 ? !(pArgs->GetElement(3)->IsNil()) : false; // Validate the slot - // TODO(heliogenesis): Add an option to force use of device slot - see https://github.com/kronosaur/TranscendenceDev/pull/75 bool bCanInstallToDeviceSlot = true; if (iSlot != -1) { CShip *pShip = pObj->AsShip(); IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); - bCanInstallToDeviceSlot = bForceUseOfDeviceSlot ? pDevSlots->ItemFitsSlot(pObj, Item, iSlot) : true; if (Item.IsArmor() && pShip && (iSlot < 0 || iSlot >= pShip->GetArmorSectionCount())) @@ -6923,7 +6921,7 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) CSpaceObject::InstallItemResults iResult; CString sResult; CItem ItemToReplace; - bool bCanInstall = pObj->CanInstallItem(Item, iSlot, &iResult, &sResult, &ItemToReplace) && bCanInstallToDeviceSlot; // TODO(heliogenesis): Move this into CanInstallItem in ShipClass + bool bCanInstall = pObj->CanInstallItem(Item, iSlot, bForceUseOfDeviceSlot, &iResult, &sResult, &ItemToReplace); // Generate the result @@ -10632,7 +10630,7 @@ ICCItem *fnShipGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) { IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); CString sProperty = pArgs->GetElement(1)->GetStringValue(); - return pShip->GetDeviceSlotProperty(pCC, *pCtx, sProperty); + return pShip->GetDeviceSlotProperty(pCC, *pCtx, sProperty, pArgs); } case FN_SHIP_DOCK_OBJ: @@ -10949,7 +10947,7 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) CSpaceObject::InstallItemResults iResult; CString sResult; - pShip->CanInstallItem(Item, iSlot, &iResult, &sResult); + pShip->CanInstallItem(Item, iSlot, false, &iResult, &sResult); if (!sResult.IsBlank()) return pCC->CreateString(sResult); @@ -11162,7 +11160,7 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) return pCC->CreateNil(); // See if we passed in a device slot - // TODO(heliogenesis): Add option to force use of device slot - see https://github.com/kronosaur/TranscendenceDev/pull/75 + // TODO(heliogenesis): Prevent installation if we fail the "can install" check e.g. if we force use of dev slot?? int iDeviceSlot = -1; int iSlotPosIndex = -1; if (pArgs->GetCount() >= 3) diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index d67a0d2b9..4582bdb80 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -54,6 +54,19 @@ #define TABLE_ATTRIB CONSTLIT("table") #define UNID_ATTRIB CONSTLIT("unid") +#define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("deviceSlotAttributes") +#define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("deviceSlotCriteria") +#define PROPERTY_DEVICE_SLOT_FIREARC CONSTLIT("deviceSlotFireArc") +#define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("deviceSlotMaxMass") +#define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("deviceSlotMaxPower") +#define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("deviceSlotMaxPowerPercent") +#define PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL CONSTLIT("deviceSlotOmnidirectional") +#define PROPERTY_DEVICE_SLOT_POS CONSTLIT("deviceSlotPos") +#define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("deviceSlotPosAngle") +#define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("deviceSlotPosRadius") +#define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("deviceSlotSecondaryWeapon") +#define PROPERTY_DEVICE_SLOT_TARGET_CRITERIA CONSTLIT("deviceSlotTargetCriteria") + class CNullDevice : public IDeviceGenerator { public: @@ -1497,7 +1510,7 @@ ALERROR CGroupOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement if (!pSlotDesc->DefaultDesc.sID.IsBlank()) { - m_SlotDescIndicesByID.Insert(pSlotDesc->DefaultDesc.sID, m_SlotDesc.GetCount()); + m_SlotDescIndicesByID.Insert(pSlotDesc->DefaultDesc.sID, m_SlotDesc.GetCount() - 1); } } else diff --git a/Mammoth/TSE/CShip.cpp b/Mammoth/TSE/CShip.cpp index e4379875f..736c099fa 100644 --- a/Mammoth/TSE/CShip.cpp +++ b/Mammoth/TSE/CShip.cpp @@ -929,7 +929,7 @@ bool CShip::CanBeDestroyedBy (CSpaceObject &Attacker) const return false; } -bool CShip::CanInstallItem (const CItem &Item, int iSlot, InstallItemResults *retiResult, CString *retsResult, CItem *retItemToReplace) +bool CShip::CanInstallItem (const CItem &Item, int iSlot, bool bForceUseOfDeviceSlot, InstallItemResults *retiResult, CString *retsResult, CItem *retItemToReplace) // CanInstallItem // @@ -941,6 +941,7 @@ bool CShip::CanInstallItem (const CItem &Item, int iSlot, InstallItemResults *re CString sResult; CItem ItemToReplace; const CHullDesc &Hull = m_pClass->GetHullDesc(); + const IDeviceGenerator *pDevSlots = GetClass()->GetDeviceSlots(); // If this is an armor item, see if we can install it. @@ -1025,6 +1026,11 @@ bool CShip::CanInstallItem (const CItem &Item, int iSlot, InstallItemResults *re if (!Item.MatchesCriteria(Hull.GetDeviceCriteria())) iResult = insNotCompatible; + // If we force use of a device slot, and that device slot doesn't fit, then we cannot install + + if (bForceUseOfDeviceSlot && !pDevSlots->ItemFitsSlot(this, Item, iSlot)) + iResult = insNotCompatible; + // Ask the object if we can install this item else if (!FireCanInstallItem(Item, iSlot, &sResult)) diff --git a/Mammoth/TSE/CSpaceObject.cpp b/Mammoth/TSE/CSpaceObject.cpp index 495fce813..ab5995e71 100644 --- a/Mammoth/TSE/CSpaceObject.cpp +++ b/Mammoth/TSE/CSpaceObject.cpp @@ -966,7 +966,7 @@ bool CSpaceObject::CanFireOnObjHelper (CSpaceObject *pObj) const ); } -bool CSpaceObject::CanInstallItem (const CItem &Item, int iSlot, InstallItemResults *retiResult, CString *retsResult, CItem *retItemToReplace) +bool CSpaceObject::CanInstallItem (const CItem &Item, int iSlot, bool bForceUseOfDeviceSlot, InstallItemResults *retiResult, CString *retsResult, CItem *retItemToReplace) // CanInstallItem // diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index a625e80c6..63368ec42 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -6,6 +6,9 @@ #include "PreComp.h" #include +#define FIELD_DEVICE_SLOT CONSTLIT("deviceSlot") +#define FIELD_SLOT_ID CONSTLIT("slotID") + #define PROPERTY_ALWAYS_LEAVE_WRECK CONSTLIT("alwaysLeaveWreck") #define PROPERTY_ARMOR_COUNT CONSTLIT("armorCount") #define PROPERTY_AUTO_TARGET CONSTLIT("autoTarget") @@ -26,20 +29,7 @@ #define PROPERTY_CHARACTER_NAME CONSTLIT("characterName") #define PROPERTY_DEVICE_DAMAGE_IMMUNE CONSTLIT("deviceDamageImmune") #define PROPERTY_DEVICE_DISRUPT_IMMUNE CONSTLIT("deviceDisruptImmune") -#define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("deviceSlotAttributes") -#define PROPERTY_DEVICE_SLOT_COUNT CONSTLIT("deviceSlotCount") -#define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("deviceSlotCriteria") -#define PROPERTY_DEVICE_SLOT_FIREARC CONSTLIT("deviceSlotFireArc") #define PROPERTY_DEVICE_SLOT_IDS CONSTLIT("deviceSlotIDs") -#define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("deviceSlotMaxMass") -#define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("deviceSlotMaxPower") -#define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("deviceSlotMaxPowerPercent") -#define PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL CONSTLIT("deviceSlotOmnidirectional") -#define PROPERTY_DEVICE_SLOT_POS CONSTLIT("deviceSlotPos") -#define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("deviceSlotPosAngle") -#define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("deviceSlotPosRadius") -#define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("deviceSlotSecondaryWeapon") -#define PROPERTY_DEVICE_SLOT_TARGET_CRITERIA CONSTLIT("deviceSlotTargetCriteria") #define PROPERTY_DISINTEGRATION_IMMUNE CONSTLIT("disintegrationImmune") #define PROPERTY_DOCKED_AT_ID CONSTLIT("dockedAtID") #define PROPERTY_DOCKING_ENABLED CONSTLIT("dockingEnabled") @@ -255,29 +245,13 @@ bool CShip::IsDeviceSlotProperty(const CString& sName) const // IsDeviceSlotProperty // -// Returns TRUE if the property is a device slot property +// Returns TRUE if the property is a device slot property tied to a specific device slot. { - std::set deviceSlotProperties = { - PROPERTY_DEVICE_SLOT_ATTRIBUTES, - PROPERTY_DEVICE_SLOT_COUNT, - PROPERTY_DEVICE_SLOT_CRITERIA, - PROPERTY_DEVICE_SLOT_FIREARC, - PROPERTY_DEVICE_SLOT_IDS, - PROPERTY_DEVICE_SLOT_MAX_MASS, - PROPERTY_DEVICE_SLOT_MAX_POWER, - PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT, - PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL, - PROPERTY_DEVICE_SLOT_POS, - PROPERTY_DEVICE_SLOT_POS_ANGLE, - PROPERTY_DEVICE_SLOT_POS_RADIUS, - PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON, - PROPERTY_DEVICE_SLOT_TARGET_CRITERIA - }; - return deviceSlotProperties.find(sName) != deviceSlotProperties.end(); + return true; } -ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName) const +ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName, const ICCItem* pArgs) const // GetDeviceSlotProperty // @@ -285,8 +259,40 @@ ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const // TODO(heliogenesis): Complete this function { - // Device slot properties + // Device slot properties tied to specific device slots + int iDeviceSlot = -1; + if (pArgs->GetCount() >= 3) + { + IDeviceGenerator* pDevSlots = this->GetClass().GetDeviceSlots(); + int numSlots = pDevSlots->GetNumberOfDescs(); + ICCItem* pOptions = pArgs->GetElement(2); + if (pOptions->IsInteger()) + iDeviceSlot = pOptions->GetIntegerValue(); + else + { + ICCItem* pDeviceSlot = pOptions->GetElement(FIELD_DEVICE_SLOT); + ICCItem* pDeviceSlotID = pOptions->GetElement(FIELD_SLOT_ID); + if (pDeviceSlot && !pDeviceSlot->IsNil()) + iDeviceSlot = pDeviceSlot->GetIntegerValue(); + + if (pDeviceSlotID && !pDeviceSlotID->IsNil()) + { + CString sDeviceSlotID = pDeviceSlotID->GetStringValue(); + iDeviceSlot = pDevSlots->GetDescIndexGivenId(sDeviceSlotID); + if (iDeviceSlot == -1) + return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); + } + } + if (iDeviceSlot != -1) + { + if (iDeviceSlot < 0 || iDeviceSlot >= this->GetDeviceCount()) + return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); + } + } + else + return pCC->CreateError(CONSTLIT("Insufficient arguments")); return pCC->CreateError(CONSTLIT("Unimplemented function")); + } ICCItem *CShip::GetPropertyCompatible (CCodeChainCtx &Ctx, const CString &sName) const @@ -366,7 +372,7 @@ ICCItem *CShip::GetPropertyCompatible (CCodeChainCtx &Ctx, const CString &sName) else if (strEquals(sName, PROPERTY_CHALLENGE_RATING)) return CC.CreateInteger(CChallengeRatingCalculator::CalcChallengeRating(*this)); - + else if (strEquals(sName, PROPERTY_CHARACTER)) return (m_pCharacter ? CC.CreateInteger(m_pCharacter->GetUNID()) : CC.CreateNil()); @@ -379,6 +385,10 @@ ICCItem *CShip::GetPropertyCompatible (CCodeChainCtx &Ctx, const CString &sName) else if (strEquals(sName, PROPERTY_DEVICE_DISRUPT_IMMUNE)) return CC.CreateBool(m_Armor.IsImmune(specialDeviceDisrupt)); + // TODO(heliogenesis): Create new function to get all slot IDs from a slot struct + //else if (strEquals(sName, PROPERTY_DEVICE_SLOT_IDS)) + // return; + else if (strEquals(sName, PROPERTY_DISINTEGRATION_IMMUNE)) return CC.CreateBool(m_Armor.IsImmune(specialDisintegration)); From 9395da1463b3c521966fc04efeec1d542589e888 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Wed, 28 Apr 2021 22:41:27 -0400 Subject: [PATCH 05/20] Initial work on GetDeviceSlotProperty, still need Attributes and WeaponTargetCriteria --- Mammoth/Include/TSEDevices.h | 2 + Mammoth/Include/TSESpaceObjectsImpl.h | 2 +- Mammoth/TSE/CCExtensions.cpp | 51 +++++++++------ Mammoth/TSE/CDeviceTable.cpp | 90 +++++++++++++++++++++++---- Mammoth/TSE/ShipProperties.cpp | 10 +-- 5 files changed, 116 insertions(+), 39 deletions(-) diff --git a/Mammoth/Include/TSEDevices.h b/Mammoth/Include/TSEDevices.h index 8ec97997c..b68f7d3a5 100644 --- a/Mammoth/Include/TSEDevices.h +++ b/Mammoth/Include/TSEDevices.h @@ -552,6 +552,8 @@ class IDeviceGenerator virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const { return false; }; virtual int GetNumberOfDescs () const { return 1; } virtual const int GetDescIndexGivenId (const CString& sID) const { return -1; } + virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property) const { return pCC->CreateNil(); }; + virtual TArray GetDeviceSlotIds() const { return TArray(); } static ALERROR InitDeviceDescFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, SDeviceDesc *retDesc); }; diff --git a/Mammoth/Include/TSESpaceObjectsImpl.h b/Mammoth/Include/TSESpaceObjectsImpl.h index 424bf29aa..8d374bbe7 100644 --- a/Mammoth/Include/TSESpaceObjectsImpl.h +++ b/Mammoth/Include/TSESpaceObjectsImpl.h @@ -1020,7 +1020,7 @@ class CShip : public TSpaceObjectImpl bool FindDeviceAtPos (const CVector &vPos, CInstalledDevice **retpDevice); int GetAmmoForSelectedLinkedFireWeapons(CInstalledDevice *pDevice); DeviceNames GetDeviceNameForCategory (ItemCategories iCategory); - ICCItem* GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName, const ICCItem* pArgs) const; + ICCItem* GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const ICCItem* pArgs) const; int GetItemDeviceName (const CItem &Item) const; CItem GetNamedItem (DeviceNames iDev) const; bool HasNamedDevice (DeviceNames iDev) const; diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 6b6d8db4d..e05eb9714 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -300,7 +300,7 @@ ICCItem *fnObjGetArmor (CEvalContext *pEvalCtx, ICCItem *pArguments, DWORD dwDat #define FN_SHIP_BLINDNESS 14 #define FN_SHIP_ENHANCE_ITEM 15 #define FN_SHIP_CAN_INSTALL_DEVICE 16 -// spare +#define FN_SHIP_DEV_SLOT_IDS 17 #define FN_SHIP_IS_RADIOACTIVE 18 #define FN_SHIP_CANCEL_ORDERS 19 #define FN_SHIP_ADD_ENERGY_FIELD 20 @@ -1210,8 +1210,13 @@ static PRIMITIVEPROCDEF g_Extensions[] = "(shpGetClassName class flags) -> class name", "ii", 0, }, + { "shpGetDeviceSlotIds", fnShipGet, FN_SHIP_DEV_SLOT_IDS, + "(shpGetDeviceSlotProperty ship) -> list of IDs", + + "i", 0, }, + { "shpGetDeviceSlotProperty", fnShipGet, FN_SHIP_DEV_SLOT_PROPERTY, - "(shpGetDeviceSlotProperty ship property [deviceSlot]) -> angle\n\n" + "(shpGetDeviceSlotProperty ship [deviceSlot] property) -> angle\n\n" "deviceSlot can be an int or struct with these parameters:\n\n" " deviceSlot: device slot number\n" @@ -1219,22 +1224,21 @@ static PRIMITIVEPROCDEF g_Extensions[] = " slotPosIndex: device slot pos index\n" "property:\n\n" - " 'deviceSlotAttributes\n" - " 'deviceSlotCount\n" - " 'deviceSlotCriteria\n" - " 'deviceSlotFireArc\n" - " 'deviceSlotIDs\n" - " 'deviceSlotMaxMass\n" - " 'deviceSlotMaxPower\n" - " 'deviceSlotMaxPowerPercent\n" - " 'deviceSlotOmnidirectional\n" - " 'deviceSlotPos\n" - " 'deviceSlotPosAngle\n" - " 'deviceSlotPosRadius\n" - " 'deviceSlotSecondaryWeapon\n" - " 'deviceSlotTargetCriteria\n", + " 'attributes\n" + " 'criteria\n" + " 'fireArc\n" + " 'maxMass\n" + " 'maxPower\n" + " 'maxPowerPercent\n" + " 'omnidirectional\n" + " 'pos\n" + " 'posAngle\n" + " 'posCartesian\n" + " 'posRadius\n" + " 'secondaryWeapon\n" + " 'targetCriteria\n", - "is*", 0, }, + "i*s", 0, }, { "shpGetDirection", fnShipGetOld, FN_SHIP_DIRECTION, "(shpGetDirection ship) -> angle", @@ -10624,11 +10628,18 @@ ICCItem *fnShipGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) } } + case FN_SHIP_DEV_SLOT_IDS: + { + TArray ids = pShip->GetClass()->GetDeviceSlots()->GetDeviceSlotIds(); + ICCItem* pIDs = pCC->CreateLinkedList(); + for (int i = 0; i < ids.GetCount(); i++) + pIDs->AppendString(ids[i]); + return pIDs; + } + case FN_SHIP_DEV_SLOT_PROPERTY: { - IDeviceGenerator* pDevSlots = pShip->GetClass()->GetDeviceSlots(); - CString sProperty = pArgs->GetElement(1)->GetStringValue(); - return pShip->GetDeviceSlotProperty(pCC, *pCtx, sProperty, pArgs); + return pShip->GetDeviceSlotProperty(pCC, *pCtx, pArgs); } case FN_SHIP_DOCK_OBJ: diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index 4582bdb80..62927657a 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -54,18 +54,19 @@ #define TABLE_ATTRIB CONSTLIT("table") #define UNID_ATTRIB CONSTLIT("unid") -#define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("deviceSlotAttributes") -#define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("deviceSlotCriteria") -#define PROPERTY_DEVICE_SLOT_FIREARC CONSTLIT("deviceSlotFireArc") -#define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("deviceSlotMaxMass") -#define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("deviceSlotMaxPower") -#define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("deviceSlotMaxPowerPercent") -#define PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL CONSTLIT("deviceSlotOmnidirectional") -#define PROPERTY_DEVICE_SLOT_POS CONSTLIT("deviceSlotPos") -#define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("deviceSlotPosAngle") -#define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("deviceSlotPosRadius") -#define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("deviceSlotSecondaryWeapon") -#define PROPERTY_DEVICE_SLOT_TARGET_CRITERIA CONSTLIT("deviceSlotTargetCriteria") +#define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("attributes") +#define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("criteria") +#define PROPERTY_DEVICE_SLOT_FIRE_ARC CONSTLIT("fireArc") +#define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("maxMass") +#define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("maxPower") +#define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("maxPowerPercent") +#define PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL CONSTLIT("omnidirectional") +#define PROPERTY_DEVICE_SLOT_POS CONSTLIT("pos") +#define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("posAngle") +#define PROPERTY_DEVICE_SLOT_POS_CARTESIAN CONSTLIT("posCartesian") +#define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("posRadius") +#define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("secondaryWeapon") +#define PROPERTY_DEVICE_SLOT_TARGET_CRITERIA CONSTLIT("targetCriteria") class CNullDevice : public IDeviceGenerator { @@ -203,7 +204,9 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const override; virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const override; virtual int GetNumberOfDescs () const override { return m_SlotDesc.GetCount(); } - virtual const int GetDescIndexGivenId (const CString& sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *(m_SlotDescIndicesByID.GetAt(sID)) : -1; } + virtual const int GetDescIndexGivenId (const CString& sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *m_SlotDescIndicesByID.GetAt(sID) : -1; } + virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property) const override; + virtual TArray GetDeviceSlotIds() const override { TArray ids; for (int i = 0; i < m_SlotDescIndicesByID.GetCount(); i++) { ids.Insert(m_SlotDescIndicesByID.GetKey(i)); } return ids; } private: struct SEntry @@ -1413,6 +1416,67 @@ const CGroupOfDeviceGenerators::SSlotDesc *CGroupOfDeviceGenerators::FindSlotDes return NULL; } +ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property) const + +// GetDeviceSlotProperty +// +// Return the value of the property requested +// TODO(heliogenesis): Complete unimplemented fields + { + const SSlotDesc &Slot = m_SlotDesc[iSlotIndex]; + const SDeviceDesc &DefaultDesc = Slot.DefaultDesc; + if (Property == PROPERTY_DEVICE_SLOT_ATTRIBUTES) + return pCC->CreateError("Unimplemented function"); + else if (Property == PROPERTY_DEVICE_SLOT_CRITERIA) + return pCC->CreateString(Slot.Criteria.AsString()); + else if (Property == PROPERTY_DEVICE_SLOT_FIRE_ARC) + { + if (DefaultDesc.bOmnidirectional) + return pCC->CreateString(OMNIDIRECTIONAL_ATTRIB); + else if (DefaultDesc.iMaxFireArc != DefaultDesc.iMinFireArc) + { + ICCItem* pResult = pCC->CreateLinkedList(); + pResult->Append(pCC->CreateInteger(DefaultDesc.iMinFireArc)); + pResult->Append(pCC->CreateInteger(DefaultDesc.iMaxFireArc)); + return pResult; + } + else + return (DefaultDesc.iMinFireArc == 0) ? pCC->CreateNil() : pCC->CreateInteger(DefaultDesc.iMinFireArc); + } + else if (Property == PROPERTY_DEVICE_SLOT_MAX_MASS) + return pCC->CreateInteger(Slot.iMaxMass); + else if (Property == PROPERTY_DEVICE_SLOT_MAX_POWER) + return pCC->CreateInteger(Slot.iMaxPower); + else if (Property == PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT) + return pCC->CreateDouble(Slot.fMaxPowerPercent); + else if (Property == PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL) + return pCC->CreateBool(DefaultDesc.bOmnidirectional); + else if (Property == PROPERTY_DEVICE_SLOT_POS) + { + ICCItem* pResult = pCC->CreateLinkedList(); + pResult->Append(pCC->CreateInteger(DefaultDesc.iPosAngle)); + pResult->Append(pCC->CreateInteger(DefaultDesc.iPosRadius)); + return pResult; + } + else if (Property == PROPERTY_DEVICE_SLOT_POS_ANGLE) + return pCC->CreateInteger(DefaultDesc.iPosAngle); + else if (Property == PROPERTY_DEVICE_SLOT_POS_CARTESIAN) + { + ICCItem* pResult = pCC->CreateLinkedList(); + pResult->Append(pCC->CreateInteger(int(sin((DefaultDesc.iPosAngle + 90) * PI / 2.0) * DefaultDesc.iPosRadius))); + pResult->Append(pCC->CreateInteger(int(cos((DefaultDesc.iPosAngle + 90) * PI / 2.0) * DefaultDesc.iPosRadius))); + return pResult; + } + else if (Property == PROPERTY_DEVICE_SLOT_POS_RADIUS) + return pCC->CreateInteger(DefaultDesc.iPosRadius); + else if (Property == PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON) + return pCC->CreateBool(DefaultDesc.bSecondary); + else if (Property == PROPERTY_DEVICE_SLOT_TARGET_CRITERIA) + return pCC->CreateInteger("Unimplemented function"); + else + return pCC->CreateError("Unknown device slot property", pCC->CreateString(Property)); + } + bool CGroupOfDeviceGenerators::ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const // ItemFitsSlot diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index 63368ec42..f10e963d2 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -251,21 +251,20 @@ bool CShip::IsDeviceSlotProperty(const CString& sName) const return true; } -ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const CString& sName, const ICCItem* pArgs) const +ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const ICCItem* pArgs) const // GetDeviceSlotProperty // // Returns a device slot property -// TODO(heliogenesis): Complete this function { - // Device slot properties tied to specific device slots int iDeviceSlot = -1; if (pArgs->GetCount() >= 3) { + CString sProperty = pArgs->GetElement(2)->GetStringValue(); IDeviceGenerator* pDevSlots = this->GetClass().GetDeviceSlots(); int numSlots = pDevSlots->GetNumberOfDescs(); - ICCItem* pOptions = pArgs->GetElement(2); + ICCItem* pOptions = pArgs->GetElement(1); if (pOptions->IsInteger()) iDeviceSlot = pOptions->GetIntegerValue(); else @@ -288,10 +287,11 @@ ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const if (iDeviceSlot < 0 || iDeviceSlot >= this->GetDeviceCount()) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } + + return pDevSlots->GetDeviceSlotProperty(iDeviceSlot, pCC, sProperty); } else return pCC->CreateError(CONSTLIT("Insufficient arguments")); - return pCC->CreateError(CONSTLIT("Unimplemented function")); } From 471da0a2c439bd24cea0befa4bf3718e2aa003d1 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Thu, 29 Apr 2021 03:03:33 -0400 Subject: [PATCH 06/20] Implement device slot attributes --- Mammoth/Include/TSEDevices.h | 3 +- Mammoth/TSE/CCExtensions.cpp | 4 +-- Mammoth/TSE/CDeviceTable.cpp | 52 +++++++++++++++++++++++++--------- Mammoth/TSE/ShipProperties.cpp | 2 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/Mammoth/Include/TSEDevices.h b/Mammoth/Include/TSEDevices.h index b68f7d3a5..5f1d6c57a 100644 --- a/Mammoth/Include/TSEDevices.h +++ b/Mammoth/Include/TSEDevices.h @@ -481,6 +481,7 @@ struct SDeviceDesc CEnhancementDesc Enhancements; // Slot enhancements to installed device int iSlotBonus = 0; double rShotSeparationScale = 1.; // Governs scaling of shot separation for dual etc weapons + }; class CDeviceDescList @@ -552,7 +553,7 @@ class IDeviceGenerator virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const { return false; }; virtual int GetNumberOfDescs () const { return 1; } virtual const int GetDescIndexGivenId (const CString& sID) const { return -1; } - virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property) const { return pCC->CreateNil(); }; + virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property, const ICCItem* pArgs) const { return pCC->CreateNil(); }; virtual TArray GetDeviceSlotIds() const { return TArray(); } static ALERROR InitDeviceDescFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, SDeviceDesc *retDesc); diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index e05eb9714..f1b8e11e6 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -1227,6 +1227,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = " 'attributes\n" " 'criteria\n" " 'fireArc\n" + " 'hasAttribute\n" " 'maxMass\n" " 'maxPower\n" " 'maxPowerPercent\n" @@ -1235,8 +1236,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = " 'posAngle\n" " 'posCartesian\n" " 'posRadius\n" - " 'secondaryWeapon\n" - " 'targetCriteria\n", + " 'secondaryWeapon\n", "i*s", 0, }, diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index 62927657a..5b3b2d35b 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -3,6 +3,9 @@ // IDeviceGenerator objects #include "PreComp.h" +#include +#include +#include #define DEVICE_TAG CONSTLIT("Device") #define DEVICES_TAG CONSTLIT("Devices") @@ -16,6 +19,7 @@ #define NULL_TAG CONSTLIT("Null") #define TABLE_TAG CONSTLIT("Table") +#define ATTRIBUTES_ATTRIB CONSTLIT("attributes") #define CANNOT_BE_EMPTY_ATTRIB CONSTLIT("cannotBeEmpty") #define CATEGORIES_ATTRIB CONSTLIT("categories") #define CHANCE_ATTRIB CONSTLIT("chance") @@ -57,6 +61,7 @@ #define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("attributes") #define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("criteria") #define PROPERTY_DEVICE_SLOT_FIRE_ARC CONSTLIT("fireArc") +#define PROPERTY_DEVICE_SLOT_HAS_ATTRIBUTE CONSTLIT("hasAttribute") #define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("maxMass") #define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("maxPower") #define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("maxPowerPercent") @@ -66,7 +71,6 @@ #define PROPERTY_DEVICE_SLOT_POS_CARTESIAN CONSTLIT("posCartesian") #define PROPERTY_DEVICE_SLOT_POS_RADIUS CONSTLIT("posRadius") #define PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON CONSTLIT("secondaryWeapon") -#define PROPERTY_DEVICE_SLOT_TARGET_CRITERIA CONSTLIT("targetCriteria") class CNullDevice : public IDeviceGenerator { @@ -205,7 +209,7 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const override; virtual int GetNumberOfDescs () const override { return m_SlotDesc.GetCount(); } virtual const int GetDescIndexGivenId (const CString& sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *m_SlotDescIndicesByID.GetAt(sID) : -1; } - virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property) const override; + virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property, const ICCItem* pArgs) const override; virtual TArray GetDeviceSlotIds() const override { TArray ids; for (int i = 0; i < m_SlotDescIndicesByID.GetCount(); i++) { ids.Insert(m_SlotDescIndicesByID.GetKey(i)); } return ids; } private: @@ -217,6 +221,7 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator struct SSlotDesc { + TSortMap Attributes; CItemCriteria Criteria; SDeviceDesc DefaultDesc; int iMaxCount; @@ -1416,7 +1421,7 @@ const CGroupOfDeviceGenerators::SSlotDesc *CGroupOfDeviceGenerators::FindSlotDes return NULL; } -ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property) const +ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property, const ICCItem* pArgs) const // GetDeviceSlotProperty // @@ -1426,23 +1431,32 @@ ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, const SSlotDesc &Slot = m_SlotDesc[iSlotIndex]; const SDeviceDesc &DefaultDesc = Slot.DefaultDesc; if (Property == PROPERTY_DEVICE_SLOT_ATTRIBUTES) - return pCC->CreateError("Unimplemented function"); + { + ICCItem* pResult = pCC->CreateLinkedList(); + for (int i = 0; i < Slot.Attributes.GetCount(); i++) + { + pResult->Append(pCC->CreateString(Slot.Attributes.GetKey(i))); + } + return pResult; + } else if (Property == PROPERTY_DEVICE_SLOT_CRITERIA) return pCC->CreateString(Slot.Criteria.AsString()); else if (Property == PROPERTY_DEVICE_SLOT_FIRE_ARC) - { + { if (DefaultDesc.bOmnidirectional) return pCC->CreateString(OMNIDIRECTIONAL_ATTRIB); else if (DefaultDesc.iMaxFireArc != DefaultDesc.iMinFireArc) - { + { ICCItem* pResult = pCC->CreateLinkedList(); pResult->Append(pCC->CreateInteger(DefaultDesc.iMinFireArc)); pResult->Append(pCC->CreateInteger(DefaultDesc.iMaxFireArc)); return pResult; - } + } else return (DefaultDesc.iMinFireArc == 0) ? pCC->CreateNil() : pCC->CreateInteger(DefaultDesc.iMinFireArc); - } + } + else if (Property == PROPERTY_DEVICE_SLOT_HAS_ATTRIBUTE) + return pArgs->GetCount() >= 4 ? pCC->CreateBool(Slot.Attributes.Find(pArgs->GetElement(3)->GetStringValue())) : pCC->CreateError("Insufficient arguments"); else if (Property == PROPERTY_DEVICE_SLOT_MAX_MASS) return pCC->CreateInteger(Slot.iMaxMass); else if (Property == PROPERTY_DEVICE_SLOT_MAX_POWER) @@ -1452,27 +1466,25 @@ ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, else if (Property == PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL) return pCC->CreateBool(DefaultDesc.bOmnidirectional); else if (Property == PROPERTY_DEVICE_SLOT_POS) - { + { ICCItem* pResult = pCC->CreateLinkedList(); pResult->Append(pCC->CreateInteger(DefaultDesc.iPosAngle)); pResult->Append(pCC->CreateInteger(DefaultDesc.iPosRadius)); return pResult; - } + } else if (Property == PROPERTY_DEVICE_SLOT_POS_ANGLE) return pCC->CreateInteger(DefaultDesc.iPosAngle); else if (Property == PROPERTY_DEVICE_SLOT_POS_CARTESIAN) - { + { ICCItem* pResult = pCC->CreateLinkedList(); pResult->Append(pCC->CreateInteger(int(sin((DefaultDesc.iPosAngle + 90) * PI / 2.0) * DefaultDesc.iPosRadius))); pResult->Append(pCC->CreateInteger(int(cos((DefaultDesc.iPosAngle + 90) * PI / 2.0) * DefaultDesc.iPosRadius))); return pResult; - } + } else if (Property == PROPERTY_DEVICE_SLOT_POS_RADIUS) return pCC->CreateInteger(DefaultDesc.iPosRadius); else if (Property == PROPERTY_DEVICE_SLOT_SECONDARY_WEAPON) return pCC->CreateBool(DefaultDesc.bSecondary); - else if (Property == PROPERTY_DEVICE_SLOT_TARGET_CRITERIA) - return pCC->CreateInteger("Unimplemented function"); else return pCC->CreateError("Unknown device slot property", pCC->CreateString(Property)); } @@ -1562,6 +1574,18 @@ ALERROR CGroupOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement pSlotDesc->fMaxPowerPercent = pEntry->GetAttributeFloat(MAX_POWER_PERCENT_ATTRIB); pSlotDesc->iMaxMass = pEntry->GetAttributeInteger(MAX_MASS_ATTRIB); + const std::string sAttributes = std::string(pEntry->GetAttribute(ATTRIBUTES_ATTRIB)); + const char cDelimiter = ';'; + + std::istringstream iss (sAttributes); + std::string item; + while (std::getline(iss, item, cDelimiter)) + { + item.erase(std::remove(item.begin(), item.end(), ' '), item.end()); + if (!item.empty()) + pSlotDesc->Attributes.Insert(CString(item.c_str())); + } + if (error = IDeviceGenerator::InitDeviceDescFromXML(Ctx, pEntry, &pSlotDesc->DefaultDesc)) return error; diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index f10e963d2..b4b039b0e 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -288,7 +288,7 @@ ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } - return pDevSlots->GetDeviceSlotProperty(iDeviceSlot, pCC, sProperty); + return pDevSlots->GetDeviceSlotProperty(iDeviceSlot, pCC, sProperty, pArgs); } else return pCC->CreateError(CONSTLIT("Insufficient arguments")); From ee5b643df22b8f78293c48887fc92f8387f9399f Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Thu, 29 Apr 2021 23:57:32 -0400 Subject: [PATCH 07/20] Add support for Description --- Mammoth/Include/TSEDevices.h | 6 +++--- Mammoth/TSE/CCExtensions.cpp | 3 ++- Mammoth/TSE/CDeviceTable.cpp | 13 ++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Mammoth/Include/TSEDevices.h b/Mammoth/Include/TSEDevices.h index 5f1d6c57a..8a66c7b69 100644 --- a/Mammoth/Include/TSEDevices.h +++ b/Mammoth/Include/TSEDevices.h @@ -550,10 +550,10 @@ class IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx& Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc* retDesc) const { return false; }; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const { return false; } virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const { return false; } - virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const { return false; }; + virtual bool ItemFitsSlot (CSpaceObject *pObj, const CItem &Item, const int iSlotIndex) const { return false; }; virtual int GetNumberOfDescs () const { return 1; } - virtual const int GetDescIndexGivenId (const CString& sID) const { return -1; } - virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property, const ICCItem* pArgs) const { return pCC->CreateNil(); }; + virtual const int GetDescIndexGivenId (const CString &sID) const { return -1; } + virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain *pCC, const CString &Property, const ICCItem *pArgs) const { return pCC->CreateNil(); }; virtual TArray GetDeviceSlotIds() const { return TArray(); } static ALERROR InitDeviceDescFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, SDeviceDesc *retDesc); diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index f1b8e11e6..38fb51d02 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -1226,8 +1226,9 @@ static PRIMITIVEPROCDEF g_Extensions[] = "property:\n\n" " 'attributes\n" " 'criteria\n" + " 'description\n" " 'fireArc\n" - " 'hasAttribute\n" + " 'hasAttribute [attribute]\n" " 'maxMass\n" " 'maxPower\n" " 'maxPowerPercent\n" diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index 5b3b2d35b..9de990f7d 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -60,6 +60,7 @@ #define PROPERTY_DEVICE_SLOT_ATTRIBUTES CONSTLIT("attributes") #define PROPERTY_DEVICE_SLOT_CRITERIA CONSTLIT("criteria") +#define PROPERTY_DEVICE_SLOT_DESCRIPTION CONSTLIT("description") #define PROPERTY_DEVICE_SLOT_FIRE_ARC CONSTLIT("fireArc") #define PROPERTY_DEVICE_SLOT_HAS_ATTRIBUTE CONSTLIT("hasAttribute") #define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("maxMass") @@ -206,10 +207,10 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, CSpaceObject* pObj, const CString& sID, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CItem &Item, SDeviceDesc *retDesc) const override; virtual bool FindDefaultDesc (SDeviceGenerateCtx &Ctx, const CDeviceDescList &DescList, const CString &sID, SDeviceDesc *retDesc) const override; - virtual bool ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const override; + virtual bool ItemFitsSlot (CSpaceObject *pObj, const CItem &Item, const int iSlotIndex) const override; virtual int GetNumberOfDescs () const override { return m_SlotDesc.GetCount(); } - virtual const int GetDescIndexGivenId (const CString& sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *m_SlotDescIndicesByID.GetAt(sID) : -1; } - virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property, const ICCItem* pArgs) const override; + virtual const int GetDescIndexGivenId (const CString &sID) const override { return m_SlotDescIndicesByID.Find(sID) ? *m_SlotDescIndicesByID.GetAt(sID) : -1; } + virtual ICCItem* GetDeviceSlotProperty (const int iSlotIndex, CCodeChain *pCC, const CString &Property, const ICCItem *pArgs) const override; virtual TArray GetDeviceSlotIds() const override { TArray ids; for (int i = 0; i < m_SlotDescIndicesByID.GetCount(); i++) { ids.Insert(m_SlotDescIndicesByID.GetKey(i)); } return ids; } private: @@ -1421,7 +1422,7 @@ const CGroupOfDeviceGenerators::SSlotDesc *CGroupOfDeviceGenerators::FindSlotDes return NULL; } -ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, CCodeChain* pCC, const CString& Property, const ICCItem* pArgs) const +ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, CCodeChain *pCC, const CString &Property, const ICCItem *pArgs) const // GetDeviceSlotProperty // @@ -1441,6 +1442,8 @@ ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, } else if (Property == PROPERTY_DEVICE_SLOT_CRITERIA) return pCC->CreateString(Slot.Criteria.AsString()); + else if (Property == PROPERTY_DEVICE_SLOT_DESCRIPTION) + return pCC->CreateString(Slot.Description); else if (Property == PROPERTY_DEVICE_SLOT_FIRE_ARC) { if (DefaultDesc.bOmnidirectional) @@ -1489,7 +1492,7 @@ ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, return pCC->CreateError("Unknown device slot property", pCC->CreateString(Property)); } -bool CGroupOfDeviceGenerators::ItemFitsSlot (CSpaceObject* pObj, const CItem& Item, const int iSlotIndex) const +bool CGroupOfDeviceGenerators::ItemFitsSlot (CSpaceObject *pObj, const CItem &Item, const int iSlotIndex) const // ItemFitsSlot // From 348570c6630b5876718f01f7e4dfd9892d9d337e Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Sat, 5 Jun 2021 04:35:02 -0400 Subject: [PATCH 08/20] Fix problems --- Mammoth/Include/TSE.h | 1 + Mammoth/Include/TSESpaceObjectsImpl.h | 1 + Mammoth/TSE/CCExtensions.cpp | 18 +++++++++++------- Mammoth/TSE/CDeviceSystem.cpp | 7 ++++++- Mammoth/TSE/CShip.cpp | 5 +++-- Mammoth/TSE/CSpaceObject.cpp | 5 +++++ 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Mammoth/Include/TSE.h b/Mammoth/Include/TSE.h index 91e458a85..3bd5b6438 100644 --- a/Mammoth/Include/TSE.h +++ b/Mammoth/Include/TSE.h @@ -637,6 +637,7 @@ class CSpaceObject bool FindDevice (const CItem &Item, CInstalledDevice **retpDevice, CString *retsError); virtual CInstalledDevice *FindDevice (const CItem &Item) { return NULL; } virtual bool FindDeviceSlotDesc (const CItem &Item, SDeviceDesc *retDesc) { return false; } + virtual bool FindDeviceSlotDesc (const CString &ID, SDeviceDesc *retDesc) { return false; } bool FireCanInstallItem (const CItem &Item, const CDeviceSystem::SSlotDesc &Slot, CString *retsResult); bool FireCanRemoveItem (const CItem &Item, int iSlot, CString *retsResult); virtual CInstalledDevice *GetDevice (int iDev) { return NULL; } diff --git a/Mammoth/Include/TSESpaceObjectsImpl.h b/Mammoth/Include/TSESpaceObjectsImpl.h index 920d389ff..88d51ddb6 100644 --- a/Mammoth/Include/TSESpaceObjectsImpl.h +++ b/Mammoth/Include/TSESpaceObjectsImpl.h @@ -1158,6 +1158,7 @@ class CShip : public TSpaceObjectImpl virtual bool FindDataField (const CString &sField, CString *retsValue) override; virtual CInstalledDevice *FindDevice (const CItem &Item) override; virtual bool FindDeviceSlotDesc (const CItem &Item, SDeviceDesc *retDesc) override { return m_pClass->FindDeviceSlotDesc(this, Item, retDesc); } + virtual bool FindDeviceSlotDesc (const CString &ID, SDeviceDesc *retDesc) override { return m_pClass->FindDeviceSlotDesc(this, ID, retDesc); } virtual bool FollowsObjThroughGate (CSpaceObject *pLeader = NULL) override; virtual AbilityStatus GetAbility (Abilities iAbility) const override; virtual int GetAISettingInteger (const CString &sSetting) override { return m_pController->GetAISettingInteger(sSetting); } diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 044003199..3ce1be2fb 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -6926,8 +6926,10 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) if (!Slot.sID.IsBlank()) { - if (!pObj->GetDeviceSystem().FindSlotDesc(Slot.sID)) - return pCC->CreateError(CONSTLIT("Unkown slot ID"), pArgs->GetElement(2)); + CShip* pShip = pObj->AsShip(); + const bool bDeviceSlotExists = bForceUseOfDeviceSlot ? pShip->GetClass()->GetDeviceSlots()->FindDeviceSlot(Slot.sID) : pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); + if (!bDeviceSlotExists) + return pCC->CreateError(CONSTLIT("Unknown slot ID"), pArgs->GetElement(2)); } } @@ -11198,15 +11200,17 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) && (Slot.iIndex < 0 || Slot.iIndex >= pShip->GetDeviceCount() || (!(bForceUseOfDeviceSlot) && pShip->GetDevice(Slot.iIndex)->IsEmpty()))) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } - else if (Slot.iIndex == -1 && bForceUseOfDeviceSlot) + + if (!Slot.sID.IsBlank()) { - return pCC->CreateNil(); + const bool bDeviceSlotExists = bForceUseOfDeviceSlot ? pShip->GetClass()->GetDeviceSlots()->FindDeviceSlot(Slot.sID) : pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); + if (!bDeviceSlotExists) + return pCC->CreateError(CONSTLIT("Unknown slot ID"), pArgs->GetElement(2)); } - if (!Slot.sID.IsBlank()) + else if (Slot.iIndex == -1 && Slot.sID.IsBlank() && bForceUseOfDeviceSlot) { - if (!pShip->GetDeviceSystem().FindSlotDesc(Slot.sID)) - return pCC->CreateError(CONSTLIT("Unkown slot ID"), pArgs->GetElement(2)); + return pCC->CreateNil(); } } diff --git a/Mammoth/TSE/CDeviceSystem.cpp b/Mammoth/TSE/CDeviceSystem.cpp index b780ce4c9..b5fc55a34 100644 --- a/Mammoth/TSE/CDeviceSystem.cpp +++ b/Mammoth/TSE/CDeviceSystem.cpp @@ -778,7 +778,12 @@ bool CDeviceSystem::Install (CSpaceObject *pObj, CItemListManipulator &ItemList, SDeviceDesc Desc; if (Slot.sID) { - FindSlotDesc(Slot.sID, &Desc); + pObj->FindDeviceSlotDesc(Slot.sID, &Desc); + auto pObjAsShip = pObj->AsShip(); + if (Slot.iIndex == -1 && pObjAsShip) + { + iDeviceSlot = pObjAsShip->GetClass()->GetDeviceSlots()->GetDescIndexGivenId(Slot.sID); + } } else { diff --git a/Mammoth/TSE/CShip.cpp b/Mammoth/TSE/CShip.cpp index 512b2bd2d..53516f503 100644 --- a/Mammoth/TSE/CShip.cpp +++ b/Mammoth/TSE/CShip.cpp @@ -1105,6 +1105,7 @@ bool CShip::CanInstallItem (const CItem &Item, const CDeviceSystem::SSlotDesc &S else if (Item.IsDevice()) { CItemCtx ItemCtx(&Item); + int iSlotFromId = pDevSlots->GetDescIndexGivenId(Slot.sID); // Get the item type @@ -1118,7 +1119,7 @@ bool CShip::CanInstallItem (const CItem &Item, const CDeviceSystem::SSlotDesc &S // If we force use of a device slot, and that device slot doesn't fit, then we cannot install - if (bForceUseOfDeviceSlot && !pDevSlots->ItemFitsSlot(this, Item, iSlot)) + if (bForceUseOfDeviceSlot && !pDevSlots->ItemFitsSlot(this, Item, iSlotFromId != -1 ? iSlotFromId : iSlot)) iResult = insNotCompatible; // Ask the object if we can install this item @@ -1128,7 +1129,7 @@ bool CShip::CanInstallItem (const CItem &Item, const CDeviceSystem::SSlotDesc &S // Fire CanBeInstalled to check for custom conditions - else if (!Item.FireCanBeInstalled(this, Slot.iIndex, &sResult)) + else if (!Item.FireCanBeInstalled(this, bForceUseOfDeviceSlot && (iSlotFromId != -1) ? iSlotFromId : Slot.iIndex, &sResult)) iResult = insCannotInstall; // See if the ship's engine core is powerful enough diff --git a/Mammoth/TSE/CSpaceObject.cpp b/Mammoth/TSE/CSpaceObject.cpp index c31973c4f..db30d5f40 100644 --- a/Mammoth/TSE/CSpaceObject.cpp +++ b/Mammoth/TSE/CSpaceObject.cpp @@ -2032,6 +2032,11 @@ bool CSpaceObject::FireCanInstallItem (const CItem &Item, const CDeviceSystem::S const CItem &ItemToReplace = ItemList.GetItemAtCursor(); Ctx.DefineItem(CONSTLIT("aItemToReplace"), ItemToReplace); } + if (AsShip() ? SetCursorAtDevice(ItemList, AsShip()->GetClass()->GetDeviceSlots()->GetDescIndexGivenId(Slot.sID)) : false) + { + const CItem & ItemToReplace = ItemList.GetItemAtCursor(); + Ctx.DefineItem(CONSTLIT("aItemToReplace"), ItemToReplace); + } else Ctx.DefineNil(CONSTLIT("aItemToReplace")); From 7d1b9164cd06735a1d70b654ecc0505a471dffe1 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Sun, 6 Jun 2021 03:06:18 -0400 Subject: [PATCH 09/20] Fix bugs with device slot IDs, and some possible crashes --- Mammoth/Include/TSEShipSystems.h | 3 ++- Mammoth/TSE/CCExtensions.cpp | 8 ++++---- Mammoth/TSE/CDeviceSystem.cpp | 25 ++++++++++++++++--------- Mammoth/TSE/CDeviceTable.cpp | 2 -- Mammoth/TSE/CShip.cpp | 16 +++++++++++----- Mammoth/TSE/CSpaceObject.cpp | 2 +- Mammoth/TSUI/CWeaponHUDDefault.cpp | 2 +- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/Mammoth/Include/TSEShipSystems.h b/Mammoth/Include/TSEShipSystems.h index bf319890d..ea6d4fd30 100644 --- a/Mammoth/Include/TSEShipSystems.h +++ b/Mammoth/Include/TSEShipSystems.h @@ -201,10 +201,11 @@ class CDeviceSystem int GetCountByID (const CString &sID) const; CInstalledDevice &GetDevice (int iIndex) { return *m_Devices[iIndex]; } CDeviceItem GetDeviceItem (int iIndex) const { if (!m_Devices[iIndex]->IsEmpty()) return m_Devices[iIndex]->GetItem()->AsDeviceItem(); else return CItem().AsDeviceItem(); } + const IDeviceGenerator *GetSlots() const { return m_pSlots; } const CInstalledDevice &GetDevice (int iIndex) const { return *m_Devices[iIndex]; } const CInstalledDevice *GetNamedDevice (DeviceNames iDev) const { if (HasNamedDevices() && m_NamedDevices[iDev] != -1) return &GetDevice(m_NamedDevices[iDev]); else return NULL; } CInstalledDevice *GetNamedDevice (DeviceNames iDev) { if (HasNamedDevices() && m_NamedDevices[iDev] != -1) return &GetDevice(m_NamedDevices[iDev]); else return NULL; } - CDeviceItem GetNamedDeviceItem (DeviceNames iDev) const { if (HasNamedDevices() && m_NamedDevices[iDev] != -1) return GetDevice(m_NamedDevices[iDev]).GetItem()->AsDeviceItem(); else return CItem().AsDeviceItem(); } + CDeviceItem GetNamedDeviceItem (DeviceNames iDev) const { if (HasNamedDevices() && m_NamedDevices[iDev] != -1 && GetDevice(m_NamedDevices[iDev]).GetItem()) return GetDevice(m_NamedDevices[iDev]).GetItem()->AsDeviceItem(); else return CItem().AsDeviceItem(); } int GetNamedIndex (DeviceNames iDev) const { return (HasNamedDevices() ? m_NamedDevices[iDev] : -1); } DWORD GetTargetTypes (void) const; bool HasNamedDevices (void) const { return (m_NamedDevices.GetCount() > 0); } diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 3ce1be2fb..6f14b7977 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -6920,14 +6920,14 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) return pCC->CreateError(CONSTLIT("Invalid armor segment"), pArgs->GetElement(2)); if (Item.IsDevice() && pShip - && (Slot.iIndex < 0 || Slot.iIndex >= pShip->GetDeviceCount() || (!(bForceUseOfDeviceSlot) && pShip->GetDevice(Slot.iIndex)->IsEmpty()))) + && (Slot.iIndex < 0 || Slot.iIndex >= pShip->GetDeviceCount())) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } if (!Slot.sID.IsBlank()) { CShip* pShip = pObj->AsShip(); - const bool bDeviceSlotExists = bForceUseOfDeviceSlot ? pShip->GetClass()->GetDeviceSlots()->FindDeviceSlot(Slot.sID) : pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); + const bool bDeviceSlotExists = pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); if (!bDeviceSlotExists) return pCC->CreateError(CONSTLIT("Unknown slot ID"), pArgs->GetElement(2)); } @@ -11197,13 +11197,13 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) if (Slot.iIndex != -1) { if (Item.IsDevice() - && (Slot.iIndex < 0 || Slot.iIndex >= pShip->GetDeviceCount() || (!(bForceUseOfDeviceSlot) && pShip->GetDevice(Slot.iIndex)->IsEmpty()))) + && (Slot.iIndex < 0 || Slot.iIndex >= pShip->GetDeviceCount())) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } if (!Slot.sID.IsBlank()) { - const bool bDeviceSlotExists = bForceUseOfDeviceSlot ? pShip->GetClass()->GetDeviceSlots()->FindDeviceSlot(Slot.sID) : pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); + const bool bDeviceSlotExists = pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); if (!bDeviceSlotExists) return pCC->CreateError(CONSTLIT("Unknown slot ID"), pArgs->GetElement(2)); } diff --git a/Mammoth/TSE/CDeviceSystem.cpp b/Mammoth/TSE/CDeviceSystem.cpp index b5fc55a34..8b5d673c4 100644 --- a/Mammoth/TSE/CDeviceSystem.cpp +++ b/Mammoth/TSE/CDeviceSystem.cpp @@ -758,11 +758,19 @@ bool CDeviceSystem::Install (CSpaceObject *pObj, CItemListManipulator &ItemList, int iDeviceSlot = Slot.iIndex; if (iDeviceSlot == -1) { - iDeviceSlot = FindFreeSlot(); - if (iDeviceSlot == -1) + auto pObjAsShip = pObj->AsShip(); + if (!Slot.sID.IsBlank() && pObjAsShip) { - ASSERT(false); - return false; + iDeviceSlot = pObjAsShip->GetClass()->GetDeviceSlots()->GetDescIndexGivenId(Slot.sID); + } + else + { + iDeviceSlot = FindFreeSlot(); + if (iDeviceSlot == -1) + { + ASSERT(false); + return false; + } } } @@ -779,11 +787,6 @@ bool CDeviceSystem::Install (CSpaceObject *pObj, CItemListManipulator &ItemList, if (Slot.sID) { pObj->FindDeviceSlotDesc(Slot.sID, &Desc); - auto pObjAsShip = pObj->AsShip(); - if (Slot.iIndex == -1 && pObjAsShip) - { - iDeviceSlot = pObjAsShip->GetClass()->GetDeviceSlots()->GetDescIndexGivenId(Slot.sID); - } } else { @@ -1013,6 +1016,10 @@ void CDeviceSystem::ReadFromStream (SLoadCtx &Ctx, CSpaceObject *pObj) if (Ctx.dwVersion < 29) m_Devices[i]->SetDeviceSlot(i); } + + CShip *pObjAsShip = pObj->AsShip(); + if (pObjAsShip) + m_pSlots = pObjAsShip->GetClass()->GetDeviceSlots(); } void CDeviceSystem::ReadyFirstMissile (CSpaceObject *pObj) diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index 522c69f79..4ae3eeb16 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -289,8 +289,6 @@ ALERROR IDeviceGenerator::InitDeviceDescFromXML (SDesignLoadCtx &Ctx, CXMLElemen // InitDeviceDescFromXML // // Loads a device desc from XML. -// TODO(heliogenesis): Add support for attribute list, weapon target definition, and description, and possibly max mass? -// See https://discord.com/channels/265561663741100043/265561663741100043/823740088294703156 { ALERROR error; diff --git a/Mammoth/TSE/CShip.cpp b/Mammoth/TSE/CShip.cpp index 53516f503..3b26e6a14 100644 --- a/Mammoth/TSE/CShip.cpp +++ b/Mammoth/TSE/CShip.cpp @@ -430,7 +430,9 @@ void CShip::CalcDeviceBonus (void) for (CDeviceItem DeviceItem : GetDeviceSystem()) { - CInstalledDevice &Device = *DeviceItem.GetInstalledDevice(); + CInstalledDevice *pDevice = DeviceItem.GetInstalledDevice(); + if (!pDevice) continue; + CInstalledDevice &Device = *pDevice; CItemCtx ItemCtx(this, &Device); // Keep track of device types to see if we have duplicates @@ -461,7 +463,9 @@ void CShip::CalcDeviceBonus (void) for (CDeviceItem OtherDevItem : GetDeviceSystem()) { - CInstalledDevice &OtherDev = *OtherDevItem.GetInstalledDevice(); + CInstalledDevice *pOtherDev = OtherDevItem.GetInstalledDevice(); + if (!pOtherDev) continue; + CInstalledDevice &OtherDev = *pOtherDev; if (OtherDev.GetDeviceSlot() != Device.GetDeviceSlot()) { // See if this device enhances us @@ -511,7 +515,9 @@ void CShip::CalcDeviceBonus (void) for (CDeviceItem DeviceItem : GetDeviceSystem()) { - CInstalledDevice &Device = *DeviceItem.GetInstalledDevice(); + CInstalledDevice *pDevice = DeviceItem.GetInstalledDevice(); + if (!pDevice) continue; + CInstalledDevice &Device = *pDevice; int *pCount = DeviceTypes.GetAt(Device.GetClass()->GetUNID()); Device.SetDuplicate(*pCount > 1); @@ -1029,7 +1035,7 @@ bool CShip::CanInstallItem (const CItem &Item, const CDeviceSystem::SSlotDesc &S CString sResult; CItem ItemToReplace; const CHullDesc &Hull = m_pClass->GetHullDesc(); - const IDeviceGenerator *pDevSlots = GetClass()->GetDeviceSlots(); + const IDeviceGenerator *pDevSlots = GetDeviceSystem().GetSlots(); int iSlot = Slot.iIndex; @@ -1129,7 +1135,7 @@ bool CShip::CanInstallItem (const CItem &Item, const CDeviceSystem::SSlotDesc &S // Fire CanBeInstalled to check for custom conditions - else if (!Item.FireCanBeInstalled(this, bForceUseOfDeviceSlot && (iSlotFromId != -1) ? iSlotFromId : Slot.iIndex, &sResult)) + else if (!Item.FireCanBeInstalled(this, Slot.iIndex, &sResult)) iResult = insCannotInstall; // See if the ship's engine core is powerful enough diff --git a/Mammoth/TSE/CSpaceObject.cpp b/Mammoth/TSE/CSpaceObject.cpp index db30d5f40..c7060cef2 100644 --- a/Mammoth/TSE/CSpaceObject.cpp +++ b/Mammoth/TSE/CSpaceObject.cpp @@ -2032,7 +2032,7 @@ bool CSpaceObject::FireCanInstallItem (const CItem &Item, const CDeviceSystem::S const CItem &ItemToReplace = ItemList.GetItemAtCursor(); Ctx.DefineItem(CONSTLIT("aItemToReplace"), ItemToReplace); } - if (AsShip() ? SetCursorAtDevice(ItemList, AsShip()->GetClass()->GetDeviceSlots()->GetDescIndexGivenId(Slot.sID)) : false) + if (AsShip() ? SetCursorAtDevice(ItemList, AsShip()->GetDeviceSystem().GetSlots()->GetDescIndexGivenId(Slot.sID)) : false) { const CItem & ItemToReplace = ItemList.GetItemAtCursor(); Ctx.DefineItem(CONSTLIT("aItemToReplace"), ItemToReplace); diff --git a/Mammoth/TSUI/CWeaponHUDDefault.cpp b/Mammoth/TSUI/CWeaponHUDDefault.cpp index 8e937cb50..af7f78b22 100644 --- a/Mammoth/TSUI/CWeaponHUDDefault.cpp +++ b/Mammoth/TSUI/CWeaponHUDDefault.cpp @@ -149,7 +149,7 @@ void CWeaponHUDDefault::PaintDeviceStatus (CShip *pShip, DeviceNames iDev, int x const CG16bitFont &LargeBoldFont = VI.GetFont(fontLargeBold); CInstalledDevice *pDevice = pShip->GetNamedDevice(iDev); - if (pDevice) + if (pDevice && pDevice->GetClass()) { CItemCtx ItemCtx(pShip, pDevice); CDeviceClass *pClass = pDevice->GetClass(); From 82ee475151524a2786cb0696ebeaef571c4fd8df Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Sun, 6 Jun 2021 03:25:54 -0400 Subject: [PATCH 10/20] Clean up and fix compile errors --- Mammoth/TSE/CCExtensions.cpp | 2 +- Mammoth/TSE/CDeviceSystem.cpp | 6 +----- Mammoth/TSE/ShipProperties.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 14babab13..29f139f74 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -10646,7 +10646,7 @@ ICCItem *fnShipGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) case FN_SHIP_DEV_SLOT_IDS: { - TArray ids = pShip->GetClass()->GetDeviceSlots()->GetDeviceSlotIds(); + TArray ids = pShip->GetDeviceSystem().GetSlots()->GetDeviceSlotIds(); ICCItem* pIDs = pCC->CreateLinkedList(); for (int i = 0; i < ids.GetCount(); i++) pIDs->AppendString(ids[i]); diff --git a/Mammoth/TSE/CDeviceSystem.cpp b/Mammoth/TSE/CDeviceSystem.cpp index fe4ce5378..30d0187f7 100644 --- a/Mammoth/TSE/CDeviceSystem.cpp +++ b/Mammoth/TSE/CDeviceSystem.cpp @@ -758,7 +758,7 @@ bool CDeviceSystem::Install (CSpaceObject *pObj, CItemListManipulator &ItemList, auto pObjAsShip = pObj->AsShip(); if (!Slot.sID.IsBlank() && pObjAsShip) { - iDeviceSlot = pObjAsShip->GetClass()->GetDeviceSlots()->GetDescIndexGivenId(Slot.sID); + iDeviceSlot = pObjAsShip->GetDeviceSystem().GetSlots()->GetDescIndexGivenId(Slot.sID); } else { @@ -1016,10 +1016,6 @@ void CDeviceSystem::ReadFromStream (SLoadCtx &Ctx, CSpaceObject *pObj, const IDe if (Ctx.dwVersion < 29) m_Devices[i]->SetDeviceSlot(i); } - - CShip *pObjAsShip = pObj->AsShip(); - if (pObjAsShip) - m_pSlots = pObjAsShip->GetClass()->GetDeviceSlots(); } void CDeviceSystem::ReadyFirstMissile (CSpaceObject *pObj) diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index 5381cbc97..d4aa5c74d 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -276,15 +276,15 @@ ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const if (pArgs->GetCount() >= 3) { CString sProperty = pArgs->GetElement(2)->GetStringValue(); - IDeviceGenerator* pDevSlots = this->GetClass().GetDeviceSlots(); + const IDeviceGenerator *pDevSlots = this->GetDeviceSystem().GetSlots(); int numSlots = pDevSlots->GetNumberOfDescs(); - ICCItem* pOptions = pArgs->GetElement(1); + ICCItem *pOptions = pArgs->GetElement(1); if (pOptions->IsInteger()) iDeviceSlot = pOptions->GetIntegerValue(); else { - ICCItem* pDeviceSlot = pOptions->GetElement(FIELD_DEVICE_SLOT); - ICCItem* pDeviceSlotID = pOptions->GetElement(FIELD_SLOT_ID); + ICCItem *pDeviceSlot = pOptions->GetElement(FIELD_DEVICE_SLOT); + ICCItem *pDeviceSlotID = pOptions->GetElement(FIELD_SLOT_ID); if (pDeviceSlot && !pDeviceSlot->IsNil()) iDeviceSlot = pDeviceSlot->GetIntegerValue(); From 03a349422464da65a0979d87a81e2cf4ca229ae2 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Mon, 7 Jun 2021 01:30:22 -0400 Subject: [PATCH 11/20] Remove forceUseOfDeviceSlot from shpInstallDevice --- Mammoth/TSE/CCExtensions.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 29f139f74..13d1e3a66 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -1321,7 +1321,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = "ivi", PPFLAG_SIDEEFFECTS, }, { "shpInstallDevice", fnShipSet, FN_SHIP_INSTALL_DEVICE, - "(shpInstallDevice ship item [deviceSlot] [forceUseOfDeviceSlot]) -> itemStruct (or Nil)\n\n" + "(shpInstallDevice ship item [deviceSlot]) -> itemStruct (or Nil)\n\n" "deviceSlot can be an int or struct with these parameters:\n\n" " deviceSlot: device slot number\n" @@ -11186,7 +11186,6 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) return pCC->CreateNil(); // See if we passed in a device slot - bool bForceUseOfDeviceSlot = pArgs->GetCount() >= 4 ? !(pArgs->GetElement(3)->IsNil()) : false; CDeviceSystem::SSlotDesc Slot; if (pArgs->GetCount() > 2) { @@ -11208,11 +11207,6 @@ ICCItem *fnShipSet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) if (!bDeviceSlotExists) return pCC->CreateError(CONSTLIT("Unknown slot ID"), pArgs->GetElement(2)); } - - else if (Slot.iIndex == -1 && Slot.sID.IsBlank() && bForceUseOfDeviceSlot) - { - return pCC->CreateNil(); - } } // Otherwise, install or remove From c9c3a5aad0afdc1f97efa760eb97420ab83a90dc Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Wed, 6 Oct 2021 01:37:37 -0400 Subject: [PATCH 12/20] Add functions to get device slot given device, or device given device slot --- Mammoth/TSE/CCExtensions.cpp | 2 ++ Mammoth/TSE/Devices.cpp | 4 ++++ Mammoth/TSE/ShipProperties.cpp | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 4b2004d75..3439fca39 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -1238,6 +1238,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = " 'attributes\n" " 'criteria\n" " 'description\n" + " 'deviceAtSlot\n" " 'fireArc\n" " 'hasAttribute [attribute]\n" " 'maxMass\n" @@ -2246,6 +2247,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = "property (device)\n\n" " 'capacitor\n" + " 'deviceSlotID\n" " 'enabled\n" " 'linkedFireOptions\n" " 'pos\n" diff --git a/Mammoth/TSE/Devices.cpp b/Mammoth/TSE/Devices.cpp index 1438de0f5..3598a054c 100644 --- a/Mammoth/TSE/Devices.cpp +++ b/Mammoth/TSE/Devices.cpp @@ -42,6 +42,7 @@ #define PROPERTY_CAPACITOR CONSTLIT("capacitor") #define PROPERTY_CYBER_DEFENSE_LEVEL CONSTLIT("cyberDefenseLevel") #define PROPERTY_CYCLE_FIRE CONSTLIT("cycleFire") +#define PROPERTY_DEVICE_SLOT_ID CONSTLIT("deviceSlotID") #define PROPERTY_DEVICE_SLOTS CONSTLIT("deviceSlots") #define PROPERTY_ENABLED CONSTLIT("enabled") #define PROPERTY_EXTERNAL CONSTLIT("external") @@ -549,6 +550,9 @@ ICCItem *CDeviceClass::FindItemProperty (CItemCtx &Ctx, const CString &sName) else if (strEquals(sName, PROPERTY_CYCLE_FIRE)) return (pDevice ? CC.CreateBool(pDevice->GetCycleFireSettings()) : CC.CreateNil()); + else if (strEquals(sName, PROPERTY_DEVICE_SLOT_ID)) + return (pDevice ? CC.CreateString(pDevice->GetID()) : CC.CreateNil()); + else if (strEquals(sName, PROPERTY_DEVICE_SLOTS)) return CC.CreateInteger(GetSlotsRequired()); diff --git a/Mammoth/TSE/ShipProperties.cpp b/Mammoth/TSE/ShipProperties.cpp index e086162d8..c687b0094 100644 --- a/Mammoth/TSE/ShipProperties.cpp +++ b/Mammoth/TSE/ShipProperties.cpp @@ -29,6 +29,7 @@ #define PROPERTY_CHARACTER_NAME CONSTLIT("characterName") #define PROPERTY_DEVICE_DAMAGE_IMMUNE CONSTLIT("deviceDamageImmune") #define PROPERTY_DEVICE_DISRUPT_IMMUNE CONSTLIT("deviceDisruptImmune") +#define PROPERTY_DEVICE_AT_SLOT CONSTLIT("deviceAtSlot") #define PROPERTY_DEVICE_SLOT_IDS CONSTLIT("deviceSlotIDs") #define PROPERTY_DISINTEGRATION_IMMUNE CONSTLIT("disintegrationImmune") #define PROPERTY_DOCKED_AT_ID CONSTLIT("dockedAtID") @@ -312,6 +313,11 @@ ICCItem* CShip::GetDeviceSlotProperty(CCodeChain* pCC, CCodeChainCtx& Ctx, const return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); } + if (strEquals(sProperty, PROPERTY_DEVICE_AT_SLOT)) + { + return CreateListFromItem(m_Devices.GetDevice(iDeviceSlot).GetDeviceItem()); + } + return pDevSlots->GetDeviceSlotProperty(iDeviceSlot, pCC, sProperty, pArgs); } else From 0cd9361bced2aea5817b2985d34a8837dbcee319 Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Wed, 6 Oct 2021 02:27:18 -0400 Subject: [PATCH 13/20] Add NAME attribute to device slots --- Mammoth/TSE/CDeviceTable.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mammoth/TSE/CDeviceTable.cpp b/Mammoth/TSE/CDeviceTable.cpp index 4ae3eeb16..314951c0e 100644 --- a/Mammoth/TSE/CDeviceTable.cpp +++ b/Mammoth/TSE/CDeviceTable.cpp @@ -50,6 +50,7 @@ #define MAX_POWER_ATTRIB CONSTLIT("maxPower") #define MAX_POWER_PERCENT_ATTRIB CONSTLIT("maxPowerPercentage") #define MISSILE_DEFENSE_ATTRIB CONSTLIT("missileDefense") +#define NAME_ATTRIB CONSTLIT("name") #define OMNIDIRECTIONAL_ATTRIB CONSTLIT("omnidirectional") #define SECONDARY_WEAPON_ATTRIB CONSTLIT("secondaryWeapon") #define SEGMENT_ID_ATTRIB CONSTLIT("segmentID") @@ -66,6 +67,7 @@ #define PROPERTY_DEVICE_SLOT_MAX_MASS CONSTLIT("maxMass") #define PROPERTY_DEVICE_SLOT_MAX_POWER CONSTLIT("maxPower") #define PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT CONSTLIT("maxPowerPercent") +#define PROPERTY_DEVICE_SLOT_NAME CONSTLIT("name") #define PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL CONSTLIT("omnidirectional") #define PROPERTY_DEVICE_SLOT_POS CONSTLIT("pos") #define PROPERTY_DEVICE_SLOT_POS_ANGLE CONSTLIT("posAngle") @@ -231,6 +233,7 @@ class CGroupOfDeviceGenerators : public IDeviceGenerator int iMaxCount; int iMaxMass = -1; CString Description; + CString Name; int iMaxPower = -1; Metric fMaxPowerPercent = -1.0; }; @@ -1506,6 +1509,8 @@ ICCItem* CGroupOfDeviceGenerators::GetDeviceSlotProperty (const int iSlotIndex, return pCC->CreateInteger(Slot.iMaxPower); else if (Property == PROPERTY_DEVICE_SLOT_MAX_POWER_PERCENT) return pCC->CreateDouble(Slot.fMaxPowerPercent); + else if (Property == PROPERTY_DEVICE_SLOT_NAME) + return pCC->CreateString(Slot.Name); else if (Property == PROPERTY_DEVICE_SLOT_OMNIDIRECTIONAL) return pCC->CreateBool(DefaultDesc.bOmnidirectional); else if (Property == PROPERTY_DEVICE_SLOT_POS) @@ -1613,6 +1618,7 @@ ALERROR CGroupOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement pSlotDesc->Criteria.Init(pEntry->GetAttribute(CRITERIA_ATTRIB)); pSlotDesc->Description = pEntry->GetAttribute(DESCRIPTION_ATTRIB); + pSlotDesc->Name = pEntry->GetAttribute(NAME_ATTRIB); pSlotDesc->iMaxPower = pEntry->GetAttributeInteger(MAX_POWER_ATTRIB); pSlotDesc->fMaxPowerPercent = pEntry->GetAttributeFloat(MAX_POWER_PERCENT_ATTRIB); pSlotDesc->iMaxMass = pEntry->GetAttributeInteger(MAX_MASS_ATTRIB); From 6a4bcb5865026eb5dc80b74279c49e6c8198009f Mon Sep 17 00:00:00 2001 From: Bryon Leung Date: Thu, 28 Oct 2021 03:38:48 -0400 Subject: [PATCH 14/20] Replace forceUseOfDeviceSlot with API version check; allow rpgInstallDevicePrep to check slot IDs --- Mammoth/Include/TSEVersions.h | 2 +- Mammoth/TSE/CCExtensions.cpp | 6 ++++-- Transcendence/TransCore/RPGCode.xml | 4 ++++ Transcendence/TransCore/Transcendence.xml | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Mammoth/Include/TSEVersions.h b/Mammoth/Include/TSEVersions.h index 1c60ca40b..b1d950cf7 100644 --- a/Mammoth/Include/TSEVersions.h +++ b/Mammoth/Include/TSEVersions.h @@ -5,7 +5,7 @@ #pragma once -constexpr DWORD API_VERSION = 53; +constexpr DWORD API_VERSION = 54; constexpr DWORD UNIVERSE_SAVE_VERSION = 40; constexpr DWORD SYSTEM_SAVE_VERSION = 211; diff --git a/Mammoth/TSE/CCExtensions.cpp b/Mammoth/TSE/CCExtensions.cpp index 21dca1e17..0a2973e26 100644 --- a/Mammoth/TSE/CCExtensions.cpp +++ b/Mammoth/TSE/CCExtensions.cpp @@ -1647,7 +1647,7 @@ static PRIMITIVEPROCDEF g_Extensions[] = "ii", 0, }, { "objCanInstallItem", fnObjGet, FN_OBJ_CAN_INSTALL_ITEM, - "(objCanInstallItem obj item [armorSeg|deviceSlot] [forceUseOfDeviceSlot]) -> (True/Nil resultCode resultString [itemToReplace])\n\n" + "(objCanInstallItem obj item [armorSeg|deviceSlot]) -> (True/Nil resultCode resultString [itemToReplace])\n\n" "resultCode\n\n" @@ -6974,7 +6974,7 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) return pCC->CreateError(CONSTLIT("Invalid item"), pArgs->GetElement(1)); CDeviceSystem::SSlotDesc Slot; - bool bForceUseOfDeviceSlot = pArgs->GetCount() > 3 ? !(pArgs->GetElement(3)->IsNil()) : false; + bool bForceUseOfDeviceSlot = false; if (pArgs->GetCount() > 2) { if (!CTLispConvert::AsSlotDesc(*pArgs->GetElement(2), Slot)) @@ -6995,6 +6995,7 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) && pShip && (Slot.iIndex < 0 || Slot.iIndex >= pShip->GetDeviceCount())) return pCC->CreateError(CONSTLIT("Invalid device slot"), pArgs->GetElement(2)); + bForceUseOfDeviceSlot = pCtx->GetAPIVersion() >= 54; } if (!Slot.sID.IsBlank()) @@ -7003,6 +7004,7 @@ ICCItem *fnObjGet (CEvalContext *pEvalCtx, ICCItem *pArgs, DWORD dwData) const bool bDeviceSlotExists = pShip->GetDeviceSystem().FindSlotDesc(Slot.sID); if (!bDeviceSlotExists) return pCC->CreateError(CONSTLIT("Unknown slot ID"), pArgs->GetElement(2)); + bForceUseOfDeviceSlot = pCtx->GetAPIVersion() >= 54; } } diff --git a/Transcendence/TransCore/RPGCode.xml b/Transcendence/TransCore/RPGCode.xml index 3a1a2445f..3e5a8e7e6 100644 --- a/Transcendence/TransCore/RPGCode.xml +++ b/Transcendence/TransCore/RPGCode.xml @@ -1860,6 +1860,7 @@ ; noCargoCheck: If True, then we don't check to see if the old device fits in cargo ; replaceItem: If not Nil, we try to replace this device. ; showActualItem: Show true item, even if unknown to player. + ; slotID: If not Nil, we try to install in the device slot with the specified ID. ; targetObj: Object on which to install (if Nil, we assume player ship) ; techCriteria: If not Nil, the item must match this criteria ; techCriteriaOverride: If not Nil, and item matches this criteria, install even if above maxTechLevel @@ -1953,6 +1954,9 @@ ) (recommendedSlot (switch + (@ data 'slotID) + {slotID : (@ data 'slotID)} + (not (@ data 'replaceItem)) -1 diff --git a/Transcendence/TransCore/Transcendence.xml b/Transcendence/TransCore/Transcendence.xml index 570331161..6d36ce297 100644 --- a/Transcendence/TransCore/Transcendence.xml +++ b/Transcendence/TransCore/Transcendence.xml @@ -104,7 +104,7 @@ ]>