From f749bac35788f1cb72aefb07717d01ec132ab902 Mon Sep 17 00:00:00 2001 From: Omar Aglan Date: Tue, 28 Jul 2026 12:48:14 +0300 Subject: [PATCH] unify(worldbuilder): Add Generals compatibility prerequisites --- .../Include/Common/MapReaderWriterInfo.h | 1 + .../GameEngine/Include/Common/ThingTemplate.h | 5 ++ .../GameEngine/Include/Common/WellKnownKeys.h | 72 +++++++++++++++++++ .../Include/GameLogic/PolygonTrigger.h | 12 ++++ .../Source/GameLogic/Map/PolygonTrigger.cpp | 18 ++++- 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/Generals/Code/GameEngine/Include/Common/MapReaderWriterInfo.h b/Generals/Code/GameEngine/Include/Common/MapReaderWriterInfo.h index c370ac5b3c0..6496fb891bb 100644 --- a/Generals/Code/GameEngine/Include/Common/MapReaderWriterInfo.h +++ b/Generals/Code/GameEngine/Include/Common/MapReaderWriterInfo.h @@ -48,6 +48,7 @@ #define K_TRIGGERS_VERSION_1 1 #define K_TRIGGERS_VERSION_2 2 // Added m_isWaterArea #define K_TRIGGERS_VERSION_3 3 // Added m_isRiver & m_riverStart +#define K_TRIGGERS_VERSION_4 4 // Added layer name. #define K_LIGHTING_VERSION_1 1 #define K_LIGHTING_VERSION_2 2 // Added 2 additional global lights for objects. #define K_LIGHTING_VERSION_3 3 // Added 2 additional global lights for terrain. diff --git a/Generals/Code/GameEngine/Include/Common/ThingTemplate.h b/Generals/Code/GameEngine/Include/Common/ThingTemplate.h index a2a5847e6d2..4a27a19838f 100644 --- a/Generals/Code/GameEngine/Include/Common/ThingTemplate.h +++ b/Generals/Code/GameEngine/Include/Common/ThingTemplate.h @@ -431,6 +431,7 @@ class ThingTemplate : public Overridable // Only Object can ask this. Everyone else should ask the Object. In fact, you really should ask the Object everything. Real friend_getVisionRange() const { return m_visionRange; } ///< get vision range + Real friend_calcVisionRange() const { return m_visionRange; } ///< WorldBuilder compatibility alias Real friend_getShroudClearingRange() const { return m_shroudClearingRange; } ///< get vision range for Shroud ONLY (Design requested split) // This function is only for use by the AIUpdateModuleData::parseLocomotorSet function. @@ -505,6 +506,8 @@ class ThingTemplate : public Overridable const AudioEventRTS *getSoundPromotedHero() const { return getAudio(TTAUDIO_soundPromotedHero); } const AudioEventRTS *getSoundFalling() const { return getAudio(TTAUDIO_soundFalling); } + Bool hasSoundAmbient() const { return m_audioarray.m_audio[TTAUDIO_soundAmbient] != nullptr; } + const AudioEventRTS *getPerUnitSound(const AsciiString& soundName) const; const FXList* getPerUnitFX(const AsciiString& fxName) const; @@ -610,6 +613,8 @@ class ThingTemplate : public Overridable AsciiString getUpgradeCameoName( Int n)const{ return m_upgradeCameoUpgradeNames[n]; } + const WeaponTemplateSetVector& getWeaponTemplateSets() const {return m_weaponTemplateSets;} + protected: // diff --git a/Generals/Code/GameEngine/Include/Common/WellKnownKeys.h b/Generals/Code/GameEngine/Include/Common/WellKnownKeys.h index 67cacd62e22..ff1277b478b 100644 --- a/Generals/Code/GameEngine/Include/Common/WellKnownKeys.h +++ b/Generals/Code/GameEngine/Include/Common/WellKnownKeys.h @@ -712,6 +712,78 @@ DEFINE_KEY(objectGrantUpgrade) */ DEFINE_KEY(uniqueID) +/** + Which: MapObject Properties + Type: AsciiString + Usage: What ambient sound does this object have attached to it? + Missing means "Use the default sound for object type from INI" + Blank means "No ambient sound" +*/ +DEFINE_KEY(objectSoundAmbient) + +/** + Which: MapObject Properties + Type: Bool + Usage: Does the ambient sound have customized flags & properties? Blank or false - use INI parameters for sound +*/ +DEFINE_KEY(objectSoundAmbientCustomized) + +/** + Which: MapObject Properties + Type: Bool + Usage: Does the ambient sound start off playing? + Blank -- use default of true for looping sounds, false for non-looping sounds +*/ +DEFINE_KEY(objectSoundAmbientEnabled) + +/** + Which: MapObject Properties + Type: Bool + Usage: Does the ambient sound loop? Blank -- use default for sound +*/ +DEFINE_KEY(objectSoundAmbientLooping) + +/** + Which: MapObject Properties + Type: Int + Usage: How many times does the sound loop (0 = forever)? Blank - use default for sound +*/ +DEFINE_KEY(objectSoundAmbientLoopCount) + +/** + Which: MapObject Properties + Type: Real + Usage: Minimum volume of sound. Blank - use default for sound +*/ +DEFINE_KEY(objectSoundAmbientMinVolume) + +/** + Which: MapObject Properties + Type: Real + Usage: Base volume of sound. Blank - use default for sound +*/ +DEFINE_KEY(objectSoundAmbientVolume) + +/** + Which: MapObject Properties + Type: Real + Usage: Minimum range of sound. Within this area, sound plays at full volume. Blank - use default for sound +*/ +DEFINE_KEY(objectSoundAmbientMinRange) + +/** + Which: MapObject Properties + Type: Real + Usage: Maximum range of sound. Sound drops to zero at this range Blank - use default for sound +*/ +DEFINE_KEY(objectSoundAmbientMaxRange) + +/** + Which: MapObject Properties + Type: Int + Usage: Priority of sound using the enum AudioPriority Blank - use default for sound +*/ +DEFINE_KEY(objectSoundAmbientPriority) // --------------------------------------------------------------------------------------- // well-known keys in Player dicts. diff --git a/Generals/Code/GameEngine/Include/GameLogic/PolygonTrigger.h b/Generals/Code/GameEngine/Include/GameLogic/PolygonTrigger.h index d3e133834fc..c2abfe51688 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/PolygonTrigger.h +++ b/Generals/Code/GameEngine/Include/GameLogic/PolygonTrigger.h @@ -81,6 +81,9 @@ class PolygonTrigger : public MemoryPoolObject, Bool m_exportWithScripts; Bool m_isWaterArea; ///< Used to specify water areas in the map. Bool m_isRiver; ///< Used to specify that a water area is a river. + AsciiString m_layerName; ///< Used to specify the layer in the World Builder. + Bool m_shouldRender; + Bool m_selected; static PolygonTrigger* ThePolygonTriggerListPtr; static Int s_currentID; ///< Current id for new triggers. @@ -116,6 +119,15 @@ class PolygonTrigger : public MemoryPoolObject, void deletePoint(Int ndx); void setTriggerName(AsciiString name) {m_triggerName = name;}; + void setLayerName(AsciiString name) {m_layerName = name;}; + AsciiString getLayerName() const {return m_layerName;} + + void setShouldRender(Bool toggle) {m_shouldRender = toggle;} + Bool getShouldRender() const {return m_shouldRender;} + + void setSelected(Bool toggle) {m_selected = toggle;} + Bool getSelected() const {return m_selected;} + void getCenterPoint(Coord3D* pOutCoord) const; Real getRadius() const; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp b/Generals/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp index 6cea7c6227a..0129556aad6 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp @@ -48,6 +48,8 @@ m_numPoints(0), m_sizePoints(0), m_exportWithScripts(false), m_isWaterArea(false), +m_shouldRender(true), +m_selected(false), m_isRiver(FALSE), m_riverStart(0) { @@ -140,6 +142,7 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu Bool isRiver; Int riverStart; AsciiString triggerName; + AsciiString layerName; // Remove any existing polygon triggers, if any. PolygonTrigger::deleteTriggers(); // just in case. PolygonTrigger *pPrevTrig = nullptr; @@ -148,6 +151,9 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu while (count>0) { count--; triggerName = file.readAsciiString(); + if (info->version >= K_TRIGGERS_VERSION_4) { + layerName = file.readAsciiString(); + } triggerID = file.readInt(); isWater = false; if (info->version >= K_TRIGGERS_VERSION_2) { @@ -163,6 +169,9 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu numPoints = file.readInt(); PolygonTrigger *pTrig = newInstance(PolygonTrigger)(numPoints+1); pTrig->setTriggerName(triggerName); + if (info->version >= K_TRIGGERS_VERSION_4) { + pTrig->setLayerName(layerName); + } pTrig->setWaterArea(isWater); pTrig->setRiver(isRiver); pTrig->setRiverStart(riverStart); @@ -177,6 +186,12 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu loc.z = file.readInt(); pTrig->addPoint(loc); } + if (numPoints < 2) { + DEBUG_LOG(("Deleting polygon trigger '%s' with %d points.", + pTrig->getTriggerName().str(), numPoints)); + deleteInstance(pTrig); + continue; + } if (pPrevTrig) { pPrevTrig->setNextPoly(pTrig); } else { @@ -224,7 +239,7 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu */ void PolygonTrigger::WritePolygonTriggersDataChunk(DataChunkOutput &chunkWriter) { - chunkWriter.openDataChunk("PolygonTriggers", K_TRIGGERS_VERSION_3); + chunkWriter.openDataChunk("PolygonTriggers", K_TRIGGERS_VERSION_4); PolygonTrigger *pTrig; Int count = 0; @@ -234,6 +249,7 @@ void PolygonTrigger::WritePolygonTriggersDataChunk(DataChunkOutput &chunkWriter) chunkWriter.writeInt(count); for (pTrig=PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { chunkWriter.writeAsciiString(pTrig->getTriggerName()); + chunkWriter.writeAsciiString(pTrig->getLayerName()); chunkWriter.writeInt(pTrig->getID()); chunkWriter.writeByte(pTrig->isWaterArea()); chunkWriter.writeByte(pTrig->isRiver());