diff --git a/Core/GameEngine/Include/Common/GameDefines.h b/Core/GameEngine/Include/Common/GameDefines.h index 7a6f4be4d11..165287ba38d 100644 --- a/Core/GameEngine/Include/Common/GameDefines.h +++ b/Core/GameEngine/Include/Common/GameDefines.h @@ -95,6 +95,10 @@ #define RETAIL_COMPATIBLE_XFER_SAVE (1) // Game is expected to be Xfer Save compatible with retail Generals 1.08, Zero Hour 1.04 #endif +#ifndef RETAIL_COMPATIBLE_WORLDBUILDER +#define RETAIL_COMPATIBLE_WORLDBUILDER (1) // WorldBuilder output is expected to remain readable by retail tools +#endif + // This is here to easily toggle between the retail compatible with fixed pathfinding fallback and pure fixed pathfinding mode #ifndef RETAIL_COMPATIBLE_PATHFINDING #define RETAIL_COMPATIBLE_PATHFINDING (1) 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..e666eab1825 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); @@ -224,7 +233,12 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu */ void PolygonTrigger::WritePolygonTriggersDataChunk(DataChunkOutput &chunkWriter) { +#if RETAIL_COMPATIBLE_WORLDBUILDER && RTS_GENERALS + // TheSuperHackers @info OmarAglan 30/07/2026 Retail Generals expects version 3 and does not read polygon trigger layer names. chunkWriter.openDataChunk("PolygonTriggers", K_TRIGGERS_VERSION_3); +#else + chunkWriter.openDataChunk("PolygonTriggers", K_TRIGGERS_VERSION_4); +#endif PolygonTrigger *pTrig; Int count = 0; @@ -234,6 +248,9 @@ void PolygonTrigger::WritePolygonTriggersDataChunk(DataChunkOutput &chunkWriter) chunkWriter.writeInt(count); for (pTrig=PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { chunkWriter.writeAsciiString(pTrig->getTriggerName()); +#if !(RETAIL_COMPATIBLE_WORLDBUILDER && RTS_GENERALS) + chunkWriter.writeAsciiString(pTrig->getLayerName()); +#endif chunkWriter.writeInt(pTrig->getID()); chunkWriter.writeByte(pTrig->isWaterArea()); chunkWriter.writeByte(pTrig->isRiver()); @@ -480,7 +497,7 @@ const WaterHandle* PolygonTrigger::getWaterHandle() const Bool PolygonTrigger::isValid() const { - if (m_numPoints == 0) { + if (m_numPoints < 2) { return FALSE; } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp index 00386047267..9f09848ba60 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp @@ -1640,7 +1640,8 @@ PolygonTrigger *TerrainLogic::getTriggerAreaByName( AsciiString name ) { for (PolygonTrigger* pTrig = PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { const AsciiString& trigName = pTrig->getTriggerName(); - if (name == trigName) + // TheSuperHackers @info OmarAglan 30/07/2026 Retain invalid triggers for snapshot compatibility, but do not expose them as usable areas. + if (name == trigName && pTrig->isValid()) return pTrig; } return nullptr; diff --git a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt index 1a65bb55d3d..24fbc8605a0 100644 --- a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt @@ -60,6 +60,8 @@ set(WORLDBUILDER_SRC "src/RampTool.cpp" "src/RoadOptions.cpp" "src/RoadTool.cpp" + "src/RulerOptions.cpp" + "src/RulerTool.cpp" "src/SaveMap.cpp" "src/ScorchOptions.cpp" "src/ScorchTool.cpp" @@ -75,6 +77,7 @@ set(WORLDBUILDER_SRC "src/TeamBehavior.cpp" "src/TeamGeneric.cpp" "src/TeamIdentity.cpp" + "src/TeamObjectProperties.cpp" "src/TeamReinforcement.cpp" "src/teamsdialog.cpp" "src/TerrainMaterial.cpp" @@ -156,6 +159,8 @@ set(WORLDBUILDER_SRC "include/RampTool.h" "include/RoadOptions.h" "include/RoadTool.h" + "include/RulerOptions.h" + "include/RulerTool.h" "include/SaveMap.h" "include/ScorchOptions.h" "include/ScorchTool.h" @@ -171,6 +176,7 @@ set(WORLDBUILDER_SRC "include/TeamBehavior.h" "include/TeamGeneric.h" "include/TeamIdentity.h" + "include/TeamObjectProperties.h" "include/TeamReinforcement.h" "include/teamsdialog.h" "include/TerrainMaterial.h" @@ -184,6 +190,7 @@ set(WORLDBUILDER_SRC "include/WaypointTool.h" "include/WBFrameWnd.h" "include/WBHeightMap.h" + "include/WBPopupSlider.h" "include/wbview.h" "include/wbview3d.h" "include/WHeightMapEdit.h" diff --git a/Generals/Code/Tools/WorldBuilder/include/CUndoable.h b/Generals/Code/Tools/WorldBuilder/include/CUndoable.h index e136336dac1..14504e31bc4 100644 --- a/Generals/Code/Tools/WorldBuilder/include/CUndoable.h +++ b/Generals/Code/Tools/WorldBuilder/include/CUndoable.h @@ -384,3 +384,27 @@ class DeletePolygonUndoable : public Undoable virtual void Do() override; virtual void Undo() override; }; + +/// MultipleUndoable +/** + * An undoable that doesn't do anything; it just consolidates a number of other + * Undoables in a single logical undo step. + */ +class MultipleUndoable : public Undoable +{ +protected: + Undoable * m_undoableList; //< The head of the list of undoables, in the order they should be done. Reverse order for undoes +public: + MultipleUndoable(); + // destructor. + virtual ~MultipleUndoable() override; + + /** Add other undoables in the order you would want them UNdone; e.g. in the reverse order you want them done + * The MultipleUndoable object will then own the pointers. + */ + void addUndoable( Undoable * undoable ); + + virtual void Do() override; + virtual void Undo() override; + virtual void Redo() override; +}; diff --git a/Generals/Code/Tools/WorldBuilder/include/CameraOptions.h b/Generals/Code/Tools/WorldBuilder/include/CameraOptions.h index f336a35c636..69d4536df02 100644 --- a/Generals/Code/Tools/WorldBuilder/include/CameraOptions.h +++ b/Generals/Code/Tools/WorldBuilder/include/CameraOptions.h @@ -53,6 +53,8 @@ class CameraOptions : public CDialog, public PopupSliderOwner // Generated message map functions //{{AFX_MSG(CameraOptions) afx_msg void OnCameraReset(); + afx_msg void OnDropWaypointButton(); + afx_msg void OnCenterOnSelectedButton(); afx_msg void OnMove(int x, int y); virtual BOOL OnInitDialog() override; afx_msg void OnChangePitchEdit(); diff --git a/Generals/Code/Tools/WorldBuilder/include/DrawObject.h b/Generals/Code/Tools/WorldBuilder/include/DrawObject.h index f1416d97e0b..3a7681a3a99 100644 --- a/Generals/Code/Tools/WorldBuilder/include/DrawObject.h +++ b/Generals/Code/Tools/WorldBuilder/include/DrawObject.h @@ -34,6 +34,8 @@ class MeshClass; class PolygonTrigger; class WaterRenderObjClass; +class MapObject; +class Render2DClass; // // DrawObject: Draws 3d feedback for tools & objects. // @@ -77,12 +79,14 @@ class DrawObject : public RenderObjClass // void Set_Flag(unsigned int flag, Bool onoff) { Flags &= (~flag); if (onoff) Flags |= flag; } Int freeMapResources(); + int initData(); - void setDrawObjects(Bool val, Bool waypoints, Bool poly) { m_drawObjects = val; m_drawWaypoints=waypoints; m_drawPolygonAreas = poly;} + void setDrawObjects(Bool val, Bool waypoints, Bool poly, Bool bounding, Bool sight, Bool weapon, Bool sound, Bool testart, Bool letterbox) { m_drawObjects = val; m_drawWaypoints=waypoints; m_drawPolygonAreas = poly; m_drawBoundingBoxes = bounding; m_drawSightRanges = sight; m_drawWeaponRanges = weapon; m_drawSoundRanges = sound; m_drawTestArtHighlight = testart, m_drawLetterbox = letterbox;} static void setDoBrushFeedback(Bool val) { m_toolWantsFeedback = val; m_meshFeedback=false;} static void setDoMeshFeedback(Bool val) { m_meshFeedback = val; } static void setDoRampFeedback(Bool val) { m_rampFeedback = val; } static void setDoBoundaryFeedback(Bool val) { m_boundaryFeedback = val; } + static void setDoAmbientSoundFeedback(Bool val) { m_ambientSoundFeedback = val; } static void setBrushFeedbackParms(Bool square, Int width, Int featherWidth) @@ -122,6 +126,12 @@ class DrawObject : public RenderObjClass Bool m_drawObjects; Bool m_drawWaypoints; Bool m_drawPolygonAreas; + Bool m_drawBoundingBoxes; + Bool m_drawSightRanges; + Bool m_drawWeaponRanges; + Bool m_drawSoundRanges; + Bool m_drawTestArtHighlight; + Bool m_drawLetterbox; DX8VertexBufferClass *m_vertexFeedback; ///< Vertex buffer for brush feedback. DX8IndexBufferClass *m_indexFeedback; ///< indices defining a triangle strip for the feedback on terrain @@ -132,6 +142,8 @@ class DrawObject : public RenderObjClass MeshClass *m_moldMesh; ///< W3D mesh model for the mold. SphereClass m_moldMeshBounds; ///< Bounding sphere for mold mesh. + Render2DClass *m_lineRenderer; //< Used to render 2D lines for bounding boxes. + CPoint m_winSize; //< Holds the size of the window. protected: // static state vars. static Bool m_squareFeedback; ///< True for square brush feedback, false for round. @@ -155,7 +167,7 @@ class DrawObject : public RenderObjClass static Real m_rampWidth; protected: - int initData(); + void addCircleToLineRenderer( const Coord3D & center, Real radius, Real width, unsigned long color, CameraClass* camera ); Int updateVB(DX8VertexBufferClass *vertexBufferTile, Int color, Bool doArrow, Bool doDiamond); void updatePolygonVB(PolygonTrigger *pTrig, Bool selected, Bool isOpen); void updateFeedbackVB(); @@ -165,6 +177,12 @@ class DrawObject : public RenderObjClass void updateForWater(); void updateBoundaryVB(); void updateAmbientSoundVB(); + void updateVBWithBoundingBox(MapObject *pMapObj, CameraClass* camera); + void updateVBWithSightRange(MapObject *pMapObj, CameraClass* camera); + void updateVBWithWeaponRange(MapObject *pMapObj, CameraClass* camera); + void updateVBWithTestArtHighlight(MapObject *pMapObj, CameraClass* camera); + void updateVBWithSoundRanges(MapObject *pMapObj, CameraClass* camera); + bool worldToScreen(const Coord3D *w, ICoord2D *s, CameraClass* camera); }; diff --git a/Generals/Code/Tools/WorldBuilder/include/EditAction.h b/Generals/Code/Tools/WorldBuilder/include/EditAction.h index cfae6a683bd..35f6791fdb5 100644 --- a/Generals/Code/Tools/WorldBuilder/include/EditAction.h +++ b/Generals/Code/Tools/WorldBuilder/include/EditAction.h @@ -62,6 +62,7 @@ class EditAction : public CDialog CRichEditCtrl m_myEditCtrl; CHARRANGE m_curLinkChrg; Int m_curEditParameter; + CTreeCtrl m_actionTreeView; protected: diff --git a/Generals/Code/Tools/WorldBuilder/include/EditCondition.h b/Generals/Code/Tools/WorldBuilder/include/EditCondition.h index cbd29f3282e..c1db7fcc661 100644 --- a/Generals/Code/Tools/WorldBuilder/include/EditCondition.h +++ b/Generals/Code/Tools/WorldBuilder/include/EditCondition.h @@ -24,6 +24,13 @@ class Condition; class SidesList; + +class CMyTreeCtrl : public CTreeCtrl +{ +public: + virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam ) override; +}; + ///////////////////////////////////////////////////////////////////////////// // EditCondition dialog @@ -61,6 +68,7 @@ class EditCondition : public CDialog CRichEditCtrl m_myEditCtrl; CHARRANGE m_curLinkChrg; Int m_curEditParameter; + CTreeCtrl m_conditionTreeView; protected: diff --git a/Generals/Code/Tools/WorldBuilder/include/EditObjectParameter.h b/Generals/Code/Tools/WorldBuilder/include/EditObjectParameter.h index 901d64d2744..dfc5de76bb5 100644 --- a/Generals/Code/Tools/WorldBuilder/include/EditObjectParameter.h +++ b/Generals/Code/Tools/WorldBuilder/include/EditObjectParameter.h @@ -44,6 +44,7 @@ friend class EditParameter; //{{AFX_VIRTUAL(EditObjectParameter) protected: virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV support + virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) override; //}}AFX_VIRTUAL // Implementation diff --git a/Generals/Code/Tools/WorldBuilder/include/EditParameter.h b/Generals/Code/Tools/WorldBuilder/include/EditParameter.h index 02172ec544d..05d5813fe62 100644 --- a/Generals/Code/Tools/WorldBuilder/include/EditParameter.h +++ b/Generals/Code/Tools/WorldBuilder/include/EditParameter.h @@ -50,8 +50,8 @@ class EditParameter : public CDialog // Implementation public: - static Int edit( Parameter *pParm, AsciiString unitName = AsciiString::TheEmptyString ); - static AsciiString getWarningText(Parameter *pParm); + static Int edit( Parameter *pParm, Int keyPressed, AsciiString unitName = AsciiString::TheEmptyString ); + static AsciiString getWarningText(Parameter *pParm, Bool isAction); static AsciiString getInfoText(Parameter *pParm); static void setCurSidesList(SidesList *sidesListP) {m_sidesListP = sidesListP;}; static Bool loadScripts(CComboBox *pCombo, Bool subr, AsciiString match = AsciiString::TheEmptyString); @@ -93,10 +93,10 @@ class EditParameter : public CDialog static Bool loadEmoticons( CComboBox *pCombo, AsciiString match = AsciiString::TheEmptyString ); static AsciiString getCreatedUnitTemplateName(AsciiString unitName); - void loadCounters(CComboBox *pCombo); - void loadConditionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo); - void loadActionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo); - void loadFlags(CComboBox *pCombo); + static Bool loadCounters(CComboBox *pCombo, AsciiString match = AsciiString::TheEmptyString); + static void loadConditionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo); + static Bool loadActionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo, AsciiString match); + static Bool loadFlags(CComboBox *pCombo, AsciiString match = AsciiString::TheEmptyString); protected: @@ -106,11 +106,15 @@ class EditParameter : public CDialog Int m_int; Real m_real; + Int m_key; // key pressed to invoke the edit parameter dialog. + static SidesList *m_sidesListP; static AsciiString m_selectedLocalizedString; protected: + Bool scanReal(CEdit *pEdit, Real scale); +protected: // Generated message map functions //{{AFX_MSG(EditParameter) afx_msg void OnChangeEdit(); diff --git a/Generals/Code/Tools/WorldBuilder/include/ExportScriptsOptions.h b/Generals/Code/Tools/WorldBuilder/include/ExportScriptsOptions.h index c78869d01ae..9a9f97d2aeb 100644 --- a/Generals/Code/Tools/WorldBuilder/include/ExportScriptsOptions.h +++ b/Generals/Code/Tools/WorldBuilder/include/ExportScriptsOptions.h @@ -50,12 +50,14 @@ class ExportScriptsOptions : public CDialog static Bool m_waypoints; static Bool m_triggers; static Bool m_allScripts; + static Bool m_sides; public: Bool getDoUnits() {return m_units;} Bool getDoWaypoints() {return m_waypoints;} Bool getDoTriggers() {return m_triggers;} Bool getDoAllScripts() {return m_allScripts;} + Bool getDoSides() {return m_sides;} protected: diff --git a/Generals/Code/Tools/WorldBuilder/include/LayersList.h b/Generals/Code/Tools/WorldBuilder/include/LayersList.h index 6f4079a6026..09df1a03795 100644 --- a/Generals/Code/Tools/WorldBuilder/include/LayersList.h +++ b/Generals/Code/Tools/WorldBuilder/include/LayersList.h @@ -42,15 +42,20 @@ // FORWARD DECLARATIONS /////////////////////////////////////////////////////// class MapObject; +class PolygonTrigger; // TYPE DEFINES /////////////////////////////////////////////////////////////// typedef std::list ListMapObjectPtr; typedef ListMapObjectPtr::iterator ListMapObjectPtrIt; +typedef std::list ListPolygonTriggerPtr; +typedef ListPolygonTriggerPtr::iterator ListPolygonTriggerPtrIt; + struct Layer { AsciiString layerName; ListMapObjectPtr objectsInLayer; + ListPolygonTriggerPtr polygonTriggersInLayer; Bool show; }; @@ -86,9 +91,12 @@ class LayersList : public CDialog void resetLayers(); void addMapObjectToLayersList(IN MapObject *objToAdd, AsciiString layerToAddTo = AsciiString(TheDefaultLayerName.c_str())); + void addPolygonTriggerToLayersList(IN PolygonTrigger *triggerToAdd, AsciiString layerToAddTo = AsciiString(TheDefaultLayerName.c_str())); AsciiString removeMapObjectFromLayersList(IN MapObject *objToRemove); + AsciiString removePolygonTriggerFromLayersList(IN PolygonTrigger *triggerToRemove); void changeMapObjectLayer(IN MapObject *objToChange, AsciiString layerToPlaceOn); + void changePolygonTriggerLayer(IN PolygonTrigger *triggerToChange, AsciiString layerToPlaceOn); void addLayerNamed(IN AsciiString layerToAdd); void removeLayerNamed(IN AsciiString layerToRemove); @@ -105,29 +113,40 @@ class LayersList : public CDialog const ListLayer& GetAllLayers() const { return mLayers; } static MapObject *findObjectByUID(AsciiString objectIDToFind); + static PolygonTrigger *findPolygonTriggerByUID(AsciiString objectIDToFind); + static Bool findAndSelectMapObject(AsciiString selectedItemAsciiString); + static Bool findAndSelectPolygonTrigger(AsciiString selectedItemAsciiString); + static void unselectAllMapObjects(); + static void unselectAllPolygonTriggers(); + + public: + // This is a string because making it an AsciiString makes us barf on construction. :-( + static std::string TheDefaultLayerName; + static std::string ThePolygonTriggerLayerName; + static std::string TheDefaultNewLayerName; + static std::string TheActiveLayerName; + static const std::string TheUnmutableDefaultLayerName; protected: AsciiString mCurrentlyEditingLabel; + ListLayer mLayers; CLLTreeCtrl *mTree; CImageList mImageList; Bool m_performUpdates; + Bool m_activatedLayer; HTREEITEM findTreeLayerNamed(const AsciiString& nameToFind); HTREEITEM findTreeObjectNamed(const AsciiString& objectToFind, HTREEITEM layerItem); - // This is a string because making it an AsciiString makes us barf on construction. :-( - static std::string TheDefaultLayerName; - static std::string TheDefaultNewLayerName; - static const std::string TheUnmutableDefaultLayerName; - // This function takes an MapObject, and does one of the following: // 1) Return true if the MapObject can be found, and // layerIt points to a valid layer iterator in which the MapObject was found // MapObjectIt points to a valid MapObject iterator on the layerIts MapObjectsInLayer member // 2) Returns false if the MapObject cannot be found. Bool findMapObjectAndList(IN MapObject *MapObjectToFind, OUT ListLayerIt *layerIt = nullptr, OUT ListMapObjectPtrIt *MapObjectIt = nullptr); + Bool findPolygonTriggerAndList(IN PolygonTrigger *PolygonTriggerToFind, OUT ListLayerIt *layerIt = nullptr, OUT ListPolygonTriggerPtrIt *PolygonTriggerIt = nullptr); // This function takes a layer name, and does one of the following: // 1) Return true if the layer can be found, and @@ -136,7 +155,11 @@ class LayersList : public CDialog Bool findLayerNamed(IN AsciiString layerName, OUT ListLayerIt *layerIt = nullptr); void addMapObjectToLayer(IN MapObject *objToAdd, IN ListLayerIt *layerIt); + void addPolygonTriggerToLayer(IN PolygonTrigger *objToAdd, IN ListLayerIt *layerIt); void removeMapObjectFromLayer(IN MapObject *objToRemove, IN ListLayerIt *layerIt = nullptr, IN ListMapObjectPtrIt *MapObjectIt = nullptr); + void removePolygonTriggerFromLayer(IN PolygonTrigger *triggerToRemove, IN ListLayerIt *layerIt = nullptr, IN ListPolygonTriggerPtrIt *PolygonTriggerIt = nullptr); + void updateObjectRenderFlags(IN ListLayerIt *layerIt); + void updateTreeImages(); protected: virtual void OnOK() override; @@ -149,8 +172,10 @@ class LayersList : public CDialog afx_msg void OnMergeLayer(UINT commandID); afx_msg void OnMergeObject(UINT commandID); afx_msg void OnMergeViewSelection(UINT commandID); + afx_msg void OnSelectActiveLayer(); + afx_msg void OnSelectLayerObject(); afx_msg void OnNewLayer(); afx_msg void OnDeleteLayer(); afx_msg void OnHideShowLayer(); diff --git a/Generals/Code/Tools/WorldBuilder/include/MainFrm.h b/Generals/Code/Tools/WorldBuilder/include/MainFrm.h index bc37892cf45..a6919a15296 100644 --- a/Generals/Code/Tools/WorldBuilder/include/MainFrm.h +++ b/Generals/Code/Tools/WorldBuilder/include/MainFrm.h @@ -45,12 +45,13 @@ #include "CameraOptions.h" #include "ScorchOptions.h" #include "BuildList.h" +#include "RulerOptions.h" #define TWO_D_WINDOW_SECTION "TwoDWindow" #define MAIN_FRAME_SECTION "MainFrame" class LayersList; - +class ScriptDialog; class CMainFrame : public CFrameWnd { @@ -87,6 +88,7 @@ class CMainFrame : public CFrameWnd void adjustWindowSize(); Bool isAutoSaving() {return m_autoSaving;}; void handleCameraChange(); + void onEditScripts(); protected: // control bar embedded members CStatusBar m_wndStatusBar; @@ -113,7 +115,8 @@ class CMainFrame : public CFrameWnd GlobalLightOptions m_globalLightOptions; CameraOptions m_cameraOptions; LayersList* m_layersList; - + ScriptDialog* m_scriptDialog; + RulerOptions m_rulerOptions; CWnd *m_curOptions; Int m_curOptionsX; diff --git a/Generals/Code/Tools/WorldBuilder/include/RulerOptions.h b/Generals/Code/Tools/WorldBuilder/include/RulerOptions.h new file mode 100644 index 00000000000..359a24fbf23 --- /dev/null +++ b/Generals/Code/Tools/WorldBuilder/include/RulerOptions.h @@ -0,0 +1,73 @@ +/* +** Command & Conquer Generals(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#pragma once + +// RulerOptions.h : header file +// +#include "OptionsPanel.h" + +///////////////////////////////////////////////////////////////////////////// +// RulerOptions dialog + +class RulerOptions : public COptionsPanel +{ + +// Construction +public: + + RulerOptions(CWnd* pParent = nullptr); // standard constructor + +// Dialog Data + //{{AFX_DATA(RulerOptions) + enum { IDD = IDD_RULER_OPTIONS }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(RulerOptions) + protected: + virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV support + virtual void OnOK() override {return;}; //!< Modeless dialogs don't OK, so eat this for modeless. + virtual void OnCancel() override {return;}; //!< Modeless dialogs don't close on ESC, so eat this for modeless. + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(RulerOptions) + virtual BOOL OnInitDialog() override; + afx_msg void OnChangeWidthEdit(); + afx_msg void OnChangeCheckRuler(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +protected: + static RulerOptions *m_staticThis; ///< Reference to the floating panel so SetWidth and SetFeather can be static. + + Bool m_updating; ///. +*/ + +// RulerTool.h +// Author: Mike Lytle, January 2003 + +#pragma once + +#include "Tool.h" + +class RulerTool : public Tool +{ +protected: + Coord3D m_downPt3d; + int m_rulerType; + WbView* m_View; + Real m_savedLength; + + static RulerTool* m_staticThis; + +public: + RulerTool(); + virtual ~RulerTool() override; + +public: + /// Clear the selection on activate or deactivate. + virtual void activate() override; + virtual void deactivate() override; + + virtual void setCursor() override; + virtual void mouseDown(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldBuilderDoc *pDoc) override; + virtual void mouseMoved(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldBuilderDoc *pDoc) override; + virtual Bool followsTerrain() override {return false;}; + + static void setLength(Real length); + static Bool switchType(); + static int getType(); + static Real getLength(); + +}; diff --git a/Generals/Code/Tools/WorldBuilder/include/ScriptDialog.h b/Generals/Code/Tools/WorldBuilder/include/ScriptDialog.h index 34737b5c09a..34fed5d5729 100644 --- a/Generals/Code/Tools/WorldBuilder/include/ScriptDialog.h +++ b/Generals/Code/Tools/WorldBuilder/include/ScriptDialog.h @@ -80,9 +80,13 @@ class ScriptDialog : public CDialog // Implementation public: - static void updateWarnings(); + static void updateWarnings(Bool forceUpdate=false); static void updateScriptWarning(Script *pScript); + static void patchScriptParametersForGC(Script *pScript); + static void checkParametersForGC(); + + /// To allow CSDTreeCtrl access to these member functions of ScriptDialog Script *friend_getCurScript(); ScriptGroup *friend_getCurGroup(); @@ -94,6 +98,8 @@ class ScriptDialog : public CDialog static ScriptDialog *m_staticThis; CSDTreeCtrl *mTree; Bool m_draggingTreeView; + Bool m_autoUpdateWarnings; ///< flag whether we should updateWarnings on script editor actions. + HTREEITEM m_dragItem; MapObject *m_firstReadObject; @@ -138,6 +144,9 @@ class ScriptDialog : public CDialog afx_msg void OnEditScript(); afx_msg void OnCopyScript(); afx_msg void OnDelete(); + afx_msg void OnVerify(); + afx_msg void OnPatchGC(); + afx_msg void OnAutoVerify(); afx_msg void OnSave(); afx_msg void OnLoad(); afx_msg void OnDblclkScriptTree(NMHDR* pNMHDR, LRESULT* pResult); diff --git a/Generals/Code/Tools/WorldBuilder/include/TeamObjectProperties.h b/Generals/Code/Tools/WorldBuilder/include/TeamObjectProperties.h new file mode 100644 index 00000000000..ef787ccc338 --- /dev/null +++ b/Generals/Code/Tools/WorldBuilder/include/TeamObjectProperties.h @@ -0,0 +1,106 @@ +/* +** Command & Conquer Generals(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +// TeamObjectProperties.h +// Mike Lytle +// January, 2003 +// (c) Electronic Arts 2003 + +#pragma once + +#include "resource.h" + +// Forward declarations. +class Dict; + + +// External Defines + +class TeamObjectProperties : public CPropertyPage +{ +// Construction +public: + TeamObjectProperties(Dict* dictToEdit = nullptr); + virtual ~TeamObjectProperties() override; + +// Dialog Data + //{{AFX_DATA(MapObjectProps) + enum { IDD = IDD_TeamObjectProperties }; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(TeamObjectProperties) + protected: + virtual void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV support + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) override; + //}}AFX_VIRTUAL + +// Implementation +protected: + Dict* m_dictToEdit; + +#if 0 // Keys not implemented yet. jba. [3/26/2003]// + void updateTheUI(void); + + // Generated message map functions + //{{AFX_MSG(TeamObjectProperties) + virtual BOOL OnInitDialog(); + virtual void OnOK(); + afx_msg void _HealthToDict(void); + afx_msg void _EnabledToDict(void); + afx_msg void _IndestructibleToDict(void); + afx_msg void _UnsellableToDict(void); + afx_msg void _PoweredToDict(void); + afx_msg void _AggressivenessToDict(void); + afx_msg void _VisibilityToDict(void); + afx_msg void _VeterancyToDict(void); + afx_msg void _ShroudClearingDistanceToDict(void); + afx_msg void _RecruitableAIToDict(void); + afx_msg void _SelectableToDict(void); + afx_msg void _WeatherToDict(void); + afx_msg void _TimeToDict(void); + afx_msg void _HPsToDict(); + afx_msg void _StoppingDistanceToDict(void); + afx_msg void _UpdateTeamMembers(void); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() + + void _DictToHealth(void); + void _DictToHPs(void); + void _DictToEnabled(void); + void _DictToDestructible(void); + void _DictToUnsellable(void); + void _DictToPowered(void); + void _DictToAggressiveness(void); + void _DictToVisibilityRange(void); + void _DictToVeterancy(void); + void _DictToShroudClearingDistance(void); + void _DictToRecruitableAI(); + void _DictToSelectable(void); + void _DictToWeather(void); + void _DictToTime(void); + void _DictToStoppingDistance(void); + void _PropertiesToDict(void); +#endif +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. diff --git a/Generals/Code/Tools/WorldBuilder/include/WBHeightMap.h b/Generals/Code/Tools/WorldBuilder/include/WBHeightMap.h index b680e82bbdf..25f8565876b 100644 --- a/Generals/Code/Tools/WorldBuilder/include/WBHeightMap.h +++ b/Generals/Code/Tools/WorldBuilder/include/WBHeightMap.h @@ -18,9 +18,14 @@ #pragma once +#include "W3DDevice/GameClient/FlatHeightMap.h" #include "W3DDevice/GameClient/HeightMap.h" - +#define USE_FLAT_HEIGHT_MAP 0 // Use the original height map for mission disk. jba. [4/15/2003] +#if USE_FLAT_HEIGHT_MAP +class WBHeightMap : public FlatHeightMapRenderObjClass +#else class WBHeightMap : public HeightMapRenderObjClass +#endif { public: diff --git a/Generals/Code/Tools/WorldBuilder/include/WHeightMapEdit.h b/Generals/Code/Tools/WorldBuilder/include/WHeightMapEdit.h index e923b87c432..e12dd2bc508 100644 --- a/Generals/Code/Tools/WorldBuilder/include/WHeightMapEdit.h +++ b/Generals/Code/Tools/WorldBuilder/include/WHeightMapEdit.h @@ -137,8 +137,8 @@ class WorldHeightMapEdit : public WorldHeightMap void showTileStatusInfo(); ///< pops up a dialog box with tile mem usage. - Bool selectDuplicates(); ///< Selects any dupicate map objects. - Bool selectSimilar(); ///< Selects any dupicate map objects. + Bool selectDuplicates(); ///< Selects any duplicate map objects. + Bool selectSimilar(); ///< Selects any duplicate map objects. Bool selectInvalidTeam(); ///< Selects any objects with invalid teams. Bool resize(Int newXSize, Int newYSize, Int newHeight, Int newBorder, Bool anchorTop, Bool anchorBottom, diff --git a/Generals/Code/Tools/WorldBuilder/include/WorldBuilder.h b/Generals/Code/Tools/WorldBuilder/include/WorldBuilder.h index d4d4d90cf57..4585e9b4b76 100644 --- a/Generals/Code/Tools/WorldBuilder/include/WorldBuilder.h +++ b/Generals/Code/Tools/WorldBuilder/include/WorldBuilder.h @@ -51,6 +51,7 @@ #include "BuildListTool.h" #include "RampTool.h" #include "ScorchTool.h" +#include "RulerTool.h" #include "Common/Debug.h" ///////////////////////////////////////////////////////////////////////////// @@ -93,7 +94,7 @@ class CWorldBuilderApp : public CWinApp protected: - enum {NUM_VIEW_TOOLS=24}; + enum {NUM_VIEW_TOOLS=25}; Tool *m_tools[NUM_VIEW_TOOLS]; ///< array of tool pointers. Tool *m_curTool; ///< Currently active tool. @@ -122,6 +123,7 @@ class CWorldBuilderApp : public CWinApp RampTool m_rampTool; ///< Ramp tool. ScorchTool m_scorchTool; ///< Scorch tool. BorderTool m_borderTool; ///< Border tool. + RulerTool m_rulerTool; ///< Ruler tool. Int m_lockCurTool; @@ -154,7 +156,7 @@ class CWorldBuilderApp : public CWinApp /// Set the tool that will be active. void setActiveTool(Tool *newTool); - /// Sets the current directry for file opens. + /// Sets the current directory for file opens. void setCurrentDirectory(AsciiString dir) {m_currentDirectory = dir;}; Tool *getCurTool() { return m_curTool; } diff --git a/Generals/Code/Tools/WorldBuilder/include/mapobjectprops.h b/Generals/Code/Tools/WorldBuilder/include/mapobjectprops.h index 2f15bcf5fa6..d1b92acd143 100644 --- a/Generals/Code/Tools/WorldBuilder/include/mapobjectprops.h +++ b/Generals/Code/Tools/WorldBuilder/include/mapobjectprops.h @@ -27,6 +27,9 @@ class MapObject; class ModifyObjectUndoable; +class MultipleUndoable; +class CWorldBuilderDoc; +class MapObject; ///////////////////////////////////////////////////////////////////////////// // External Defines @@ -65,35 +68,62 @@ class MapObjectProps : public COptionsPanel, public PopupSliderOwner static MapObjectProps *TheMapObjectProps; + // Data common to all property pages Dict* m_dictToEdit; std::vector m_allSelectedDicts; const char* m_title; MapObject *m_selectedObject; + MapObject *m_dictSource; // Source object for m_dictToEdit. m_selectedObject is not always the current source + // of m_dictToEdit, and I don't understand why, so I'm making another MapObject pointer + // which is always kept in sync. - void updateTheUI(); - void enableButtons(); - int getSel(); - WBPopupSliderButton m_heightSlider; - WBPopupSliderButton m_angleSlider; Real m_angle; Real m_height; + Real m_scale; + + WBPopupSliderButton m_heightSlider; + WBPopupSliderButton m_angleSlider; + WBPopupSliderButton m_scaleSlider; + + Int m_defaultEntryIndex; //< Index in the sound combobox of the entry labelled "default" + Bool m_defaultIsNone; //< The default for this object is no sound + AsciiString m_defaultEntryName; //< The original name of the default entry + ModifyObjectUndoable *m_posUndoable; + Coord3D m_position; + + void deletePages(); + void updateTheUI(); + void enableButtons(); + int getSel(); + // Generated message map functions //{{AFX_MSG(MapObjectProps) - afx_msg void OnSelchangeProperties(); virtual BOOL OnInitDialog() override; + virtual void OnOK() override; + virtual void OnCancel() override; + afx_msg void OnSelchangeProperties(); afx_msg void OnEditprop(); afx_msg void OnNewprop(); afx_msg void OnRemoveprop(); afx_msg void OnDblclkProperties(); - virtual void OnOK() override; - virtual void OnCancel() override; + afx_msg void _TeamToDict(); afx_msg void _NameToDict(); + afx_msg void _ScriptToDict(); + afx_msg void _WeatherToDict(); + afx_msg void _TimeToDict(); + afx_msg void _ScaleToDict(); + afx_msg void SetZOffset(); + afx_msg void SetAngle(); + afx_msg void SetPosition(); + afx_msg void OnScaleOn(); + afx_msg void OnScaleOff(); + afx_msg void OnKillfocusMAPOBJECTXYPosition(); + afx_msg void _PrebuiltUpgradesToDict(); afx_msg void _HealthToDict(); afx_msg void _EnabledToDict(); - afx_msg void _ScriptToDict(); afx_msg void _IndestructibleToDict(); afx_msg void _UnsellableToDict(); afx_msg void _TargetableToDict(); @@ -104,23 +134,32 @@ class MapObjectProps : public COptionsPanel, public PopupSliderOwner afx_msg void _ShroudClearingDistanceToDict(); afx_msg void _RecruitableAIToDict(); afx_msg void _SelectableToDict(); - afx_msg void _WeatherToDict(); - afx_msg void _TimeToDict(); - afx_msg void _PrebuiltUpgradesToDict(); - afx_msg void SetZOffset(); - afx_msg void SetAngle(); afx_msg void _HPsToDict(); afx_msg void _StoppingDistanceToDict(); - //}}AFX_MSG + afx_msg void attachedSoundToDict(); + afx_msg void customizeToDict(); + afx_msg void enabledToDict(); + afx_msg void loopingToDict(); + afx_msg void loopCountToDict(); + afx_msg void minVolumeToDict(); + afx_msg void volumeToDict(); + afx_msg void minRangeToDict(); + afx_msg void maxRangeToDict(); + afx_msg void priorityToDict(); + //}}AFX_MSG DECLARE_MESSAGE_MAP() - void _DictToTeam(); void _DictToName(); + void _DictToTeam(); + void _DictToScript(); + void _DictToScale(); + void _DictToWeather(); + void _DictToTime(); + void _DictToPrebuiltUpgrades(); void _DictToHealth(); void _DictToHPs(); void _DictToEnabled(); - void _DictToScript(); void _DictToDestructible(); void _DictToUnsellable(); void _DictToTargetable(); @@ -132,21 +171,38 @@ class MapObjectProps : public COptionsPanel, public PopupSliderOwner void _DictToShroudClearingDistance(); void _DictToRecruitableAI(); void _DictToSelectable(); - void _DictToWeather(); - void _DictToTime(); + void _DictToStoppingDistance(); void ShowZOffset(MapObject* pMapObj); void ShowAngle(MapObject* pMapObj); - void _DictToStoppingDistance(); - void _DictToPrebuiltUpgrades(); - -public: + void ShowPosition(MapObject* pMapObj); + void dictToAttachedSound(); + void dictToCustomize(); + void dictToEnabled(); + void dictToLooping(); + void dictToLoopCount(); + void dictToMinVolume(); + void dictToVolume(); + void dictToMinRange(); + void dictToMaxRange(); + void dictToPriority(); + + void clearCustomizeFlag( CWorldBuilderDoc* pDoc, MultipleUndoable * ownerUndoable ); + + // Implementation of PopupSliderOwner callbacks virtual void GetPopSliderInfo(const long sliderID, long *pMin, long *pMax, long *pLineSize, long *pInitial) override; virtual void PopSliderChanged(const long sliderID, long theVal) override; virtual void PopSliderFinished(const long sliderID, long theVal) override; +public: static MapObject *getSingleSelectedMapObject(); static void update(); +private: + /// Disallow copying: Object is not set up to be copied + MapObjectProps( const MapObjectProps & other ); // Deliberately undefined + MapObjectProps & operator=( const MapObjectProps & other ); // Deliberately undefined + void updateTheUI(MapObject *pMapObj); + void InitSound(); }; //{{AFX_INSERT_LOCATION}} diff --git a/Generals/Code/Tools/WorldBuilder/include/wbview.h b/Generals/Code/Tools/WorldBuilder/include/wbview.h index 5ef83521269..af519442e82 100644 --- a/Generals/Code/Tools/WorldBuilder/include/wbview.h +++ b/Generals/Code/Tools/WorldBuilder/include/wbview.h @@ -34,6 +34,12 @@ enum TPickedStatus { PICK_ARROW }; +enum RulerTypeEnum { + RULER_NONE, + RULER_LINE, + RULER_CIRCLE, +}; + ///////////////////////////////////////////////////////////////////////////// // WbView view @@ -77,6 +83,9 @@ class WbView : public CView // Box feedback. RECT m_feedbackBox; Bool m_doRectFeedback; + int m_doRulerFeedback; + Coord3D m_rulerPoints[2]; + Real m_rulerLength; // Light direction feedback Coord3D m_lightDirection[3]; //direction of all 3 lights @@ -88,6 +97,8 @@ class WbView : public CView public: void doRectFeedback(Bool doFeedback, RECT &rect) {m_feedbackBox=rect;m_doRectFeedback = doFeedback;}; + void doRulerFeedback(int doRulerFeedback) {m_doRulerFeedback = doRulerFeedback;} + void rulerFeedbackInfo(Coord3D &point1, Coord3D &point2, Real dist); void doLightFeedback(Bool doFeedback, Coord3D direction, Int lightIndex) { m_doLightFeedback=doFeedback; if (m_doLightFeedback) m_lightDirection[lightIndex]=direction;} diff --git a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h index e6c7befa7a0..c825a4b72b5 100644 --- a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h @@ -16,6 +16,7 @@ ** along with this program. If not, see . */ + // WbView3d.h // Class to encapsulate height map. // Author: Steven Johnson, Aug 2001 @@ -137,6 +138,16 @@ class WbView3d : public WbView, public DX8_CleanupHook afx_msg void OnUpdateViewPartialmapsize128x128(CCmdUI* pCmdUI); afx_msg void OnViewShowModels(); afx_msg void OnUpdateViewShowModels(CCmdUI* pCmdUI); + afx_msg void OnViewBoundingBoxes(); + afx_msg void OnUpdateViewBoundingBoxes(CCmdUI* pCmdUI); + afx_msg void OnViewSightRanges(); + afx_msg void OnUpdateViewSightRanges(CCmdUI* pCmdUI); + afx_msg void OnViewWeaponRanges(); + afx_msg void OnUpdateViewWeaponRanges(CCmdUI* pCmdUI); + afx_msg void OnHighlightTestArt(); + afx_msg void OnUpdateHighlightTestArt(CCmdUI* pCmdUI); + afx_msg void OnShowLetterbox(); + afx_msg void OnUpdateShowLetterbox(CCmdUI* pCmdUI); afx_msg void OnViewLayersList(); afx_msg void OnUpdateViewLayersList(CCmdUI* pCmdUI); afx_msg void OnViewGarrisoned(); @@ -145,7 +156,9 @@ class WbView3d : public WbView, public DX8_CleanupHook afx_msg void OnUpdateViewShowMapBoundaries(CCmdUI* pCmdUI); afx_msg void OnViewShowAmbientSounds(); afx_msg void OnUpdateViewShowAmbientSounds(CCmdUI* pCmdUI); - //}}AFX_MSG + afx_msg void OnViewShowSoundCircles(); + afx_msg void OnUpdateViewShowSoundCircles(CCmdUI* pCmdUI); + //}}AFX_MSG DECLARE_MESSAGE_MAP() private: @@ -199,6 +212,12 @@ class WbView3d : public WbView, public DX8_CleanupHook Bool m_showLayersList; ///< Flag whether the layers list is visible or not. Bool m_showMapBoundaries; ///< Flag whether to show all the map boundaries or not Bool m_showAmbientSounds; ///< Flag whether to show all the ambient sounds or not + Bool m_showSoundCircles; ///< Flag whether to show the minimum and maximum radii of the ambient sounds attached to the selected object + Bool m_showBoundingBoxes; + Bool m_showSightRanges; + Bool m_showWeaponRanges; + Bool m_highlightTestArt; + Bool m_showLetterbox; ID3DXFont* m3DFont; @@ -211,6 +230,7 @@ class WbView3d : public WbView, public DX8_CleanupHook void init3dScene(); void initAssets(); void initWW3D(); + void drawCircle( HDC hdc, const Coord3D & centerPoint, Real radius, COLORREF color ); void drawLabels(HDC hdc); void drawLabels(); void shutdownWW3D(); @@ -220,6 +240,7 @@ class WbView3d : public WbView, public DX8_CleanupHook void updateHysteresis(); void updateLights(); void updateScorches(); + void updateTrees(); public: virtual Bool viewToDocCoords(CPoint curPt, Coord3D *newPt, Bool constrain=true) override; @@ -247,10 +268,12 @@ class WbView3d : public WbView, public DX8_CleanupHook virtual void pitchCamera(Real delta) override; void setCameraPitch(Real absolutePitch); Real getCameraPitch(); + Real getCurrentZoom(); //WST 10/17/2002 Real getHeightAboveGround() { return m_actualHeightAboveGround; } Vector3 getCameraSource() { return m_cameraSource; } Vector3 getCameraTarget() { return m_cameraTarget; } Real getCameraAngle() { return m_cameraAngle; } + CPoint getActualWinSize() {return m_actualWinSize;} virtual MapObject *picked3dObjectInView(CPoint viewPt) override; virtual BuildListInfo *pickedBuildObjectInView(CPoint viewPt) override; @@ -290,6 +313,16 @@ class WbView3d : public WbView, public DX8_CleanupHook void togglePitchAndRotation() { m_doPitch = !m_doPitch; } virtual Bool isDoingPitch() override { return m_doPitch; } + void setShowBoundingBoxes(Bool toggle) {m_showBoundingBoxes = toggle;} + Bool getShowBoundingBoxes() { return m_showBoundingBoxes;} + void setShowSightRanges(Bool toggle) {m_showSightRanges = toggle;} + Bool getShowSightRanges() { return m_showSightRanges;} + void setShowWeaponRanges(Bool toggle) {m_showWeaponRanges = toggle;} + Bool getShowWeaponRanges() { return m_showWeaponRanges;} + void setHighlightTestArt(Bool toggle) {m_highlightTestArt = toggle;} + Bool getHighlightTestArt() { return m_highlightTestArt;} + void setShowLetterbox(Bool toggle) {m_showLetterbox = toggle;} + Bool getShowLetterbox() { return m_showLetterbox;} }; inline UINT WbView3d::getLastDrawTime() { return m_time; } diff --git a/Generals/Code/Tools/WorldBuilder/res/Toolbar.bmp b/Generals/Code/Tools/WorldBuilder/res/Toolbar.bmp index 4f12bc25b9e..61478f4f724 100644 Binary files a/Generals/Code/Tools/WorldBuilder/res/Toolbar.bmp and b/Generals/Code/Tools/WorldBuilder/res/Toolbar.bmp differ diff --git a/Generals/Code/Tools/WorldBuilder/res/WorldBuilder.rc b/Generals/Code/Tools/WorldBuilder/res/WorldBuilder.rc index 4755a373920..0918509c0ea 100644 --- a/Generals/Code/Tools/WorldBuilder/res/WorldBuilder.rc +++ b/Generals/Code/Tools/WorldBuilder/res/WorldBuilder.rc @@ -27,18 +27,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // TEXTINCLUDE // -1 TEXTINCLUDE DISCARDABLE +1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END -2 TEXTINCLUDE DISCARDABLE +2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END -3 TEXTINCLUDE DISCARDABLE +3 TEXTINCLUDE DISCARDABLE BEGIN "#define _AFX_NO_SPLITTER_RESOURCES\r\n" "#define _AFX_NO_OLE_RESOURCES\r\n" @@ -99,8 +99,8 @@ BEGIN BUTTON ID_EDIT_CUT BUTTON ID_EDIT_COPY BUTTON ID_EDIT_PASTE - BUTTON ID_FILE_PRINT SEPARATOR + BUTTON ID_RULER_TOOL BUTTON ID_POINTER_TOOL BUTTON ID_LOCK_HORIZONTAL BUTTON ID_BRUSH_TOOL @@ -130,10 +130,8 @@ BEGIN BUTTON ID_POLYGON_TOOL BUTTON ID_BORDERTOOL SEPARATOR - BUTTON ID_LOOK_NORTH - BUTTON ID_LOOK_SOUTH - BUTTON ID_LOOK_WEST - BUTTON ID_LOOK_EAST + BUTTON ID_SCRIPT_EDIT + BUTTON ID_TEAM_EDIT SEPARATOR BUTTON ID_APP_ABOUT END @@ -173,7 +171,7 @@ END // Menu // -IDR_MAPDOC MENU PRELOAD DISCARDABLE +IDR_MAPDOC MENU PRELOAD DISCARDABLE BEGIN POPUP "&File" BEGIN @@ -184,7 +182,7 @@ BEGIN MENUITEM "Save &As...", ID_FILE_SAVE_AS MENUITEM "&Jump to Game\tCtrl+J", ID_FILE_JUMPTOGAME MENUITEM SEPARATOR - MENUITEM "Resize Map", ID_FILE_RESIZE + MENUITEM "Resize...", ID_FILE_RESIZE MENUITEM SEPARATOR MENUITEM "&Print...\tCtrl+P", ID_FILE_PRINT MENUITEM "Print Pre&view", ID_FILE_PRINT_PREVIEW @@ -207,7 +205,7 @@ BEGIN MENUITEM "Delete\tDel", ID_EDIT_DELETE MENUITEM SEPARATOR MENUITEM "Select Duplicate Objects", ID_EDIT_SELECTDUP - MENUITEM "Select Bad Team Objects", ID_EDIT_SELECTINVALIDTEAM + MENUITEM "Select Objects w/bad teams", ID_EDIT_SELECTINVALIDTEAM MENUITEM "Select Si&milar\tCtrl+M", ID_EDIT_SELECTSIMILAR MENUITEM "Select Macrotexture...", ID_EDIT_SELECTMACROTEXTURE MENUITEM "Replace Selected...", ID_EDIT_REPLACE @@ -233,8 +231,8 @@ BEGIN MENUITEM "Edit Shadows...", ID_EDIT_SHADOWS MENUITEM "Edit Map Settings...", ID_EDIT_MAPSETTINGS MENUITEM SEPARATOR - MENUITEM "Edit Player List...", ID_EDIT_PLAYERLIST MENUITEM "Edit Teams...", ID_EDIT_TEAMLIST + MENUITEM "Edit Player List...", ID_EDIT_PLAYERLIST END POPUP "&View" BEGIN @@ -248,11 +246,18 @@ BEGIN MENUITEM "Show Shadows", ID_VIEW_SHOWSHADOWS MENUITEM "Show Labels", ID_VIEW_LABELS MENUITEM "Show Objects", ID_VIEW_SHOWMODELS + MENUITEM "Show Bounding Boxes", ID_VIEW_BOUNDINGBOXES + MENUITEM "Show Sight Ranges", ID_VIEW_SIGHTRANGES + MENUITEM "Show Weapon Ranges", ID_VIEW_WEAPONRANGES MENUITEM "Show Garrisoned", ID_VIEW_GARRISONED MENUITEM "Show Map Boundaries", ID_VIEW_SHOWMAPBOUNDARIES + MENUITEM "Show Letterbox", ID_SHOW_LETTERBOX MENUITEM "Show Sound Flags", ID_VIEW_SHOWAMBIENTSOUNDS + MENUITEM "Show Sound Circles", ID_VIEW_SHOW_SOUND_CIRCLES MENUITEM SEPARATOR - MENUITEM "Show Impassable Areas\tCtrl+I", + MENUITEM "Highlight Test Art", ID_HIGHLIGHT_TESTART + MENUITEM SEPARATOR + MENUITEM "Show Impassable Areas\tCtrl+I", ID_VIEW_SHOWIMPASSABLEAREAS MENUITEM "Impassable Area Options...", ID_VIEW_IMPASSABLEAREAOPTIONS @@ -272,6 +277,13 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Show Wireframe 3D View\tCtrl+W", ID_VIEW_SHOWWIREFRAME MENUITEM "Show From Top Down View\tCtrl+F", ID_VIEW_SHOWTOPDOWNVIEW + POPUP "Camera Direction" + BEGIN + MENUITEM "Look North", ID_LOOK_NORTH + MENUITEM "Look South", ID_LOOK_SOUTH + MENUITEM "Look West", ID_LOOK_WEST + MENUITEM "Look East", ID_LOOK_EAST + END MENUITEM "Show 3-Way Blends in White", ID_VIEW_SHOWEXTRABLENDS MENUITEM "Show Clouds\tCtrl+U", ID_VIEW_SHOWCLOUDS MENUITEM "Show Soft Water", ID_VIEW_SHOWSOFTWATER @@ -302,10 +314,10 @@ BEGIN BEGIN MENUITEM "Map Cliff Textures", ID_TEXTURESIZING_MAPCLIFFTEXTURES - MENUITEM "Remove Cliff Textures", ID_TEXTURESIZING_REMOVECLIFFTEXMAPPING + MENUITEM "Remove Cliff Tex Mapping", ID_TEXTURESIZING_REMOVECLIFFTEXMAPPING MENUITEM SEPARATOR - MENUITEM "Optimize Tile Usage", ID_TS_CANONICAL + MENUITEM "Optimize tiles and blend tiles.", ID_TS_CANONICAL MENUITEM SEPARATOR MENUITEM "Remap Textures...", ID_TS_REMAP MENUITEM SEPARATOR @@ -327,10 +339,13 @@ BEGIN END END -IDR_LAYERSLISTPOPUP MENU DISCARDABLE +IDR_LAYERSLISTPOPUP MENU DISCARDABLE BEGIN POPUP "Layers List" BEGIN + MENUITEM "Select Object", ID_SELECTLAYEROBJECT + MENUITEM "Select Active Layer", ID_SELECTACTIVELAYER + MENUITEM SEPARATOR MENUITEM "Insert New Layer", ID_INSERTNEWLAYER MENUITEM "Delete Current Layer", ID_DELETECURRENTLAYER POPUP "Merge Layer into" @@ -353,7 +368,7 @@ BEGIN END END -IDR_SCRIPTDIALOGPOPUP MENU DISCARDABLE +IDR_SCRIPTDIALOGPOPUP MENU DISCARDABLE BEGIN POPUP "Layers List" BEGIN @@ -367,7 +382,7 @@ END // Accelerator // -IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE +IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE BEGIN "0", ID_EDIT_PICKANYTHING, VIRTKEY, CONTROL, NOINVERT "1", ID_EDIT_PICKSTRUCTS, VIRTKEY, CONTROL, NOINVERT @@ -386,7 +401,7 @@ BEGIN "F", ID_TOGGLE_PITCH_AND_ROTATE, VIRTKEY, NOINVERT "F", ID_VIEW_SHOWTOPDOWNVIEW, VIRTKEY, CONTROL, NOINVERT "G", IDM_ShowGrid, VIRTKEY, CONTROL, NOINVERT - "G", ID_VIEW_SNAPTOGRID, VIRTKEY, SHIFT, CONTROL, + "G", ID_VIEW_SNAPTOGRID, VIRTKEY, SHIFT, CONTROL, NOINVERT "I", ID_VIEW_SHOWIMPASSABLEAREAS, VIRTKEY, CONTROL, NOINVERT "J", ID_FILE_JUMPTOGAME, VIRTKEY, CONTROL, NOINVERT @@ -410,7 +425,7 @@ BEGIN "W", ID_VIEW_SHOWWIREFRAME, VIRTKEY, CONTROL, NOINVERT "X", ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT - "Z", ID_EDIT_REDO, VIRTKEY, SHIFT, CONTROL, + "Z", ID_EDIT_REDO, VIRTKEY, SHIFT, CONTROL, NOINVERT END @@ -454,23 +469,23 @@ BEGIN EDITTEXT IDC_INITIAL_HEIGHT,75,58,26,12,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,129,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 - CONTROL "",IDC_TOP_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_TOP_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,53,83,20,18 - CONTROL "",IDC_TOP,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_TOP,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,73,83,20,18 - CONTROL "",IDC_TOP_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_TOP_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,93,83,20,18 - CONTROL "",IDC_CENTER_LEFT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_CENTER_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,53,101,20,18 - CONTROL "",IDC_CENTER,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_CENTER,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,73,101,20,18 - CONTROL "",IDC_CENTER_RIGHT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_CENTER_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,93,101,20,18 - CONTROL "",IDC_BOTTOM_LEFT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_BOTTOM_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,53,119,20,18 - CONTROL "",IDC_BOTTOM,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_BOTTOM,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,73,119,20,18 - CONTROL "",IDC_BOTTOM_RIGHT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_BOTTOM_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,93,119,20,18 LTEXT "Initial height (0-255):",IDC_STATIC,7,59,67,9 LTEXT "Vert (y) size:",IDC_STATIC,7,25,42,9 @@ -508,15 +523,15 @@ BEGIN LTEXT "35 FT.",IDC_FEATHER_LABEL,71,68,41,8 END -IDD_TERRAIN_MATERIAL DIALOG DISCARDABLE 0, 0, 200, 298 +IDD_TERRAIN_MATERIAL DIALOG DISCARDABLE 0, 0, 200, 286 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Terrain Material Options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,126 PUSHBUTTON "Swap",IDC_SWAP_TEXTURES,138,138,25,16 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,67,137,65,55 LTEXT "Gravel",IDC_TERRAIN_NAME,70,197,86,9 EDITTEXT IDC_SIZE_EDIT,53,217,17,12,ES_AUTOHSCROLL @@ -532,7 +547,7 @@ BEGIN 27,270,98,10 END -IDD_MOUND_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 183 +IDD_MOUND_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 146 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Terrain Brush Options" FONT 8, "MS Sans Serif" @@ -559,16 +574,16 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Object Selection Opts" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,0,5,199,126 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,80,137,57,49 LTEXT "Light Tank",IDC_OBJECT_NAME,65,205,67,9 EDITTEXT IDC_OBJECT_HEIGHT_EDIT,106,191,26,12,ES_AUTOHSCROLL LTEXT "Height (0==on terrain)",IDC_STATIC,13,193,74,8 LTEXT "Object Name:",IDC_STATIC,13,205,42,9 LTEXT "Default Owner:",IDC_STATIC,13,219,48,8 - COMBOBOX IDC_OWNINGTEAM,13,229,162,104,CBS_DROPDOWNLIST | + COMBOBOX IDC_OWNINGTEAM,13,229,162,104,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END @@ -593,9 +608,9 @@ STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Replace " FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,174,126 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,15,201,65,55 LTEXT "Gravel",IDC_TERRAIN_NAME,44,185,83,10 DEFPUSHBUTTON "OK",IDOK,129,231,50,14 @@ -635,7 +650,7 @@ BEGIN LTEXT "This tool has no options.",IDC_STATIC,15,34,89,43 END -IDD_FEATHER_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 218 +IDD_FEATHER_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 186 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Feather Brush Options" FONT 8, "MS Sans Serif" @@ -664,10 +679,10 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Mesh Mold Options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_MESHMOLD_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_MESHMOLD_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,93 PUSHBUTTON "Apply",IDC_APPLY_MESH,5,224,56,17 - CONTROL "Preview",IDC_PREVIEW,"Button",BS_AUTOCHECKBOX | + CONTROL "Preview",IDC_PREVIEW,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,147,225,40,10 RTEXT "Angle (deg)",IDC_STATIC,5,142,41,10 EDITTEXT IDC_ANGLE_EDIT,50,140,29,12,ES_AUTOHSCROLL @@ -692,7 +707,7 @@ STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Select Mactotexture" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TEXTURE_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TEXTURE_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,136,126 DEFPUSHBUTTON "OK",IDOK,5,140,50,14 END @@ -756,7 +771,7 @@ BEGIN PUSHBUTTON "Restore To Default",IDC_GlobalLightingReset,4,4,75,14 END -IDD_LIGHT_OPTIONS DIALOG DISCARDABLE 0, 0, 122, 189 +IDD_LIGHT_OPTIONS DIALOG DISCARDABLE 0, 0, 122, 156 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Light Options" FONT 8, "MS Sans Serif" @@ -781,13 +796,13 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,129,196,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,215,50,14 - LISTBOX IDC_OPEN_LIST,15,26,155,162,LBS_SORT | + LISTBOX IDC_OPEN_LIST,15,26,155,162,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Open Map:",IDC_STATIC,15,15,36,8 PUSHBUTTON "Browse...",IDC_BROWSE,16,195,61,16 - CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,58,6,54,16 - CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,115,6,55,16 END @@ -798,93 +813,25 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,129,197,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,214,50,14 - LISTBOX IDC_SAVE_LIST,13,25,157,136,LBS_SORT | + LISTBOX IDC_SAVE_LIST,13,25,157,136,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Browse...",IDC_BROWSE,7,197,50,14 GROUPBOX "Map name:",IDC_STATIC,7,166,172,27 EDITTEXT IDC_SAVE_MAP_EDIT,13,175,157,12,ES_AUTOHSCROLL - CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,66,6,54,16 - CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,123,6,55,16 LTEXT "Existing maps:",IDC_STATIC,13,15,46,8 END -IDD_MAPOBJECT_PROPS DIALOG DISCARDABLE 0, 0, 200, 311 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION -CAPTION "Object Properties" -FONT 8, "MS Sans Serif" -BEGIN - COMBOBOX IDC_MAPOBJECT_Team,31,19,166,141,CBS_DROPDOWNLIST | - CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Team:",IDC_STATICTEAMCAPTION,3,21,21,8 - LTEXT "Name:",IDC_STATIC,3,6,22,8 - EDITTEXT IDC_MAPOBJECT_Name,31,3,166,14,ES_AUTOHSCROLL - LTEXT "Initial Health %",IDC_STATIC,3,52,58,8 - COMBOBOX IDC_MAPOBJECT_StartingHealth,71,50,95,71, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_MAPOBJECT_StartingHealthEdit,172,50,25,14, - ES_AUTOHSCROLL - CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,3,81,58,10 - CONTROL "Indestructible",IDC_MAPOBJECT_Indestructible,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,3,106,58,10 - CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,71,81,58,10 - CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,3,93,58,10 - COMBOBOX IDC_MAPOBJECT_Script,31,34,166,67,CBS_DROPDOWNLIST | - WS_DISABLED | WS_VSCROLL | WS_TABSTOP - LTEXT "Script:",IDC_STATIC,3,36,21,8,WS_DISABLED - LTEXT "Aggressiveness:",IDC_STATIC,3,122,66,8 - COMBOBOX IDC_MAPOBJECT_Aggressiveness,71,120,126,73, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_MAPOBJECT_VisionDistance,169,204,27,14, - ES_AUTOHSCROLL - LTEXT "Targetting Distance:",IDC_STATIC,82,207,83,8 - CONTROL "AI Recruitable",IDC_MAPOBJECT_RecruitableAI,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,71,105,69,10 - LTEXT "Shroud Clearing Distance:",IDC_STATIC,82,226,83,8 - EDITTEXT IDC_MAPOBJECT_ShroudClearingDistance,169,222,27,14, - ES_AUTOHSCROLL - LTEXT "Veterancy:",IDC_STATIC,3,138,66,8 - COMBOBOX IDC_MAPOBJECT_Veterancy,71,136,126,73,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_MAPOBJECT_ZOffset,25,188,24,14,ES_AUTOHSCROLL - LTEXT "Z:",IDC_STATIC,13,191,8,8 - EDITTEXT IDC_MAPOBJECT_Angle,25,204,24,14,ES_AUTOHSCROLL - LTEXT "Angle:",IDC_STATIC,3,207,19,8 - PUSHBUTTON "1",IDC_HEIGHT_POPUP,51,188,8,12,BS_BITMAP - PUSHBUTTON "1",IDC_ANGLE_POPUP,51,205,8,12,BS_BITMAP - COMBOBOX IDC_MAPOBJECT_Weather,71,153,126,76,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_Time,71,169,126,65,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_HitPoints,71,66,126,52,CBS_DROPDOWN | - CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Max Hitpoints",IDC_STATIC,3,67,58,8 - EDITTEXT IDC_MAPOBJECT_StoppingDistance,169,186,27,14, - ES_AUTOHSCROLL | ES_NUMBER - LTEXT "Stopping Distance:",IDC_STATIC,82,188,83,8 - CONTROL "Selectable",IDC_MAPOBJECT_Selectable,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,71,93,58,10 - LTEXT "Weather:",IDC_STATIC,3,155,66,8 - LTEXT "Time:",IDC_STATIC,3,171,66,8 - LISTBOX IDC_MAPOBJECT_BuildWithUpgrades,9,253,182,51, - LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | - WS_TABSTOP - GROUPBOX "Pre-built upgrades",IDC_STATIC,3,242,194,66 - CONTROL "Targetable",IDC_MAPOBJECT_Targetable,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,139,81,58,10 -END - IDD_PROPEDIT DIALOG DISCARDABLE 0, 0, 200, 84 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Property Edit" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_KEYNAME,38,7,107,14,ES_AUTOHSCROLL - COMBOBOX IDC_KEYTYPE,38,30,107,153,CBS_DROPDOWNLIST | WS_VSCROLL | + COMBOBOX IDC_KEYTYPE,38,30,107,153,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_VALUE,38,50,107,14,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,162,7,31,14 @@ -901,24 +848,24 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Player List" FONT 8, "MS Sans Serif" BEGIN - LISTBOX IDC_PLAYERS,7,7,275,69,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + LISTBOX IDC_PLAYERS,7,7,275,69,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP PUSHBUTTON "New Player",IDC_NEWPLAYER,7,254,45,14 PUSHBUTTON "Remove Player",IDC_REMOVEPLAYER,56,254,56,14 DEFPUSHBUTTON "OK",IDOK,177,274,51,14 LTEXT "Allies:",IDC_STATIC,7,133,68,8 LTEXT "Enemies:",IDC_STATIC,153,133,78,8 - LISTBOX IDC_ALLIESLIST,7,144,129,40,LBS_SORT | LBS_MULTIPLESEL | + LISTBOX IDC_ALLIESLIST,7,144,129,40,LBS_SORT | LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LISTBOX IDC_ENEMIESLIST,153,144,129,40,LBS_SORT | - LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + LISTBOX IDC_ENEMIESLIST,153,144,129,40,LBS_SORT | + LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LISTBOX IDC_PLAYER_ATTITUDE_OUT,7,203,129,40,NOT LBS_NOTIFY | - LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | + LISTBOX IDC_PLAYER_ATTITUDE_OUT,7,203,129,40,NOT LBS_NOTIFY | + LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP LTEXT "How Player Regard Others:",IDC_STATIC,7,192,86,8 - LISTBOX IDC_PLAYER_ATTITUDE_IN,153,203,129,40,NOT LBS_NOTIFY | - LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | + LISTBOX IDC_PLAYER_ATTITUDE_IN,153,203,129,40,NOT LBS_NOTIFY | + LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP LTEXT "How Others Regard Player:",IDC_STATIC,153,192,94,8 PUSHBUTTON "Cancel",IDCANCEL,232,274,50,14 @@ -927,10 +874,10 @@ BEGIN EDITTEXT IDC_PLAYERDISPLAYNAME,82,100,84,14,ES_AUTOHSCROLL CONTROL "Is Player computer-controlled?",IDC_PLAYERISCOMPUTER, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,163,87,110,10 - COMBOBOX IDC_PLAYERFACTION,178,110,96,105,CBS_DROPDOWNLIST | + COMBOBOX IDC_PLAYERFACTION,178,110,96,105,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "",IDC_PlayerColor,8,116,14,12 - COMBOBOX IDC_PlayerColorCombo,51,116,83,120,CBS_DROPDOWNLIST | + COMBOBOX IDC_PlayerColorCombo,51,116,83,120,CBS_DROPDOWNLIST | WS_TABSTOP PUSHBUTTON "Set Name",IDC_CHANGE_NAME,15,88,36,9 PUSHBUTTON "Add Skirmish Players",IDC_ADDSKIRMISHPLAYERS,42,274,71, @@ -945,20 +892,20 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Build List" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_SIDES_COMBO,9,10,184,133,CBS_DROPDOWNLIST | + COMBOBOX IDC_SIDES_COMBO,9,10,184,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Side:",IDC_STATIC,2,0,195,28 - LISTBOX IDC_BUILD_LIST,9,42,183,125,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_BUILD_LIST,9,42,183,125,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Build List",IDC_STATIC,2,31,196,167 - CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN | + CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN | WS_DISABLED,16,224,177,16 GROUPBOX "Power Used:",IDC_STATIC,7,214,190,28,WS_DISABLED CONTROL "Structure Already Built",IDC_ALREADY_BUILD,"Button", BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT | WS_TABSTOP, 100,169,90,10 RTEXT "Rebuilds:",IDC_STATIC,111,184,35,8 - COMBOBOX IDC_REBUILDS,149,182,43,64,CBS_DROPDOWN | WS_VSCROLL | + COMBOBOX IDC_REBUILDS,149,182,43,64,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Up",IDC_MOVE_UP,9,172,22,11 PUSHBUTTON "Down",IDC_MOVE_DOWN,9,184,22,11 @@ -1006,15 +953,19 @@ BEGIN PUSHBUTTON "&Delete",IDC_DELETE,403,152,50,14 PUSHBUTTON "Import Scripts...",IDC_LOAD,386,309,60,14 PUSHBUTTON "Export Script(s)...",IDC_SAVE,317,309,60,14 - CONTROL "Tree1",IDC_SCRIPT_TREE,"SysTreeView32",TVS_HASBUTTONS | - TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | + CONTROL "Tree1",IDC_SCRIPT_TREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | WS_TABSTOP,7,7,386,193,WS_EX_CLIENTEDGE PUSHBUTTON "New &Folder...",IDC_NEW_FOLDER,403,46,50,14 - EDITTEXT IDC_SCRIPT_DESCRIPTION,208,206,187,99,ES_MULTILINE | + EDITTEXT IDC_SCRIPT_DESCRIPTION,208,206,187,99,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL PUSHBUTTON "Cancel",IDCANCEL,403,253,50,14 - EDITTEXT IDC_SCRIPT_COMMENT,7,206,195,99,ES_MULTILINE | + EDITTEXT IDC_SCRIPT_COMMENT,7,206,195,99,ES_MULTILINE | ES_READONLY | WS_VSCROLL + CONTROL "Auto Verify",IDC_AUTO_VERIFY,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,261,311,52,8 + PUSHBUTTON "&Verify",IDC_VERIFY,403,22,50,14 + PUSHBUTTON "&Patch ""GC_""",IDC_PATCH_GC,403,169,50,14 END IDD_ScriptTabWindow DIALOG DISCARDABLE 0, 0, 391, 255 @@ -1032,7 +983,7 @@ STYLE WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Script Conditions" FONT 8, "MS Sans Serif" BEGIN - LISTBOX IDC_CONDITION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_CONDITION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Conditions for this script:",IDC_STATIC,7,14,81,8 PUSHBUTTON "New...",IDC_NEW,319,32,50,14 @@ -1050,7 +1001,7 @@ STYLE WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Actions if true." FONT 8, "MS Sans Serif" BEGIN - LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Actions to take if conditions are true:",IDC_STATIC,7, 14,139,8 @@ -1070,7 +1021,7 @@ FONT 8, "MS Sans Serif" BEGIN LTEXT "Actions to take if conditions are false:",IDC_STATIC,7, 14,120,8 - LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "New...",IDC_NEW,319,32,50,14 PUSHBUTTON "Edit...",IDC_EDIT,319,48,50,14 @@ -1095,11 +1046,11 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,11,69,108,10 CONTROL "Easy",IDC_EASY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 157,41,31,10 - CONTROL "Normal",IDC_NORMAL,"Button",BS_AUTOCHECKBOX | + CONTROL "Normal",IDC_NORMAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,56,38,10 CONTROL "Hard",IDC_HARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 157,71,31,10 - EDITTEXT IDC_SCRIPT_COMMENT,7,100,320,98,ES_MULTILINE | + EDITTEXT IDC_SCRIPT_COMMENT,7,100,320,98,ES_MULTILINE | WS_VSCROLL LTEXT "Script Name:",IDC_STATIC,7,12,43,8 GROUPBOX "Active in:",IDC_STATIC,151,30,58,54 @@ -1114,20 +1065,22 @@ BEGIN LTEXT "seconds.",IDC_STATIC,283,60,30,8 END -IDD_ScriptCondition DIALOG DISCARDABLE 0, 0, 271, 149 +IDD_ScriptCondition DIALOG DISCARDABLE 0, 0, 311, 450 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Edit Condition:" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,153,128,50,14 - PUSHBUTTON "Cancel",IDCANCEL,214,128,50,14 + DEFPUSHBUTTON "OK",IDOK,197,429,50,14 + PUSHBUTTON "Cancel",IDCANCEL,254,428,50,14 CONTROL "",IDC_RICH_EDIT_HERE,"Static",SS_BLACKFRAME | SS_SUNKEN, - 7,29,257,57 - COMBOBOX IDC_CONDITION_TYPE,7,7,257,271,CBS_DROPDOWNLIST | - CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Warnings:",IDC_WARNINGS_CAPTION,7,89,257,36 - LTEXT "These are the freaking warnings.",IDC_WARNINGS,9,99,210, - 26 + 7,319,297,59 + GROUPBOX "Warnings:",IDC_WARNINGS_CAPTION,7,378,297,45 + LTEXT "These are the freaking warnings.",IDC_WARNINGS,9,388, + 210,30 + CONTROL "Tree1",IDC_CONDITION_TREE,"SysTreeView32", + TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | + TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | + TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,7,7,297,308 END IDD_EDIT_PARAMETER DIALOG DISCARDABLE 0, 0, 281, 74 @@ -1138,28 +1091,30 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,171,52,50,14 PUSHBUTTON "Cancel",IDCANCEL,224,52,50,14 GROUPBOX "Parameter:",IDC_CAPTION,7,7,267,41 - COMBOBOX IDC_COMBO,15,21,250,87,CBS_DROPDOWN | CBS_SORT | + COMBOBOX IDC_COMBO,15,21,250,87,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_EDIT,19,21,190,12,ES_AUTOHSCROLL - COMBOBOX IDC_LIST,19,21,190,84,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_LIST,19,21,190,84,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "Preview Sound",IDC_PREVIEWSOUND,7,52,62,14 + PUSHBUTTON "Preview Sound",IDC_PREVIEWSOUND,7,52,62,14 END -IDD_ScriptAction DIALOG DISCARDABLE 0, 0, 270, 149 +IDD_ScriptAction DIALOG DISCARDABLE 0, 0, 311, 450 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Edit Action:" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,152,128,50,14 - PUSHBUTTON "Cancel",IDCANCEL,213,128,50,14 + DEFPUSHBUTTON "OK",IDOK,197,429,50,14 + PUSHBUTTON "Cancel",IDCANCEL,254,428,50,14 CONTROL "",IDC_RICH_EDIT_HERE,"Static",SS_BLACKFRAME | SS_SUNKEN, - 7,29,256,59 - COMBOBOX IDC_CONDITION_TYPE,7,7,256,276,CBS_DROPDOWNLIST | - CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Warnings:",IDC_WARNINGS_CAPTION,7,89,256,36 - LTEXT "These are the freaking warnings.",IDC_WARNINGS,9,99,210, - 26 + 7,319,297,59 + GROUPBOX "Warnings:",IDC_WARNINGS_CAPTION,7,378,297,45 + LTEXT "These are the freaking warnings.",IDC_WARNINGS,9,388, + 210,30 + CONTROL "Tree1",IDC_ACTION_TREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | + TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT | + WS_BORDER | WS_TABSTOP,7,7,297,308 END IDD_TEAMS_DIALOG DIALOG DISCARDABLE 0, 0, 515, 294 @@ -1171,9 +1126,9 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,458,273,50,14 PUSHBUTTON "Add New Team",IDC_NEWTEAM,7,273,56,14 PUSHBUTTON "Delete Team",IDC_DELETETEAM,121,273,54,14 - LISTBOX IDC_PLAYER_LIST,7,7,105,263,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_PLAYER_LIST,7,7,105,263,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - CONTROL "List1",IDC_TEAMS_LIST,"SysListView32",LVS_REPORT | + CONTROL "List1",IDC_TEAMS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,116,7,392,263 PUSHBUTTON "Copy Team",IDC_COPYTEAM,67,273,50,14 PUSHBUTTON "Select Team Members...",IDC_SelectTeamMembers,179,273, @@ -1221,7 +1176,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,29,157,50,14 PUSHBUTTON "Cancel",IDCANCEL,88,157,50,14 GROUPBOX "Object:",IDC_CAPTION,7,7,131,145 - CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,15,20,114,126 END @@ -1232,38 +1187,38 @@ FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_MAX,177,2,27,14,ES_AUTOHSCROLL RTEXT "Home Position:",IDC_STATIC,2,37,53,8 - COMBOBOX IDC_HOME_WAYPOINT,58,36,113,228,CBS_DROPDOWNLIST | + COMBOBOX IDC_HOME_WAYPOINT,58,36,113,228,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Min:",IDC_STATIC,6,122,14,8 LTEXT "Max:",IDC_STATIC,24,122,16,8 LTEXT "Unit Type:",IDC_STATIC,50,122,91,8 EDITTEXT IDC_MIN_UNIT1,2,131,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT1,24,131,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE1,47,131,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE1,47,131,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT2,2,145,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT2,23,145,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE2,47,145,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE2,47,145,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT3,2,159,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT3,24,159,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE3,47,159,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE3,47,159,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT4,2,173,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT4,24,173,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE4,47,173,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE4,47,173,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT5,2,187,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT5,24,187,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE5,47,187,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE5,47,187,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT6,2,201,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT6,24,201,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE6,47,201,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE6,47,201,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT7,2,215,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT7,24,215,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE7,47,215,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE7,47,215,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Team Description:",IDC_STATIC,0,285,213,38 EDITTEXT IDC_DESCRIPTION,8,294,195,27,ES_AUTOHSCROLL @@ -1275,7 +1230,7 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,255,164,9 LTEXT "Maximum Quantity:",IDC_STATIC,116,4,59,8 RTEXT "Condition:",IDC_STATIC,11,62,47,8 - COMBOBOX IDC_PRODUCTION_CONDITION,64,59,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_PRODUCTION_CONDITION,64,59,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Production:",IDC_STATIC,1,53,212,66 RTEXT "Priority:",IDC_STATIC,3,89,24,8 @@ -1292,7 +1247,7 @@ BEGIN PUSHBUTTON "...",IDC_UNIT_TYPE6_BUTTON,197,201,12,12 PUSHBUTTON "...",IDC_UNIT_TYPE7_BUTTON,197,215,12,12 EDITTEXT IDC_TEAM_NAME,2,1,107,14,ES_AUTOHSCROLL - COMBOBOX IDC_TEAMOWNER,58,20,113,176,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_TEAMOWNER,58,20,113,176,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP RTEXT "Owner:",IDC_STATIC,2,24,53,8 CONTROL "Team created once and only once.",IDC_TEAM_SINGLETON, @@ -1301,7 +1256,7 @@ BEGIN EDITTEXT IDC_TEAM_BUILD_FRAMES,32,101,25,12,ES_AUTOHSCROLL LTEXT "frames.",IDC_STATIC,58,103,24,9 CONTROL "Execute associated actions", - IDC_PRODUCTION_EXECUTEACTIONS,"Button",BS_AUTOCHECKBOX | + IDC_PRODUCTION_EXECUTEACTIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,63,76,103,10 END @@ -1311,22 +1266,22 @@ CAPTION "Reinforcement" FONT 8, "MS Sans Serif" BEGIN GROUPBOX "If reinforcing, then:",IDC_STATIC,13,7,184,87 - CONTROL "Deploy by",IDC_DEPLOY_BY,"Button",BS_AUTOCHECKBOX | + CONTROL "Deploy by",IDC_DEPLOY_BY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,23,44,9 - COMBOBOX IDC_TRANSPORT_COMBO,66,21,126,140,CBS_DROPDOWN | + COMBOBOX IDC_TRANSPORT_COMBO,66,21,126,140,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Veterancy Level",IDC_STATIC,15,109,141,42 - COMBOBOX IDC_VETERANCY,23,124,124,60,CBS_DROPDOWNLIST | + COMBOBOX IDC_VETERANCY,23,124,124,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Transports exit map after unloading.", - IDC_TRANSPORTS_EXIT,"Button",BS_AUTOCHECKBOX | + IDC_TRANSPORTS_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,66,36,124,11 CONTROL "Load members into transports (if applicable).", - IDC_TEAM_STARTS_FULL,"Button",BS_AUTOCHECKBOX | + IDC_TEAM_STARTS_FULL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,78,166,11 GROUPBOX "Start team or transports at waypoint:",IDC_STATIC,19,50, 171,26 - COMBOBOX IDC_WAYPOINT_COMBO,25,60,160,176,CBS_DROPDOWN | CBS_SORT | + COMBOBOX IDC_WAYPOINT_COMBO,25,60,160,176,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP END @@ -1338,36 +1293,36 @@ BEGIN GROUPBOX "Behavior Script Triggers:",IDC_STATIC,7,7,216,107 GROUPBOX "Behavior Options",IDC_STATIC,7,141,216,106 RTEXT "On Create:",IDC_STATIC,23,25,51,8 - COMBOBOX IDC_ON_CREATE_SCRIPT,85,22,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_CREATE_SCRIPT,85,22,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP RTEXT "On Enemy Sighted:",IDC_STATIC,13,44,61,8 - COMBOBOX IDC_ON_ENEMY_SIGHTED,85,43,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_ENEMY_SIGHTED,85,43,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_ON_DESTROYED,85,80,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_DESTROYED,85,80,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP RTEXT "On Destroyed %",IDC_STATIC,10,81,51,8 EDITTEXT IDC_PERCENT_DESTROYED,62,80,18,12,ES_AUTOHSCROLL - COMBOBOX IDC_ENEMY_INTERACTIONS,19,182,159,69,CBS_DROPDOWNLIST | + COMBOBOX IDC_ENEMY_INTERACTIONS,19,182,159,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Initial Team Behavior",IDC_STATIC,15,172,172,27 CONTROL "Transports return to base after unloading.", - IDC_TRANSPORTS_RETURN,"Button",BS_AUTOCHECKBOX | + IDC_TRANSPORTS_RETURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,15,151,179,8 CONTROL "Team avoids threats.",IDC_AVOID_THREATS,"Button", BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,15,162,179,8 RTEXT "On All Clear:",IDC_STATIC,13,59,61,8 - COMBOBOX IDC_ON_ALL_CLEAR,85,58,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_ALL_CLEAR,85,58,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "",IDC_STATIC,7,36,216,37 RTEXT "On Idle:",IDC_STATIC,23,99,51,8 - COMBOBOX IDC_ON_IDLE_SCRIPT,85,96,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_IDLE_SCRIPT,85,96,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Behavior Scirpt Triggers:",IDC_STATIC,7,7,216,131 RTEXT "On Unit Destroyed:",IDC_STATIC,13,119,61,8 COMBOBOX IDC_ON_UNIT_DESTROYED_SCRIPT,85,116,132,173, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "Does this team focus on a single target at a time ", - IDC_ATTACK_COMMON_TARGET,"Button",BS_AUTOCHECKBOX | + IDC_ATTACK_COMMON_TARGET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,215,173,8 GROUPBOX "Attack:",IDC_STATIC,15,204,181,34 LTEXT "in Hard and Brutal (never in Normal)?",IDC_STATIC,35, @@ -1379,8 +1334,8 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Export Script Options" FONT 8, "MS Sans Serif" BEGIN - DEFPUSHBUTTON "OK",IDOK,69,132,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,132,50,14 + DEFPUSHBUTTON "OK",IDOK,69,152,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,152,50,14 CONTROL "Include waypoints and waypoint paths.",IDC_WAYPOINTS, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,20,150,8 CONTROL "Include trigger areas.",IDC_TRIGGERS,"Button", @@ -1388,37 +1343,39 @@ BEGIN CONTROL "Include units and buildings.",IDC_UNITS,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,12,61,154,9 GROUPBOX "Include items referenced in the scripts:",IDC_STATIC,7, - 7,172,73 + 7,172,88 CONTROL "Export all scripts.",IDC_ALL_SCRIPTS,"Button", - BS_AUTORADIOBUTTON,15,94,97,8 + BS_AUTORADIOBUTTON,15,115,97,8 CONTROL "Export selected scripts.",IDC_SELECTED_SCRIPTS,"Button", - BS_AUTORADIOBUTTON,15,106,99,8 - GROUPBOX "Export Mode:",IDC_STATIC,7,83,172,39 + BS_AUTORADIOBUTTON,15,127,99,8 + GROUPBOX "Export Mode:",IDC_STATIC,7,104,172,39 + CONTROL "Include sides.",IDC_SIDES,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,12,79,154,9 END -IDD_GROVE_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 173 +IDD_GROVE_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 166 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Grove Options" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_Grove_Type1,32,21,164,81,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type1,32,21,164,81,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "%",IDC_STATIC,15,11,8,8 EDITTEXT IDC_Grove_Per1,8,21,20,13,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_Grove_Type2,32,36,164,80,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type2,32,36,164,80,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per2,8,36,20,13,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_Grove_Type3,32,51,164,77,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type3,32,51,164,77,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per3,8,51,20,13,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_Grove_Type4,32,66,164,78,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type4,32,66,164,78,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per4,8,66,20,13,ES_AUTOHSCROLL | ES_NUMBER LTEXT "Tree Type",IDC_STATIC,34,11,34,8 - EDITTEXT IDC_Grove_PerTotal,8,97,20,13,ES_AUTOHSCROLL | + EDITTEXT IDC_Grove_PerTotal,8,97,20,13,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER LTEXT "% Total",IDC_STATIC,33,99,24,8 - COMBOBOX IDC_Grove_Type5,32,81,164,77,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type5,32,81,164,77,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per5,8,81,20,13,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_Grove_NumberTrees,8,115,40,14,ES_AUTOHSCROLL @@ -1429,12 +1386,12 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,146,81,10 END -IDD_FENCE_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 245 +IDD_FENCE_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 206 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Fence options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,126 EDITTEXT IDC_FENCE_SPACING_EDIT,146,143,49,12,ES_AUTOHSCROLL LTEXT "Fence spacing:",IDC_STATIC,74,145,68,8 @@ -1442,14 +1399,14 @@ BEGIN 179,190,25 END -IDD_BLEND_MATERIAL DIALOG DISCARDABLE 0, 0, 200, 245 +IDD_BLEND_MATERIAL DIALOG DISCARDABLE 0, 0, 200, 217 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Blend Material Options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,126 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,65,137,65,55 LTEXT "Gravel",IDC_TERRAIN_NAME,67,197,86,9 END @@ -1461,9 +1418,9 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,19,76,50,14 PUSHBUTTON "Cancel",IDCANCEL,79,76,50,14 - LTEXT "Which faction does the player use?",IDC_STATIC,7,7,143, - 36 - COMBOBOX IDC_COMBO1,7,46,143,260,CBS_DROPDOWNLIST | CBS_SORT | + LTEXT "Which of the following PlayerTemplates shall I use to add the Player you need?", + IDC_STATIC,7,7,143,36 + COMBOBOX IDC_COMBO1,7,46,143,260,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP END @@ -1474,7 +1431,7 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,210,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,210,24,50,14 - CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,7,7,198,284 END @@ -1492,7 +1449,7 @@ BEGIN ES_AUTOHSCROLL | WS_DISABLED CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,71,131,10 - COMBOBOX IDC_MAPOBJECT_Script,41,31,166,67,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Script,41,31,166,67,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Script:",IDC_STATIC,7,34,21,8 END @@ -1515,12 +1472,12 @@ BEGIN LTEXT "Ramp Width:",IDC_STATIC,7,15,42,14,SS_CENTERIMAGE END -IDD_SCORCH_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 181 +IDD_SCORCH_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 86 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Scorch Options" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_SCORCHTYPE,7,15,186,88,CBS_DROPDOWNLIST | WS_VSCROLL | + COMBOBOX IDC_SCORCHTYPE,7,15,186,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_SIZE_EDIT,60,37,17,12,ES_AUTOHSCROLL PUSHBUTTON "1",IDC_SIZE_POPUP,79,37,8,12,BS_BITMAP @@ -1535,18 +1492,18 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,70,242,50,14 PUSHBUTTON "Cancel",IDCANCEL,138,242,50,14 - COMBOBOX IDC_MAP_WEATHER,62,54,112,104,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAP_WEATHER,62,54,112,104,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP RTEXT "Time",IDC_STATIC,7,40,49,8 - COMBOBOX IDC_MAP_TIMEOFDAY,62,38,112,97,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAP_TIMEOFDAY,62,38,112,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP RTEXT "Weather",IDC_STATIC,8,56,49,8 EDITTEXT IDC_MAP_TITLE,62,7,112,12,ES_AUTOHSCROLL - EDITTEXT IDC_MAP_DESCRIPTION,7,73,181,155,ES_MULTILINE | + EDITTEXT IDC_MAP_DESCRIPTION,7,73,181,155,ES_MULTILINE | ES_AUTOHSCROLL | WS_VSCROLL | WS_HSCROLL RTEXT "Map Name",IDC_STATIC,7,7,49,10 RTEXT "Compression",IDC_STATIC,7,24,49,8 - COMBOBOX IDC_MAP_COMPRESSION,62,22,112,97,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAP_COMPRESSION,62,22,112,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END @@ -1555,8 +1512,8 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Layers List" FONT 8, "MS Sans Serif" BEGIN - CONTROL "Tree1",IDC_LL_TREE,"SysTreeView32",TVS_HASBUTTONS | - TVS_LINESATROOT | TVS_EDITLABELS | TVS_DISABLEDRAGDROP | + CONTROL "Tree1",IDC_LL_TREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_LINESATROOT | TVS_EDITLABELS | TVS_DISABLEDRAGDROP | WS_TABSTOP,7,7,207,148 END @@ -1567,7 +1524,7 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,210,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,210,24,50,14 - CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,7,24,198,267 LTEXT "Static",IDC_MISSINGLABEL,7,7,195,8 END @@ -1578,7 +1535,7 @@ CAPTION "Water Options" FONT 8, "MS Sans Serif" BEGIN GROUPBOX "Water Area Name:",IDC_STATIC,1,1,195,34 - COMBOBOX IDC_WATERNAME_EDIT,7,15,186,88,CBS_DROPDOWN | CBS_SORT | + COMBOBOX IDC_WATERNAME_EDIT,7,15,186,88,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Water Height:",IDC_WATER_HEIGHT1,1,40,195,33 EDITTEXT IDC_HEIGHT_EDIT,70,52,17,12,ES_AUTOHSCROLL @@ -1586,40 +1543,43 @@ BEGIN PUSHBUTTON "1",IDC_HEIGHT_POPUP,89,52,8,12,BS_BITMAP CONTROL "Create Water Polygon",IDC_WATER_POLYGON,"Button", BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,31,89,99,16 - CONTROL "River",IDC_MAKE_RIVER,"Button",BS_AUTOCHECKBOX | + CONTROL "River",IDC_MAKE_RIVER,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,31,119,98,16 GROUPBOX "Point spacing for water polygons and rivers.", IDC_STATIC,13,140,168,29 EDITTEXT IDC_SPACING,49,153,63,12,ES_AUTOHSCROLL END -IDD_CAMERA_OPTIONS DIALOG DISCARDABLE 0, 0, 142, 94 +IDD_CAMERA_OPTIONS DIALOG DISCARDABLE 0, 0, 144, 162 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Camera Options" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_PITCH_EDIT,89,11,27,12,ES_AUTOHSCROLL PUSHBUTTON "1",IDC_PITCH_POPUP,121,11,9,12,BS_BITMAP - GROUPBOX "Pitch",-1,83,1,55,29 + GROUPBOX "Pitch",-1,85,1,55,29 PUSHBUTTON "Restore To Default",IDC_CameraReset,4,4,75,14 LTEXT "Height above ground:",-1,7,33,73,10 LTEXT "Zoom:",-1,7,44,25,10 - LTEXT "(1.0 = max, 0.0 = min)",-1,58,44,80,10 + LTEXT "(1.0 == max, 0.0 == min)",-1,60,44,80,10 LTEXT "",IDC_ZOOMTEXT,29,44,27,10 - LTEXT "",IDC_HEIGHTTEXT,84,33,54,10 + LTEXT "",IDC_HEIGHTTEXT,86,33,54,10 LTEXT "Position:",-1,7,66,28,10 - LTEXT "",IDC_POSTEXT,35,65,103,10 + LTEXT "",IDC_POSTEXT,37,65,103,10 LTEXT "Target:",-1,7,76,28,10 - LTEXT "",IDC_TARGETTEXT,35,75,103,10 + LTEXT "",IDC_TARGETTEXT,37,75,103,10 + PUSHBUTTON "Drop Waypoint",IDC_DROP_WAYPOINT_BUTTON,33,97,82,14 + PUSHBUTTON "Center Camera On Selected Object", + IDC_CENTER_ON_SELECTED,13,128,116,14 END -IDD_WAYPOINT_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 212 +IDD_WAYPOINT_OPTIONS DIALOG DISCARDABLE 0, 0, 200, 186 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Waypoint Options" FONT 8, "MS Sans Serif" BEGIN GROUPBOX "Waypoint Name:",IDC_WAYPOINT_CAPTION1,1,1,195,34 - COMBOBOX IDC_WAYPOINTNAME_EDIT,7,15,186,88,CBS_DROPDOWN | + COMBOBOX IDC_WAYPOINTNAME_EDIT,7,15,186,88,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_WAYPOINTLABEL1_EDIT,7,119,182,12,ES_AUTOHSCROLL EDITTEXT IDC_WAYPOINTLABEL2_EDIT,8,134,182,12,ES_AUTOHSCROLL @@ -1633,7 +1593,7 @@ BEGIN EDITTEXT IDC_WAYPOINT_LOCATIONY,111,50,69,12,ES_AUTOHSCROLL GROUPBOX "List of Current Waypoints:",IDC_LIST_WAYPOINTS,1,74,195, 28 - COMBOBOX IDC_LIST_OF_WAYPOINT_NAMES,7,85,183,88,CBS_DROPDOWN | + COMBOBOX IDC_LIST_OF_WAYPOINT_NAMES,7,85,183,88,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "Bi-Directional",IDC_WAYPOINT_BIDIRECTIONAL,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,11,172,132,9 @@ -1647,7 +1607,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,99,110,50,14 PUSHBUTTON "Cancel",IDCANCEL,152,110,50,14 LTEXT "REPLACEIT",IDC_REPLACETHISTEXT,7,7,195,19 - LISTBOX IDC_VALIDTEAMLIST,7,27,195,82,LBS_SORT | + LISTBOX IDC_VALIDTEAMLIST,7,27,195,82,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END @@ -1656,62 +1616,62 @@ STYLE WS_CHILD | WS_CAPTION CAPTION "Generic" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_TeamGeneric_Script1,58,13,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script1,58,13,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 1:",IDC_SCRIPT_PREFIX1,6,14,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script2,58,31,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script2,58,31,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 2:",IDC_SCRIPT_PREFIX2,6,32,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script3,58,49,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script3,58,49,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 3:",IDC_SCRIPT_PREFIX3,6,50,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script4,58,67,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script4,58,67,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 4:",IDC_SCRIPT_PREFIX4,6,68,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script5,58,85,160,67,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script5,58,85,160,67,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 5:",IDC_SCRIPT_PREFIX5,6,86,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script6,58,103,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script6,58,103,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 6:",IDC_SCRIPT_PREFIX6,6,104,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script7,58,121,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script7,58,121,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 7:",IDC_SCRIPT_PREFIX7,6,122,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script8,58,139,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script8,58,139,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 8:",IDC_SCRIPT_PREFIX8,6,140,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script9,58,157,160,67,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script9,58,157,160,67,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 9:",IDC_SCRIPT_PREFIX9,6,158,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script10,58,175,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script10,58,175,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 10:",IDC_SCRIPT_PREFIX10,6,176,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script11,58,193,160,65,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script11,58,193,160,65,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 11:",IDC_SCRIPT_PREFIX11,6,194,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script12,58,211,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script12,58,211,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 12:",IDC_SCRIPT_PREFIX12,6,212,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script13,58,229,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script13,58,229,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 13:",IDC_SCRIPT_PREFIX13,6,230,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script14,58,247,160,65,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script14,58,247,160,65,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 14:",IDC_SCRIPT_PREFIX14,6,248,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script15,58,265,160,67,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script15,58,265,160,67,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 15:",IDC_SCRIPT_PREFIX15,6,266,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script16,58,283,160,73,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script16,58,283,160,73,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 16:",IDC_SCRIPT_PREFIX16,6,284,47,12, SS_CENTERIMAGE @@ -1729,6 +1689,180 @@ BEGIN DEFPUSHBUTTON "Preview",IDC_PREVIEW,7,52,50,14 END +IDD_RULER_OPTIONS DIALOG DISCARDABLE 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Ruler Options" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Diameter:",IDC_STATIC,39,25,35,9 + EDITTEXT IDC_RULER_WIDTH,83,21,54,14,ES_AUTOHSCROLL + CONTROL "Circular Measurements:",IDC_CHECK_RULER,"Button", + BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,40,51,95,14 +END + +IDD_TeamObjectProperties DIALOG DISCARDABLE 0, 0, 213, 327 +STYLE DS_MODALFRAME | WS_CHILD | WS_DISABLED | WS_CAPTION | WS_SYSMENU +CAPTION "Common Object Properties" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Initial Health %",IDC_STATIC,11,57,58,8,WS_DISABLED + COMBOBOX IDC_MAPOBJECT_StartingHealth,79,54,95,71, + CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_MAPOBJECT_StartingHealthEdit,180,54,25,14, + ES_AUTOHSCROLL | WS_DISABLED + CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,11,86,58,10 + CONTROL "Indestructible",IDC_MAPOBJECT_Indestructible,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,11,110,58,10 + CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,79,86,58,10 + CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,11,97,58,10 + LTEXT "Aggressiveness:",IDC_STATIC,11,126,66,8,WS_DISABLED + COMBOBOX IDC_MAPOBJECT_Aggressiveness,79,124,126,73, + CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_MAPOBJECT_VisionDistance,177,209,27,14, + ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Targetting Distance:",IDC_STATIC,90,211,83,8, + WS_DISABLED + CONTROL "AI Recruitable",IDC_MAPOBJECT_RecruitableAI,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,79,110,69,10 + LTEXT "Shroud Clearing Distance:",IDC_STATIC,90,230,83,8, + WS_DISABLED + EDITTEXT IDC_MAPOBJECT_ShroudClearingDistance,177,226,27,14, + ES_AUTOHSCROLL | WS_DISABLED + LTEXT "Veterancy:",IDC_STATIC,11,142,66,8,WS_DISABLED + COMBOBOX IDC_MAPOBJECT_Veterancy,79,140,126,73,CBS_DROPDOWNLIST | + WS_DISABLED | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_Weather,79,158,126,76,CBS_DROPDOWNLIST | + WS_DISABLED | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_Time,79,174,126,65,CBS_DROPDOWNLIST | + WS_DISABLED | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_HitPoints,79,70,126,52,CBS_DROPDOWN | + CBS_SORT | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + LTEXT "Max Hitpoints",IDC_STATIC,11,71,58,8,WS_DISABLED + EDITTEXT IDC_MAPOBJECT_StoppingDistance,177,190,27,14, + ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + LTEXT "Stopping Distance:",IDC_STATIC,90,193,83,8,WS_DISABLED + CONTROL "Selectable",IDC_MAPOBJECT_Selectable,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,79,97,58,10 + LTEXT "Weather:",IDC_STATIC,11,159,66,8,WS_DISABLED + LTEXT "Time:",IDC_STATIC,11,175,66,8,WS_DISABLED + DEFPUSHBUTTON "Update Team Members",IDC_UPDATE_TEAM_MEMBERS,53,278,107, + 14,WS_DISABLED | WS_GROUP +END + +IDD_MAPOBJECT_PROPS DIALOG DISCARDABLE 0, 0, 205, 382 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Object Properties" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_MAPOBJECT_Name,33,11,160,12,ES_AUTOHSCROLL | + WS_GROUP + COMBOBOX IDC_MAPOBJECT_Team,33,26,160,141,CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_Script,33,40,160,67,CBS_DROPDOWNLIST | + WS_DISABLED | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_StartingHealth,64,64,34,71, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP + EDITTEXT IDC_MAPOBJECT_StartingHealthEdit,101,64,25,14, + ES_AUTOHSCROLL + COMBOBOX IDC_MAPOBJECT_HitPoints,63,83,66,52,CBS_DROPDOWN | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_Aggressiveness,63,101,65,73, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_Veterancy,63,119,65,73,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,133,63,42,10 + CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,133,73,49,10 + CONTROL "Targetable",IDC_MAPOBJECT_Targetable,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,133,83,50,10 + CONTROL "Indestructible",IDC_MAPOBJECT_Indestructible,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,133,93,58,10 + CONTROL "AI Recruitable",IDC_MAPOBJECT_RecruitableAI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,133,103,61,10 + CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,133,113,44,10 + CONTROL "Selectable",IDC_MAPOBJECT_Selectable2,"Button", + BS_AUTO3STATE | WS_TABSTOP,133,123,49,10 + EDITTEXT IDC_MAPOBJECT_StoppingDistance,41,140,27,12, + ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP + EDITTEXT IDC_MAPOBJECT_VisionDistance,105,140,27,12, + ES_AUTOHSCROLL + EDITTEXT IDC_MAPOBJECT_ShroudClearingDistance,163,140,27,12, + ES_AUTOHSCROLL + EDITTEXT IDC_MAPOBJECT_XYPosition,38,172,93,12,ES_AUTOHSCROLL + EDITTEXT IDC_MAPOBJECT_ZOffset,158,172,24,12,ES_AUTOHSCROLL + PUSHBUTTON "1",IDC_HEIGHT_POPUP,185,171,8,12,BS_BITMAP + EDITTEXT IDC_MAPOBJECT_Angle,158,188,24,12,ES_AUTOHSCROLL + PUSHBUTTON "1",IDC_ANGLE_POPUP,185,188,8,12,BS_BITMAP + COMBOBOX IDC_MAPOBJECT_Weather,39,188,93,76,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_GROUP | WS_TABSTOP + COMBOBOX IDC_MAPOBJECT_Time,39,204,93,65,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_SOUND_COMBO,66,232,127,160,CBS_DROPDOWNLIST | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_GROUP | + WS_TABSTOP + CONTROL "Customize",IDC_CUSTOMIZE_CHECKBOX,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,14,247,55,10 + CONTROL "Enabled",IDC_ENABLED_CHECKBOX,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,78,247,50,10 + CONTROL "Looping",IDC_LOOPING_CHECKBOX,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,142,247,50,10 + EDITTEXT IDC_LOOPCOUNT_EDIT,53,258,40,12,ES_AUTOHSCROLL | + ES_NUMBER + COMBOBOX IDC_PRIORITY_COMBO,127,258,65,70,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_VOLUME_EDIT,53,274,40,12,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_MIN_VOLUME_EDIT,146,274,45,12,ES_AUTOHSCROLL | + ES_NUMBER + EDITTEXT IDC_MIN_RANGE_EDIT,53,290,40,12,ES_AUTOHSCROLL | + ES_NUMBER + EDITTEXT IDC_MAX_RANGE_EDIT,146,290,45,12,ES_AUTOHSCROLL | + ES_NUMBER + CONTROL "No Scale",IDC_SCALE_OFF,"Button",BS_AUTORADIOBUTTON | + NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,120,207,45,10 + CONTROL "z",IDC_SCALE_ON,"Button",BS_AUTORADIOBUTTON | NOT + WS_VISIBLE | WS_DISABLED | WS_TABSTOP,153,208,8,10 + EDITTEXT IDC_MAPOBJECT_Scale,163,204,24,14,ES_AUTOHSCROLL | NOT + WS_VISIBLE | WS_DISABLED + PUSHBUTTON "1",IDC_SCALE_POPUP,189,206,8,12,BS_BITMAP | NOT + WS_VISIBLE | WS_DISABLED + LISTBOX IDC_MAPOBJECT_BuildWithUpgrades,7,318,184,50, + LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | + WS_GROUP | WS_TABSTOP + GROUPBOX "General",IDC_STATIC_MAPOBJECT_GENERAL,4,2,193,54 + GROUPBOX "Logical",IDC_STATIC_MAPOBJECT_LOGICAL,4,56,193,105 + GROUPBOX "Sound",IDC_STATIC_MAPOBJECT_SOUND,4,223,193,82 + GROUPBOX "Visual",IDC_STATIC_MAPOBJECT_VISUAL,4,163,193,58 + LTEXT "Attached Sound:",IDC_STATIC,10,234,54,8 + LTEXT "Loop Count:",IDC_STATIC,8,258,40,8 + LTEXT "Volume:",IDC_STATIC,22,276,26,8 + LTEXT "Min Volume:",IDC_STATIC,102,276,40,8 + LTEXT "Min Range:",IDC_STATIC,10,294,38,8 + LTEXT "Max Range:",IDC_STATIC,102,294,40,8 + LTEXT "Priority:",IDC_STATIC,102,258,24,8 + LTEXT "Initial Health %",IDC_STATIC,13,67,47,8 + LTEXT "Max HP",IDC_STATIC,34,84,26,8 + RTEXT "Aggressiveness:",IDC_STATIC,8,102,52,8 + RTEXT "Veterancy:",IDC_STATIC,25,120,35,8 + LTEXT "Stopping:",IDC_STATIC,10,143,31,8 + LTEXT "Targeting:",IDC_STATIC,72,143,33,8 + LTEXT "Shroud:",IDC_STATIC,136,143,26,8 + GROUPBOX "Distance",IDC_MAPOBJECT_DISTANCE,7,131,188,27 + LTEXT "Name:",IDC_STATIC,9,13,22,8 + LTEXT "Team:",IDC_STATICTEAMCAPTION,9,28,21,8 + LTEXT "Script:",IDC_STATIC,9,42,21,8,WS_DISABLED + RTEXT "Weather:",IDC_STATIC,7,191,30,8 + RTEXT "Time:",IDC_STATIC,19,206,18,8 + LTEXT "Angle:",IDC_STATIC,136,191,21,8 + LTEXT "Z:",IDC_STATIC,146,174,8,8 + GROUPBOX "Pre-built upgrades",IDC_STATIC,4,307,193,67 + RTEXT "XY Pos:",IDC_STATIC,8,174,26,8 +END + #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// @@ -1782,7 +1916,7 @@ END // #ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO DISCARDABLE +GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_ABOUTBOX, DIALOG BEGIN @@ -1818,7 +1952,7 @@ BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 195 TOPMARGIN, 5 - BOTTOMMARGIN, 294 + BOTTOMMARGIN, 282 END IDD_MOUND_OPTIONS, DIALOG @@ -1826,7 +1960,7 @@ BEGIN LEFTMARGIN, 1 RIGHTMARGIN, 196 TOPMARGIN, 1 - BOTTOMMARGIN, 180 + BOTTOMMARGIN, 143 END IDD_OBJECT_OPTIONS, DIALOG @@ -1871,7 +2005,7 @@ BEGIN LEFTMARGIN, 1 RIGHTMARGIN, 196 TOPMARGIN, 1 - BOTTOMMARGIN, 215 + BOTTOMMARGIN, 183 END IDD_MESHMOLD_OPTIONS, DIALOG @@ -1903,7 +2037,7 @@ BEGIN LEFTMARGIN, 1 RIGHTMARGIN, 118 TOPMARGIN, 1 - BOTTOMMARGIN, 186 + BOTTOMMARGIN, 153 END IDD_OPEN_MAP, DIALOG @@ -1922,14 +2056,6 @@ BEGIN BOTTOMMARGIN, 227 END - IDD_MAPOBJECT_PROPS, DIALOG - BEGIN - LEFTMARGIN, 3 - RIGHTMARGIN, 197 - TOPMARGIN, 3 - BOTTOMMARGIN, 308 - END - IDD_PROPEDIT, DIALOG BEGIN LEFTMARGIN, 7 @@ -2026,9 +2152,9 @@ BEGIN IDD_ScriptAction, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 263 + RIGHTMARGIN, 304 TOPMARGIN, 7 - BOTTOMMARGIN, 142 + BOTTOMMARGIN, 443 END IDD_TEAMS_DIALOG, DIALOG @@ -2097,7 +2223,7 @@ BEGIN LEFTMARGIN, 2 RIGHTMARGIN, 196 TOPMARGIN, 7 - BOTTOMMARGIN, 166 + BOTTOMMARGIN, 159 END IDD_FENCE_OPTIONS, DIALOG @@ -2105,7 +2231,7 @@ BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 195 TOPMARGIN, 5 - BOTTOMMARGIN, 241 + BOTTOMMARGIN, 202 END IDD_BLEND_MATERIAL, DIALOG @@ -2113,7 +2239,7 @@ BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 195 TOPMARGIN, 5 - BOTTOMMARGIN, 241 + BOTTOMMARGIN, 213 END IDD_ADDPLAYER, DIALOG @@ -2153,7 +2279,7 @@ BEGIN LEFTMARGIN, 1 RIGHTMARGIN, 196 TOPMARGIN, 1 - BOTTOMMARGIN, 177 + BOTTOMMARGIN, 82 END IDD_MAP_SETTINGS, DIALOG @@ -2201,7 +2327,7 @@ BEGIN LEFTMARGIN, 1 RIGHTMARGIN, 196 TOPMARGIN, 1 - BOTTOMMARGIN, 208 + BOTTOMMARGIN, 182 END IDD_CHANGE_TEAM_OWNER, DIALOG @@ -2227,6 +2353,27 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 66 END + + IDD_RULER_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + IDD_TeamObjectProperties, DIALOG + BEGIN + BOTTOMMARGIN, 321 + END + + IDD_MAPOBJECT_PROPS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 197 + TOPMARGIN, 7 + BOTTOMMARGIN, 374 + END END #endif // APSTUDIO_INVOKED @@ -2274,186 +2421,201 @@ IDC_SCORCH CURSOR DISCARDABLE "IDC_Scorch.cur" IDD_PROPEDIT DLGINIT BEGIN IDC_KEYTYPE, 0x403, 5, 0 -0x6f42, 0x6c6f, "\000" +0x6f42, 0x6c6f, "\000" IDC_KEYTYPE, 0x403, 4, 0 -0x6e49, 0x0074, +0x6e49, 0x0074, IDC_KEYTYPE, 0x403, 5, 0 -0x6552, 0x6c61, "\000" +0x6552, 0x6c61, "\000" IDC_KEYTYPE, 0x403, 6, 0 -0x7341, 0x6963, 0x0069, +0x7341, 0x6963, 0x0069, IDC_KEYTYPE, 0x403, 8, 0 -0x6e55, 0x6369, 0x646f, 0x0065, +0x6e55, 0x6369, 0x646f, 0x0065, 0 END IDD_BUILD_LIST_PANEL DLGINIT BEGIN IDC_REBUILDS, 0x403, 5, 0 -0x6f4e, 0x656e, "\000" +0x6f4e, 0x656e, "\000" IDC_REBUILDS, 0x403, 2, 0 -0x0031, +0x0031, IDC_REBUILDS, 0x403, 2, 0 -0x0032, +0x0032, IDC_REBUILDS, 0x403, 2, 0 -0x0033, +0x0033, IDC_REBUILDS, 0x403, 2, 0 -0x0034, +0x0034, IDC_REBUILDS, 0x403, 2, 0 -0x0035, +0x0035, IDC_REBUILDS, 0x403, 10, 0 -0x6e55, 0x696c, 0x696d, 0x6574, 0x0064, - 0 -END - -IDD_ScriptCondition DLGINIT -BEGIN - IDC_CONDITION_TYPE, 0x403, 6, 0 -0x654e, 0x6576, 0x0072, - IDC_CONDITION_TYPE, 0x403, 29, 0 -0x6f43, 0x6e75, 0x6574, 0x2072, 0x6f63, 0x706d, 0x7261, 0x6465, 0x7420, -0x206f, 0x2061, 0x6176, 0x756c, 0x2e65, "\000" - IDC_CONDITION_TYPE, 0x403, 26, 0 -0x6c46, 0x6761, 0x6320, 0x6d6f, 0x6170, 0x6572, 0x2064, 0x6f74, 0x6120, -0x7620, 0x6c61, 0x6575, 0x002e, - IDC_CONDITION_TYPE, 0x403, 7, 0 -0x6c41, 0x6177, 0x7379, "\000" - 0 -END - -IDD_ScriptAction DLGINIT -BEGIN - IDC_CONDITION_TYPE, 0x403, 18, 0 -0x6544, 0x7562, 0x2067, 0x654d, 0x7373, 0x6761, 0x2065, 0x6f42, 0x0078, - - IDC_CONDITION_TYPE, 0x403, 21, 0 -0x6553, 0x2074, 0x6c66, 0x6761, 0x7420, 0x206f, 0x2061, 0x6176, 0x756c, -0x2e65, "\000" - IDC_CONDITION_TYPE, 0x403, 24, 0 -0x6553, 0x2074, 0x6f63, 0x6e75, 0x6574, 0x2072, 0x6f74, 0x6120, 0x7620, -0x6c61, 0x6575, 0x002e, - IDC_CONDITION_TYPE, 0x403, 8, 0 -0x6956, 0x7463, 0x726f, 0x0079, - IDC_CONDITION_TYPE, 0x403, 7, 0 -0x6544, 0x6566, 0x7461, "\000" - IDC_CONDITION_TYPE, 0x403, 14, 0 -0x6f4e, 0x6f20, 0x6570, 0x6172, 0x6974, 0x6e6f, 0x002e, +0x6e55, 0x696c, 0x696d, 0x6574, 0x0064, 0 END IDD_TeamReinforcement DLGINIT BEGIN IDC_TRANSPORT_COMBO, 0x403, 11, 0 -0x6548, 0x696c, 0x6f63, 0x7470, 0x7265, "\000" +0x6548, 0x696c, 0x6f63, 0x7470, 0x7265, "\000" IDC_VETERANCY, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_VETERANCY, 0x403, 8, 0 -0x6556, 0x6574, 0x6172, 0x006e, +0x6556, 0x6574, 0x6172, 0x006e, IDC_VETERANCY, 0x403, 6, 0 -0x6c45, 0x7469, 0x0065, +0x6c45, 0x7469, 0x0065, IDC_VETERANCY, 0x403, 7, 0 -0x6548, 0x6f72, 0x6369, "\000" +0x6548, 0x6f72, 0x6369, "\000" IDC_WAYPOINT_COMBO, 0x403, 9, 0 -0x6157, 0x7079, 0x696f, 0x746e, "\000" +0x6157, 0x7079, 0x696f, 0x746e, "\000" 0 END IDD_TeamBehavior DLGINIT BEGIN IDC_ENEMY_INTERACTIONS, 0x403, 6, 0 -0x6c53, 0x6565, 0x0070, +0x6c53, 0x6565, 0x0070, IDC_ENEMY_INTERACTIONS, 0x403, 8, 0 -0x6150, 0x7373, 0x7669, 0x0065, +0x6150, 0x7373, 0x7669, 0x0065, IDC_ENEMY_INTERACTIONS, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_ENEMY_INTERACTIONS, 0x403, 6, 0 -0x6c41, 0x7265, 0x0074, +0x6c41, 0x7265, 0x0074, IDC_ENEMY_INTERACTIONS, 0x403, 11, 0 -0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" +0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" 0 END -IDD_MAPOBJECT_PROPS DLGINIT +IDD_SCORCH_OPTIONS DLGINIT +BEGIN + IDC_SCORCHTYPE, 0x403, 9, 0 +0x6353, 0x726f, 0x6863, 0x3120, "\000" + IDC_SCORCHTYPE, 0x403, 9, 0 +0x6353, 0x726f, 0x6863, 0x3220, "\000" + IDC_SCORCHTYPE, 0x403, 9, 0 +0x6353, 0x726f, 0x6863, 0x3320, "\000" + IDC_SCORCHTYPE, 0x403, 9, 0 +0x6353, 0x726f, 0x6863, 0x3420, "\000" + IDC_SCORCHTYPE, 0x403, 13, 0 +0x6f52, 0x6e75, 0x2064, 0x6853, 0x6461, 0x776f, "\000" + IDC_SCORCHTYPE, 0x403, 12, 0 +0x7243, 0x6361, 0x206b, 0x614d, 0x6b72, 0x0073, + 0 +END + +IDD_WATER_OPTIONS DLGINIT +BEGIN + IDC_WATERNAME_EDIT, 0x403, 22, 0 +0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, +0x6f69, 0x006e, + 0 +END + +IDD_WAYPOINT_OPTIONS DLGINIT +BEGIN + IDC_WAYPOINTNAME_EDIT, 0x403, 22, 0 +0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, +0x6f69, 0x006e, + IDC_LIST_OF_WAYPOINT_NAMES, 0x403, 1, 0 +"\000" + 0 +END + +IDD_TeamObjectProperties DLGINIT BEGIN IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 -0x6544, 0x6461, "\000" +0x6544, 0x6461, "\000" IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3532, 0x0025, +0x3532, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3035, 0x0025, +0x3035, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3537, 0x0025, +0x3537, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 -0x3031, 0x2530, "\000" +0x3031, 0x2530, "\000" IDC_MAPOBJECT_StartingHealth, 0x403, 6, 0 -0x744f, 0x6568, 0x0072, +0x744f, 0x6568, 0x0072, IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 -0x6c53, 0x6565, 0x0070, +0x6c53, 0x6565, 0x0070, IDC_MAPOBJECT_Aggressiveness, 0x403, 8, 0 -0x6150, 0x7373, 0x7669, 0x0065, +0x6150, 0x7373, 0x7669, 0x0065, IDC_MAPOBJECT_Aggressiveness, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 -0x6c41, 0x7265, 0x0074, +0x6c41, 0x7265, 0x0074, IDC_MAPOBJECT_Aggressiveness, 0x403, 11, 0 -0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" +0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_MAPOBJECT_Veterancy, 0x403, 8, 0 -0x6556, 0x6574, 0x6172, 0x006e, +0x6556, 0x6574, 0x6172, 0x006e, IDC_MAPOBJECT_Veterancy, 0x403, 6, 0 -0x6c45, 0x7469, 0x0065, +0x6c45, 0x7469, 0x0065, IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 -0x6548, 0x6f72, 0x6369, "\000" +0x6548, 0x6f72, 0x6369, "\000" IDC_MAPOBJECT_Weather, 0x403, 16, 0 -0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, +0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, IDC_MAPOBJECT_Weather, 0x403, 17, 0 -0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" +0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" IDC_MAPOBJECT_Weather, 0x403, 15, 0 -0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" +0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" IDC_MAPOBJECT_Time, 0x403, 13, 0 -0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" +0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" IDC_MAPOBJECT_Time, 0x403, 14, 0 -0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, +0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, IDC_MAPOBJECT_Time, 0x403, 16, 0 -0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, +0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, IDC_MAPOBJECT_HitPoints, 0x403, 19, 0 -0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, -"\000" - 0 -END - -IDD_SCORCH_OPTIONS DLGINIT -BEGIN - IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3120, "\000" - IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3220, "\000" - IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3320, "\000" - IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3420, "\000" - IDC_SCORCHTYPE, 0x403, 13, 0 -0x6f52, 0x6e75, 0x2064, 0x6853, 0x6461, 0x776f, "\000" - IDC_SCORCHTYPE, 0x403, 12, 0 -0x7243, 0x6361, 0x206b, 0x614d, 0x6b72, 0x0073, - 0 -END - -IDD_WATER_OPTIONS DLGINIT -BEGIN - IDC_WATERNAME_EDIT, 0x403, 22, 0 -0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, -0x6f69, 0x006e, +0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, +"\000" 0 END -IDD_WAYPOINT_OPTIONS DLGINIT +IDD_MAPOBJECT_PROPS DLGINIT BEGIN - IDC_WAYPOINTNAME_EDIT, 0x403, 22, 0 -0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, -0x6f69, 0x006e, - IDC_LIST_OF_WAYPOINT_NAMES, 0x403, 1, 0 -"\000" + IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 +0x6544, 0x6461, "\000" + IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 +0x3532, 0x0025, + IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 +0x3035, 0x0025, + IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 +0x3537, 0x0025, + IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 +0x3031, 0x2530, "\000" + IDC_MAPOBJECT_StartingHealth, 0x403, 6, 0 +0x744f, 0x6568, 0x0072, + IDC_MAPOBJECT_HitPoints, 0x403, 19, 0 +0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, +"\000" + IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 +0x6c53, 0x6565, 0x0070, + IDC_MAPOBJECT_Aggressiveness, 0x403, 8, 0 +0x6150, 0x7373, 0x7669, 0x0065, + IDC_MAPOBJECT_Aggressiveness, 0x403, 7, 0 +0x6f4e, 0x6d72, 0x6c61, "\000" + IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 +0x6c41, 0x7265, 0x0074, + IDC_MAPOBJECT_Aggressiveness, 0x403, 11, 0 +0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" + IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 +0x6f4e, 0x6d72, 0x6c61, "\000" + IDC_MAPOBJECT_Veterancy, 0x403, 8, 0 +0x6556, 0x6574, 0x6172, 0x006e, + IDC_MAPOBJECT_Veterancy, 0x403, 6, 0 +0x6c45, 0x7469, 0x0065, + IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 +0x6548, 0x6f72, 0x6369, "\000" + IDC_MAPOBJECT_Weather, 0x403, 16, 0 +0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, + IDC_MAPOBJECT_Weather, 0x403, 17, 0 +0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" + IDC_MAPOBJECT_Weather, 0x403, 15, 0 +0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" + IDC_MAPOBJECT_Time, 0x403, 13, 0 +0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" + IDC_MAPOBJECT_Time, 0x403, 14, 0 +0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, + IDC_MAPOBJECT_Time, 0x403, 16, 0 +0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, 0 END @@ -2463,19 +2625,19 @@ END // String Table // -STRINGTABLE PRELOAD DISCARDABLE +STRINGTABLE PRELOAD DISCARDABLE BEGIN IDR_MAINFRAME "Generals World Builder\nMission\nMission\n Missions (*.map)\n.map\nGeneralsMap\n Generals Mission Map" IDS_SKELETON "SkeletonWindow" END -STRINGTABLE PRELOAD DISCARDABLE +STRINGTABLE PRELOAD DISCARDABLE BEGIN AFX_IDS_APP_TITLE "WorldBuilder" AFX_IDS_IDLEMESSAGE "Ready" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_INDICATOR_EXT "EXT" ID_INDICATOR_CAPS "CAP" @@ -2485,7 +2647,7 @@ BEGIN ID_INDICATOR_REC "REC" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FILE_NEW "Create a new document\nNew" ID_FILE_OPEN "Open an existing document\nOpen" @@ -2498,13 +2660,13 @@ BEGIN ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_APP_ABOUT "Display program information, version number and copyright\nAbout" ID_APP_EXIT "Quit the application; prompts to save documents\nExit" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FILE_MRU_FILE1 "Open this document" ID_FILE_MRU_FILE2 "Open this document" @@ -2524,13 +2686,13 @@ BEGIN ID_FILE_MRU_FILE16 "Open this document" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_NEXT_PANE "Switch to the next window pane\nNext Pane" ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_WINDOW_NEW "Open another window for the active document\nNew Window" ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons" @@ -2540,7 +2702,7 @@ BEGIN ID_WINDOW_SPLIT "Split the active window into panes\nSplit" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_EDIT_CLEAR "Erase the selection\nErase" ID_EDIT_CLEAR_ALL "Erase everything\nErase All" @@ -2555,13 +2717,13 @@ BEGIN ID_EDIT_REDO "Redo the previously undone action\nRedo" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar" ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN AFX_IDS_SCSIZE "Change the window size" AFX_IDS_SCMOVE "Change the window position" @@ -2572,14 +2734,14 @@ BEGIN AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN AFX_IDS_SCRESTORE "Restore the window to normal size" AFX_IDS_SCTASKLIST "Activate Task List" AFX_IDS_MDICHILD "Activate this window" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN AFX_IDS_PREVIEW_CLOSE "Close print preview mode\nCancel Preview" IDS_NEW "New" @@ -2594,18 +2756,53 @@ BEGIN IDS_FILE_IS_READONLY "The file is read-only. Change the protection, or use Save As to save to another file." END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE +BEGIN + IDS_REPLACEFILE "%s already exists. Do you want to replace it?" + IDS_ONLY_ONE_FILE "Sorry, only one map may be open at a time." + IDS_NO_AUTOSAVE "Unable to autosave file." + IDS_TOO_MANY_TILES "Warning - too many textures to fit in map." + IDS_TOO_MANY_BLENDS "Warning - too many blends to fit in map." + IDS_TEXTURE_TOO_LARGE "There is not room to add this texture to the map. You can use the paintbucket tool to replace another texture with this one." + IDS_ALPHA_BLEND "Alpha Blend" + IDS_SCRIPT_INFORMATION "Information:" + IDS_SCRIPT_WARNINGS "Warnings:" + IDS_SCRIPT_NOWARNINGS "No Warnings" + IDS_CONFIRM_REPLACE_TEXTURE "Replace all occurences of texture %s?" + ID_RAMPTOOL "Place Ramps on the map\nRamp" + IDS_CONFIRM_REMOVE_CLIFF_MAPPING + "Remove all cliff mapping in the entire map?" + IDS_NUM_SELECTED_ON_TEAM "For team %s, %d units selected." + IDS_MAX_OBJECTS "The object count has exceeded %d. Please reduce the number of objects in this map or performance will suffer." + IDS_REPLACEOWNER "Team %s has an invalid owner. Please select a valid owner from the list below:" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_SPLASH_LOADING "Loading..." + IDS_SINGLE_SELECTION_ONLY "Single Selection Only" + IDS_NO_UPGRADES "No Upgrades Available" + IDS_TEAMS_FIXED "One or more teams have been fixed. Please save and re-open the file." + IDS_MAPOBJECT_PROPS_TITLE "Object Properties" + IDS_NO_PROBLEMS "No problems were detected." + IDS_DUPLICATE_TEAM_REMOVED "Duplicate instance of team ""%s"" removed." + IDS_PLAYERLESS_TEAM_REMOVED + "Team ""%s"" was on non-existent player ""%s"". Team removed." + IDS_NEED_TO_FIX_TEAMS "One or more objects had invalid teams. Please run Validation>Fix Teams to correct this." +END + +STRINGTABLE DISCARDABLE BEGIN ID_BRUSH_TOOL "Draw the height on the height map.\nHeight Brush" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FEATHERTOOL "Smooths the height levels in the height map.\nSmooth Height" ID_BIG_TILE_TOOL "Draws a Brush Options Size block of the current texture tile. \nLarge Tile" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_BRUSH_ADD_TOOL "Adds height to (raises) the height map.\nMound" ID_BRUSH_SUBTRACT_TOOL "Removes height from (lowers) the height map.\nDig" @@ -2614,7 +2811,7 @@ BEGIN ID_AUTO_EDGE_OUT_TOOL "Auto edges the current texture area outward.\nAuto Edge Out" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_EYEDROPPER_TOOL "Hot key ALT. Selects the foreground texture by picking on the texture in the edit windows.\nEyedropper" ID_PLACE_OBJECT_TOOL "Places the current object in Object Selection panel. Drag to orient.\nPlace Object" @@ -2623,10 +2820,9 @@ BEGIN ID_GROVE_TOOL "Click to place random foliage, drag to place foliage in a rectangular area.\nGrove" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN - ID_LOOK_WEST "Rotate the camera to look West.\nLook West" - ID_LOOK_EAST "Rotate the camera to look East.\nLook East" + ID_TEAM_EDIT "Edit teams.\nEdit Teams" ID_LOCK_HORIZONTAL "Lock tool movement to 45 degree increment.\nLock Angle" ID_LOCK_VERTICAL "Lock tool movement to up and down.\nLock Vertical" ID_WAYPOINT_TOOL "Add and connect waypoints.\nWaypoint Tool" @@ -2635,75 +2831,52 @@ BEGIN ID_HAND_SCROLL_TOOL "Hot key space bar. Scrolls the map.\nScroll" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_ROAD_TOOL "Click and Drag to make Roads.\nRoad" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_MOLD_TOOL "Shapes the terrain using a 3D mesh.\nMesh Mold Tool" - ID_LOOK_NORTH "Sets the camera angle to look North.\nLook North" - ID_LOOK_SOUTH "Rotate the camera to look South.\nLook South" + ID_RULER_TOOL "Measure distance between two points. \nRuler Tool" + ID_SCRIPT_EDIT "Edit scripts.\nEdit Scripts" END -STRINGTABLE DISCARDABLE -BEGIN - IDS_REPLACEFILE "%s already exists. Do you want to replace it?" - IDS_ONLY_ONE_FILE "Sorry, only one map may be open at a time." - IDS_NO_AUTOSAVE "Unable to autosave file." - IDS_TOO_MANY_TILES "Warning - too many textures to fit in map." - IDS_TOO_MANY_BLENDS "Warning - too many blends to fit in map." - IDS_TEXTURE_TOO_LARGE "There is not room to add this texture to the map. You can use the paintbucket tool to replace another texture with this one." - IDS_ALPHA_BLEND "Alpha Blend" - IDS_SCRIPT_INFORMATION "Information:" - IDS_SCRIPT_WARNINGS "Warnings:" - IDS_SCRIPT_NOWARNINGS "No Warnings" - IDS_CONFIRM_REPLACE_TEXTURE "Replace all occurences of texture %s?" - ID_RAMPTOOL "Place Ramps on the map\nRamp" - IDS_CONFIRM_REMOVE_CLIFF_MAPPING - "Remove all cliff mapping in the entire map?" - IDS_NUM_SELECTED_ON_TEAM "For team %s, %d units selected." - IDS_MAX_OBJECTS "The object count has exceeded %d. Please reduce the number of objects in this map or performance will suffer." - IDS_REPLACEOWNER "Team %s has an invalid owner. Please select a valid owner from the list below:" -END - -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FENCE_TOOL "Places a row of objects. Drag then use shift to stretch.\nFence" ID_WATER_TOOL "Add and modify water areas.\nWater Tool" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_SCORCH_TOOL "Add Scorchmarks to the map\nAdd Scorchmarks" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_EDIT_MAPSETTINGS "Edit Map Settings" ID_EDIT_PICKROADS "Pick only roads" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_VIEW_LAYERS_LIST "Show or hide the layers list\nToggle LayersList" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_BORDERTOOL "Add and adjust borders.\nBorder Tool" - ID_VALIDATION_GENERATEMAPREPORT + ID_VALIDATION_GENERATEMAPREPORT "Generate a report about Map validity, possible problems, etc." ID_VALIDATION_FIXTEAMS "Adjust all teams so that they're ""Execute Associated Action"" is false." END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN - IDS_SPLASH_LOADING "Loading..." - IDS_SINGLE_SELECTION_ONLY "Single Selection Only" - IDS_NO_UPGRADES "No Upgrades Available" - IDS_TEAMS_FIXED "All Teams have been fixed." + ID_VIEW_SHOW_SOUND_CIRCLES + "Show the minimum and maximum radii around objects with ambient sounds\nShow Sound Circles" END #endif // English (U.S.) resources @@ -2733,4 +2906,3 @@ LANGUAGE 9, 1 ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED - diff --git a/Generals/Code/Tools/WorldBuilder/res/icon2.ico b/Generals/Code/Tools/WorldBuilder/res/icon2.ico new file mode 100644 index 00000000000..0bec4909604 Binary files /dev/null and b/Generals/Code/Tools/WorldBuilder/res/icon2.ico differ diff --git a/Generals/Code/Tools/WorldBuilder/res/resource.h b/Generals/Code/Tools/WorldBuilder/res/resource.h index af7dd6d8432..77f8952d856 100644 --- a/Generals/Code/Tools/WorldBuilder/res/resource.h +++ b/Generals/Code/Tools/WorldBuilder/res/resource.h @@ -1,3 +1,21 @@ +/* +** Command & Conquer Generals(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by WorldBuilder.rc @@ -114,6 +132,14 @@ #define IDD_TeamGeneric 229 #define IDD_IMPASSABLEOPTIONS 230 #define IDD_EULA_AGREEMENT 231 +#define IDD_RULER_OPTIONS 232 +#define IDD_TeamObjectProperties 233 +#define IDI_Selected 234 +#define IDD_MAPOBJECT_PROPPAGE_GENERAL 235 +#define IDD_MAPOBJECT_PROPPAGE_LOGICAL 236 +#define IDD_MAPOBJECT_PROPPAGE_VISUAL 237 +#define IDD_MAPOBJECT_PROPPAGE_UPGRADES 238 +#define IDD_MAPOBJECT_PROPPAGE_SOUND 239 #define IDC_HEIGHT_COMBO 1000 #define IDC_CELL_WIDTH 1001 #define IDC_INITIAL_HEIGHT 1002 @@ -260,8 +286,11 @@ #define IDC_COPY_SCRIPT 1125 #define IDC_DELETE 1126 #define IDC_SCRIPT_NAME 1127 +#define IDC_VERIFY 1127 #define IDC_RICH_EDIT_HERE 1128 -#define IDC_CONDITION_LIST 1129 +#define IDC_PATCH_GC 1129 +#define IDC_CONDITION_TREE 1130 +#define IDC_CONDITION_LIST 1130 #define IDC_EDIT_CONDITION 1131 #define IDC_CONDITION_TYPE 1132 #define IDC_CAPTION 1133 @@ -320,6 +349,7 @@ #define IDC_MAPOBJECT_Selectable 1166 #define IDC_PRODUCTION_EXECUTEACTIONS 1166 #define IDC_PASSABLE_CHECK 1166 +#define IDC_AUTO_VERIFY 1166 #define IDC_EASY 1167 #define IDC_CHECK2 1167 #define IDC_LR_POPUP2 1167 @@ -331,6 +361,7 @@ #define IDC_TEAM_STARTS_FULL 1168 #define IDC_WAYPOINT_BIDIRECTIONAL 1168 #define IDC_GROUP_ACTIVE 1169 +#define IDC_MAPOBJECT_Selectable2 1169 #define IDC_PLAYERDISPLAYNAME 1170 #define IDC_CHECK4 1170 #define IDC_TRANSPORTS_RETURN 1170 @@ -382,12 +413,14 @@ #define IDC_TeamGeneric_Script2 1199 #define IDC_PASSABLE 1199 #define IDC_EVERY_FRAME 1199 +#define IDC_SCALE_OFF 1199 #define IDC_MIN_UNIT7 1200 #define IDC_RADIO2 1200 #define IDC_USERMAPS 1200 #define IDC_TeamGeneric_Script3 1200 #define IDC_IMPASSABLE 1200 #define IDC_EVERY_SECOND 1200 +#define IDC_SCALE_ON 1200 #define IDC_MAX_UNIT7 1201 #define IDC_RADIO3 1201 #define IDC_TeamGeneric_Script4 1201 @@ -517,6 +550,31 @@ #define IDC_SCRIPT_PREFIX15 1313 #define IDC_SCRIPT_PREFIX16 1314 #define IDC_TeamGeneric_Script1 1315 +#define IDC_DROP_WAYPOINT_BUTTON 1316 +#define IDC_ACTION_TREE 1326 +#define IDC_CENTER_ON_SELECTED 1327 +#define IDC_CHECK_RULER 1328 +#define IDC_SIDES 1329 +#define IDC_RULER_WIDTH 1330 +#define IDC_UPDATE_TEAM_MEMBERS 1331 +#define IDC_USE_TEAM_DEFAULTS 1332 +#define IDC_LOOPING_CHECKBOX 1333 +#define IDC_ENABLED_CHECKBOX 1334 +#define IDC_CUSTOMIZE_CHECKBOX 1335 +#define IDC_MAPOBJECT_Scale 1336 +#define IDC_SOUND_COMBO 1346 +#define IDC_LOOPCOUNT_EDIT 1347 +#define IDC_MIN_VOLUME_EDIT 1348 +#define IDC_PRIORITY_COMBO 1349 +#define IDC_MIN_RANGE_EDIT 1350 +#define IDC_MAX_RANGE_EDIT 1351 +#define IDC_VOLUME_EDIT 1352 +#define IDC_MAPOBJECT_XYPosition 1353 +#define IDC_STATIC_MAPOBJECT_GENERAL 1379 +#define IDC_STATIC_MAPOBJECT_LOGICAL 1380 +#define IDC_STATIC_MAPOBJECT_SOUND 1381 +#define IDC_STATIC_MAPOBJECT_VISUAL 1382 +#define IDC_MAPOBJECT_DISTANCE 1383 #define ID_BRUSH_TOOL 32771 #define IDM_ShowGrid 32772 #define ID_FEATHERTOOL 32791 @@ -575,10 +633,9 @@ #define ID_MOLD_TOOL 32955 #define ID_VIEW_SHOWMACROTEXTURE 32956 #define ID_EDIT_SELECTMACROTEXTURE 32957 -#define ID_LOOK_NORTH 32958 -#define ID_LOOK_SOUTH 32959 -#define ID_LOOK_WEST 32960 -#define ID_LOOK_EAST 32961 +#define ID_RULER_TOOL 32958 +#define ID_SCRIPT_EDIT 32959 +#define ID_TEAM_EDIT 32960 #define ID_LOCK_HORIZONTAL 32962 #define ID_LOCK_VERTICAL 32963 #define ID_WAYPOINT_TOOL 32964 @@ -622,6 +679,11 @@ #define ID_EDIT_SELECTINVALIDTEAM 33005 #define ID_FILE_DUMPTOFILE 33006 #define ID_SCORCH_TOOL 33007 +#define ID_VIEW_BOUNDINGBOXES 33008 +#define ID_VIEW_SIGHTRANGES 33009 +#define ID_VIEW_WEAPONRANGES 33010 +#define ID_HIGHLIGHT_TESTART 33011 +#define ID_SHOW_LETTERBOX 33012 #define ID_TEXTURESIZING_REMOVECLIFFTEXMAPPING 33014 #define ID_VIEW_LAYERS_LIST 33015 #define ID_INSERTNEWLAYER 33017 @@ -653,6 +715,13 @@ #define ID_EDIT_PICKSOUNDS 33341 #define ID_VIEW_SHOW_TERRAIN 33342 #define ID_VIEW_IMPASSABLEAREAOPTIONS 33343 +#define ID_SELECTLAYEROBJECT 33344 +#define ID_SELECTACTIVELAYER 33345 +#define ID_VIEW_SHOW_SOUND_CIRCLES 33346 +#define ID_LOOK_NORTH 33347 +#define ID_LOOK_SOUTH 33348 +#define ID_LOOK_WEST 33349 +#define ID_LOOK_EAST 33350 #define IDS_NEW 61446 #define IDS_RESIZE 61447 #define IDS_REMOVING_INUSE_TEAM 61448 @@ -689,15 +758,20 @@ #define IDS_EULA_AGREEMENT3 61478 #define IDS_EULA_AGREEMENT4 61479 #define IDS_EULA_AGREEMENT5 61480 +#define IDS_MAPOBJECT_PROPS_TITLE 61481 +#define IDS_NO_PROBLEMS 61482 +#define IDS_DUPLICATE_TEAM_REMOVED 61483 +#define IDS_PLAYERLESS_TEAM_REMOVED 61484 +#define IDS_NEED_TO_FIX_TEAMS 61485 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 232 -#define _APS_NEXT_COMMAND_VALUE 33344 -#define _APS_NEXT_CONTROL_VALUE 1326 +#define _APS_NEXT_RESOURCE_VALUE 242 +#define _APS_NEXT_COMMAND_VALUE 33351 +#define _APS_NEXT_CONTROL_VALUE 1354 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/Generals/Code/Tools/WorldBuilder/src/BorderTool.cpp b/Generals/Code/Tools/WorldBuilder/src/BorderTool.cpp index 73aa050139f..db1213e8e56 100644 --- a/Generals/Code/Tools/WorldBuilder/src/BorderTool.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/BorderTool.cpp @@ -124,7 +124,7 @@ void BorderTool::mouseDown(TTrackingMode m, CPoint viewPt, WbView* pView, CWorld return; } - static Coord3D zero = {0.0f, 0.0f, 0.0f}; + //static Coord3D zero = {0.0f, 0.0f, 0.0f}; Coord3D groundPt; pView->viewToDocCoords(viewPt, &groundPt); @@ -138,10 +138,24 @@ void BorderTool::mouseDown(TTrackingMode m, CPoint viewPt, WbView* pView, CWorld Int motion; pDoc->findBoundaryNear(&groundPt, BOUNDARY_PICK_DISTANCE, &m_modifyBorderNdx, &motion); - if (motion == 0) { + + // if bottom left boundary grabbed + if (motion == 0) + { // modifying the bottom left is not allowed. m_modifyBorderNdx = -1; - } else { + } + // else if no boundary is near + else if (motion == -1) + { + // add a boundary + m_addingNewBorder = true; + + ICoord2D initialBoundary = { 1, 1 }; + pDoc->addBoundary(&initialBoundary); + } + else + { m_modificationType = (ModificationType) motion; } } diff --git a/Generals/Code/Tools/WorldBuilder/src/BrushTool.cpp b/Generals/Code/Tools/WorldBuilder/src/BrushTool.cpp index b6da31f7bcc..0e27409ba33 100644 --- a/Generals/Code/Tools/WorldBuilder/src/BrushTool.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/BrushTool.cpp @@ -20,6 +20,7 @@ // Texture tiling tool for worldbuilder. // Author: John Ahlquist, April 2001 + #include "StdAfx.h" #include "resource.h" diff --git a/Generals/Code/Tools/WorldBuilder/src/BuildList.cpp b/Generals/Code/Tools/WorldBuilder/src/BuildList.cpp index 34dc1374e7f..7d0b6439e0c 100644 --- a/Generals/Code/Tools/WorldBuilder/src/BuildList.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/BuildList.cpp @@ -737,15 +737,15 @@ void BuildList::OnExport() static FILE *theLogFile = nullptr; Bool open = false; try { - char buffer[ _MAX_PATH ]; - ::GetModuleFileName( nullptr, buffer, sizeof( buffer ) ); - if (char *pEnd = strrchr(buffer, '\\')) + char buffer[_MAX_PATH]; + ::GetModuleFileName(nullptr, buffer, sizeof(buffer)); + if (char* pEnd = strrchr(buffer, '\\')) { *(pEnd + 1) = 0; } - SidesInfo *pSide = TheSidesList->getSideInfo(m_curSide); - Dict *d = TheSidesList->getSideInfo(m_curSide)->getDict(); + SidesInfo* pSide = TheSidesList->getSideInfo(m_curSide); + Dict* d = TheSidesList->getSideInfo(m_curSide)->getDict(); AsciiString name = d->getAsciiString(TheKey_playerName); strlcat(buffer, name.str(), ARRAY_SIZE(buffer)); strlcat(buffer, "_BuildList.ini", ARRAY_SIZE(buffer)); diff --git a/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp b/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp index 9e79467c778..78e36be6d6c 100644 --- a/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/CUndoable.cpp @@ -792,9 +792,9 @@ void DictItemUndoable::Do() *m_dictToModify[i] = m_newDictData; else m_dictToModify[i]->copyPairFrom(m_newDictData, m_key); - MapObjectProps::update(); // ugh, hack to update panel - ObjectOptions::update(); // ditto } + MapObjectProps::update(); // ugh, hack to update panel + ObjectOptions::update(); // ditto if (m_inval && m_pDoc) { WbView3d *p3View = m_pDoc->GetActive3DView(); p3View->resetRenderObjects(); @@ -809,9 +809,9 @@ void DictItemUndoable::Undo() *m_dictToModify[i] = m_oldDictData[i]; else m_dictToModify[i]->copyPairFrom(m_oldDictData[i], m_key); - MapObjectProps::update(); // ugh, hack to update panel - ObjectOptions::update(); // ditto } + MapObjectProps::update(); // ugh, hack to update panel + ObjectOptions::update(); // ditto if (m_inval && m_pDoc) { WbView3d *p3View = m_pDoc->GetActive3DView(); p3View->resetRenderObjects(); @@ -1067,6 +1067,8 @@ AddPolygonUndoable::AddPolygonUndoable(PolygonTrigger *pTrig): // void AddPolygonUndoable::Do() { + // The call to LayersList must be done here because only the WorldBuilder knows about Layers. + TheLayersList->addPolygonTriggerToLayersList(m_trigger, m_trigger->getLayerName()); PolygonTrigger::addPolygonTrigger(m_trigger); m_isTriggerInList = true; } @@ -1076,6 +1078,8 @@ void AddPolygonUndoable::Do() // void AddPolygonUndoable::Undo() { + // The call to LayersList must be done here because only the WorldBuilder knows about Layers. + TheLayersList->removePolygonTriggerFromLayersList(m_trigger); PolygonTrigger::removePolygonTrigger(m_trigger); m_isTriggerInList = false; } @@ -1335,6 +1339,7 @@ DeletePolygonUndoable::DeletePolygonUndoable(PolygonTrigger *pTrig): // void DeletePolygonUndoable::Do() { + TheLayersList->removePolygonTriggerFromLayersList(m_trigger); PolygonTrigger::removePolygonTrigger(m_trigger); m_isTriggerInList = false; } @@ -1345,8 +1350,96 @@ void DeletePolygonUndoable::Do() void DeletePolygonUndoable::Undo() { PolygonTrigger::addPolygonTrigger(m_trigger); + TheLayersList->addPolygonTriggerToLayersList(m_trigger, m_trigger->getLayerName()); m_isTriggerInList = true; } +/************************************************************************* +** MultipleUndoable +***************************************************************************/ +// +// MultipleUndoable - constructor. +// +MultipleUndoable::MultipleUndoable() + : m_undoableList( nullptr ) +{ +} + +// +// MultipleUndoable - destructor +// +MultipleUndoable::~MultipleUndoable() +{ + if ( m_undoableList ) + { + REF_PTR_RELEASE(m_undoableList); + } +} + +// +// Add another undo to the list. +// +void MultipleUndoable::addUndoable( Undoable * undoable ) +{ + undoable->LinkNext( m_undoableList ); + + REF_PTR_SET( m_undoableList, undoable ); +} + + +// +/// Do all the list's actions. +// +void MultipleUndoable::Do() +{ + Undoable * undoable = m_undoableList; + + while ( undoable != nullptr ) + { + Undoable * next = undoable->GetNext(); + undoable->Do(); + undoable = next; + } +} + + +// +// Recursive function to help traverse a singly-linked list in reverse order +// +static void undoHelper(Undoable * undoable) +{ + if ( undoable == nullptr ) + return; + + undoHelper( undoable->GetNext() ); + + undoable->Undo(); +} + +// +// Undo all the list's actions. This is harder, because we need to do it in reverse order, for a +// singly linked list +// +void MultipleUndoable::Undo() +{ + undoHelper(m_undoableList); +} + + +// +/// Redo all the list's actions. +// +void MultipleUndoable::Redo() +{ + Undoable * undoable = m_undoableList; + + while ( undoable != nullptr ) + { + Undoable * next = undoable->GetNext(); + undoable->Redo(); + undoable = next; + } +} + diff --git a/Generals/Code/Tools/WorldBuilder/src/CameraOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/CameraOptions.cpp index 8057093f5e5..069c34e2ed3 100644 --- a/Generals/Code/Tools/WorldBuilder/src/CameraOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/CameraOptions.cpp @@ -19,6 +19,7 @@ // CameraOptions.cpp : implementation file // + #include "StdAfx.h" #include "resource.h" #include "WorldBuilder.h" @@ -26,6 +27,10 @@ #include "wbview3d.h" #include "WorldBuilderDoc.h" + +#include "WaypointOptions.h" //WST 10/7/2002 +#include "CUndoable.h" //WST 10/7/2002 + ///////////////////////////////////////////////////////////////////////////// // CameraOptions dialog @@ -52,12 +57,15 @@ void CameraOptions::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CameraOptions, CDialog) //{{AFX_MSG_MAP(CameraOptions) ON_BN_CLICKED(IDC_CameraReset, OnCameraReset) + ON_BN_CLICKED(IDC_DROP_WAYPOINT_BUTTON, OnDropWaypointButton) + ON_BN_CLICKED(IDC_CENTER_ON_SELECTED, OnCenterOnSelectedButton) ON_WM_MOVE() ON_EN_CHANGE(IDC_PITCH_EDIT, OnChangePitchEdit) ON_WM_SHOWWINDOW() //}}AFX_MSG_MAP END_MESSAGE_MAP() + ///////////////////////////////////////////////////////////////////////////// // CameraOptions message handlers @@ -71,6 +79,65 @@ void CameraOptions::OnCameraReset() } } +//WST 10/7/2002 - Drop waypoint button for Adam Isgreen ----------- +void CameraOptions::OnDropWaypointButton() +{ + //The following code is taken from waypointTool.cpp. On mouse down. + WbView3d * p3View = CWorldBuilderDoc::GetActive3DView(); + Coord3D docPt; + CWorldBuilderDoc *pDoc = CWorldBuilderDoc::GetActiveDoc(); + + Vector3 camTarget = p3View->getCameraTarget(); + docPt.x = camTarget.X; + docPt.y = camTarget.Y; + docPt.z = MAGIC_GROUND_Z; + + // + // MBL CNC3 INCURSION 10.29.2002 - Fix compile error w/ 10-15-2002 Drop + // + // MapObject *pNew = new MapObject(docPt, "*Waypoints/Waypoint", 0, 0, nullptr, nullptr ); + MapObject *pNew = newInstance(MapObject)(docPt, "*Waypoints/Waypoint", 0, 0, nullptr, nullptr ); + + Int id = pDoc->getNextWaypointID(); + AsciiString name = WaypointOptions::GenerateUniqueName(id); + pNew->setSelected(true); + pNew->setIsWaypoint(); + pNew->setWaypointID(id); + pNew->setWaypointName(name); + pNew->getProperties()->setAsciiString(TheKey_originalOwner, "team"); + AddObjectUndoable *pUndo = new AddObjectUndoable(pDoc, pNew); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + pNew = nullptr; // undoable owns it now. +} + +//WST 11/25/2002 - New Center Camera button for Designers ----------- +void CameraOptions::OnCenterOnSelectedButton() +{ + // Center camera on the selected map object + + int count = 0; + const Coord3D *objectPosition; + + MapObject *mapObject = MapObject::getFirstMapObject(); + while (mapObject) { + if (mapObject->isSelected()) { + objectPosition = mapObject->getLocation(); + count++; + } + mapObject = mapObject->getNext(); + } + + if (count==1) { + // Only center if there is only one object selected on map + WbView3d * p3View = CWorldBuilderDoc::GetActive3DView(); + if (p3View) { + p3View->setCenterInView(objectPosition->x/MAP_XY_FACTOR,objectPosition->y/MAP_XY_FACTOR); + } + } +} + + void CameraOptions::OnMove(int x, int y) { CDialog::OnMove(x, y); @@ -139,7 +206,9 @@ void CameraOptions::stuffValuesIntoFields() m_updating = false; Real height = p3View->getHeightAboveGround(); - Real zoom = height/TheGlobalData->m_maxCameraHeight; + //WST 10/11/2002 This is inaccurate Real zoom = height/TheGlobalData->m_maxCameraHeight; + Real zoom = p3View->getCurrentZoom(); //WST 10.11.2002 + putReal(IDC_ZOOMTEXT, zoom); putReal(IDC_HEIGHTTEXT, height); diff --git a/Generals/Code/Tools/WorldBuilder/src/ContourOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/ContourOptions.cpp index d4d0b00c39e..ce0f6ee43d4 100644 --- a/Generals/Code/Tools/WorldBuilder/src/ContourOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/ContourOptions.cpp @@ -108,7 +108,7 @@ BOOL ContourOptions::OnInitDialog() /// Handles slider ui messages. /** Gets the info, determines if it is the feather or width slider, - gets the new value, and updates the correspondig edit control + gets the new value, and updates the corresponding edit control and the brush tool. */ void ContourOptions::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { diff --git a/Generals/Code/Tools/WorldBuilder/src/DrawObject.cpp b/Generals/Code/Tools/WorldBuilder/src/DrawObject.cpp index a342e337161..a0f966521c7 100644 --- a/Generals/Code/Tools/WorldBuilder/src/DrawObject.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/DrawObject.cpp @@ -39,7 +39,6 @@ #include "WW3D2/meshmdl.h" #include "WW3D2/shader.h" #include "Common/MapObject.h" -#include "Common/ThingTemplate.h" #include "GameLogic/PolygonTrigger.h" #include "GameLogic/SidesList.h" #include "resource.h" @@ -52,6 +51,11 @@ #include "LayersList.h" #include "Common/WellKnownKeys.h" #include "Common/BorderColors.h" +#include "Common/ThingTemplate.h" +#include "W3DDevice/Common/W3DConvert.h" +#include "WW3D2/render2d.h" +#include "GameLogic/Weapon.h" +#include "Common/AudioEventInfo.h" #ifdef RTS_DEBUG #define NO_INTENSE_DEBUG 1 @@ -95,7 +99,6 @@ Bool DrawObject::m_meshFeedback = false; Bool DrawObject::m_rampFeedback = false; Bool DrawObject::m_boundaryFeedback = false; Bool DrawObject::m_ambientSoundFeedback = false; - Coord3D DrawObject::m_feedbackPoint; CPoint DrawObject::m_cellCenter; @@ -131,6 +134,8 @@ void DrawObject::stopWaypointDragFeedback() DrawObject::~DrawObject() { freeMapResources(); + REF_PTR_RELEASE(m_waterDrawObject); + TheWaterRenderObj = nullptr; } DrawObject::DrawObject() : @@ -144,8 +149,9 @@ DrawObject::DrawObject() : m_vertexFeedback(nullptr), m_indexFeedback(nullptr), m_indexWater(nullptr), - m_moldMesh(nullptr) - + m_moldMesh(nullptr), + m_lineRenderer(nullptr), + m_drawSoundRanges(false) { m_feedbackPoint.x = 20; m_feedbackPoint.y = 20; @@ -153,6 +159,9 @@ DrawObject::DrawObject() : m_waterDrawObject = new WaterRenderObjClass; m_waterDrawObject->init(0, 0, 0, nullptr, WaterRenderObjClass::WATER_TYPE_0_TRANSLUCENT); TheWaterRenderObj=m_waterDrawObject; + + //(gth) this was needed to fix the extents bug that is based off water and too small for our maps + Set_Force_Visible(true); } @@ -178,14 +187,19 @@ DrawObject & DrawObject::operator = (const DrawObject & that) void DrawObject::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const { + // (gth) CNC3 these bounds don't actually work for all levels... + // we set the "force visible" flag for this object since it encapsulates all of the UI + // gadgets for the whole level anyway. Vector3 ObjSpaceCenter(TheGlobalData->m_waterExtentX,TheGlobalData->m_waterExtentY,50*MAP_XY_FACTOR); float length = ObjSpaceCenter.Length(); - sphere.Init(ObjSpaceCenter, length); } void DrawObject::Get_Obj_Space_Bounding_Box(AABoxClass & box) const { + // (gth) CNC3 these bounds don't actually work for all levels... + // we set the "force visible" flag for this object since it encapsulates all of the UI + // gadgets for the whole level anyway. Vector3 minPt(-2*TheGlobalData->m_waterExtentX,-2*TheGlobalData->m_waterExtentY,0); Vector3 maxPt(2*TheGlobalData->m_waterExtentX,2*TheGlobalData->m_waterExtentY,100*MAP_XY_FACTOR); box.Init(minPt,maxPt); @@ -214,8 +228,9 @@ Int DrawObject::freeMapResources() REF_PTR_RELEASE(m_indexFeedback); REF_PTR_RELEASE(m_indexWater); REF_PTR_RELEASE(m_moldMesh); - REF_PTR_RELEASE(m_waterDrawObject); - TheWaterRenderObj = nullptr; + + delete m_lineRenderer; + m_lineRenderer = nullptr; return 0; } @@ -237,10 +252,10 @@ Int DrawObject::initData() freeMapResources(); //free old data and ib/vb m_numTriangles = 2*NUM_TRI; - m_indexBuffer=NEW_REF(DX8IndexBufferClass,(m_numTriangles*3)); + m_indexBuffer=NEW_REF(DX8IndexBufferClass,(m_numTriangles*3, DX8IndexBufferClass::USAGE_DYNAMIC)); // Fill up the IB - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); for (i=0; i<3*m_numTriangles; i+=3) @@ -252,11 +267,11 @@ Int DrawObject::initData() ib+=3; //skip the 3 indices we just filled } - m_vertexBufferTile1=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_numTriangles*3,DX8VertexBufferClass::USAGE_DEFAULT)); - m_vertexBufferTile2=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_numTriangles*3,DX8VertexBufferClass::USAGE_DEFAULT)); + m_vertexBufferTile1=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_numTriangles*3,DX8VertexBufferClass::USAGE_DYNAMIC)); + m_vertexBufferTile2=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_numTriangles*3,DX8VertexBufferClass::USAGE_DYNAMIC)); - m_vertexFeedback=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,NUM_FEEDBACK_VERTEX,DX8VertexBufferClass::USAGE_DEFAULT)); - m_indexFeedback=NEW_REF(DX8IndexBufferClass,(NUM_FEEDBACK_INDEX)); + m_vertexFeedback=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,NUM_FEEDBACK_VERTEX,DX8VertexBufferClass::USAGE_DYNAMIC)); + m_indexFeedback=NEW_REF(DX8IndexBufferClass,(NUM_FEEDBACK_INDEX,DX8IndexBufferClass::USAGE_DYNAMIC)); //go with a preset material for now. m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); @@ -306,11 +321,11 @@ void DrawObject::updateMeshVB() m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -398,7 +413,7 @@ void DrawObject::updateMeshVB() Int numPoly = m_moldMesh->Get_Model()->Get_Polygon_Count(); - const Vector3i *pPoly =m_moldMesh->Get_Model()->Get_Polygon_Array(); + const TriIndex *pPoly =m_moldMesh->Get_Model()->Get_Polygon_Array(); if (3*numPoly+9 >= NUM_FEEDBACK_INDEX) { return; } @@ -434,11 +449,11 @@ void DrawObject::updateRampVB() m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -550,11 +565,11 @@ void DrawObject::updateBoundaryVB() m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -606,11 +621,11 @@ void DrawObject::updateBoundaryVB() endPt.z = TheTerrainRenderObject->getHeightMapHeight(endPt.x, endPt.y, nullptr); } - if ((m_feedbackVertexCount + 8) > NUM_FEEDBACK_VERTEX) { + if (m_feedbackVertexCount + 8 > NUM_FEEDBACK_VERTEX) { return; } - if ((m_feedbackIndexCount + 12) > NUM_FEEDBACK_INDEX) { + if (m_feedbackIndexCount + 12 > NUM_FEEDBACK_INDEX) { return; } @@ -726,11 +741,11 @@ void DrawObject::updateAmbientSoundVB() { m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -828,7 +843,6 @@ void DrawObject::updateAmbientSoundVB() } } - /** updateMeshVB puts waypoint path triangles into m_vertexFeedback. */ void DrawObject::updateWaypointVB() @@ -837,11 +851,11 @@ void DrawObject::updateWaypointVB() m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -1075,11 +1089,11 @@ void DrawObject::updatePolygonVB(PolygonTrigger *pTrig, Bool selected, Bool isOp green = green<<8; m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -1169,11 +1183,11 @@ void DrawObject::updateFeedbackVB() const Int theAlpha = 64; m_feedbackVertexCount = 0; m_feedbackIndexCount = 0; - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback); + DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexFeedback, D3DLOCK_DISCARD); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); UnsignedShort *curIb = ib; - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexFeedback, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); VertexFormatXYZDUV1 *curVb = vb; @@ -1378,7 +1392,7 @@ Int DrawObject::updateVB(DX8VertexBufferClass *pVB, Int color, Bool doArrow, Boo if (pVB ) { - DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB); + DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB, D3DLOCK_DISCARD); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); const Real theZ = 0.0f; @@ -1387,6 +1401,10 @@ Int DrawObject::updateVB(DX8VertexBufferClass *pVB, Int color, Bool doArrow, Boo if (doDiamond) { theRadius *= 5.0; } + else + { + theRadius *= 2.0; + } Int limit = NUM_TRI-(NUM_ARROW_TRI+NUM_SELECT_TRI); float curAngle = 0; @@ -1432,8 +1450,12 @@ Int DrawObject::updateVB(DX8VertexBufferClass *pVB, Int color, Bool doArrow, Boo vb++; } curAngle += deltaAngle; + } + if (!doDiamond) { + theRadius /= 2.0; } + if (!doArrow) { theRadius /= 20; halfLineWidth /= 20; @@ -1533,6 +1555,7 @@ Int DrawObject::updateVB(DX8VertexBufferClass *pVB, Int color, Bool doArrow, Boo curAngle += deltaAngle; } + #if 0 // Now do the highlight triangle. This is in yellow. for (k=0; k<3; k++) { @@ -1582,6 +1605,417 @@ Int DrawObject::updateVB(DX8VertexBufferClass *pVB, Int color, Bool doArrow, Boo return -1; } +#define BOUNDING_BOX_LINE_WIDTH 2.0f +/** Draw an object's bounding box into the vertex buffer. **/ +// MLL C&C3 +void DrawObject::updateVBWithBoundingBox(MapObject *pMapObj, CameraClass* camera) +{ + if (!pMapObj || !m_lineRenderer || !pMapObj->getThingTemplate()) { + return; + } + + unsigned long color = 0xFFAA00AA; // Purple + + GeometryInfo ginfo = pMapObj->getThingTemplate()->getTemplateGeometryInfo(); + + Coord3D pos = *pMapObj->getLocation(); + if (TheTerrainRenderObject) { + // Make sure that the position is on the terrain. + pos.z += TheTerrainRenderObject->getHeightMapHeight(pos.x, pos.y, nullptr); + } + + switch (ginfo.getGeomType()) + { + //--------------------------------------------------------------------------------------------- + case GEOMETRY_BOX: + { + Real angle = pMapObj->getAngle(); + Real c = (Real)cos(angle); + Real s = (Real)sin(angle); + Real exc = ginfo.getMajorRadius()*c; + Real eyc = ginfo.getMinorRadius()*c; + Real exs = ginfo.getMajorRadius()*s; + Real eys = ginfo.getMinorRadius()*s; + Coord3D pts[4]; + pts[0].x = pos.x - exc - eys; + pts[0].y = pos.y + eyc - exs; + pts[0].z = 0; + pts[1].x = pos.x + exc - eys; + pts[1].y = pos.y + eyc + exs; + pts[1].z = 0; + pts[2].x = pos.x + exc + eys; + pts[2].y = pos.y - eyc + exs; + pts[2].z = 0; + pts[3].x = pos.x - exc + eys; + pts[3].y = pos.y - eyc - exs; + pts[3].z = 0; + Real z = pos.z; + for (int i = 0; i < 2; i++) { + for (int corner = 0; corner < 4; corner++) { + ICoord2D start, end; + pts[corner].z = z; + pts[(corner+1)&3].z = z; + bool shouldStart = worldToScreen(&pts[corner], &start, camera); + bool shouldEnd = worldToScreen(&pts[(corner+1)&3], &end, camera); + if (shouldStart && shouldEnd) { + m_lineRenderer->Add_Line(Vector2(start.x, start.y), Vector2(end.x, end.y), BOUNDING_BOX_LINE_WIDTH, color); + } + } + + z += ginfo.getMaxHeightAbovePosition(); + } + break; + } + + //--------------------------------------------------------------------------------------------- + case GEOMETRY_SPHERE: // not quite right, but close enough + case GEOMETRY_CYLINDER: + { + Real angle, inc = PI/4.0f; + Real radius = ginfo.getMajorRadius(); + Coord3D pnt, lastPnt; + ICoord2D start, end; + Real z = pos.z; + + bool shouldEnd, shouldStart; + // Draw the cylinder. + for (int i=0; i<2; i++) { + angle = 0.0f; + lastPnt.x = pos.x + radius * (Real)cos(angle); + lastPnt.y = pos.y + radius * (Real)sin(angle); + lastPnt.z = z; + shouldEnd = worldToScreen(&lastPnt, &end, camera); + + for( angle = inc; angle <= 2.0f * PI; angle += inc ) { + pnt.x = pos.x + radius * (Real)cos(angle); + pnt.y = pos.y + radius * (Real)sin(angle); + pnt.z = z; + shouldStart = worldToScreen(&pnt, &start, camera); + if (shouldStart && shouldEnd) { + m_lineRenderer->Add_Line(Vector2(start.x, start.y), Vector2(end.x, end.y), BOUNDING_BOX_LINE_WIDTH, color); + } + lastPnt = pnt; + end = start; + shouldEnd = shouldStart; + } + + // Next time around, draw the top of the cylinder. + z += ginfo.getMaxHeightAbovePosition(); + } + + // Draw centerline + pnt.x = pos.x; + pnt.y = pos.y; + pnt.z = pos.z; + shouldStart = worldToScreen( &pnt, &start, camera); + pnt.z = pos.z + ginfo.getMaxHeightAbovePosition(); + shouldEnd = worldToScreen( &pnt, &end, camera); + if (shouldStart && shouldEnd) { + m_lineRenderer->Add_Line(Vector2(start.x, start.y), Vector2(end.x, end.y), BOUNDING_BOX_LINE_WIDTH, color); + } + break; + } + } +} + +/** Draw a "circle" into the m_lineRenderer, e.g. to visualize weapon range, sight range, sound range **/ +void DrawObject::addCircleToLineRenderer( const Coord3D & center, Real radius, Real width, unsigned long color, CameraClass* camera ) +{ + Real angle, inc = PI/4.0f; + Coord3D pnt, lastPnt; + ICoord2D start, end; + Real z = center.z; + + // Draw the circle. + angle = 0.0f; + lastPnt.x = center.x + radius * (Real)cos(angle); + lastPnt.y = center.y + radius * (Real)sin(angle); + lastPnt.z = z; + bool shouldEnd = worldToScreen(&lastPnt, &end, camera); + + for( angle = inc; angle <= 2.0f * PI; angle += inc ) { + pnt.x = center.x + radius * (Real)cos(angle); + pnt.y = center.y + radius * (Real)sin(angle); + pnt.z = z; + + bool shouldStart = worldToScreen(&pnt, &start, camera); + if (shouldStart && shouldEnd) { + m_lineRenderer->Add_Line(Vector2(start.x, start.y), Vector2(end.x, end.y), width, color); + } + + lastPnt = pnt; + end = start; + shouldEnd = shouldStart; + } + +} + +#define SIGHT_RANGE_LINE_WIDTH 2.0f +/** Draw an object's sight range into the vertex buffer. **/ +// MLL C&C3 +void DrawObject::updateVBWithSightRange(MapObject *pMapObj, CameraClass* camera) +{ + if (!pMapObj || !m_lineRenderer || !pMapObj->getThingTemplate()) { + return; + } + + const unsigned long color = 0xFFF0F0F0; // Light blue. + + Real radius = pMapObj->getThingTemplate()->friend_calcVisionRange(); + + Coord3D pos = *pMapObj->getLocation(); + if (TheTerrainRenderObject) { + // Make sure that the position is on the terrain. + pos.z += TheTerrainRenderObject->getHeightMapHeight(pos.x, pos.y, nullptr); + } + + addCircleToLineRenderer(pos, radius, SIGHT_RANGE_LINE_WIDTH, color, camera ); +} + +#define WEAPON_RANGE_LINE_WIDTH 1.0f +/** Draw an object's weapon range into the vertex buffer. **/ +// MLL C&C3 +void DrawObject::updateVBWithWeaponRange(MapObject *pMapObj, CameraClass* camera) +{ + if (!pMapObj || !m_lineRenderer || !pMapObj->getThingTemplate()) { + return; + } + + const unsigned long colors[WEAPONSLOT_COUNT] = {0xFF00FF00, 0xFFE0F00A, 0xFFFF0000}; // Green, Yellow, Red + + + Coord3D pos = *pMapObj->getLocation(); + if (TheTerrainRenderObject) { + // Make sure that the position is on the terrain. + pos.z += TheTerrainRenderObject->getHeightMapHeight(pos.x, pos.y, nullptr); + } + + const WeaponTemplateSetVector& weapons = pMapObj->getThingTemplate()->getWeaponTemplateSets(); + + for (WeaponTemplateSetVector::const_iterator it = weapons.begin(); it != weapons.end(); ++it) { + if (it->hasAnyWeapons() == false) { + continue; + } + + for (int i = 0; i < WEAPONSLOT_COUNT; i++) { + const WeaponTemplate* tmpl = it->getNth((WeaponSlotType)i); + + if (tmpl == nullptr) { + continue; + } + + Real radius = tmpl->getUnmodifiedAttackRange(); + + addCircleToLineRenderer(pos, radius, WEAPON_RANGE_LINE_WIDTH, colors[i], camera ); + } + } +} + +#define SOUND_RANGE_LINE_WIDTH 1.0f +/** Draw an object's min & max sound ranges into the vertex buffer. **/ +// MLL C&C3 +void DrawObject::updateVBWithSoundRanges(MapObject *pMapObj, CameraClass* camera) +{ + if (!pMapObj || !m_lineRenderer) { + return; + } + + const unsigned long colors[2] = {0xFF0000FF, 0xFFFF00FF}; // Blue and purple + // Colors match those used in W3DView.cpp + + + Coord3D pos = *pMapObj->getLocation(); + if (TheTerrainRenderObject) { + // Make sure that the position is on the terrain. + pos.z += TheTerrainRenderObject->getHeightMapHeight(pos.x, pos.y, nullptr); + } + + // Does this object actually have an attached sound? + const AudioEventInfo * audioInfo = nullptr; + + Dict * properties = pMapObj->getProperties(); + + Bool exists = false; + AsciiString ambientName = properties->getAsciiString( TheKey_objectSoundAmbient, &exists ); + + if ( exists ) + { + if ( ambientName.isEmpty() ) + { + // User has removed normal sound + return; + } + else + { + if ( TheAudio == nullptr ) + { + DEBUG_CRASH( ("TheAudio is null! Can't draw sound circles") ); + return; + } + + audioInfo = TheAudio->findAudioEventInfo( ambientName ); + + if ( audioInfo == nullptr ) + { + DEBUG_CRASH( ("Override audio named %s is missing; Can't draw sound circles", ambientName.str() ) ); + return; + } + } + } + else + { + const ThingTemplate * thingTemplate = pMapObj->getThingTemplate(); + if ( thingTemplate == nullptr ) + { + // No sound if no template + return; + } + + if ( !thingTemplate->hasSoundAmbient() ) + { + return; + } + + const AudioEventRTS * event = thingTemplate->getSoundAmbient(); + + if ( event == nullptr ) + { + return; + } + + audioInfo = event->getAudioEventInfo(); + + if ( audioInfo == nullptr ) + { + // May just not be set up yet + if ( TheAudio == nullptr ) + { + DEBUG_CRASH( ("TheAudio is null! Can't draw sound circles") ); + return; + } + + audioInfo = TheAudio->findAudioEventInfo( event->getEventName() ); + + if ( audioInfo == nullptr ) + { + DEBUG_CRASH( ("Default ambient sound %s has no info; Can't draw sound circles", event->getEventName().str() ) ); + return; + } + } + } + + // Should have set up audioInfo or returned by now + DEBUG_ASSERTCRASH( audioInfo != nullptr, ("Managed to finish setting up audio info without setting it?!?" ) ); + if ( audioInfo == nullptr ) + { + return; + } + + // Get the current radius (could be overridden) + Real minRadius = audioInfo->m_minDistance; + Real maxRadius = audioInfo->m_maxDistance; + Bool customized = properties->getBool( TheKey_objectSoundAmbientCustomized, &exists ); + if ( exists && customized ) + { + Real valReal; + + valReal = properties->getReal( TheKey_objectSoundAmbientMinRange, &exists ); + if ( exists ) + { + minRadius = valReal; + } + valReal = properties->getReal( TheKey_objectSoundAmbientMaxRange, &exists ); + if ( exists ) + { + maxRadius = valReal; + } + } + addCircleToLineRenderer(pos, minRadius, SOUND_RANGE_LINE_WIDTH, colors[0], camera ); + addCircleToLineRenderer(pos, maxRadius, SOUND_RANGE_LINE_WIDTH, colors[1], camera ); +} + + +#define TEST_ART_HIGHLIGHT_LINE_WIDTH 5.0f +/** Draw test art with an X on it. **/ +// MLL C&C3 +void DrawObject::updateVBWithTestArtHighlight(MapObject *pMapObj, CameraClass* camera) +{ + if (!pMapObj || !m_lineRenderer || pMapObj->getThingTemplate() || pMapObj->isScorch()) { + // It is test art if it doesn't have a ThingTemplate. + return; + } + + unsigned long color = 0xFFA000A0; // Purple + + + Coord3D pos = *pMapObj->getLocation(); + if (TheTerrainRenderObject) { + // Make sure that the position is on the terrain. + pos.z += TheTerrainRenderObject->getHeightMapHeight(pos.x, pos.y, nullptr); + } + + Real angle, inc = PI/2.0f; + Coord3D pnt, lastPnt; + ICoord2D start, end; + Real z = pos.z; + Real radius = 30.0f; + + // Draw the diamond. + angle = 0.0f; + lastPnt.x = pos.x + radius * (Real)cos(angle); + lastPnt.y = pos.y + radius * (Real)sin(angle); + lastPnt.z = z; + bool shouldEnd = worldToScreen(&lastPnt, &end, camera); + + for( angle = inc; angle <= 2.0f * PI; angle += inc ) { + pnt.x = pos.x + radius * (Real)cos(angle); + pnt.y = pos.y + radius * (Real)sin(angle); + pnt.z = z; + + bool shouldStart = worldToScreen(&pnt, &start, camera); + if (shouldStart && shouldEnd) { + m_lineRenderer->Add_Line(Vector2(start.x, start.y), Vector2(end.x, end.y), TEST_ART_HIGHLIGHT_LINE_WIDTH, color); + } + + lastPnt = pnt; + end = start; + shouldEnd = shouldStart; + } + +} + + +/** Transform a 3D Coordinate into 2D screen space **/ +// MLL C&C3 +bool DrawObject::worldToScreen(const Coord3D *w, ICoord2D *s, CameraClass* camera) +{ + + if ((w == nullptr) || (s == nullptr) || (camera == nullptr)) { + return false; + } + + Vector3 world; + Vector3 screen; + + world.Set(w->x, w->y, w->z); + camera->Project(screen, world); + + // + // note that the screen coord returned from the project W3D camera + // gave us a screen coords that range from (-1,-1) bottom left to + // (1,1) top right ... we are turning that into (0,0) upper left + // coords now + // + W3DLogicalScreenToPixelScreen(screen.X, screen.Y, &s->x, &s->y, m_winSize.x, m_winSize.y); + + if ((screen.X > 2.0f) || (screen.Y > 2.0f) || (screen.X < -2.0f) || (screen.Y < -2.0f)) { + // Too far off the screen. + return false; + } + + return (true); +} + /** Tells drawobject where the tool is located, so it can draw feedback. */ void DrawObject::setFeedbackPos(Coord3D pos) { @@ -1620,25 +2054,55 @@ void DrawObject::setRampFeedbackParms(const Coord3D *start, const Coord3D *end, } +bool _skip_drawobject_render = false; + /** Render draws into the current 3d context. */ void DrawObject::Render(RenderInfoClass & rinfo) { +//DEBUG! +if (_skip_drawobject_render) { + return; +} + + if (m_lineRenderer == nullptr) { + // This can't be created in init because the doc hasn't been created yet. + m_lineRenderer = new Render2DClass(); + ASSERT(m_lineRenderer); + CWorldBuilderDoc *pDoc = CWorldBuilderDoc::GetActiveDoc(); + ASSERT(pDoc); + WbView3d *pView = pDoc->Get3DView(); + ASSERT(pView); + m_winSize = pView->getActualWinSize(); + m_lineRenderer->Set_Coordinate_Range(RectClass(0, 0, m_winSize.x, m_winSize.y)); + m_lineRenderer->Reset(); + m_lineRenderer->Enable_Texturing(FALSE); + } + DX8Wrapper::Apply_Render_State_Changes(); DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); DX8Wrapper::Set_Texture(0, nullptr); + DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); DX8Wrapper::Apply_Render_State_Changes(); Int count=0; Int i; + bool linesToRender = false; + curHighlight++; if (curHighlight >= NUM_HIGHLIGHT) { curHighlight = 0; } m_waterDrawObject->update(); - if (m_drawObjects || m_drawWaypoints) { + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferTile1); + if (m_drawObjects || m_drawWaypoints || m_drawBoundingBoxes || m_drawSightRanges || m_drawWeaponRanges || m_drawSoundRanges || m_drawTestArtHighlight) { //Apply the shader and material + //WST Variables below are for optimization to reduce VB updates which are extremely slow + // Optimization strategy is to remember last setting and avoid re-updating unless it changed + int rememberLastSettingVB1 = -99999; + int rememberLastSettingVB2 = -99999; + MapObject *pMapObj; for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) { // simple Draw test. @@ -1650,11 +2114,7 @@ void DrawObject::Render(RenderInfoClass & rinfo) if (TheTerrainRenderObject) { loc.z += TheTerrainRenderObject->getHeightMapHeight(loc.x, loc.y, nullptr); } - // Cull. - SphereClass bounds(Vector3(loc.x, loc.y, loc.z), THE_RADIUS); - if (rinfo.Camera.Cull_Sphere(bounds)) { - continue; - } + // Range overlays can extend well beyond THE_RADIUS, so culling by the object center would hide visible feedback. Bool doArrow = true; if (pMapObj->getFlag(FLAG_ROAD_FLAGS) || pMapObj->getFlag(FLAG_BRIDGE_FLAGS) || pMapObj->isWaypoint()) { @@ -1667,6 +2127,31 @@ void DrawObject::Render(RenderInfoClass & rinfo) continue; } } else { + // MLL C&C3 + if (pMapObj->isSelected()) { + if (doArrow && m_drawBoundingBoxes) { + linesToRender = true; + updateVBWithBoundingBox(pMapObj, &rinfo.Camera); + } + if (doArrow && m_drawSightRanges) { + linesToRender = true; + updateVBWithSightRange(pMapObj, &rinfo.Camera); + } + if (doArrow && m_drawWeaponRanges) { + linesToRender = true; + updateVBWithWeaponRange(pMapObj, &rinfo.Camera); + } + if (doArrow && m_drawSoundRanges) { + linesToRender = true; + updateVBWithSoundRanges(pMapObj, &rinfo.Camera); + } + } + + if (doArrow && m_drawTestArtHighlight) { + linesToRender = true; + updateVBWithTestArtHighlight(pMapObj, &rinfo.Camera); + } + if (!m_drawObjects) { continue; } @@ -1676,13 +2161,38 @@ void DrawObject::Render(RenderInfoClass & rinfo) } if (count&1) { - updateVB(m_vertexBufferTile1, pMapObj->getColor(), doArrow, doDiamond); + int setting = pMapObj->getColor(); + + if (doArrow) { + setting |= (1<<25); + } + if (doDiamond) { + setting |= (1<<26); + } + + if (setting != rememberLastSettingVB1) { + rememberLastSettingVB1 = setting; + updateVB(m_vertexBufferTile1,pMapObj->getColor(), doArrow, doDiamond); + } DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferTile1); + } else { - updateVB(m_vertexBufferTile2, pMapObj->getColor(), doArrow, doDiamond); + int setting = pMapObj->getColor(); + + if (doArrow) { + setting |= (1<<25); + } + if (doDiamond) { + setting |= (1<<26); + } + + if (setting != rememberLastSettingVB2) { + rememberLastSettingVB2 = setting; + updateVB(m_vertexBufferTile2, pMapObj->getColor(), doArrow, doDiamond); + } DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferTile2); } - count++; + ///@todo - remove the istree stuff, or get the info from the thing template. jba. Bool isTree = false; @@ -1699,24 +2209,22 @@ void DrawObject::Render(RenderInfoClass & rinfo) } DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); - DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - if (isTree) { DX8Wrapper::Draw_Triangles( NUM_TRI*3,polyCount, 0, (m_numTriangles*3)); } else { DX8Wrapper::Draw_Triangles( 0,polyCount, 0, (m_numTriangles*3)); } + + count++; } } - - DX8Wrapper::Set_Vertex_Buffer(nullptr); //release reference to vertex buffer - DX8Wrapper::Set_Index_Buffer(nullptr,0); //release reference to vertex buffer - if (m_drawPolygonAreas) { + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); Int selected; for (selected = 0; selected < 2; selected++) { for (PolygonTrigger *pTrig=PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); + if (!pTrig->getShouldRender()) continue; Bool polySelected = PolygonTool::isSelected(pTrig); if (polySelected && !selected) continue; if (!polySelected && selected) continue; @@ -1775,8 +2283,6 @@ void DrawObject::Render(RenderInfoClass & rinfo) } } - DX8Wrapper::Set_Vertex_Buffer(nullptr); //release reference to vertex buffer - DX8Wrapper::Set_Index_Buffer(nullptr,0); //release reference to vertex buffer if (BuildListTool::isActive()) for (i=0; igetNumSides(); i++) { SidesInfo *pSide = TheSidesList->getSideInfo(i); @@ -1816,16 +2322,15 @@ void DrawObject::Render(RenderInfoClass & rinfo) } #if 1 - DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); DX8Wrapper::Set_Transform(D3DTS_WORLD,tmXX); DX8Wrapper::Draw_Triangles( 0,polyCountA, 0, (m_numTriangles*3)); #endif + } } - DX8Wrapper::Set_Vertex_Buffer(nullptr); //release reference to vertex buffer - DX8Wrapper::Set_Index_Buffer(nullptr,0); //release reference to vertex buffer - + DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); Matrix3D tmReset(Transform); DX8Wrapper::Set_Transform(D3DTS_WORLD,tmReset); @@ -1836,13 +2341,12 @@ void DrawObject::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Index_Buffer(m_indexFeedback,0); DX8Wrapper::Set_Shader(m_shaderClass); DX8Wrapper::Draw_Triangles( 0, m_feedbackIndexCount/3, 0, m_feedbackVertexCount); -// DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - // DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); + DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); } } - DX8Wrapper::Set_Vertex_Buffer(nullptr); //release reference to vertex buffer - DX8Wrapper::Set_Index_Buffer(nullptr,0); //release reference to vertex buffer + #if 1 if (m_meshFeedback) { @@ -1865,9 +2369,6 @@ void DrawObject::Render(RenderInfoClass & rinfo) } #endif - DX8Wrapper::Set_Vertex_Buffer(nullptr); //release reference to vertex buffer - DX8Wrapper::Set_Index_Buffer(nullptr,0); //release reference to vertex buffer - #if 1 if (m_rampFeedback) { updateRampVB(); @@ -1882,9 +2383,6 @@ void DrawObject::Render(RenderInfoClass & rinfo) } #endif - DX8Wrapper::Set_Vertex_Buffer(nullptr); //release reference to vertex buffer - DX8Wrapper::Set_Index_Buffer(nullptr,0); //release reference to vertex buffer - #if 1 if (m_boundaryFeedback) { updateBoundaryVB(); @@ -1917,13 +2415,31 @@ void DrawObject::Render(RenderInfoClass & rinfo) } } - DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); + DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); if (m_waterDrawObject) { m_waterDrawObject->renderWater(); } + if (m_drawLetterbox) { + int w = m_winSize.x; + int h = m_winSize.y; + int size = (int)((h - (9.0f / 16.0f * w)) * 0.5f); + RectClass rect(0, 0, w, size); + m_lineRenderer->Add_Quad(rect, 0xFF000000); + rect.Set(0, h - size, w, h); + m_lineRenderer->Add_Quad(rect, 0xFF000000); + linesToRender = true; + } + + // Render any lines that have been added, like bounding boxes. + // MLL C&C3 + if (linesToRender && m_lineRenderer) { + m_lineRenderer->Render(); + // Clear the old lines. + m_lineRenderer->Reset(); + } } diff --git a/Generals/Code/Tools/WorldBuilder/src/EditAction.cpp b/Generals/Code/Tools/WorldBuilder/src/EditAction.cpp index c7bce6af8ef..4189f694fc9 100644 --- a/Generals/Code/Tools/WorldBuilder/src/EditAction.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/EditAction.cpp @@ -50,11 +50,42 @@ void EditAction::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(EditAction, CDialog) //{{AFX_MSG_MAP(EditAction) - ON_CBN_SELCHANGE(IDC_CONDITION_TYPE, OnSelchangeScriptActionType) ON_WM_TIMER() //}}AFX_MSG_MAP END_MESSAGE_MAP() +/** Locate the child item in tree item parent with name pLabel. If not +found, add it. Either way, return child. */ +static HTREEITEM findOrAdd(CTreeCtrl *tree, HTREEITEM parent, const char *pLabel) +{ + TVINSERTSTRUCT ins; + char buffer[_MAX_PATH]; + ::memset(&ins, 0, sizeof(ins)); + HTREEITEM child = tree->GetChildItem(parent); + while (child != nullptr) { + ins.item.mask = TVIF_HANDLE|TVIF_TEXT; + ins.item.hItem = child; + ins.item.pszText = buffer; + ins.item.cchTextMax = sizeof(buffer)-2; + tree->GetItem(&ins.item); + if (strcmp(buffer, pLabel) == 0) { + return(child); + } + child = tree->GetNextSiblingItem(child); + } + + // not found, so add it. + ::memset(&ins, 0, sizeof(ins)); + ins.hParent = parent; + ins.hInsertAfter = TVI_SORT; + ins.item.mask = TVIF_PARAM|TVIF_TEXT; + ins.item.lParam = -1; + ins.item.pszText = (char*)pLabel; + ins.item.cchTextMax = strlen(pLabel); + child = tree->InsertItem(&ins); + return(child); +} + ///////////////////////////////////////////////////////////////////////////// // EditAction message handlers @@ -65,39 +96,117 @@ BOOL EditAction::OnInitDialog() // CDC *pDc =GetDC(); + CRect rect; + + CTreeCtrl *pTree = (CTreeCtrl *)GetDlgItem(IDC_ACTION_TREE); + pTree->GetWindowRect(&rect); + + ScreenToClient(&rect); + m_actionTreeView.Create(TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS| + TVS_SHOWSELALWAYS|TVS_DISABLEDRAGDROP|WS_TABSTOP, rect, this, IDC_ACTION_TREE); + m_actionTreeView.ShowWindow(SW_SHOW); + pTree->DestroyWindow(); CWnd *pWnd = GetDlgItem(IDC_RICH_EDIT_HERE); - CRect rect; pWnd->GetWindowRect(&rect); ScreenToClient(&rect); rect.DeflateRect(2,2,2,2); - m_myEditCtrl.Create(WS_CHILD | ES_MULTILINE, rect, this, IDC_RICH_EDIT_HERE+1); + m_myEditCtrl.Create(WS_CHILD | WS_TABSTOP | ES_MULTILINE, rect, this, IDC_RICH_EDIT_HERE+1); m_myEditCtrl.ShowWindow(SW_SHOW); - m_myEditCtrl.SetEventMask(m_myEditCtrl.GetEventMask() | ENM_LINK | ENM_SELCHANGE); + m_myEditCtrl.SetEventMask(m_myEditCtrl.GetEventMask() | ENM_LINK | ENM_SELCHANGE | ENM_KEYEVENTS); - CComboBox *pCmbo = (CComboBox *)GetDlgItem(IDC_CONDITION_TYPE); - pCmbo->ResetContent(); Int i; + HTREEITEM selItem = nullptr; for (i=0; igetActionTemplate(i); - Int ndx = pCmbo->AddString(pTemplate->getName().str()); + char prefix[_MAX_PATH]; + const char *name = pTemplate->getName().str(); + + Int count = 0; + HTREEITEM parent = TVI_ROOT; + do { + count = 0; + const char *nameStart = name; + while (*name && *name != '/') { + count++; + name++; + } + if (*name=='/') { + count++; + name++; + } else { + name = nameStart; + count = 0; + } + if (count>0) { + strlcpy(prefix, nameStart, count); + parent = findOrAdd(&m_actionTreeView, parent, prefix); + } + } while (count>0); + + TVINSERTSTRUCT ins; + ::memset(&ins, 0, sizeof(ins)); + ins.hParent = parent; + ins.hInsertAfter = TVI_SORT; + ins.item.mask = TVIF_PARAM|TVIF_TEXT; + ins.item.lParam = i; + ins.item.pszText = (char*)name; + ins.item.cchTextMax = 0; + HTREEITEM item = m_actionTreeView.InsertItem(&ins); if (i == m_action->getActionType()) { - pCmbo->SetCurSel(ndx); + selItem = item; } + +#if RTS_ZEROHOUR + name = pTemplate->getName2().str(); + count = 0; + if (pTemplate->getName2().isEmpty()) continue; + parent = TVI_ROOT; + do { + count = 0; + const char *nameStart = name; + while (*name && *name != '/') { + count++; + name++; + } + if (*name=='/') { + count++; + name++; + } else { + name = nameStart; + count = 0; + } + if (count>0) { + strlcpy(prefix, nameStart, count); + parent = findOrAdd(&m_actionTreeView, parent, prefix); + } + } while (count>0); + + ::memset(&ins, 0, sizeof(ins)); + ins.hParent = parent; + ins.hInsertAfter = TVI_SORT; + ins.item.mask = TVIF_PARAM|TVIF_TEXT; + ins.item.lParam = i; + ins.item.pszText = (char*)name; + ins.item.cchTextMax = 0; + m_actionTreeView.InsertItem(&ins); +#endif } + m_actionTreeView.Select(selItem, TVGN_FIRSTVISIBLE); + m_actionTreeView.SelectItem(selItem); m_action->setWarnings(false); m_myEditCtrl.SetWindowText(m_action->getUiText().str()); m_myEditCtrl.SetSel(-1, -1); - formatScriptActionText(-1); + formatScriptActionText(0); + m_actionTreeView.SetFocus(); - return TRUE; // return TRUE unless you set the focus to a control + return FALSE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } -void EditAction::formatScriptActionText(Int parameterNdx) -{ +void EditAction::formatScriptActionText(Int parameterNdx) { CHARFORMAT2 cf; m_updating = true; long startSel, endSel; @@ -114,12 +223,13 @@ void EditAction::formatScriptActionText(Int parameterNdx) m_myEditCtrl.SetSel(0, 1000); m_myEditCtrl.SetSelectionCharFormat(cf); - m_myEditCtrl.SetReadOnly(); + //m_myEditCtrl.SetReadOnly(); // Set up the links. cf.dwMask = CFE_UNDERLINE | CFM_LINK | CFM_COLOR; cf.dwEffects = CFE_LINK | CFE_UNDERLINE; cf.crTextColor = RGB(0,0,255); + m_curEditParameter = parameterNdx; AsciiString strings[MAX_PARMS]; Int curChar = 0; @@ -133,10 +243,13 @@ void EditAction::formatScriptActionText(Int parameterNdx) curChar += strings[i].getLength(); } if (igetNumParameters()) { - warningText.concat(EditParameter::getWarningText(m_action->getParameter(i))); + warningText.concat(EditParameter::getWarningText(m_action->getParameter(i), false)); informationText.concat(EditParameter::getInfoText(m_action->getParameter(i))); numChars = m_action->getParameter(i)->getUiText().getLength(); - if (numChars==0) continue; + if (curChar==0) { + curChar++; + numChars--; + } m_myEditCtrl.SetSel(curChar, curChar+numChars); if (i==parameterNdx) { startSel = curChar; @@ -175,6 +288,8 @@ void EditAction::formatScriptActionText(Int parameterNdx) m_modifiedTextColor = false; m_myEditCtrl.SetSel(startSel, endSel); + m_curLinkChrg.cpMax = endSel; + m_curLinkChrg.cpMin = startSel; m_updating = false; } @@ -182,125 +297,159 @@ void EditAction::formatScriptActionText(Int parameterNdx) BOOL EditAction::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { - if (LOWORD(wParam) == IDC_RICH_EDIT_HERE+1) - { + NMTREEVIEW *pHdr = (NMTREEVIEW *)lParam; + + // Handle events from the tree control. + if (pHdr->hdr.idFrom == IDC_ACTION_TREE) { + if (pHdr->hdr.code == TVN_SELCHANGED) { + char buffer[_MAX_PATH]; + HTREEITEM hItem = m_actionTreeView.GetSelectedItem(); + TVITEM item; + ::memset(&item, 0, sizeof(item)); + item.mask = TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT|TVIF_STATE; + item.hItem = hItem; + item.pszText = buffer; + item.cchTextMax = sizeof(buffer)-2; + m_actionTreeView.GetItem(&item); + if (item.lParam >= 0) { + enum ScriptAction::ScriptActionType actionType = (enum ScriptAction::ScriptActionType)item.lParam; + if (m_action->getActionType() != actionType) { + m_action->setActionType( actionType ); + m_myEditCtrl.SetWindowText(m_action->getUiText().str()); + formatScriptActionText(0); + } + } + } else if (pHdr->hdr.code == TVN_KEYDOWN) { + NMTVKEYDOWN *pKey = (NMTVKEYDOWN*)lParam; + Int key = pKey->wVKey; + if (key==VK_SHIFT || key==VK_SPACE) { + HTREEITEM hItem = m_actionTreeView.GetSelectedItem(); + if (!m_actionTreeView.ItemHasChildren(hItem)) { + hItem = m_actionTreeView.GetParentItem(hItem); + } + m_actionTreeView.Expand(hItem, TVE_TOGGLE); + return 0; + } + return 0; + } + return TRUE; + } + + // Handle events from the rich edit control containing the action pieces. + if (LOWORD(wParam) == IDC_RICH_EDIT_HERE+1) { NMHDR *pHdr = (NMHDR *)lParam; - if (pHdr->hwndFrom == m_myEditCtrl.m_hWnd && pHdr->code == EN_LINK) - { - ENLINK *pLink = (ENLINK *)pHdr; - CHARRANGE chrg = pLink->chrg; - if (pLink->msg == WM_LBUTTONDOWN) - { + if (pHdr->hwndFrom == m_myEditCtrl.m_hWnd) { + if (pHdr->code == EN_LINK) { + ENLINK *pLink = (ENLINK *)pHdr; + CHARRANGE chrg = pLink->chrg; // Determine which parameter. Int numChars = 0; Int curChar = 0; AsciiString strings[MAX_PARMS]; Int numStrings = m_action->getUiStrings(strings); Int i; - for (i=0; igetNumParameters()) - { + if (igetNumParameters()) { numChars = m_action->getParameter(i)->getUiText().getLength(); - if (curChar == chrg.cpMin && curChar+numChars == chrg.cpMax) - { - //Kris: - //Before we edit the parameter, there is a new prerequisite for parameters - //but only a few will ever care. We will store what we perceive as the unit, - //and for simplicity, we'll store the first occurrence of the unit, although - //this can change in the future should the need arise. - AsciiString unitName; - for( int j = 0; j < MAX_PARMS; j++ ) - { - Parameter *parameter = m_action->getParameter( j ); - if( parameter && parameter->getParameterType() == Parameter::UNIT ) - { - unitName = parameter->getString(); - break; - } - } - - if( EditParameter::edit( m_action->getParameter(i), unitName ) == IDOK ) - { - m_myEditCtrl.SetWindowText(m_action->getUiText().str()); - m_curEditParameter = i; - this->PostMessage(WM_TIMER, 0, 0); - } - return true; + match = (curChar+numChars/2 > chrg.cpMin && curChar+numChars/2 < chrg.cpMax); + if (match) { + m_curEditParameter = i; + break; } curChar += numChars; } } - } - CHARRANGE curChrg; - m_myEditCtrl.GetSel(curChrg); - if (curChrg.cpMin == chrg.cpMin && curChrg.cpMax == chrg.cpMax) - { - return true; - } - if (m_modifiedTextColor) - { - formatScriptActionText(-1); - } - m_curLinkChrg = chrg; - m_myEditCtrl.SetSel(chrg.cpMin, chrg.cpMax); - CHARFORMAT cf; - memset(&cf, 0, sizeof(cf)); - cf.cbSize = sizeof(cf); - cf.dwMask = CFM_COLOR; - cf.crTextColor = RGB(0,0,0); - m_myEditCtrl.SetSelectionCharFormat(cf); - m_modifiedTextColor = true; - return true; - } - else if (pHdr->hwndFrom == m_myEditCtrl.m_hWnd && pHdr->code == EN_SELCHANGE) - { - if (m_updating) - { - return true; - } - CHARRANGE curChrg; - m_myEditCtrl.GetSel(curChrg); - if (curChrg.cpMin == m_curLinkChrg.cpMin && curChrg.cpMax == m_curLinkChrg.cpMax) - { + if (pLink->msg == WM_LBUTTONDOWN) + { + // Determine which parameter. + if (match) + { + if( m_action->getParameter( m_curEditParameter )->getParameterType() == Parameter::COMMANDBUTTON_ABILITY ) + { + EditParameter::edit(m_action->getParameter(m_curEditParameter), 0, m_action->getParameter(0)->getString() ); + } + else + { + EditParameter::edit(m_action->getParameter(m_curEditParameter), 0 ); + } + m_myEditCtrl.SetWindowText(m_action->getUiText().str()); + this->PostMessage(WM_TIMER, 0, 0); + return true; + } + } + CHARRANGE curChrg; + m_myEditCtrl.GetSel(curChrg); + if (curChrg.cpMin == chrg.cpMin && curChrg.cpMax == chrg.cpMax) { + return true; + } + if (m_modifiedTextColor) { + formatScriptActionText(m_curEditParameter); + } + m_curLinkChrg = chrg; + m_myEditCtrl.SetSel(chrg.cpMin, chrg.cpMax); + m_myEditCtrl.SetFocus(); + CHARFORMAT cf; + memset(&cf, 0, sizeof(cf)); + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_COLOR; + cf.crTextColor = RGB(0,0,0); + m_myEditCtrl.SetSelectionCharFormat(cf); + m_modifiedTextColor = true; return true; - } - if (m_modifiedTextColor) - { - formatScriptActionText(-1); + } else if (pHdr->code == EN_SETFOCUS) { + this->PostMessage(WM_TIMER, 0, 0); + } else if (pHdr->code == EN_SELCHANGE) { + if (m_updating) { + return true; + } + CHARRANGE curChrg; + m_myEditCtrl.GetSel(curChrg); + if (curChrg.cpMin == m_curLinkChrg.cpMin && curChrg.cpMax == m_curLinkChrg.cpMax) { + return true; + } + m_myEditCtrl.SetSel(m_curLinkChrg.cpMin, m_curLinkChrg.cpMax); + if (m_modifiedTextColor) { + this->PostMessage(WM_TIMER, 0, 0); + } + } else if (pHdr->code == EN_MSGFILTER) { + MSGFILTER *pFilter = (MSGFILTER *)pHdr; + if (pFilter->msg == WM_CHAR) { + Int keyPressed = pFilter->wParam; + if (keyPressed==VK_RETURN) { + return 1; + } + if (keyPressed==VK_RETURN || keyPressed == VK_TAB) { + m_curEditParameter++; + if (m_curEditParameter >= m_action->getNumParameters()) { + m_curEditParameter = 0; + return 1; + } + this->PostMessage(WM_TIMER, 0, 0); + return 0; + } + EditParameter::edit(m_action->getParameter(m_curEditParameter), keyPressed); + m_curEditParameter++; + if (m_curEditParameter >= m_action->getNumParameters()) { + m_curEditParameter = 0; + } + this->PostMessage(WM_TIMER, 0, 0); + return 0; + } + return 1; } } } return CDialog::OnNotify(wParam, lParam, pResult); } -void EditAction::OnSelchangeScriptActionType() -{ - CComboBox *pCombo = (CComboBox *)GetDlgItem(IDC_CONDITION_TYPE); - Int index = 0; - CString str; - pCombo->GetWindowText(str); - Int i; - for (i=0; igetActionTemplate(i); - if (str == pTemplate->getName().str()) { - index = i; - break; - } - } - - m_action->setActionType((enum ScriptAction::ScriptActionType)i ); - m_myEditCtrl.SetWindowText(m_action->getUiText().str()); - formatScriptActionText(-1); -} - /** Not actually a timer - just used to send a delayed message to self because rich edit control is stupid. jba. */ void EditAction::OnTimer(UINT nIDEvent) { + m_myEditCtrl.SetWindowText(m_action->getUiText().str()); formatScriptActionText(m_curEditParameter); } diff --git a/Generals/Code/Tools/WorldBuilder/src/EditCondition.cpp b/Generals/Code/Tools/WorldBuilder/src/EditCondition.cpp index 4ea362a23aa..62f14373c44 100644 --- a/Generals/Code/Tools/WorldBuilder/src/EditCondition.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/EditCondition.cpp @@ -25,6 +25,18 @@ #include "EditParameter.h" #include "GameLogic/ScriptEngine.h" + +LRESULT CMyTreeCtrl::WindowProc( UINT message, WPARAM wParam, LPARAM lParam ) +{ + if (message==WM_KEYDOWN) { + Int nVirtKey = (int) wParam; // virtual-key code + if (nVirtKey == ' ') { + return 0; + } + } + return CTreeCtrl::WindowProc(message, wParam, lParam); +} + ///////////////////////////////////////////////////////////////////////////// // EditCondition dialog @@ -54,6 +66,38 @@ BEGIN_MESSAGE_MAP(EditCondition, CDialog) //}}AFX_MSG_MAP END_MESSAGE_MAP() +/** Locate the child item in tree item parent with name pLabel. If not +found, add it. Either way, return child. */ +static HTREEITEM findOrAdd(CTreeCtrl *tree, HTREEITEM parent, const char *pLabel) +{ + TVINSERTSTRUCT ins; + char buffer[_MAX_PATH]; + ::memset(&ins, 0, sizeof(ins)); + HTREEITEM child = tree->GetChildItem(parent); + while (child != nullptr) { + ins.item.mask = TVIF_HANDLE|TVIF_TEXT; + ins.item.hItem = child; + ins.item.pszText = buffer; + ins.item.cchTextMax = sizeof(buffer)-2; + tree->GetItem(&ins.item); + if (strcmp(buffer, pLabel) == 0) { + return(child); + } + child = tree->GetNextSiblingItem(child); + } + + // not found, so add it. + ::memset(&ins, 0, sizeof(ins)); + ins.hParent = parent; + ins.hInsertAfter = TVI_SORT; + ins.item.mask = TVIF_PARAM|TVIF_TEXT; + ins.item.lParam = -1; + ins.item.pszText = (char*)pLabel; + ins.item.cchTextMax = strlen(pLabel); + child = tree->InsertItem(&ins); + return(child); +} + ///////////////////////////////////////////////////////////////////////////// // EditCondition message handlers @@ -64,33 +108,112 @@ BOOL EditCondition::OnInitDialog() // CDC *pDc =GetDC(); + CRect rect; + + CTreeCtrl *pTree = (CTreeCtrl *)GetDlgItem(IDC_CONDITION_TREE); + pTree->GetWindowRect(&rect); + + ScreenToClient(&rect); + m_conditionTreeView.Create(TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS| + TVS_SHOWSELALWAYS|TVS_DISABLEDRAGDROP|WS_TABSTOP, rect, this, IDC_CONDITION_TREE); + m_conditionTreeView.ShowWindow(SW_SHOW); + pTree->DestroyWindow(); CWnd *pWnd = GetDlgItem(IDC_RICH_EDIT_HERE); - CRect rect; pWnd->GetWindowRect(&rect); ScreenToClient(&rect); rect.DeflateRect(2,2,2,2); - m_myEditCtrl.Create(WS_CHILD | ES_MULTILINE, rect, this, IDC_RICH_EDIT_HERE+1); + m_myEditCtrl.Create(WS_CHILD | WS_TABSTOP | ES_MULTILINE, rect, this, IDC_RICH_EDIT_HERE+1); m_myEditCtrl.ShowWindow(SW_SHOW); - m_myEditCtrl.SetEventMask(m_myEditCtrl.GetEventMask() | ENM_LINK | ENM_SELCHANGE); + m_myEditCtrl.SetEventMask(m_myEditCtrl.GetEventMask() | ENM_LINK | ENM_SELCHANGE | ENM_KEYEVENTS); - CComboBox *pCmbo = (CComboBox *)GetDlgItem(IDC_CONDITION_TYPE); - pCmbo->ResetContent(); Int i; + HTREEITEM selItem = nullptr; for (i=0; igetConditionTemplate(i); - Int ndx = pCmbo->AddString(pTemplate->getName().str()); + char prefix[_MAX_PATH]; + const char *name = pTemplate->getName().str(); + + Int count = 0; + HTREEITEM parent = TVI_ROOT; + do { + count = 0; + const char *nameStart = name; + while (*name && *name != '/') { + count++; + name++; + } + if (*name=='/') { + count++; + name++; + } else { + name = nameStart; + count = 0; + } + if (count>0) { + strlcpy(prefix, nameStart, count); + parent = findOrAdd(&m_conditionTreeView, parent, prefix); + } + } while (count>0); + + TVINSERTSTRUCT ins; + ::memset(&ins, 0, sizeof(ins)); + ins.hParent = parent; + ins.hInsertAfter = TVI_SORT; + ins.item.mask = TVIF_PARAM|TVIF_TEXT; + ins.item.lParam = i; + ins.item.pszText = (char*)name; + ins.item.cchTextMax = 0; + HTREEITEM item = m_conditionTreeView.InsertItem(&ins); if (i == m_condition->getConditionType()) { - pCmbo->SetCurSel(ndx); + selItem = item; } + +#if RTS_ZEROHOUR + name = pTemplate->getName2().str(); + count = 0; + if (pTemplate->getName2().isEmpty()) continue; + parent = TVI_ROOT; + do { + count = 0; + const char *nameStart = name; + while (*name && *name != '/') { + count++; + name++; + } + if (*name=='/') { + count++; + name++; + } else { + name = nameStart; + count = 0; + } + if (count>0) { + strlcpy(prefix, nameStart, count); + parent = findOrAdd(&m_conditionTreeView, parent, prefix); + } + } while (count>0); + + ::memset(&ins, 0, sizeof(ins)); + ins.hParent = parent; + ins.hInsertAfter = TVI_SORT; + ins.item.mask = TVIF_PARAM|TVIF_TEXT; + ins.item.lParam = i; + ins.item.pszText = (char*)name; + ins.item.cchTextMax = 0; + m_conditionTreeView.InsertItem(&ins); +#endif } + m_conditionTreeView.Select(selItem, TVGN_FIRSTVISIBLE); + m_conditionTreeView.SelectItem(selItem); m_condition->setWarnings(false); m_myEditCtrl.SetWindowText(m_condition->getUiText().str()); m_myEditCtrl.SetSel(-1, -1); - formatConditionText(-1); + formatConditionText(0); + m_conditionTreeView.SetFocus(); - return TRUE; // return TRUE unless you set the focus to a control + return FALSE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } @@ -112,28 +235,34 @@ void EditCondition::formatConditionText(Int parameterNdx) { m_myEditCtrl.SetSel(0, 1000); m_myEditCtrl.SetSelectionCharFormat(cf); - m_myEditCtrl.SetReadOnly(); + //m_myEditCtrl.SetReadOnly(); // Set up the links. cf.dwMask = CFE_UNDERLINE | CFM_LINK | CFM_COLOR; cf.dwEffects = CFE_LINK | CFE_UNDERLINE; cf.crTextColor = RGB(0,0,255); + m_curEditParameter = parameterNdx; AsciiString strings[MAX_PARMS]; Int curChar = 0; Int numChars = 0; Int numStrings = m_condition->getUiStrings(strings); - Int i; AsciiString warningText; + AsciiString informationText; + Int i; for (i=0; igetNumParameters()) { + warningText.concat(EditParameter::getWarningText(m_condition->getParameter(i), false)); + informationText.concat(EditParameter::getInfoText(m_condition->getParameter(i))); numChars = m_condition->getParameter(i)->getUiText().getLength(); - warningText.concat(EditParameter::getWarningText(m_condition->getParameter(i))); + if (curChar==0) { + curChar++; + numChars--; + } m_myEditCtrl.SetSel(curChar, curChar+numChars); - if (numChars==0) continue; if (i==parameterNdx) { startSel = curChar; endSel = curChar+numChars; @@ -148,11 +277,19 @@ void EditCondition::formatConditionText(Int parameterNdx) { CString cstr; if (warningText.isEmpty()) { - if (cstr.LoadString(IDS_SCRIPT_NOWARNINGS)) { - GetDlgItem(IDC_WARNINGS_CAPTION)->SetWindowText(cstr); + if (informationText.isEmpty()) { + if (cstr.LoadString(IDS_SCRIPT_NOWARNINGS)) { + GetDlgItem(IDC_WARNINGS_CAPTION)->SetWindowText(cstr); + } + GetDlgItem(IDC_WARNINGS_CAPTION)->EnableWindow(false); + GetDlgItem(IDC_WARNINGS)->SetWindowText(""); + } else { + if (cstr.LoadString(IDS_SCRIPT_INFORMATION)) { + GetDlgItem(IDC_WARNINGS_CAPTION)->SetWindowText(cstr); + } + GetDlgItem(IDC_WARNINGS_CAPTION)->EnableWindow(true); + GetDlgItem(IDC_WARNINGS)->SetWindowText(informationText.str()); } - GetDlgItem(IDC_WARNINGS_CAPTION)->EnableWindow(false); - GetDlgItem(IDC_WARNINGS)->SetWindowText(""); } else { if (cstr.LoadString(IDS_SCRIPT_WARNINGS)) { GetDlgItem(IDC_WARNINGS_CAPTION)->SetWindowText(cstr); @@ -163,6 +300,8 @@ void EditCondition::formatConditionText(Int parameterNdx) { m_modifiedTextColor = false; m_myEditCtrl.SetSel(startSel, endSel); + m_curLinkChrg.cpMax = endSel; + m_curLinkChrg.cpMin = startSel; m_updating = false; } @@ -170,65 +309,140 @@ void EditCondition::formatConditionText(Int parameterNdx) { BOOL EditCondition::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { + NMTREEVIEW *pHdr = (NMTREEVIEW *)lParam; + + // Handle events from the tree control. + if (pHdr->hdr.idFrom == IDC_CONDITION_TREE) { + if (pHdr->hdr.code == TVN_SELCHANGED) { + char buffer[_MAX_PATH]; + HTREEITEM hItem = m_conditionTreeView.GetSelectedItem(); + TVITEM item; + ::memset(&item, 0, sizeof(item)); + item.mask = TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT|TVIF_STATE; + item.hItem = hItem; + item.pszText = buffer; + item.cchTextMax = sizeof(buffer)-2; + m_conditionTreeView.GetItem(&item); + if (item.lParam >= 0) { + enum Condition::ConditionType conditionType = (enum Condition::ConditionType)item.lParam; + if (m_condition->getConditionType() != conditionType) { + m_condition->setConditionType( conditionType ); + m_myEditCtrl.SetWindowText(m_condition->getUiText().str()); + formatConditionText(0); + } + } + } else if (pHdr->hdr.code == TVN_KEYDOWN) { + NMTVKEYDOWN *pKey = (NMTVKEYDOWN*)lParam; + Int key = pKey->wVKey; + if (key==VK_SHIFT || key==VK_SPACE) { + HTREEITEM hItem = m_conditionTreeView.GetSelectedItem(); + if (!m_conditionTreeView.ItemHasChildren(hItem)) { + hItem = m_conditionTreeView.GetParentItem(hItem); + } + m_conditionTreeView.Expand(hItem, TVE_TOGGLE); + return 0; + } + return 0; + } + return TRUE; + } + + // Handle events from the rich edit control containing the condition pieces. if (LOWORD(wParam) == IDC_RICH_EDIT_HERE+1) { NMHDR *pHdr = (NMHDR *)lParam; - if (pHdr->hwndFrom == m_myEditCtrl.m_hWnd && pHdr->code == EN_LINK) { - ENLINK *pLink = (ENLINK *)pHdr; - CHARRANGE chrg = pLink->chrg; - if (pLink->msg == WM_LBUTTONDOWN) { + if (pHdr->hwndFrom == m_myEditCtrl.m_hWnd) { + if (pHdr->code == EN_LINK) { + ENLINK *pLink = (ENLINK *)pHdr; + CHARRANGE chrg = pLink->chrg; // Determine which parameter. Int numChars = 0; Int curChar = 0; AsciiString strings[MAX_PARMS]; Int numStrings = m_condition->getUiStrings(strings); Int i; + Bool match = false; for (i=0; igetNumParameters()) { numChars = m_condition->getParameter(i)->getUiText().getLength(); - if (curChar == chrg.cpMin && curChar+numChars == chrg.cpMax) { - if (IDOK==EditParameter::edit(m_condition->getParameter(i))) { - m_myEditCtrl.SetWindowText(m_condition->getUiText().str()); - m_curEditParameter = i; - this->PostMessage(WM_TIMER, 0, 0); - } - return true; + match = (curChar+numChars/2 > chrg.cpMin && curChar+numChars/2 < chrg.cpMax); + if (match) { + m_curEditParameter = i; + break; } curChar += numChars; } } - } - CHARRANGE curChrg; - m_myEditCtrl.GetSel(curChrg); - if (curChrg.cpMin == chrg.cpMin && curChrg.cpMax == chrg.cpMax) { - return true; - } - if (m_modifiedTextColor) { - formatConditionText(-1); - } - m_curLinkChrg = chrg; - m_myEditCtrl.SetSel(chrg.cpMin, chrg.cpMax); - CHARFORMAT cf; - memset(&cf, 0, sizeof(cf)); - cf.cbSize = sizeof(cf); - cf.dwMask = CFM_COLOR; - cf.crTextColor = RGB(0,0,0); - m_myEditCtrl.SetSelectionCharFormat(cf); - m_modifiedTextColor = true; - return true; - } else if (pHdr->hwndFrom == m_myEditCtrl.m_hWnd && pHdr->code == EN_SELCHANGE) { - if (m_updating) { - return true; - } - CHARRANGE curChrg; - m_myEditCtrl.GetSel(curChrg); - if (curChrg.cpMin == m_curLinkChrg.cpMin && curChrg.cpMax == m_curLinkChrg.cpMax) { + if (pLink->msg == WM_LBUTTONDOWN) { + // Determine which parameter. + if (match) { + EditParameter::edit(m_condition->getParameter(m_curEditParameter), 0); + m_myEditCtrl.SetWindowText(m_condition->getUiText().str()); + this->PostMessage(WM_TIMER, 0, 0); + return true; + } + } + CHARRANGE curChrg; + m_myEditCtrl.GetSel(curChrg); + if (curChrg.cpMin == chrg.cpMin && curChrg.cpMax == chrg.cpMax) { + return true; + } + if (m_modifiedTextColor) { + formatConditionText(m_curEditParameter); + } + m_curLinkChrg = chrg; + m_myEditCtrl.SetSel(chrg.cpMin, chrg.cpMax); + m_myEditCtrl.SetFocus(); + CHARFORMAT cf; + memset(&cf, 0, sizeof(cf)); + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_COLOR; + cf.crTextColor = RGB(0,0,0); + m_myEditCtrl.SetSelectionCharFormat(cf); + m_modifiedTextColor = true; return true; - } - if (m_modifiedTextColor) { - formatConditionText(-1); + } else if (pHdr->code == EN_SETFOCUS) { + this->PostMessage(WM_TIMER, 0, 0); + } else if (pHdr->code == EN_SELCHANGE) { + if (m_updating) { + return true; + } + CHARRANGE curChrg; + m_myEditCtrl.GetSel(curChrg); + if (curChrg.cpMin == m_curLinkChrg.cpMin && curChrg.cpMax == m_curLinkChrg.cpMax) { + return true; + } + m_myEditCtrl.SetSel(m_curLinkChrg.cpMin, m_curLinkChrg.cpMax); + if (m_modifiedTextColor) { + this->PostMessage(WM_TIMER, 0, 0); + } + } else if (pHdr->code == EN_MSGFILTER) { + MSGFILTER *pFilter = (MSGFILTER *)pHdr; + if (pFilter->msg == WM_CHAR) { + Int keyPressed = pFilter->wParam; + if (keyPressed==VK_RETURN) { + return 1; + } + if (keyPressed==VK_RETURN || keyPressed == VK_TAB) { + m_curEditParameter++; + if (m_curEditParameter >= m_condition->getNumParameters()) { + m_curEditParameter = 0; + return 1; + } + this->PostMessage(WM_TIMER, 0, 0); + return 0; + } + EditParameter::edit(m_condition->getParameter(m_curEditParameter), keyPressed); + m_curEditParameter++; + if (m_curEditParameter >= m_condition->getNumParameters()) { + m_curEditParameter = 0; + } + this->PostMessage(WM_TIMER, 0, 0); + return 0; + } + return 1; } } } @@ -251,12 +465,13 @@ void EditCondition::OnSelchangeConditionType() } m_condition->setConditionType((enum Condition::ConditionType)index); m_myEditCtrl.SetWindowText(m_condition->getUiText().str()); - formatConditionText(-1); + formatConditionText(m_curEditParameter); } /** Not actually a timer - just used to send a delayed message to self because rich edit control is stupid. jba. */ void EditCondition::OnTimer(UINT nIDEvent) { + m_myEditCtrl.SetWindowText(m_condition->getUiText().str()); formatConditionText(m_curEditParameter); } diff --git a/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp b/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp index 5e7c6568182..8be357cbd52 100644 --- a/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/EditObjectParameter.cpp @@ -233,6 +233,28 @@ HTREEITEM EditObjectParameter::findOrAdd(HTREEITEM parent, const char *pLabel) return(child); } +BOOL EditObjectParameter::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + NMTREEVIEW *pHdr = (NMTREEVIEW *)lParam; + + // Handle events from the tree control. + if (pHdr->hdr.idFrom == IDC_TERRAIN_TREEVIEW) { + if (pHdr->hdr.code == TVN_KEYDOWN) { + NMTVKEYDOWN *pKey = (NMTVKEYDOWN*)lParam; + Int key = pKey->wVKey; + if (key==VK_SHIFT || key==VK_SPACE) { + HTREEITEM hItem = m_objectTreeView.GetSelectedItem(); + if (!m_objectTreeView.ItemHasChildren(hItem)) { + hItem = m_objectTreeView.GetParentItem(hItem); + } + m_objectTreeView.Expand(hItem, TVE_TOGGLE); + return 0; + } + return 0; + } + } + return CDialog::OnNotify(wParam, lParam, pResult); +} void EditObjectParameter::OnOK() { diff --git a/Generals/Code/Tools/WorldBuilder/src/EditParameter.cpp b/Generals/Code/Tools/WorldBuilder/src/EditParameter.cpp index 664cdc9505f..3e8afc32149 100644 --- a/Generals/Code/Tools/WorldBuilder/src/EditParameter.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/EditParameter.cpp @@ -105,7 +105,7 @@ END_MESSAGE_MAP() // EditParameter message handlers SidesList *EditParameter::m_sidesListP = nullptr; -Int EditParameter::edit( Parameter *pParm, AsciiString unitName ) +Int EditParameter::edit( Parameter *pParm, Int keyPressed, AsciiString unitName ) { if (pParm->getParameterType() == Parameter::COORD3D) { @@ -147,6 +147,7 @@ Int EditParameter::edit( Parameter *pParm, AsciiString unitName ) else { EditParameter editDlg; + editDlg.m_key = keyPressed; editDlg.m_parameter = pParm; //Set the name of the unit, because some parameters build information from the unit itself. editDlg.m_unitName = unitName; @@ -155,7 +156,7 @@ Int EditParameter::edit( Parameter *pParm, AsciiString unitName ) } } -AsciiString EditParameter::getWarningText(Parameter *pParm) +AsciiString EditParameter::getWarningText(Parameter *pParm, Bool isAction) { AsciiString warningText; AsciiString uiString = pParm->getString(); @@ -255,12 +256,13 @@ AsciiString EditParameter::getWarningText(Parameter *pParm) } break; - case Parameter::OBJECT_TYPE_LIST: // No warning is possible. break; case Parameter::COUNTER: - /// @todo - perhaps add more complex syntaxing for counters. + if (!isAction && !loadCounters(nullptr, uiString)) { + warningText.format("Counter/Timer '%s' does not exist.", uiString.str()); + } break; case Parameter::INT: break; @@ -272,6 +274,10 @@ AsciiString EditParameter::getWarningText(Parameter *pParm) break; case Parameter::ANGLE: break; +#if RTS_ZEROHOUR + case Parameter::PERCENT: + break; +#endif case Parameter::BOOLEAN: break; @@ -279,7 +285,9 @@ AsciiString EditParameter::getWarningText(Parameter *pParm) break; case Parameter::FLAG: - /// @todo - perhaps add more complex syntaxing for flags. + if (!isAction && !loadFlags(nullptr, uiString)) { + warningText.format("Flag '%s' is never initialized.", uiString.str()); + } break; case Parameter::COMPARISON: break; @@ -293,7 +301,12 @@ AsciiString EditParameter::getWarningText(Parameter *pParm) case Parameter::RADAR_EVENT_TYPE: break; - case Parameter::RELATION: +#if RTS_ZEROHOUR + case Parameter::LEFT_OR_RIGHT: + break; +#endif + + case Parameter::RELATION: break; case Parameter::DIALOG: @@ -377,6 +390,10 @@ AsciiString EditParameter::getWarningText(Parameter *pParm) case Parameter::REVEALNAME: break; + + } + if (warningText.isNotEmpty()) { + warningText.concat(" "); } return warningText; } @@ -415,6 +432,9 @@ AsciiString EditParameter::getInfoText(Parameter *pParm) case Parameter::COLOR: case Parameter::COORD3D: case Parameter::ANGLE: +#if RTS_ZEROHOUR + case Parameter::PERCENT: +#endif case Parameter::BOOLEAN: case Parameter::REAL: case Parameter::FLAG: @@ -441,6 +461,10 @@ AsciiString EditParameter::getInfoText(Parameter *pParm) case Parameter::OBJECT_TYPE_LIST: case Parameter::REVEALNAME: case Parameter::OBJECT_PANEL_FLAG: +#if RTS_ZEROHOUR + case Parameter::LEFT_OR_RIGHT: +#endif + break; case Parameter::LOCALIZED_TEXT: @@ -478,6 +502,7 @@ void EditParameter::OnEditchangeCombo() void EditParameter::loadConditionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo) { OrCondition *pOr; + if (pCombo==nullptr) return; // null pcombo is used in syntaxing commands. jba. for (pOr= pScr->getOrCondition(); pOr; pOr = pOr->getNextOrCondition()) { Condition *pCondition; for (pCondition = pOr->getFirstAndCondition(); pCondition; pCondition = pCondition->getNext()) { @@ -501,19 +526,26 @@ void EditParameter::loadConditionParameter(Script *pScr, Parameter::ParameterTyp } } -void EditParameter::loadActionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo) +Bool EditParameter::loadActionParameter(Script *pScr, Parameter::ParameterType type, CComboBox *pCombo, AsciiString match) { ScriptAction *pAction; + Bool found = false; for (pAction = pScr->getAction(); pAction; pAction = pAction->getNext()) { Int i; for (i=0; igetNumParameters(); i++) { if (type == pAction->getParameter(i)->getParameterType()) { - if (CB_ERR == pCombo->FindStringExact(-1, pAction->getParameter(i)->getString().str())) { - pCombo->AddString(pAction->getParameter(i)->getString().str()); + if (pCombo) { + if (CB_ERR == pCombo->FindStringExact(-1, pAction->getParameter(i)->getString().str())) { + pCombo->AddString(pAction->getParameter(i)->getString().str()); + } + } + if (match == pAction->getParameter(i)->getString()) { + found = true; } } } } + return found; } Bool EditParameter::loadAttackSetParameter(Script *pScr, CComboBox *pCombo, AsciiString match) @@ -662,9 +694,10 @@ AsciiString EditParameter::getCreatedUnitTemplateName(AsciiString unitName) return AsciiString::TheEmptyString; } -void EditParameter::loadCounters(CComboBox *pCombo) +Bool EditParameter::loadCounters(CComboBox *pCombo, AsciiString match) { - pCombo->ResetContent(); + Bool found = false; + if (pCombo) pCombo->ResetContent(); Int i; SidesList *sidesListP = m_sidesListP; if (sidesListP==nullptr) sidesListP = TheSidesList; @@ -673,16 +706,21 @@ void EditParameter::loadCounters(CComboBox *pCombo) Script *pScr; for (pScr = pSL->getScript(); pScr; pScr=pScr->getNext()) { loadConditionParameter(pScr, Parameter::COUNTER, pCombo); - loadActionParameter(pScr, Parameter::COUNTER, pCombo); + if (loadActionParameter(pScr, Parameter::COUNTER, pCombo, match)) { + found = true; + } } ScriptGroup *pGroup; for (pGroup = pSL->getScriptGroup(); pGroup; pGroup=pGroup->getNext()) { for (pScr = pGroup->getScript(); pScr; pScr=pScr->getNext()) { loadConditionParameter(pScr, Parameter::COUNTER, pCombo); - loadActionParameter(pScr, Parameter::COUNTER, pCombo); + if (loadActionParameter(pScr, Parameter::COUNTER, pCombo, match)) { + found = true; + } } } } + return found; } Bool EditParameter::loadAttackPrioritySets(CComboBox *pCombo, AsciiString match) @@ -944,9 +982,10 @@ Bool EditParameter::loadEmoticons( CComboBox *pCombo, AsciiString match ) } //------------------------------------------------------------------------------------------------- -void EditParameter::loadFlags(CComboBox *pCombo) +Bool EditParameter::loadFlags(CComboBox *pCombo, AsciiString match) { - pCombo->ResetContent(); + Bool found = false; + if (pCombo) pCombo->ResetContent(); Int i; SidesList *sidesListP = m_sidesListP; if (sidesListP==nullptr) sidesListP = TheSidesList; @@ -955,16 +994,21 @@ void EditParameter::loadFlags(CComboBox *pCombo) Script *pScr; for (pScr = pSL->getScript(); pScr; pScr=pScr->getNext()) { loadConditionParameter(pScr, Parameter::FLAG, pCombo); - loadActionParameter(pScr, Parameter::FLAG, pCombo); + if (loadActionParameter(pScr, Parameter::FLAG, pCombo, match)) { + found = true; + } } ScriptGroup *pGroup; for (pGroup = pSL->getScriptGroup(); pGroup; pGroup=pGroup->getNext()) { for (pScr = pGroup->getScript(); pScr; pScr=pScr->getNext()) { loadConditionParameter(pScr, Parameter::FLAG, pCombo); - loadActionParameter(pScr, Parameter::FLAG, pCombo); + if (loadActionParameter(pScr, Parameter::FLAG, pCombo, match)) { + found = true; + } } } } + return found; } //------------------------------------------------------------------------------------------------- @@ -1273,7 +1317,7 @@ Bool EditParameter::loadFontNames(CComboBox *pCombo, AsciiString match) } // EditParameter::readFontFile ====================================================== -/** Read the font file defintitions and load them */ +/** Read the font file definitions and load them */ //============================================================================= void EditParameter::readFontFile( const char *filename ) { @@ -1296,7 +1340,7 @@ void EditParameter::readFontFile( const char *filename ) for( Int i = 0; i < fontCount; i++ ) { - // read all the font defitions + // read all the font definitions char fontBuffer[ 512 ]; Int size, bold; char c; @@ -1813,6 +1857,14 @@ BOOL EditParameter::OnInitDialog() showCombo = false; break; +#if RTS_ZEROHOUR + case Parameter::PERCENT: + captionText = "Percent:"; + editText.Format("%.2f", m_parameter->getReal()*100.0f); + showCombo = false; + break; +#endif + case Parameter::FLAG: captionText = "Flag named:"; showCombo = true; @@ -1820,12 +1872,13 @@ BOOL EditParameter::OnInitDialog() break; case Parameter::COMPARISON: captionText = "Comparison:"; - pList->InsertString(-1, "Less Than"); - pList->InsertString(-1, "Less Than or Equal"); - pList->InsertString(-1, "Equal To"); - pList->InsertString(-1, "Greater Than or Equal"); - pList->InsertString(-1, "Greater Than"); - pList->InsertString(-1, "Not Equal To"); + pList->InsertString(-1, "LT Less Than"); + pList->InsertString(-1, "LE Less Than or Equal"); + pList->InsertString(-1, "EQ Equal To"); + pList->InsertString(-1, "GE Greater Than or Equal"); + pList->InsertString(-1, "GT Greater Than"); + pList->InsertString(-1, "NE Not Equal To"); + pList->SetCurSel(m_parameter->getInt()); showList = true; break; @@ -1871,7 +1924,7 @@ BOOL EditParameter::OnInitDialog() case Parameter::RADAR_EVENT_TYPE: captionText = "Radar Event Type:"; - pList->InsertString(-1, "Construction"); + pList->InsertString(-1,"Construction"); pList->InsertString(-1,"Upgrade"); pList->InsertString(-1,"Under Attack"); pList->InsertString(-1,"Information"); @@ -1879,6 +1932,18 @@ BOOL EditParameter::OnInitDialog() showList = true; break; + +#if RTS_ZEROHOUR + case Parameter::LEFT_OR_RIGHT: + captionText = "Evacuate Container Side Choices:"; + pList->InsertString(-1,"Left"); + pList->InsertString(-1,"Right"); + pList->InsertString(-1,"Center (Default)"); + pList->SetCurSel(m_parameter->getInt() - 1); + showList = true; + break; +#endif + case Parameter::RELATION: captionText = "Relation:"; pList->InsertString(-1, "Enemy"); @@ -2056,13 +2121,17 @@ BOOL EditParameter::OnInitDialog() pCombo->SetCurSel(0); } pCombo->SetFocus(); + if (m_key && m_key != VK_SPACE) pCombo->PostMessage(WM_CHAR, m_key, 0); } else if (showList) { pList->ShowWindow(SW_SHOW); pList->SetFocus(); + if (m_key && m_key != VK_SPACE) pList->PostMessage(WM_CHAR, m_key, 0); } else { pEdit->ShowWindow(SW_SHOW); pEdit->SetWindowText(editText); + pEdit->SetSel(0, 999); pEdit->SetFocus(); + if (m_key && m_key != VK_SPACE) pEdit->PostMessage(WM_CHAR, m_key, 0); } pCaption->SetWindowText(captionText); @@ -2075,6 +2144,22 @@ BOOL EditParameter::OnInitDialog() // EXCEPTION: OCX Property Pages should return FALSE } +Bool EditParameter::scanReal(CEdit *pEdit, Real scale) +{ + CString txt; + Real theReal; + + pEdit->GetWindowText(txt); + if (1==sscanf(txt, "%f", &theReal)) { + m_parameter->friend_setReal(theReal*scale); + return TRUE; + } else { + pEdit->SetFocus(); + ::MessageBeep(MB_ICONEXCLAMATION); + return FALSE; + } +} + void EditParameter::OnOK() { CComboBox *pCombo = (CComboBox*)GetDlgItem(IDC_COMBO); @@ -2149,27 +2234,24 @@ void EditParameter::OnOK() break; case Parameter::REAL: - pEdit->GetWindowText(txt); - Real theReal; - if (1==sscanf(txt, "%f", &theReal)) { - m_parameter->friend_setReal(theReal); - } else { - pEdit->SetFocus(); - ::MessageBeep(MB_ICONEXCLAMATION); + if (! scanReal(pEdit, 1.0f)) { return; } break; case Parameter::ANGLE: - pEdit->GetWindowText(txt); - if (1==sscanf(txt, "%f", &theReal)) { - m_parameter->friend_setReal(theReal*PI/180); - } else { - pEdit->SetFocus(); - ::MessageBeep(MB_ICONEXCLAMATION); + if (! scanReal(pEdit, PI/180.0f)) { + return; + } + break; + +#if RTS_ZEROHOUR + case Parameter::PERCENT: + if (! scanReal(pEdit, 1.0f/100.0f)) { return; } break; +#endif case Parameter::BOOLEAN: case Parameter::COMPARISON: @@ -2194,6 +2276,14 @@ void EditParameter::OnOK() case Parameter::RADAR_EVENT_TYPE: m_parameter->friend_setInt(pList->GetCurSel() + RADAR_EVENT_CONSTRUCTION); break; + + +#if RTS_ZEROHOUR + case Parameter::LEFT_OR_RIGHT: + m_parameter->friend_setInt(pList->GetCurSel() + 1); + break; +#endif + case Parameter::LOCALIZED_TEXT: pCombo->GetWindowText(txt); comboText = AsciiString(txt); diff --git a/Generals/Code/Tools/WorldBuilder/src/ExportScriptsOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/ExportScriptsOptions.cpp index 1fcad1a76eb..b749bd3387d 100644 --- a/Generals/Code/Tools/WorldBuilder/src/ExportScriptsOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/ExportScriptsOptions.cpp @@ -29,6 +29,7 @@ Bool ExportScriptsOptions::m_units = true; Bool ExportScriptsOptions::m_waypoints = true; Bool ExportScriptsOptions::m_triggers = true; Bool ExportScriptsOptions::m_allScripts = false; +Bool ExportScriptsOptions::m_sides = true; ExportScriptsOptions::ExportScriptsOptions(CWnd* pParent /*=nullptr*/) : CDialog(ExportScriptsOptions::IDD, pParent) @@ -68,6 +69,9 @@ void ExportScriptsOptions::OnOK() m_triggers = pButton->GetCheck()==1; pButton = (CButton*)GetDlgItem(IDC_ALL_SCRIPTS); m_allScripts = pButton->GetCheck()==1; + pButton = (CButton*)GetDlgItem(IDC_SIDES); + m_sides = pButton->GetCheck()==1; + CDialog::OnOK(); } @@ -86,6 +90,8 @@ BOOL ExportScriptsOptions::OnInitDialog() pButton->SetCheck(m_allScripts?1:0); pButton = (CButton*)GetDlgItem(IDC_SELECTED_SCRIPTS); pButton->SetCheck(m_allScripts?0:1); + pButton = (CButton*)GetDlgItem(IDC_SIDES); + pButton->SetCheck(m_sides?1:0); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE diff --git a/Generals/Code/Tools/WorldBuilder/src/FeatherTool.cpp b/Generals/Code/Tools/WorldBuilder/src/FeatherTool.cpp index 54e3b5a0105..c05bcea2e2a 100644 --- a/Generals/Code/Tools/WorldBuilder/src/FeatherTool.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/FeatherTool.cpp @@ -20,6 +20,7 @@ // Texture tiling tool for worldbuilder. // Author: John Ahlquist, April 2001 + #include "StdAfx.h" #include "resource.h" diff --git a/Generals/Code/Tools/WorldBuilder/src/FloodFillTool.cpp b/Generals/Code/Tools/WorldBuilder/src/FloodFillTool.cpp index e5fcd2cab97..8d4041010fe 100644 --- a/Generals/Code/Tools/WorldBuilder/src/FloodFillTool.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/FloodFillTool.cpp @@ -20,6 +20,7 @@ // Texture tiling tool for worldbuilder. // Author: John Ahlquist, April 2001 + #include "StdAfx.h" #include "resource.h" diff --git a/Generals/Code/Tools/WorldBuilder/src/GlobalLightOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/GlobalLightOptions.cpp index 1eaa4ba4f2c..cebfdf75016 100644 --- a/Generals/Code/Tools/WorldBuilder/src/GlobalLightOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/GlobalLightOptions.cpp @@ -937,7 +937,7 @@ void GlobalLightOptions::OnShowWindow(BOOL bShow, UINT nStatus) stuffValuesIntoFields(K_SUN); stuffValuesIntoFields(K_ACCENT1); stuffValuesIntoFields(K_ACCENT2); - if (!IsWindowVisible()) { + if (!bShow) { WbView3d * pView = CWorldBuilderDoc::GetActive3DView(); if (pView) { Coord3D lightRay; diff --git a/Generals/Code/Tools/WorldBuilder/src/LayersList.cpp b/Generals/Code/Tools/WorldBuilder/src/LayersList.cpp index a7b52ca12ac..9e8f03e494a 100644 --- a/Generals/Code/Tools/WorldBuilder/src/LayersList.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/LayersList.cpp @@ -42,9 +42,11 @@ #include "PointerTool.h" #include "WorldBuilderDoc.h" +#include "GameLogic/PolygonTrigger.h" #include + static int newLayerNum = 1; // CLLTreeCtrl Implementation ///////////////////////////////////////////////////////////////////// @@ -68,6 +70,18 @@ void CLLTreeCtrl::buildMoveMenu(CMenu* moveMenu, UINT firstID) } } +enum LayersListMenuSelectionsEnum { + LAYERS_LIST_SELECT_OBJECT, + LAYERS_LIST_SELECT_ACTIVE_LAYER, + LAYERS_LIST_BREAK_1, + LAYERS_LIST_INSERT_NEW_LAYER, + LAYERS_LIST_DELETE_CURRENT_LAYER, + LAYERS_LIST_MERGE_LAYER_INTO, + LAYERS_LIST_MERGE_OBJECT_INTO, + LAYERS_LIST_MERGE_VIEW_SELECTION_INTO, + LAYERS_LIST_BREAK_2, + LAYERS_LIST_HIDE_CURRENT_LAYER, +}; void CLLTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) { // first, if there's something under the mouse, select it. @@ -98,34 +112,50 @@ void CLLTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) } ClientToScreen(&point); - CMenu *moveViewSelectionMenu = pPopup->GetSubMenu(4); - moveViewSelectionMenu ->RemoveMenu(0, MF_BYPOSITION); + CMenu *moveViewSelectionMenu = pPopup->GetSubMenu(LAYERS_LIST_MERGE_VIEW_SELECTION_INTO); + moveViewSelectionMenu->RemoveMenu(0, MF_BYPOSITION); buildMoveMenu(moveViewSelectionMenu, ID_LAYERSLIST_MERGEVIEWSELECTIONINTO_BEGIN); if (item) { if (contextIsLayer) { - LayersList *ll = (LayersList*) GetParent(); - pPopup->RemoveMenu(3, MF_BYPOSITION); - Bool hidden = ll->isLayerHidden(AsciiString(GetItemText(item))); - pPopup->CheckMenuItem(ID_HIDECURRENTLAYER, MF_BYCOMMAND | (hidden ? MF_CHECKED : MF_UNCHECKED)); + CString itemText = GetItemText(item); + if ((itemText.CompareNoCase(LayersList::TheActiveLayerName.c_str()) == 0) || + ((LayersList::TheActiveLayerName.c_str() == nullptr) && + (LayersList::TheUnmutableDefaultLayerName.compare(LayersList::TheDefaultLayerName) == 0))) { + // Don't allow the current layer to be hidden. + // Because the objects will immediately disappear when placed. + pPopup->EnableMenuItem(ID_HIDECURRENTLAYER, MF_GRAYED); + } else { + LayersList *ll = (LayersList*) GetParent(); + Bool hidden = ll->isLayerHidden(AsciiString(itemText)); + pPopup->CheckMenuItem(ID_HIDECURRENTLAYER, MF_BYCOMMAND | (hidden ? MF_CHECKED : MF_UNCHECKED)); + } - CMenu *moveMenu = pPopup->GetSubMenu(2); + CMenu *moveMenu = pPopup->GetSubMenu(LAYERS_LIST_MERGE_LAYER_INTO); moveMenu->RemoveMenu(0, MF_BYPOSITION); buildMoveMenu(moveMenu, ID_LAYERSLIST_MERGELAYERINTO_BEGIN); + + pPopup->RemoveMenu(LAYERS_LIST_MERGE_VIEW_SELECTION_INTO, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_MERGE_OBJECT_INTO, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_SELECT_OBJECT, MF_BYPOSITION); + } else { pPopup->EnableMenuItem(ID_DELETECURRENTLAYER, MF_GRAYED); - pPopup->RemoveMenu(2, MF_BYPOSITION); - pPopup->RemoveMenu(ID_HIDECURRENTLAYER, MF_BYCOMMAND); + pPopup->EnableMenuItem(ID_HIDECURRENTLAYER, MF_GRAYED); - CMenu* moveMenu = pPopup->GetSubMenu(2); + CMenu* moveMenu = pPopup->GetSubMenu(LAYERS_LIST_MERGE_OBJECT_INTO); moveMenu->RemoveMenu(0, MF_BYPOSITION); buildMoveMenu(moveMenu, ID_LAYERSLIST_MERGEOBJECTINTO_BEGIN); + + pPopup->RemoveMenu(LAYERS_LIST_MERGE_LAYER_INTO, MF_BYPOSITION); } } else { - pPopup->EnableMenuItem(ID_DELETECURRENTLAYER, MF_GRAYED); - pPopup->RemoveMenu(3, MF_BYPOSITION); - pPopup->RemoveMenu(2, MF_BYPOSITION); - pPopup->RemoveMenu(ID_HIDECURRENTLAYER, MF_BYCOMMAND); + pPopup->RemoveMenu(LAYERS_LIST_HIDE_CURRENT_LAYER, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_MERGE_OBJECT_INTO, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_MERGE_LAYER_INTO, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_DELETE_CURRENT_LAYER, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_SELECT_ACTIVE_LAYER, MF_BYPOSITION); + pPopup->RemoveMenu(LAYERS_LIST_SELECT_OBJECT, MF_BYPOSITION); } pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x, point.y, GetParent()); @@ -140,6 +170,7 @@ END_MESSAGE_MAP() LayersList::LayersList(UINT nIDTemplate, CWnd *parentWnd) : CDialog(nIDTemplate, parentWnd) { mTree = nullptr; + m_activatedLayer = false; resetLayers(); } @@ -160,6 +191,8 @@ void LayersList::resetLayers() defaultLayer.show = true; mLayers.clear(); mLayers.push_back(defaultLayer); + defaultLayer.layerName = AsciiString(ThePolygonTriggerLayerName.c_str()); + mLayers.push_back(defaultLayer); TheLayersList = this; if (mTree) { mTree->DeleteAllItems(); @@ -179,9 +212,12 @@ void LayersList::addMapObjectToLayersList(MapObject *objToAdd, AsciiString layer // try to add a layer of that name. addLayerNamed(layerToAddTo); if (!findLayerNamed(layerToAddTo, &layerIt)) { - // if we still can't find that layer name, then try adding it to the default layer. - if (!findLayerNamed(AsciiString(TheDefaultLayerName.c_str()), &layerIt)) { - return; + // Try to place it in the active layer. + if (!findLayerNamed(AsciiString(TheActiveLayerName.c_str()), &layerIt)) { + // if we still can't find that layer name, then try adding it to the default layer. + if (!findLayerNamed(AsciiString(TheDefaultLayerName.c_str()), &layerIt)) { + return; + } } } } @@ -189,6 +225,32 @@ void LayersList::addMapObjectToLayersList(MapObject *objToAdd, AsciiString layer addMapObjectToLayer(objToAdd, &layerIt); } +void LayersList::addPolygonTriggerToLayersList(PolygonTrigger *triggerToAdd, AsciiString layerToAddTo) +{ + if (!triggerToAdd || findPolygonTriggerAndList(triggerToAdd)) { + DEBUG_CRASH(("PolygonTrigger added was null or object already in Layers List. jkmcd")); + return; + } + ListLayerIt layerIt; + + if (!findLayerNamed(layerToAddTo, &layerIt)) { + // try to add a layer of that name. + addLayerNamed(layerToAddTo); + if (!findLayerNamed(layerToAddTo, &layerIt)) { + // Try to place it in the active layer. + if (!findLayerNamed(AsciiString(TheActiveLayerName.c_str()), &layerIt)) { + // if we still can't find that layer name, then try adding it to the trigger layer. + if (!findLayerNamed(AsciiString(ThePolygonTriggerLayerName.c_str()), &layerIt)) { + return; + } + } + } + } + + addPolygonTriggerToLayer(triggerToAdd, &layerIt); +} + + AsciiString LayersList::removeMapObjectFromLayersList(MapObject *objToRemove) { ListLayerIt layerIt; @@ -202,6 +264,20 @@ AsciiString LayersList::removeMapObjectFromLayersList(MapObject *objToRemove) return layerIt->layerName; } +AsciiString LayersList::removePolygonTriggerFromLayersList(PolygonTrigger *triggerToRemove) +{ + ListLayerIt layerIt; + ListPolygonTriggerPtrIt triggerIt; + if (!triggerToRemove || !findPolygonTriggerAndList(triggerToRemove, &layerIt, &triggerIt)) { + DEBUG_CRASH(("Couldn't find that polygon trigger in the layers list. jkmcd")); + return AsciiString::TheEmptyString; + } + + removePolygonTriggerFromLayer(triggerToRemove, &layerIt, &triggerIt); + return layerIt->layerName; +} + + void LayersList::changeMapObjectLayer(MapObject *objToChange, AsciiString layerToPlaceOn) { if (!objToChange) { @@ -213,6 +289,17 @@ void LayersList::changeMapObjectLayer(MapObject *objToChange, AsciiString layerT addMapObjectToLayersList(objToChange, layerToPlaceOn); } +void LayersList::changePolygonTriggerLayer(PolygonTrigger *triggerToChange, AsciiString layerToPlaceOn) +{ + if (!triggerToChange) { + DEBUG_CRASH(("Attempted to change location of null object. jkmcd")); + return; + } + + removePolygonTriggerFromLayersList(triggerToChange); + addPolygonTriggerToLayersList(triggerToChange, layerToPlaceOn); +} + void LayersList::addLayerNamed(IN AsciiString layerToAdd) { if (findLayerNamed(layerToAdd)) { @@ -238,6 +325,12 @@ void LayersList::removeLayerNamed(IN AsciiString layerToRemove) return; } + // Not allowed to remove the Default trigger layer + if (layerToRemove.compareNoCase(ThePolygonTriggerLayerName.c_str()) == 0) { + return; + } + + // If we can't find the layer, how can we remove it? if (!findLayerNamed(layerToRemove, &layerIt)) { DEBUG_CRASH(("Couldn't find layer named %s", layerToRemove.str())); @@ -280,9 +373,25 @@ void LayersList::mergeLayerInto(IN ListLayerIt src, IN ListLayerIt dst) changeMapObjectLayer(*mopIt, dst->layerName); } + ListPolygonTriggerPtrIt ptpIt; + for (ptpIt = src->polygonTriggersInLayer.begin(); ptpIt != src->polygonTriggersInLayer.end(); ptpIt = src->polygonTriggersInLayer.begin()) { + changePolygonTriggerLayer(*ptpIt, dst->layerName); + } + + + // Don't remove these layers. if (src->layerName.compareNoCase(TheDefaultLayerName.c_str()) == 0) { return; } + if (src->layerName.compareNoCase(ThePolygonTriggerLayerName.c_str()) == 0) { + return; + } + + if (src->layerName.compareNoCase(TheActiveLayerName.c_str()) == 0) { + // The active layer is no longer available. + TheActiveLayerName = AsciiString::TheEmptyString.str(); + } + // remove the layer from the tree view HTREEITEM itemToRemove = findTreeLayerNamed(src->layerName); @@ -336,6 +445,11 @@ void LayersList::updateUIFromList() pTree->InsertItem((*objIt)->getName().str(), iconToShow, iconToShow, thisBranch); } } + + for (ListPolygonTriggerPtrIt triggerIt = layersIt->polygonTriggersInLayer.begin(); triggerIt != layersIt->polygonTriggersInLayer.end(); ++triggerIt) { + const AsciiString& uniqueID = (*triggerIt)->getTriggerName(); + pTree->InsertItem(uniqueID.str(), iconToShow, iconToShow, thisBranch); + } } } @@ -365,6 +479,33 @@ Bool LayersList::findMapObjectAndList(IN MapObject *objectToFind, OUT ListLayerI return false; } +Bool LayersList::findPolygonTriggerAndList(IN PolygonTrigger *triggerToFind, OUT ListLayerIt *layerIt, OUT ListPolygonTriggerPtrIt *triggerIt) +{ + if (!triggerToFind) { + return false; + } + + for (ListLayerIt layersIt = mLayers.begin(); layersIt != mLayers.end(); ++layersIt) { + for (ListPolygonTriggerPtrIt triggerPtrIt = layersIt->polygonTriggersInLayer.begin(); triggerPtrIt != layersIt->polygonTriggersInLayer.end(); ++triggerPtrIt) { + if ((*triggerPtrIt) == triggerToFind) { + if (layerIt) { + (*layerIt) = layersIt; + } + + if (triggerIt) { + (*triggerIt) = triggerPtrIt; + } + + return true; + } + } + } + + // if we get here, it means we didn't find the object anywhere in any of the layers + return false; +} + + Bool LayersList::findLayerNamed(IN AsciiString layerName, OUT ListLayerIt *layerIt) { if (layerName.isEmpty()) { @@ -438,6 +579,55 @@ void LayersList::addMapObjectToLayer(IN MapObject *objectToAdd, IN ListLayerIt * } +void LayersList::addPolygonTriggerToLayer(IN PolygonTrigger *triggerToAdd, IN ListLayerIt *layerIt) +{ + if (!triggerToAdd) { + DEBUG_CRASH(("No trigger to add in addPolygonTriggerToLayer. This should not happen. jkmcd")); + return; + } + + ListLayerIt layerToAddTo; + if (layerIt) { + layerToAddTo = *layerIt; + } else { + // By default, add to the default layer. + if (!findLayerNamed(AsciiString(ThePolygonTriggerLayerName.c_str()), &layerToAddTo)) { + // If we couldn't find that layer, then we're fuxored. + return; + } + } + + if (layerToAddTo->layerName.compareNoCase(AsciiString(ThePolygonTriggerLayerName.c_str())) == 0) { + triggerToAdd->setLayerName(AsciiString::TheEmptyString); + } else { + triggerToAdd->setLayerName(layerToAddTo->layerName); + } + + // layerToAddTo now has a valid layer to add to. + layerToAddTo->polygonTriggersInLayer.push_back(triggerToAdd); + + // only update this object. + HTREEITEM hItem = findTreeLayerNamed(layerToAddTo->layerName); + if (hItem) { + const AsciiString& triggerName = triggerToAdd->getTriggerName(); + int iconToShow = (layerToAddTo->show ? 0 : 1); + mTree->InsertItem(triggerName.str(), iconToShow, iconToShow, hItem); + } + + CWorldBuilderDoc *pDoc = CWorldBuilderDoc::GetActiveDoc(); + if (!pDoc) { + return; + } + + if (!layerToAddTo->show) { + triggerToAdd->setShouldRender(false); + } else { + triggerToAdd->setShouldRender(true); + } + +} + + void LayersList::removeMapObjectFromLayer(IN MapObject *objectToRemove, IN ListLayerIt *layerIt, IN ListMapObjectPtrIt *objectIt) { if (!objectToRemove) { @@ -478,6 +668,46 @@ void LayersList::removeMapObjectFromLayer(IN MapObject *objectToRemove, IN ListL } +void LayersList::removePolygonTriggerFromLayer(IN PolygonTrigger *triggerToRemove, IN ListLayerIt *layerIt, IN ListPolygonTriggerPtrIt *triggerIt) +{ + if (!triggerToRemove) { + DEBUG_CRASH(("Attempted to remove null trigger from layers list. jkmcd")); + return; + } + + ListLayerIt layerToRemoveFrom; + ListPolygonTriggerPtrIt triggerBeingRemove; + + if (layerIt && triggerIt) { + layerToRemoveFrom = (*layerIt); + triggerBeingRemove = (*triggerIt); + } else { + if (!findPolygonTriggerAndList(triggerToRemove, &layerToRemoveFrom, &triggerBeingRemove)) { + DEBUG_CRASH(("Couldn't find the object anywhere. Why did we try to remove it? jkmcd")); + return; + } + } + + // only remove this object + HTREEITEM layer = findTreeLayerNamed(layerToRemoveFrom->layerName); + if (layer) { + const AsciiString& triggerUID = (*triggerBeingRemove)->getTriggerName(); + HTREEITEM itemToDelete = findTreeObjectNamed(triggerUID.str(), layer); + if (itemToDelete) { + mTree->DeleteItem(itemToDelete); + } + } + + // don't need to update the layer in the object because only 1 of 2 things can be happening: + // 1. We are about to delete the object + // 2. The object is about to be moved to the default layer (and will be updated anyways.) + + // layerToRemoveFrom and objectToRemove are now valid. Remove em. + layerToRemoveFrom->polygonTriggersInLayer.erase(triggerBeingRemove); + +} + + BOOL LayersList::OnInitDialog() { // call the parent first @@ -502,10 +732,12 @@ BOOL LayersList::OnInitDialog() pTree = (CTreeCtrl*) GetDlgItem(IDC_LL_TREE); // pTree should == mTree now. - mImageList.Create(16, 16, ILC_COLOR8, 2, 2); + mImageList.Create(16, 16, ILC_COLOR8, 3, 3); + // If the order of these are changed, please update the enum in updateTreeImages. mImageList.Add(LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_Show))); mImageList.Add(LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_Hide))); + mImageList.Add(LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_Selected))); pTree->SetImageList(&mImageList, LVSIL_NORMAL); pTree->InsertItem(TheDefaultLayerName.c_str(), 0, 0); @@ -536,6 +768,13 @@ void LayersList::OnBeginEditLabel(NMHDR *pNotifyStruct, LRESULT* pResult) return; } + if (strcmp(ptvdi->item.pszText, ThePolygonTriggerLayerName.c_str()) == 0) { + // Can't edit the default polygon trigger layer name. + (*pResult) = 1; + return; + } + + CString str = pTree->GetItemText(ptvdi->item.hItem); // if we can't find the layer of that name, then if (!findLayerNamed(AsciiString(str))) { @@ -565,11 +804,30 @@ void LayersList::OnEndEditLabel(NMHDR *pNotifyStruct, LRESULT* pResult) return; } - layerIt->layerName = AsciiString(ptvdi->item.pszText); - if (mCurrentlyEditingLabel.compareNoCase(AsciiString(TheDefaultLayerName.c_str())) == 0) { + AsciiString newLayerName(ptvdi->item.pszText); + Bool isDefaultLayer = mCurrentlyEditingLabel.compareNoCase(AsciiString(TheDefaultLayerName.c_str())) == 0; + Bool isActiveLayer = mCurrentlyEditingLabel.compareNoCase(TheActiveLayerName.c_str()) == 0; + AsciiString objectLayerName = isDefaultLayer ? AsciiString::TheEmptyString : newLayerName; + + // Keep persisted object and trigger assignments in sync with the renamed layer. + for (ListMapObjectPtrIt objectIt = layerIt->objectsInLayer.begin(); + objectIt != layerIt->objectsInLayer.end(); ++objectIt) { + (*objectIt)->getProperties()->setAsciiString(TheKey_objectLayer, objectLayerName); + } + for (ListPolygonTriggerPtrIt triggerIt = layerIt->polygonTriggersInLayer.begin(); + triggerIt != layerIt->polygonTriggersInLayer.end(); ++triggerIt) { + (*triggerIt)->setLayerName(newLayerName); + } + + layerIt->layerName = newLayerName; + if (isDefaultLayer) { // update the default label to be the new layer name. TheDefaultLayerName = layerIt->layerName.str(); } + if (isActiveLayer) { + // The active layer is tracked by name. + TheActiveLayerName = layerIt->layerName.str(); + } // do this to prevent rebuilding the tree. pTree->SetItemText(ptvdi->item.hItem, layerIt->layerName.str()); @@ -577,6 +835,7 @@ void LayersList::OnEndEditLabel(NMHDR *pNotifyStruct, LRESULT* pResult) mCurrentlyEditingLabel = AsciiString::TheEmptyString; } + void LayersList::OnNewLayer() { CTreeCtrl *pTree = (CTreeCtrl*) GetDlgItem(IDC_LL_TREE); @@ -614,13 +873,31 @@ void LayersList::OnDeleteLayer() return; } + if (asciiCatToDelete.compareNoCase(AsciiString(ThePolygonTriggerLayerName.c_str())) == 0) { + return; + } + ListLayerIt srcLayerIt, dstLayerIt; if (!findLayerNamed(asciiCatToDelete, &srcLayerIt)) { return; } - if (!findLayerNamed(AsciiString(TheDefaultLayerName.c_str()), &dstLayerIt)) { - return; + + if (asciiCatToDelete.compareNoCase(TheActiveLayerName.c_str()) == 0) { + // The active layer is being deleted. + TheActiveLayerName = AsciiString::TheEmptyString.str(); + updateTreeImages(); + + if (!findLayerNamed(AsciiString(TheDefaultLayerName.c_str()), &dstLayerIt)) { + return; + } + } else { + + if (!findLayerNamed(AsciiString(TheActiveLayerName.c_str()), &dstLayerIt)) { + if (!findLayerNamed(AsciiString(TheDefaultLayerName.c_str()), &dstLayerIt)) { + return; + } + } } mergeLayerInto(srcLayerIt, dstLayerIt); @@ -683,28 +960,8 @@ void LayersList::OnHideShowLayer() } layerIt->show = !layerIt->show; - - ListMapObjectPtrIt it; - for (it = layerIt->objectsInLayer.begin(); it != layerIt->objectsInLayer.end(); ++it) { - if (layerIt->show) { - (*it)->clearFlag(FLAG_DONT_RENDER); - } else { - (*it)->setFlag(FLAG_DONT_RENDER); - } - pDoc->invalObject((*it)); - } - - int iconToShow = (layerIt->show ? 0 : 1); - HTREEITEM item = mTree->GetSelectedItem(); - if (item) { - mTree->SetItemImage(item, iconToShow, iconToShow); - item = mTree->GetChildItem(item); - while (item) { - mTree->SetItemImage(item, iconToShow, iconToShow); - item = mTree->GetNextSiblingItem(item); - } - } - + updateObjectRenderFlags(&layerIt); + updateTreeImages(); //PointerTool::clearSelection(); } @@ -795,6 +1052,102 @@ void LayersList::OnMergeObject(UINT commandID) MapObject *objToMove = findObjectByUID(lastClickedObj); if (objToMove) { changeMapObjectLayer(objToMove, layerIt->layerName); + } else { + PolygonTrigger* triggerToMove = findPolygonTriggerByUID(lastClickedObj); + changePolygonTriggerLayer(triggerToMove, layerIt->layerName); + } +} + +void LayersList::OnSelectActiveLayer() +{ + AsciiString lastClickedLayer = mTree->getLastClickedLayer(); + ListLayerIt srclayerIt = mLayers.begin(); + while (srclayerIt != mLayers.end() && srclayerIt->layerName.compareNoCase(lastClickedLayer) != 0) { + ++srclayerIt; + } + + if (srclayerIt == mLayers.end()) { + return; + } + + if (srclayerIt->layerName.compareNoCase(TheActiveLayerName.c_str()) == 0) { + // No layer is selected as default. + TheActiveLayerName = AsciiString::TheEmptyString.str(); + } else { + // Select this layer to be the default as new objects and triggers are added. + TheActiveLayerName = srclayerIt->layerName.str(); + // The active layer has to be shown. + srclayerIt->show = true; + + updateObjectRenderFlags(&srclayerIt); + } + + updateTreeImages(); +} + +void LayersList::updateObjectRenderFlags(ListLayerIt *updateLayer) +{ + ListLayerIt layerIt = *updateLayer; + + ListMapObjectPtrIt it; + for (it = layerIt->objectsInLayer.begin(); it != layerIt->objectsInLayer.end(); ++it) { + if (layerIt->show) { + (*it)->clearFlag(FLAG_DONT_RENDER); + } else { + (*it)->setFlag(FLAG_DONT_RENDER); + } + + CWorldBuilderDoc *pDoc = CWorldBuilderDoc::GetActiveDoc(); + pDoc->invalObject((*it)); + } + + ListPolygonTriggerPtrIt pit; + for (pit = layerIt->polygonTriggersInLayer.begin(); pit != layerIt->polygonTriggersInLayer.end(); ++pit) { + if (layerIt->show) { + (*pit)->setShouldRender(true); + } else { + (*pit)->setShouldRender(false); + } + //pDoc->invalObject((*it)); + } +} + +void LayersList::updateTreeImages() +{ + enum { + SHOW_ICON, + HIDE_ICON, + SELECTED_ICON, + }; + + if (!mTree) { + return; + } + + + ListLayerIt layerIt; + + for (layerIt = mLayers.begin(); layerIt != mLayers.end(); layerIt++) { + + HTREEITEM layer = findTreeLayerNamed(layerIt->layerName); + int childIcon = SHOW_ICON; + + if (layerIt->layerName.compareNoCase(TheActiveLayerName.c_str()) == 0) { + mTree->SetItemImage(layer, SELECTED_ICON, SELECTED_ICON); + childIcon = SHOW_ICON; + } else if (layerIt->show == false) { + childIcon = HIDE_ICON; + mTree->SetItemImage(layer, HIDE_ICON, HIDE_ICON); + } else { + childIcon = SHOW_ICON; + mTree->SetItemImage(layer, SHOW_ICON, SHOW_ICON); + } + + HTREEITEM item = mTree->GetChildItem(layer); + while (item) { + mTree->SetItemImage(item, childIcon, childIcon); + item = mTree->GetNextSiblingItem(item); + } } } @@ -827,10 +1180,129 @@ void LayersList::OnMergeViewSelection(UINT commandID) changeMapObjectLayer(allSelectedObjects.top(), layerIt->layerName); allSelectedObjects.pop(); } + + + PolygonTrigger *polygonTrigger = PolygonTrigger::getFirstPolygonTrigger(); + + std::stack allSelectedTriggers; + while (polygonTrigger) { + if (polygonTrigger->getSelected()) { + allSelectedTriggers.push(polygonTrigger); + } + + polygonTrigger = polygonTrigger->getNext(); + } + + while (!allSelectedTriggers.empty()) { + changePolygonTriggerLayer(allSelectedTriggers.top(), layerIt->layerName); + allSelectedTriggers.pop(); + } +} + + +//WST 11/23/2002 +void LayersList::unselectAllMapObjects() +{ + MapObject *mapObject = MapObject::getFirstMapObject(); + while (mapObject) { + mapObject->setSelected(false); + mapObject = mapObject->getNext(); + } +} + +void LayersList::unselectAllPolygonTriggers() +{ + PolygonTrigger *trigger = PolygonTrigger::getFirstPolygonTrigger(); + while (trigger) { + trigger->setSelected(false); + trigger = trigger->getNext(); + } +} + + +//WST 11/23/2002 +Bool LayersList::findAndSelectMapObject(AsciiString selectedItemAsciiString) +{ + MapObject *mapObject = MapObject::getFirstMapObject(); + + while (mapObject) { + Bool dontcare; + AsciiString mapObjectName = (mapObject)->getProperties()->getAsciiString(TheKey_uniqueID, &dontcare); + + if (mapObjectName.compareNoCase(selectedItemAsciiString) == 0) { + // Found it... select this object + mapObject->setSelected(true); + return (true); + } + mapObject = mapObject->getNext(); + } + + return (false); +} + + +Bool LayersList::findAndSelectPolygonTrigger(AsciiString selectedItemAsciiString) +{ + PolygonTrigger *trigger = PolygonTrigger::getFirstPolygonTrigger(); + + while (trigger) { + const AsciiString& triggerName = trigger->getTriggerName(); + + if (triggerName.compareNoCase(selectedItemAsciiString) == 0) { + // Found it... select this object + trigger->setSelected(true); + return (true); + } + trigger = trigger->getNext(); + } + return (false); } +//WST 11/21/02 New Design team request to select objects from layer view box +void LayersList::OnSelectLayerObject() +{ + CTreeCtrl *pTree = (CTreeCtrl*) GetDlgItem(IDC_LL_TREE); + if (!pTree) { + return; + } + + HTREEITEM item = pTree->GetSelectedItem(); + if (!item) { + return; + } + + + CString selectedItemCString = pTree->GetItemText(item); + AsciiString selectedItemAsciiString(selectedItemCString.GetBuffer(0)); + + //Unselect everything on the map and get ready to find the one user wanted + unselectAllMapObjects(); + unselectAllPolygonTriggers(); + + // Lets check and see if this is a layer that user selected or individual items + ListLayerIt srcLayerIt; + if (findLayerNamed(selectedItemAsciiString, &srcLayerIt)) { + // Ok, User selected the Layer, lets select all map objects in the layer + ListMapObjectPtrIt mopIt; + for (mopIt = srcLayerIt->objectsInLayer.begin(); mopIt != srcLayerIt->objectsInLayer.end(); ++mopIt) { + (*mopIt)->setSelected(true); + } + + ListPolygonTriggerPtrIt ptpIt; + for (ptpIt = srcLayerIt->polygonTriggersInLayer.begin(); ptpIt != srcLayerIt->polygonTriggersInLayer.end(); ++ptpIt) { + (*ptpIt)->setSelected(true); + } + } + else { + // User selected individual items + if (!findAndSelectMapObject(selectedItemAsciiString)) { + findAndSelectPolygonTrigger(selectedItemAsciiString); + } + } +} + MapObject *LayersList::findObjectByUID(AsciiString objectIDToFind) { MapObject *obj = MapObject::getFirstMapObject(); @@ -849,12 +1321,30 @@ MapObject *LayersList::findObjectByUID(AsciiString objectIDToFind) return nullptr; } +PolygonTrigger* LayersList::findPolygonTriggerByUID(AsciiString triggerIDToFind) +{ + PolygonTrigger *trigger = PolygonTrigger::getFirstPolygonTrigger(); + + while (trigger) { + const AsciiString& triggerName = trigger->getTriggerName(); + + if (triggerName.compareNoCase(triggerIDToFind) == 0) { + return (trigger); + } + trigger = trigger->getNext(); + } + + return (nullptr); +} + BEGIN_MESSAGE_MAP(LayersList, CDialog) ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_LL_TREE, OnBeginEditLabel) ON_NOTIFY(TVN_ENDLABELEDIT, IDC_LL_TREE, OnEndEditLabel) + ON_COMMAND(ID_SELECTLAYEROBJECT, OnSelectLayerObject) ON_COMMAND(ID_INSERTNEWLAYER, OnNewLayer) ON_COMMAND(ID_DELETECURRENTLAYER, OnDeleteLayer) ON_COMMAND(ID_HIDECURRENTLAYER, OnHideShowLayer) + ON_COMMAND(ID_SELECTACTIVELAYER, OnSelectActiveLayer) ON_COMMAND_RANGE(ID_LAYERSLIST_MERGELAYERINTO_BEGIN, ID_LAYERSLIST_MERGELAYERINTO_END, OnMergeLayer) ON_COMMAND_RANGE(ID_LAYERSLIST_MERGEOBJECTINTO_BEGIN, ID_LAYERSLIST_MERGEOBJECTINTO_END, OnMergeObject) ON_COMMAND_RANGE(ID_LAYERSLIST_MERGEVIEWSELECTIONINTO_BEGIN, ID_LAYERSLIST_MERGEVIEWSELECTIONINTO_END, OnMergeViewSelection) @@ -864,7 +1354,9 @@ END_MESSAGE_MAP() // for purposes of linking. // TheDefaultLayerName is NOT constant, because it is okay to change it. -std::string LayersList::TheDefaultLayerName = "Default Layer"; +std::string LayersList::TheDefaultLayerName = "Default Object Layer"; std::string LayersList::TheDefaultNewLayerName = "New Layer"; -const std::string LayersList::TheUnmutableDefaultLayerName = "Default Layer"; +std::string LayersList::ThePolygonTriggerLayerName = "Default Trigger Layer"; +std::string LayersList::TheActiveLayerName; +const std::string LayersList::TheUnmutableDefaultLayerName = "Default Object Layer"; LayersList *TheLayersList = nullptr; diff --git a/Generals/Code/Tools/WorldBuilder/src/MainFrm.cpp b/Generals/Code/Tools/WorldBuilder/src/MainFrm.cpp index 26125e89382..754d8daaa1d 100644 --- a/Generals/Code/Tools/WorldBuilder/src/MainFrm.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/MainFrm.cpp @@ -32,6 +32,7 @@ #include "WorldBuilderDoc.h" #include "WorldBuilderView.h" +#include "ScriptDialog.h" ///////////////////////////////////////////////////////////////////////////// // CMainFrame @@ -71,11 +72,16 @@ CMainFrame::CMainFrame() m_hAutoSaveTimer = 0; m_autoSaving = false; m_layersList = nullptr; + m_scriptDialog = nullptr; } CMainFrame::~CMainFrame() { delete m_layersList; + m_layersList = nullptr; + + delete m_scriptDialog; + m_scriptDialog = nullptr; SaveBarState("MainFrame"); TheMainFrame = nullptr; @@ -178,6 +184,12 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) if (m_optionsPanelWidth < frameRect.Width()) m_optionsPanelWidth = frameRect.Width(); if (m_optionsPanelHeight < frameRect.Height()) m_optionsPanelHeight = frameRect.Height(); + m_rulerOptions.Create(IDD_RULER_OPTIONS, this); + m_rulerOptions.SetWindowPos(nullptr, frameRect.left, frameRect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE); + m_rulerOptions.GetWindowRect(&frameRect); + if (m_optionsPanelWidth < frameRect.Width()) m_optionsPanelWidth = frameRect.Width(); + if (m_optionsPanelHeight < frameRect.Height()) m_optionsPanelHeight = frameRect.Height(); + m_objectOptions.Create(IDD_OBJECT_OPTIONS, this); m_objectOptions.SetWindowPos(nullptr, frameRect.left, frameRect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE); m_objectOptions.GetWindowRect(&frameRect); @@ -373,6 +385,7 @@ void CMainFrame::showOptionsDialog(Int dialogID) case IDD_MAPOBJECT_PROPS: newOptions = &m_mapObjectProps; break; case IDD_ROAD_OPTIONS:newOptions = &m_roadOptions; break; case IDD_MOUND_OPTIONS:newOptions = &m_moundOptions; break; + case IDD_RULER_OPTIONS:newOptions = &m_rulerOptions; break; case IDD_FEATHER_OPTIONS:newOptions = &m_featherOptions; break; case IDD_MESHMOLD_OPTIONS:newOptions = &m_meshMoldOptions; break; case IDD_WAYPOINT_OPTIONS:newOptions = &m_waypointOptions; break; @@ -409,6 +422,22 @@ void CMainFrame::OnEditGloballightoptions() m_globalLightOptions.ShowWindow(SW_SHOWNA); } +void CMainFrame::onEditScripts() +{ + delete m_scriptDialog; + + CRect frameRect; + GetWindowRect(&frameRect); + + // Setup the Script Dialog. + // This needs to be recreated each time so that it will have the current data. + m_scriptDialog = new ScriptDialog(this); + m_scriptDialog->Create(IDD_ScriptDialog, this); + m_scriptDialog->SetWindowPos(nullptr, frameRect.left, frameRect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE); + m_scriptDialog->GetWindowRect(&frameRect); + m_scriptDialog->ShowWindow(SW_SHOWNA); +} + ///////////////////////////////////////////////////////////////////////////// // CMainFrame diagnostics @@ -496,4 +525,3 @@ void CMainFrame::handleCameraChange() { m_cameraOptions.update(); } - diff --git a/Generals/Code/Tools/WorldBuilder/src/MeshMoldOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/MeshMoldOptions.cpp index 7a04ba1cd2b..0da28fda2ee 100644 --- a/Generals/Code/Tools/WorldBuilder/src/MeshMoldOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/MeshMoldOptions.cpp @@ -101,6 +101,12 @@ BOOL MeshMoldOptions::OnInitDialog() fileBuf[i] = 0; } } + char *nameStart = fileBuf; + for (i=0; iCreate_Render_Obj(modelName.str()); diff --git a/Generals/Code/Tools/WorldBuilder/src/RampTool.cpp b/Generals/Code/Tools/WorldBuilder/src/RampTool.cpp index 572684b34c6..7bc43436e96 100644 --- a/Generals/Code/Tools/WorldBuilder/src/RampTool.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/RampTool.cpp @@ -30,6 +30,8 @@ /* Revision History: */ /* 4/19/2002 : Initial creation */ /*---------------------------------------------------------------------------*/ + + #include "StdAfx.h" #include "RampTool.h" diff --git a/Generals/Code/Tools/WorldBuilder/src/RulerOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/RulerOptions.cpp new file mode 100644 index 00000000000..99e7824a529 --- /dev/null +++ b/Generals/Code/Tools/WorldBuilder/src/RulerOptions.cpp @@ -0,0 +1,131 @@ +/* +** Command & Conquer Generals(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +// Mike Lytle +// 01/07/03 +// RulerOptions.cpp + +#include "StdAfx.h" +#include "resource.h" +#include "Lib/BaseType.h" +#include "RulerOptions.h" +#include "WorldBuilderView.h" +#include "RulerTool.h" + +RulerOptions* RulerOptions::m_staticThis = nullptr; + +///////////////////////////////////////////////////////////////////////////// +RulerOptions::RulerOptions(CWnd* pParent /*=nullptr*/) +{ + //{{AFX_DATA_INIT(RulerOptions) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + +/// Windows default stuff. +void RulerOptions::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(RulerOptions) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +/** Update the value in the edit control. */ +void RulerOptions::setWidth(Real width) +{ + CString buf; + // Multiply by 2 because we are changing from radius to diameter. + buf.Format("%f", width * 2.0f); + if (m_staticThis && !m_staticThis->m_updating) { + CWnd *pEdit = m_staticThis->GetDlgItem(IDC_RULER_WIDTH); + if (pEdit && pEdit->IsWindowEnabled()) { + pEdit->SetWindowText(buf); + } + } +} + + +/// Dialog UI initialization. +BOOL RulerOptions::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_staticThis = this; + m_updating = false; + if (RulerTool::getType() != RULER_CIRCLE) { + CWnd *pEdit = GetDlgItem(IDC_RULER_WIDTH); + if (pEdit) { + // Disable the edit box since the ruler isn't a circle. + pEdit->EnableWindow(false); + } + } else { + // Only the circle rulers use the edit box to change the size. + setWidth(RulerTool::getLength()); + } + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void RulerOptions::OnChangeWidthEdit() +{ + if (m_updating) return; + CWnd *pEdit = GetDlgItem(IDC_RULER_WIDTH); + char buffer[_MAX_PATH]; + if (pEdit) { + pEdit->GetWindowText(buffer, sizeof(buffer)); + float width; + m_updating = true; + // Pull out the length from the text. + if (1 == sscanf(buffer, "%f", &width)) { + // Change from diameter to radius. + RulerTool::setLength(width / 2.0f); + } + m_updating = false; + } +} + +void RulerOptions::OnChangeCheckRuler() +{ + if (m_updating) return; + CWnd *pCheck = GetDlgItem(IDC_CHECK_RULER); + if (pCheck) { + if (RulerTool::switchType()) { + CWnd *pEdit = GetDlgItem(IDC_RULER_WIDTH); + if (pEdit) { + // The edit box is disabled when the ruler is a line. + pEdit->EnableWindow(!pEdit->IsWindowEnabled()); + // Make sure that the length is updated. + if (pEdit->IsWindowEnabled()) { + setWidth(RulerTool::getLength()); + } + } + } + } +} + + + + +BEGIN_MESSAGE_MAP(RulerOptions, COptionsPanel) + //{{AFX_MSG_MAP(RulerOptions) + ON_EN_CHANGE(IDC_RULER_WIDTH, OnChangeWidthEdit) + ON_BN_CLICKED(IDC_CHECK_RULER, OnChangeCheckRuler) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() diff --git a/Generals/Code/Tools/WorldBuilder/src/RulerTool.cpp b/Generals/Code/Tools/WorldBuilder/src/RulerTool.cpp new file mode 100644 index 00000000000..6e0bf006024 --- /dev/null +++ b/Generals/Code/Tools/WorldBuilder/src/RulerTool.cpp @@ -0,0 +1,187 @@ +/* +** Command & Conquer Generals(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +// RulerTool.cpp +// Author: Mike Lytle, January 2003 + + +#include "StdAfx.h" +#include "resource.h" + +#include "RulerTool.h" +#include "MainFrm.h" +#include "WorldBuilderDoc.h" +#include "WorldBuilderView.h" +#include "wbview3d.h" +#include "ObjectTool.h" + + +// Saved off so that static functions can access its members. +RulerTool* RulerTool::m_staticThis = nullptr; + +/// Constructor +RulerTool::RulerTool() : +Tool(ID_RULER_TOOL, IDC_POINTER) +{ + m_downPt3d.set(0.0f, 0.0f, 0.0f); + m_rulerType = RULER_LINE; + m_View = nullptr; + m_staticThis = this; +} + +/// Destructor +RulerTool::~RulerTool() +{ +} + +// Activate. +void RulerTool::activate() +{ + Tool::activate(); + CMainFrame::GetMainFrame()->showOptionsDialog(IDD_RULER_OPTIONS); + if (m_View != nullptr) { + // Is it dangerous to assume that the pointer is still good? + m_View->doRulerFeedback(m_rulerType); + } +} + +// Deactivate. +void RulerTool::deactivate() +{ + Tool::deactivate(); + + if (m_View != nullptr) { + m_View->doRulerFeedback(RULER_NONE); + } + +} + +/** Set the cursor. */ +void RulerTool::setCursor() +{ + Tool::setCursor(); +} + + +/** Execute the tool on mouse down */ +void RulerTool::mouseDown(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldBuilderDoc *pDoc) +{ + if (m != TRACK_L) return; + + if (m_View == nullptr) { + // Save so that when we are done the view can stop drawing the rulers. + m_View = pView; + } + + Coord3D cpt; + pView->viewToDocCoords(viewPt, &cpt); + + m_downPt3d = cpt; + pView->snapPoint(&m_downPt3d); +} + +/// Left button move code. +void RulerTool::mouseMoved(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldBuilderDoc *pDoc) +{ + if (m != TRACK_L) return; + + if (m_View == nullptr) { + // Save so that when we are done the view can stop drawing the rulers. + m_View = pView; + } + + Coord3D cpt; + pView->viewToDocCoords(viewPt, &cpt, false); + + if (m_rulerType == RULER_CIRCLE) { + Coord3D pt; + pt.x = cpt.x + m_savedLength; + pt.y = cpt.y + m_savedLength; + pt.z = cpt.z; + RulerOptions::setWidth(m_savedLength); + pView->doRulerFeedback(RULER_CIRCLE); + pView->rulerFeedbackInfo(cpt, pt, m_savedLength); + pView->Invalidate(); + } else { //m_rulerType == RULER_LINE + Coord3D diff; + diff.set(cpt); + diff.sub(m_downPt3d); + m_savedLength = diff.length(); + RulerOptions::setWidth(m_savedLength); + pView->doRulerFeedback(RULER_LINE); + pView->rulerFeedbackInfo(cpt, m_downPt3d, m_savedLength); + pView->Invalidate(); + } + + pDoc->updateAllViews(); +} + +void RulerTool::setLength(Real length) +{ + if (!m_staticThis || (m_staticThis->m_rulerType != RULER_CIRCLE)) { + // This should only be called when the ruler type is a circle. + // Line rulers are always extended by the mouse. + return; + } + + m_staticThis->m_savedLength = length; + if (m_staticThis->m_View) { + m_staticThis->m_View->rulerFeedbackInfo(m_staticThis->m_downPt3d, m_staticThis->m_downPt3d, length); + m_staticThis->m_View->Invalidate(); + } + + CString str; + str.Format("Diameter (in feet): %f", length * 2.0f); + CMainFrame::GetMainFrame()->SetMessageText(str); +} + +Bool RulerTool::switchType() +{ + if (!m_staticThis) { + return (FALSE); + } + + if (m_staticThis->m_rulerType == RULER_LINE) { + m_staticThis->m_rulerType = RULER_CIRCLE; + } else { + m_staticThis->m_rulerType = RULER_LINE; + } + if (m_staticThis->m_View != nullptr) { + m_staticThis->m_View->doRulerFeedback(m_staticThis->m_rulerType); + } + + return (TRUE); +} + +int RulerTool::getType() +{ + if (!m_staticThis) { + return (RULER_NONE); + } + + return (m_staticThis->m_rulerType); +} + +Real RulerTool::getLength() +{ + if (m_staticThis) { + return m_staticThis->m_savedLength; + } + + return (0.0f); +} diff --git a/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp b/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp index 0264bf1ae37..512b192f423 100644 --- a/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/ScriptDialog.cpp @@ -42,6 +42,7 @@ #include "WaypointOptions.h" #include "Common/UnicodeString.h" + static const Int K_LOCAL_TEAMS_VERSION_1 = 1; #define SCRIPT_DIALOG_SECTION "ScriptDialog" @@ -153,6 +154,7 @@ ScriptDialog::ScriptDialog(CWnd* pParent /*=nullptr*/) : CDialog(ScriptDialog::IDD, pParent) { m_draggingTreeView = false; + m_autoUpdateWarnings = true; //{{AFX_DATA_INIT(ScriptDialog) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT @@ -182,6 +184,9 @@ BEGIN_MESSAGE_MAP(ScriptDialog, CDialog) ON_BN_CLICKED(IDC_EDIT_SCRIPT, OnEditScript) ON_BN_CLICKED(IDC_COPY_SCRIPT, OnCopyScript) ON_BN_CLICKED(IDC_DELETE, OnDelete) + ON_BN_CLICKED(IDC_VERIFY, OnVerify) + ON_BN_CLICKED(IDC_PATCH_GC, OnPatchGC) + ON_BN_CLICKED(IDC_AUTO_VERIFY, OnAutoVerify) ON_BN_CLICKED(IDC_SAVE, OnSave) ON_BN_CLICKED(IDC_LOAD, OnLoad) ON_NOTIFY(NM_DBLCLK, IDC_SCRIPT_TREE, OnDblclkScriptTree) @@ -314,7 +319,7 @@ void ScriptDialog::updateScriptWarning(Script *pScript) Int i; for (i=0; igetNumParameters(); i++) { AsciiString warning; - warning = EditParameter::getWarningText(pCondition->getParameter(i)); + warning = EditParameter::getWarningText(pCondition->getParameter(i), FALSE); if (!warning.isEmpty()) { pScript->setWarnings(true); pCondition->setWarnings(true); @@ -328,7 +333,7 @@ void ScriptDialog::updateScriptWarning(Script *pScript) Int i; for (i=0; igetNumParameters(); i++) { AsciiString warning; - warning = EditParameter::getWarningText(pAction->getParameter(i)); + warning = EditParameter::getWarningText(pAction->getParameter(i), TRUE); if (!warning.isEmpty()) { pScript->setWarnings(true); pAction->setWarnings(true); @@ -337,9 +342,42 @@ void ScriptDialog::updateScriptWarning(Script *pScript) } } +void ScriptDialog::OnPatchGC() +{ + checkParametersForGC(); + updateIcons(TVI_ROOT); +/* //Put up a dialog asking for search/replace parameters instead of hard-coded GC_ prefix. + ReplaceParameter editDlg(); + if (IDOK==editDlg.DoModal()) + { + + }*/ +} + +/**Force a pass over all the scripts to make sure no warnings. I moved this +to user control because this function is VERY slow. 7-15-03 -MW*/ +void ScriptDialog::OnVerify() +{ + updateWarnings(true); //force an update of warnings + updateIcons(TVI_ROOT); +} + +void ScriptDialog::OnAutoVerify() +{ + CButton *pButton = (CButton*)GetDlgItem(IDC_AUTO_VERIFY); + m_autoUpdateWarnings=(pButton->GetCheck()==1); + ::AfxGetApp()->WriteProfileInt(SCRIPT_DIALOG_SECTION, "AutoVerifyScripts", m_autoUpdateWarnings?1:0); + //if user wants to check warnings manually, enable the verify button + CWnd *pWnd = GetDlgItem(IDC_VERIFY); + pWnd->EnableWindow(!m_autoUpdateWarnings); +} + /** Updates the warning flags in the scripts, script groups & script conditions & actions. */ -void ScriptDialog::updateWarnings() +void ScriptDialog::updateWarnings(Bool forceUpdate) { + if (m_staticThis && m_staticThis->m_autoUpdateWarnings == false && forceUpdate == false) + return; //user has disabled warnings to speed up the script editor + SidesList *sidesListP = TheSidesList; Int i; if (m_staticThis) sidesListP = &m_staticThis->m_sides; @@ -362,10 +400,124 @@ void ScriptDialog::updateWarnings() } } +extern AsciiString ConvertToNonGCName(AsciiString name, Bool checkTemplate=true); + +void ScriptDialog::patchScriptParametersForGC(Script *pScript) +{ + AsciiString swapString; + pScript->setWarnings(false); + OrCondition *pOr; + for (pOr= pScript->getOrCondition(); pOr; pOr = pOr->getNextOrCondition()) { + Condition *pCondition; + for (pCondition = pOr->getFirstAndCondition(); pCondition; pCondition = pCondition->getNext()) { + pCondition->setWarnings(false); + Int i; + for (i=0; igetNumParameters(); i++) { + AsciiString warning; + Parameter *pParm = pCondition->getParameter(i); + warning = EditParameter::getWarningText(pParm, FALSE); + if (!warning.isEmpty()) { + if (pParm->getParameterType() == Parameter::OBJECT_TYPE) + { //see if removing the GC prefix fixes this warning: + AsciiString uiString = pParm->getString(); + if (uiString.isEmpty()) + uiString = "???"; + if (uiString.startsWith("GC_")) + { swapString = ConvertToNonGCName(uiString, false); + pParm->friend_setString(swapString); + warning = EditParameter::getWarningText(pParm, FALSE); + if (!warning.isEmpty()) + { //Removing GC prefix didn't help, so restore original + pParm->friend_setString(uiString); + } + else + continue; //warning was fixed so leave swapped parameter. + } + } + pScript->setWarnings(true); + pCondition->setWarnings(true); + } + } + } + } + ScriptAction *pAction; + for (pAction = pScript->getAction(); pAction; pAction = pAction->getNext()) { + pAction->setWarnings(false); + Int i; + for (i=0; igetNumParameters(); i++) { + AsciiString warning; + Parameter *pParm=pAction->getParameter(i); + warning = EditParameter::getWarningText(pParm, TRUE); + if (!warning.isEmpty()) { + if (pParm->getParameterType() == Parameter::OBJECT_TYPE) + { //see if removing the GC prefix fixes this warning: + AsciiString uiString = pParm->getString(); + if (uiString.isEmpty()) + uiString = "???"; + if (uiString.startsWith("GC_")) + { swapString = ConvertToNonGCName(uiString,false); + pParm->friend_setString(swapString); + warning = EditParameter::getWarningText(pParm, FALSE); + if (!warning.isEmpty()) + { //Removing GC prefix didn't help, so restore original + pParm->friend_setString(uiString); + } + else + continue; //warning was fixed so leave swapped parameter. + } + } + pScript->setWarnings(true); + pAction->setWarnings(true); + } + } + } +} + +/*Checks all script parameters for obsolete values (example: mission disk using GC_ templates)*/ +void ScriptDialog::checkParametersForGC() +{ + SidesList *sidesListP = TheSidesList; + Int i; + if (m_staticThis) sidesListP = &m_staticThis->m_sides; + for (i=0; igetNumSides(); i++) { + ScriptList *pSL = sidesListP->getSideInfo(i)->getScriptList(); + Script *pScr; + for (pScr = pSL->getScript(); pScr; pScr=pScr->getNext()) { + updateScriptWarning(pScr); + if (pScr->hasWarnings()) + { //check if this is using invalid GC parameters + patchScriptParametersForGC(pScr); + } + } + ScriptGroup *pGroup; + for (pGroup = pSL->getScriptGroup(); pGroup; pGroup=pGroup->getNext()) { + pGroup->setWarnings(false); + for (pScr = pGroup->getScript(); pScr; pScr=pScr->getNext()) { + updateScriptWarning(pScr); + if (pScr->hasWarnings()) { + //check if this is using invalid GC parameters. + patchScriptParametersForGC(pScr); + if (pScr->hasWarnings()) //patching may have removed warning + pGroup->setWarnings(true); + } + } + } + } +} + BOOL ScriptDialog::OnInitDialog() { CDialog::OnInitDialog(); + m_autoUpdateWarnings=::AfxGetApp()->GetProfileInt(SCRIPT_DIALOG_SECTION, "AutoVerifyScripts", 1); + + CButton *pButton = (CButton*)GetDlgItem(IDC_AUTO_VERIFY); + pButton->SetCheck(m_autoUpdateWarnings ? 1:0); + + //if user wants to check warnings manually, enable the verify button + CWnd *pWnd = GetDlgItem(IDC_VERIFY); + pWnd->EnableWindow(!m_autoUpdateWarnings); + m_staticThis = this; CTreeCtrl *pTree = (CTreeCtrl*)GetDlgItem(IDC_SCRIPT_TREE); @@ -388,7 +540,7 @@ BOOL ScriptDialog::OnInitDialog() m_sides = *TheSidesList; EditParameter::setCurSidesList(&m_sides); Int i; - updateWarnings(); + updateWarnings(true); if (pTree) { m_imageList.Create(IDB_FOLDERSCRIPT, 16, 2, ILC_COLOR4); pTree->SetImageList(&m_imageList, TVSIL_STATE); @@ -1100,6 +1252,7 @@ void ScriptDialog::scanForWaypointsAndTeams(Script *pScript, Bool doUnits, Bool } #define K_PLAYERS_NAMES_FOR_SCRIPTS_VERSION_1 1 +#define K_PLAYERS_NAMES_FOR_SCRIPTS_VERSION_2 2 /** Write out selected scripts, and possibly waypoints, trigger areas & teams. */ void ScriptDialog::OnSave() @@ -1108,6 +1261,7 @@ void ScriptDialog::OnSave() Bool doTriggerAreas = true; Bool doUnits = true; Bool doAllScripts = true; + Bool doSides = true; Int i; ExportScriptsOptions optionsDlg; @@ -1118,6 +1272,7 @@ void ScriptDialog::OnSave() doUnits = optionsDlg.getDoUnits(); doTriggerAreas = optionsDlg.getDoTriggers(); doAllScripts = optionsDlg.getDoAllScripts(); + doSides = optionsDlg.getDoSides(); Script *pScript = getCurScript(); ScriptGroup *pGroup = getCurGroup(); @@ -1211,12 +1366,19 @@ void ScriptDialog::OnSave() ScriptList::WriteScriptsDataChunk(chunkWriter, scripts, numScriptLists); /***************Players DATA ***************/ - chunkWriter.openDataChunk("ScriptsPlayers", K_PLAYERS_NAMES_FOR_SCRIPTS_VERSION_1); - if (doAllScripts) { + chunkWriter.openDataChunk("ScriptsPlayers", K_PLAYERS_NAMES_FOR_SCRIPTS_VERSION_2); + chunkWriter.writeInt(doSides); + if (doAllScripts || doSides) { chunkWriter.writeInt(m_sides.getNumSides()); for (i=0; igetDict()->getAsciiString(TheKey_playerName); chunkWriter.writeAsciiString(name); + + if (doSides) { + // The user has requested that the sides get exported. + chunkWriter.writeDict(*m_sides.getSideInfo(i)->getDict()); + } + } } else { chunkWriter.writeInt(1); @@ -1410,6 +1572,7 @@ void ScriptDialog::OnLoad() } else { Int j; for (j=0; jgetDict()->getAsciiString(TheKey_playerName); if (name == m_readPlayerNames[j]) { curSide = j; @@ -1455,13 +1618,21 @@ void ScriptDialog::OnLoad() scripts[i]->discard(); /* Frees the script list, but none of it's children, as they have been copied into the current scripts. */ scripts[i] = nullptr; - reloadPlayer(curSide, pSL); + //reloadPlayer(curSide, pSL); } else { deleteInstance(scripts[i]); scripts[i] = nullptr; } } + for (i = 0; i < m_sides.getNumSides(); i++) { + // Make sure that the dialog tree is updated. + ScriptList *pSL = m_sides.getSideInfo(i)->getScriptList(); + reloadPlayer(i, pSL); + updateIcons(TVI_ROOT); + } + + } catch(...) { DEBUG_CRASH(("threw exception in ScriptDialog::OnLoad")); } @@ -1607,15 +1778,19 @@ Bool ScriptDialog::ParseTeamsDataChunk(DataChunkInput &file, DataChunkInfo *info TeamsInfo ti; ti.init(&teamDict); CFixTeamOwnerDialog fix(&ti, &pThis->m_sides); + bool nameSet = false; if (fix.DoModal() == IDOK) { if (fix.pickedValidTeam()) { teamDict.setAsciiString(TheKey_teamOwner, fix.getSelectedOwner()); + nameSet = true; } } - AsciiString neutralPlayerName; // neutral player name is empty string - // player doesn't exist, so add it to the neutral player. - teamDict.setAsciiString(TheKey_teamOwner, neutralPlayerName); + if (nameSet == false) { + AsciiString neutralPlayerName; // neutral player name is empty string + // player doesn't exist, so add it to the neutral player. + teamDict.setAsciiString(TheKey_teamOwner, neutralPlayerName); + } pThis->m_sides.addTeam(&teamDict); } } @@ -1632,11 +1807,38 @@ Bool ScriptDialog::ParseTeamsDataChunk(DataChunkInput &file, DataChunkInfo *info Bool ScriptDialog::ParsePlayersDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData) { ScriptDialog *pThis = (ScriptDialog *)userData; + Int readDicts = 0; + if (info->version >= K_PLAYERS_NAMES_FOR_SCRIPTS_VERSION_2) { + readDicts = file.readInt(); + } Int numNames = file.readInt(); Int i; for (i=0; i=MAX_PLAYER_COUNT) break; pThis->m_readPlayerNames[i] = file.readAsciiString(); + if (readDicts) { + Dict sideDict = file.readDict(); + bool nameFound = false; + for (Int j=0; j < pThis->m_sides.getNumSides(); j++) { + AsciiString name = pThis->m_sides.getSideInfo(j)->getDict()->getAsciiString(TheKey_playerName); + + if (name == pThis->m_readPlayerNames[i]) { + // The side already exists so don't add it or overwrite the old data. + nameFound = true; + break; + } + } + if (nameFound == false) { + // This side doesn't currently exist, so add it. + pThis->m_sides.addSide(&sideDict); + ScriptList* pList = newInstance(ScriptList); + SidesInfo* sides = pThis->m_sides.findSideInfo(pThis->m_readPlayerNames[i]); + // A script list must be created. + sides->setScriptList(pList); + // Update the dialog. + pThis->addPlayer(i); + } + } } DEBUG_ASSERTCRASH(file.atEndOfChunk(), ("Unexpected data left over.")); return true; diff --git a/Generals/Code/Tools/WorldBuilder/src/SplashScreen.cpp b/Generals/Code/Tools/WorldBuilder/src/SplashScreen.cpp index 8f139382d02..50ff5910398 100644 --- a/Generals/Code/Tools/WorldBuilder/src/SplashScreen.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/SplashScreen.cpp @@ -16,6 +16,7 @@ ** along with this program. If not, see . */ + #include "StdAfx.h" #include "SplashScreen.h" diff --git a/Generals/Code/Tools/WorldBuilder/src/TeamGeneric.cpp b/Generals/Code/Tools/WorldBuilder/src/TeamGeneric.cpp index 76ae9a5c0f4..338bcb6ed5b 100644 --- a/Generals/Code/Tools/WorldBuilder/src/TeamGeneric.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/TeamGeneric.cpp @@ -16,6 +16,7 @@ ** along with this program. If not, see . */ + #include "StdAfx.h" #include "resource.h" diff --git a/Generals/Code/Tools/WorldBuilder/src/TeamObjectProperties.cpp b/Generals/Code/Tools/WorldBuilder/src/TeamObjectProperties.cpp new file mode 100644 index 00000000000..007b99cd2c2 --- /dev/null +++ b/Generals/Code/Tools/WorldBuilder/src/TeamObjectProperties.cpp @@ -0,0 +1,684 @@ +/* +** Command & Conquer Generals(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +// TeamObjectProperties.cpp +// Mike Lytle +// January, 2003 +// (c) Electronic Arts 2003 + +#include "StdAfx.h" +#include "TeamObjectProperties.h" +#include "Common/MapObject.h" +#include "Common/WellKnownKeys.h" + + +///////////////////////////////////////////////////////////////////////////// +// TeamObjectProperties dialog + +TeamObjectProperties::TeamObjectProperties(Dict* dictToEdit) + : CPropertyPage(TeamObjectProperties::IDD), + m_dictToEdit(dictToEdit) +{ + //{{AFX_DATA_INIT(TeamObjectProperties) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + +TeamObjectProperties::~TeamObjectProperties() +{ +} + +void TeamObjectProperties::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(TeamObjectProperties) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + +#if 0 +BEGIN_MESSAGE_MAP(TeamObjectProperties, CPropertyPage) + //{{AFX_MSG_MAP(TeamObjectProperties) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_StartingHealth, _HealthToDict) + ON_CBN_SELENDOK(IDC_MAPOBJECT_HitPoints, _HPsToDict) + ON_CBN_KILLFOCUS(IDC_MAPOBJECT_HitPoints, _HPsToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Enabled, _EnabledToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Indestructible, _IndestructibleToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Unsellable, _UnsellableToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Powered, _PoweredToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Aggressiveness, _AggressivenessToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_VisionDistance, _VisibilityToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_ShroudClearingDistance, _ShroudClearingDistanceToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Veterancy, _VeterancyToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_RecruitableAI, _RecruitableAIToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Selectable, _SelectableToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Weather, _WeatherToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Time, _TimeToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_StoppingDistance, _StoppingDistanceToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_StartingHealthEdit, _HealthToDict) + ON_BN_CLICKED(IDC_UPDATE_TEAM_MEMBERS, _UpdateTeamMembers) + + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// TeamObjectProperties message handlers + +BOOL TeamObjectProperties::OnInitDialog() +{ + CDialog::OnInitDialog(); + updateTheUI(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void TeamObjectProperties::OnOK() +{ + _PropertiesToDict(); +} + +void TeamObjectProperties::updateTheUI() +{ + _DictToHealth(); + _DictToHPs(); + _DictToEnabled(); + _DictToDestructible(); + _DictToPowered(); + _DictToUnsellable(); + _DictToAggressiveness(); + _DictToVisibilityRange(); + _DictToVeterancy(); + _DictToWeather(); + _DictToTime(); + _DictToShroudClearingDistance(); + _DictToRecruitableAI(); + _DictToSelectable(); + _DictToStoppingDistance(); +} + +void TeamObjectProperties::_DictToHealth() +{ + Int value = 100; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_teamObjectInitialHealth, &exists); + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_StartingHealth); + CWnd* pItem2 = GetDlgItem(IDC_MAPOBJECT_StartingHealthEdit); + if (pItem && pItem2) { + if (value == 0) { + pItem->SelectString(-1, "0%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else if (value == 25) { + pItem->SelectString(-1, "25%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else if (value == 50) { + pItem->SelectString(-1, "50%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else if (value == 75) { + pItem->SelectString(-1, "75%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else if (value == 100) { + pItem->SelectString(-1, "100%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else { + pItem->SelectString(-1, "Other"); + static char buff[12]; + snprintf(buff, ARRAY_SIZE(buff), "%d", value); + pItem2->SetWindowText(buff); + pItem2->EnableWindow(TRUE); + } + } +} + +void TeamObjectProperties::_DictToHPs() +{ + Int value = -1; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_teamObjectMaxHPs, &exists); + if (!exists) + value = -1; + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_HitPoints); + pItem->ResetContent(); + CString str; + str.Format("Default For Unit"); + pItem->InsertString(-1, str); + + if (value != -1) { + str.Format("%d", value); + pItem->InsertString(-1, str); + pItem->SetCurSel(1); + } else { + pItem->SetCurSel(0); + } +} + +void TeamObjectProperties::_DictToEnabled() +{ + Bool enabled = true; + Bool exists; + if (m_dictToEdit) { + enabled = m_dictToEdit->getBool(TheKey_teamObjectEnabled, &exists); + } + + CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_Enabled); + if (pItem) { + pItem->SetCheck(enabled); + } +} + +void TeamObjectProperties::_DictToDestructible() +{ + Bool destructible = true; + Bool exists; + if (m_dictToEdit) { + destructible = m_dictToEdit->getBool(TheKey_teamObjectIndestructible, &exists); + } + + CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_Indestructible); + if (pItem) { + pItem->SetCheck(destructible); + } +} + +void TeamObjectProperties::_DictToUnsellable() +{ + Bool unsellable = false; + Bool exists; + if (m_dictToEdit) { + unsellable = m_dictToEdit->getBool(TheKey_teamObjectUnsellable, &exists); + } + + CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_Unsellable); + if (pItem) { + pItem->SetCheck(unsellable); + } +} + +void TeamObjectProperties::_DictToPowered() +{ + Bool powered = true; + Bool exists; + if (m_dictToEdit) { + powered = m_dictToEdit->getBool(TheKey_teamObjectPowered, &exists); + } + + CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_Powered); + if (pItem) { + pItem->SetCheck(powered); + } + +} + +void TeamObjectProperties::_DictToAggressiveness() +{ + Int value = 0; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_teamObjectAggressiveness, &exists); + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Aggressiveness); + if (pItem) { + if (value == -2) { + pItem->SelectString(-1, "Sleep"); + } else if (value == -1) { + pItem->SelectString(-1, "Passive"); + } else if (value == 0) { + pItem->SelectString(-1, "Normal"); + } else if (value == 1) { + pItem->SelectString(-1, "Alert"); + } else if (value == 2) { + pItem->SelectString(-1, "Aggressive"); + } + } +} + +void TeamObjectProperties::_DictToVisibilityRange() +{ + Int distance = 0; + Bool exists; + if (m_dictToEdit) { + distance = m_dictToEdit->getInt(TheKey_teamObjectVisualRange, &exists); + } + + CWnd* pItem = GetDlgItem(IDC_MAPOBJECT_VisionDistance); + if (pItem) { + static char buff[12]; + snprintf(buff, ARRAY_SIZE(buff), "%d", distance); + if (distance == 0) { + pItem->SetWindowText(""); + } else { + pItem->SetWindowText(buff); + } + } +} + +void TeamObjectProperties::_DictToVeterancy() +{ + Int value = 0; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_teamObjectVeterancy, &exists); + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Veterancy); + if (pItem) { + pItem->SetCurSel(value); + } +} + +void TeamObjectProperties::_DictToWeather() +{ + Int value = 0; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_teamObjectWeather, &exists); + if (!exists) + value = 0; + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Weather); + pItem->SetCurSel(value); +} + +void TeamObjectProperties::_DictToTime() +{ + Int value = 0; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_teamObjectTime, &exists); + if (!exists) + value = 0; + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Time); + pItem->SetCurSel(value); +} + +void TeamObjectProperties::_DictToShroudClearingDistance() +{ + Int distance = 0; + Bool exists; + if (m_dictToEdit) { + distance = m_dictToEdit->getInt(TheKey_teamObjectShroudClearingDistance, &exists); + } + + CWnd* pItem = GetDlgItem(IDC_MAPOBJECT_ShroudClearingDistance); + if (pItem) { + static char buff[12]; + snprintf(buff, ARRAY_SIZE(buff), "%d", distance); + if (distance == 0) { + pItem->SetWindowText(""); + } else { + pItem->SetWindowText(buff); + } + } +} + +void TeamObjectProperties::_DictToRecruitableAI() +{ + Bool recruitableAI = true; + Bool exists; + if (m_dictToEdit) { + recruitableAI = m_dictToEdit->getBool(TheKey_teamObjectRecruitableAI, &exists); + } + + CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_RecruitableAI); + if (pItem) { + pItem->SetCheck(recruitableAI); + } +} + +void TeamObjectProperties::_DictToSelectable() +{ + Bool selectable = true; + Bool exists; + if (m_dictToEdit) { + selectable = m_dictToEdit->getBool(TheKey_teamObjectSelectable, &exists); + } + + CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_Selectable); + if (pItem) { + pItem->SetCheck(selectable); + } +} + +void TeamObjectProperties::_DictToStoppingDistance() +{ + Real stoppingDistance = 1.0f; + Bool exists = false; + if (m_dictToEdit) { + stoppingDistance = m_dictToEdit->getReal(TheKey_teamObjectStoppingDistance, &exists); + } + + CWnd* pItem = GetDlgItem(IDC_MAPOBJECT_StoppingDistance); + if (pItem) { + static char buff[64]; + sprintf(buff, ARRAY_SIZE(buff), "%g", stoppingDistance); + if (stoppingDistance == 0) { + pItem->SetWindowText(""); + } else { + pItem->SetWindowText(buff); + } + } +} + +void TeamObjectProperties::_HealthToDict() +{ + Int value; + static char buf[1024]; + + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_StartingHealth); + owner->GetWindowText(buf, sizeof(buf)-2); + if (strcmp(buf, "Dead") == 0) { + value = 0; + } else if (strcmp(buf, "25%") == 0) { + value = 25; + } else if (strcmp(buf, "50%") == 0) { + value = 50; + } else if (strcmp(buf, "75%") == 0) { + value = 75; + } else if (strcmp(buf, "100%") == 0) { + value = 100; + } else if (strcmp(buf, "Other") == 0) { + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_StartingHealthEdit); + edit->EnableWindow(TRUE); + CString cstr; + edit->GetWindowText(cstr); + if (cstr.IsEmpty()) { + return; + } + value = atoi(cstr.GetBuffer(0)); + } + + m_dictToEdit->setInt(TheKey_teamObjectInitialHealth, value); +} + +void TeamObjectProperties::_EnabledToDict() +{ + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Enabled); + Bool isChecked = (owner->GetCheck() != 0); + + m_dictToEdit->setBool(TheKey_teamObjectEnabled, isChecked); +} + + +void TeamObjectProperties::_IndestructibleToDict() +{ + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Indestructible); + Bool isChecked = (owner->GetCheck() != 0); + + m_dictToEdit->setBool(TheKey_teamObjectIndestructible, isChecked); +} + +void TeamObjectProperties::_UnsellableToDict() +{ + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Unsellable); + Bool isChecked = (owner->GetCheck() != 0); + + m_dictToEdit->setBool(TheKey_teamObjectUnsellable, isChecked); +} + +void TeamObjectProperties::_PoweredToDict() +{ + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Powered); + Bool isChecked = (owner->GetCheck() != 0); + + m_dictToEdit->setBool(TheKey_teamObjectPowered, isChecked); +} + +void TeamObjectProperties::_AggressivenessToDict() +{ + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Aggressiveness); + static char buf[1024]; + owner->GetWindowText(buf, sizeof(buf)-2); + int value = 0; + + if (strcmp(buf, "Sleep") == 0) { + value = -2; + } else if (strcmp(buf, "Passive") == 0) { + value = -1; + } else if (strcmp(buf, "Normal") == 0) { + value = 0; + } else if (strcmp(buf, "Alert") == 0) { + value = 1; + } else if (strcmp(buf, "Aggressive") == 0) { + value = 2; + } + + m_dictToEdit->setInt(TheKey_teamObjectAggressiveness, value); +} + +void TeamObjectProperties::_VisibilityToDict() +{ + int value = -1; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_VisionDistance); + edit->EnableWindow(TRUE); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + value = atoi(cstr.GetBuffer(0)); + } + + if (value != -1) { + m_dictToEdit->setInt(TheKey_teamObjectVisualRange, value); + } +} + +void TeamObjectProperties::_VeterancyToDict() +{ + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Veterancy); + static char buf[1024]; + int curSel = owner->GetCurSel(); + int value = 0; + if (curSel >= 0) { + value=curSel; + } + + m_dictToEdit->setInt(TheKey_teamObjectVeterancy, value); +} + +void TeamObjectProperties::_WeatherToDict() +{ + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Weather); + static char buf[1024]; + int curSel = owner->GetCurSel(); + + m_dictToEdit->setInt(TheKey_teamObjectWeather, curSel); +} + +void TeamObjectProperties::_TimeToDict() +{ + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Time); + static char buf[1024]; + int curSel = owner->GetCurSel(); + + m_dictToEdit->setInt(TheKey_teamObjectTime, curSel); +} + +void TeamObjectProperties::_ShroudClearingDistanceToDict() +{ + int value = -1; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ShroudClearingDistance); + edit->EnableWindow(TRUE); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + value = atoi(cstr.GetBuffer(0)); + } + + if (value != -1) { + m_dictToEdit->setInt(TheKey_teamObjectShroudClearingDistance, value); + } +} + +void TeamObjectProperties::_RecruitableAIToDict() +{ + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_RecruitableAI); + Bool isChecked = (owner->GetCheck() != 0); + + m_dictToEdit->setBool(TheKey_teamObjectRecruitableAI, isChecked); +} + +void TeamObjectProperties::_SelectableToDict() +{ + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Selectable); + Bool isChecked = (owner->GetCheck() != 0); + + m_dictToEdit->setBool(TheKey_teamObjectSelectable, isChecked); +} + +void TeamObjectProperties::_HPsToDict() +{ + Int value; + static char buf[1024]; + + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_HitPoints); + owner->GetWindowText(buf, sizeof(buf)-2); + value = atoi(buf); + if (value == 0) + value = -1; + + m_dictToEdit->setInt(TheKey_teamObjectMaxHPs, value); +} + +void TeamObjectProperties::_StoppingDistanceToDict() +{ + Real value; + static char buf[1024]; + + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_StoppingDistance); + CString cstr; + edit->GetWindowText(cstr); + if (cstr.IsEmpty()) { + return; + } + value = atof(cstr.GetBuffer(0)); + + m_dictToEdit->setReal(TheKey_teamObjectStoppingDistance, value); +} + +void TeamObjectProperties::_UpdateTeamMembers() +{ + CString msg; + msg.Format("Are you sure you want to change the team members?"); + if (::AfxMessageBox(msg, MB_YESNO) == IDNO) { + return; + } + + AsciiString teamName = m_dictToEdit->getAsciiString(TheKey_teamName); + + MapObject *pObj; + for (pObj=MapObject::getFirstMapObject(); pObj; pObj=pObj->getNext()) { + Dict* objectDict = pObj->getProperties(); + DEBUG_ASSERTCRASH(objectDict, ("objectDict shouldn't be null")); + + AsciiString objectsTeam = objectDict->getAsciiString(TheKey_originalOwner); + + if (teamName == objectsTeam) { + DEBUG_ASSERTCRASH(m_dictToEdit, ("m_dictToEdit shouldn't be null")); + Bool exists; + + Int value = m_dictToEdit->getInt(TheKey_teamObjectInitialHealth, &exists); + objectDict->setInt(TheKey_objectInitialHealth, value); + + value = m_dictToEdit->getInt(TheKey_teamObjectMaxHPs, &exists); + objectDict->setInt(TheKey_objectMaxHPs, value); + + Bool enabled = m_dictToEdit->getBool(TheKey_teamObjectEnabled, &exists); + objectDict->setBool(TheKey_objectEnabled, enabled); + + enabled = m_dictToEdit->getBool(TheKey_teamObjectIndestructible, &exists); + objectDict->setBool(TheKey_objectIndestructible, enabled); + + enabled = m_dictToEdit->getBool(TheKey_teamObjectUnsellable, &exists); + objectDict->setBool(TheKey_objectUnsellable, enabled); + + enabled = m_dictToEdit->getBool(TheKey_teamObjectPowered, &exists); + objectDict->setBool(TheKey_objectPowered, enabled); + + value = m_dictToEdit->getInt(TheKey_teamObjectAggressiveness, &exists); + objectDict->setInt(TheKey_objectAggressiveness, value); + + value = m_dictToEdit->getInt(TheKey_teamObjectVisualRange, &exists); + objectDict->setInt(TheKey_objectVisualRange, value); + + value = m_dictToEdit->getInt(TheKey_teamObjectVeterancy, &exists); + objectDict->setInt(TheKey_objectVeterancy, value); + + value = m_dictToEdit->getInt(TheKey_teamObjectWeather, &exists); + objectDict->setInt(TheKey_objectWeather, value); + + value = m_dictToEdit->getInt(TheKey_teamObjectTime, &exists); + objectDict->setInt(TheKey_objectTime, value); + + value = m_dictToEdit->getInt(TheKey_teamObjectShroudClearingDistance, &exists); + objectDict->setInt(TheKey_objectShroudClearingDistance, value); + + enabled = m_dictToEdit->getBool(TheKey_teamObjectRecruitableAI, &exists); + objectDict->setBool(TheKey_objectRecruitableAI, enabled); + + enabled = m_dictToEdit->getBool(TheKey_teamObjectSelectable, &exists); + objectDict->setBool(TheKey_objectSelectable, enabled); + + Real dist = m_dictToEdit->getReal(TheKey_teamObjectStoppingDistance, &exists); + objectDict->setReal(TheKey_objectStoppingDistance, dist); + + } + } +} + + +void TeamObjectProperties::_PropertiesToDict() +{ + // Make sure that the attributes are in the dictionary. + _HealthToDict(); + _HPsToDict(); + _EnabledToDict(); + _IndestructibleToDict(); + _UnsellableToDict(); + _PoweredToDict(); + _AggressivenessToDict(); + _VisibilityToDict(); + _ShroudClearingDistanceToDict(); + _VeterancyToDict(); + _RecruitableAIToDict(); + _SelectableToDict(); + _WeatherToDict(); + _TimeToDict(); + _StoppingDistanceToDict(); + _HealthToDict(); +} + +#endif + +BOOL TeamObjectProperties::OnCommand(WPARAM wParam, LPARAM lParam) +{ + return CPropertyPage::OnCommand(wParam, lParam); +} diff --git a/Generals/Code/Tools/WorldBuilder/src/TileTool.cpp b/Generals/Code/Tools/WorldBuilder/src/TileTool.cpp index f9d9aa9217a..747e0ec4e3d 100644 --- a/Generals/Code/Tools/WorldBuilder/src/TileTool.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/TileTool.cpp @@ -83,11 +83,12 @@ void TileTool::mouseDown(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldBu void TileTool::mouseUp(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldBuilderDoc *pDoc) { if (m != TRACK_L && m != TRACK_R) return; - +#define DONT_DO_FULL_UPDATE +#ifdef DO_FULL_UPDATE m_htMapEditCopy->optimizeTiles(); // force to optimize tileset IRegion2D partialRange = {0,0,0,0}; pDoc->updateHeightMap(m_htMapEditCopy, false, partialRange); - +#endif WBDocUndoable *pUndo = new WBDocUndoable(pDoc, m_htMapEditCopy); pDoc->AddAndDoUndoable(pUndo); REF_PTR_RELEASE(pUndo); // belongs to pDoc now. @@ -166,6 +167,9 @@ void TileTool::mouseMoved(TTrackingMode m, CPoint viewPt, WbView* pView, CWorldB partialRange.hi.x = totalMaxX+1; partialRange.lo.y = totalMinY; partialRange.hi.y = totalMaxY+1; + if (fullUpdate) { + m_htMapEditCopy->optimizeTiles(); // force to optimize tileset + } pDoc->updateHeightMap(m_htMapEditCopy, !fullUpdate, partialRange); } pView->UpdateWindow(); diff --git a/Generals/Code/Tools/WorldBuilder/src/WBHeightMap.cpp b/Generals/Code/Tools/WorldBuilder/src/WBHeightMap.cpp index faa11da19ad..c567f1909e5 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WBHeightMap.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WBHeightMap.cpp @@ -45,7 +45,6 @@ #include #include - //----------------------------------------------------------------------------- // Private Data //----------------------------------------------------------------------------- @@ -68,9 +67,11 @@ void WBHeightMap::setFlattenHeights(Bool flat) { if (m_flattenHeights != flat) { m_flattenHeights = flat; +#if !USE_FLAT_HEIGHT_MAP m_originX = 0; m_originY = 0; updateBlock(0, 0, m_x-1, m_y-1, m_map, nullptr); +#endif } } @@ -83,6 +84,7 @@ void WBHeightMap::setFlattenHeights(Bool flat) /** Flattens the terrain for the top down view.. */ //============================================================================= void WBHeightMap::flattenHeights() { +#if !USE_FLAT_HEIGHT_MAP Real theZ = THE_Z; Int i, j; for (j=0; jhasRGBDataForWidth(2*width)) { - Int j; - UnsignedByte *pSrcData = pSrc->getRGBDataForWidth(2*width); - Int xOffset=0; - Int yOffset=0; - if (tileNdx & 1) xOffset = width; - if (tileNdx & 2) yOffset = width; - for (j=0; jhasRGBDataForWidth(2 * width)) { + UnsignedByte *pSrcData = pSrc->getRGBDataForWidth(2 * width); + Int xOffset = (tileNdx & 1) ? width : 0; + Int yOffset = (tileNdx & 2) ? width : 0; + for (Int j = 0; j < width; ++j) { + UnsignedByte *pDestData = buffer + j * width * TILE_BYTES_PER_PIXEL; + UnsignedByte *pSrcRow = pSrcData + (j + yOffset) * width * TILE_BYTES_PER_PIXEL * 2; + pSrcRow += xOffset * TILE_BYTES_PER_PIXEL; + memcpy(pDestData, pSrcRow, width * TILE_BYTES_PER_PIXEL); + } + return true; } - return(false); + return false; } - - UnsignedByte * WorldHeightMapEdit::getPointerToClassTileData(Int texClass) { TileData *pSrc = nullptr; @@ -633,7 +624,11 @@ void WorldHeightMapEdit::saveToFile(DataChunkOutput &chunkWriter) chunkWriter.closeDataChunk(); /***************BLEND TILE DATA ***************/ +#if RTS_GENERALS chunkWriter.openDataChunk("BlendTileData", K_BLEND_TILE_VERSION_7); +#else + chunkWriter.openDataChunk("BlendTileData", K_BLEND_TILE_VERSION_8); +#endif chunkWriter.writeInt(m_dataSize); chunkWriter.writeArrayOfBytes((char*)m_tileNdxes, m_dataSize*sizeof(Short)); chunkWriter.writeArrayOfBytes((char*)m_blendTileNdxes, m_dataSize*sizeof(Short)); @@ -1130,7 +1125,7 @@ void WorldHeightMapEdit::blendSpecificTiles(Int xIndex, Int yIndex, Int srcXInde blendInfo.customBlendEdgeClass = edgeClass; //Check if there is already a blend tile at the destination and record its flip state. - //We need to know this so that we don't accidentally apply a third blend layer with with + //We need to know this so that we don't accidentally apply a third blend layer with //a different flip and introduce z-fighting over this tile. Bool baseNeedsFlip = false; UnsignedByte baseIsDiagonal = 0; @@ -1200,7 +1195,12 @@ void WorldHeightMapEdit::blendSpecificTiles(Int xIndex, Int yIndex, Int srcXInde //force the primary layer to flip if the extra blend layer needs flip. //we only do this on vertical/horizontal base blends because they work in either flip cases. if (flipped && !baseIsDiagonal) - m_blendedTiles[m_blendTileNdxes[ndx]].inverted |= FLIPPED_MASK; + { //Find a new tile so as not to affect other cells using the base one. + TBlendTileInfo tempBlendTileInfo=m_blendedTiles[m_blendTileNdxes[ndx]]; + tempBlendTileInfo.inverted |= FLIPPED_MASK; + Short newNdx = findOrCreateBlendTile(&tempBlendTileInfo); + m_blendTileNdxes[ndx] = newNdx; //remap this tile to use a new one. + } } else m_blendTileNdxes[ndx] = newNdx; @@ -1886,7 +1886,7 @@ Bool WorldHeightMapEdit::resize(Int newXSize, Int newYSize, Int newHeight, Int n m_dataSize = newDataSize; delete(m_cellCliffState); delete(m_cellFlipState); - Int numBytesX = (m_width+1)/8; //how many bytes to fit all bitflags + Int numBytesX = (m_width+7)/8; //how many bytes to fit all bitflags m_flipStateWidth=numBytesX; m_cellFlipState = MSGNEW("WorldHeightMapEdit::resize") UnsignedByte[numBytesX*m_height]; @@ -3444,6 +3444,5 @@ void WorldHeightMapEdit::findBoundaryNear(Coord3D *pt, float okDistance, Int *ou } (*outNdx) = -1; + (*outHandle) = -1; } - - diff --git a/Generals/Code/Tools/WorldBuilder/src/WaterOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/WaterOptions.cpp index 9e3d04144d0..2e2f0dc0d04 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WaterOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WaterOptions.cpp @@ -167,6 +167,8 @@ void WaterOptions::OnChangeWaterEdit() if (pTrig->isValid()) { didMatch = true; } else { + // Keep layer membership in sync when discarding the invalid trigger. + TheLayersList->removePolygonTriggerFromLayersList(pTrig); PolygonTrigger::removePolygonTrigger(pTrig); } break; diff --git a/Generals/Code/Tools/WorldBuilder/src/WaypointOptions.cpp b/Generals/Code/Tools/WorldBuilder/src/WaypointOptions.cpp index 4b16a953ab3..c9b9bcb73e2 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WaypointOptions.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WaypointOptions.cpp @@ -491,6 +491,8 @@ void WaypointOptions::OnChangeWaypointnameEdit() if (pTrig->isValid()) { didMatch = true; } else { + // Keep layer membership in sync when discarding the invalid trigger. + TheLayersList->removePolygonTriggerFromLayersList(pTrig); PolygonTrigger::removePolygonTrigger(pTrig); } break; diff --git a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp index c122151259d..dc926a4fa40 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp @@ -229,6 +229,7 @@ CWorldBuilderApp::CWorldBuilderApp() : m_tools[21] = &m_rampTool; m_tools[22] = &m_scorchTool; m_tools[23] = &m_borderTool; + m_tools[24] = &m_rulerTool; // set up initial values. m_brushTool.setHeight(16); @@ -255,6 +256,7 @@ CWorldBuilderApp::~CWorldBuilderApp() m_tools[i] = nullptr; } } + _exit(0); } ///////////////////////////////////////////////////////////////////////////// @@ -271,13 +273,21 @@ static LONG WINAPI UnHandledExceptionFilter(struct _EXCEPTION_POINTERS* e_info) BOOL CWorldBuilderApp::InitInstance() { + ApplicationHWnd = GetDesktopWindow(); + // initialization SetUnhandledExceptionFilter(UnHandledExceptionFilter); // initialize the memory manager early initMemoryManager(); +#ifdef DEBUG_LOGGING + // Turn on console output jba [3/20/2003] + DebugSetFlags(DebugGetFlags() | DEBUG_FLAG_LOG_TO_CONSOLE); +#endif + DEBUG_LOG(("starting Worldbuilder.")); + #ifdef RTS_DEBUG DEBUG_LOG(("RTS_DEBUG defined.")); #endif @@ -333,9 +343,10 @@ BOOL CWorldBuilderApp::InitInstance() #endif #ifdef DEBUG_CRASHING - TheWritableGlobalData->m_debugIgnoreAsserts = true; + TheWritableGlobalData->m_debugIgnoreAsserts = false; #endif + DEBUG_LOG(("TheWritableGlobalData %x", TheWritableGlobalData)); #if 1 // srj sez: put INI into our user data folder, not the ap dir free((void*)m_pszProfileName); @@ -366,6 +377,14 @@ BOOL CWorldBuilderApp::InitInstance() WorldHeightMapEdit::init(); initSubsystem(TheScriptEngine, (ScriptEngine*)(new ScriptEngine())); + +#if RTS_ZEROHOUR + TheScriptEngine->turnBreezeOff(); // stop the tree sway. +#endif + + // [2/11/2003] + ini.loadFileDirectory( "Data\\Scripts\\Scripts", INI_LOAD_OVERWRITE, nullptr ); + initSubsystem(TheAudio, (AudioManager*)new MilesAudioManager()); initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new VideoPlayer())); initSubsystem(TheModuleFactory, (ModuleFactory*)(new W3DModuleFactory())); @@ -526,7 +545,7 @@ void CWorldBuilderApp::setActiveTool(Tool *pNewTool) // CWorldBuilderApp::updateCurTool //============================================================================= /** Checks to see if any key modifiers (ctrl or alt) are pressed. If so, -selectes the appropriate tool, else uses the normal tool. */ +selects the appropriate tool, else uses the normal tool. */ //============================================================================= void CWorldBuilderApp::updateCurTool(Bool forceHand) { @@ -638,6 +657,9 @@ int CWorldBuilderApp::ExitInstance() #ifdef MEMORYPOOL_CHECKPOINTING TheMemoryPoolFactory->debugMemoryReport(REPORT_FACTORYINFO | REPORT_CP_LEAKS | REPORT_CP_STACKTRACE, gFirstCP, lastCP); #endif + #ifdef MEMORYPOOL_DEBUG + TheMemoryPoolFactory->debugMemoryReport(REPORT_POOLINFO | REPORT_POOL_OVERFLOW | REPORT_SIMPLE_LEAKS, 0, 0); + #endif shutdownMemoryManager(); return CWinApp::ExitInstance(); diff --git a/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp b/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp index 14032945d3b..525af794123 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp @@ -59,6 +59,7 @@ #include "WorldBuilderView.h" #include "MapPreview.h" + // Can't currently have multiple open... jba. #define notONLY_ONE_AT_A_TIME @@ -107,6 +108,7 @@ BEGIN_MESSAGE_MAP(CWorldBuilderDoc, CDocument) ON_UPDATE_COMMAND_UI(ID_WINDOW_2DWINDOW, OnUpdateWindow2dwindow) ON_COMMAND(ID_VIEW_RELOADTEXTURES, OnViewReloadtextures) ON_COMMAND(ID_EDIT_SCRIPTS, OnEditScripts) + ON_COMMAND(ID_SCRIPT_EDIT, OnEditScripts) ON_COMMAND(ID_VIEWHOME, OnViewHome) ON_COMMAND(ID_TEXTURESIZING_TILE4X4, OnTexturesizingTile4x4) ON_UPDATE_COMMAND_UI(ID_TEXTURESIZING_TILE4X4, OnUpdateTexturesizingTile4x4) @@ -393,6 +395,16 @@ void CWorldBuilderDoc::Serialize(CArchive& ar) } pMapObj = pMapObj->getNext(); } + + PolygonTrigger* polyTrigger = PolygonTrigger::getFirstPolygonTrigger(); + // Add the triggers to the layers list. + while (polyTrigger) { + layerName = polyTrigger->getLayerName(); + TheLayersList->addPolygonTriggerToLayersList(polyTrigger, layerName); + + polyTrigger = polyTrigger->getNext(); + } + TheLayersList->enableUpdates(); TerrainMaterial::updateTextures(m_heightMap); @@ -420,6 +432,25 @@ void CWorldBuilderDoc::Serialize(CArchive& ar) } } +AsciiString ConvertToNonGCName(AsciiString name, Bool checkTemplate=true) +{ + const char* replacePrefix = "GC_"; + const size_t offset = name.startsWith(replacePrefix) ? strlen(replacePrefix) : 0u; + char newName[256]; + strlcpy(newName, name.str() + offset, ARRAY_SIZE(newName)); + AsciiString swapName; + swapName.set(newName); + if (checkTemplate) + { + const ThingTemplate *tt = TheThingFactory->findTemplate(swapName); + if (tt) { + return swapName; + } + return AsciiString::TheEmptyString; + } + return swapName; +} + AsciiString ConvertName(AsciiString name) { const char* replacePrefix = "Fundamentalist"; @@ -460,14 +491,20 @@ void CWorldBuilderDoc::validate() Bool changed = false; AsciiString swapName; + Bool needToFixTeams = false; + // verify/fix the build lists for (int side=0; sidegetNumSides(); side++) { SidesInfo *pSide = TheSidesList->getSideInfo(side); AsciiString tmplname = pSide->getDict()->getAsciiString(TheKey_playerFaction); + AsciiString playername = pSide->getDict()->getAsciiString(TheKey_playerName); + if (tmplname.isEmpty()) { + continue; // Neutral player has empty template. jba. [8/8/2003] + } const PlayerTemplate* pt = ThePlayerTemplateStore->findPlayerTemplate(NAMEKEY(tmplname)); if (!pt) { - DEBUG_LOG(("Faction %s could not be found in sides list!", tmplname.str())); + DEBUG_LOG(("Player '%s' Faction '%s' could not be found in sides list!", playername.str(), tmplname.str())); if (tmplname.startsWith("FactionFundamentalist")) { swapName = ConvertFaction(tmplname); if (swapName != AsciiString::TheEmptyString) { @@ -550,6 +587,15 @@ void CWorldBuilderDoc::validate() } } + // quick hack to remove "GC_" objects from Generals mission disk maps. + if (name.startsWith("GC_")) { + swapName = ConvertToNonGCName(name); + if (swapName != AsciiString::TheEmptyString) { + swapDict.setAsciiString(NAMEKEY(name), swapName); + exists = true; + } + } + if (!exists) { ReplaceUnitDialog dlg; dlg.setMissing(name); @@ -590,9 +636,13 @@ void CWorldBuilderDoc::validate() if (pSide) { // Bool hasColor = false; AsciiString tmplname = pSide->getDict()->getAsciiString(TheKey_playerFaction); + AsciiString playername = pSide->getDict()->getAsciiString(TheKey_playerName); + if (tmplname.isEmpty()) { + continue; // Neutral player has empty template. jba. [8/8/2003] + } const PlayerTemplate* pt = ThePlayerTemplateStore->findPlayerTemplate(NAMEKEY(tmplname)); if (!pt) { - DEBUG_LOG(("Faction %s could not be found in sides list!", tmplname.str())); + DEBUG_LOG(("Player '%s' Faction '%s' could not be found in sides list!", playername.str(), tmplname.str())); if (tmplname.startsWith("FactionFundamentalist")) { swapName = ConvertFaction(tmplname); if (swapName != AsciiString::TheEmptyString) { @@ -602,15 +652,21 @@ void CWorldBuilderDoc::validate() } } } else { - DEBUG_LOG(("Side %s could not be found in sides list!", teamOwner.str())); + needToFixTeams = true; + DEBUG_LOG(("Side '%s' could not be found in sides list!", teamOwner.str())); } } else { - DEBUG_LOG(("Team %s could not be found in sides list!", teamName.str())); + needToFixTeams = true; + DEBUG_LOG(("Team '%s' could not be found in sides list!", teamName.str())); } } else { - DEBUG_LOG(("Object %s does not have a team at all!", name.str())); + needToFixTeams = true; + DEBUG_LOG(("Object '%s' does not have a team at all!", name.str())); } } + if (needToFixTeams) { + AfxMessageBox(IDS_NEED_TO_FIX_TEAMS, MB_OK|MB_ICONERROR); + } } void CWorldBuilderDoc::OnJumpToGame() @@ -1235,6 +1291,7 @@ BOOL CWorldBuilderDoc::OnNewDocument() PolygonTrigger *pTrig = newInstance(PolygonTrigger)(4); ICoord3D loc; pTrig->setWaterArea(true); + pTrig->setTriggerName("Default Water"); loc.x = -hi.borderWidth*MAP_XY_FACTOR; loc.y = -hi.borderWidth*MAP_XY_FACTOR; loc.z = TheGlobalData->m_waterPositionZ; @@ -1246,7 +1303,7 @@ BOOL CWorldBuilderDoc::OnNewDocument() loc.x = -hi.borderWidth*MAP_XY_FACTOR; pTrig->addPoint(loc); PolygonTrigger::addPolygonTrigger(pTrig); - + TheLayersList->addPolygonTriggerToLayersList(pTrig, pTrig->getLayerName()); SetHeightMap(m_heightMap, true); TerrainMaterial::updateTextures(m_heightMap); @@ -1886,8 +1943,8 @@ void CWorldBuilderDoc::OnViewReloadtextures() void CWorldBuilderDoc::OnEditScripts() { - ScriptDialog script; - script.DoModal(); + ASSERT(CMainFrame::GetMainFrame()); + CMainFrame::GetMainFrame()->onEditScripts(); } /* when "home" key is pressed, goes to the initial camera waypoint or if diff --git a/Generals/Code/Tools/WorldBuilder/src/mapobjectprops.cpp b/Generals/Code/Tools/WorldBuilder/src/mapobjectprops.cpp index 0e8ff0f3185..fde41ae74ad 100644 --- a/Generals/Code/Tools/WorldBuilder/src/mapobjectprops.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/mapobjectprops.cpp @@ -31,6 +31,7 @@ #include "Common/ThingTemplate.h" #include "Common/UnicodeString.h" #include "Common/WellKnownKeys.h" +#include "Common/AudioEventInfo.h" #include "GameLogic/Module/UpgradeModule.h" #include "GameLogic/Module/GenerateMinefieldBehavior.h" @@ -39,6 +40,7 @@ const char* NEUTRAL_TEAM_UI_STR = "(neutral)"; const char* NEUTRAL_TEAM_INTERNAL_STR = "team"; + ///////////////////////////////////////////////////////////////////////////// // MapObjectProps dialog @@ -51,21 +53,39 @@ void MapObjectProps::makeMain() TheMapObjectProps = this; } + MapObjectProps::MapObjectProps(Dict* dictToEdit, const char* title, CWnd* pParent /*=nullptr*/) : COptionsPanel(MapObjectProps::IDD, pParent), m_dictToEdit(dictToEdit), m_title(title), - m_selectedObject(nullptr) + m_selectedObject(nullptr), + m_dictSource(nullptr), + m_scale( 1.0f ), + m_height( 0 ), + m_posUndoable( nullptr ), + m_angle( 0 ), + m_defaultEntryIndex(0), + m_defaultIsNone(true) { - //{{AFX_DATA_INIT(MapObjectProps) + + + //{{AFX_DATA_INIT(MapObjectProps) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } MapObjectProps::~MapObjectProps() { - if (TheMapObjectProps == this) + if (TheMapObjectProps == this) TheMapObjectProps = nullptr; + + if ( m_posUndoable != nullptr ) + { + REF_PTR_RELEASE( m_posUndoable ); + } + + if ( m_hWnd ) + DestroyWindow(); } void MapObjectProps::DoDataExchange(CDataExchange* pDX) @@ -79,73 +99,85 @@ void MapObjectProps::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(MapObjectProps, CDialog) //{{AFX_MSG_MAP(MapObjectProps) - ON_LBN_SELCHANGE(IDC_PROPERTIES, OnSelchangeProperties) + ON_BN_CLICKED(IDC_CUSTOMIZE_CHECKBOX, customizeToDict) ON_BN_CLICKED(IDC_EDITPROP, OnEditprop) - ON_BN_CLICKED(IDC_NEWPROP, OnNewprop) - ON_BN_CLICKED(IDC_REMOVEPROP, OnRemoveprop) - ON_LBN_DBLCLK(IDC_PROPERTIES, OnDblclkProperties) - ON_CBN_SELCHANGE(IDC_MAPOBJECT_Team, _TeamToDict) - ON_EN_KILLFOCUS(IDC_MAPOBJECT_Name, _NameToDict) - ON_CBN_SELCHANGE(IDC_MAPOBJECT_StartingHealth, _HealthToDict) - ON_CBN_SELENDOK(IDC_MAPOBJECT_HitPoints, _HPsToDict) - ON_CBN_KILLFOCUS(IDC_MAPOBJECT_HitPoints, _HPsToDict) + ON_BN_CLICKED(IDC_ENABLED_CHECKBOX, enabledToDict) + ON_BN_CLICKED(IDC_LOOPING_CHECKBOX, loopingToDict) ON_BN_CLICKED(IDC_MAPOBJECT_Enabled, _EnabledToDict) - ON_CBN_SELCHANGE(IDC_MAPOBJECT_Script, _ScriptToDict) ON_BN_CLICKED(IDC_MAPOBJECT_Indestructible, _IndestructibleToDict) - ON_BN_CLICKED(IDC_MAPOBJECT_Unsellable, _UnsellableToDict) - ON_BN_CLICKED(IDC_MAPOBJECT_Targetable, _TargetableToDict) ON_BN_CLICKED(IDC_MAPOBJECT_Powered, _PoweredToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_RecruitableAI, _RecruitableAIToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Selectable, _SelectableToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Targetable, _TargetableToDict) + ON_BN_CLICKED(IDC_MAPOBJECT_Unsellable, _UnsellableToDict) + ON_BN_CLICKED(IDC_NEWPROP, OnNewprop) + ON_BN_CLICKED(IDC_REMOVEPROP, OnRemoveprop) + ON_BN_CLICKED(IDC_SCALE_OFF, OnScaleOff) + ON_BN_CLICKED(IDC_SCALE_ON, OnScaleOn) + ON_CBN_KILLFOCUS(IDC_MAPOBJECT_HitPoints, _HPsToDict) ON_CBN_SELCHANGE(IDC_MAPOBJECT_Aggressiveness, _AggressivenessToDict) - ON_EN_KILLFOCUS(IDC_MAPOBJECT_VisionDistance, _VisibilityToDict) - ON_EN_KILLFOCUS(IDC_MAPOBJECT_ShroudClearingDistance, _ShroudClearingDistanceToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Script, _ScriptToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_StartingHealth, _HealthToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Team, _TeamToDict) + ON_CBN_SELCHANGE(IDC_MAPOBJECT_Time, _TimeToDict) ON_CBN_SELCHANGE(IDC_MAPOBJECT_Veterancy, _VeterancyToDict) - ON_BN_CLICKED(IDC_MAPOBJECT_RecruitableAI, _RecruitableAIToDict) - ON_BN_CLICKED(IDC_MAPOBJECT_Selectable, _SelectableToDict) ON_CBN_SELCHANGE(IDC_MAPOBJECT_Weather, _WeatherToDict) - ON_CBN_SELCHANGE(IDC_MAPOBJECT_Time, _TimeToDict) - ON_EN_KILLFOCUS(IDC_MAPOBJECT_ZOffset, SetZOffset) + ON_CBN_SELCHANGE(IDC_PRIORITY_COMBO, priorityToDict) + ON_CBN_SELCHANGE(IDC_SOUND_COMBO, attachedSoundToDict) + ON_CBN_SELENDOK(IDC_MAPOBJECT_HitPoints, _HPsToDict) + ON_EN_KILLFOCUS(IDC_LOOPCOUNT_EDIT, loopCountToDict) ON_EN_KILLFOCUS(IDC_MAPOBJECT_Angle, SetAngle) - ON_EN_KILLFOCUS(IDC_MAPOBJECT_StoppingDistance, _StoppingDistanceToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_Name, _NameToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_Scale, _ScaleToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_ShroudClearingDistance, _ShroudClearingDistanceToDict) ON_EN_KILLFOCUS(IDC_MAPOBJECT_StartingHealthEdit, _HealthToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_StoppingDistance, _StoppingDistanceToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_VisionDistance, _VisibilityToDict) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_XYPosition, OnKillfocusMAPOBJECTXYPosition) + ON_EN_KILLFOCUS(IDC_MAPOBJECT_ZOffset, SetZOffset) + ON_EN_KILLFOCUS(IDC_MAX_RANGE_EDIT, maxRangeToDict) + ON_EN_KILLFOCUS(IDC_MIN_RANGE_EDIT, minRangeToDict) + ON_EN_KILLFOCUS(IDC_MIN_VOLUME_EDIT, minVolumeToDict) + ON_EN_KILLFOCUS(IDC_VOLUME_EDIT, volumeToDict) + ON_LBN_DBLCLK(IDC_PROPERTIES, OnDblclkProperties) ON_LBN_SELCHANGE(IDC_MAPOBJECT_BuildWithUpgrades, _PrebuiltUpgradesToDict) + ON_LBN_SELCHANGE(IDC_PROPERTIES, OnSelchangeProperties) //}}AFX_MSG_MAP END_MESSAGE_MAP() -///////////////////////////////////////////////////////////////////////////// -// MapObjectProps message handlers static AsciiString getNthKeyStr(const Dict* d, int i) { - NameKeyType k = d->getNthKey(i); - AsciiString kstr = TheNameKeyGenerator->keyToName(k); - return kstr; + NameKeyType k = d->getNthKey(i); + AsciiString kstr = TheNameKeyGenerator->keyToName(k); + return kstr; } static AsciiString getNthValueStr(const Dict* d, int i, Bool* enquote) { - *enquote = false; - AsciiString vstr; - switch(d->getNthType(i)) - { + *enquote = false; + AsciiString vstr; + switch(d->getNthType(i)) + { case Dict::DICT_BOOL: - vstr.format("%s", d->getNthBool(i) ? "true" : "false"); - break; - case Dict::DICT_INT: - vstr.format("%d", d->getNthInt(i), d->getNthInt(i)); - break; - case Dict::DICT_REAL: - vstr.format("%f", d->getNthReal(i)); - break; - case Dict::DICT_ASCIISTRING: - vstr.format("%s", d->getNthAsciiString(i).str()); - *enquote = true; - break; - case Dict::DICT_UNICODESTRING: - vstr.format("%ls", d->getNthUnicodeString(i).str()); - *enquote = true; - break; - } - return vstr; + vstr.format("%s", d->getNthBool(i) ? "true" : "false"); + break; + case Dict::DICT_INT: + vstr.format("%d", d->getNthInt(i), d->getNthInt(i)); + break; + case Dict::DICT_REAL: + vstr.format("%f", d->getNthReal(i)); + break; + case Dict::DICT_ASCIISTRING: + vstr.format("%s", d->getNthAsciiString(i).str()); + *enquote = true; + break; + case Dict::DICT_UNICODESTRING: + vstr.format("%ls", d->getNthUnicodeString(i).str()); + *enquote = true; + break; + } + return vstr; } int MapObjectProps::getSel() @@ -157,257 +189,688 @@ int MapObjectProps::getSel() // return sel; } -void MapObjectProps::enableButtons() +/// Move data from object to dialog controls +void MapObjectProps::_DictToTeam() { - // do nothing + int i; + + AsciiString name; + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Team); + owner->ResetContent(); + for (i = 0; i < TheSidesList->getNumTeams(); i++) + { + name = TheSidesList->getTeamInfo(i)->getDict()->getAsciiString(TheKey_teamName); + if (name == NEUTRAL_TEAM_INTERNAL_STR) + name = NEUTRAL_TEAM_UI_STR; + owner->AddString(name.str()); + } + // re-find, since the list is sorted + i = -1; + if (m_dictToEdit) + { + name = m_dictToEdit->getAsciiString(TheKey_originalOwner); + if (name == NEUTRAL_TEAM_INTERNAL_STR) + name = NEUTRAL_TEAM_UI_STR; + i = owner->FindStringExact(-1, name.str()); + DEBUG_ASSERTLOG(i >= 0, ("missing team '%s'. Non-fatal (jkmcd)", name.str())); + + } + owner->SetCurSel(i); } -void MapObjectProps::OnSelchangeProperties() +/// Move data from object to dialog controls +void MapObjectProps::_DictToName() { + AsciiString name; + Bool exists; + if (m_dictToEdit) + { + name = m_dictToEdit->getAsciiString(TheKey_objectName, &exists); + } + CWnd* pItem = GetDlgItem(IDC_MAPOBJECT_Name); + if (pItem) + { + pItem->SetWindowText(name.str()); + } } -BOOL MapObjectProps::OnInitDialog() +/// Move data from object to dialog controls +void MapObjectProps::_DictToScript() { - CDialog::OnInitDialog(); - - if (m_title) - SetWindowText(m_title); + if (!m_dictToEdit) + { + return; + } - m_heightSlider.SetupPopSliderButton(this, IDC_HEIGHT_POPUP, this); - m_angleSlider.SetupPopSliderButton(this, IDC_ANGLE_POPUP, this); - m_posUndoable = nullptr; - m_angle = 0; - m_height = 0; - - updateTheUI(); + Bool exists; + CComboBox *pCombo = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Script); + // Load the subroutine scripts into the combo box. + EditParameter::loadScripts(pCombo, true); + /*Int stringNdx =*/ pCombo->AddString(""); + AsciiString script = m_dictToEdit->getAsciiString(TheKey_objectScriptAttachment, &exists); - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE + if (script.isEmpty()) { + pCombo->SelectString(-1, ""); + } else { + pCombo->SelectString(-1, script.str()); + } } -/*static*/ void MapObjectProps::update() +/// Move data from dialog controls to object +void MapObjectProps::_TeamToDict() { - if (TheMapObjectProps) - { - TheMapObjectProps->updateTheUI(); - } + getAllSelectedDicts(); + + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Team); + static char buf[1024]; + owner->GetWindowText(buf, sizeof(buf)-2); + if (strcmp(buf, NEUTRAL_TEAM_UI_STR)==0) + strlcpy(buf, NEUTRAL_TEAM_INTERNAL_STR, ARRAY_SIZE(buf)); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + Dict newDict; + newDict.setAsciiString(TheKey_originalOwner, AsciiString(buf)); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } } -void MapObjectProps::updateTheUI() +/// Move data from dialog controls to object +void MapObjectProps::_NameToDict() { - if (this != TheMapObjectProps) { - return; - } - - for (MapObject *pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) { - if (!pMapObj->isSelected() || pMapObj->isWaypoint() || pMapObj->isLight()) { - continue; - } + getAllSelectedDicts(); - m_dictToEdit = pMapObj ? pMapObj->getProperties() : nullptr; - - _DictToTeam(); - _DictToName(); - _DictToHealth(); - _DictToHPs(); - _DictToEnabled(); - _DictToScript(); - _DictToDestructible(); - _DictToPowered(); - _DictToAggressiveness(); - _DictToVisibilityRange(); - _DictToVeterancy(); - _DictToWeather(); - _DictToTime(); - _DictToShroudClearingDistance(); - _DictToRecruitableAI(); - _DictToSelectable(); - _DictToStoppingDistance(); - _DictToPrebuiltUpgrades(); - _DictToUnsellable(); - _DictToTargetable(); - ShowZOffset(pMapObj); - ShowAngle(pMapObj); + CWnd *owner = GetDlgItem(IDC_MAPOBJECT_Name); + CString cstr; + owner->GetWindowText(cstr); - // simply break after the first one that's selected - break; - } + // Note: when starting up, this is called before a document exists. Just ignore such + // calls, since there can't be an object to affect. + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + Dict newDict; + newDict.setAsciiString(TheKey_objectName, cstr.GetBuffer(0)); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } } -/*static*/ MapObject *MapObjectProps::getSingleSelectedMapObject() +/// Move data from dialog controls to object +void MapObjectProps::_ScriptToDict() { - MapObject *pMapObj; - MapObject *theMapObj = nullptr; -// Bool found = false; - Int selCount=0; - for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) { - if (pMapObj->isSelected()) { - if (!pMapObj->isWaypoint() && !pMapObj->isLight()) - { - theMapObj = pMapObj; - } - selCount++; - } - } - if (selCount==1 && theMapObj) { - return theMapObj; - } - return(nullptr); + getAllSelectedDicts(); + + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Script); + static char buf[1024]; + owner->GetWindowText(buf, sizeof(buf)-2); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + Dict newDict; + newDict.setAsciiString(TheKey_objectScriptAttachment, AsciiString(buf)); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + + +/// Move data from object to dialog controls +void MapObjectProps::_DictToScale() +{ +// Currently not in the Mission Disk. +#if 0 + m_scale = 1; + Bool exists; + if (m_dictToEdit) { + m_scale = m_dictToEdit->getReal(TheKey_objectPrototypeScale, &exists); + } + if (!exists) { + m_scale = 1; + } + + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_Scale); + CString cstr; + cstr.Format("%.2f", m_scale); + edit->SetWindowText(cstr); + + CButton *off = (CButton*) GetDlgItem(IDC_SCALE_OFF); + CButton *on = (CButton*) GetDlgItem(IDC_SCALE_ON); + if (!exists) { + off->SetCheck(1); + on->SetCheck(0); + edit->EnableWindow(false); + GetDlgItem(IDC_SCALE_POPUP)->EnableWindow(false); + } else { + off->SetCheck(0); + on->SetCheck(1); + edit->EnableWindow(TRUE); + GetDlgItem(IDC_SCALE_POPUP)->EnableWindow(true); + } +#endif + } -void MapObjectProps::OnEditprop() +/// Move data from object to dialog controls +void MapObjectProps::_DictToWeather() { - int sel = getSel(); - if (sel == -1 || !m_dictToEdit) - return; + Int value = 0; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_objectWeather, &exists); + if (!exists) + value = 0; + } - Bool enquote; - AsciiString kstr = getNthKeyStr(m_dictToEdit, sel); - AsciiString vstr = getNthValueStr(m_dictToEdit, sel, &enquote); - Dict::DataType type = m_dictToEdit->getNthType(sel); + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Weather); + pItem->SetCurSel(value); +} - PropEdit propDlg(&kstr, &type, &vstr, true, this); - if (propDlg.DoModal() == IDOK) - { - Dict newDict = DictItemUndoable::buildSingleItemDict(kstr, type, vstr); - if (this == TheMapObjectProps) - { - // it's the floating panel; use an undoable - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - DictItemUndoable *pUndo = new DictItemUndoable(&m_dictToEdit, newDict, newDict.getNthKey(0)); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - } - else - { - // we're running modal; just slam it in the dict - m_dictToEdit->copyPairFrom(newDict, newDict.getNthKey(0)); - } - updateTheUI(); - } +/// Move data from object to dialog controls +void MapObjectProps::_DictToTime() +{ + Int value = 0; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_objectTime, &exists); + if (!exists) + value = 0; + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Time); + pItem->SetCurSel(value); } -void MapObjectProps::OnNewprop() +/// Move data from dialog controls to object +void MapObjectProps::_WeatherToDict() { - if (!m_dictToEdit) - return; + getAllSelectedDicts(); - // TODO: Add your control notification handler code here - static Dict::DataType lastNewType = Dict::DICT_BOOL; - AsciiString key, value; + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Weather); + static char buf[1024]; + int curSel = owner->GetCurSel(); - PropEdit propDlg(&key, &lastNewType, &value, false, this); - if (propDlg.DoModal() == IDOK) - { - Dict newDict = DictItemUndoable::buildSingleItemDict(key, lastNewType, value); - if (this == TheMapObjectProps) - { - // it's the floating panel; use an undoable - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - DictItemUndoable *pUndo = new DictItemUndoable(&m_dictToEdit, newDict, newDict.getNthKey(0)); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - } - else - { - // we're running modal; just slam it in the dict - m_dictToEdit->copyPairFrom(newDict, newDict.getNthKey(0)); - } - updateTheUI(); - } + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + Dict newDict; + newDict.setInt(TheKey_objectWeather, curSel); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } } -void MapObjectProps::OnRemoveprop() +/// Move data from dialog controls to object +void MapObjectProps::_TimeToDict() { - int sel = getSel(); - if (sel == -1) - return; - - NameKeyType k = m_dictToEdit->getNthKey(sel); - if (this == TheMapObjectProps) - { - // it's the floating panel; use an undoable - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; // empty dict - DictItemUndoable *pUndo = new DictItemUndoable(&m_dictToEdit, newDict, k); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - } - else - { - // we're running modal; just slam it in the dict - m_dictToEdit->remove(k); - } - updateTheUI(); + getAllSelectedDicts(); + + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Time); + static char buf[1024]; + int curSel = owner->GetCurSel(); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + Dict newDict; + newDict.setInt(TheKey_objectTime, curSel); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_ScaleToDict() +{ +// Currently not in mission disk. +#if 0 + getAllSelectedDicts(); + + Real value = 0.0f; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_Scale); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + value = atof(cstr); + } + m_scale = value; + + CButton *off = (CButton*) GetDlgItem(IDC_SCALE_OFF); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + Dict newDict; + if (off->GetCheck() == 1) { + newDict.remove(TheKey_objectPrototypeScale); + } else { + newDict.setReal(TheKey_objectPrototypeScale, m_scale); + } + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +#endif } -void MapObjectProps::OnDblclkProperties() +/// Move data from object to dialog controls +void MapObjectProps::ShowZOffset(MapObject *pMapObj) { - OnEditprop(); + const Coord3D *loc = pMapObj->getLocation(); + static char buff[32]; + m_height = loc->z; + snprintf(buff, ARRAY_SIZE(buff), "%0.2f", loc->z); + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ZOffset); + edit->SetWindowText(buff); } -void MapObjectProps::_DictToTeam() +/// Move data from dialog controls to object +void MapObjectProps::SetZOffset() +{ + Real value = 0.0f; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ZOffset); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + value = atof(cstr); + } + m_height = value; + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + ModifyObjectUndoable *pUndo = new ModifyObjectUndoable(pDoc); + pDoc->AddAndDoUndoable(pUndo); + pUndo->SetZOffset(value); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } +} + +/// Move data from object to dialog controls +void MapObjectProps::ShowAngle(MapObject *pMapObj) { - int i; + m_angle = pMapObj->getAngle() * 180 / PI; + static char buff[32]; + snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_angle); + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_Angle); + edit->SetWindowText(buff); + m_angle = atof(buff); +} - AsciiString name; - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Team); - owner->ResetContent(); - for (i = 0; i < TheSidesList->getNumTeams(); i++) - { - name = TheSidesList->getTeamInfo(i)->getDict()->getAsciiString(TheKey_teamName); - if (name == NEUTRAL_TEAM_INTERNAL_STR) - name = NEUTRAL_TEAM_UI_STR; - owner->AddString(name.str()); - } - // re-find, since the list is sorted - i = -1; - if (m_dictToEdit) - { - name = m_dictToEdit->getAsciiString(TheKey_originalOwner); - if (name == NEUTRAL_TEAM_INTERNAL_STR) - name = NEUTRAL_TEAM_UI_STR; - i = owner->FindStringExact(-1, name.str()); - DEBUG_ASSERTLOG(i >= 0, ("missing team '%s'. Non-fatal (jkmcd)", name.str())); - } - owner->SetCurSel(i); +/// Move data from object to dialog controls +void MapObjectProps::ShowPosition(MapObject *pMapObj) +{ + m_position = *pMapObj->getLocation(); + static char buff[64]; + snprintf(buff, ARRAY_SIZE(buff), "%0.2f, %0.2f", m_position.x, m_position.y); + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_XYPosition); + edit->SetWindowText(buff); + sscanf(buff, "%f,%f", &m_position.x, &m_position.y); } -void MapObjectProps::_DictToName() +/// Move data from dialog controls to object +void MapObjectProps::SetAngle() { - AsciiString name; - Bool exists; - if (m_dictToEdit) { - name = m_dictToEdit->getAsciiString(TheKey_objectName, &exists); - } + Real angle = m_angle; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_Angle); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + angle = atof(cstr); + } + if (m_selectedObject==nullptr) return; + if (m_angle!=angle) + { + m_angle = angle; + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + ModifyObjectUndoable *pUndo = new ModifyObjectUndoable(pDoc); + pDoc->AddAndDoUndoable(pUndo); + pUndo->RotateTo(angle * PI/180); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } + } +} + +/// Move data from dialog controls to object +void MapObjectProps::SetPosition() +{ + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_XYPosition); + CString cstr; + edit->GetWindowText(cstr); + Coord3D loc; + loc = m_position; + if (m_selectedObject==nullptr) return; + if (!cstr.IsEmpty()) { + if (sscanf(cstr, "%f, %f", &loc.x, &loc.y)!=2) + loc = m_position; + } + if (loc.x!=m_position.x || loc.y != m_position.y) { + m_position = loc; + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc ) + { + ModifyObjectUndoable *pUndo = new ModifyObjectUndoable(pDoc); + pDoc->AddAndDoUndoable(pUndo); + if (m_selectedObject) { + loc = *m_selectedObject->getLocation(); + } + pUndo->SetOffset(m_position.x-loc.x, m_position.y-loc.y); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } + } +} + +/// Slider control +void MapObjectProps::GetPopSliderInfo(const long sliderID, long *pMin, long *pMax, long *pLineSize, long *pInitial) +{ + switch (sliderID) { - CWnd* pItem = GetDlgItem(IDC_MAPOBJECT_Name); - if (pItem) { - pItem->SetWindowText(name.str()); + case IDC_HEIGHT_POPUP: + *pMin = -50; + *pMax = 50; + *pInitial = m_height; + *pLineSize = 1; + break; + + case IDC_ANGLE_POPUP: + *pMin = 0; + *pMax = 360; + *pInitial = m_angle; + *pLineSize = 1; + break; + + case IDC_SCALE_POPUP: + *pMin = 1; + *pMax = 500; + *pInitial = m_scale*100; + *pLineSize = 1; + break; + + default: + // uh-oh! + DEBUG_CRASH(("Slider message from unknown control")); + break; } } -void MapObjectProps::_DictToHealth() +/// Slider control +void MapObjectProps::PopSliderChanged(const long sliderID, long theVal) { - Int value = 100; - Bool exists; - if (m_dictToEdit) { - value = m_dictToEdit->getInt(TheKey_objectInitialHealth, &exists); - } + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc == nullptr ) + return; - CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_StartingHealth); - CWnd* pItem2 = GetDlgItem(IDC_MAPOBJECT_StartingHealthEdit); - if (pItem && pItem2) { - if (value == 0) { - pItem->SelectString(-1, "0%"); - pItem2->SetWindowText(""); - pItem2->EnableWindow(FALSE); - } else if (value == 25) { - pItem->SelectString(-1, "25%"); - pItem2->SetWindowText(""); - pItem2->EnableWindow(FALSE); - } else if (value == 50) { + CWnd* edit; + static char buff[32]; + switch (sliderID) { + case IDC_HEIGHT_POPUP: + if (!m_posUndoable) { + m_posUndoable = new ModifyObjectUndoable(pDoc); + pDoc->AddAndDoUndoable(m_posUndoable); + } + m_posUndoable->SetZOffset(theVal); + m_height = theVal; + snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_height); + edit = GetDlgItem(IDC_MAPOBJECT_ZOffset); + edit->SetWindowText(buff); + break; + + case IDC_ANGLE_POPUP: + if (!m_posUndoable) { + m_posUndoable = new ModifyObjectUndoable(pDoc); + pDoc->AddAndDoUndoable(m_posUndoable); + } + m_posUndoable->RotateTo(theVal * PI/180); + m_angle = theVal; + snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_angle); + edit = GetDlgItem(IDC_MAPOBJECT_Angle); + edit->SetWindowText(buff); + break; + + case IDC_SCALE_POPUP: + m_scale = theVal/100.0f; + snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_scale); + edit = GetDlgItem(IDC_MAPOBJECT_Scale); + edit->SetWindowText(buff); + break; + + default: + // uh-oh! + DEBUG_CRASH(("Slider message from unknown control")); + break; + } +} + +/// Slider control +void MapObjectProps::PopSliderFinished(const long sliderID, long theVal) +{ + switch (sliderID) { + case IDC_HEIGHT_POPUP: + case IDC_ANGLE_POPUP: + if ( m_posUndoable != nullptr ) + { + REF_PTR_RELEASE(m_posUndoable); // belongs to pDoc now. + } + m_posUndoable = nullptr; + break; + + case IDC_SCALE_POPUP: + _ScaleToDict(); + break; + + default: + // uh-oh! + DEBUG_CRASH(("Slider message from unknown control")); + break; + } + +} + +/// Move data from dialog controls to object +void MapObjectProps::_PrebuiltUpgradesToDict() +{ + getAllSelectedDicts(); + + CListBox *pBox = (CListBox *) GetDlgItem(IDC_MAPOBJECT_BuildWithUpgrades); + if (!pBox) { + return; + } + + // We only work for single selections + if (m_allSelectedDicts.size() != 1) { + return; + } + + if (m_selectedObject) { + if ( !m_selectedObject->getThingTemplate() ) { + return; + } + } + + Bool exists; + int upgradeNum = 0; + AsciiString upgradeString; + + // We're going to sub this entire dict for the existing entire dict. + Dict newDict = *m_allSelectedDicts[0]; + + // First, clear out any existing notions of what we should upgrade. + do { + AsciiString keyName; + keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_objectGrantUpgrade).str(), upgradeNum); + upgradeString = newDict.getAsciiString(NAMEKEY(keyName), &exists); + + if (exists) { + newDict.remove(NAMEKEY(keyName)); + } + + ++upgradeNum; + } while (!upgradeString.isEmpty()); + + upgradeNum = 0; + // We've now removed them, so lets add the ones that are selected now. + Int countOfItems = pBox->GetCount(); + for (Int i = 0; i < countOfItems; ++i) { + if (pBox->GetSel(i) > 0) { + CString selTxt; + // This thing is selected. Get its text, and add it to the dict. + pBox->GetText(i, selTxt); + + AsciiString keyName; + keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_objectGrantUpgrade).str(), upgradeNum); + newDict.setAsciiString(NAMEKEY(keyName), AsciiString(selTxt.GetBuffer(0))); + ++upgradeNum; + } + } + + // Now, do the Undoable + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, NAMEKEY_INVALID, m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } +} + +/// Move data from object to dialog controls +void MapObjectProps::_DictToPrebuiltUpgrades() +{ + getAllSelectedDicts(); + + CListBox *pBox = (CListBox*) GetDlgItem(IDC_MAPOBJECT_BuildWithUpgrades); + if (!pBox) { + return; + } + + // First, clear out the list + pBox->ResetContent(); + CString cstr; + + // Then, if there's multiple units selected, add the Single Selection Only string + if (m_allSelectedDicts.size() > 1) { + cstr.LoadString(IDS_SINGLE_SELECTION_ONLY); + pBox->AddString(cstr); + return; + } + + if (m_selectedObject == nullptr) { + return; + } + + // Otherwise, fill it with the upgrades available for this unit + const ThingTemplate *tt = m_selectedObject->getThingTemplate(); + if (tt == nullptr) { + // This is valid. For instance, Scorch marks do not have thing templates. + return; + } + + Bool noUpgrades = false; + + // Now do any behaviors that are also upgrades. + const ModuleInfo& mi = tt->getBehaviorModuleInfo(); + if (mi.getCount() == 0) { + if (noUpgrades) { + cstr.LoadString(IDS_NO_UPGRADES); + pBox->AddString(cstr); + return; + } + } else { + Int numBehaviorModules = mi.getCount(); + + Int numBehaviorsWithUpgrades = 0; + + for (int i = 0; i < numBehaviorModules; ++i) { + if (mi.getNthName(i).compareNoCase("GenerateMinefieldBehavior") == 0) { + const GenerateMinefieldBehaviorModuleData *gmbmd = (const GenerateMinefieldBehaviorModuleData *)mi.getNthData(i); + if (!gmbmd) { + continue; + } + if (!gmbmd->m_upgradeMuxData.m_activationUpgradeNames.empty()) { + cstr = gmbmd->m_upgradeMuxData.m_activationUpgradeNames[0].str(); + if (pBox->FindString(-1, cstr) == LB_ERR) { + pBox->AddString(cstr); + ++numBehaviorsWithUpgrades; + } + } + } + } + + if (numBehaviorsWithUpgrades == 0) { + if (noUpgrades) { + cstr.LoadString(IDS_NO_UPGRADES); + pBox->AddString(cstr); + return; + } + } + } + + // Finally, walk through the upgrades that he already has, and select the appropriate members + // from the list + + Bool exists; + int upgradeNum = 0; + AsciiString upgradeString; + + do { + AsciiString keyName; + keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_objectGrantUpgrade).str(), upgradeNum); + upgradeString = m_dictToEdit->getAsciiString(NAMEKEY(keyName), &exists); + + if (exists) { + Int selNdx = pBox->FindStringExact(-1, upgradeString.str()); + if (selNdx == LB_ERR) { + DEBUG_CRASH(("Object claims '%s', but it wasn't found in the list of possible upgrades.", upgradeString.str())); + ++upgradeNum; + continue; + } + pBox->SetSel(selNdx); + + } else { + upgradeString.clear(); + } + + ++upgradeNum; + } while (!upgradeString.isEmpty()); +} + +/// Move data from object to dialog controls +void MapObjectProps::_DictToHealth() +{ + Int value = 100; + Bool exists; + if (m_dictToEdit) { + value = m_dictToEdit->getInt(TheKey_objectInitialHealth, &exists); + } + + CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_StartingHealth); + CWnd* pItem2 = GetDlgItem(IDC_MAPOBJECT_StartingHealthEdit); + if (pItem && pItem2) { + if (value == 0) { + pItem->SelectString(-1, "0%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else if (value == 25) { + pItem->SelectString(-1, "25%"); + pItem2->SetWindowText(""); + pItem2->EnableWindow(FALSE); + } else if (value == 50) { pItem->SelectString(-1, "50%"); pItem2->SetWindowText(""); pItem2->EnableWindow(FALSE); @@ -429,6 +892,8 @@ void MapObjectProps::_DictToHealth() } } + +/// Move data from object to dialog controls void MapObjectProps::_DictToHPs() { Int value = -1; @@ -454,6 +919,7 @@ void MapObjectProps::_DictToHPs() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToEnabled() { Bool enabled = true; @@ -468,26 +934,8 @@ void MapObjectProps::_DictToEnabled() } } -void MapObjectProps::_DictToScript() -{ - if (!m_dictToEdit) { - return; - } - - Bool exists; - CComboBox *pCombo = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Script); - // Load the subroutine scripts into the combo box. - EditParameter::loadScripts(pCombo, true); - /*Int stringNdx =*/ pCombo->AddString(""); - AsciiString script = m_dictToEdit->getAsciiString(TheKey_objectScriptAttachment, &exists); - - if (script.isEmpty()) { - pCombo->SelectString(-1, ""); - } else { - pCombo->SelectString(-1, script.str()); - } -} +/// Move data from object to dialog controls void MapObjectProps::_DictToDestructible() { Bool destructible = true; @@ -502,6 +950,7 @@ void MapObjectProps::_DictToDestructible() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToUnsellable() { Bool unsellable = false; @@ -516,6 +965,7 @@ void MapObjectProps::_DictToUnsellable() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToTargetable() { Bool targetable = false; @@ -532,6 +982,7 @@ void MapObjectProps::_DictToTargetable() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToPowered() { Bool powered = true; @@ -547,6 +998,7 @@ void MapObjectProps::_DictToPowered() } +/// Move data from object to dialog controls void MapObjectProps::_DictToAggressiveness() { Int value = 0; @@ -571,6 +1023,7 @@ void MapObjectProps::_DictToAggressiveness() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToVisibilityRange() { Int distance = 0; @@ -591,6 +1044,7 @@ void MapObjectProps::_DictToVisibilityRange() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToVeterancy() { Int value = 0; @@ -605,34 +1059,7 @@ void MapObjectProps::_DictToVeterancy() } } -void MapObjectProps::_DictToWeather() -{ - Int value = 0; - Bool exists; - if (m_dictToEdit) { - value = m_dictToEdit->getInt(TheKey_objectWeather, &exists); - if (!exists) - value = 0; - } - - CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Weather); - pItem->SetCurSel(value); -} - -void MapObjectProps::_DictToTime() -{ - Int value = 0; - Bool exists; - if (m_dictToEdit) { - value = m_dictToEdit->getInt(TheKey_objectTime, &exists); - if (!exists) - value = 0; - } - - CComboBox* pItem = (CComboBox*) GetDlgItem(IDC_MAPOBJECT_Time); - pItem->SetCurSel(value); -} - +/// Move data from object to dialog controls void MapObjectProps::_DictToShroudClearingDistance() { Int distance = 0; @@ -653,6 +1080,7 @@ void MapObjectProps::_DictToShroudClearingDistance() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToRecruitableAI() { Bool recruitableAI = true; @@ -667,12 +1095,16 @@ void MapObjectProps::_DictToRecruitableAI() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToSelectable() { - Bool selectable = true; - Bool exists; + Int selectable = true; + Bool exists=false; if (m_dictToEdit) { - selectable = m_dictToEdit->getBool(TheKey_objectSelectable, &exists); + selectable = m_dictToEdit->getBool(TheKey_objectSelectable, &exists); + } + if (!exists) { + selectable = 2; } CButton* pItem = (CButton*) GetDlgItem(IDC_MAPOBJECT_Selectable); @@ -681,6 +1113,7 @@ void MapObjectProps::_DictToSelectable() } } +/// Move data from object to dialog controls void MapObjectProps::_DictToStoppingDistance() { Real stoppingDistance = 1.0f; @@ -697,142 +1130,8 @@ void MapObjectProps::_DictToStoppingDistance() } } -void MapObjectProps::_DictToPrebuiltUpgrades() -{ - getAllSelectedDicts(); - - CListBox *pBox = (CListBox*) GetDlgItem(IDC_MAPOBJECT_BuildWithUpgrades); - if (!pBox) { - return; - } - - // First, clear out the list - pBox->ResetContent(); - CString cstr; - - // Then, if there's multiple units selected, add the Single Selection Only string - if (m_allSelectedDicts.size() > 1) { - cstr.LoadString(IDS_SINGLE_SELECTION_ONLY); - pBox->AddString(cstr); - return; - } - - if (m_selectedObject == nullptr) { - return; - } - - // Otherwise, fill it with the upgrades available for this unit - const ThingTemplate *tt = m_selectedObject->getThingTemplate(); - if (tt == nullptr) { - // This is valid. For instance, Scorch marks do not have thing templates. - return; - } - - Bool noUpgrades = false; - - // Now do any behaviors that are also upgrades. - const ModuleInfo& mi = tt->getBehaviorModuleInfo(); - if (mi.getCount() == 0) { - if (noUpgrades) { - cstr.LoadString(IDS_NO_UPGRADES); - pBox->AddString(cstr); - return; - } - } else { - Int numBehaviorModules = mi.getCount(); - - Int numBehaviorsWithUpgrades = 0; - - for (int i = 0; i < numBehaviorModules; ++i) { - if (mi.getNthName(i).compareNoCase("GenerateMinefieldBehavior") == 0) { - const GenerateMinefieldBehaviorModuleData *gmbmd = (const GenerateMinefieldBehaviorModuleData *)mi.getNthData(i); - if (!gmbmd) { - continue; - } - if (!gmbmd->m_upgradeMuxData.m_activationUpgradeNames.empty()) { - cstr = gmbmd->m_upgradeMuxData.m_activationUpgradeNames[0].str(); - if (pBox->FindString(-1, cstr) == LB_ERR) { - pBox->AddString(cstr); - ++numBehaviorsWithUpgrades; - } - } - } - } - - if (numBehaviorsWithUpgrades == 0) { - if (noUpgrades) { - cstr.LoadString(IDS_NO_UPGRADES); - pBox->AddString(cstr); - return; - } - } - } - - // Finally, walk through the upgrades that he already has, and select the appropriate members - // from the list - - Bool exists; - int upgradeNum = 0; - AsciiString upgradeString; - - do { - AsciiString keyName; - keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_objectGrantUpgrade).str(), upgradeNum); - upgradeString = m_dictToEdit->getAsciiString(NAMEKEY(keyName), &exists); - - if (exists) { - Int selNdx = pBox->FindStringExact(-1, upgradeString.str()); - if (selNdx == LB_ERR) { - DEBUG_CRASH(("Object claims '%s', but it wasn't found in the list of possible upgrades.", upgradeString.str())); - ++upgradeNum; - continue; - } - pBox->SetSel(selNdx); - - } else { - upgradeString.clear(); - } - - ++upgradeNum; - } while (!upgradeString.isEmpty()); -} - -void MapObjectProps::_TeamToDict() -{ - getAllSelectedDicts(); - - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Team); - static char buf[1024]; - owner->GetWindowText(buf, sizeof(buf)-2); - if (strcmp(buf, NEUTRAL_TEAM_UI_STR)==0) - strcpy(buf, NEUTRAL_TEAM_INTERNAL_STR); - - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setAsciiString(TheKey_originalOwner, AsciiString(buf)); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} - -void MapObjectProps::_NameToDict() -{ - getAllSelectedDicts(); - - CWnd *owner = GetDlgItem(IDC_MAPOBJECT_Name); - CString cstr; - owner->GetWindowText(cstr); - - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setAsciiString(TheKey_objectName, cstr.GetBuffer(0)); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} +/// Move data from dialog controls to object void MapObjectProps::_HealthToDict() { getAllSelectedDicts(); @@ -863,456 +1162,1679 @@ void MapObjectProps::_HealthToDict() value = atoi(cstr.GetBuffer(0)); } CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setInt(TheKey_objectInitialHealth, value); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setInt(TheKey_objectInitialHealth, value); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } } -void MapObjectProps::_PrebuiltUpgradesToDict() + +/// Move data from dialog controls to object +void MapObjectProps::_EnabledToDict() { getAllSelectedDicts(); - CListBox *pBox = (CListBox *) GetDlgItem(IDC_MAPOBJECT_BuildWithUpgrades); - if (!pBox) { - return; - } - - // We only work for single selections - if (m_allSelectedDicts.size() != 1) { - return; - } + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Enabled); + Bool isChecked = (owner->GetCheck() != 0); - if (m_selectedObject) { - if ( !m_selectedObject->getThingTemplate() ) { - return; - } - } + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setBool(TheKey_objectEnabled, isChecked); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_IndestructibleToDict() +{ + getAllSelectedDicts(); - Bool exists; - int upgradeNum = 0; - AsciiString upgradeString; + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Indestructible); + Bool isChecked = (owner->GetCheck() != 0); - // We're going to sub this entire dict for the existing entire dict. - Dict newDict = *m_allSelectedDicts[0]; + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setBool(TheKey_objectIndestructible, isChecked); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_UnsellableToDict() +{ + getAllSelectedDicts(); - // First, clear out any existing notions of what we should upgrade. - do { - AsciiString keyName; - keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_objectGrantUpgrade).str(), upgradeNum); - upgradeString = newDict.getAsciiString(NAMEKEY(keyName), &exists); + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Unsellable); + Bool isChecked = (owner->GetCheck() != 0); - if (exists) { - newDict.remove(NAMEKEY(keyName)); - } + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setBool(TheKey_objectUnsellable, isChecked); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_TargetableToDict() +{ + getAllSelectedDicts(); - ++upgradeNum; - } while (!upgradeString.isEmpty()); - - upgradeNum = 0; - // We've now removed them, so lets add the ones that are selected now. - Int countOfItems = pBox->GetCount(); - for (Int i = 0; i < countOfItems; ++i) { - if (pBox->GetSel(i) > 0) { - CString selTxt; - // This thing is selected. Get its text, and add it to the dict. - pBox->GetText(i, selTxt); - - AsciiString keyName; - keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_objectGrantUpgrade).str(), upgradeNum); - newDict.setAsciiString(NAMEKEY(keyName), AsciiString(selTxt.GetBuffer(0))); - ++upgradeNum; - } - } + CButton *owner = (CButton*)GetDlgItem( IDC_MAPOBJECT_Targetable ); + Bool isChecked = owner->GetCheck() != 0; - // Now, do the Undoable CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, NAMEKEY_INVALID, m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setBool( TheKey_objectTargetable, isChecked ); + DictItemUndoable *pUndo = new DictItemUndoable( getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size() ); + pDoc->AddAndDoUndoable( pUndo ); + REF_PTR_RELEASE( pUndo ); // belongs to pDoc now. + // Update is called by Do + } } -void MapObjectProps::_EnabledToDict() + +/// Move data from dialog controls to object +void MapObjectProps::_PoweredToDict() { getAllSelectedDicts(); - CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Enabled); + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Powered); Bool isChecked = (owner->GetCheck() != 0); CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool(TheKey_objectEnabled, isChecked); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} - -void MapObjectProps::_ScriptToDict() + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setBool(TheKey_objectPowered, isChecked); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_AggressivenessToDict() { getAllSelectedDicts(); - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Script); + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Aggressiveness); static char buf[1024]; owner->GetWindowText(buf, sizeof(buf)-2); + int value = 0; + + if (strcmp(buf, "Sleep") == 0) { + value = -2; + } else if (strcmp(buf, "Passive") == 0) { + value = -1; + } else if (strcmp(buf, "Normal") == 0) { + value = 0; + } else if (strcmp(buf, "Alert") == 0) { + value = 1; + } else if (strcmp(buf, "Aggressive") == 0) { + value = 2; + } CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setAsciiString(TheKey_objectScriptAttachment, AsciiString(buf)); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setInt(TheKey_objectAggressiveness, value); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_VisibilityToDict() +{ + getAllSelectedDicts(); -void MapObjectProps::_IndestructibleToDict() + int value = -1; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_VisionDistance); + edit->EnableWindow(TRUE); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + value = atoi(cstr.GetBuffer(0)); + } + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + if (value != -1) { + newDict.setInt(TheKey_objectVisualRange, value); + } + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, TheKey_objectVisualRange, m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_VeterancyToDict() { getAllSelectedDicts(); - CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Indestructible); - Bool isChecked = (owner->GetCheck() != 0); + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Veterancy); + static char buf[1024]; + int curSel = owner->GetCurSel(); + int value = 0; + if (curSel >= 0) { + value=curSel; + } CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool(TheKey_objectIndestructible, isChecked); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setInt(TheKey_objectVeterancy, value); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_ShroudClearingDistanceToDict() +{ + getAllSelectedDicts(); -void MapObjectProps::_UnsellableToDict() + int value = -1; + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ShroudClearingDistance); + edit->EnableWindow(TRUE); + CString cstr; + edit->GetWindowText(cstr); + if (!cstr.IsEmpty()) { + value = atoi(cstr.GetBuffer(0)); + } + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + if (value != -1) { + newDict.setInt(TheKey_objectShroudClearingDistance, value); + } + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, TheKey_objectShroudClearingDistance, m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_RecruitableAIToDict() { getAllSelectedDicts(); - CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Unsellable); + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_RecruitableAI); Bool isChecked = (owner->GetCheck() != 0); CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool(TheKey_objectUnsellable, isChecked); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setBool(TheKey_objectRecruitableAI, isChecked); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_SelectableToDict() +{ + getAllSelectedDicts(); + + CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Selectable); + Bool isChecked = (owner->GetCheck() == 1); + Bool isTristate = (owner->GetCheck() == 2); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + if (isTristate) { + newDict.remove(TheKey_objectSelectable); + } else { + newDict.setBool(TheKey_objectSelectable, isChecked); + } + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Do + } +} + +/// Move data from dialog controls to object +void MapObjectProps::_HPsToDict() +{ + getAllSelectedDicts(); + + Int value; + static char buf[1024]; + + CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_HitPoints); + owner->GetWindowText(buf, sizeof(buf)-2); + value = atoi(buf); + if (value == 0) + value = -1; + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setInt(TheKey_objectMaxHPs, value); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } } -void MapObjectProps::_TargetableToDict() +/// Move data from dialog controls to object +void MapObjectProps::_StoppingDistanceToDict() { getAllSelectedDicts(); - CButton *owner = (CButton*)GetDlgItem( IDC_MAPOBJECT_Targetable ); - Bool isChecked = owner->GetCheck() != 0; + Real value; + static char buf[1024]; + + CWnd* edit = GetDlgItem(IDC_MAPOBJECT_StoppingDistance); + CString cstr; + edit->GetWindowText(cstr); + if (cstr.IsEmpty()) { + return; + } + value = atof(cstr.GetBuffer(0)); CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool( TheKey_objectTargetable, isChecked ); - DictItemUndoable *pUndo = new DictItemUndoable( getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size() ); - pDoc->AddAndDoUndoable( pUndo ); - REF_PTR_RELEASE( pUndo ); // belongs to pDoc now. - // Update is called by Do + if ( pDoc != nullptr ) + { + Dict newDict; + newDict.setReal(TheKey_objectStoppingDistance, value); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_PoweredToDict() +void MapObjectProps::OnEditprop() { - getAllSelectedDicts(); + int sel = getSel(); + if (sel == -1 || !m_dictToEdit) + return; + + Bool enquote; + AsciiString kstr = getNthKeyStr(m_dictToEdit, sel); + AsciiString vstr = getNthValueStr(m_dictToEdit, sel, &enquote); + Dict::DataType type = m_dictToEdit->getNthType(sel); + + PropEdit propDlg(&kstr, &type, &vstr, true, this); + if (propDlg.DoModal() == IDOK) + { + Dict newDict = DictItemUndoable::buildSingleItemDict(kstr, type, vstr); + if (this == TheMapObjectProps) + { + // it's the floating panel; use an undoable + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + DictItemUndoable *pUndo = new DictItemUndoable(&m_dictToEdit, newDict, newDict.getNthKey(0)); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } + else + { + // we're running modal; just slam it in the dict + m_dictToEdit->copyPairFrom(newDict, newDict.getNthKey(0)); + } + updateTheUI(); + } +} + +void MapObjectProps::OnNewprop() +{ + if (!m_dictToEdit) + return; + + // TODO: Add your control notification handler code here + static Dict::DataType lastNewType = Dict::DICT_BOOL; + AsciiString key, value; + + PropEdit propDlg(&key, &lastNewType, &value, false, this); + if (propDlg.DoModal() == IDOK) + { + Dict newDict = DictItemUndoable::buildSingleItemDict(key, lastNewType, value); + if (this == TheMapObjectProps) + { + // it's the floating panel; use an undoable + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + DictItemUndoable *pUndo = new DictItemUndoable(&m_dictToEdit, newDict, newDict.getNthKey(0)); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } + else + { + // we're running modal; just slam it in the dict + m_dictToEdit->copyPairFrom(newDict, newDict.getNthKey(0)); + } + updateTheUI(); + } +} + +void MapObjectProps::OnRemoveprop() +{ + int sel = getSel(); + if (sel == -1) + return; + + NameKeyType k = m_dictToEdit->getNthKey(sel); + if (this == TheMapObjectProps) + { + // it's the floating panel; use an undoable + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + Dict newDict; // empty dict + DictItemUndoable *pUndo = new DictItemUndoable(&m_dictToEdit, newDict, k); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + } + else + { + // we're running modal; just slam it in the dict + m_dictToEdit->remove(k); + } + updateTheUI(); +} + +void MapObjectProps::OnDblclkProperties() +{ + OnEditprop(); +} + + +static const Char NO_SOUND_STRING[] = "(None)"; +static const Char BASE_DEFAULT_STRING[] = "Default"; + +void MapObjectProps::OnSelchangeProperties() +{ + +} + +/// Initialize dialog, especially drop down lists +BOOL MapObjectProps::OnInitDialog() +{ + CDialog::OnInitDialog(); + + if (m_title) + SetWindowText(m_title); + + m_heightSlider.SetupPopSliderButton(this, IDC_HEIGHT_POPUP, this); + m_angleSlider.SetupPopSliderButton(this, IDC_ANGLE_POPUP, this); + m_scaleSlider.SetupPopSliderButton(this, IDC_SCALE_POPUP, this); + m_posUndoable = nullptr; + m_angle = 0; + m_height = 0; + m_scale = 1.0f; - CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Powered); - Bool isChecked = (owner->GetCheck() != 0); + InitSound(); + updateTheUI(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool(TheKey_objectPowered, isChecked); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + return TRUE; +} +//--------------------------------------------------------------------------------------------------- +/*static*/ void MapObjectProps::update() +{ + if (TheMapObjectProps) + { + TheMapObjectProps->updateTheUI(); + } } -void MapObjectProps::_AggressivenessToDict() +void MapObjectProps::updateTheUI() { - getAllSelectedDicts(); + if (this != TheMapObjectProps) { + return; + } + for (MapObject *pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) { + if (!pMapObj->isSelected() || pMapObj->isWaypoint() || pMapObj->isLight()) { + continue; + } - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Aggressiveness); - static char buf[1024]; - owner->GetWindowText(buf, sizeof(buf)-2); - int value = 0; + m_dictSource = pMapObj; + // Select correct dictionary + m_dictToEdit = m_dictSource ? m_dictSource->getProperties() : nullptr; - if (strcmp(buf, "Sleep") == 0) { - value = -2; - } else if (strcmp(buf, "Passive") == 0) { - value = -1; - } else if (strcmp(buf, "Normal") == 0) { - value = 0; - } else if (strcmp(buf, "Alert") == 0) { - value = 1; - } else if (strcmp(buf, "Aggressive") == 0) { - value = 2; + updateTheUI(m_dictSource); + + // simply break after the first one that's selected + break; } +} - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setInt(TheKey_objectAggressiveness, value); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do +/// Move *all* data from object to dialog controls +void MapObjectProps::updateTheUI(MapObject *pMapObj) +{ + _DictToName(); + _DictToTeam(); + _DictToScript(); + _DictToWeather(); + _DictToTime(); + _DictToScale(); + _DictToPrebuiltUpgrades(); + _DictToHealth(); + _DictToHPs(); + _DictToEnabled(); + _DictToDestructible(); + _DictToPowered(); + _DictToAggressiveness(); + _DictToVisibilityRange(); + _DictToVeterancy(); + _DictToShroudClearingDistance(); + _DictToRecruitableAI(); + _DictToSelectable(); + _DictToStoppingDistance(); + _DictToUnsellable(); + _DictToTargetable(); + ShowZOffset(pMapObj); + ShowAngle(pMapObj); + ShowPosition(pMapObj); + + // Warning: order is important. dictToAttachedSound() must come before dictToCustomize(), + // dictToCustomize() must come before any of the customization controls, dictToLooping() + // must come before dictToLoopCount(), and dictToLooping() and dictToLoopCount() must + // come before dictToEnabled(). + dictToAttachedSound(); + dictToCustomize(); + dictToLooping(); + dictToLoopCount(); + dictToEnabled(); + dictToMinVolume(); + dictToVolume(); + dictToMinRange(); + dictToMaxRange(); + dictToPriority(); +} + +//--------------------------------------------------------------------------------------------------- + +void MapObjectProps::InitSound() +{ + CComboBox * priorityComboBox = (CComboBox *)GetDlgItem(IDC_PRIORITY_COMBO); + DEBUG_ASSERTCRASH( priorityComboBox != nullptr, ("Cannot find sound priority combobox" ) ); + + if ( priorityComboBox != nullptr ) + { + Int i; + for ( i = 0; i <= AP_CRITICAL; i++ ) + { + Int index = priorityComboBox->InsertString( i,theAudioPriorityNames[i] ); + (void)index; + DEBUG_ASSERTCRASH( index == i, ("insert string returned %d, expected %d", index, i ) ); + } + } + + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + DEBUG_ASSERTCRASH( soundComboBox != nullptr, ("Cannot find sound combobox" ) ); + m_defaultEntryIndex = 0; + m_defaultIsNone = true; + + // Load up combobox + if ( soundComboBox != nullptr ) + { + // Add all the sound names in order. Since the combobox has the SORTED style, + // we can just add the strings in and let the combo box sort them + const AudioEventInfoHash & audioEventHash = TheAudio->getAllAudioEvents(); + + AudioEventInfoHash::const_iterator it; + for ( it = audioEventHash.begin(); it != audioEventHash.end(); it++ ) + { + if ( it->second->m_soundType == AT_SoundEffect ) + { + // Hmm, should we be filtering the list in any other way? Oh well. + soundComboBox->AddString( it->second->m_audioName.str() ); + } + } + + m_defaultEntryIndex = soundComboBox->InsertString( 0, BASE_DEFAULT_STRING ); + m_defaultEntryName = NO_SOUND_STRING; + m_defaultIsNone = true; + + soundComboBox->InsertString( 1, NO_SOUND_STRING ); + } + +} + + +// Adds a series of Undoable's to the given MultipleUndoable which clears the +// objectSoundAmbientCustomized flag and all the customization flags out of +// all the selected dictionaries. +// NOTE: assumes getAllSelectedDicts() has already been called +void MapObjectProps::clearCustomizeFlag( CWorldBuilderDoc* pDoc, MultipleUndoable * ownerUndoable ) +{ + Dict empty; + + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientCustomized, m_allSelectedDicts.size(), pDoc, true); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + // Note: we can set all the undoes in between the first and last undo to not invalidate, + // since the first (last for doing) and last invalidate after these changes anyway + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientMaxRange, m_allSelectedDicts.size(), pDoc, false); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientMinVolume, m_allSelectedDicts.size(), pDoc, false); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientVolume, m_allSelectedDicts.size(), pDoc, false); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientMinRange, m_allSelectedDicts.size(), pDoc, false); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientLooping, m_allSelectedDicts.size(), pDoc, false); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientLoopCount, m_allSelectedDicts.size(), pDoc, false); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. + + pUndo = new DictItemUndoable(getAllSelectedDictsData(), empty, TheKey_objectSoundAmbientPriority, m_allSelectedDicts.size(), pDoc, true); + ownerUndoable->addUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to ownerUndoable now. +} + +/// Move data from dialog controls to object(s) +void MapObjectProps::attachedSoundToDict() +{ + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + return; + + getAllSelectedDicts(); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + MultipleUndoable *pUndo = new MultipleUndoable; + + Dict newDict; + + // For the default, erase the objectSoundAmbient key + if ( soundComboBox->GetCurSel() != m_defaultEntryIndex ) + { + CString selectionText; + soundComboBox->GetLBText( soundComboBox->GetCurSel(), selectionText ); + if ( selectionText == NO_SOUND_STRING ) + { + newDict.setAsciiString(TheKey_objectSoundAmbient, ""); + // Can't customize the null sound + clearCustomizeFlag( pDoc, pUndo ); + } + else + { + newDict.setAsciiString(TheKey_objectSoundAmbient, static_cast< const char * >( selectionText) ); + } + } + else if ( m_defaultIsNone ) + { + // Can't customize the null sound + clearCustomizeFlag( pDoc, pUndo ); + } + + DictItemUndoable *pDictUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, TheKey_objectSoundAmbient, m_allSelectedDicts.size(), pDoc, true); + pUndo->addUndoable( pDictUndo ); + pDoc->AddAndDoUndoable( pUndo ); + REF_PTR_RELEASE( pDictUndo ); // belongs to pUndo + REF_PTR_RELEASE( pUndo ); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_VisibilityToDict() +/// Move data from dialog controls to object(s) +void MapObjectProps::customizeToDict() { - getAllSelectedDicts(); + CButton * customizeCheckbox = (CButton *)GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr ) + return; - int value = -1; - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_VisionDistance); - edit->EnableWindow(TRUE); - CString cstr; - edit->GetWindowText(cstr); - if (!cstr.IsEmpty()) { - value = atoi(cstr.GetBuffer(0)); - } + getAllSelectedDicts(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - if (value != -1) { - newDict.setInt(TheKey_objectVisualRange, value); - } - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, TheKey_objectVisualRange, m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + + // For space reasons, erase key instead of added "false" key. Should be treated the same + if ( customizeCheckbox->GetCheck() == 1 ) + { + newDict.setBool( TheKey_objectSoundAmbientCustomized, true ); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, TheKey_objectSoundAmbientCustomized, m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } + else + { + MultipleUndoable *pUndo = new MultipleUndoable; + clearCustomizeFlag( pDoc, pUndo ); + pDoc->AddAndDoUndoable( pUndo ); + REF_PTR_RELEASE( pUndo ); // belongs to pDoc now. + // Update is called by Doc + } + } } -void MapObjectProps::_VeterancyToDict() +/// Move data from dialog controls to object(s) +void MapObjectProps::enabledToDict() { - getAllSelectedDicts(); + CButton * enabledCheckbox = (CButton *)GetDlgItem(IDC_ENABLED_CHECKBOX); + if ( enabledCheckbox == nullptr ) + return; - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Veterancy); - static char buf[1024]; - int curSel = owner->GetCurSel(); - int value = 0; - if (curSel >= 0) { - value=curSel; - } + getAllSelectedDicts(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setInt(TheKey_objectVeterancy, value); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; -} + newDict.setBool( TheKey_objectSoundAmbientEnabled, enabledCheckbox->GetCheck() != 0 ); -void MapObjectProps::_WeatherToDict() + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } +} + +/// Move data from dialog controls to object(s) +void MapObjectProps::loopingToDict() { - getAllSelectedDicts(); + CButton * loopingCheckbox = (CButton *)GetDlgItem(IDC_LOOPING_CHECKBOX); + if ( loopingCheckbox == nullptr ) + return; - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Weather); - static char buf[1024]; - int curSel = owner->GetCurSel(); + getAllSelectedDicts(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setInt(TheKey_objectWeather, curSel); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + + newDict.setBool( TheKey_objectSoundAmbientLooping, loopingCheckbox->GetCheck() != 0 ); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_TimeToDict() +/// Move data from dialog controls to object(s) +void MapObjectProps::loopCountToDict() { - getAllSelectedDicts(); + CEdit * loopCountEdit = (CEdit *)GetDlgItem(IDC_LOOPCOUNT_EDIT); + if ( loopCountEdit == nullptr ) + return; - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_Time); - static char buf[1024]; - int curSel = owner->GetCurSel(); + getAllSelectedDicts(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setInt(TheKey_objectTime, curSel); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + + CString loopCountString; + loopCountEdit->GetWindowText(loopCountString); + newDict.setInt( TheKey_objectSoundAmbientLoopCount, atoi( loopCountString ) ); + + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_ShroudClearingDistanceToDict() +/// Move data from dialog controls to object(s) +void MapObjectProps::minVolumeToDict() { - getAllSelectedDicts(); + CEdit * minVolumeEdit = (CEdit *)GetDlgItem(IDC_MIN_VOLUME_EDIT); + if ( minVolumeEdit == nullptr ) + return; - int value = -1; - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ShroudClearingDistance); - edit->EnableWindow(TRUE); - CString cstr; - edit->GetWindowText(cstr); - if (!cstr.IsEmpty()) { - value = atoi(cstr.GetBuffer(0)); - } + getAllSelectedDicts(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - if (value != -1) { - newDict.setInt(TheKey_objectShroudClearingDistance, value); - } - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, TheKey_objectShroudClearingDistance, m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; -void MapObjectProps::_RecruitableAIToDict() -{ - getAllSelectedDicts(); + CString minVolumeString; + minVolumeEdit->GetWindowText(minVolumeString); - CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_RecruitableAI); - Bool isChecked = (owner->GetCheck() != 0); + // Note: min volume is stored as Real between 0.0 and 1.0, but displayed as a percentage from 0 to 100 + newDict.setReal( TheKey_objectSoundAmbientMinVolume, INT_TO_REAL( atoi( minVolumeString ) ) / 100.0f ); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool(TheKey_objectRecruitableAI, isChecked); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_SelectableToDict() +/// Move data from dialog controls to object(s) +void MapObjectProps::volumeToDict() { - getAllSelectedDicts(); + CEdit * volumeEdit = (CEdit *)GetDlgItem(IDC_VOLUME_EDIT); + if ( volumeEdit == nullptr ) + return; - CButton *owner = (CButton*) GetDlgItem(IDC_MAPOBJECT_Selectable); - Bool isChecked = (owner->GetCheck() != 0); + getAllSelectedDicts(); - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setBool(TheKey_objectSelectable, isChecked); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + + CString volumeString; + volumeEdit->GetWindowText(volumeString); + + // Note: volume is stored as Real between 0.0 and 1.0, but displayed as a percentage from 0 to 100 + newDict.setReal( TheKey_objectSoundAmbientVolume, INT_TO_REAL( atoi( volumeString ) ) / 100.0f ); + + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_HPsToDict() + +/// Move data from dialog controls to object(s) +void MapObjectProps::minRangeToDict() { - getAllSelectedDicts(); + CEdit * minRangeEdit = (CEdit *)GetDlgItem(IDC_MIN_RANGE_EDIT); + if ( minRangeEdit == nullptr ) + return; - Int value; - static char buf[1024]; + getAllSelectedDicts(); - CComboBox *owner = (CComboBox*)GetDlgItem(IDC_MAPOBJECT_HitPoints); - owner->GetWindowText(buf, sizeof(buf)-2); - value = atoi(buf); - if (value == 0) - value = -1; + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; + CString minRangeString; + minRangeEdit->GetWindowText(minRangeString); - newDict.setInt(TheKey_objectMaxHPs, value); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size()); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + newDict.setReal( TheKey_objectSoundAmbientMinRange, INT_TO_REAL( atoi( minRangeString ) ) ); + + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::_StoppingDistanceToDict() +/// Move data from dialog controls to object(s) +void MapObjectProps::maxRangeToDict() { - getAllSelectedDicts(); + CEdit * maxRangeEdit = (CEdit *)GetDlgItem(IDC_MAX_RANGE_EDIT); + if ( maxRangeEdit == nullptr ) + return; - Real value; - static char buf[1024]; + getAllSelectedDicts(); - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_StoppingDistance); - CString cstr; - edit->GetWindowText(cstr); - if (cstr.IsEmpty()) { - return; - } - value = atof(cstr.GetBuffer(0)); + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - Dict newDict; - newDict.setReal(TheKey_objectStoppingDistance, value); - DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Update is called by Do -} + CString maxRangeString; + maxRangeEdit->GetWindowText(maxRangeString); -void MapObjectProps::OnOK() -{ + newDict.setReal( TheKey_objectSoundAmbientMaxRange, INT_TO_REAL( atoi( maxRangeString ) ) ); + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } } -void MapObjectProps::OnCancel() -{ +/// Move data from dialog controls to object(s) +void MapObjectProps::priorityToDict() +{ + CComboBox * priorityComboBox = (CComboBox *)GetDlgItem(IDC_PRIORITY_COMBO); + if ( priorityComboBox == nullptr ) + return; + + getAllSelectedDicts(); + + CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); + if ( pDoc != nullptr ) + { + Dict newDict; + + newDict.setInt( TheKey_objectSoundAmbientPriority, priorityComboBox->GetCurSel() ); + + DictItemUndoable *pUndo = new DictItemUndoable(getAllSelectedDictsData(), newDict, newDict.getNthKey(0), m_allSelectedDicts.size(), pDoc, true); + pDoc->AddAndDoUndoable(pUndo); + REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Update is called by Doc + } +} + + +/// Move data from object to dialog controls +void MapObjectProps::dictToAttachedSound() +{ + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + return; + + // Update the string for the "default" entry + m_defaultIsNone = true; + m_defaultEntryName = NO_SOUND_STRING; + soundComboBox->DeleteString(m_defaultEntryIndex); + const ThingTemplate * thingTemplate = nullptr; + if (m_dictSource) + { + thingTemplate = m_dictSource->getThingTemplate(); + } + + if ( thingTemplate ) + { + AsciiString string( BASE_DEFAULT_STRING ); + + const AudioEventRTS * defaultAudioEvent; + + // Note: getSoundAmbient will return a non-null pointer even if there is no real sound attached to the object + if ( thingTemplate->hasSoundAmbient() ) + { + defaultAudioEvent = thingTemplate->getSoundAmbient(); + } + else + { + defaultAudioEvent = nullptr; + } + + if ( defaultAudioEvent == nullptr || defaultAudioEvent == TheAudio->getValidSilentAudioEvent() ) + { + string.concat( " " ); + } + else + { + string.concat( " <" ); + string.concat( defaultAudioEvent->getEventName() ); + string.concat( '>' ); + m_defaultEntryName = defaultAudioEvent->getEventName(); + m_defaultIsNone = false; + } + m_defaultEntryIndex = soundComboBox->InsertString(0, string.str()); + } + else + { + m_defaultEntryIndex = soundComboBox->InsertString(0, BASE_DEFAULT_STRING); + } + + // Now select the correct entry in the list box + AsciiString sound; + Bool exists = false; + if (m_dictToEdit) + { + sound = m_dictToEdit->getAsciiString(TheKey_objectSoundAmbient, &exists); + } + + if ( !exists ) + { + // Use the "default" entry + soundComboBox->SetCurSel( m_defaultEntryIndex ); + return; + } + + if ( sound.isEmpty() ) + { + // Use the entry "(None)" + sound = NO_SOUND_STRING; + } + + // Note: better than SelectString because we want the exact string not a prefix + Int index = soundComboBox->FindStringExact( -1, sound.str() ); + if ( index > -1 ) + { + soundComboBox->SetCurSel( index ); + } + else + { + DEBUG_CRASH( ("Could not find existing sound's name %s in combo box", sound.str() ) ); + soundComboBox->SetCurSel( m_defaultEntryIndex ); + } +} + +/// Move data from object to dialog controls +void MapObjectProps::dictToCustomize() +{ + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr ) + return; + + // If the current sound is "none", disable the customize button + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + return; + + int index = soundComboBox->GetCurSel(); + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || + ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + customizeCheckbox->SetCheck( 0 ); + customizeCheckbox->EnableWindow( false ); + return; + } + + // Sound is not "none", so we can customize if we wish + customizeCheckbox->EnableWindow( true ); + + Bool exists = false; + Bool customized = false; + if (m_dictToEdit) + { + customized = m_dictToEdit->getBool(TheKey_objectSoundAmbientCustomized, &exists); + } + + customizeCheckbox->SetCheck( exists && customized ? 1 : 0 ); +} + + +/// Move data from object to dialog controls +void MapObjectProps::dictToLooping() +{ + CButton * loopingCheckbox = ( CButton * )GetDlgItem(IDC_LOOPING_CHECKBOX); + if ( loopingCheckbox == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 ) + { + loopingCheckbox->EnableWindow( false ); + } + else + { + loopingCheckbox->EnableWindow( true ); + + // If customization is enabled, look to see if the looping flag has already been + // customized + Bool exists = false; + Bool looping = false; + if (m_dictToEdit) + { + looping = m_dictToEdit->getBool(TheKey_objectSoundAmbientLooping, &exists); + } + + if ( exists ) + { + loopingCheckbox->SetCheck( looping ? 1 : 0 ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the looping checkbox + + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + loopingCheckbox->SetCheck( 0 ); + return; + } + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + loopingCheckbox->SetCheck( 0 ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + loopingCheckbox->SetCheck( ( audioEventInfo && ( audioEventInfo->m_control & AC_LOOP ) ) ? 1 : 0 ); +} + +/// Move data from object to dialog controls +void MapObjectProps::dictToLoopCount() +{ + CEdit * loopCountEdit = ( CEdit * )GetDlgItem(IDC_LOOPCOUNT_EDIT); + if ( loopCountEdit == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + // If the looping checkbox is off, the loop count control is disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + CButton * loopingCheckbox = ( CButton * )GetDlgItem(IDC_LOOPING_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 || + loopingCheckbox == nullptr || loopingCheckbox->GetCheck() == 0 ) + { + loopCountEdit->EnableWindow( false ); + } + else + { + loopCountEdit->EnableWindow( true ); + + // If customization is enabled, look to see if the loop count has already been + // customized + Bool exists = false; + Int loopCount = 0; + if (m_dictToEdit) + { + loopCount = m_dictToEdit->getInt(TheKey_objectSoundAmbientLoopCount, &exists); + } + + if ( exists ) + { + CString loopCountText; + loopCountText.Format( "%d", loopCount ); + loopCountEdit->SetWindowText( loopCountText ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the loop count + + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + loopCountEdit->SetWindowText( "0" ); + return; + } + + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + loopCountEdit->SetWindowText( "0" ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + if ( audioEventInfo == nullptr ) + { + loopCountEdit->SetWindowText( "0" ); + return; + } + + CString loopCountText; + loopCountText.Format( "%d", audioEventInfo->m_loopCount ); + loopCountEdit->SetWindowText( loopCountText ); +} + +/// Move data from object to dialog controls +void MapObjectProps::dictToEnabled() +{ + CButton * enableCheckbox = ( CButton * )GetDlgItem(IDC_ENABLED_CHECKBOX); + if ( enableCheckbox == nullptr ) + return; + + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + + // If we don't have a sound, we can't enable it + CString currentString; + if ( soundComboBox == nullptr ) + { + enableCheckbox->EnableWindow( false ); + enableCheckbox->SetCheck( 0 ); + return; + } + + Int soundIndex = soundComboBox->GetCurSel(); + soundComboBox->GetLBText( soundIndex, currentString ); + if ( currentString == NO_SOUND_STRING || + ( soundIndex == m_defaultEntryIndex && m_defaultIsNone ) ) + { + enableCheckbox->SetCheck( 0 ); + enableCheckbox->EnableWindow( false ); + return; + } + else + { + enableCheckbox->EnableWindow( true ); + + // Look to see if the enabled flag has already been customized + Bool exists = false; + Bool enabled = false; + if (m_dictToEdit) + { + enabled = m_dictToEdit->getBool(TheKey_objectSoundAmbientEnabled, &exists); + } + + if ( exists ) + { + enableCheckbox->SetCheck( enabled ? 1 : 0 ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the enabled checkbox + + // Look up sound and see if it's looping. Looping-forever sounds start enabled; + // non-looping ones don't. + // Actually, by now, dictToLooping and dictToLoopCount will have looked up the + // info we need for us + // NOTE: This test should match the tests done in Object::updateObjValuesFromMapProperties() + // when it decided whether or not to enable a customized sound + CButton * loopingCheckbox = (CButton *)GetDlgItem(IDC_LOOPING_CHECKBOX); + CEdit * loopCountEdit = (CEdit *)GetDlgItem(IDC_LOOPCOUNT_EDIT); + if ( loopingCheckbox && loopCountEdit && loopingCheckbox->GetCheck() == 1 ) + { + CString loopCount; + loopCountEdit->GetWindowText( loopCount ); + + if ( atoi(loopCount) == 0 ) + { + enableCheckbox->SetCheck( 1 ); + return; + } + } + + enableCheckbox->SetCheck( 0 ); +} + + +/// Move data from object to dialog controls +void MapObjectProps::dictToMinVolume() +{ + CEdit * minVolumeEdit = ( CEdit * )GetDlgItem(IDC_MIN_VOLUME_EDIT); + if ( minVolumeEdit == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 ) + { + minVolumeEdit->EnableWindow( false ); + } + else + { + minVolumeEdit->EnableWindow( true ); + + // If customization is enabled, look to see if the minimum volume has already been + // customized + Bool exists = false; + Real minVolume = 0.0f; + if (m_dictToEdit) + { + minVolume = m_dictToEdit->getReal(TheKey_objectSoundAmbientMinVolume, &exists); + } + + if ( exists ) + { + // Note: min volume is stored as Real between 0.0 and 1.0, but displayed as a percentage from 0 to 100 + CString minVolumeText; + minVolumeText.Format( "%d", REAL_TO_INT( ( minVolume * 100.0f ) + 0.5 ) ); + minVolumeEdit->SetWindowText( minVolumeText ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the minimum volume + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + minVolumeEdit->SetWindowText( "40" ); + return; + } + + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + minVolumeEdit->SetWindowText( "40" ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + if ( audioEventInfo == nullptr ) + { + minVolumeEdit->SetWindowText( "40" ); + return; + } + + // Note: min volume is stored as Real between 0.0 and 1.0, but displayed as a percentage from 0 to 100 + CString minVolumeText; + minVolumeText.Format( "%d", REAL_TO_INT( ( audioEventInfo->m_minVolume * 100.0f ) + 0.5 ) ); + minVolumeEdit->SetWindowText( minVolumeText ); +} + +/// Move data from object to dialog controls +void MapObjectProps::dictToVolume() +{ + CEdit * volumeEdit = ( CEdit * )GetDlgItem(IDC_VOLUME_EDIT); + if ( volumeEdit == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 ) + { + volumeEdit->EnableWindow( false ); + } + else + { + volumeEdit->EnableWindow( true ); + + // If customization is enabled, look to see if the volume has already been + // customized + Bool exists = false; + Real volume = 0.0f; + if (m_dictToEdit) + { + volume = m_dictToEdit->getReal(TheKey_objectSoundAmbientVolume, &exists); + } + + if ( exists ) + { + // Note: min volume is stored as Real between 0.0 and 1.0, but displayed as a percentage from 0 to 100 + CString volumeText; + volumeText.Format( "%d", REAL_TO_INT( ( volume * 100.0f ) + 0.5 ) ); + volumeEdit->SetWindowText( volumeText ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the volume + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + volumeEdit->SetWindowText( "100" ); + return; + } + + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + volumeEdit->SetWindowText( "100" ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + if ( audioEventInfo == nullptr ) + { + volumeEdit->SetWindowText( "100" ); + return; + } + + // Note: volume is stored as Real between 0.0 and 1.0, but displayed as a percentage from 0 to 100 + CString volumeText; + volumeText.Format( "%d", REAL_TO_INT( ( audioEventInfo->m_volume * 100.0f ) + 0.5 ) ); + volumeEdit->SetWindowText( volumeText ); +} + + +/// Move data from object to dialog controls +void MapObjectProps::dictToMinRange() +{ + CEdit * minRangeEdit = ( CEdit * )GetDlgItem(IDC_MIN_RANGE_EDIT); + if ( minRangeEdit == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 ) + { + minRangeEdit->EnableWindow( false ); + } + else + { + minRangeEdit->EnableWindow( true ); + + // If customization is enabled, look to see if the minimum range has already been + // customized + Bool exists = false; + Real minRange = 0.0f; + if (m_dictToEdit) + { + minRange = m_dictToEdit->getReal(TheKey_objectSoundAmbientMinRange, &exists); + } + + if ( exists ) + { + CString minRangeText; + minRangeText.Format( "%d", REAL_TO_INT(minRange) ); + minRangeEdit->SetWindowText( minRangeText ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the minimum range + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + minRangeEdit->SetWindowText( "175" ); + return; + } + + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + minRangeEdit->SetWindowText( "175" ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + if ( audioEventInfo == nullptr ) + { + minRangeEdit->SetWindowText( "175" ); + return; + } + + CString minRangeText; + minRangeText.Format( "%d", REAL_TO_INT( audioEventInfo->m_minDistance ) ); + minRangeEdit->SetWindowText( minRangeText ); +} + + +/// Move data from object to dialog controls +void MapObjectProps::dictToMaxRange() +{ + CEdit * maxRangeEdit = ( CEdit * )GetDlgItem(IDC_MAX_RANGE_EDIT); + if ( maxRangeEdit == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 ) + { + maxRangeEdit->EnableWindow( false ); + } + else + { + maxRangeEdit->EnableWindow( true ); + + // If customization is enabled, look to see if the maximum range has already been + // customized + Bool exists = false; + Real maxRange = 0.0f; + if (m_dictToEdit) + { + maxRange = m_dictToEdit->getReal(TheKey_objectSoundAmbientMaxRange, &exists); + } + + if ( exists ) + { + CString maxRangeText; + maxRangeText.Format( "%d", REAL_TO_INT( maxRange ) ); + maxRangeEdit->SetWindowText( maxRangeText ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the minimum range + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + maxRangeEdit->SetWindowText( "600" ); + return; + } + + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + maxRangeEdit->SetWindowText( "600" ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + if ( audioEventInfo == nullptr ) + { + maxRangeEdit->SetWindowText( "600" ); + return; + } + + CString maxRangeText; + maxRangeText.Format( "%d", REAL_TO_INT( audioEventInfo->m_maxDistance ) ); + maxRangeEdit->SetWindowText( maxRangeText ); +} + +/// Move data from object to dialog controls +void MapObjectProps::dictToPriority() +{ + CComboBox * priorityComboBox = ( CComboBox * )GetDlgItem(IDC_PRIORITY_COMBO); + if ( priorityComboBox == nullptr ) + return; + + // If the customized checkbox is off, all customization controls are disabled + CButton * customizeCheckbox = ( CButton * )GetDlgItem(IDC_CUSTOMIZE_CHECKBOX); + if ( customizeCheckbox == nullptr || customizeCheckbox->GetCheck() == 0 ) + { + priorityComboBox->EnableWindow( false ); + } + else + { + priorityComboBox->EnableWindow( true ); + + // If customization is enabled, look to see if the maximum range has already been + // customized + Bool exists = false; + Int priorityEnum = AP_LOWEST; + if (m_dictToEdit) + { + priorityEnum = m_dictToEdit->getInt(TheKey_objectSoundAmbientPriority, &exists); + } + + if ( exists ) + { + if ( priorityEnum < 0 || priorityEnum > AP_CRITICAL ) + { + DEBUG_CRASH( ("Bad soundAmbientPriority key %d", priorityEnum ) ); + priorityEnum = AP_LOWEST; + } + + // Note: indexes of priority combobox map to priority enum + priorityComboBox->SetCurSel( priorityEnum ); + + // Don't use defaults, just return + return; + } + } + + // If we get here, we need the default for the priority + CComboBox * soundComboBox = (CComboBox *)GetDlgItem(IDC_SOUND_COMBO); + if ( soundComboBox == nullptr ) + { + priorityComboBox->SetCurSel( AP_LOWEST ); + return; + } + + Int index = soundComboBox->GetCurSel(); + + CString currentString; + soundComboBox->GetLBText( index, currentString ); + if ( currentString == NO_SOUND_STRING || ( index == m_defaultEntryIndex && m_defaultIsNone ) ) + { + priorityComboBox->SetCurSel( AP_LOWEST ); + return; + } + + if ( index == m_defaultEntryIndex ) + { + // Correct the current string e.g. remove "Default <" and ">" + currentString = m_defaultEntryName.str(); + } + + AudioEventInfo * audioEventInfo = TheAudio->findAudioEventInfo(static_cast< const char * >( currentString ) ); + + if ( audioEventInfo == nullptr ) + { + priorityComboBox->SetCurSel( AP_LOWEST ); + return; + } + + priorityComboBox->SetCurSel( audioEventInfo->m_priority ); +} + + +// Special message to handle pages being resized to new sheet size +// see knowledge base article Q143291 +const Int RESIZE_PAGE_MESSAGE = WM_USER + 117; -} +///////////////////////////////////////////////////////////////////////////// +// MapObjectProps message handlers -void MapObjectProps::ShowZOffset(MapObject *pMapObj) + + +void MapObjectProps::enableButtons() { - const Coord3D *loc = pMapObj->getLocation(); - static char buff[32]; - m_height = loc->z; - snprintf(buff, ARRAY_SIZE(buff), "%0.2f", loc->z); - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ZOffset); - edit->SetWindowText(buff); + // do nothing } -void MapObjectProps::SetZOffset() + +/*static*/ MapObject *MapObjectProps::getSingleSelectedMapObject() { - Real value = 0.0f; - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_ZOffset); - CString cstr; - edit->GetWindowText(cstr); - if (!cstr.IsEmpty()) { - value = atof(cstr); + MapObject *pMapObj; + MapObject *theMapObj = nullptr; +// Bool found = false; + Int selCount=0; + for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) { + if (pMapObj->isSelected()) { + if (!pMapObj->isWaypoint() && !pMapObj->isLight()) + { + theMapObj = pMapObj; + } + selCount++; + } } - m_height = value; - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - ModifyObjectUndoable *pUndo = new ModifyObjectUndoable(pDoc); - pDoc->AddAndDoUndoable(pUndo); - pUndo->SetZOffset(value); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + if (selCount==1 && theMapObj) { + return theMapObj; + } + return(nullptr); } -void MapObjectProps::ShowAngle(MapObject *pMapObj) -{ - m_angle = pMapObj->getAngle() * 180 / PI; - static char buff[32]; - snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_angle); - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_Angle); - edit->SetWindowText(buff); + + + +void MapObjectProps::OnOK() +{ + // Make sure CPropertySheet functions don't close the window } -void MapObjectProps::SetAngle() +void MapObjectProps::OnCancel() { - Real angle = 0.0f; - CWnd* edit = GetDlgItem(IDC_MAPOBJECT_Angle); - CString cstr; - edit->GetWindowText(cstr); - if (!cstr.IsEmpty()) { - angle = atof(cstr); - } - m_angle = angle; - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - ModifyObjectUndoable *pUndo = new ModifyObjectUndoable(pDoc); - pDoc->AddAndDoUndoable(pUndo); - pUndo->RotateTo(angle * PI/180); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. + // Make sure CPropertySheet functions don't close the window } + + void MapObjectProps::getAllSelectedDicts() { m_allSelectedDicts.clear(); @@ -1351,82 +2873,20 @@ Dict** MapObjectProps::getAllSelectedDictsData() #endif } -void MapObjectProps::GetPopSliderInfo(const long sliderID, long *pMin, long *pMax, long *pLineSize, long *pInitial) +/// Move data from dialog controls to object +void MapObjectProps::OnScaleOn() { - switch (sliderID) { - - case IDC_HEIGHT_POPUP: - *pMin = -50; - *pMax = 50; - *pInitial = m_height; - *pLineSize = 1; - break; - - case IDC_ANGLE_POPUP: - *pMin = 0; - *pMax = 360; - *pInitial = m_angle; - *pLineSize = 1; - break; - - default: - // uh-oh! - DEBUG_CRASH(("Slider message from unknown control")); - break; - } + _ScaleToDict(); } -void MapObjectProps::PopSliderChanged(const long sliderID, long theVal) +/// Move data from dialog controls to object +void MapObjectProps::OnScaleOff() { - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - CWnd* edit; - static char buff[32]; - switch (sliderID) { - case IDC_HEIGHT_POPUP: - if (!m_posUndoable) { - m_posUndoable = new ModifyObjectUndoable(pDoc); - pDoc->AddAndDoUndoable(m_posUndoable); - } - m_posUndoable->SetZOffset(theVal); - m_height = theVal; - snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_height); - edit = GetDlgItem(IDC_MAPOBJECT_ZOffset); - edit->SetWindowText(buff); - break; - - case IDC_ANGLE_POPUP: - if (!m_posUndoable) { - m_posUndoable = new ModifyObjectUndoable(pDoc); - pDoc->AddAndDoUndoable(m_posUndoable); - } - m_posUndoable->RotateTo(theVal * PI/180); - m_angle = theVal; - snprintf(buff, ARRAY_SIZE(buff), "%0.2f", m_angle); - edit = GetDlgItem(IDC_MAPOBJECT_Angle); - edit->SetWindowText(buff); - break; - - default: - // uh-oh! - DEBUG_CRASH(("Slider message from unknown control")); - break; - } + _ScaleToDict(); } -void MapObjectProps::PopSliderFinished(const long sliderID, long theVal) +/// Move data from dialog controls to object +void MapObjectProps::OnKillfocusMAPOBJECTXYPosition() { - switch (sliderID) { - case IDC_HEIGHT_POPUP: - case IDC_ANGLE_POPUP: - REF_PTR_RELEASE(m_posUndoable); // belongs to pDoc now. - m_posUndoable = nullptr; - break; - - default: - // uh-oh! - DEBUG_CRASH(("Slider message from unknown control")); - break; - } - + SetPosition(); } - diff --git a/Generals/Code/Tools/WorldBuilder/src/playerlistdlg.cpp b/Generals/Code/Tools/WorldBuilder/src/playerlistdlg.cpp index ce79975e5e8..2b7ccf5827a 100644 --- a/Generals/Code/Tools/WorldBuilder/src/playerlistdlg.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/playerlistdlg.cpp @@ -339,6 +339,7 @@ void PlayerListDlg::OnEditplayer() AfxMessageBox("Implement me. (Sorry.)"); return; +#if 0 Dict *playerDict = m_sides.getSideInfo(m_curPlayerIdx)->getDict(); AsciiString pnameold = playerDict->getAsciiString(TheKey_playerName); Bool isneutral = pnameold.isEmpty(); @@ -372,11 +373,11 @@ void PlayerListDlg::OnEditplayer() fixDefaultTeamName(m_sides, pnameold, pnamenew); Bool modified = m_sides.validateSides(); - (void)modified; DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnEditplayer")); updateTheUI(); } +#endif } void PlayerListDlg::OnRemoveplayer() @@ -843,97 +844,47 @@ void PlayerListDlg::OnChangePlayerdisplayname() updateTheUI(); } -void PlayerListDlg::OnAddskirmishplayers() +static void addSide(SidesList *sides, AsciiString faction, + AsciiString playerName, const wchar_t *playerUName) { - // PlyrCivilian - - AsciiString addedPTName = "FactionCivilian"; - AsciiString pname = "PlyrCivilian"; - UnicodeString pnameu; - pnameu = L"PlyrCivilian"; - - if (!m_sides.findSideInfo(pname)) { - - Dict newPlayerDict; - newPlayerDict.setAsciiString(TheKey_playerName, pname); - newPlayerDict.setBool(TheKey_playerIsHuman, false); - newPlayerDict.setUnicodeString(TheKey_playerDisplayName, pnameu); - newPlayerDict.setAsciiString(TheKey_playerFaction, addedPTName); - newPlayerDict.setAsciiString(TheKey_playerEnemies, ""); - newPlayerDict.setAsciiString(TheKey_playerAllies, ""); - - ensureValidPlayerName(&newPlayerDict); - m_sides.addSide(&newPlayerDict); - - Bool modified = m_sides.validateSides(); - (void)modified; - DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnNewplayer")); - } - - addedPTName = "FactionAmerica"; - pname = "SkirmishAmerica"; - pnameu = L"SkirmishAmerica"; - - if (!m_sides.findSideInfo(pname)) { - - Dict newPlayerDict; - newPlayerDict.setAsciiString(TheKey_playerName, pname); - newPlayerDict.setBool(TheKey_playerIsHuman, false); - newPlayerDict.setUnicodeString(TheKey_playerDisplayName, pnameu); - newPlayerDict.setAsciiString(TheKey_playerFaction, addedPTName); - newPlayerDict.setAsciiString(TheKey_playerEnemies, ""); - newPlayerDict.setAsciiString(TheKey_playerAllies, ""); - - ensureValidPlayerName(&newPlayerDict); - m_sides.addSide(&newPlayerDict); - - Bool modified = m_sides.validateSides(); - (void)modified; - DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnNewplayer")); - } - - addedPTName = "FactionChina"; - pname = "SkirmishChina"; - pnameu = L"SkirmishChina"; - - if (!m_sides.findSideInfo(pname)) { + if (!sides->findSideInfo(playerName)) { Dict newPlayerDict; - newPlayerDict.setAsciiString(TheKey_playerName, pname); + UnicodeString playerUStr; + playerUStr = playerUName; + newPlayerDict.setAsciiString(TheKey_playerName, playerName); newPlayerDict.setBool(TheKey_playerIsHuman, false); - newPlayerDict.setUnicodeString(TheKey_playerDisplayName, pnameu); - newPlayerDict.setAsciiString(TheKey_playerFaction, addedPTName); + newPlayerDict.setUnicodeString(TheKey_playerDisplayName, playerUStr); + newPlayerDict.setAsciiString(TheKey_playerFaction, faction); newPlayerDict.setAsciiString(TheKey_playerEnemies, ""); newPlayerDict.setAsciiString(TheKey_playerAllies, ""); ensureValidPlayerName(&newPlayerDict); - m_sides.addSide(&newPlayerDict); + sides->addSide(&newPlayerDict); - Bool modified = m_sides.validateSides(); + Bool modified = sides->validateSides(); (void)modified; DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnNewplayer")); } +} - addedPTName = "FactionGLA"; - pname = "SkirmishGLA"; - pnameu = L"SkirmishGLA"; - - if (!m_sides.findSideInfo(pname)) { - - Dict newPlayerDict; - newPlayerDict.setAsciiString(TheKey_playerName, pname); - newPlayerDict.setBool(TheKey_playerIsHuman, false); - newPlayerDict.setUnicodeString(TheKey_playerDisplayName, pnameu); - newPlayerDict.setAsciiString(TheKey_playerFaction, addedPTName); - newPlayerDict.setAsciiString(TheKey_playerEnemies, ""); - newPlayerDict.setAsciiString(TheKey_playerAllies, ""); - - ensureValidPlayerName(&newPlayerDict); - m_sides.addSide(&newPlayerDict); +void PlayerListDlg::OnAddskirmishplayers() +{ + // PlyrCivilian - Bool modified = m_sides.validateSides(); - (void)modified; - DEBUG_ASSERTLOG(!modified,("had to clean up sides in PlayerListDlg::OnNewplayer")); - } + addSide(&m_sides, "FactionCivilian", "PlyrCivilian", L"PlyrCivilian"); + addSide(&m_sides, "FactionAmerica", "SkirmishAmerica", L"SkirmishAmerica"); + addSide(&m_sides, "FactionChina", "SkirmishChina", L"SkirmishChina"); + addSide(&m_sides, "FactionGLA", "SkirmishGLA", L"SkirmishGLA"); + + addSide(&m_sides, "FactionAmericaAirForceGeneral", "SkirmishAmericaAirForceGeneral", L"SkirmishAmericaAirForceGeneral"); + addSide(&m_sides, "FactionAmericaLaserGeneral", "SkirmishAmericaLaserGeneral", L"SkirmishAmericaLaserGeneral"); + addSide(&m_sides, "FactionAmericaSuperWeaponGeneral", "SkirmishAmericaSuperWeaponGeneral", L"SkirmishAmericaSuperWeaponGeneral"); + addSide(&m_sides, "FactionChinaTankGeneral", "SkirmishChinaTankGeneral", L"SkirmishChinaTankGeneral"); + addSide(&m_sides, "FactionChinaNukeGeneral", "SkirmishChinaNukeGeneral", L"SkirmishChinaNukeGeneral"); + addSide(&m_sides, "FactionChinaInfantryGeneral", "SkirmishChinaInfantryGeneral", L"SkirmishChinaInfantryGeneral"); + addSide(&m_sides, "FactionGLADemolitionGeneral", "SkirmishGLADemolitionGeneral", L"SkirmishGLADemolitionGeneral"); + addSide(&m_sides, "FactionGLAToxinGeneral", "SkirmishGLAToxinGeneral", L"SkirmishGLAToxinGeneral"); + addSide(&m_sides, "FactionGLAStealthGeneral", "SkirmishGLAStealthGeneral", L"SkirmishGLAStealthGeneral"); updateTheUI(); } diff --git a/Generals/Code/Tools/WorldBuilder/src/teamsdialog.cpp b/Generals/Code/Tools/WorldBuilder/src/teamsdialog.cpp index 63b62e8f2d9..708f44fa6d5 100644 --- a/Generals/Code/Tools/WorldBuilder/src/teamsdialog.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/teamsdialog.cpp @@ -30,6 +30,7 @@ #include "TeamGeneric.h" #include "TeamIdentity.h" #include "TeamReinforcement.h" +#include "TeamObjectProperties.h" #include "WorldBuilderDoc.h" #include "CUndoable.h" #include "wbview3d.h" @@ -296,7 +297,7 @@ void CTeamsDialog::OnDeleteteam() void CTeamsDialog::OnEditTemplate() { CPropertySheet editDialog; - editDialog.Construct("Edit Team:"); + editDialog.Construct("Edit Team Template."); TeamIdentity identity; identity.setTeamDict(m_sides.getTeamInfo(m_curTeam)->getDict()); identity.setSidesList(&m_sides); @@ -308,10 +309,13 @@ void CTeamsDialog::OnEditTemplate() TeamGeneric generic; generic.setTeamDict(m_sides.getTeamInfo(m_curTeam)->getDict()); + TeamObjectProperties object(m_sides.getTeamInfo(m_curTeam)->getDict()); + editDialog.AddPage(&identity); editDialog.AddPage(&reinforcements); editDialog.AddPage(&behavior); editDialog.AddPage(&generic); + editDialog.AddPage(&object); if (IDOK == editDialog.DoModal()) { } diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview.cpp index a087a7cb8f9..21315478432 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview.cpp @@ -20,7 +20,9 @@ // #include "StdAfx.h" +#include "resource.h" #include "CUndoable.h" +#include "CFixTeamOwnerDialog.h" #include "WorldBuilder.h" #include "WorldBuilderDoc.h" #include "wbview.h" @@ -32,6 +34,7 @@ #include "GlobalLightOptions.h" #include "playerlistdlg.h" #include "teamsdialog.h" +#include "LayersList.h" Bool WbView::m_snapToGrid = false; @@ -46,7 +49,8 @@ WbView::WbView() : m_hysteresis(0), m_lockAngle(false), m_doLightFeedback(FALSE), - m_pickConstraint(ES_NONE) + m_pickConstraint(ES_NONE), + m_doRulerFeedback(RULER_NONE) { Int showWay = ::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowWaypoints", 1); m_showWaypoints = (showWay!=0); @@ -105,6 +109,7 @@ BEGIN_MESSAGE_MAP(WbView, CView) ON_COMMAND(ID_EDIT_PLAYERLIST, OnEditPlayerlist) ON_COMMAND(ID_EDIT_WORLDINFO, OnEditWorldinfo) ON_COMMAND(ID_EDIT_TEAMLIST, OnEditTeamlist) + ON_COMMAND(ID_TEAM_EDIT, OnEditTeamlist) ON_UPDATE_COMMAND_UI(ID_OBJECTPROPERTIES_REFLECTSINMIRROR, OnUpdateObjectpropertiesReflectsinmirror) ON_COMMAND(ID_EDIT_PICKSTRUCTS, OnPickStructures) ON_UPDATE_COMMAND_UI(ID_EDIT_PICKSTRUCTS, OnUpdatePickStructures) @@ -208,6 +213,19 @@ void WbView::mouseMove(TTrackingMode m, CPoint viewPt) if (CMainFrame::GetMainFrame()->isAutoSaving()) { return; } + + if (m_doRulerFeedback != RULER_NONE) { + // If the user is measuring stuff, no need to do the rest of the text. + CString str; + if (m_doRulerFeedback == RULER_CIRCLE) { + str.Format("Diameter (in feet): %f", m_rulerLength * 2.0f); + } else { + str.Format("Length (in feet): %f", m_rulerLength); + } + CMainFrame::GetMainFrame()->SetMessageText(str); + return; + } + // Generate the status text display with coordinates and height. Coord3D cpt; viewToDocCoords(viewPt, &cpt); @@ -244,7 +262,12 @@ void WbView::mouseMove(TTrackingMode m, CPoint viewPt) } Real height = TheTerrainRenderObject->getHeightMapHeight(cpt.x, cpt.y, nullptr); CString str, str2, str3; - str.Format("%d object(s), ", totalObjects); + // If a layer has been activated, display it. + if (strcmp(AsciiString::TheEmptyString.str(), LayersList::TheActiveLayerName.c_str()) != 0) { + str.Format("Active Layer: (%s) %d object(s), ", LayersList::TheActiveLayerName.c_str(), totalObjects); + } else { + str.Format("%d object(s), ", totalObjects); + } str2.Format("%d waypoint(s), ", totalWaypoints); str3.Format("(%.2f,%.2f), height %.2f", cpt.x, cpt.y, height); str += str2; @@ -910,25 +933,116 @@ void WbView::OnUpdateShowNames(CCmdUI* pCmdUI) void WbView::OnValidationFixTeams() { - std::vector allTeamDicts; - Int numTeams = TheSidesList->getNumTeams(); - // Get all team dicts in the map - for (Int i = 0; i < numTeams; ++i) + Bool anyFixes = false; + Int i; + // Check for duplicate teams. + for (i = 0; i < TheSidesList->getNumTeams(); ++i) { - allTeamDicts.push_back(TheSidesList->getTeamInfo(i)->getDict()); + Dict *d = TheSidesList->getTeamInfo(i)->getDict(); + + AsciiString tname = d->getAsciiString(TheKey_teamName); + Int j; + for (j=0; jgetTeamInfo(j)->getDict(); + if (prevd->getAsciiString(TheKey_teamName).compare(tname)==0) { + anyFixes = true; + CString msg; + msg.Format(IDS_DUPLICATE_TEAM_REMOVED, tname.str()); + AfxMessageBox(msg, MB_OK); + TheSidesList->removeTeam(i); + i--; + break; + } + } } - Dict newDict; - newDict.setBool(TheKey_teamExecutesActionsOnCreate, false); + // Check for teams with invalid owners. + for (i = 0; i < TheSidesList->getNumTeams(); ++i) + { + Dict *d = TheSidesList->getTeamInfo(i)->getDict(); + AsciiString oname = d->getAsciiString(TheKey_teamOwner); + AsciiString tname = d->getAsciiString(TheKey_teamName); + SidesInfo* pSide = TheSidesList->findSideInfo(oname); + Bool found = pSide!=nullptr; + if (!found) { + CString msg; + msg.Format(IDS_PLAYERLESS_TEAM_REMOVED, tname.str(), oname.str()); + AfxMessageBox(msg, MB_OK); + anyFixes = true; + TheSidesList->removeTeam(i); + i--; + } + } + + // Check for objects with invalid teams. [8/8/2003] + MapObject *pMapObj; + for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) + { + // there is no validation code for these items as of yet. + if (pMapObj->isScorch() || pMapObj->isWaypoint() || pMapObj->isLight() || pMapObj->getFlag(FLAG_ROAD_FLAGS) || pMapObj->getFlag(FLAG_BRIDGE_FLAGS)) + { + continue; + } + + if (pMapObj->getThingTemplate()==nullptr) { + continue; // Objects that don't have templates don't need teams. [8/8/2003] + } + // at this point, only objects with models and teams should be left to process + + AsciiString name = pMapObj->getName(); + AsciiString tmplName = pMapObj->getThingTemplate()->getName(); + + // the following code verifies and fixes the team name, player name, and faction linkages + Bool teamExists; + AsciiString teamName = pMapObj->getProperties()->getAsciiString(TheKey_originalOwner, &teamExists); + if (teamExists) { + TeamsInfo *teamInfo = TheSidesList->findTeamInfo(teamName); + if (teamInfo) { + AsciiString teamOwner = teamInfo->getDict()->getAsciiString(TheKey_teamOwner); + SidesInfo* pSide = TheSidesList->findSideInfo(teamOwner); + if (!pSide) { + teamExists = false; + DEBUG_LOG(("Side '%s' could not be found in sides list!", teamOwner.str())); + } + } else { + // Couldn't find team. [8/8/2003] + teamExists = false; + } + } else { + // Object doesn't even have a team name at all. bad. jba. [8/8/2003] + teamExists = false; + } + if (!teamExists) { + // Query the user for a player, and stick it on the default team. [8/8/2003] + AsciiString warning; + warning.format("Object '%s' named '%s' on team '%s' - team doesn't exist. Select player for object...", + tmplName.str(), name.str(), teamName.str()); + + anyFixes = true; + ::AfxMessageBox(warning.str(), MB_OK); + TeamsInfo ti; + CFixTeamOwnerDialog fix(&ti, TheSidesList); + if (fix.DoModal() == IDOK) { + if (fix.pickedValidTeam()) { + AsciiString team; + team.set("team"); + team.concat(fix.getSelectedOwner()); + if (TheSidesList->findTeamInfo(team)==nullptr) { + team.set("team"); // neutral. + } + pMapObj->getProperties()->setAsciiString(TheKey_originalOwner, team); + } + } + } + } - // Now, do the Undoable - CWorldBuilderDoc* pDoc = CWorldBuilderDoc::GetActiveDoc(); - DictItemUndoable *pUndo = new DictItemUndoable(&allTeamDicts.front(), newDict, newDict.getNthKey(0), allTeamDicts.size(), pDoc, true); - pDoc->AddAndDoUndoable(pUndo); - REF_PTR_RELEASE(pUndo); // belongs to pDoc now. - // Show a message indicating success. - AfxMessageBox(IDS_TEAMS_FIXED); + if (anyFixes) { + // Show a message indicating success. + AfxMessageBox(IDS_TEAMS_FIXED, MB_OK|MB_ICONWARNING); + } else { + AfxMessageBox(IDS_NO_PROBLEMS, MB_OK); + } } void WbView::OnShowTerrain() @@ -963,3 +1077,9 @@ int WbView::OnCreate(LPCREATESTRUCT lpcs) return CView::OnCreate(lpcs); } +void WbView::rulerFeedbackInfo(Coord3D &point1, Coord3D &point2, Real dist) +{ + m_rulerPoints[0] = point1; + m_rulerPoints[1] = point2; + m_rulerLength = dist; +} diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index 1d824b032f0..fc44730ad83 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -29,6 +29,7 @@ #include "WW3D2/intersec.h" #include "W3DDevice/GameClient/W3DAssetManager.h" #include "W3DDevice/GameClient/Module/W3DModelDraw.h" +#include "W3DDevice/GameClient/Module/W3DTreeDraw.h" #include "WW3D2/agg_def.h" #include "WW3D2/part_ldr.h" #include "WW3D2/hanim.h" @@ -203,17 +204,17 @@ class PlaceholderView : public View virtual void initHeightForMap() override {}; ///< Init the camera height for the map at the current position. virtual void scrollBy( Coord2D *delta ){}; ///< Shift the view by the given delta virtual void moveCameraTo(const Coord3D *o, Int frames, Int shutter, - Bool orient) {lookAt(o);}; + Bool orient, Real easeIn, Real easeOut) override {lookAt(o);}; virtual void moveCameraAlongWaypointPath(Waypoint *way, Int frames, Int shutter, - Bool orient) {}; + Bool orient, Real easeIn, Real easeOut) override {}; virtual Bool isCameraMovementFinished() override {return true;}; - virtual void resetCamera(const Coord3D *location, Int frames) {}; ///< Move camera to location, and reset to default angle & zoom. - virtual void rotateCamera(Real rotations, Int frames) {}; ///< Rotate camera about current viewpoint. - virtual void rotateCameraTowardObject(ObjectID id, Int milliseconds, Int holdMilliseconds) {}; ///< Rotate camera to face an object, and hold on it - virtual void cameraModFinalZoom(Real finalZoom){}; ///< Final zoom for current camera movement. + virtual void resetCamera(const Coord3D *location, Int frames, Real easeIn, Real easeOut) override {}; ///< Move camera to location, and reset to default angle & zoom. + virtual void rotateCamera(Real rotations, Int frames, Real easeIn, Real easeOut) override {}; ///< Rotate camera about current viewpoint. + virtual void rotateCameraTowardObject(ObjectID id, Int milliseconds, Int holdMilliseconds, Real easeIn, Real easeOut) override {}; ///< Rotate camera to face an object, and hold on it + virtual void cameraModFinalZoom(Real finalZoom, Real easeIn, Real easeOut) override {}; ///< Final zoom for current camera movement. virtual void cameraModRollingAverage(Int framesToAverage) override {}; ///< Number of frames to average movement for current camera movement. virtual void cameraModFinalTimeMultiplier(Int finalMultiplier) override {}; ///< Final time multiplier for current camera movement. - virtual void cameraModFinalPitch(Real finalPitch){}; ///< Final pitch for current camera movement. + virtual void cameraModFinalPitch(Real finalPitch, Real easeIn, Real easeOut) override {}; ///< Final pitch for current camera movement. virtual void cameraModFreezeTime() override {} ///< Freezes time during the next camera movement. virtual void cameraModFreezeAngle() override {} ///< Freezes time during the next camera movement. virtual void cameraModLookToward(Coord3D *pLoc) override {} ///< Sets a look at point during camera movement. @@ -223,8 +224,8 @@ class PlaceholderView : public View virtual Int getTimeMultiplier() override {return 1;}; ///< Get the time multiplier. virtual void setTimeMultiplier(Int multiple) override {}; ///< Set the time multiplier. virtual void setDefaultView(Real pitch, Real angle, Real maxHeight) override {}; - virtual void zoomCamera( Real finalZoom, Int milliseconds ) {}; - virtual void pitchCamera( Real finalPitch, Int milliseconds ) {}; + virtual void zoomCamera( Real finalZoom, Int milliseconds, Real easeIn, Real easeOut ) override {}; + virtual void pitchCamera( Real finalPitch, Int milliseconds, Real easeIn, Real easeOut ) override {}; virtual void setAngle( Real angle ) override {}; ///< Rotate the view around the up axis to the given angle virtual Real getAngle() override { return 0; } @@ -399,7 +400,13 @@ WbView3d::WbView3d() : m_curTrackingZ(10), m_ww3dInited(false), m_showLayersList(false), - m_showMapBoundaries(false) + m_showMapBoundaries(false), + m_showBoundingBoxes(false), + m_showSightRanges(false), + m_showWeaponRanges(false), + m_highlightTestArt(false), + m_showLetterbox(false), + m_showSoundCircles(false) { TheTacticalView = &bogusTacticalView; m_actualWinSize.x = ::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "Width", THREE_D_VIEW_WIDTH); @@ -416,10 +423,17 @@ WbView3d::WbView3d() : m_showEntireMap = (::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowEntireMap", 1) != 0); m_projection = (::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowTopDownView", 0) != 0); m_showShadows = (::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowShadows", 1) != 0); + TheWritableGlobalData->m_useShadowDecals = m_showShadows; + TheWritableGlobalData->m_useShadowVolumes = m_showShadows; TheWritableGlobalData->m_showSoftWaterEdge = (::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowSoftWater", 1) != 0); TheWritableGlobalData->m_use3WayTerrainBlends = (::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowExtraBlends", 1) > 1 ? 2 : 1); setShowModels(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowModels", 1) != 0); + setShowBoundingBoxes(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowBoundingBoxes", 0) != 0); + setShowSightRanges(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowSightRanges", 0) != 0); + setShowWeaponRanges(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowWeaponRanges", 0) != 0); setShowGarrisoned(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowGarrisoned", 0) != 0); + setHighlightTestArt(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "HighlightTestArt", 0) != 0); + setShowLetterbox(::AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowLetterbox", 0) != 0); } // ---------------------------------------------------------------------------- @@ -432,13 +446,27 @@ WbView3d::~WbView3d() REF_PTR_RELEASE(m_lightFeedbackMesh[i]); } } - + REF_PTR_RELEASE(m_drawObject) ; + REF_PTR_RELEASE(m_heightMapRenderObj); W3DShaderManager::shutdown(); shutdownWW3D(); } // ---------------------------------------------------------------------------- void WbView3d::shutdownWW3D() { + delete m_intersector; + m_intersector = nullptr; + + delete m_layer; + m_layer = nullptr; + + delete m_buildLayer; + m_buildLayer = nullptr; + + if (m3DFont) { + m3DFont->Release(); + m3DFont = nullptr; + } if (m_ww3dInited) { m_lightList.Reset_List(); @@ -473,20 +501,6 @@ void WbView3d::shutdownWW3D() WWMath::Shutdown(); } m_ww3dInited = false; - - delete m_intersector; - m_intersector = nullptr; - - delete m_layer; - m_layer = nullptr; - - delete m_buildLayer; - m_buildLayer = nullptr; - - if (m3DFont) { - m3DFont->Release(); - m3DFont = nullptr; - } } //============================================================================= @@ -503,6 +517,9 @@ void WbView3d::ReleaseResources() m3DFont->Release(); } m3DFont = nullptr; + if (m_drawObject) { + m_drawObject->freeMapResources(); + } } //============================================================================= @@ -517,6 +534,7 @@ void WbView3d::ReAcquireResources() TheTerrainRenderObject->loadRoadsAndBridges(nullptr,FALSE); TheTerrainRenderObject->worldBuilderUpdateBridgeTowers( m_assetManager, m_scene ); } + m_drawObject->initData(); IDirect3DDevice8* pDev = DX8Wrapper::_Get_D3D_Device8(); if (pDev) { @@ -637,7 +655,7 @@ void WbView3d::setupCamera() pos.y = m_centerPt.Y* MAP_XY_FACTOR; pos.z = m_centerPt.Z* MAP_XY_FACTOR; - Real groundLevel = getHeightAroundPos(m_heightMapRenderObj, pos.x, pos.y); + Real groundLevel = m_heightMapRenderObj?getHeightAroundPos(m_heightMapRenderObj, pos.x, pos.y) : 0; // set position of camera itself /* @@ -703,7 +721,7 @@ void WbView3d::setupCamera() // build new camera transform camtransform.Make_Identity(); - if (factor+zOffset < 0) { + if (factor < 0) { //WST 11/11/02. Fix camera flipping over when near the ground too early targetPos = sourcePos + (sourcePos-targetPos); } camtransform.Look_At( sourcePos, targetPos, 0 ); @@ -715,17 +733,21 @@ void WbView3d::setupCamera() m_camera->Get_Clip_Planes(nearZ, farZ); m_camera->Set_Clip_Planes(lookDistance/200, lookDistance*3); - if (m_projection) { - camtransform.Make_Identity(); - camtransform.Set_Translation(Vector3(targetPos.X, targetPos.Y, lookDistance)); - m_heightMapRenderObj->setFlattenHeights(true); - //m_camera->Set_Projection_Type(CameraClass::ORTHO); - } else { - m_heightMapRenderObj->setFlattenHeights(false); - //m_camera->Set_Projection_Type(CameraClass::PERSPECTIVE); + if (m_heightMapRenderObj) { + if (m_projection) { + camtransform.Make_Identity(); + camtransform.Set_Translation(Vector3(targetPos.X, targetPos.Y, lookDistance)); + m_heightMapRenderObj->setFlattenHeights(true); + //m_camera->Set_Projection_Type(CameraClass::ORTHO); + } else { + m_heightMapRenderObj->setFlattenHeights(false); + //m_camera->Set_Projection_Type(CameraClass::PERSPECTIVE); + } } m_camera->Set_Transform( camtransform ); - m_heightMapRenderObj->setDrawEntireMap(m_showEntireMap); + if (m_heightMapRenderObj) { + m_heightMapRenderObj->setDrawEntireMap(m_showEntireMap); + } // not needed, handled in OnSize // m_camera->Set_Aspect_Ratio((float)m_actualWinSize.x/(float)m_actualWinSize.y); } @@ -823,8 +845,11 @@ void WbView3d::resetRenderObjects() TheW3DShadowManager->Reset(); updateLights(); - if (m_heightMapRenderObj) + if (m_heightMapRenderObj) { m_scene->Add_Render_Object(m_heightMapRenderObj); + m_heightMapRenderObj->removeAllTrees(); + m_heightMapRenderObj->removeAllProps(); + } } // ---------------------------------------------------------------------------- @@ -978,6 +1003,40 @@ void WbView3d::updateScorches() } } +// ---------------------------------------------------------------------------- +void WbView3d::updateTrees() +{ + TheTerrainRenderObject->removeAllTrees(); + TheTerrainRenderObject->removeAllProps(); + MapObject *pMapObj; + for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) + { + const ThingTemplate *tTemplate; + + tTemplate = pMapObj->getThingTemplate(); + if (tTemplate && tTemplate->isKindOf(KINDOF_OPTIMIZED_TREE) ) + { + Real scale = tTemplate->getAssetScale(); + const ModuleInfo& mi = tTemplate->getDrawModuleInfo(); + if (mi.getCount() > 0) + { + const ModuleData* mdd = mi.getNthData(0); + AsciiString name = KEYNAME(mdd->getModuleTagNameKey()); + const W3DTreeDrawModuleData* md = mdd ? mdd->getAsW3DTreeDrawModuleData(): nullptr; + if (md) + { + Coord3D pos = *pMapObj->getLocation(); + if (m_heightMapRenderObj) { + pos.z += m_heightMapRenderObj->getHeightMapHeight(pos.x, pos.y, nullptr); + TheTerrainRenderObject->addTree((DrawableID)(Int)pMapObj, pos, scale, pMapObj->getAngle(), + 0.0f /*no random scaling*/, md); + } + } + } + } + } +} + // ---------------------------------------------------------------------------- void WbView3d::invalidateCellInView(int xIndex, int yIndex) { @@ -1001,7 +1060,7 @@ void WbView3d::updateFenceListObjects(MapObject *pObject) AsciiString modelName = getModelNameAndScale(pMapObj, &scale, BODY_PRISTINE); // set render object, or create if we need to if( renderObj == nullptr && modelName.isEmpty() == FALSE && - strncmp( modelName.str(), "No ", 3 ) != 0 ) + strncmp( modelName.str(), "No ", 3 ) ) { renderObj = m_assetManager->Create_Render_Obj( modelName.str(), scale, 0); @@ -1061,6 +1120,14 @@ AsciiString WbView3d::getBestModelName(const ThingTemplate* tt, const ModelCondi { return md->getBestModelNameForWB(c); } + + // TheSuperHackers @bugfix ViTeXFTW 15/02/2026 Fix tree objects not showing a preview in + // WB object placer. The W3DTreeDraw module stores its model name differently from W3DModelDraw. + const W3DTreeDrawModuleData* treeData = mdd ? mdd->getAsW3DTreeDrawModuleData() : nullptr; + if (treeData) + { + return treeData->m_modelName; + } } } // removing this crash as sounds can (and should) have no model - jkmcd @@ -1127,7 +1194,7 @@ void WbView3d::invalBuildListItemInView(BuildListInfo *pBuildToInval) } // set render object, or create if we need to if( renderObj == nullptr && modelName.isEmpty() == FALSE && - strncmp( modelName.str(), "No ", 3 ) != 0 ) + strncmp( modelName.str(), "No ", 3 ) ) { renderObj = m_assetManager->Create_Render_Obj( modelName.str(), scale, playerColor); @@ -1289,6 +1356,7 @@ AsciiString WbView3d::getModelNameAndScale(MapObject *pMapObj, Real *scale, Body void WbView3d::invalObjectInView(MapObject *pMapObjIn) { ++m_updateCount; + Bool updateAllTrees = false; if (m_heightMapRenderObj == nullptr) { m_heightMapRenderObj = NEW_REF(WBHeightMap,()); @@ -1306,6 +1374,7 @@ void WbView3d::invalObjectInView(MapObject *pMapObjIn) MapObject *pMapObj; for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext()) { + if (found) break; if (pMapObjIn == pMapObj) found = true; if (pMapObjIn != nullptr && !found) { @@ -1330,6 +1399,15 @@ void WbView3d::invalObjectInView(MapObject *pMapObjIn) Coord3D loc = *pMapObj->getLocation(); loc.z += m_heightMapRenderObj->getHeightMapHeight(loc.x, loc.y, nullptr); + const ThingTemplate *tTemplate = pMapObj->getThingTemplate(); + if (tTemplate && tTemplate->isKindOf(KINDOF_OPTIMIZED_TREE)) { + if (!m_heightMapRenderObj->updateTreePosition((DrawableID)(Int)pMapObj, loc, pMapObj->getAngle())) { + // Couldn't find it, so update them all. [5/27/2003] + updateAllTrees = true; + } + if (found) break; + } + RenderObjClass *renderObj=nullptr; Shadow *shadowObj=nullptr; @@ -1337,62 +1415,60 @@ void WbView3d::invalObjectInView(MapObject *pMapObjIn) Int playerColor = 0xFFFFFF; BodyDamageType curDamageState = BODY_PRISTINE; Bool isVehicle = false; - if (pMapObj) + + Bool exists; + if (tTemplate && !(pMapObj->getFlags() & FLAG_DONT_RENDER)) { - Bool exists; - const ThingTemplate* tt = pMapObj->getThingTemplate(); - if (tt && !(pMapObj->getFlags() & FLAG_DONT_RENDER)) - { - isVehicle = tt->isKindOf(KINDOF_VEHICLE); - AsciiString objectTeamName = pMapObj->getProperties()->getAsciiString(TheKey_originalOwner, &exists); - if (exists) { - TeamsInfo *teamInfo = TheSidesList->findTeamInfo(objectTeamName); - if (teamInfo) { - AsciiString teamOwner = teamInfo->getDict()->getAsciiString(TheKey_teamOwner); - SidesInfo* pSide = TheSidesList->findSideInfo(teamOwner); - if (pSide) { - Bool hasColor = false; - Int color = pSide->getDict()->getInt(TheKey_playerColor, &hasColor); - if (hasColor) { - playerColor = color; - } else { - AsciiString tmplname = pSide->getDict()->getAsciiString(TheKey_playerFaction); - const PlayerTemplate* pt = ThePlayerTemplateStore->findPlayerTemplate(NAMEKEY(tmplname)); - if (pt) { - playerColor = pt->getPreferredColor()->getAsInt(); - } + isVehicle = tTemplate->isKindOf(KINDOF_VEHICLE); + AsciiString objectTeamName = pMapObj->getProperties()->getAsciiString(TheKey_originalOwner, &exists); + if (exists) { + TeamsInfo *teamInfo = TheSidesList->findTeamInfo(objectTeamName); + if (teamInfo) { + AsciiString teamOwner = teamInfo->getDict()->getAsciiString(TheKey_teamOwner); + SidesInfo* pSide = TheSidesList->findSideInfo(teamOwner); + if (pSide) { + Bool hasColor = false; + Int color = pSide->getDict()->getInt(TheKey_playerColor, &hasColor); + if (hasColor) { + playerColor = color; + } else { + AsciiString tmplname = pSide->getDict()->getAsciiString(TheKey_playerFaction); + const PlayerTemplate* pt = ThePlayerTemplateStore->findPlayerTemplate(NAMEKEY(tmplname)); + if (pt) { + playerColor = pt->getPreferredColor()->getAsInt(); } } } } } - Int health = 100; - health = pMapObj->getProperties()->getInt(TheKey_objectInitialHealth, &exists); - Real ratio = health/100.0; - if (ratio > TheGlobalData->m_unitDamagedThresh) - { - curDamageState = BODY_PRISTINE; - } - else if (ratio > TheGlobalData->m_unitReallyDamagedThresh) - { - curDamageState = BODY_DAMAGED; - } - else if (ratio > 0.0f) - { - curDamageState = BODY_REALLYDAMAGED; - } - else - { - curDamageState = BODY_RUBBLE; - } - } + Int health = 100; + health = pMapObj->getProperties()->getInt(TheKey_objectInitialHealth, &exists); + Real ratio = health/100.0; + if (ratio > TheGlobalData->m_unitDamagedThresh) + { + curDamageState = BODY_PRISTINE; + } + else if (ratio > TheGlobalData->m_unitReallyDamagedThresh) + { + curDamageState = BODY_DAMAGED; + } + else if (ratio > 0.0f) + { + curDamageState = BODY_REALLYDAMAGED; + } + else + { + curDamageState = BODY_RUBBLE; + } + + if (!renderObj) { Real scale = 1.0; AsciiString modelName = getModelNameAndScale(pMapObj, &scale, curDamageState); // set render object, or create if we need to if( renderObj == nullptr && modelName.isEmpty() == FALSE && - strncmp( modelName.str(), "No ", 3 ) != 0 ) + strncmp( modelName.str(), "No ", 3 ) ) { if (!getShowModels()) { @@ -1404,7 +1480,6 @@ void WbView3d::invalObjectInView(MapObject *pMapObjIn) Shadow::ShadowTypeInfo shadowInfo; shadowInfo.allowUpdates=FALSE; //shadow image will never update shadowInfo.allowWorldAlign=TRUE; //shadow image will wrap around world objects - const ThingTemplate *tTemplate = pMapObj->getThingTemplate(); if (tTemplate && tTemplate->getShadowType() != SHADOW_NONE && !(pMapObj->getFlags() & FLAG_DONT_RENDER)) { //add correct type of shadow strlcpy(shadowInfo.m_ShadowName, tTemplate->getShadowTextureName().str(), ARRAY_SIZE(shadowInfo.m_ShadowName)); @@ -1456,6 +1531,10 @@ void WbView3d::invalObjectInView(MapObject *pMapObjIn) if (pMapObjIn->getFlags() & (FLAG_ROAD_FLAGS|FLAG_BRIDGE_FLAGS)) { isRoad = true; } + const ThingTemplate *tTemplate = pMapObjIn->getThingTemplate(); + if (tTemplate && tTemplate->isKindOf(KINDOF_OPTIMIZED_TREE)) { + updateAllTrees = true; + } } if (!found && pMapObjIn && pMapObjIn->getRenderObj()) { if( m_showShadows ) { @@ -1471,6 +1550,9 @@ void WbView3d::invalObjectInView(MapObject *pMapObjIn) if (isRoad) { m_needToLoadRoads = true; // load roads next time we redraw. } + if (updateAllTrees) { + updateTrees(); + } if (isLight) { updateLights(); } @@ -1488,7 +1570,6 @@ void WbView3d::updateHeightMapInView(WorldHeightMap *htMap, Bool partial, const { if (htMap == nullptr) return; - ++m_updateCount; if (m_heightMapRenderObj == nullptr) { @@ -1675,7 +1756,7 @@ Bool WbView3d::viewToDocCoords(CPoint curPt, Coord3D *newPt, Bool constrain) if (WbApp()->isCurToolLocked()) { followTerrain = WbApp()->getCurTool()->followsTerrain(); } - if (followTerrain) { + if (followTerrain && TheTerrainRenderObject) { CastResultStruct castResult; RayCollisionTestClass rayCollide(ray, &castResult) ; if( TheTerrainRenderObject->Cast_Ray(rayCollide) ) @@ -1905,6 +1986,7 @@ void WbView3d::updateHysteresis() // ---------------------------------------------------------------------------- Bool WbView3d::docToViewCoords(Coord3D curPt, CPoint* newPt) { + Bool coordInsideFrustum = true; Vector3 world; Vector3 screen; newPt->x = -1000; @@ -1914,7 +1996,11 @@ Bool WbView3d::docToViewCoords(Coord3D curPt, CPoint* newPt) } world.Set( curPt.x, curPt.y, curPt.z ); - if (m_camera->Project( screen, world ) != CameraClass::INSIDE_FRUSTUM) return false; + if (m_camera->Project( screen, world ) != CameraClass::INSIDE_FRUSTUM) { + coordInsideFrustum = false; + } else { + coordInsideFrustum = true; + } CRect rClient; GetClientRect(&rClient); @@ -1933,7 +2019,7 @@ Bool WbView3d::docToViewCoords(Coord3D curPt, CPoint* newPt) newPt->x = rClient.left + sx; newPt->y = rClient.top + sy; - return true; + return coordInsideFrustum; } // ---------------------------------------------------------------------------- @@ -1965,6 +2051,7 @@ void WbView3d::redraw() Int curTicks = GetTickCount(); RefRenderObjListIterator lightListIt(&m_lightList); m_heightMapRenderObj->updateCenter(m_camera, &m_cameraTarget, &lightListIt); + m_heightMapRenderObj->On_Frame_Update(); --m_updateCount; curTicks = GetTickCount()-curTicks; @@ -1975,7 +2062,8 @@ void WbView3d::redraw() if (m_drawObject) { m_drawObject->setDrawObjects(m_showObjects, m_showWaypoints || WaypointTool::isActive(), - m_showPolygonTriggers || PolygonTool::isActive()); + m_showPolygonTriggers || PolygonTool::isActive(), + m_showBoundingBoxes, m_showSightRanges, m_showWeaponRanges, m_showSoundCircles, m_highlightTestArt, m_showLetterbox); } WW3D::Update_Logic_Frame_Time(TheFramePacer->getLogicTimeStepMilliseconds()); @@ -2109,6 +2197,16 @@ BEGIN_MESSAGE_MAP(WbView3d, WbView) ON_UPDATE_COMMAND_UI(ID_VIEW_PARTIALMAPSIZE_128X128, OnUpdateViewPartialmapsize128x128) ON_COMMAND(ID_VIEW_SHOWMODELS, OnViewShowModels) ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWMODELS, OnUpdateViewShowModels) + ON_COMMAND(ID_VIEW_BOUNDINGBOXES, OnViewBoundingBoxes) + ON_UPDATE_COMMAND_UI(ID_VIEW_BOUNDINGBOXES, OnUpdateViewBoundingBoxes) + ON_COMMAND(ID_VIEW_SIGHTRANGES, OnViewSightRanges) + ON_UPDATE_COMMAND_UI(ID_VIEW_SIGHTRANGES, OnUpdateViewSightRanges) + ON_COMMAND(ID_VIEW_WEAPONRANGES, OnViewWeaponRanges) + ON_UPDATE_COMMAND_UI(ID_VIEW_WEAPONRANGES, OnUpdateViewWeaponRanges) + ON_COMMAND(ID_HIGHLIGHT_TESTART, OnHighlightTestArt) + ON_UPDATE_COMMAND_UI(ID_HIGHLIGHT_TESTART, OnUpdateHighlightTestArt) + ON_COMMAND(ID_SHOW_LETTERBOX, OnShowLetterbox) + ON_UPDATE_COMMAND_UI(ID_SHOW_LETTERBOX, OnUpdateShowLetterbox) ON_COMMAND(ID_VIEW_GARRISONED, OnViewGarrisoned) ON_UPDATE_COMMAND_UI(ID_VIEW_GARRISONED, OnUpdateViewGarrisoned) ON_COMMAND(ID_VIEW_LAYERS_LIST, OnViewLayersList) @@ -2117,6 +2215,8 @@ BEGIN_MESSAGE_MAP(WbView3d, WbView) ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWMAPBOUNDARIES, OnUpdateViewShowMapBoundaries) ON_COMMAND(ID_VIEW_SHOWAMBIENTSOUNDS, OnViewShowAmbientSounds) ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWAMBIENTSOUNDS, OnUpdateViewShowAmbientSounds) + ON_COMMAND(ID_VIEW_SHOW_SOUND_CIRCLES, OnViewShowSoundCircles) + ON_UPDATE_COMMAND_UI(ID_VIEW_SHOW_SOUND_CIRCLES, OnUpdateViewShowSoundCircles) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -2258,6 +2358,7 @@ int WbView3d::OnCreate(LPCREATESTRUCT lpCreateStruct) m_showLayersList = AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowLayersList", 0); m_showMapBoundaries = AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowMapBoundaries", 0); m_showAmbientSounds = AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowAmbientSounds", 0); + m_showSoundCircles = AfxGetApp()->GetProfileInt(MAIN_FRAME_SECTION, "ShowSoundCircles", 0); DrawObject::setDoBoundaryFeedback(m_showMapBoundaries); DrawObject::setDoAmbientSoundFeedback(m_showAmbientSounds); @@ -2283,6 +2384,48 @@ void WbView3d::OnPaint() } +////////////////////////////////////////////////////////////////////////// +/// Draw a (not very good) circle into the hdc +void WbView3d::drawCircle( HDC hdc, const Coord3D & centerPoint, Real radius, COLORREF color ) +{ + CPoint rulerPoints[2]; + Coord3D pnt; + Real angle = 0.0f; + Real inc = PI/4.0f; + + // Create and select a correctly colored pen. Remember the old one so that it can be restored. + HPEN pen = CreatePen(PS_SOLID, 2, color); + HPEN penOld = (HPEN)SelectObject(hdc, pen); + + + // Get the starting point on the circumference of the circle. + pnt.x = centerPoint.x + radius * (Real)cosf(angle); + pnt.y = centerPoint.y + radius * (Real)sinf(angle); + pnt.z = centerPoint.z; + docToViewCoords(pnt, &rulerPoints[0]); + + angle += inc; + for(; angle <= 2.0f * PI; angle += inc) { + // Get a new point on the circumference of the circle. + pnt.x = centerPoint.x + radius * (Real)cosf(angle); + pnt.y = centerPoint.y + radius * (Real)sinf(angle); + pnt.z = centerPoint.z; + + docToViewCoords(pnt, &rulerPoints[1]); + + ::Polyline(hdc, rulerPoints, 2); + + // Remember the last point to use as the starting point for the next line. + rulerPoints[0].x = rulerPoints[1].x; + rulerPoints[0].y = rulerPoints[1].y; + } + + // Restore previous pen. + SelectObject(hdc, penOld); + // Delete new pen. + DeleteObject(pen); +} + void WbView3d::drawLabels() { @@ -2329,7 +2472,7 @@ void WbView3d::drawLabels(HDC hdc) pos = *pMapObj->getLocation(); pos.z = m_heightMapRenderObj->getHeightMapHeight(pos.x, pos.y, nullptr); } else if (pMapObj->getThingTemplate() && !(pMapObj->getFlags() & (FLAG_ROAD_FLAGS|FLAG_BRIDGE_FLAGS)) && - pMapObj->getRenderObj() == nullptr) { + pMapObj->getRenderObj() == nullptr && !pMapObj->getThingTemplate()->isKindOf(KINDOF_OPTIMIZED_TREE)) { name = pMapObj->getThingTemplate()->getName(); pos = *pMapObj->getLocation(); pos.z += m_heightMapRenderObj->getHeightMapHeight(pos.x, pos.y, nullptr); @@ -2344,7 +2487,7 @@ void WbView3d::drawLabels(HDC hdc) case 3: name = pMapObj->getProperties()->getAsciiString(TheKey_waypointPathLabel3, &exists); break; default: name.clear(); } - if (!name.isEmpty()) { + if (!name.isEmpty() && m_showWaypoints) { CPoint pt; Vector3 world, screen; world.Set( pos.x+MAP_XY_FACTOR/2, pos.y, pos.z ); @@ -2414,6 +2557,28 @@ void WbView3d::drawLabels(HDC hdc) ::FrameRect(hdc, &m_feedbackBox, (HBRUSH)brush.GetSafeHandle()); } + if (hdc && m_doRulerFeedback) { + if (m_doRulerFeedback == RULER_LINE) { + // Change world coords to screen viewport coords. + CPoint rulerPoints[2]; + docToViewCoords(m_rulerPoints[0], &rulerPoints[0]); + docToViewCoords(m_rulerPoints[1], &rulerPoints[1]); + + // Create and select a green pen. Remember the old one so that it can be restored. + HPEN pen = CreatePen(PS_SOLID, 2, RGB(0,255,0)); + HPEN penOld = (HPEN)SelectObject(hdc, pen); + // Draw the line ruler. + ::Polyline(hdc, rulerPoints, 2); + + // Restore previous pen. + SelectObject(hdc, penOld); + // Delete new pen. + DeleteObject(pen); + } else if (m_doRulerFeedback == RULER_CIRCLE) { + drawCircle( hdc, m_rulerPoints[0], m_rulerLength, RGB( 0, 255, 0 ) ); + } + } + if (hdc && m_doLightFeedback) { //Draw Lines to indicate the direction of each light source // Int LightColors[MAX_GLOBAL_LIGHTS]={RGB(255,0,0),RGB(0,255,0),RGB(0,0,255)}; @@ -2481,7 +2646,7 @@ void WbView3d::drawLabels(HDC hdc) } else { if (!m_doLightFeedback) - { //not in light feedback mode. Make sure the temporary feeback models are gone + { //not in light feedback mode. Make sure the temporary feedback models are gone for (Int lIndex=0; lIndex 2.0f) + { + m_mouseWheelOffset += zDelta; + } + else if (getCurrentZoom() > 1.0f) + { + m_mouseWheelOffset += zDelta/2; + } + else + { + m_mouseWheelOffset += zDelta/8; + } + MSG msg; while (::PeekMessage(&msg, m_hWnd, WM_MOUSEWHEEL, WM_MOUSEWHEEL, PM_REMOVE)) { zDelta = (short) HIWORD(msg.wParam); // wheel rotation @@ -2616,6 +2795,32 @@ Real WbView3d::getCameraPitch() return m_FXPitch; } + +//WST 10.17.2002 ---------------------------------------------------------------------------- +Real WbView3d::getCurrentZoom() +{ + float zOffset = - m_mouseWheelOffset / 1200; //WST 11/21/02 new triple speed camera zoom. + Real zoom = 1.0f; + if (zOffset != 0) { + Real zPos = (m_cameraOffset.length()-m_groundLevel)/m_cameraOffset.length(); + Real zAbs = zOffset + zPos; + if (zAbs<0) zAbs = -zAbs; + if (zAbs<0.01) zAbs = 0.01f; + //DEBUG_LOG(("zOffset = %.2f, zAbs = %.2f, zPos = %.2f", zOffset, zAbs, zPos)); + if (zOffset > 0) { + zOffset *= zAbs; + } else if (zOffset < -0.3f) { + zOffset = -0.15f + zOffset/2.0f; + } + if (zOffset < -0.6f) { + zOffset = -0.3f + zOffset/2.0f; + } + //DEBUG_LOG(("zOffset = %.2f", zOffset)); + zoom = zAbs; + } + return zoom; +} + // ---------------------------------------------------------------------------- void WbView3d::OnTimer(UINT nIDEvent) { @@ -2734,12 +2939,12 @@ void WbView3d::OnEditSelectmacrotexture() void WbView3d::OnLookEast() { - m_cameraAngle = -PI/2; + m_cameraAngle = -PI / 2; } void WbView3d::OnUpdateLookEast(CCmdUI* pCmdUI) { - pCmdUI->SetCheck(m_cameraAngle==-PI/2?1:0); + pCmdUI->SetCheck(m_cameraAngle == -PI / 2 ? 1 : 0); } void WbView3d::OnLookNorth() @@ -2749,28 +2954,27 @@ void WbView3d::OnLookNorth() void WbView3d::OnUpdateLookNorth(CCmdUI* pCmdUI) { - pCmdUI->SetCheck(m_cameraAngle==0?1:0); + pCmdUI->SetCheck(m_cameraAngle == 0 ? 1 : 0); } void WbView3d::OnLookSouth() { m_cameraAngle = PI; - } void WbView3d::OnUpdateLookSouth(CCmdUI* pCmdUI) { - pCmdUI->SetCheck(m_cameraAngle==PI?1:0); + pCmdUI->SetCheck(m_cameraAngle == PI ? 1 : 0); } void WbView3d::OnLookWest() { - m_cameraAngle = PI/2; + m_cameraAngle = PI / 2; } void WbView3d::OnUpdateLookWest(CCmdUI* pCmdUI) { - pCmdUI->SetCheck(m_cameraAngle==PI/2?1:0); + pCmdUI->SetCheck(m_cameraAngle == PI / 2 ? 1 : 0); } void WbView3d::OnViewShowshadows() @@ -2791,6 +2995,8 @@ void WbView3d::OnViewShowshadows() } else { TheW3DShadowManager->removeAllShadows(); } + TheWritableGlobalData->m_useShadowDecals = m_showShadows; + TheWritableGlobalData->m_useShadowVolumes = m_showShadows; ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "ShowShadows", m_showShadows?1:0); } @@ -2862,6 +3068,77 @@ void WbView3d::OnUpdateViewShowModels(CCmdUI* pCmdUI) pCmdUI->SetCheck(getShowModels()?1:0); } +// MLL C&C3 +void WbView3d::OnViewBoundingBoxes() +{ + setShowBoundingBoxes(!getShowBoundingBoxes()); + ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "ShowBoundingBoxes", getShowBoundingBoxes()?1:0); + resetRenderObjects(); + invalObjectInView(nullptr); +} +// MLL C&C3 +void WbView3d::OnUpdateViewBoundingBoxes(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(getShowBoundingBoxes()?1:0); +} + + +// MLL C&C3 +void WbView3d::OnViewSightRanges() +{ + setShowSightRanges(!getShowSightRanges()); + ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "ShowSightRanges", getShowSightRanges()?1:0); + resetRenderObjects(); + invalObjectInView(nullptr); +} +// MLL C&C3 +void WbView3d::OnUpdateViewSightRanges(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(getShowSightRanges()?1:0); +} + +// MLL C&C3 +void WbView3d::OnViewWeaponRanges() +{ + setShowWeaponRanges(!getShowWeaponRanges()); + ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "ShowWeaponRanges", getShowWeaponRanges()?1:0); + resetRenderObjects(); + invalObjectInView(nullptr); +} +// MLL C&C3 +void WbView3d::OnUpdateViewWeaponRanges(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(getShowWeaponRanges()?1:0); +} + +// MLL C&C3 +void WbView3d::OnHighlightTestArt() +{ + setHighlightTestArt(!getHighlightTestArt()); + ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "HighlightTestArt", getHighlightTestArt()?1:0); + resetRenderObjects(); + invalObjectInView(nullptr); +} +// MLL C&C3 +void WbView3d::OnUpdateHighlightTestArt(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(getHighlightTestArt()?1:0); +} + + +// MLL C&C3 +void WbView3d::OnShowLetterbox() +{ + setShowLetterbox(!getShowLetterbox()); + ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "ShowLetterBox", getShowLetterbox()?1:0); +} +// MLL C&C3 +void WbView3d::OnUpdateShowLetterbox(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(getShowLetterbox()?1:0); +} + + void WbView3d::OnViewGarrisoned() { setShowGarrisoned(!getShowGarrisoned()); @@ -3018,3 +3295,16 @@ void WbView3d::OnUpdateViewShowAmbientSounds(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_showAmbientSounds ? 1 : 0); } + +void WbView3d::OnViewShowSoundCircles() +{ + m_showSoundCircles = !m_showSoundCircles; + ::AfxGetApp()->WriteProfileInt(MAIN_FRAME_SECTION, "ShowSoundCircles", m_showSoundCircles ? 1 : 0); + resetRenderObjects(); + invalObjectInView(nullptr); +} + +void WbView3d::OnUpdateViewShowSoundCircles(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_showSoundCircles ? 1 : 0); +} diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/PolygonTrigger.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/PolygonTrigger.h index d618de16a06..680766111db 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/PolygonTrigger.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/PolygonTrigger.h @@ -120,13 +120,13 @@ class PolygonTrigger : public MemoryPoolObject, void setTriggerName(AsciiString name) {m_triggerName = name;}; void setLayerName(AsciiString name) {m_layerName = name;}; - AsciiString getLayerName() const {return m_layerName;} + AsciiString getLayerName() const {return m_layerName;} void setShouldRender(Bool toggle) {m_shouldRender = toggle;} - Bool getShouldRender() {return m_shouldRender;} + Bool getShouldRender() const {return m_shouldRender;} void setSelected(Bool toggle) {m_selected = toggle;} - Bool getSelected() {return m_selected;} + Bool getSelected() const {return m_selected;} void getCenterPoint(Coord3D* pOutCoord) const; Real getRadius() const; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp index 4f19ee9cfc2..8f74d44f7eb 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/PolygonTrigger.cpp @@ -186,12 +186,6 @@ 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 { @@ -239,7 +233,12 @@ Bool PolygonTrigger::ParsePolygonTriggersDataChunk(DataChunkInput &file, DataChu */ void PolygonTrigger::WritePolygonTriggersDataChunk(DataChunkOutput &chunkWriter) { +#if RETAIL_COMPATIBLE_WORLDBUILDER && RTS_GENERALS + // TheSuperHackers @info OmarAglan 30/07/2026 Retail Generals expects version 3 and does not read polygon trigger layer names. + chunkWriter.openDataChunk("PolygonTriggers", K_TRIGGERS_VERSION_3); +#else chunkWriter.openDataChunk("PolygonTriggers", K_TRIGGERS_VERSION_4); +#endif PolygonTrigger *pTrig; Int count = 0; @@ -249,7 +248,9 @@ void PolygonTrigger::WritePolygonTriggersDataChunk(DataChunkOutput &chunkWriter) chunkWriter.writeInt(count); for (pTrig=PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { chunkWriter.writeAsciiString(pTrig->getTriggerName()); +#if !(RETAIL_COMPATIBLE_WORLDBUILDER && RTS_GENERALS) chunkWriter.writeAsciiString(pTrig->getLayerName()); +#endif chunkWriter.writeInt(pTrig->getID()); chunkWriter.writeByte(pTrig->isWaterArea()); chunkWriter.writeByte(pTrig->isRiver()); @@ -496,7 +497,7 @@ const WaterHandle* PolygonTrigger::getWaterHandle() const Bool PolygonTrigger::isValid() const { - if (m_numPoints == 0) { + if (m_numPoints < 2) { return FALSE; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp index 5a3d16f86ae..9e9fd789ac3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/TerrainLogic.cpp @@ -1640,7 +1640,8 @@ PolygonTrigger *TerrainLogic::getTriggerAreaByName( AsciiString name ) { for (PolygonTrigger* pTrig = PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { const AsciiString& trigName = pTrig->getTriggerName(); - if (name == trigName) + // TheSuperHackers @info OmarAglan 30/07/2026 Retain invalid triggers for snapshot compatibility, but do not expose them as usable areas. + if (name == trigName && pTrig->isValid()) return pTrig; } return nullptr; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt index c377a85c87c..414a3ce89ad 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt @@ -176,6 +176,7 @@ set(WORLDBUILDER_SRC "include/TeamBehavior.h" "include/TeamGeneric.h" "include/TeamIdentity.h" + "include/TeamObjectProperties.h" "include/TeamReinforcement.h" "include/teamsdialog.h" "include/TerrainMaterial.h" @@ -189,6 +190,7 @@ set(WORLDBUILDER_SRC "include/WaypointTool.h" "include/WBFrameWnd.h" "include/WBHeightMap.h" + "include/WBPopupSlider.h" "include/wbview.h" "include/wbview3d.h" "include/WHeightMapEdit.h" diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/CFixTeamOwnerDialog.h b/GeneralsMD/Code/Tools/WorldBuilder/include/CFixTeamOwnerDialog.h index b05d5383cbf..f2532e85eec 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/CFixTeamOwnerDialog.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/CFixTeamOwnerDialog.h @@ -16,8 +16,6 @@ ** along with this program. If not, see . */ - - #include "Common/AsciiString.h" class TeamsInfo; class SidesList; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/WBHeightMap.h b/GeneralsMD/Code/Tools/WorldBuilder/include/WBHeightMap.h index 57f0f640c1b..7f08c2fc124 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/WBHeightMap.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/WBHeightMap.h @@ -20,8 +20,8 @@ #include "W3DDevice/GameClient/FlatHeightMap.h" #include "W3DDevice/GameClient/HeightMap.h" -#define dont_USE_FLAT_HEIGHT_MAP // Use the original height map for mission disk. jba. [4/15/2003] -#ifdef USE_FLAT_HEIGHT_MAP +#define USE_FLAT_HEIGHT_MAP 0 // Use the original height map for mission disk. jba. [4/15/2003] +#if USE_FLAT_HEIGHT_MAP class WBHeightMap : public FlatHeightMapRenderObjClass #else class WBHeightMap : public HeightMapRenderObjClass diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/WHeightMapEdit.h b/GeneralsMD/Code/Tools/WorldBuilder/include/WHeightMapEdit.h index c51ffb3a4d0..68b1044ef4e 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/WHeightMapEdit.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/WHeightMapEdit.h @@ -147,6 +147,8 @@ class WorldHeightMapEdit : public WorldHeightMap void reloadTextures(); ///< Reloads textures from disk. void resetResources(); ///< Releases textures in preparation for device reset. + Bool getRawTileData(Short tileNdx, Int width, UnsignedByte *buffer, Int bufLen); + void dbgVerifyAfterUndo(); ///< Verifies the structures are still consistent. Bool doCliffAdjustment(Int xIndex, Int yIndex); Bool removeCliffMapping(); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h index 953fd38c154..7439499c471 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h @@ -109,6 +109,14 @@ class WbView3d : public WbView, public DX8_CleanupHook afx_msg void OnViewShowmacrotexture(); afx_msg void OnUpdateViewShowmacrotexture(CCmdUI* pCmdUI); afx_msg void OnEditSelectmacrotexture(); + afx_msg void OnLookEast(); + afx_msg void OnUpdateLookEast(CCmdUI* pCmdUI); + afx_msg void OnLookNorth(); + afx_msg void OnUpdateLookNorth(CCmdUI* pCmdUI); + afx_msg void OnLookSouth(); + afx_msg void OnUpdateLookSouth(CCmdUI* pCmdUI); + afx_msg void OnLookWest(); + afx_msg void OnUpdateLookWest(CCmdUI* pCmdUI); afx_msg void OnViewShowshadows(); afx_msg void OnUpdateViewShowshadows(CCmdUI* pCmdUI); afx_msg void OnViewShowSoftWater(); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/res/WorldBuilder.rc b/GeneralsMD/Code/Tools/WorldBuilder/res/WorldBuilder.rc index 6cbb57e5ac1..0918509c0ea 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/res/WorldBuilder.rc +++ b/GeneralsMD/Code/Tools/WorldBuilder/res/WorldBuilder.rc @@ -27,18 +27,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // TEXTINCLUDE // -1 TEXTINCLUDE DISCARDABLE +1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END -2 TEXTINCLUDE DISCARDABLE +2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END -3 TEXTINCLUDE DISCARDABLE +3 TEXTINCLUDE DISCARDABLE BEGIN "#define _AFX_NO_SPLITTER_RESOURCES\r\n" "#define _AFX_NO_OLE_RESOURCES\r\n" @@ -171,7 +171,7 @@ END // Menu // -IDR_MAPDOC MENU PRELOAD DISCARDABLE +IDR_MAPDOC MENU PRELOAD DISCARDABLE BEGIN POPUP "&File" BEGIN @@ -257,7 +257,7 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Highlight Test Art", ID_HIGHLIGHT_TESTART MENUITEM SEPARATOR - MENUITEM "Show Impassable Areas\tCtrl+I", + MENUITEM "Show Impassable Areas\tCtrl+I", ID_VIEW_SHOWIMPASSABLEAREAS MENUITEM "Impassable Area Options...", ID_VIEW_IMPASSABLEAREAOPTIONS @@ -277,6 +277,13 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Show Wireframe 3D View\tCtrl+W", ID_VIEW_SHOWWIREFRAME MENUITEM "Show From Top Down View\tCtrl+F", ID_VIEW_SHOWTOPDOWNVIEW + POPUP "Camera Direction" + BEGIN + MENUITEM "Look North", ID_LOOK_NORTH + MENUITEM "Look South", ID_LOOK_SOUTH + MENUITEM "Look West", ID_LOOK_WEST + MENUITEM "Look East", ID_LOOK_EAST + END MENUITEM "Show 3-Way Blends in White", ID_VIEW_SHOWEXTRABLENDS MENUITEM "Show Clouds\tCtrl+U", ID_VIEW_SHOWCLOUDS MENUITEM "Show Soft Water", ID_VIEW_SHOWSOFTWATER @@ -332,7 +339,7 @@ BEGIN END END -IDR_LAYERSLISTPOPUP MENU DISCARDABLE +IDR_LAYERSLISTPOPUP MENU DISCARDABLE BEGIN POPUP "Layers List" BEGIN @@ -361,7 +368,7 @@ BEGIN END END -IDR_SCRIPTDIALOGPOPUP MENU DISCARDABLE +IDR_SCRIPTDIALOGPOPUP MENU DISCARDABLE BEGIN POPUP "Layers List" BEGIN @@ -375,7 +382,7 @@ END // Accelerator // -IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE +IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE BEGIN "0", ID_EDIT_PICKANYTHING, VIRTKEY, CONTROL, NOINVERT "1", ID_EDIT_PICKSTRUCTS, VIRTKEY, CONTROL, NOINVERT @@ -394,7 +401,7 @@ BEGIN "F", ID_TOGGLE_PITCH_AND_ROTATE, VIRTKEY, NOINVERT "F", ID_VIEW_SHOWTOPDOWNVIEW, VIRTKEY, CONTROL, NOINVERT "G", IDM_ShowGrid, VIRTKEY, CONTROL, NOINVERT - "G", ID_VIEW_SNAPTOGRID, VIRTKEY, SHIFT, CONTROL, + "G", ID_VIEW_SNAPTOGRID, VIRTKEY, SHIFT, CONTROL, NOINVERT "I", ID_VIEW_SHOWIMPASSABLEAREAS, VIRTKEY, CONTROL, NOINVERT "J", ID_FILE_JUMPTOGAME, VIRTKEY, CONTROL, NOINVERT @@ -418,7 +425,7 @@ BEGIN "W", ID_VIEW_SHOWWIREFRAME, VIRTKEY, CONTROL, NOINVERT "X", ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT - "Z", ID_EDIT_REDO, VIRTKEY, SHIFT, CONTROL, + "Z", ID_EDIT_REDO, VIRTKEY, SHIFT, CONTROL, NOINVERT END @@ -462,23 +469,23 @@ BEGIN EDITTEXT IDC_INITIAL_HEIGHT,75,58,26,12,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,129,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 - CONTROL "",IDC_TOP_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_TOP_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,53,83,20,18 - CONTROL "",IDC_TOP,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_TOP,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,73,83,20,18 - CONTROL "",IDC_TOP_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_TOP_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,93,83,20,18 - CONTROL "",IDC_CENTER_LEFT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_CENTER_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,53,101,20,18 - CONTROL "",IDC_CENTER,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_CENTER,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,73,101,20,18 - CONTROL "",IDC_CENTER_RIGHT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_CENTER_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,93,101,20,18 - CONTROL "",IDC_BOTTOM_LEFT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_BOTTOM_LEFT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,53,119,20,18 - CONTROL "",IDC_BOTTOM,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | + CONTROL "",IDC_BOTTOM,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,73,119,20,18 - CONTROL "",IDC_BOTTOM_RIGHT,"Button",BS_AUTOCHECKBOX | + CONTROL "",IDC_BOTTOM_RIGHT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,93,119,20,18 LTEXT "Initial height (0-255):",IDC_STATIC,7,59,67,9 LTEXT "Vert (y) size:",IDC_STATIC,7,25,42,9 @@ -521,10 +528,10 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Terrain Material Options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,126 PUSHBUTTON "Swap",IDC_SWAP_TEXTURES,138,138,25,16 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,67,137,65,55 LTEXT "Gravel",IDC_TERRAIN_NAME,70,197,86,9 EDITTEXT IDC_SIZE_EDIT,53,217,17,12,ES_AUTOHSCROLL @@ -567,16 +574,16 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Object Selection Opts" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,0,5,199,126 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,80,137,57,49 LTEXT "Light Tank",IDC_OBJECT_NAME,65,205,67,9 EDITTEXT IDC_OBJECT_HEIGHT_EDIT,106,191,26,12,ES_AUTOHSCROLL LTEXT "Height (0==on terrain)",IDC_STATIC,13,193,74,8 LTEXT "Object Name:",IDC_STATIC,13,205,42,9 LTEXT "Default Owner:",IDC_STATIC,13,219,48,8 - COMBOBOX IDC_OWNINGTEAM,13,229,162,104,CBS_DROPDOWNLIST | + COMBOBOX IDC_OWNINGTEAM,13,229,162,104,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END @@ -601,9 +608,9 @@ STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Replace " FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,174,126 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,15,201,65,55 LTEXT "Gravel",IDC_TERRAIN_NAME,44,185,83,10 DEFPUSHBUTTON "OK",IDOK,129,231,50,14 @@ -672,10 +679,10 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Mesh Mold Options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_MESHMOLD_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_MESHMOLD_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,93 PUSHBUTTON "Apply",IDC_APPLY_MESH,5,224,56,17 - CONTROL "Preview",IDC_PREVIEW,"Button",BS_AUTOCHECKBOX | + CONTROL "Preview",IDC_PREVIEW,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,147,225,40,10 RTEXT "Angle (deg)",IDC_STATIC,5,142,41,10 EDITTEXT IDC_ANGLE_EDIT,50,140,29,12,ES_AUTOHSCROLL @@ -700,7 +707,7 @@ STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Select Mactotexture" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TEXTURE_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TEXTURE_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,136,126 DEFPUSHBUTTON "OK",IDOK,5,140,50,14 END @@ -789,13 +796,13 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,129,196,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,215,50,14 - LISTBOX IDC_OPEN_LIST,15,26,155,162,LBS_SORT | + LISTBOX IDC_OPEN_LIST,15,26,155,162,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Open Map:",IDC_STATIC,15,15,36,8 PUSHBUTTON "Browse...",IDC_BROWSE,16,195,61,16 - CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,58,6,54,16 - CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,115,6,55,16 END @@ -806,14 +813,14 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,129,197,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,214,50,14 - LISTBOX IDC_SAVE_LIST,13,25,157,136,LBS_SORT | + LISTBOX IDC_SAVE_LIST,13,25,157,136,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Browse...",IDC_BROWSE,7,197,50,14 GROUPBOX "Map name:",IDC_STATIC,7,166,172,27 EDITTEXT IDC_SAVE_MAP_EDIT,13,175,157,12,ES_AUTOHSCROLL - CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "System Maps",IDC_SYSTEMMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,66,6,54,16 - CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | + CONTROL "User Maps",IDC_USERMAPS,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE,123,6,55,16 LTEXT "Existing maps:",IDC_STATIC,13,15,46,8 END @@ -824,7 +831,7 @@ CAPTION "Property Edit" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_KEYNAME,38,7,107,14,ES_AUTOHSCROLL - COMBOBOX IDC_KEYTYPE,38,30,107,153,CBS_DROPDOWNLIST | WS_VSCROLL | + COMBOBOX IDC_KEYTYPE,38,30,107,153,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_VALUE,38,50,107,14,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,162,7,31,14 @@ -841,24 +848,24 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Player List" FONT 8, "MS Sans Serif" BEGIN - LISTBOX IDC_PLAYERS,7,7,275,69,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + LISTBOX IDC_PLAYERS,7,7,275,69,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP PUSHBUTTON "New Player",IDC_NEWPLAYER,7,254,45,14 PUSHBUTTON "Remove Player",IDC_REMOVEPLAYER,56,254,56,14 DEFPUSHBUTTON "OK",IDOK,177,274,51,14 LTEXT "Allies:",IDC_STATIC,7,133,68,8 LTEXT "Enemies:",IDC_STATIC,153,133,78,8 - LISTBOX IDC_ALLIESLIST,7,144,129,40,LBS_SORT | LBS_MULTIPLESEL | + LISTBOX IDC_ALLIESLIST,7,144,129,40,LBS_SORT | LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LISTBOX IDC_ENEMIESLIST,153,144,129,40,LBS_SORT | - LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + LISTBOX IDC_ENEMIESLIST,153,144,129,40,LBS_SORT | + LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - LISTBOX IDC_PLAYER_ATTITUDE_OUT,7,203,129,40,NOT LBS_NOTIFY | - LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | + LISTBOX IDC_PLAYER_ATTITUDE_OUT,7,203,129,40,NOT LBS_NOTIFY | + LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP LTEXT "How Player Regard Others:",IDC_STATIC,7,192,86,8 - LISTBOX IDC_PLAYER_ATTITUDE_IN,153,203,129,40,NOT LBS_NOTIFY | - LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | + LISTBOX IDC_PLAYER_ATTITUDE_IN,153,203,129,40,NOT LBS_NOTIFY | + LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP LTEXT "How Others Regard Player:",IDC_STATIC,153,192,94,8 PUSHBUTTON "Cancel",IDCANCEL,232,274,50,14 @@ -867,10 +874,10 @@ BEGIN EDITTEXT IDC_PLAYERDISPLAYNAME,82,100,84,14,ES_AUTOHSCROLL CONTROL "Is Player computer-controlled?",IDC_PLAYERISCOMPUTER, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,163,87,110,10 - COMBOBOX IDC_PLAYERFACTION,178,110,96,105,CBS_DROPDOWNLIST | + COMBOBOX IDC_PLAYERFACTION,178,110,96,105,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "",IDC_PlayerColor,8,116,14,12 - COMBOBOX IDC_PlayerColorCombo,51,116,83,120,CBS_DROPDOWNLIST | + COMBOBOX IDC_PlayerColorCombo,51,116,83,120,CBS_DROPDOWNLIST | WS_TABSTOP PUSHBUTTON "Set Name",IDC_CHANGE_NAME,15,88,36,9 PUSHBUTTON "Add Skirmish Players",IDC_ADDSKIRMISHPLAYERS,42,274,71, @@ -885,20 +892,20 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Build List" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_SIDES_COMBO,9,10,184,133,CBS_DROPDOWNLIST | + COMBOBOX IDC_SIDES_COMBO,9,10,184,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Side:",IDC_STATIC,2,0,195,28 - LISTBOX IDC_BUILD_LIST,9,42,183,125,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_BUILD_LIST,9,42,183,125,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Build List",IDC_STATIC,2,31,196,167 - CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN | + CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN | WS_DISABLED,16,224,177,16 GROUPBOX "Power Used:",IDC_STATIC,7,214,190,28,WS_DISABLED CONTROL "Structure Already Built",IDC_ALREADY_BUILD,"Button", BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT | WS_TABSTOP, 100,169,90,10 RTEXT "Rebuilds:",IDC_STATIC,111,184,35,8 - COMBOBOX IDC_REBUILDS,149,182,43,64,CBS_DROPDOWN | WS_VSCROLL | + COMBOBOX IDC_REBUILDS,149,182,43,64,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Up",IDC_MOVE_UP,9,172,22,11 PUSHBUTTON "Down",IDC_MOVE_DOWN,9,184,22,11 @@ -946,16 +953,16 @@ BEGIN PUSHBUTTON "&Delete",IDC_DELETE,403,152,50,14 PUSHBUTTON "Import Scripts...",IDC_LOAD,386,309,60,14 PUSHBUTTON "Export Script(s)...",IDC_SAVE,317,309,60,14 - CONTROL "Tree1",IDC_SCRIPT_TREE,"SysTreeView32",TVS_HASBUTTONS | - TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | + CONTROL "Tree1",IDC_SCRIPT_TREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | WS_TABSTOP,7,7,386,193,WS_EX_CLIENTEDGE PUSHBUTTON "New &Folder...",IDC_NEW_FOLDER,403,46,50,14 - EDITTEXT IDC_SCRIPT_DESCRIPTION,208,206,187,99,ES_MULTILINE | + EDITTEXT IDC_SCRIPT_DESCRIPTION,208,206,187,99,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL PUSHBUTTON "Cancel",IDCANCEL,403,253,50,14 - EDITTEXT IDC_SCRIPT_COMMENT,7,206,195,99,ES_MULTILINE | + EDITTEXT IDC_SCRIPT_COMMENT,7,206,195,99,ES_MULTILINE | ES_READONLY | WS_VSCROLL - CONTROL "Auto Verify",IDC_AUTO_VERIFY,"Button",BS_AUTOCHECKBOX | + CONTROL "Auto Verify",IDC_AUTO_VERIFY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,311,52,8 PUSHBUTTON "&Verify",IDC_VERIFY,403,22,50,14 PUSHBUTTON "&Patch ""GC_""",IDC_PATCH_GC,403,169,50,14 @@ -976,7 +983,7 @@ STYLE WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Script Conditions" FONT 8, "MS Sans Serif" BEGIN - LISTBOX IDC_CONDITION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_CONDITION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Conditions for this script:",IDC_STATIC,7,14,81,8 PUSHBUTTON "New...",IDC_NEW,319,32,50,14 @@ -994,7 +1001,7 @@ STYLE WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Actions if true." FONT 8, "MS Sans Serif" BEGIN - LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Actions to take if conditions are true:",IDC_STATIC,7, 14,139,8 @@ -1014,7 +1021,7 @@ FONT 8, "MS Sans Serif" BEGIN LTEXT "Actions to take if conditions are false:",IDC_STATIC,7, 14,120,8 - LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_ACTION_LIST,7,29,306,104,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "New...",IDC_NEW,319,32,50,14 PUSHBUTTON "Edit...",IDC_EDIT,319,48,50,14 @@ -1039,11 +1046,11 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,11,69,108,10 CONTROL "Easy",IDC_EASY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 157,41,31,10 - CONTROL "Normal",IDC_NORMAL,"Button",BS_AUTOCHECKBOX | + CONTROL "Normal",IDC_NORMAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,56,38,10 CONTROL "Hard",IDC_HARD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 157,71,31,10 - EDITTEXT IDC_SCRIPT_COMMENT,7,100,320,98,ES_MULTILINE | + EDITTEXT IDC_SCRIPT_COMMENT,7,100,320,98,ES_MULTILINE | WS_VSCROLL LTEXT "Script Name:",IDC_STATIC,7,12,43,8 GROUPBOX "Active in:",IDC_STATIC,151,30,58,54 @@ -1071,8 +1078,8 @@ BEGIN LTEXT "These are the freaking warnings.",IDC_WARNINGS,9,388, 210,30 CONTROL "Tree1",IDC_CONDITION_TREE,"SysTreeView32", - TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | - TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | + TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | + TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,7,7,297,308 END @@ -1084,10 +1091,10 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,171,52,50,14 PUSHBUTTON "Cancel",IDCANCEL,224,52,50,14 GROUPBOX "Parameter:",IDC_CAPTION,7,7,267,41 - COMBOBOX IDC_COMBO,15,21,250,87,CBS_DROPDOWN | CBS_SORT | + COMBOBOX IDC_COMBO,15,21,250,87,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_EDIT,19,21,190,12,ES_AUTOHSCROLL - COMBOBOX IDC_LIST,19,21,190,84,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_LIST,19,21,190,84,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Preview Sound",IDC_PREVIEWSOUND,7,52,62,14 END @@ -1104,9 +1111,9 @@ BEGIN GROUPBOX "Warnings:",IDC_WARNINGS_CAPTION,7,378,297,45 LTEXT "These are the freaking warnings.",IDC_WARNINGS,9,388, 210,30 - CONTROL "Tree1",IDC_ACTION_TREE,"SysTreeView32",TVS_HASBUTTONS | - TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | - TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT | + CONTROL "Tree1",IDC_ACTION_TREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | + TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,7,7,297,308 END @@ -1119,9 +1126,9 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,458,273,50,14 PUSHBUTTON "Add New Team",IDC_NEWTEAM,7,273,56,14 PUSHBUTTON "Delete Team",IDC_DELETETEAM,121,273,54,14 - LISTBOX IDC_PLAYER_LIST,7,7,105,263,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_PLAYER_LIST,7,7,105,263,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - CONTROL "List1",IDC_TEAMS_LIST,"SysListView32",LVS_REPORT | + CONTROL "List1",IDC_TEAMS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,116,7,392,263 PUSHBUTTON "Copy Team",IDC_COPYTEAM,67,273,50,14 PUSHBUTTON "Select Team Members...",IDC_SelectTeamMembers,179,273, @@ -1169,7 +1176,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,29,157,50,14 PUSHBUTTON "Cancel",IDCANCEL,88,157,50,14 GROUPBOX "Object:",IDC_CAPTION,7,7,131,145 - CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,15,20,114,126 END @@ -1180,38 +1187,38 @@ FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_MAX,177,2,27,14,ES_AUTOHSCROLL RTEXT "Home Position:",IDC_STATIC,2,37,53,8 - COMBOBOX IDC_HOME_WAYPOINT,58,36,113,228,CBS_DROPDOWNLIST | + COMBOBOX IDC_HOME_WAYPOINT,58,36,113,228,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Min:",IDC_STATIC,6,122,14,8 LTEXT "Max:",IDC_STATIC,24,122,16,8 LTEXT "Unit Type:",IDC_STATIC,50,122,91,8 EDITTEXT IDC_MIN_UNIT1,2,131,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT1,24,131,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE1,47,131,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE1,47,131,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT2,2,145,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT2,23,145,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE2,47,145,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE2,47,145,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT3,2,159,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT3,24,159,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE3,47,159,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE3,47,159,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT4,2,173,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT4,24,173,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE4,47,173,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE4,47,173,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT5,2,187,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT5,24,187,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE5,47,187,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE5,47,187,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT6,2,201,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT6,24,201,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE6,47,201,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE6,47,201,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MIN_UNIT7,2,215,17,12,ES_AUTOHSCROLL EDITTEXT IDC_MAX_UNIT7,24,215,17,12,ES_AUTOHSCROLL - COMBOBOX IDC_UNIT_TYPE7,47,215,144,210,CBS_DROPDOWNLIST | + COMBOBOX IDC_UNIT_TYPE7,47,215,144,210,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Team Description:",IDC_STATIC,0,285,213,38 EDITTEXT IDC_DESCRIPTION,8,294,195,27,ES_AUTOHSCROLL @@ -1223,7 +1230,7 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,255,164,9 LTEXT "Maximum Quantity:",IDC_STATIC,116,4,59,8 RTEXT "Condition:",IDC_STATIC,11,62,47,8 - COMBOBOX IDC_PRODUCTION_CONDITION,64,59,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_PRODUCTION_CONDITION,64,59,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Production:",IDC_STATIC,1,53,212,66 RTEXT "Priority:",IDC_STATIC,3,89,24,8 @@ -1240,7 +1247,7 @@ BEGIN PUSHBUTTON "...",IDC_UNIT_TYPE6_BUTTON,197,201,12,12 PUSHBUTTON "...",IDC_UNIT_TYPE7_BUTTON,197,215,12,12 EDITTEXT IDC_TEAM_NAME,2,1,107,14,ES_AUTOHSCROLL - COMBOBOX IDC_TEAMOWNER,58,20,113,176,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_TEAMOWNER,58,20,113,176,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP RTEXT "Owner:",IDC_STATIC,2,24,53,8 CONTROL "Team created once and only once.",IDC_TEAM_SINGLETON, @@ -1249,7 +1256,7 @@ BEGIN EDITTEXT IDC_TEAM_BUILD_FRAMES,32,101,25,12,ES_AUTOHSCROLL LTEXT "frames.",IDC_STATIC,58,103,24,9 CONTROL "Execute associated actions", - IDC_PRODUCTION_EXECUTEACTIONS,"Button",BS_AUTOCHECKBOX | + IDC_PRODUCTION_EXECUTEACTIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,63,76,103,10 END @@ -1259,22 +1266,22 @@ CAPTION "Reinforcement" FONT 8, "MS Sans Serif" BEGIN GROUPBOX "If reinforcing, then:",IDC_STATIC,13,7,184,87 - CONTROL "Deploy by",IDC_DEPLOY_BY,"Button",BS_AUTOCHECKBOX | + CONTROL "Deploy by",IDC_DEPLOY_BY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,23,44,9 - COMBOBOX IDC_TRANSPORT_COMBO,66,21,126,140,CBS_DROPDOWN | + COMBOBOX IDC_TRANSPORT_COMBO,66,21,126,140,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Veterancy Level",IDC_STATIC,15,109,141,42 - COMBOBOX IDC_VETERANCY,23,124,124,60,CBS_DROPDOWNLIST | + COMBOBOX IDC_VETERANCY,23,124,124,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Transports exit map after unloading.", - IDC_TRANSPORTS_EXIT,"Button",BS_AUTOCHECKBOX | + IDC_TRANSPORTS_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,66,36,124,11 CONTROL "Load members into transports (if applicable).", - IDC_TEAM_STARTS_FULL,"Button",BS_AUTOCHECKBOX | + IDC_TEAM_STARTS_FULL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,78,166,11 GROUPBOX "Start team or transports at waypoint:",IDC_STATIC,19,50, 171,26 - COMBOBOX IDC_WAYPOINT_COMBO,25,60,160,176,CBS_DROPDOWN | CBS_SORT | + COMBOBOX IDC_WAYPOINT_COMBO,25,60,160,176,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP END @@ -1286,36 +1293,36 @@ BEGIN GROUPBOX "Behavior Script Triggers:",IDC_STATIC,7,7,216,107 GROUPBOX "Behavior Options",IDC_STATIC,7,141,216,106 RTEXT "On Create:",IDC_STATIC,23,25,51,8 - COMBOBOX IDC_ON_CREATE_SCRIPT,85,22,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_CREATE_SCRIPT,85,22,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP RTEXT "On Enemy Sighted:",IDC_STATIC,13,44,61,8 - COMBOBOX IDC_ON_ENEMY_SIGHTED,85,43,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_ENEMY_SIGHTED,85,43,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_ON_DESTROYED,85,80,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_DESTROYED,85,80,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP RTEXT "On Destroyed %",IDC_STATIC,10,81,51,8 EDITTEXT IDC_PERCENT_DESTROYED,62,80,18,12,ES_AUTOHSCROLL - COMBOBOX IDC_ENEMY_INTERACTIONS,19,182,159,69,CBS_DROPDOWNLIST | + COMBOBOX IDC_ENEMY_INTERACTIONS,19,182,159,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Initial Team Behavior",IDC_STATIC,15,172,172,27 CONTROL "Transports return to base after unloading.", - IDC_TRANSPORTS_RETURN,"Button",BS_AUTOCHECKBOX | + IDC_TRANSPORTS_RETURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,15,151,179,8 CONTROL "Team avoids threats.",IDC_AVOID_THREATS,"Button", BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,15,162,179,8 RTEXT "On All Clear:",IDC_STATIC,13,59,61,8 - COMBOBOX IDC_ON_ALL_CLEAR,85,58,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_ALL_CLEAR,85,58,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "",IDC_STATIC,7,36,216,37 RTEXT "On Idle:",IDC_STATIC,23,99,51,8 - COMBOBOX IDC_ON_IDLE_SCRIPT,85,96,132,173,CBS_DROPDOWNLIST | + COMBOBOX IDC_ON_IDLE_SCRIPT,85,96,132,173,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Behavior Scirpt Triggers:",IDC_STATIC,7,7,216,131 RTEXT "On Unit Destroyed:",IDC_STATIC,13,119,61,8 COMBOBOX IDC_ON_UNIT_DESTROYED_SCRIPT,85,116,132,173, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "Does this team focus on a single target at a time ", - IDC_ATTACK_COMMON_TARGET,"Button",BS_AUTOCHECKBOX | + IDC_ATTACK_COMMON_TARGET,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,215,173,8 GROUPBOX "Attack:",IDC_STATIC,15,204,181,34 LTEXT "in Hard and Brutal (never in Normal)?",IDC_STATIC,35, @@ -1342,7 +1349,7 @@ BEGIN CONTROL "Export selected scripts.",IDC_SELECTED_SCRIPTS,"Button", BS_AUTORADIOBUTTON,15,127,99,8 GROUPBOX "Export Mode:",IDC_STATIC,7,104,172,39 - CONTROL "Include sides.",IDC_SIDES,"Button",BS_AUTOCHECKBOX | + CONTROL "Include sides.",IDC_SIDES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,79,154,9 END @@ -1351,24 +1358,24 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Grove Options" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_Grove_Type1,32,21,164,81,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type1,32,21,164,81,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "%",IDC_STATIC,15,11,8,8 EDITTEXT IDC_Grove_Per1,8,21,20,13,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_Grove_Type2,32,36,164,80,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type2,32,36,164,80,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per2,8,36,20,13,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_Grove_Type3,32,51,164,77,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type3,32,51,164,77,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per3,8,51,20,13,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_Grove_Type4,32,66,164,78,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type4,32,66,164,78,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per4,8,66,20,13,ES_AUTOHSCROLL | ES_NUMBER LTEXT "Tree Type",IDC_STATIC,34,11,34,8 - EDITTEXT IDC_Grove_PerTotal,8,97,20,13,ES_AUTOHSCROLL | + EDITTEXT IDC_Grove_PerTotal,8,97,20,13,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER LTEXT "% Total",IDC_STATIC,33,99,24,8 - COMBOBOX IDC_Grove_Type5,32,81,164,77,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_Grove_Type5,32,81,164,77,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_Grove_Per5,8,81,20,13,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_Grove_NumberTrees,8,115,40,14,ES_AUTOHSCROLL @@ -1384,7 +1391,7 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Fence options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,126 EDITTEXT IDC_FENCE_SPACING_EDIT,146,143,49,12,ES_AUTOHSCROLL LTEXT "Fence spacing:",IDC_STATIC,74,145,68,8 @@ -1397,9 +1404,9 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Blend Material Options" FONT 8, "MS Sans Serif" BEGIN - CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,5,5,190,126 - CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | + CONTROL "",IDC_TERRAIN_SWATCHES,"Static",SS_BLACKFRAME | SS_SUNKEN,65,137,65,55 LTEXT "Gravel",IDC_TERRAIN_NAME,67,197,86,9 END @@ -1413,7 +1420,7 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,79,76,50,14 LTEXT "Which of the following PlayerTemplates shall I use to add the Player you need?", IDC_STATIC,7,7,143,36 - COMBOBOX IDC_COMBO1,7,46,143,260,CBS_DROPDOWNLIST | CBS_SORT | + COMBOBOX IDC_COMBO1,7,46,143,260,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP END @@ -1424,7 +1431,7 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,210,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,210,24,50,14 - CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,7,7,198,284 END @@ -1442,7 +1449,7 @@ BEGIN ES_AUTOHSCROLL | WS_DISABLED CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,7,71,131,10 - COMBOBOX IDC_MAPOBJECT_Script,41,31,166,67,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Script,41,31,166,67,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Script:",IDC_STATIC,7,34,21,8 END @@ -1470,7 +1477,7 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Scorch Options" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_SCORCHTYPE,7,15,186,88,CBS_DROPDOWNLIST | WS_VSCROLL | + COMBOBOX IDC_SCORCHTYPE,7,15,186,88,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_SIZE_EDIT,60,37,17,12,ES_AUTOHSCROLL PUSHBUTTON "1",IDC_SIZE_POPUP,79,37,8,12,BS_BITMAP @@ -1485,18 +1492,18 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,70,242,50,14 PUSHBUTTON "Cancel",IDCANCEL,138,242,50,14 - COMBOBOX IDC_MAP_WEATHER,62,54,112,104,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAP_WEATHER,62,54,112,104,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP RTEXT "Time",IDC_STATIC,7,40,49,8 - COMBOBOX IDC_MAP_TIMEOFDAY,62,38,112,97,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAP_TIMEOFDAY,62,38,112,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP RTEXT "Weather",IDC_STATIC,8,56,49,8 EDITTEXT IDC_MAP_TITLE,62,7,112,12,ES_AUTOHSCROLL - EDITTEXT IDC_MAP_DESCRIPTION,7,73,181,155,ES_MULTILINE | + EDITTEXT IDC_MAP_DESCRIPTION,7,73,181,155,ES_MULTILINE | ES_AUTOHSCROLL | WS_VSCROLL | WS_HSCROLL RTEXT "Map Name",IDC_STATIC,7,7,49,10 RTEXT "Compression",IDC_STATIC,7,24,49,8 - COMBOBOX IDC_MAP_COMPRESSION,62,22,112,97,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAP_COMPRESSION,62,22,112,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END @@ -1505,8 +1512,8 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Layers List" FONT 8, "MS Sans Serif" BEGIN - CONTROL "Tree1",IDC_LL_TREE,"SysTreeView32",TVS_HASBUTTONS | - TVS_LINESATROOT | TVS_EDITLABELS | TVS_DISABLEDRAGDROP | + CONTROL "Tree1",IDC_LL_TREE,"SysTreeView32",TVS_HASBUTTONS | + TVS_LINESATROOT | TVS_EDITLABELS | TVS_DISABLEDRAGDROP | WS_TABSTOP,7,7,207,148 END @@ -1517,7 +1524,7 @@ FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,210,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,210,24,50,14 - CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | + CONTROL "",IDC_OBJECT_TREEVIEW,"Static",SS_BLACKFRAME | SS_SUNKEN,7,24,198,267 LTEXT "Static",IDC_MISSINGLABEL,7,7,195,8 END @@ -1528,7 +1535,7 @@ CAPTION "Water Options" FONT 8, "MS Sans Serif" BEGIN GROUPBOX "Water Area Name:",IDC_STATIC,1,1,195,34 - COMBOBOX IDC_WATERNAME_EDIT,7,15,186,88,CBS_DROPDOWN | CBS_SORT | + COMBOBOX IDC_WATERNAME_EDIT,7,15,186,88,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP GROUPBOX "Water Height:",IDC_WATER_HEIGHT1,1,40,195,33 EDITTEXT IDC_HEIGHT_EDIT,70,52,17,12,ES_AUTOHSCROLL @@ -1536,7 +1543,7 @@ BEGIN PUSHBUTTON "1",IDC_HEIGHT_POPUP,89,52,8,12,BS_BITMAP CONTROL "Create Water Polygon",IDC_WATER_POLYGON,"Button", BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,31,89,99,16 - CONTROL "River",IDC_MAKE_RIVER,"Button",BS_AUTOCHECKBOX | + CONTROL "River",IDC_MAKE_RIVER,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,31,119,98,16 GROUPBOX "Point spacing for water polygons and rivers.", IDC_STATIC,13,140,168,29 @@ -1572,7 +1579,7 @@ CAPTION "Waypoint Options" FONT 8, "MS Sans Serif" BEGIN GROUPBOX "Waypoint Name:",IDC_WAYPOINT_CAPTION1,1,1,195,34 - COMBOBOX IDC_WAYPOINTNAME_EDIT,7,15,186,88,CBS_DROPDOWN | + COMBOBOX IDC_WAYPOINTNAME_EDIT,7,15,186,88,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_WAYPOINTLABEL1_EDIT,7,119,182,12,ES_AUTOHSCROLL EDITTEXT IDC_WAYPOINTLABEL2_EDIT,8,134,182,12,ES_AUTOHSCROLL @@ -1586,7 +1593,7 @@ BEGIN EDITTEXT IDC_WAYPOINT_LOCATIONY,111,50,69,12,ES_AUTOHSCROLL GROUPBOX "List of Current Waypoints:",IDC_LIST_WAYPOINTS,1,74,195, 28 - COMBOBOX IDC_LIST_OF_WAYPOINT_NAMES,7,85,183,88,CBS_DROPDOWN | + COMBOBOX IDC_LIST_OF_WAYPOINT_NAMES,7,85,183,88,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "Bi-Directional",IDC_WAYPOINT_BIDIRECTIONAL,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,11,172,132,9 @@ -1600,7 +1607,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,99,110,50,14 PUSHBUTTON "Cancel",IDCANCEL,152,110,50,14 LTEXT "REPLACEIT",IDC_REPLACETHISTEXT,7,7,195,19 - LISTBOX IDC_VALIDTEAMLIST,7,27,195,82,LBS_SORT | + LISTBOX IDC_VALIDTEAMLIST,7,27,195,82,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END @@ -1609,62 +1616,62 @@ STYLE WS_CHILD | WS_CAPTION CAPTION "Generic" FONT 8, "MS Sans Serif" BEGIN - COMBOBOX IDC_TeamGeneric_Script1,58,13,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script1,58,13,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 1:",IDC_SCRIPT_PREFIX1,6,14,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script2,58,31,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script2,58,31,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 2:",IDC_SCRIPT_PREFIX2,6,32,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script3,58,49,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script3,58,49,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 3:",IDC_SCRIPT_PREFIX3,6,50,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script4,58,67,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script4,58,67,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 4:",IDC_SCRIPT_PREFIX4,6,68,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script5,58,85,160,67,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script5,58,85,160,67,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 5:",IDC_SCRIPT_PREFIX5,6,86,47,12,SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script6,58,103,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script6,58,103,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 6:",IDC_SCRIPT_PREFIX6,6,104,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script7,58,121,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script7,58,121,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 7:",IDC_SCRIPT_PREFIX7,6,122,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script8,58,139,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script8,58,139,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 8:",IDC_SCRIPT_PREFIX8,6,140,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script9,58,157,160,67,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script9,58,157,160,67,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 9:",IDC_SCRIPT_PREFIX9,6,158,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script10,58,175,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script10,58,175,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 10:",IDC_SCRIPT_PREFIX10,6,176,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script11,58,193,160,65,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script11,58,193,160,65,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 11:",IDC_SCRIPT_PREFIX11,6,194,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script12,58,211,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script12,58,211,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 12:",IDC_SCRIPT_PREFIX12,6,212,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script13,58,229,160,66,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script13,58,229,160,66,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 13:",IDC_SCRIPT_PREFIX13,6,230,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script14,58,247,160,65,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script14,58,247,160,65,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 14:",IDC_SCRIPT_PREFIX14,6,248,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script15,58,265,160,67,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script15,58,265,160,67,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 15:",IDC_SCRIPT_PREFIX15,6,266,47,12, SS_CENTERIMAGE - COMBOBOX IDC_TeamGeneric_Script16,58,283,160,73,CBS_DROPDOWN | + COMBOBOX IDC_TeamGeneric_Script16,58,283,160,73,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Script 16:",IDC_SCRIPT_PREFIX16,6,284,47,12, SS_CENTERIMAGE @@ -1703,13 +1710,13 @@ BEGIN CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_MAPOBJECT_StartingHealthEdit,180,54,25,14, ES_AUTOHSCROLL | WS_DISABLED - CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | + CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,11,86,58,10 CONTROL "Indestructible",IDC_MAPOBJECT_Indestructible,"Button", BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,11,110,58,10 CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,79,86,58,10 - CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | + CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,11,97,58,10 LTEXT "Aggressiveness:",IDC_STATIC,11,126,66,8,WS_DISABLED COMBOBOX IDC_MAPOBJECT_Aggressiveness,79,124,126,73, @@ -1725,13 +1732,13 @@ BEGIN EDITTEXT IDC_MAPOBJECT_ShroudClearingDistance,177,226,27,14, ES_AUTOHSCROLL | WS_DISABLED LTEXT "Veterancy:",IDC_STATIC,11,142,66,8,WS_DISABLED - COMBOBOX IDC_MAPOBJECT_Veterancy,79,140,126,73,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Veterancy,79,140,126,73,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_Weather,79,158,126,76,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Weather,79,158,126,76,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_Time,79,174,126,65,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Time,79,174,126,65,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_HitPoints,79,70,126,52,CBS_DROPDOWN | + COMBOBOX IDC_MAPOBJECT_HitPoints,79,70,126,52,CBS_DROPDOWN | CBS_SORT | WS_DISABLED | WS_VSCROLL | WS_TABSTOP LTEXT "Max Hitpoints",IDC_STATIC,11,71,58,8,WS_DISABLED EDITTEXT IDC_MAPOBJECT_StoppingDistance,177,190,27,14, @@ -1750,23 +1757,23 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "Object Properties" FONT 8, "MS Sans Serif" BEGIN - EDITTEXT IDC_MAPOBJECT_Name,33,11,160,12,ES_AUTOHSCROLL | + EDITTEXT IDC_MAPOBJECT_Name,33,11,160,12,ES_AUTOHSCROLL | WS_GROUP - COMBOBOX IDC_MAPOBJECT_Team,33,26,160,141,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Team,33,26,160,141,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_Script,33,40,160,67,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Script,33,40,160,67,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_MAPOBJECT_StartingHealth,64,64,34,71, CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP EDITTEXT IDC_MAPOBJECT_StartingHealthEdit,101,64,25,14, ES_AUTOHSCROLL - COMBOBOX IDC_MAPOBJECT_HitPoints,63,83,66,52,CBS_DROPDOWN | + COMBOBOX IDC_MAPOBJECT_HitPoints,63,83,66,52,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_MAPOBJECT_Aggressiveness,63,101,65,73, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_Veterancy,63,119,65,73,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Veterancy,63,119,65,73,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | + CONTROL "Enabled",IDC_MAPOBJECT_Enabled,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,133,63,42,10 CONTROL "Unsellable",IDC_MAPOBJECT_Unsellable,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,133,73,49,10 @@ -1776,7 +1783,7 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,133,93,58,10 CONTROL "AI Recruitable",IDC_MAPOBJECT_RecruitableAI,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,133,103,61,10 - CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | + CONTROL "Powered",IDC_MAPOBJECT_Powered,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,133,113,44,10 CONTROL "Selectable",IDC_MAPOBJECT_Selectable2,"Button", BS_AUTO3STATE | WS_TABSTOP,133,123,49,10 @@ -1791,40 +1798,40 @@ BEGIN PUSHBUTTON "1",IDC_HEIGHT_POPUP,185,171,8,12,BS_BITMAP EDITTEXT IDC_MAPOBJECT_Angle,158,188,24,12,ES_AUTOHSCROLL PUSHBUTTON "1",IDC_ANGLE_POPUP,185,188,8,12,BS_BITMAP - COMBOBOX IDC_MAPOBJECT_Weather,39,188,93,76,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Weather,39,188,93,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP - COMBOBOX IDC_MAPOBJECT_Time,39,204,93,65,CBS_DROPDOWNLIST | + COMBOBOX IDC_MAPOBJECT_Time,39,204,93,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - COMBOBOX IDC_SOUND_COMBO,66,232,127,160,CBS_DROPDOWNLIST | - CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_GROUP | + COMBOBOX IDC_SOUND_COMBO,66,232,127,160,CBS_DROPDOWNLIST | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Customize",IDC_CUSTOMIZE_CHECKBOX,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,14,247,55,10 - CONTROL "Enabled",IDC_ENABLED_CHECKBOX,"Button",BS_AUTOCHECKBOX | + CONTROL "Enabled",IDC_ENABLED_CHECKBOX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,78,247,50,10 - CONTROL "Looping",IDC_LOOPING_CHECKBOX,"Button",BS_AUTOCHECKBOX | + CONTROL "Looping",IDC_LOOPING_CHECKBOX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,247,50,10 - EDITTEXT IDC_LOOPCOUNT_EDIT,53,258,40,12,ES_AUTOHSCROLL | + EDITTEXT IDC_LOOPCOUNT_EDIT,53,258,40,12,ES_AUTOHSCROLL | ES_NUMBER - COMBOBOX IDC_PRIORITY_COMBO,127,258,65,70,CBS_DROPDOWNLIST | + COMBOBOX IDC_PRIORITY_COMBO,127,258,65,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_VOLUME_EDIT,53,274,40,12,ES_AUTOHSCROLL | ES_NUMBER - EDITTEXT IDC_MIN_VOLUME_EDIT,146,274,45,12,ES_AUTOHSCROLL | + EDITTEXT IDC_MIN_VOLUME_EDIT,146,274,45,12,ES_AUTOHSCROLL | ES_NUMBER - EDITTEXT IDC_MIN_RANGE_EDIT,53,290,40,12,ES_AUTOHSCROLL | + EDITTEXT IDC_MIN_RANGE_EDIT,53,290,40,12,ES_AUTOHSCROLL | ES_NUMBER - EDITTEXT IDC_MAX_RANGE_EDIT,146,290,45,12,ES_AUTOHSCROLL | + EDITTEXT IDC_MAX_RANGE_EDIT,146,290,45,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "No Scale",IDC_SCALE_OFF,"Button",BS_AUTORADIOBUTTON | + CONTROL "No Scale",IDC_SCALE_OFF,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,120,207,45,10 - CONTROL "z",IDC_SCALE_ON,"Button",BS_AUTORADIOBUTTON | NOT + CONTROL "z",IDC_SCALE_ON,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,153,208,8,10 - EDITTEXT IDC_MAPOBJECT_Scale,163,204,24,14,ES_AUTOHSCROLL | NOT + EDITTEXT IDC_MAPOBJECT_Scale,163,204,24,14,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED - PUSHBUTTON "1",IDC_SCALE_POPUP,189,206,8,12,BS_BITMAP | NOT + PUSHBUTTON "1",IDC_SCALE_POPUP,189,206,8,12,BS_BITMAP | NOT WS_VISIBLE | WS_DISABLED LISTBOX IDC_MAPOBJECT_BuildWithUpgrades,7,318,184,50, - LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | + LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_GROUP | WS_TABSTOP GROUPBOX "General",IDC_STATIC_MAPOBJECT_GENERAL,4,2,193,54 GROUPBOX "Logical",IDC_STATIC_MAPOBJECT_LOGICAL,4,56,193,105 @@ -1909,7 +1916,7 @@ END // #ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO DISCARDABLE +GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_ABOUTBOX, DIALOG BEGIN @@ -2414,201 +2421,201 @@ IDC_SCORCH CURSOR DISCARDABLE "IDC_Scorch.cur" IDD_PROPEDIT DLGINIT BEGIN IDC_KEYTYPE, 0x403, 5, 0 -0x6f42, 0x6c6f, "\000" +0x6f42, 0x6c6f, "\000" IDC_KEYTYPE, 0x403, 4, 0 -0x6e49, 0x0074, +0x6e49, 0x0074, IDC_KEYTYPE, 0x403, 5, 0 -0x6552, 0x6c61, "\000" +0x6552, 0x6c61, "\000" IDC_KEYTYPE, 0x403, 6, 0 -0x7341, 0x6963, 0x0069, +0x7341, 0x6963, 0x0069, IDC_KEYTYPE, 0x403, 8, 0 -0x6e55, 0x6369, 0x646f, 0x0065, +0x6e55, 0x6369, 0x646f, 0x0065, 0 END IDD_BUILD_LIST_PANEL DLGINIT BEGIN IDC_REBUILDS, 0x403, 5, 0 -0x6f4e, 0x656e, "\000" +0x6f4e, 0x656e, "\000" IDC_REBUILDS, 0x403, 2, 0 -0x0031, +0x0031, IDC_REBUILDS, 0x403, 2, 0 -0x0032, +0x0032, IDC_REBUILDS, 0x403, 2, 0 -0x0033, +0x0033, IDC_REBUILDS, 0x403, 2, 0 -0x0034, +0x0034, IDC_REBUILDS, 0x403, 2, 0 -0x0035, +0x0035, IDC_REBUILDS, 0x403, 10, 0 -0x6e55, 0x696c, 0x696d, 0x6574, 0x0064, +0x6e55, 0x696c, 0x696d, 0x6574, 0x0064, 0 END IDD_TeamReinforcement DLGINIT BEGIN IDC_TRANSPORT_COMBO, 0x403, 11, 0 -0x6548, 0x696c, 0x6f63, 0x7470, 0x7265, "\000" +0x6548, 0x696c, 0x6f63, 0x7470, 0x7265, "\000" IDC_VETERANCY, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_VETERANCY, 0x403, 8, 0 -0x6556, 0x6574, 0x6172, 0x006e, +0x6556, 0x6574, 0x6172, 0x006e, IDC_VETERANCY, 0x403, 6, 0 -0x6c45, 0x7469, 0x0065, +0x6c45, 0x7469, 0x0065, IDC_VETERANCY, 0x403, 7, 0 -0x6548, 0x6f72, 0x6369, "\000" +0x6548, 0x6f72, 0x6369, "\000" IDC_WAYPOINT_COMBO, 0x403, 9, 0 -0x6157, 0x7079, 0x696f, 0x746e, "\000" +0x6157, 0x7079, 0x696f, 0x746e, "\000" 0 END IDD_TeamBehavior DLGINIT BEGIN IDC_ENEMY_INTERACTIONS, 0x403, 6, 0 -0x6c53, 0x6565, 0x0070, +0x6c53, 0x6565, 0x0070, IDC_ENEMY_INTERACTIONS, 0x403, 8, 0 -0x6150, 0x7373, 0x7669, 0x0065, +0x6150, 0x7373, 0x7669, 0x0065, IDC_ENEMY_INTERACTIONS, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_ENEMY_INTERACTIONS, 0x403, 6, 0 -0x6c41, 0x7265, 0x0074, +0x6c41, 0x7265, 0x0074, IDC_ENEMY_INTERACTIONS, 0x403, 11, 0 -0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" +0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" 0 END IDD_SCORCH_OPTIONS DLGINIT BEGIN IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3120, "\000" +0x6353, 0x726f, 0x6863, 0x3120, "\000" IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3220, "\000" +0x6353, 0x726f, 0x6863, 0x3220, "\000" IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3320, "\000" +0x6353, 0x726f, 0x6863, 0x3320, "\000" IDC_SCORCHTYPE, 0x403, 9, 0 -0x6353, 0x726f, 0x6863, 0x3420, "\000" +0x6353, 0x726f, 0x6863, 0x3420, "\000" IDC_SCORCHTYPE, 0x403, 13, 0 -0x6f52, 0x6e75, 0x2064, 0x6853, 0x6461, 0x776f, "\000" +0x6f52, 0x6e75, 0x2064, 0x6853, 0x6461, 0x776f, "\000" IDC_SCORCHTYPE, 0x403, 12, 0 -0x7243, 0x6361, 0x206b, 0x614d, 0x6b72, 0x0073, +0x7243, 0x6361, 0x206b, 0x614d, 0x6b72, 0x0073, 0 END IDD_WATER_OPTIONS DLGINIT BEGIN IDC_WATERNAME_EDIT, 0x403, 22, 0 -0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, -0x6f69, 0x006e, +0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, +0x6f69, 0x006e, 0 END IDD_WAYPOINT_OPTIONS DLGINIT BEGIN IDC_WAYPOINTNAME_EDIT, 0x403, 22, 0 -0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, -0x6f69, 0x006e, +0x6e49, 0x7469, 0x6169, 0x436c, 0x6d61, 0x7265, 0x5061, 0x736f, 0x7469, +0x6f69, 0x006e, IDC_LIST_OF_WAYPOINT_NAMES, 0x403, 1, 0 -"\000" +"\000" 0 END IDD_TeamObjectProperties DLGINIT BEGIN IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 -0x6544, 0x6461, "\000" +0x6544, 0x6461, "\000" IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3532, 0x0025, +0x3532, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3035, 0x0025, +0x3035, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3537, 0x0025, +0x3537, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 -0x3031, 0x2530, "\000" +0x3031, 0x2530, "\000" IDC_MAPOBJECT_StartingHealth, 0x403, 6, 0 -0x744f, 0x6568, 0x0072, +0x744f, 0x6568, 0x0072, IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 -0x6c53, 0x6565, 0x0070, +0x6c53, 0x6565, 0x0070, IDC_MAPOBJECT_Aggressiveness, 0x403, 8, 0 -0x6150, 0x7373, 0x7669, 0x0065, +0x6150, 0x7373, 0x7669, 0x0065, IDC_MAPOBJECT_Aggressiveness, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 -0x6c41, 0x7265, 0x0074, +0x6c41, 0x7265, 0x0074, IDC_MAPOBJECT_Aggressiveness, 0x403, 11, 0 -0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" +0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_MAPOBJECT_Veterancy, 0x403, 8, 0 -0x6556, 0x6574, 0x6172, 0x006e, +0x6556, 0x6574, 0x6172, 0x006e, IDC_MAPOBJECT_Veterancy, 0x403, 6, 0 -0x6c45, 0x7469, 0x0065, +0x6c45, 0x7469, 0x0065, IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 -0x6548, 0x6f72, 0x6369, "\000" +0x6548, 0x6f72, 0x6369, "\000" IDC_MAPOBJECT_Weather, 0x403, 16, 0 -0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, +0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, IDC_MAPOBJECT_Weather, 0x403, 17, 0 -0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" +0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" IDC_MAPOBJECT_Weather, 0x403, 15, 0 -0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" +0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" IDC_MAPOBJECT_Time, 0x403, 13, 0 -0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" +0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" IDC_MAPOBJECT_Time, 0x403, 14, 0 -0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, +0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, IDC_MAPOBJECT_Time, 0x403, 16, 0 -0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, +0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, IDC_MAPOBJECT_HitPoints, 0x403, 19, 0 -0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, -"\000" +0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, +"\000" 0 END IDD_MAPOBJECT_PROPS DLGINIT BEGIN IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 -0x6544, 0x6461, "\000" +0x6544, 0x6461, "\000" IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3532, 0x0025, +0x3532, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3035, 0x0025, +0x3035, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 4, 0 -0x3537, 0x0025, +0x3537, 0x0025, IDC_MAPOBJECT_StartingHealth, 0x403, 5, 0 -0x3031, 0x2530, "\000" +0x3031, 0x2530, "\000" IDC_MAPOBJECT_StartingHealth, 0x403, 6, 0 -0x744f, 0x6568, 0x0072, +0x744f, 0x6568, 0x0072, IDC_MAPOBJECT_HitPoints, 0x403, 19, 0 -0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, -"\000" +0x6544, 0x6166, 0x6c75, 0x2074, 0x6948, 0x2074, 0x6f50, 0x6e69, 0x7374, +"\000" IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 -0x6c53, 0x6565, 0x0070, +0x6c53, 0x6565, 0x0070, IDC_MAPOBJECT_Aggressiveness, 0x403, 8, 0 -0x6150, 0x7373, 0x7669, 0x0065, +0x6150, 0x7373, 0x7669, 0x0065, IDC_MAPOBJECT_Aggressiveness, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_MAPOBJECT_Aggressiveness, 0x403, 6, 0 -0x6c41, 0x7265, 0x0074, +0x6c41, 0x7265, 0x0074, IDC_MAPOBJECT_Aggressiveness, 0x403, 11, 0 -0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" +0x6741, 0x7267, 0x7365, 0x6973, 0x6576, "\000" IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 -0x6f4e, 0x6d72, 0x6c61, "\000" +0x6f4e, 0x6d72, 0x6c61, "\000" IDC_MAPOBJECT_Veterancy, 0x403, 8, 0 -0x6556, 0x6574, 0x6172, 0x006e, +0x6556, 0x6574, 0x6172, 0x006e, IDC_MAPOBJECT_Veterancy, 0x403, 6, 0 -0x6c45, 0x7469, 0x0065, +0x6c45, 0x7469, 0x0065, IDC_MAPOBJECT_Veterancy, 0x403, 7, 0 -0x6548, 0x6f72, 0x6369, "\000" +0x6548, 0x6f72, 0x6369, "\000" IDC_MAPOBJECT_Weather, 0x403, 16, 0 -0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, +0x7355, 0x2065, 0x614d, 0x2070, 0x6557, 0x7461, 0x6568, 0x0072, IDC_MAPOBJECT_Weather, 0x403, 17, 0 -0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" +0x7355, 0x2065, 0x6f4e, 0x6d72, 0x6c61, 0x4d20, 0x646f, 0x6c65, "\000" IDC_MAPOBJECT_Weather, 0x403, 15, 0 -0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" +0x7355, 0x2065, 0x6e53, 0x776f, 0x4d20, 0x646f, 0x6c65, "\000" IDC_MAPOBJECT_Time, 0x403, 13, 0 -0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" +0x7355, 0x2065, 0x614d, 0x2070, 0x6954, 0x656d, "\000" IDC_MAPOBJECT_Time, 0x403, 14, 0 -0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, +0x7355, 0x2065, 0x6144, 0x2079, 0x6f4d, 0x6564, 0x006c, IDC_MAPOBJECT_Time, 0x403, 16, 0 -0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, +0x7355, 0x2065, 0x694e, 0x6867, 0x2074, 0x6f4d, 0x6564, 0x006c, 0 END @@ -2618,19 +2625,19 @@ END // String Table // -STRINGTABLE PRELOAD DISCARDABLE +STRINGTABLE PRELOAD DISCARDABLE BEGIN IDR_MAINFRAME "Generals World Builder\nMission\nMission\n Missions (*.map)\n.map\nGeneralsMap\n Generals Mission Map" IDS_SKELETON "SkeletonWindow" END -STRINGTABLE PRELOAD DISCARDABLE +STRINGTABLE PRELOAD DISCARDABLE BEGIN AFX_IDS_APP_TITLE "WorldBuilder" AFX_IDS_IDLEMESSAGE "Ready" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_INDICATOR_EXT "EXT" ID_INDICATOR_CAPS "CAP" @@ -2640,7 +2647,7 @@ BEGIN ID_INDICATOR_REC "REC" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FILE_NEW "Create a new document\nNew" ID_FILE_OPEN "Open an existing document\nOpen" @@ -2653,13 +2660,13 @@ BEGIN ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_APP_ABOUT "Display program information, version number and copyright\nAbout" ID_APP_EXIT "Quit the application; prompts to save documents\nExit" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FILE_MRU_FILE1 "Open this document" ID_FILE_MRU_FILE2 "Open this document" @@ -2679,13 +2686,13 @@ BEGIN ID_FILE_MRU_FILE16 "Open this document" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_NEXT_PANE "Switch to the next window pane\nNext Pane" ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_WINDOW_NEW "Open another window for the active document\nNew Window" ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons" @@ -2695,7 +2702,7 @@ BEGIN ID_WINDOW_SPLIT "Split the active window into panes\nSplit" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_EDIT_CLEAR "Erase the selection\nErase" ID_EDIT_CLEAR_ALL "Erase everything\nErase All" @@ -2710,13 +2717,13 @@ BEGIN ID_EDIT_REDO "Redo the previously undone action\nRedo" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar" ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN AFX_IDS_SCSIZE "Change the window size" AFX_IDS_SCMOVE "Change the window position" @@ -2727,14 +2734,14 @@ BEGIN AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN AFX_IDS_SCRESTORE "Restore the window to normal size" AFX_IDS_SCTASKLIST "Activate Task List" AFX_IDS_MDICHILD "Activate this window" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN AFX_IDS_PREVIEW_CLOSE "Close print preview mode\nCancel Preview" IDS_NEW "New" @@ -2749,7 +2756,7 @@ BEGIN IDS_FILE_IS_READONLY "The file is read-only. Change the protection, or use Save As to save to another file." END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN IDS_REPLACEFILE "%s already exists. Do you want to replace it?" IDS_ONLY_ONE_FILE "Sorry, only one map may be open at a time." @@ -2763,14 +2770,14 @@ BEGIN IDS_SCRIPT_NOWARNINGS "No Warnings" IDS_CONFIRM_REPLACE_TEXTURE "Replace all occurences of texture %s?" ID_RAMPTOOL "Place Ramps on the map\nRamp" - IDS_CONFIRM_REMOVE_CLIFF_MAPPING + IDS_CONFIRM_REMOVE_CLIFF_MAPPING "Remove all cliff mapping in the entire map?" IDS_NUM_SELECTED_ON_TEAM "For team %s, %d units selected." IDS_MAX_OBJECTS "The object count has exceeded %d. Please reduce the number of objects in this map or performance will suffer." IDS_REPLACEOWNER "Team %s has an invalid owner. Please select a valid owner from the list below:" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN IDS_SPLASH_LOADING "Loading..." IDS_SINGLE_SELECTION_ONLY "Single Selection Only" @@ -2779,23 +2786,23 @@ BEGIN IDS_MAPOBJECT_PROPS_TITLE "Object Properties" IDS_NO_PROBLEMS "No problems were detected." IDS_DUPLICATE_TEAM_REMOVED "Duplicate instance of team ""%s"" removed." - IDS_PLAYERLESS_TEAM_REMOVED + IDS_PLAYERLESS_TEAM_REMOVED "Team ""%s"" was on non-existent player ""%s"". Team removed." IDS_NEED_TO_FIX_TEAMS "One or more objects had invalid teams. Please run Validation>Fix Teams to correct this." END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_BRUSH_TOOL "Draw the height on the height map.\nHeight Brush" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FEATHERTOOL "Smooths the height levels in the height map.\nSmooth Height" ID_BIG_TILE_TOOL "Draws a Brush Options Size block of the current texture tile. \nLarge Tile" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_BRUSH_ADD_TOOL "Adds height to (raises) the height map.\nMound" ID_BRUSH_SUBTRACT_TOOL "Removes height from (lowers) the height map.\nDig" @@ -2804,7 +2811,7 @@ BEGIN ID_AUTO_EDGE_OUT_TOOL "Auto edges the current texture area outward.\nAuto Edge Out" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_EYEDROPPER_TOOL "Hot key ALT. Selects the foreground texture by picking on the texture in the edit windows.\nEyedropper" ID_PLACE_OBJECT_TOOL "Places the current object in Object Selection panel. Drag to orient.\nPlace Object" @@ -2813,7 +2820,7 @@ BEGIN ID_GROVE_TOOL "Click to place random foliage, drag to place foliage in a rectangular area.\nGrove" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_TEAM_EDIT "Edit teams.\nEdit Teams" ID_LOCK_HORIZONTAL "Lock tool movement to 45 degree increment.\nLock Angle" @@ -2824,51 +2831,51 @@ BEGIN ID_HAND_SCROLL_TOOL "Hot key space bar. Scrolls the map.\nScroll" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_ROAD_TOOL "Click and Drag to make Roads.\nRoad" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_MOLD_TOOL "Shapes the terrain using a 3D mesh.\nMesh Mold Tool" ID_RULER_TOOL "Measure distance between two points. \nRuler Tool" ID_SCRIPT_EDIT "Edit scripts.\nEdit Scripts" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_FENCE_TOOL "Places a row of objects. Drag then use shift to stretch.\nFence" ID_WATER_TOOL "Add and modify water areas.\nWater Tool" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_SCORCH_TOOL "Add Scorchmarks to the map\nAdd Scorchmarks" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_EDIT_MAPSETTINGS "Edit Map Settings" ID_EDIT_PICKROADS "Pick only roads" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_VIEW_LAYERS_LIST "Show or hide the layers list\nToggle LayersList" END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN ID_BORDERTOOL "Add and adjust borders.\nBorder Tool" - ID_VALIDATION_GENERATEMAPREPORT + ID_VALIDATION_GENERATEMAPREPORT "Generate a report about Map validity, possible problems, etc." ID_VALIDATION_FIXTEAMS "Adjust all teams so that they're ""Execute Associated Action"" is false." END -STRINGTABLE DISCARDABLE +STRINGTABLE DISCARDABLE BEGIN - ID_VIEW_SHOW_SOUND_CIRCLES + ID_VIEW_SHOW_SOUND_CIRCLES "Show the minimum and maximum radii around objects with ambient sounds\nShow Sound Circles" END @@ -2899,4 +2906,3 @@ LANGUAGE 9, 1 ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED - diff --git a/GeneralsMD/Code/Tools/WorldBuilder/res/resource.h b/GeneralsMD/Code/Tools/WorldBuilder/res/resource.h index f2f8982adf0..977f030a095 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/res/resource.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/res/resource.h @@ -718,6 +718,10 @@ #define ID_SELECTLAYEROBJECT 33344 #define ID_SELECTACTIVELAYER 33345 #define ID_VIEW_SHOW_SOUND_CIRCLES 33346 +#define ID_LOOK_NORTH 33347 +#define ID_LOOK_SOUTH 33348 +#define ID_LOOK_WEST 33349 +#define ID_LOOK_EAST 33350 #define IDS_NEW 61446 #define IDS_RESIZE 61447 #define IDS_REMOVING_INUSE_TEAM 61448 @@ -766,7 +770,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 #define _APS_NEXT_RESOURCE_VALUE 242 -#define _APS_NEXT_COMMAND_VALUE 33347 +#define _APS_NEXT_COMMAND_VALUE 33351 #define _APS_NEXT_CONTROL_VALUE 1354 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/DrawObject.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/DrawObject.cpp index 86ee3342469..f817e0e206b 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/DrawObject.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/DrawObject.cpp @@ -2110,19 +2110,11 @@ if (_skip_drawobject_render) { continue; } -// DEBUG! -if (pMapObj->isSelected()) { - Transform.Get_Translation(); -} Coord3D loc = *pMapObj->getLocation(); if (TheTerrainRenderObject) { loc.z += TheTerrainRenderObject->getHeightMapHeight(loc.x, loc.y, nullptr); } - // Cull. - //SphereClass bounds(Vector3(loc.x, loc.y, loc.z), THE_RADIUS); - //if (rinfo.Camera.Cull_Sphere(bounds)) { - // continue; - //} + // Range overlays can extend well beyond THE_RADIUS, so culling by the object center would hide visible feedback. Bool doArrow = true; if (pMapObj->getFlag(FLAG_ROAD_FLAGS) || pMapObj->getFlag(FLAG_BRIDGE_FLAGS) || pMapObj->isWaypoint()) { @@ -2227,7 +2219,7 @@ if (pMapObj->isSelected()) { } } if (m_drawPolygonAreas) { - DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); Int selected; for (selected = 0; selected < 2; selected++) { for (PolygonTrigger *pTrig=PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { @@ -2338,7 +2330,7 @@ if (pMapObj->isSelected()) { } DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); Matrix3D tmReset(Transform); DX8Wrapper::Set_Transform(D3DTS_WORLD,tmReset); @@ -2350,7 +2342,7 @@ if (pMapObj->isSelected()) { DX8Wrapper::Set_Shader(m_shaderClass); DX8Wrapper::Draw_Triangles( 0, m_feedbackIndexCount/3, 0, m_feedbackVertexCount); DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); + DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferWater); } } diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/EditAction.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/EditAction.cpp index e1e31053733..53b43357247 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/EditAction.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/EditAction.cpp @@ -158,6 +158,7 @@ BOOL EditAction::OnInitDialog() selItem = item; } +#if RTS_ZEROHOUR name = pTemplate->getName2().str(); count = 0; if (pTemplate->getName2().isEmpty()) continue; @@ -190,6 +191,7 @@ BOOL EditAction::OnInitDialog() ins.item.pszText = (char*)name; ins.item.cchTextMax = 0; m_actionTreeView.InsertItem(&ins); +#endif } m_actionTreeView.Select(selItem, TVGN_FIRSTVISIBLE); m_actionTreeView.SelectItem(selItem); @@ -221,7 +223,7 @@ void EditAction::formatScriptActionText(Int parameterNdx) { m_myEditCtrl.SetSel(0, 1000); m_myEditCtrl.SetSelectionCharFormat(cf); - //m_myEditCtrl.SetReadOnly(); + //m_myEditCtrl.SetReadOnly(); // Set up the links. cf.dwMask = CFE_UNDERLINE | CFM_LINK | CFM_COLOR; @@ -346,7 +348,7 @@ BOOL EditAction::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) AsciiString strings[MAX_PARMS]; Int numStrings = m_action->getUiStrings(strings); Int i; - Bool match = false; + Bool match = false; for (i=0; igetName2().str(); count = 0; if (pTemplate->getName2().isEmpty()) continue; @@ -202,6 +203,7 @@ BOOL EditCondition::OnInitDialog() ins.item.pszText = (char*)name; ins.item.cchTextMax = 0; m_conditionTreeView.InsertItem(&ins); +#endif } m_conditionTreeView.Select(selItem, TVGN_FIRSTVISIBLE); m_conditionTreeView.SelectItem(selItem); @@ -233,7 +235,7 @@ void EditCondition::formatConditionText(Int parameterNdx) { m_myEditCtrl.SetSel(0, 1000); m_myEditCtrl.SetSelectionCharFormat(cf); - //m_myEditCtrl.SetReadOnly(); + //m_myEditCtrl.SetReadOnly(); // Set up the links. cf.dwMask = CFE_UNDERLINE | CFM_LINK | CFM_COLOR; @@ -358,7 +360,7 @@ BOOL EditCondition::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) AsciiString strings[MAX_PARMS]; Int numStrings = m_condition->getUiStrings(strings); Int i; - Bool match = false; + Bool match = false; for (i=0; igetReal()*100.0f); showCombo = false; break; +#endif case Parameter::FLAG: captionText = "Flag named:"; @@ -1923,7 +1933,8 @@ BOOL EditParameter::OnInitDialog() break; - case Parameter::LEFT_OR_RIGHT: +#if RTS_ZEROHOUR + case Parameter::LEFT_OR_RIGHT: captionText = "Evacuate Container Side Choices:"; pList->InsertString(-1,"Left"); pList->InsertString(-1,"Right"); @@ -1931,7 +1942,7 @@ BOOL EditParameter::OnInitDialog() pList->SetCurSel(m_parameter->getInt() - 1); showList = true; break; - +#endif case Parameter::RELATION: captionText = "Relation:"; @@ -2234,11 +2245,13 @@ void EditParameter::OnOK() } break; +#if RTS_ZEROHOUR case Parameter::PERCENT: if (! scanReal(pEdit, 1.0f/100.0f)) { return; } break; +#endif case Parameter::BOOLEAN: case Parameter::COMPARISON: @@ -2265,10 +2278,11 @@ void EditParameter::OnOK() break; - case Parameter::LEFT_OR_RIGHT: - m_parameter->friend_setInt(pList->GetCurSel() + 1); - break; - +#if RTS_ZEROHOUR + case Parameter::LEFT_OR_RIGHT: + m_parameter->friend_setInt(pList->GetCurSel() + 1); + break; +#endif case Parameter::LOCALIZED_TEXT: pCombo->GetWindowText(txt); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/LayersList.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/LayersList.cpp index f96502efd14..dfe282be47c 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/LayersList.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/LayersList.cpp @@ -804,11 +804,30 @@ void LayersList::OnEndEditLabel(NMHDR *pNotifyStruct, LRESULT* pResult) return; } - layerIt->layerName = AsciiString(ptvdi->item.pszText); - if (mCurrentlyEditingLabel.compareNoCase(AsciiString(TheDefaultLayerName.c_str())) == 0) { + AsciiString newLayerName(ptvdi->item.pszText); + Bool isDefaultLayer = mCurrentlyEditingLabel.compareNoCase(AsciiString(TheDefaultLayerName.c_str())) == 0; + Bool isActiveLayer = mCurrentlyEditingLabel.compareNoCase(TheActiveLayerName.c_str()) == 0; + AsciiString objectLayerName = isDefaultLayer ? AsciiString::TheEmptyString : newLayerName; + + // Keep persisted object and trigger assignments in sync with the renamed layer. + for (ListMapObjectPtrIt objectIt = layerIt->objectsInLayer.begin(); + objectIt != layerIt->objectsInLayer.end(); ++objectIt) { + (*objectIt)->getProperties()->setAsciiString(TheKey_objectLayer, objectLayerName); + } + for (ListPolygonTriggerPtrIt triggerIt = layerIt->polygonTriggersInLayer.begin(); + triggerIt != layerIt->polygonTriggersInLayer.end(); ++triggerIt) { + (*triggerIt)->setLayerName(newLayerName); + } + + layerIt->layerName = newLayerName; + if (isDefaultLayer) { // update the default label to be the new layer name. TheDefaultLayerName = layerIt->layerName.str(); } + if (isActiveLayer) { + // The active layer is tracked by name. + TheActiveLayerName = layerIt->layerName.str(); + } // do this to prevent rebuilding the tree. pTree->SetItemText(ptvdi->item.hItem, layerIt->layerName.str()); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/RulerTool.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/RulerTool.cpp index 894650e5dcb..de425122d29 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/RulerTool.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/RulerTool.cpp @@ -146,7 +146,7 @@ void RulerTool::setLength(Real length) } CString str; - str.Format("Diameter (in feet): %f", length * 2.0f); + str.Format("Diameter (in feet): %f", length * 2.0f); CMainFrame::GetMainFrame()->SetMessageText(str); } diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp index 27af92ec44a..9644c190c17 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp @@ -1634,7 +1634,7 @@ void ScriptDialog::OnLoad() } catch(...) { - DEBUG_CRASH(("threw exception in ScriptDialog::OnLoad")); + DEBUG_CRASH(("threw exception in ScriptDialog::OnLoad")); } } diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WBHeightMap.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WBHeightMap.cpp index c013a07b049..2d14b2cf47d 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WBHeightMap.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WBHeightMap.cpp @@ -45,7 +45,6 @@ #include #include -#define dontUSE_FLAT_HEIGHT_MAP //----------------------------------------------------------------------------- // Private Data //----------------------------------------------------------------------------- @@ -68,7 +67,7 @@ void WBHeightMap::setFlattenHeights(Bool flat) { if (m_flattenHeights != flat) { m_flattenHeights = flat; -#ifndef USE_FLAT_HEIGHT_MAP +#if !USE_FLAT_HEIGHT_MAP m_originX = 0; m_originY = 0; updateBlock(0, 0, m_x-1, m_y-1, m_map, nullptr); @@ -85,7 +84,7 @@ void WBHeightMap::setFlattenHeights(Bool flat) /** Flattens the terrain for the top down view.. */ //============================================================================= void WBHeightMap::flattenHeights() { -#ifndef USE_FLAT_HEIGHT_MAP +#if !USE_FLAT_HEIGHT_MAP Real theZ = THE_Z; Int i, j; for (j=0; jgetXExtent()+overhang), MAP_XY_FACTOR*(m_map->getYExtent()+overhang), MAP_HEIGHT_SCALE*m_map->getMaxHeightValue()+MAP_XY_FACTOR); @@ -304,7 +303,7 @@ void WBHeightMap::Render(RenderInfoClass & rinfo) if (m_flattenHeights) { flattenHeights(); } -#ifdef USE_FLAT_HEIGHT_MAP +#if USE_FLAT_HEIGHT_MAP FlatHeightMapRenderObjClass::Render(rinfo); #else HeightMapRenderObjClass::Render(rinfo); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index 3aeba787257..89af322f931 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -506,6 +506,30 @@ void WorldHeightMapEdit::loadImagesFromTerrainType( TerrainType *terrain ) } +Bool WorldHeightMapEdit::getRawTileData(Short tileNdx, Int width, UnsignedByte *buffer, Int bufLen) +{ + TileData *pSrc = nullptr; + if (tileNdx / 4 < NUM_SOURCE_TILES) { + pSrc = m_sourceTiles[tileNdx / 4]; + } + if (bufLen < (width * width * TILE_BYTES_PER_PIXEL)) { + return false; + } + if (pSrc && pSrc->hasRGBDataForWidth(2 * width)) { + UnsignedByte *pSrcData = pSrc->getRGBDataForWidth(2 * width); + Int xOffset = (tileNdx & 1) ? width : 0; + Int yOffset = (tileNdx & 2) ? width : 0; + for (Int j = 0; j < width; ++j) { + UnsignedByte *pDestData = buffer + j * width * TILE_BYTES_PER_PIXEL; + UnsignedByte *pSrcRow = pSrcData + (j + yOffset) * width * TILE_BYTES_PER_PIXEL * 2; + pSrcRow += xOffset * TILE_BYTES_PER_PIXEL; + memcpy(pDestData, pSrcRow, width * TILE_BYTES_PER_PIXEL); + } + return true; + } + return false; +} + UnsignedByte * WorldHeightMapEdit::getPointerToClassTileData(Int texClass) { TileData *pSrc = nullptr; @@ -600,7 +624,11 @@ void WorldHeightMapEdit::saveToFile(DataChunkOutput &chunkWriter) chunkWriter.closeDataChunk(); /***************BLEND TILE DATA ***************/ +#if RTS_GENERALS + chunkWriter.openDataChunk("BlendTileData", K_BLEND_TILE_VERSION_7); +#else chunkWriter.openDataChunk("BlendTileData", K_BLEND_TILE_VERSION_8); +#endif chunkWriter.writeInt(m_dataSize); chunkWriter.writeArrayOfBytes((char*)m_tileNdxes, m_dataSize*sizeof(Short)); chunkWriter.writeArrayOfBytes((char*)m_blendTileNdxes, m_dataSize*sizeof(Short)); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WaterOptions.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WaterOptions.cpp index 04e0f463ea9..5203b6d73dd 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WaterOptions.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WaterOptions.cpp @@ -167,6 +167,8 @@ void WaterOptions::OnChangeWaterEdit() if (pTrig->isValid()) { didMatch = true; } else { + // Keep layer membership in sync when discarding the invalid trigger. + TheLayersList->removePolygonTriggerFromLayersList(pTrig); PolygonTrigger::removePolygonTrigger(pTrig); } break; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WaypointOptions.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WaypointOptions.cpp index 4ce35b40e57..316757ca84c 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WaypointOptions.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WaypointOptions.cpp @@ -491,6 +491,8 @@ void WaypointOptions::OnChangeWaypointnameEdit() if (pTrig->isValid()) { didMatch = true; } else { + // Keep layer membership in sync when discarding the invalid trigger. + TheLayersList->removePolygonTriggerFromLayersList(pTrig); PolygonTrigger::removePolygonTrigger(pTrig); } break; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp index 5f19126638a..888d8ef5c4e 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp @@ -378,7 +378,9 @@ BOOL CWorldBuilderApp::InitInstance() initSubsystem(TheScriptEngine, (ScriptEngine*)(new ScriptEngine())); +#if RTS_ZEROHOUR TheScriptEngine->turnBreezeOff(); // stop the tree sway. +#endif // [2/11/2003] ini.loadFileDirectory( "Data\\Scripts\\Scripts", INI_LOAD_OVERWRITE, nullptr ); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/mapobjectprops.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/mapobjectprops.cpp index 8b2eb251fe1..deb3bb4da35 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/mapobjectprops.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/mapobjectprops.cpp @@ -665,7 +665,7 @@ void MapObjectProps::PopSliderFinished(const long sliderID, long theVal) case IDC_ANGLE_POPUP: if ( m_posUndoable != nullptr ) { - REF_PTR_RELEASE(m_posUndoable); // belongs to pDoc now. + REF_PTR_RELEASE(m_posUndoable); // belongs to pDoc now. } m_posUndoable = nullptr; break; @@ -2890,4 +2890,3 @@ void MapObjectProps::OnKillfocusMAPOBJECTXYPosition() { SetPosition(); } - diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index 5f42dc261fa..ccfe7c33acb 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2168,6 +2168,14 @@ BEGIN_MESSAGE_MAP(WbView3d, WbView) ON_COMMAND(ID_VIEW_SHOWMACROTEXTURE, OnViewShowmacrotexture) ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWMACROTEXTURE, OnUpdateViewShowmacrotexture) ON_COMMAND(ID_EDIT_SELECTMACROTEXTURE, OnEditSelectmacrotexture) + ON_COMMAND(ID_LOOK_EAST, OnLookEast) + ON_UPDATE_COMMAND_UI(ID_LOOK_EAST, OnUpdateLookEast) + ON_COMMAND(ID_LOOK_NORTH, OnLookNorth) + ON_UPDATE_COMMAND_UI(ID_LOOK_NORTH, OnUpdateLookNorth) + ON_COMMAND(ID_LOOK_SOUTH, OnLookSouth) + ON_UPDATE_COMMAND_UI(ID_LOOK_SOUTH, OnUpdateLookSouth) + ON_COMMAND(ID_LOOK_WEST, OnLookWest) + ON_UPDATE_COMMAND_UI(ID_LOOK_WEST, OnUpdateLookWest) ON_COMMAND(ID_VIEW_SHOWSOFTWATER, OnViewShowSoftWater) ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWEXTRABLENDS, OnUpdateViewShowExtraBlends) ON_COMMAND(ID_VIEW_SHOWEXTRABLENDS, OnViewExtraBlends) @@ -2929,6 +2937,46 @@ void WbView3d::OnEditSelectmacrotexture() } +void WbView3d::OnLookEast() +{ + m_cameraAngle = -PI / 2; +} + +void WbView3d::OnUpdateLookEast(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_cameraAngle == -PI / 2 ? 1 : 0); +} + +void WbView3d::OnLookNorth() +{ + m_cameraAngle = 0; +} + +void WbView3d::OnUpdateLookNorth(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_cameraAngle == 0 ? 1 : 0); +} + +void WbView3d::OnLookSouth() +{ + m_cameraAngle = PI; +} + +void WbView3d::OnUpdateLookSouth(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_cameraAngle == PI ? 1 : 0); +} + +void WbView3d::OnLookWest() +{ + m_cameraAngle = PI / 2; +} + +void WbView3d::OnUpdateLookWest(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_cameraAngle == PI / 2 ? 1 : 0); +} + void WbView3d::OnViewShowshadows() { m_showShadows = !m_showShadows; @@ -3260,4 +3308,3 @@ void WbView3d::OnUpdateViewShowSoundCircles(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_showSoundCircles ? 1 : 0); } -