diff --git a/binaries/data/mods/official/maps/scenarios/triggerTest.pmp b/binaries/data/mods/official/maps/scenarios/triggerTest.pmp
new file mode 100644
index 0000000000..2fd5ed9f12
--- /dev/null
+++ b/binaries/data/mods/official/maps/scenarios/triggerTest.pmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d81cc43c837cb427881906d36d12a2c3e299885d9b8c3d6f2714106b3ee9dd59
+size 207975
diff --git a/binaries/data/mods/official/maps/scenarios/triggerTest.xml b/binaries/data/mods/official/maps/scenarios/triggerTest.xml
new file mode 100644
index 0000000000..bbb4751929
--- /dev/null
+++ b/binaries/data/mods/official/maps/scenarios/triggerTest.xml
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ab2a5f92f97c6d84f9ee40681e280d9076eb4c1135f17cf036229c08ce61a90c
+size 1474
diff --git a/binaries/data/mods/official/scripts/TriggerSpecs.xml b/binaries/data/mods/official/scripts/TriggerSpecs.xml
new file mode 100644
index 0000000000..8323379e32
--- /dev/null
+++ b/binaries/data/mods/official/scripts/TriggerSpecs.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ int
+ 0
+
+
+
+ ATLAS_CINEMA_LIST
+ 0
+
+
+
+ holy, crap, comma, seperated, choices
+ 0
+
+
+
+
+
+
+
+
+
+
+ string
+ 0
+
+
+
+
+
\ No newline at end of file
diff --git a/binaries/data/mods/official/scripts/entity_functions.js b/binaries/data/mods/official/scripts/entity_functions.js
index bd66c85c20..1743b49d48 100644
--- a/binaries/data/mods/official/scripts/entity_functions.js
+++ b/binaries/data/mods/official/scripts/entity_functions.js
@@ -791,9 +791,16 @@ function performBuild( evt )
var hp = t.traits.health;
var points = parseFloat( b.rate ) * parseFloat( b.speed ) / 1000.0;
+ if ( bp.curr == 0 )
+ {
+ t.flattenTerrain(); //make the terrain stable for the building
+ //t.placeBuildingFootprint(false); //false means display regular footprint, not rubble
+ }
bp.curr += points;
hp.curr = Math.min( hp.max, hp.curr + (points/bp.max)*hp.max );
+
+
if( bp.curr >= bp.max )
{
// We've finished building this object; convert the foundation to a building
diff --git a/binaries/data/mods/official/scripts/trigger_functions.js b/binaries/data/mods/official/scripts/trigger_functions.js
new file mode 100644
index 0000000000..c9f337dee2
--- /dev/null
+++ b/binaries/data/mods/official/scripts/trigger_functions.js
@@ -0,0 +1,4 @@
+function getAlwaysTrue()
+{
+return true;
+}
diff --git a/source/graphics/CinemaTrack.h b/source/graphics/CinemaTrack.h
index edc6a5a2c0..e3df65b4a2 100644
--- a/source/graphics/CinemaTrack.h
+++ b/source/graphics/CinemaTrack.h
@@ -8,7 +8,7 @@
#include "maths/NUSpline.h"
/*
- Andrew (aka pyrolink)
+ Andrew Decker (aka pyrolink)
Contact: ajdecker1022@msn.com
desc: contains various functions used for cinematic camera tracks
See also: CinemaHandler.cpp, Cinematic.h/.cpp
diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp
index 44adf92ecb..0740636af3 100644
--- a/source/graphics/MapReader.cpp
+++ b/source/graphics/MapReader.cpp
@@ -24,6 +24,7 @@
#include "renderer/WaterManager.h"
#include "simulation/Entity.h"
#include "simulation/EntityManager.h"
+#include "simulation/TriggerManager.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
@@ -334,6 +335,8 @@ private:
void ReadEnvironment(XMBElement parent);
void ReadCamera(XMBElement parent);
void ReadCinema(XMBElement parent);
+ void ReadTriggers(XMBElement parent);
+ void ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group);
int ReadEntities(XMBElement parent, double end_time);
int ReadNonEntities(XMBElement parent, double end_time);
@@ -663,6 +666,164 @@ void CXMLReader::ReadCinema(XMBElement parent)
g_Game->GetView()->GetCinema()->SetAllTracks(trackList);
}
+void CXMLReader::ReadTriggers(XMBElement parent)
+{
+ MapTriggerGroup rootGroup( CStrW(L"Triggers"), CStrW(L"") );
+ g_TriggerManager.DestroyEngineTriggers();
+ ReadTriggerGroup(parent, rootGroup);
+}
+
+void CXMLReader::ReadTriggerGroup(XMBElement parent, MapTriggerGroup& group)
+{
+ #define EL(x) int el_##x = xmb_file.getElementID(#x)
+ #define AT(x) int at_##x = xmb_file.getAttributeID(#x)
+
+ EL(group);
+ EL(trigger);
+ EL(active);
+ EL(delay);
+ EL(maxruncount);
+ EL(conditions);
+ EL(logicblock);
+ EL(logicblockend);
+ EL(condition);
+ EL(parameter);
+ EL(linklogic);
+ EL(effects);
+ EL(effect);
+
+ AT(name);
+ AT(function);
+ AT(display);
+ AT(not);
+
+ #undef EL
+ #undef AT
+
+ CStrW name = parent.getAttributes().getNamedItem(at_name), parentName = group.parentName;
+ if ( group.name == L"Triggers" )
+ name = group.name;
+
+ MapTriggerGroup mapGroup(name, parentName);
+
+ XERO_ITER_EL(parent, groupChild)
+ {
+ int elementName = groupChild.getNodeName();
+ if ( elementName == el_group )
+ ReadTriggerGroup(groupChild, mapGroup);
+
+ else if ( elementName == el_trigger )
+ {
+ MapTrigger mapTrigger;
+ mapTrigger.name = CStrW( groupChild.getAttributes().getNamedItem(at_name) );
+
+ //Read everything in this trigger
+ XERO_ITER_EL(groupChild, triggerChild)
+ {
+ elementName = triggerChild.getNodeName();
+ if ( elementName == el_active )
+ {
+ if ( CStr("false") == CStr( triggerChild.getText() ) )
+ mapTrigger.active = false;
+ else
+ mapTrigger.active = true;
+ }
+
+ else if ( elementName == el_maxruncount )
+ mapTrigger.maxRunCount = CStr( triggerChild.getText() ).ToInt();
+ else if ( elementName == el_delay )
+ mapTrigger.timeValue = CStr( triggerChild.getText() ).ToFloat();
+
+ else if ( elementName == el_conditions )
+ {
+ //Read in all conditions for this trigger
+ XERO_ITER_EL(triggerChild, condition)
+ {
+ elementName = condition.getNodeName();
+ if ( elementName == el_condition )
+ {
+ MapTriggerCondition mapCondition;
+ mapCondition.name = condition.getAttributes().getNamedItem(at_name);
+ mapCondition.functionName = condition.getAttributes().getNamedItem(at_function);
+ mapCondition.displayName = condition.getAttributes().getNamedItem(at_display);
+
+ CStr notAtt(condition.getAttributes().getNamedItem(at_not));
+ if ( notAtt == CStr("true") )
+ mapCondition.not = true;
+
+ //Read in each condition child
+ XERO_ITER_EL(condition, conditionChild)
+ {
+ elementName = conditionChild.getNodeName();
+
+ if ( elementName == el_parameter )
+ mapCondition.parameters.push_back( conditionChild.getText() );
+ else if ( elementName == el_linklogic )
+ {
+ CStr logic = conditionChild.getText();
+ if ( logic == CStr("AND") )
+ mapCondition.linkLogic = 1;
+ else
+ mapCondition.linkLogic = 2;
+ }
+ }
+ mapTrigger.conditions.push_back(mapCondition);
+ } //Read all conditions
+
+ else if ( elementName == el_logicblock)
+ {
+ if ( CStr(condition.getAttributes().getNamedItem(at_not)) == CStr("true") )
+ mapTrigger.AddLogicBlock(true);
+ else
+ mapTrigger.AddLogicBlock(false);
+ }
+ else if ( elementName == el_logicblockend)
+ mapTrigger.AddLogicBlockEnd();
+
+ } //Read all conditions
+ }
+
+ else if ( elementName == el_effects )
+ {
+ //Read all effects
+ XERO_ITER_EL(triggerChild, effect)
+ {
+ if ( effect.getNodeName() != el_effect )
+ {
+ debug_warn("Invalid effect tag in trigger XML file");
+ return;
+ }
+ MapTriggerEffect mapEffect;
+ mapEffect.name = effect.getAttributes().getNamedItem(at_name);
+ mapEffect.functionName = effect.getAttributes().getNamedItem(at_function);
+ mapEffect.displayName = effect.getAttributes().getNamedItem(at_display);
+
+ //Read parameters
+ XERO_ITER_EL(effect, effectChild)
+ {
+ if ( effectChild.getNodeName() != el_parameter )
+ {
+ debug_warn("Invalid parameter tag in trigger XML file");
+ return;
+ }
+ mapEffect.parameters.push_back( effectChild.getText() );
+ }
+ mapTrigger.effects.push_back(mapEffect);
+ }
+ }
+ else
+ debug_warn("Invalid trigger node child in trigger XML file");
+
+ } //Read trigger children
+ g_TriggerManager.AddTrigger(mapGroup, mapTrigger);
+ }
+ else
+ debug_warn("Invalid group node child in XML file");
+ } //Read group children
+
+ g_TriggerManager.AddGroup(mapGroup);
+}
+
int CXMLReader::ReadEntities(XMBElement parent, double end_time)
{
XMBElementList entities = parent.getChildNodes();
@@ -848,6 +1009,10 @@ int CXMLReader::ProgressiveRead()
{
ReadCinema(node);
}
+ else if (name == "Triggers")
+ {
+ ReadTriggers(node);
+ }
else
debug_warn("Invalid map XML data");
diff --git a/source/graphics/MapReader.h b/source/graphics/MapReader.h
index fc89e6f31c..0d5d8f922b 100644
--- a/source/graphics/MapReader.h
+++ b/source/graphics/MapReader.h
@@ -16,6 +16,7 @@ class SkyManager;
class CLightEnv;
class CCamera;
class CCinemaManager;
+class CTriggerManager;
class CXMLReader;
@@ -28,7 +29,8 @@ public:
CMapReader();
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void LoadMap(const char* filename, CTerrain *pTerrain, CUnitManager *pUnitMan,
- WaterManager* pWaterMan, SkyManager* pSkyMan, CLightEnv *pLightEnv, CCamera *pCamera, CCinemaManager* pCinema);
+ WaterManager* pWaterMan, SkyManager* pSkyMan, CLightEnv *pLightEnv, CCamera *pCamera,
+ CCinemaManager* pCinema);
private:
// UnpackTerrain: unpack the terrain from the input stream
@@ -78,6 +80,7 @@ private:
CLightEnv* pLightEnv;
CCamera* pCamera;
CCinemaManager* pCinema;
+ CTriggerManager* pTrigMan;
CStr filename_xml;
// UnpackTerrain generator state
diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp
index 99013d31dd..c3896ea194 100644
--- a/source/graphics/MapWriter.cpp
+++ b/source/graphics/MapWriter.cpp
@@ -28,6 +28,7 @@
#include "renderer/WaterManager.h"
#include "simulation/EntityTemplate.h"
#include "simulation/EntityTemplateCollection.h"
+#include "simulation/TriggerManager.h"
#include "simulation/Entity.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -395,7 +396,27 @@ void CMapWriter::WriteXML(const char* filename,
}
} //track data
}
- } //(Did this really happen) - I blame XML
+ } //(Did this really happen) - I blame XML :p
+
+ const std::list& groups = g_TriggerManager.GetAllTriggerGroups();
+ std::list rootChildren;
+ std::list::const_iterator root = std::find( groups.begin(), groups.end(),
+ CStrW(L"Triggers") );
+ std::for_each(rootChildren.begin(), rootChildren.end(), copyIfRootChild(rootChildren));
+
+ {
+ XML_Element("Triggers");
+ for ( std::list::const_iterator it = rootChildren.begin();
+ it != rootChildren.end(); ++it )
+ {
+ WriteTriggerGroup(xml_file_, *it, groups);
+ }
+ for ( std::list::const_iterator it = root->triggers.begin();
+ it != root->triggers.end(); ++it )
+ {
+ WriteTrigger(xml_file_, *it);
+ }
+ }
}
if (! XML_StoreVFS(h))
@@ -405,6 +426,112 @@ void CMapWriter::WriteXML(const char* filename,
(void)vfs_close(h);
}
+void CMapWriter::WriteTriggerGroup(XMLWriter_File& xml_file_, const MapTriggerGroup& group, const std::list& groupList)
+{
+ XML_Element("Group");
+ XML_Attribute("name", group.name);
+
+ for ( std::list::const_iterator it = group.childGroups.begin();
+ it != group.childGroups.end(); ++it )
+ {
+ //Not very efficient...
+ std::list::const_iterator it2 = std::find(groupList.begin(), groupList.end(), *it);
+ if ( it2 != groupList.end() )
+ WriteTriggerGroup(xml_file_, *it2, groupList);
+ else
+ debug_warn("Invalid trigger group ID while writing map");
+ }
+
+ for ( std::list::const_iterator it = group.triggers.begin(); it != group.triggers.end(); ++it )
+ {
+ WriteTrigger(xml_file_, *it);
+ }
+}
+
+void CMapWriter::WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigger)
+{
+ XML_Element("Trigger");
+ XML_Attribute("name", trigger.name);
+
+ {
+ if ( trigger.active )
+ XML_Setting("Active", "true");
+ else
+ XML_Setting("Active", "false");
+ XML_Setting("MaxRunCount", trigger.maxRunCount);
+ XML_Setting("Delay", trigger.timeValue);
+ }
+
+ {
+ XML_Element("Conditions");
+ for ( std::list::const_iterator it2 = trigger.conditions.begin();
+ it2 != trigger.conditions.end(); ++it2 )
+ {
+ size_t distance = std::distance( trigger.conditions.begin(), it2 );
+ std::set::const_iterator logicIter;
+
+ if ( ( logicIter = trigger.logicBlocks.find(MapTriggerLogicBlock(distance)) )
+ != trigger.logicBlocks.end() )
+ {
+ XML_Element("LogicBlock");
+ if ( logicIter->not )
+ XML_Attribute("not", "true");
+ else
+ XML_Attribute("not", "false");
+ }
+
+ {
+ XML_Element("Condition");
+ XML_Attribute("name", it2->name);
+ XML_Attribute("function", it2->functionName);
+ XML_Attribute("display", it2->displayName);
+
+ if ( it2->not )
+ XML_Attribute("not", "true");
+ else
+ XML_Attribute("not", "false");
+
+ for ( std::list::const_iterator paramIter = it2->parameters.begin();
+ paramIter != it2->parameters.end(); ++paramIter )
+ {
+ XML_Setting("Parameter", *paramIter);
+ }
+
+ if ( it2->linkLogic == 1 )
+ {
+ XML_Setting("LinkLogic", "AND");
+ }
+ else if ( it2->linkLogic == 2 )
+ {
+ XML_Setting("LinkLogic", "OR");
+ }
+
+ if ( trigger.logicBlockEnds.find(distance) != trigger.logicBlockEnds.end() )
+ {
+ XML_Element("LogicBlockEnd");
+ }
+ }
+ } //Read all conditions
+ } //Conditions' scope
+
+ {
+ XML_Element("Effects");
+ for ( std::list::const_iterator it2 = trigger.effects.begin();
+ it2 != trigger.effects.end(); ++it2 )
+ {
+ XML_Element("Effect");
+ XML_Attribute("name", it2->name);
+ XML_Attribute("function", it2->functionName);
+ XML_Attribute("display", it2->displayName);
+
+ for ( std::list::const_iterator paramIter = it2->parameters.begin();
+ paramIter != it2->parameters.end(); ++paramIter )
+ {
+ XML_Setting("parameter", *paramIter);
+ }
+ }
+ } //Effects' scope
+}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RewriteAllMaps
void CMapWriter::RewriteAllMaps(CTerrain* pTerrain, CUnitManager* pUnitMan,
@@ -428,3 +555,5 @@ void CMapWriter::RewriteAllMaps(CTerrain* pTerrain, CUnitManager* pUnitMan,
writer.SaveMap(n, pTerrain, pUnitMan, pWaterMan, pSkyMan, pLightEnv, pCamera, pCinema);
}
}
+
+
\ No newline at end of file
diff --git a/source/graphics/MapWriter.h b/source/graphics/MapWriter.h
index 67dd511ccf..6152e1e878 100644
--- a/source/graphics/MapWriter.h
+++ b/source/graphics/MapWriter.h
@@ -6,13 +6,18 @@
#include "ps/CStr.h"
#include "ps/FilePacker.h"
+
class CLightEnv;
class CTerrain;
class CUnitManager;
class CCamera;
class CCinemaManager;
+class CTriggerManager;
class WaterManager;
class SkyManager;
+struct MapTrigger;
+struct MapTriggerGroup;
+class XMLWriter_File;
class CMapWriter : public CMapIO
{
@@ -20,11 +25,16 @@ public:
// constructor
CMapWriter();
// SaveMap: try to save the current map to the given file
- void SaveMap(const char* filename, CTerrain* pTerr, CUnitManager* pUnitMan, WaterManager* pWaterMan, SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema);
+ void SaveMap(const char* filename, CTerrain* pTerr, CUnitManager* pUnitMan,
+ WaterManager* pWaterMan, SkyManager* pSkyMan,
+ CLightEnv* pLightEnv, CCamera* pCamera,
+ CCinemaManager* pCinema);
// RewriteAllMaps: for use during development: load/save all maps, to
// update them to the newest format.
- static void RewriteAllMaps(CTerrain* pTerrain, CUnitManager* pUnitMan, WaterManager* pWaterMan, SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema);
+ static void RewriteAllMaps(CTerrain* pTerrain, CUnitManager* pUnitMan, WaterManager* pWaterMan,
+ SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera,
+ CCinemaManager* pCinema);
private:
// PackMap: pack the current world into a raw data stream
@@ -38,7 +48,12 @@ private:
std::vector& tileIndices);
// WriteXML: output some other data (entities, etc) in XML format
- void WriteXML(const char* filename, CUnitManager* pUnitMan, WaterManager* pWaterMan, SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema);
+ void WriteXML(const char* filename, CUnitManager* pUnitMan, WaterManager* pWaterMan,
+ SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera,
+ CCinemaManager* pCinema);
+ void WriteTriggerGroup(XMLWriter_File& xml_file_, const MapTriggerGroup& group,
+ const std::list& groupList);
+ void WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigger);
};
#endif
diff --git a/source/main.cpp b/source/main.cpp
index 66ba6cd214..eea3be632c 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -32,6 +32,7 @@ that of Atlas depending on commandline parameters.
#include "ps/Globals.h"
#include "ps/Interact.h"
#include "network/SessionManager.h"
+#include "simulation/TriggerManager.h"
#include "graphics/GameView.h"
#include "simulation/Scheduler.h"
#include "sound/CMusicPlayer.h"
@@ -264,6 +265,10 @@ static void Frame()
PROFILE( "camera update" );
g_Game->GetView()->Update(float(TimeSinceLastFrame));
}
+
+ PROFILE_START("trigger update");
+ g_TriggerManager.Update( (float)TimeSinceLastFrame );
+ PROFILE_END("trigger udpate");
PROFILE_START( "selection and interaction ui" );
// TODO Where does GameView end and other things begin?
diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp
index 4a8362bd9c..80ae2e1357 100644
--- a/source/ps/GameSetup/GameSetup.cpp
+++ b/source/ps/GameSetup/GameSetup.cpp
@@ -58,6 +58,7 @@
#include "simulation/FormationCollection.h"
#include "simulation/FormationManager.h"
#include "simulation/TerritoryManager.h"
+#include "simulation/TriggerManager.h"
#include "simulation/PathfindEngine.h"
#include "simulation/Projectile.h"
#include "simulation/Scheduler.h"
@@ -480,7 +481,9 @@ static void InitScripting()
// Register the JavaScript interfaces with the runtime
SColour::ScriptingInit();
CEntity::ScriptingInit();
+ CTrigger::ScriptingInit();
CEntityTemplate::ScriptingInit();
+
JSI_Sound::ScriptingInit();
CProfileNode::ScriptingInit();
@@ -789,7 +792,8 @@ void Shutdown(uint flags)
TIMER_BEGIN("shutdown game scripting stuff");
delete &g_GameAttributes;
-
+
+ delete &g_TriggerManager;
delete &g_FormationManager;
delete &g_TechnologyCollection;
delete &g_EntityFormationCollection;
@@ -1035,6 +1039,9 @@ void Init(int argc, char* argv[], uint flags)
g_EntityFormationCollection.loadTemplates();
g_TechnologyCollection.loadTechnologies();
new CFormationManager;
+ new CTriggerManager;
+ g_TriggerManager.LoadXML(CStr("scripts/TriggerSpecs.xml"));
+ g_ScriptingHost.RunScript("scripts/trigger_functions.js");
// CEntityManager is managed by CWorld
//new CEntityManager;
diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp
index f99ccabb9e..ab9f645f12 100644
--- a/source/scripting/ScriptGlue.cpp
+++ b/source/scripting/ScriptGlue.cpp
@@ -42,6 +42,7 @@
#include "simulation/EntityManager.h"
#include "simulation/EntityTemplate.h"
#include "simulation/FormationManager.h"
+#include "simulation/TriggerManager.h"
#include "simulation/LOSManager.h"
#include "simulation/Scheduler.h"
#include "simulation/Simulation.h"
@@ -1265,6 +1266,33 @@ JSBool getGameTime( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, js
return JS_TRUE;
}
+JSBool registerTrigger( JSContext* cx, JSObject* UNUSED(globalObject), uint argc,
+ jsval* argv, jsval* rval )
+{
+ JSU_REQUIRE_PARAMS_CPP(1);
+ CTrigger* trigger = ToNative( argv[0] );
+ debug_assert( trigger );
+
+ g_TriggerManager.AddTrigger( trigger );
+ *rval = JSVAL_NULL;
+ return JS_TRUE;
+}
+JSBool getTrigger( JSContext* cx, JSObject* UNUSED(globalObject), uint argc,
+ jsval* argv, jsval* rval )
+{
+ JSU_REQUIRE_PARAMS_CPP(1);
+ CStrW name = ToPrimitive( argv[0] );
+
+ if ( g_TriggerManager.m_TriggerMap.find(name) != g_TriggerManager.m_TriggerMap.end() )
+ *rval = ToJSVal( g_TriggerManager.m_TriggerMap[name] );
+ else
+ {
+ debug_printf("Invalid trigger name %ws", name);
+ *rval = JSVAL_NULL;
+ }
+ return JS_TRUE;
+}
+
// Reveal map
JSBool revealMap( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval )
{
diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h
index c305c5c4a0..f54bca37cd 100644
--- a/source/simulation/Entity.h
+++ b/source/simulation/Entity.h
@@ -366,6 +366,7 @@ public:
void DestroyAllNotifiers();
int findSector( int divs, float angle, float maxAngle, bool negative=true );
+ jsval FlattenTerrain( JSContext* cx, uintN argc, jsval* argv );
CEntityFormation* GetFormation();
jsval GetFormationPenalty( JSContext* cx, uintN argc, jsval* argv );
diff --git a/source/simulation/EntityScriptInterface.cpp b/source/simulation/EntityScriptInterface.cpp
index 0a3acfd855..0e5cc43d75 100644
--- a/source/simulation/EntityScriptInterface.cpp
+++ b/source/simulation/EntityScriptInterface.cpp
@@ -83,6 +83,7 @@ void CEntity::ScriptingInit()
AddMethod( "onDamaged", 1 );
AddMethod( "getVisibleEntities", 0 );
AddMethod( "getDistance", 1 );
+ AddMethod( "flattenTerrain", 0 );
AddClassProperty( L"traits.id.classes", (GetFn)&CEntity::getClassSet, (SetFn)&CEntity::setClassSet );
AddClassProperty( L"template", (CEntityTemplate* CEntity::*)&CEntity::m_base, false, (NotifyFn)&CEntity::loadBase );
@@ -922,3 +923,33 @@ int CEntity::GetAttackAction( HEntity target )
// Default return value is an invalid action ID
return 0;
}
+
+jsval CEntity::FlattenTerrain( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
+{
+ float xDiff, yDiff;
+ CVector3D pos = m_position;
+ CVector2D pos2D(m_position.X, m_position.Z);
+
+ if ( m_bounds->m_type == CBoundingObject::BOUND_CIRCLE )
+ xDiff = yDiff = m_bounds->m_radius;
+ else
+ {
+ CBoundingBox* box = static_cast( m_bounds );
+ xDiff = box->m_w;
+ yDiff = box->m_d;
+ }
+ //If we ever need to take rotated bounding boxes into account...
+ //CVector2D points[4] = { CVector2D(xDiff, yDiff), CVector2D(-xDiff, -yDiff),
+ //CVector2D(-xDiff, yDiff), CVector2D(xDiff, yDiff) };
+ //CVector3D circle = points[0].FindCircumCircle(points[1], points[2]);
+ //float cos = cosf(m_graphics_orientation.Y), sin = sinf(m_graphics_orientation.Y);
+
+ //for ( size_t i = 0; i<4; ++i )
+ //{
+ // points[i].x *= cos*circle.Z;
+ // points[i].y *= sin*circle.Z;
+ //}
+ g_Game->GetWorld()->GetTerrain()->FlattenArea(pos.X-xDiff, pos.X+xDiff, pos.Z-yDiff, pos.Z+yDiff);
+ snapToGround();
+ return JS_TRUE;
+}
\ No newline at end of file
diff --git a/source/simulation/TriggerManager.cpp b/source/simulation/TriggerManager.cpp
new file mode 100644
index 0000000000..b1e2103712
--- /dev/null
+++ b/source/simulation/TriggerManager.cpp
@@ -0,0 +1,406 @@
+#include "precompiled.h"
+
+#include "TriggerManager.h"
+#include "scripting/ScriptingHost.h"
+#include "ps/XML/Xeromyces.h"
+#include "ps/XML/XeroXMB.h"
+#include "ps/CLogger.h"
+
+#define LOG_CATEGORY "Triggers"
+
+
+CTrigger::CTrigger()
+{
+ m_timeLeft = m_timeDelay = m_maxRunCount = m_runCount = m_active = 0;
+}
+CTrigger::~CTrigger()
+{
+
+}
+CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
+ const CStrW& effectFunc)
+{
+ m_name = name;
+ m_active = active;
+ m_timeLeft = m_timeDelay = delay;
+ m_runCount = 0;
+ m_maxRunCount = maxRuns;
+
+ m_conditionFuncString = condFunc;
+ m_effectFuncString = effectFunc;
+ m_conditionFunction.Compile( L"TriggerCondition::" + m_name, condFunc );
+ m_effectFunction.Compile( L"TriggerEffect::" + m_name, effectFunc );
+
+}
+CTrigger::CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
+ CScriptObject& condFunc, CScriptObject& effectFunc)
+{
+ m_name = name;
+ m_active = active;
+ m_timeLeft = m_timeDelay = delay;
+ m_runCount = 0;
+ m_maxRunCount = maxRuns;
+ m_conditionFunction = condFunc;
+ m_effectFunction = effectFunc;
+}
+
+JSBool CTrigger::Construct( JSContext* cx, JSObject* UNUSED(obj), uint argc, jsval* argv, jsval* rval )
+{
+ JSU_REQUIRE_PARAMS_CPP(6);
+
+ CScriptObject condFunc( JS_ValueToFunction(cx, argv[4]) );
+ CScriptObject effectFunc( JS_ValueToFunction(cx, argv[5]) );
+ CTrigger* newTrigger = new CTrigger( ToPrimitive( argv[0] ),
+ ToPrimitive( argv[1] ),
+ ToPrimitive( argv[2] ),
+ ToPrimitive( argv[3] ),
+ condFunc, effectFunc );
+
+ g_TriggerManager.AddTrigger(newTrigger);
+ *rval = OBJECT_TO_JSVAL( newTrigger->GetScript() );
+ return JS_TRUE;
+}
+
+CTrigger& CTrigger::operator= (const CTrigger& trigger)
+{
+ m_name = trigger.m_name;
+ m_active = trigger.m_active;
+ m_timeLeft = trigger.m_timeLeft;
+ m_timeDelay = trigger.m_timeDelay;
+ m_maxRunCount = trigger.m_maxRunCount;
+ m_conditionFunction = trigger.m_conditionFunction;
+ m_effectFunction = trigger.m_effectFunction;
+
+ return *this;
+}
+
+void CTrigger::ScriptingInit()
+{
+ AddProperty(L"runCount", &CTrigger::m_runCount, true);
+ AddProperty(L"name", &CTrigger::m_name, true);
+ AddProperty(L"maxRunCount", &CTrigger::m_maxRunCount);
+ AddProperty(L"timeDelay", &CTrigger::m_timeDelay);
+
+ AddMethod( "activate", 0 );
+ AddMethod( "deactivate", 0 );
+
+ CJSObject::ScriptingInit("Trigger", CTrigger::Construct, 6);
+}
+
+bool CTrigger::ShouldFire()
+{
+ if ( !m_active )
+ return false;
+ return m_conditionFunction.Run( this->GetScript() );
+}
+bool CTrigger::Fire()
+{
+ m_effectFunction.Run( this->GetScript() );
+ ++m_runCount;
+ m_timeLeft = m_timeDelay;
+ return (m_runCount < m_maxRunCount);
+}
+
+jsval CTrigger::Activate(JSContext* UNUSED(cx), uint UNUSED(argc), jsval* UNUSED(argv))
+{
+ m_active = true;
+ return JS_TRUE;
+}
+jsval CTrigger::Deactivate(JSContext* UNUSED(cx), uint UNUSED(argc), jsval* UNUSED(argv))
+{
+ m_active = false;
+ return JS_TRUE;
+}
+
+
+void TriggerParameter::SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize)
+{
+ windowPosition.Remove( CStr(L" ") );
+ windowSize.Remove( CStr(L" ") );
+
+ xPos = windowPosition.BeforeFirst( CStrW(L",") ).ToInt();
+ yPos = windowPosition.AfterFirst( CStrW(L",") ).ToInt();
+ xSize = windowSize.BeforeFirst( CStrW(L",") ).ToInt();
+ ySize = windowSize.AfterFirst( CStrW(L",") ).ToInt();
+ windowType = _windowType;
+}
+
+bool TriggerParameter::operator< ( const TriggerParameter& rhs ) const
+{
+ if ( row < rhs.row )
+ return true;
+ else if ( row == rhs.row)
+ return ( column < rhs.column );
+
+ return false;
+}
+//===========Trigger Manager===========
+
+CTriggerManager::CTriggerManager()
+{
+}
+
+CTriggerManager::~CTriggerManager()
+{
+ DestroyEngineTriggers();
+}
+
+void CTriggerManager::DestroyEngineTriggers()
+{
+ for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
+ {
+ SAFE_DELETE(it->second);
+ }
+ m_TriggerMap.clear();
+}
+std::vector CTriggerManager::GetTriggerChoices(const std::wstring& name)
+{
+ return m_TriggerChoices[name];
+}
+
+void CTriggerManager::Update(float delta)
+{
+ std::list expired;
+ for ( TriggerIter it = m_TriggerMap.begin(); it != m_TriggerMap.end(); ++it )
+ {
+ if ( it->second->ShouldFire() )
+ {
+ it->second->m_timeLeft -= delta;
+ if ( it->second->m_timeLeft < 0 )
+ {
+ if ( !it->second->Fire() )
+ expired.push_back(it);
+ }
+ }
+ }
+
+ //Remove all expired triggers
+ for ( std::list::iterator it = expired.begin(); it != expired.end(); ++it )
+ {
+ delete (*it)->second;;
+ m_TriggerMap.erase(*it);
+ }
+}
+
+void CTriggerManager::AddTrigger(CTrigger* trigger)
+{
+ m_TriggerMap[trigger->GetName()] = trigger;
+}
+void CTriggerManager::AddGroup(const MapTriggerGroup& group)
+{
+ m_GroupList.push_back(group);
+}
+void CTriggerManager::SetAllGroups(const std::list& groups)
+{
+ m_GroupList = groups;
+}
+
+void CTriggerManager::AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger)
+{
+ CStrW conditionBody(L"if ( ");
+ CStrW linkLogic[] = { CStrW(L""), CStrW(L" && "), CStrW(L" || ") };
+ size_t i=0;
+
+ for ( std::list::const_iterator it = trigger.conditions.begin();
+ it != trigger.conditions.end(); ++it, ++i )
+ {
+ //Opening parenthesis here?
+ std::set::const_iterator blockIt;
+ if ( ( blockIt = trigger.logicBlocks.find(MapTriggerLogicBlock(i)) ) != trigger.logicBlocks.end() )
+ {
+ if ( blockIt->not )
+ conditionBody += CStrW(L"!");
+ conditionBody += CStrW(L" (");
+ }
+
+ if ( it->not )
+ conditionBody += CStrW(L"!");
+ conditionBody += it->functionName;
+ conditionBody += CStrW(L"(");
+ for ( std::list::const_iterator it2 = it->parameters.begin(); it2 !=
+ it->parameters.end(); ++it2 )
+ {
+ conditionBody += *it2;
+ if ( std::distance(it2, it->parameters.end()) != 1 )
+ conditionBody += CStrW(L", ");
+ }
+
+ conditionBody += CStrW(L")");
+ if ( trigger.logicBlockEnds.find(i) != trigger.logicBlockEnds.end() )
+ conditionBody += CStrW(L" )");
+
+ if ( std::distance(it, trigger.conditions.end()) != 1 )
+ conditionBody += linkLogic[it->linkLogic];
+ }
+ conditionBody += CStrW(L" )"); //closing if
+ conditionBody += CStrW(L" { return true; } ");
+ CStrW effectBody;
+
+ for ( std::list::const_iterator it = trigger.effects.begin();
+ it != trigger.effects.end(); ++it )
+ {
+ effectBody += it->functionName;
+ effectBody += CStrW(L"(");
+ for ( std::list::const_iterator it2 = it->parameters.begin(); it2 !=
+ it->parameters.end(); ++it2 )
+ {
+ effectBody += *it2;
+ std::list::const_iterator endIt = it->parameters.end();
+ if ( std::distance(it2, endIt) != 1 )
+ effectBody += CStrW(L", ");
+ }
+
+ effectBody += CStrW(L");");
+ }
+ group.triggers.push_back(trigger);
+ CTrigger* newTrigger = new CTrigger(trigger.name, trigger.active, trigger.timeValue,
+ trigger.maxRunCount, conditionBody, effectBody);
+ AddTrigger(newTrigger);
+}
+
+
+//XML stuff
+
+bool CTriggerManager::LoadXML( const CStr& filename )
+{
+ CXeromyces XeroFile;
+
+ if ( XeroFile.Load( filename.c_str() ) != PSRETURN_OK )
+ return false;
+
+ #define EL(x) int el_##x = XeroFile.getElementID(#x)
+ #define AT(x) int at_##x = XeroFile.getAttributeID(#x)
+
+ EL(condition);
+ EL(effect);
+ EL(definitions);
+
+ #undef EL
+ #undef AT
+
+ //Return false on any error to be extra sure the point gets across (FIX IT)
+ XMBElement root = XeroFile.getRoot();
+
+ if ( root.getNodeName() != el_definitions )
+ return false;
+
+ XERO_ITER_EL(root, rootChild)
+ {
+ int name = rootChild.getNodeName();
+ if ( name == el_condition )
+ {
+ if ( !loadTriggerSpec(rootChild, XeroFile, true) )
+ {
+ LOG(ERROR, LOG_CATEGORY, "Error detected in Trigger XML tag. File: %s", filename);
+ return false;
+ }
+ }
+ else if ( name == el_effect )
+ {
+ if ( !loadTriggerSpec(rootChild, XeroFile, false) )
+ {
+ LOG(ERROR, LOG_CATEGORY, "Error detected in Trigger XML tag. File: %s", filename);
+ return false;
+ }
+ }
+ else
+ {
+ LOG(ERROR, LOG_CATEGORY, "Invalid tag in trigger XML. File: ws", filename);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CTriggerManager::loadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition )
+{
+ #define EL(x) int el_##x = XeroFile.getElementID(#x)
+ #define AT(x) int at_##x = XeroFile.getAttributeID(#x)
+
+ EL(parameter);
+ EL(window);
+ EL(inputtype);
+ EL(parameterorder);
+ EL(windowrow);
+ EL(choices);
+
+ AT(type);
+ AT(position);
+ AT(name);
+ AT(size);
+ AT(function);
+
+ #undef EL
+ #undef AT
+
+ CTriggerSpec specStore;
+ specStore.functionName = CStrW( condition.getAttributes().getNamedItem(at_function) );
+ specStore.displayName = CStrW( condition.getAttributes().getNamedItem(at_name) );
+ int row = -1, column = -1;
+
+ XERO_ITER_EL(condition, child)
+ {
+ int childID = child.getNodeName();
+
+ if ( childID == el_windowrow )
+ {
+ ++row;
+ column = -1;
+
+ XERO_ITER_EL(child, windowChild)
+ {
+ ++column;
+ TriggerParameter specParam(row, column);
+ specParam.name = windowChild.getAttributes().getNamedItem(at_name);
+ childID = windowChild.getNodeName();
+
+ if ( childID != el_parameter)
+ return false;
+
+ XERO_ITER_EL(windowChild, parameterChild)
+ {
+ childID = parameterChild.getNodeName();
+
+ if ( childID == el_window )
+ {
+ CStrW type( parameterChild.getAttributes().getNamedItem(at_type) );
+ CStrW pos( parameterChild.getAttributes().getNamedItem(at_position) );
+ CStrW size( parameterChild.getAttributes().getNamedItem(at_size) );
+ specParam.SetWindowData(type, pos, size);
+ }
+
+ else if ( childID == el_inputtype )
+ specParam.inputType = CStrW( parameterChild.getText() );
+ else if ( childID == el_parameterorder )
+ specParam.parameterOrder = CStrW( parameterChild.getText() ).ToInt();
+ else if ( childID == el_choices )
+ {
+ std::vector choices;
+ CStrW comma(L","), input(parameterChild.getText());
+ CStrW substr;
+ while ( (substr = input.BeforeFirst(comma)) != input )
+ {
+ choices.push_back(substr);
+ input = input.AfterFirst(comma);
+ }
+
+ choices.push_back(substr); //Last element has no comma
+ m_TriggerChoices[specStore.functionName + specParam.name] = choices;
+ }
+ else
+ return false;
+ }
+ specStore.AddParameter(specParam);
+ }
+ }
+ else
+ return false;
+ }
+
+ if ( isCondition )
+ m_ConditionSpecs.push_back(specStore);
+ else
+ m_EffectSpecs.push_back(specStore);
+
+ return true;
+}
diff --git a/source/simulation/TriggerManager.h b/source/simulation/TriggerManager.h
new file mode 100644
index 0000000000..5d5a55e135
--- /dev/null
+++ b/source/simulation/TriggerManager.h
@@ -0,0 +1,210 @@
+//========================================================
+//Andrew Decker aka pyrolink
+//ajdecker1022@msn.com
+//Description: Manages loading trigger specs (format in Atlas) and updating trigger objects
+//=======================================================
+
+#ifndef TRIGGERMANAGER_INCLUDED
+#define TRIGGERMANAGER_INCLUDED
+
+#include "ps/Singleton.h"
+#include "scripting/ScriptableObject.h"
+#include "simulation/ScriptObject.h"
+
+class CXeromyces;
+class XMBElement;
+
+//Trigger storage - used be Atlas to keep track of different triggers
+
+struct MapTriggerCondition
+{
+ MapTriggerCondition() : linkLogic(0), not(false) { }
+ CStrW name, functionName, displayName;
+ std::list parameters;
+ int linkLogic; //0 = NONE, 1 = AND, 2 = OR
+ bool not;
+};
+
+struct MapTriggerEffect
+{
+ CStrW name, functionName, displayName;
+ std::list parameters;
+};
+
+struct MapTriggerLogicBlock
+{
+ MapTriggerLogicBlock(size_t i, bool _not=false) : index(i), not(_not) { }
+ size_t index;
+ bool not;
+
+ bool operator< (const MapTriggerLogicBlock& block) const { return (index < block.index); }
+ bool operator== (const MapTriggerLogicBlock& block) const { return (index == block.index); }
+};
+
+struct MapTrigger
+{
+ MapTrigger() : active(false), maxRunCount(0), timeValue(0) { }
+ bool active;
+ int maxRunCount;
+ float timeValue;
+ CStrW name, groupName;
+
+ std::set logicBlocks; //Indices of where "(" 's go before
+ std::set logicBlockEnds; //Indices of where ")" 's come after
+ std::list conditions;
+ std::list effects;
+
+ void AddLogicBlock(bool not) { logicBlocks.insert( MapTriggerLogicBlock(conditions.size(), not) ); }
+ void AddLogicBlockEnd() { logicBlockEnds.insert( effects.size() ); }
+};
+
+struct MapTriggerGroup
+{
+ MapTriggerGroup() { }
+ MapTriggerGroup(CStrW _name, CStrW _parentName) : name(_name), parentName(_parentName) {}
+
+ std::list triggers;
+ std::list childGroups; //Indices of children
+ CStrW name, parentName;
+
+ bool operator== (const CStrW& _name) const { return (name == _name); }
+ bool operator== (const MapTriggerGroup& group) const { return (name == group.name); }
+};
+
+
+struct copyIfRootChild
+{
+ copyIfRootChild(std::list& groupList) : m_groupList(groupList) {}
+ void operator() ( const MapTriggerGroup& group )
+ {
+ if ( group.parentName == L"Triggers" )
+ m_groupList.push_back(group);
+ }
+private:
+ void operator= (const copyIfRootChild& UNUSED(group)) const {}
+ std::list& m_groupList;
+};
+
+//Triggers used by engine
+
+class CTrigger : public CJSObject
+{
+ int m_runCount;
+ CStrW m_conditionFuncString, m_effectFuncString, m_name, m_groupName;
+ CScriptObject m_effectFunction;
+ CScriptObject m_conditionFunction;
+
+public:
+ CTrigger();
+ CTrigger(const CStrW& name, bool active, float delay, int maxRuns, const CStrW& condFunc,
+ const CStrW& effectFunc);
+ CTrigger(const CStrW& name, bool active, float delay, int maxRuns,
+ CScriptObject& condFunc, CScriptObject& effectFunc);
+
+ CTrigger& operator= (const CTrigger& trigger);
+ ~CTrigger();
+
+ void SetFunctionBody(const CStrW& body);
+ const CStrW& GetConditionString() { return m_conditionFuncString; }
+ const CStrW& GetEffectString() { return m_effectFuncString; }
+ const CStrW& GetName() { return m_name; }
+ const CStrW& GetGroupName() { return m_groupName; }
+
+ bool ShouldFire();
+ //Returns false if trigger exceeds run count
+ bool Fire();
+
+ jsval Activate(JSContext* cx, uint argc, jsval* argv);
+ jsval Deactivate(JSContext* cx, uint argc, jsval* argv);
+
+ static JSBool Construct( JSContext* cx, JSObject* obj, uint argc, jsval* argv, jsval* rval );
+ static void ScriptingInit();
+
+ JSContext* m_cx;
+
+ bool m_active;
+ //Changeable by Atlas or needed by manager, no additional affects required
+ int m_maxRunCount;
+ float m_timeLeft, m_timeDelay;
+
+};
+
+
+//*****Holds information specifying how conditions and effects should look like in atlas******
+
+struct TriggerParameter
+{
+ TriggerParameter() {}
+ TriggerParameter(int _row, int _column) : row(_row), column(_column) {}
+ void SetWindowData(const CStrW& _windowType, CStrW& windowPosition, CStrW& windowSize);
+ //Sort parameters in the order they will be added to a sizer in atlas
+ bool operator< ( const TriggerParameter& rhs ) const;
+
+ CStrW name, windowType, inputType;
+ int row, column, xPos, yPos, xSize, ySize, parameterOrder;
+};
+
+class CTriggerSpec
+{
+public:
+ CTriggerSpec() {}
+ ~CTriggerSpec() {}
+
+ void AddParameter(const TriggerParameter& param) { parameters.insert(param); }
+ const std::set& GetParameters() const { return parameters; }
+
+ CStrW displayName, functionName;
+
+private:
+
+ //Sorted by parameter order to make things easy for Atlas
+ std::set parameters;
+};
+typedef CTriggerSpec CTriggerEffect;
+typedef CTriggerSpec CTriggerCondition;
+
+
+/******************************Trigger manager******************************/
+
+class CTriggerManager : public Singleton
+{
+public:
+ typedef std::map::iterator TriggerIter ;
+
+ CTriggerManager();
+ ~CTriggerManager();
+
+ //Returns false on detection of error
+ bool LoadXML( const CStr& filename );
+ void Update(float delta);
+
+ //Add simulation trigger (probably only called from JS)
+ void AddTrigger(CTrigger* trigger);
+ void AddTrigger(MapTriggerGroup& group, const MapTrigger& trigger);
+ void AddGroup(const MapTriggerGroup& group);
+ void SetAllGroups(const std::list& groups);
+ void DestroyEngineTriggers();
+
+ const std::list& GetAllConditions() const { return m_ConditionSpecs; }
+ const std::list& GetAllEffects() const { return m_EffectSpecs; }
+ const std::list& GetAllTriggerGroups() const { return m_GroupList; }
+ std::vector GetTriggerChoices(const std::wstring& name);
+
+ std::map m_TriggerMap; //Simulation triggers - used in engine
+
+private:
+ bool loadTriggerSpec( XMBElement condition, CXeromyces& XeroFile, bool isCondition );
+
+ //Contains choices for trigger choice box parameters, with key = spec.funcName+paramName
+ std::map > m_TriggerChoices;
+
+ //Holds information which descibes trigger layout in atlas
+ std::list m_GroupList;
+ std::list m_ConditionSpecs;
+ std::list m_EffectSpecs;
+
+};
+
+#define g_TriggerManager CTriggerManager::GetSingleton()
+
+#endif //ifndef TRIGGERMANAGER_INCLUDED
diff --git a/source/tools/atlas/AtlasUI/ArchiveViewer/ArchiveViewer.cpp b/source/tools/atlas/AtlasUI/ArchiveViewer/ArchiveViewer.cpp
index b0055baf23..78da2eea3b 100644
--- a/source/tools/atlas/AtlasUI/ArchiveViewer/ArchiveViewer.cpp
+++ b/source/tools/atlas/AtlasUI/ArchiveViewer/ArchiveViewer.cpp
@@ -306,7 +306,7 @@ void ArchiveViewer::UpdateFileList()
for (size_t i = 0; i < files.size(); ++i)
{
- m_CachedFileData[i].Name = utf16tow(files[i].filename);
+ m_CachedFileData[i].Name = wxString( utf16tow(files[i].filename).c_str() );
m_CachedFileData[i].NameLower = m_CachedFileData[i].Name.Lower();
m_CachedFileData[i].Size = wxString::Format(_T("%d"), files[i].filesize);
@@ -441,7 +441,7 @@ void ArchiveViewer::ExtractFiles(bool onlySelected)
for (size_t sel = 0; sel < selection.size(); ++sel)
{
const BAREntry& file = files[selection[sel]];
- wxString filename = utf16tow(file.filename);
+ wxString filename = wxString( utf16tow(file.filename).c_str() );
int lastSlash = filename.Find(_T('\\'), true);
if (lastSlash != -1)
dirs.insert(filename.Mid(0, lastSlash+1).c_str());
@@ -480,7 +480,7 @@ void ArchiveViewer::ExtractFiles(bool onlySelected)
// Append name-in-archive to target root directory, one dir
// at a time, calling mkdir at each step if necessary
- wxFileName filePath (utf16tow(file.filename), wxPATH_WIN);
+ wxFileName filePath (wxString( utf16tow(file.filename).c_str() ), wxPATH_WIN);
filePath.MakeAbsolute(rootDir.GetPath());
// Output to disk
@@ -551,7 +551,7 @@ void ArchiveViewer::UpdatePreview(long item)
const BAREntry& file = m_BARReader->GetFileList()[ m_FileListCtrl->GetItemData(item) ];
SeekableInputStream* str = m_BARReader->GetFile(file);
- m_PreviewWindow->PreviewFile(utf16tow(file.filename), *str);
+ m_PreviewWindow->PreviewFile(wxString(utf16tow(file.filename).c_str()), *str);
delete str;
}
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp
index eae5b6accc..dc25ea13ca 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/SectionLayout.cpp
@@ -12,6 +12,7 @@
#include "Sections/Object/Object.h"
#include "Sections/Environment/Environment.h"
#include "Sections/Cinematic/Cinematic.h"
+#include "Sections/Trigger/Trigger.h"
#include "General/Datafile.h"
@@ -270,7 +271,8 @@ void SectionLayout::Build()
ADD_SIDEBAR(TerrainSidebar, _T("terrain.png"), _("Terrain"));
ADD_SIDEBAR(ObjectSidebar, _T("object.png"), _("Object"));
ADD_SIDEBAR(EnvironmentSidebar, _T("environment.png"), _("Environment"));
- ADD_SIDEBAR(CinematicSidebar, _T("cinematic.png"), _("Cinematics"));
+ ADD_SIDEBAR(CinematicSidebar, _T("cinematic.png"), _("Cinema"));
+ ADD_SIDEBAR(TriggerSidebar, _T("trigger.png"), _("Trigger"));
#undef ADD_SIDEBAR
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp
index f61365cced..a805960239 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp
@@ -90,8 +90,7 @@ public:
qGetCameraInfo qry;
qry.Post();
sCameraInfo info = qry.info;
- m_Sidebar->AddTrack(info.rX, info.rY, info.rZ, msgString,
- GetItemCount()-1);
+ m_Sidebar->AddTrack(info.rX, info.rY, info.rZ, msgString, GetItemCount()-1);
}
void DeleteTrack()
{
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp
index 24e3229766..e8ddf58ca5 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp
@@ -55,7 +55,7 @@ public:
float rdotl = rx*lx + ry*ly + rz*lz;
int diffuse = (int)std::max(0.f, ndotl*128.f);
- int specular = (int)std::min(255., 64.f*pow(std::max(0.f, rdotl), 16.f));
+ int specular = (int)std::min(255.f, 64.f*pow(std::max(0.f, rdotl), 16.f));
imgData[0] = std::min(64+diffuse+specular, 255);
imgData[1] = std::min(48+diffuse+specular, 255);
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp
new file mode 100644
index 0000000000..6f1726d99e
--- /dev/null
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp
@@ -0,0 +1,1426 @@
+#include "stdafx.h"
+
+#include "Trigger.h"
+#include "GameInterface/Messages.h"
+#include "CustomControls/Buttons/ActionButton.h"
+#include "ScenarioEditor/Tools/Common/Tools.h"
+#include
+
+using namespace AtlasMessage;
+
+BEGIN_EVENT_TABLE(TriggerSidebar, Sidebar)
+EVT_TREE_BEGIN_DRAG(wxID_ANY, TriggerSidebar::onTreeDrag)
+EVT_TREE_END_LABEL_EDIT(wxID_ANY, TriggerSidebar::onTreeNameChange)
+EVT_TREE_SEL_CHANGED(wxID_ANY, TriggerSidebar::onTreeSelChange)
+EVT_LIST_ITEM_SELECTED(TriggerSidebar::ID_CondList, TriggerSidebar::onCondSelect)
+EVT_LIST_ITEM_SELECTED(TriggerSidebar::ID_EffectList, TriggerSidebar::onEffectSelect)
+EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TriggerSidebar::onPageChange)
+END_EVENT_TABLE()
+
+
+class TriggerTreeCtrl : public wxTreeCtrl
+{
+public:
+ TriggerTreeCtrl(TriggerSidebar* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize, long style = wxTR_HAS_BUTTONS )
+ : wxTreeCtrl(parent, id, pos, size, style), m_Sidebar(parent) { }
+
+ void onClick(wxMouseEvent& evt);
+
+private:
+ TriggerSidebar* m_Sidebar;
+ DECLARE_EVENT_TABLE();
+};
+
+BEGIN_EVENT_TABLE(TriggerTreeCtrl, wxTreeCtrl)
+EVT_LEFT_DOWN(TriggerTreeCtrl::onClick)
+END_EVENT_TABLE()
+
+
+struct LogicBlockHelper
+{
+ LogicBlockHelper() { index = -1; end = false; }
+ LogicBlockHelper(int _index, bool _end) : index(_index), end(_end) {}
+ int index;
+ bool end;
+
+ bool operator< ( const LogicBlockHelper& rhs ) const
+ {
+ return index < rhs.index;
+ }
+ bool operator== ( const LogicBlockHelper& rhs ) const
+ {
+ return index == rhs.index;
+ }
+};
+class TriggerSpecText : public wxTextCtrl
+{
+ typedef void (*callback)(void* data, std::wstring input, int parameter);
+
+public:
+ TriggerSpecText(wxWindow* parent, std::wstring label, const wxPoint& pos, const wxSize& size,
+ int parameter, std::wstring dataType, callback func, void* data)
+ : wxTextCtrl(parent, wxID_ANY, wxString( label.c_str() ), pos, size, wxTE_PROCESS_ENTER),
+ m_DataType(dataType), m_Parameter(parameter), m_Data(data), m_Callback(func)
+ {
+ }
+ void onTextEnter(wxCommandEvent& WXUNUSED(evt));
+
+ //Disallow invalid input
+ bool VerifyInput(std::wstring& input)
+ {
+ std::wstringstream stream(input);
+ if ( m_DataType == L"int" )
+ {
+ int test;
+ stream >> test;
+ return !stream.fail();
+ }
+ else if ( m_DataType == L"real" )
+ {
+ float test;
+ stream >> test;
+ return !stream.fail();
+ }
+ else if ( m_DataType == L"bool" )
+ {
+ bool test;
+ stream >> test;
+ return !stream.fail();
+ }
+ else if ( m_DataType == L"string" )
+ {
+ //Make strings appear as strings to javascript
+ std::wstring quote(L"\"");
+ input.insert(0, quote);
+ input.append(quote);
+ return true;
+ }
+ else
+ {
+ wxFAIL_MSG(L"Invalid input type for trigger specification");
+ return false;
+ }
+ }
+private:
+ void* m_Data;
+ int m_Parameter;
+ std::wstring m_DataType;
+ callback m_Callback;
+
+ DECLARE_EVENT_TABLE();
+
+};
+BEGIN_EVENT_TABLE(TriggerSpecText, wxTextCtrl)
+EVT_TEXT_ENTER(wxID_ANY, TriggerSpecText::onTextEnter)
+END_EVENT_TABLE()
+
+class TriggerSpecChoice : public wxChoice
+{
+ typedef void (*callback)(void* data, std::wstring input, int parameter);
+
+public:
+ TriggerSpecChoice(wxWindow* parent, std::wstring label, const wxPoint& pos,
+ const wxSize& size, const wxArrayString& strings, int parameter, callback func, void* data)
+ : wxChoice(parent, wxID_ANY, pos, size, strings), m_Callback(func), m_Data(data), m_Parameter(parameter)
+ {
+ }
+
+ void onChoice(wxCommandEvent& evt)
+ {
+ (*m_Callback)(m_Data, std::wstring( evt.GetString().wc_str() ), m_Parameter);
+ }
+
+private:
+ callback m_Callback;
+ int m_Parameter;
+ void* m_Data;
+
+ DECLARE_EVENT_TABLE();
+};
+
+BEGIN_EVENT_TABLE(TriggerSpecChoice, wxChoice)
+EVT_CHOICE(wxID_ANY, TriggerSpecChoice::onChoice)
+END_EVENT_TABLE()
+
+class TriggerListCtrl : public wxListCtrl
+{
+public:
+ TriggerListCtrl(wxWindow* parent, TriggerSidebar* sidebar, bool condition, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize, long style = wxLC_ICON)
+ : wxListCtrl(parent, id, pos, size, style), m_Sidebar(sidebar), m_Condition(condition)
+ {
+ }
+ void onClick(wxMouseEvent& evt);
+
+ TriggerSidebar* m_Sidebar;
+ bool m_Condition;
+private:
+ DECLARE_EVENT_TABLE();
+};
+BEGIN_EVENT_TABLE(TriggerListCtrl, wxListCtrl)
+EVT_LEFT_DOWN(TriggerListCtrl::onClick)
+END_EVENT_TABLE()
+
+
+class TriggerPage : public wxPanel
+{
+public:
+ TriggerPage(wxWindow* parent, TriggerSidebar* sidebar, long ID, wxString title, bool condition)
+ : wxPanel(parent), m_Sidebar(sidebar), m_Condition(condition)
+
+ {
+ wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
+
+ m_List = new TriggerListCtrl(this, sidebar, condition, ID, wxDefaultPosition,
+ wxSize(132, 210), wxLC_REPORT | wxLC_SINGLE_SEL);
+ m_List->InsertColumn(0, title, wxLIST_FORMAT_LEFT, 100);
+
+ sizer->Add(m_List);
+ SetSizer(sizer);
+ }
+
+ wxListCtrl* m_List;
+ TriggerSidebar* m_Sidebar;
+ bool m_Condition;
+};
+
+
+
+class TriggerItemData : public wxTreeItemData, public sTrigger
+{
+public:
+ TriggerItemData(TriggerSidebar* sidebar, const std::wstring& name, bool group)
+ : m_Sidebar(sidebar), sTrigger(name), m_Group(group), m_CondCount(0), m_EffectCount(0) {}
+ TriggerItemData(TriggerSidebar* sidebar, const sTrigger& trigger, bool group)
+ : m_Sidebar(sidebar), sTrigger(trigger), m_Group(group), m_CondCount(0), m_EffectCount(0) {}
+
+ TriggerSidebar* m_Sidebar;
+ size_t m_CondCount, m_EffectCount;
+ bool m_Group;
+ std::list m_BlockIndices, m_BlockEndIndices;
+
+ void AddBlock(const int block, const int index)
+ {
+ std::vector copy = *logicBlocks;
+ copy.push_back(block);
+ logicBlocks = copy;
+ m_BlockIndices.push_back(index);
+ }
+ void AddBlockEnd(const int block, const int index)
+ {
+ std::vector copy = *logicBlockEnds;
+ copy.push_back(block);
+ logicBlockEnds = copy;
+ m_BlockEndIndices.push_back(index);
+ }
+
+ void ResetBlockIndices()
+ {
+ std::vector newLogicBlocks, newLogicBlockEnds;
+ m_BlockIndices.clear();
+ m_BlockEndIndices.clear();
+ int conditionCount = 0;
+
+ for (int i=0; im_ConditionPage->m_List->GetItemCount(); ++i)
+ {
+ if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(i) == m_Sidebar->m_LogicBlockString )
+ {
+ newLogicBlocks.push_back(conditionCount);
+ m_BlockIndices.push_back(i);
+ }
+
+ //Block ends belong to current condition, hence conditionCount-1
+ else if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(i) == m_Sidebar->m_LogicBlockEndString )
+ {
+ if ( conditionCount == 0 )
+ newLogicBlockEnds.push_back(0);
+ else
+ newLogicBlockEnds.push_back(conditionCount-1);
+ m_BlockEndIndices.push_back(i);
+ }
+ else
+ ++conditionCount;
+ }
+ logicBlocks = newLogicBlocks;
+ logicBlockEnds = newLogicBlockEnds;
+ }
+};
+
+
+void onTriggerParameter(void* data, std::wstring paramString, int parameter);
+
+
+class TriggerBottomBar : public wxPanel
+{
+ enum { ID_TimeEdit, ID_CondNameEdit, ID_EffectNameEdit, ID_TriggerNameEdit, ID_RunsEdit,
+ ID_EffectChoice, ID_CondChoice,
+ ID_TimeRadio, ID_LogicRadio,
+ ID_NotCheck, ID_ActiveCheck };
+
+public:
+ enum { NO_VIEW, TRIGGER_VIEW, CONDITION_VIEW, EFFECT_VIEW };
+
+ TriggerBottomBar(TriggerSidebar* sidebar, wxWindow* parent)
+ : wxPanel(parent), m_Sidebar(sidebar)
+ {
+ m_Sizer = new wxBoxSizer(wxHORIZONTAL);
+ SetSizer(m_Sizer);
+ m_DependentStatus = NO_VIEW;
+ }
+
+ int GetDependentStatus()
+ {
+ return m_DependentStatus;
+ }
+ void SetSpecs(std::vector conditions, std::vector effects)
+ {
+ m_ConditionSpecs = conditions;
+ m_EffectSpecs = effects;
+ }
+
+ wxArrayString GetConditionNames()
+ {
+ wxArrayString ret;
+ for ( size_t i = 0; i < m_ConditionSpecs.size(); ++i )
+ ret.Add( wxString(m_ConditionSpecs[i].displayName.c_str()) );
+ return ret;
+ }
+ wxArrayString GetEffectNames()
+ {
+ wxArrayString ret;
+ for ( size_t i = 0; i < m_EffectSpecs.size(); ++i )
+ ret.Add( wxString(m_EffectSpecs[i].displayName.c_str()) );
+ return ret;
+ }
+
+ void onEffectChoice(wxCommandEvent& evt)
+ {
+ //Retrieve specification corresponding to selection
+ if ( m_Sidebar->m_SelectedEffect != -1 )
+ {
+ std::vector::iterator it = std::find( m_EffectSpecs.begin(),
+ m_EffectSpecs.end(), std::wstring(evt.GetString()) );
+ DisplayTriggerSpec(*it);
+ }
+ }
+
+ void onCondChoice(wxCommandEvent& evt)
+ {
+ if ( m_Sidebar->m_SelectedCond != -1 )
+ {
+ std::vector::iterator it = std::find( m_ConditionSpecs.begin(),
+ m_ConditionSpecs.end(), std::wstring(evt.GetString()) );
+ DisplayTriggerSpec(*it);
+ }
+ }
+
+ void onTimeEnter(wxCommandEvent& WXUNUSED(evt))
+ {
+ float fValue;
+ std::wstringstream stream( std::wstring(m_TimeEdit->GetValue()) );
+ stream >> fValue;
+
+ if ( stream.fail() )
+ {
+ wxBell();
+ return;
+ }
+
+ m_Sidebar->GetSelectedItemData()->timeValue = fValue;
+ wxString value = wxString::Format(L"%.2f", fValue);
+ m_TimeEdit->SetValue(value);
+ m_Sidebar->UpdateEngineData();
+ }
+
+ void onConditionEnter(wxCommandEvent& WXUNUSED(evt))
+ {
+ if ( m_Sidebar->m_SelectedCond == -1 )
+ return;
+
+ std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions;
+ int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond);
+
+ if ( condition == 0 )
+ conditions[0].name = std::wstring( m_ConditionEdit->GetValue() );
+ else
+ conditions[condition-1] = std::wstring( m_ConditionEdit->GetValue() );
+
+ m_Sidebar->GetSelectedItemData()->conditions = conditions;
+ m_Sidebar->UpdateLists();
+ m_Sidebar->UpdateEngineData();
+ }
+ void onEffectEnter(wxCommandEvent& WXUNUSED(evt))
+ {
+ if ( m_Sidebar->m_SelectedEffect== -1 )
+ return;
+
+ std::vector effects = *m_Sidebar->GetSelectedItemData()->effects;
+ effects[m_Sidebar->m_SelectedEffect].name = std::wstring( m_EffectEdit->GetValue() );
+ m_Sidebar->GetSelectedItemData()->effects = effects;
+ m_Sidebar->UpdateLists();
+ m_Sidebar->UpdateEngineData();
+ }
+ void onTriggerEnter(wxCommandEvent& WXUNUSED(evt))
+ {
+ TriggerItemData* data = m_Sidebar->GetSelectedItemData();
+ if ( data == NULL || m_Sidebar->m_TriggerTree->GetSelection() == m_Sidebar->m_TriggerTree->GetRootItem() )
+ return;
+
+ wxString name = m_TriggerEdit->GetValue();
+ data->name = std::wstring(name);
+ m_Sidebar->m_TriggerTree->SetItemText(m_Sidebar->m_TriggerTree->GetSelection(), name);
+ m_Sidebar->UpdateEngineData();
+ }
+
+ void onRunsEnter(wxCommandEvent& WXUNUSED(evt))
+ {
+ int iValue;
+ std::wstringstream stream( std::wstring(m_RunsEdit->GetValue()) );
+ stream >> iValue;
+
+ if ( stream.fail() )
+ {
+ wxBell();
+ return;
+ }
+
+ m_Sidebar->GetSelectedItemData()->maxRuns = iValue;
+ m_Sidebar->UpdateEngineData();
+ }
+ void onLogicRadio(wxCommandEvent& evt)
+ {
+ if ( m_Sidebar->m_SelectedCond == -1 )
+ return;
+ std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions;
+ int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond);
+ conditions[condition-1].linkLogic = evt.GetInt() + 1;
+
+ m_Sidebar->GetSelectedItemData()->conditions = conditions;
+ m_Sidebar->UpdateLists();
+ m_Sidebar->UpdateEngineData();
+ }
+ void onActiveCheck(wxCommandEvent& evt)
+ {
+ m_Sidebar->GetSelectedItemData()->active = (evt.GetInt() == 1);
+ m_Sidebar->UpdateEngineData();
+ }
+ void onNotCheck(wxCommandEvent& evt)
+ {
+ if ( m_Sidebar->m_SelectedCond == -1 )
+ return;
+ std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions;
+ int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond);
+ bool value = (evt.GetInt() == 1);
+ conditions[condition-1].not = value;
+
+ m_Sidebar->GetSelectedItemData()->conditions = conditions;
+ m_Sidebar->UpdateLists();
+ m_Sidebar->UpdateEngineData();
+ }
+
+ void DisplayTriggerSpec(const sTriggerSpec& spec)
+ {
+ if ( m_Sizer->Detach(m_ParameterSizer) )
+ {
+ delete m_ParameterSizer;
+ m_Sizer->Layout();
+ Layout();
+ }
+
+ //m_ParameterSizer = new wxStaticBoxSizer(wxVERTICAL, this, L"Parameters");
+ m_ParameterSizer = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer* hRow = NULL;
+ std::vector parameters = *spec.parameters;
+ std::vector stringParameters;
+ int row = -1;
+
+ //Set parameter data to new data if change is needed
+ if ( m_Sidebar->m_Notebook->GetCurrentPage() == m_Sidebar->m_ConditionPage )
+ {
+ std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions;
+ int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond) - 1 ;
+ if ( *conditions[condition].displayName != *spec.displayName )
+ {
+ std::vector newParameters(parameters.size());
+ conditions[condition].parameters = newParameters;
+ conditions[condition].displayName = *spec.displayName;
+ conditions[condition].functionName = *spec.functionName;
+ m_Sidebar->GetSelectedItemData()->conditions = conditions;
+ m_Sidebar->UpdateEngineData();
+ }
+ stringParameters = *(*m_Sidebar->GetSelectedItemData()->conditions)
+ [m_Sidebar->m_SelectedCond].parameters;
+ }
+ else
+ {
+ std::vector effects = *m_Sidebar->GetSelectedItemData()->effects;
+ if ( *effects[m_Sidebar->m_SelectedEffect].displayName != *spec.displayName )
+ {
+ std::vector newParameters(parameters.size());
+ effects[m_Sidebar->m_SelectedEffect].parameters = newParameters;
+ effects[m_Sidebar->m_SelectedEffect].displayName = *spec.displayName;
+ effects[m_Sidebar->m_SelectedEffect].functionName = *spec.functionName;
+ m_Sidebar->GetSelectedItemData()->effects = effects;
+ m_Sidebar->UpdateEngineData();
+ }
+ stringParameters = *(*m_Sidebar->GetSelectedItemData()->effects)
+ [m_Sidebar->m_SelectedEffect].parameters;
+ }
+
+ //Add all parameters to sizer
+ for ( std::vector::iterator it=parameters.begin(); it!=parameters.end(); ++it )
+ {
+ if ( it->row != row )
+ {
+ row = it->row;
+ hRow = new wxBoxSizer(wxHORIZONTAL);
+ m_ParameterSizer->Add(hRow);
+ }
+
+ if ( *it->windowType == std::wstring(L"text") )
+ {
+ hRow->Add( new wxStaticText(this, wxID_ANY, wxString( (*it->name).c_str() ),
+ wxPoint(it->xPos, it->yPos)) );
+ wxTextCtrl* text = new TriggerSpecText(this, L"", wxDefaultPosition, wxSize(it->xSize, it->ySize),
+ it->parameterOrder, *it->inputType, &onTriggerParameter, this);
+
+ hRow->Add( text, 0, wxLEFT, 5 );
+ wxString fill( stringParameters[it->parameterOrder].c_str() );
+
+ //Trim quotes
+ if ( *it->inputType == L"string" && fill.size() > 0 )
+ {
+ fill.erase(0, 1);
+ fill.erase(fill.size()-1, 1);
+ }
+ text->SetValue(fill);
+ }
+
+ else if ( *it->windowType == std::wstring(L"choice") )
+ {
+ qGetTriggerChoices qChoices(*spec.functionName + *it->name);
+ qChoices.Post();
+ std::vector choices = *qChoices.choices;
+ wxArrayString strings;
+
+ for ( size_t i = 0; i < choices.size(); ++i )
+ strings.Add( wxString(choices[i].c_str()) );
+
+ hRow->Add( new wxStaticText(this, wxID_ANY, wxString( (*it->name).c_str() ),
+ wxPoint(it->xPos, it->yPos)) );
+ wxChoice* choice = new TriggerSpecChoice( this, L"", wxDefaultPosition, wxSize(it->xSize, it->ySize),
+ strings, it->parameterOrder, &onTriggerParameter, this );
+
+ hRow->Add(choice);
+ choice->SetStringSelection( wxString(stringParameters[it->parameterOrder].c_str()) );
+ }
+ else
+ {
+ wxFAIL_MSG(L"Invalid window type for trigger specification");
+ //do something else...
+ }
+ }
+
+
+ //(If nothing was added, it won't be automatically delted)
+ if ( row < 0 )
+ {
+ delete hRow;
+ delete m_ParameterSizer;
+ }
+ else
+ m_Sizer->Add(m_ParameterSizer, 0, wxLEFT, 5);
+
+ m_Sizer->Layout();
+ Layout();
+ }
+
+ void FillConditionData()
+ {
+ if ( m_Sidebar->m_SelectedCond== -1 )
+ return;
+
+ TriggerItemData* itemData = m_Sidebar->GetSelectedItemData();
+ int iCondition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond);
+ sTriggerCondition condition = (*itemData->conditions)[iCondition-1];
+ wxString display( (*condition.displayName).c_str() );
+ m_ConditionEdit->SetValue( wxString(condition.name.c_str()) );
+
+ if ( display != L"" )
+ {
+ std::vector::iterator it = std::find( m_ConditionSpecs.begin(),
+ m_ConditionSpecs.end(), std::wstring(display) );
+ if ( it != m_ConditionSpecs.end() )
+ {
+ m_ConditionChoice->SetStringSelection(display);
+ DisplayTriggerSpec(*it);
+ }
+ }
+ else
+ m_ConditionChoice->SetStringSelection(display);
+
+ if ( condition.linkLogic == 0 || condition.linkLogic == 1 )
+ m_LogicRadio->SetSelection(0);
+ else
+ m_LogicRadio->SetSelection(1);
+
+ m_NotCheck->SetValue(condition.not);
+ }
+
+ void FillEffectData()
+ {
+ TriggerItemData* itemData = m_Sidebar->GetSelectedItemData();
+ sTriggerEffect effect = (*itemData->effects)[m_Sidebar->m_SelectedEffect];
+ wxString display( (*effect.displayName).c_str() );
+
+ m_EffectEdit->SetValue( wxString(effect.name.c_str()) );
+ if ( display != L"" )
+ {
+ std::vector::iterator it = std::find( m_EffectSpecs.begin(),
+ m_EffectSpecs.end(), std::wstring(display) );
+ if ( it != m_EffectSpecs.end() )
+ {
+ m_EffectChoice->SetStringSelection(display);
+ DisplayTriggerSpec(*it);
+ }
+ }
+ //m_TimeRadio->SetSelection(effect.loop);
+
+ float timeVal = itemData->timeValue;
+ wxString value = wxString::Format(L"%.2f", timeVal);
+ m_TimeEdit->SetValue(value);
+ }
+
+ void FillTriggerData()
+ {
+ if ( m_DependentStatus != TRIGGER_VIEW )
+ return;
+ TriggerItemData* itemData = m_Sidebar->GetSelectedItemData();
+ m_TriggerEdit->SetValue( wxString( (*itemData->name).c_str()) );
+ m_ActiveCheck->SetValue(itemData->active);
+ int runs = itemData->maxRuns;
+ m_RunsEdit->SetValue( wxString( wxString::Format(L"%d", runs)) );
+
+ }
+
+ void ToEffectView()
+ {
+ DestroyChildren();
+ m_Sizer = new wxBoxSizer(wxHORIZONTAL);
+ m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor"));
+ SetSizer(m_Sizer, true);
+
+ m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor"));
+ wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:"));
+ wxStaticText* effect = new wxStaticText(this, wxID_ANY, wxString(L"Effect:"));
+ m_EffectEdit = new wxTextCtrl(this, ID_EffectNameEdit, _T(""), wxDefaultPosition,
+ wxSize(100, 18), wxTE_PROCESS_ENTER);
+
+ wxArrayString effectNames = GetEffectNames();
+ wxString radioChoice[] = { wxString(L"Delay"), wxString(L"Loop") };
+ m_EffectChoice = new wxChoice(this, ID_EffectChoice, wxDefaultPosition, wxSize(100, 13), effectNames);
+
+ m_TimeRadio = new wxRadioBox(this, ID_TimeRadio, _T("Execution type"),
+ wxDefaultPosition, wxDefaultSize, 2, radioChoice, 2, wxRA_SPECIFY_COLS);
+
+ wxStaticText* time = new wxStaticText(this, wxID_ANY, wxString(L"Time:"));
+ m_TimeEdit = new wxTextCtrl(this, ID_TimeEdit, _T(""), wxDefaultPosition,
+ wxSize(100, 18), wxTE_PROCESS_ENTER);
+
+ wxBoxSizer* hNameHolder = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* hEffectHolder = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* hTimeHolder = new wxBoxSizer(wxHORIZONTAL);
+
+ hNameHolder->Add(name);
+ hNameHolder->Add(m_EffectEdit, 0, wxLEFT, 5);
+ hEffectHolder->Add(effect);
+ hEffectHolder->Add(m_EffectChoice, 0, wxLEFT, 5);
+ hTimeHolder->Add(time);
+ hTimeHolder->Add(m_TimeEdit, 0, wxLEFT, 5);
+
+ m_DependentSizer->Add(hNameHolder, 0, wxTOP, 5);
+ m_DependentSizer->Add(hEffectHolder, 0, wxTOP, 5);
+ m_DependentSizer->Add(m_TimeRadio, 0, wxTOP | wxALIGN_CENTER, 10);
+ m_DependentSizer->Add(hTimeHolder, 0, wxTOP | wxALIGN_CENTER, 5);
+
+ m_Sizer->Add(m_DependentSizer);
+ m_Sizer->Layout();
+ Layout();
+ m_DependentStatus = EFFECT_VIEW;
+ }
+
+ void ToConditionView()
+ {
+ DestroyChildren();
+ m_Sizer = new wxBoxSizer(wxHORIZONTAL);
+ m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor"));
+ SetSizer(m_Sizer, true);
+
+ wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:"));
+ wxStaticText* condition = new wxStaticText(this, wxID_ANY, wxString(L"Condition:"));
+ m_ConditionEdit = new wxTextCtrl(this, ID_CondNameEdit, _T(""), wxDefaultPosition,
+ wxSize(100, 18), wxTE_PROCESS_ENTER);
+
+ wxArrayString conditionNames = GetConditionNames();
+ wxString radioChoice[] = { wxString(L"And"), wxString(L"Or") };
+ m_ConditionChoice = new wxChoice(this, ID_CondChoice, wxDefaultPosition,
+ wxSize(100, 13), conditionNames);
+
+ m_LogicRadio = new wxRadioBox(this, ID_LogicRadio, _T("Link logic:"),
+ wxDefaultPosition, wxDefaultSize, 2, radioChoice, 2, wxRA_SPECIFY_COLS);
+
+ m_NotCheck = new wxCheckBox(this, ID_NotCheck, wxString(L"Not: "));
+
+ wxBoxSizer* hNameHolder = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* hConditionHolder = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* hLogicHolder = new wxBoxSizer(wxHORIZONTAL);
+
+ hNameHolder->Add(name);
+ hNameHolder->Add(m_ConditionEdit, 0, wxLEFT | wxALIGN_CENTER, 5);
+ hConditionHolder->Add(condition);
+ hConditionHolder->Add(m_ConditionChoice, 0, wxLEFT | wxALIGN_CENTER, 5);
+ hLogicHolder->Add(m_LogicRadio, 0, 0, 5);
+ hLogicHolder->Add(m_NotCheck, 0, wxLEFT | wxALIGN_CENTER, 5);
+
+ m_DependentSizer->Add(hNameHolder, 0, wxTOP, 5);
+ m_DependentSizer->Add(hConditionHolder, 0, wxTOP, 5);
+ m_DependentSizer->Add(hLogicHolder, 0, wxALIGN_CENTER | wxTOP, 10);
+
+ m_Sizer->Add(m_DependentSizer);
+ m_Sizer->Layout();
+ Layout();
+ m_DependentStatus = CONDITION_VIEW;
+ }
+
+ void ToTriggerView()
+ {
+ DestroyChildren();
+ m_Sizer = new wxBoxSizer(wxHORIZONTAL);
+ m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor"));
+ SetSizer(m_Sizer, true);
+
+ wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:"));
+ m_TriggerEdit = new wxTextCtrl(this, ID_TriggerNameEdit, _T(""), wxDefaultPosition,
+ wxSize(100, 18), wxTE_PROCESS_ENTER);
+
+ wxStaticText* runs = new wxStaticText(this, wxID_ANY, wxString(L"Maximum runs:"));
+ m_RunsEdit = new wxTextCtrl(this, ID_RunsEdit, wxString(L"-1"), wxDefaultPosition, wxSize(100, 18));
+ m_ActiveCheck = new wxCheckBox(this, ID_ActiveCheck, wxString(L"Active: "));
+
+ wxBoxSizer* nameHolder = new wxBoxSizer(wxHORIZONTAL), *runsHolder = new wxBoxSizer(wxHORIZONTAL);
+
+ nameHolder->Add(name);
+ nameHolder->Add(m_TriggerEdit, 0, wxLEFT, 5);
+ runsHolder->Add(runs);
+ runsHolder->Add(m_RunsEdit, 0, wxLEFT, 5);
+
+ m_DependentSizer->Add(nameHolder);
+ m_DependentSizer->Add(runsHolder, 0, wxTOP, 5);
+ m_DependentSizer->Add(m_ActiveCheck, 0, wxTOP, 5);
+
+ m_Sizer->Add(m_DependentSizer);
+ m_Sizer->Layout();
+ Layout();
+ m_DependentStatus = TRIGGER_VIEW;
+ }
+ void ToNoView()
+ {
+ if ( m_DependentStatus == NO_VIEW )
+ return;
+ DestroyChildren();
+ m_DependentStatus = NO_VIEW;
+ }
+ TriggerSidebar* m_Sidebar;
+
+private:
+
+ wxBoxSizer* m_Sizer, *m_ParameterSizer;
+ wxStaticBoxSizer* m_DependentSizer; //dependent = effect/condition
+
+ wxTextCtrl* m_TimeEdit, *m_ConditionEdit, *m_EffectEdit, *m_TriggerEdit, *m_RunsEdit;
+ wxCheckBox* m_ActiveCheck, *m_NotCheck;
+ wxChoice* m_ConditionChoice, *m_EffectChoice;
+ wxRadioBox* m_LogicRadio, *m_TimeRadio;
+
+ std::vector m_ConditionSpecs, m_EffectSpecs;
+ int m_DependentStatus;
+
+ DECLARE_EVENT_TABLE();
+};
+
+
+BEGIN_EVENT_TABLE(TriggerBottomBar, wxPanel)
+EVT_TEXT_ENTER(TriggerBottomBar::ID_TimeEdit, TriggerBottomBar::onTimeEnter)
+EVT_TEXT_ENTER(TriggerBottomBar::ID_CondNameEdit, TriggerBottomBar::onConditionEnter)
+EVT_TEXT_ENTER(TriggerBottomBar::ID_EffectNameEdit, TriggerBottomBar::onEffectEnter)
+EVT_TEXT_ENTER(TriggerBottomBar::ID_TriggerNameEdit, TriggerBottomBar::onTriggerEnter)
+EVT_TEXT_ENTER(TriggerBottomBar::ID_RunsEdit, TriggerBottomBar::onRunsEnter)
+EVT_CHOICE(TriggerBottomBar::ID_EffectChoice, TriggerBottomBar::onEffectChoice)
+EVT_CHOICE(TriggerBottomBar::ID_CondChoice, TriggerBottomBar::onCondChoice)
+
+EVT_RADIOBOX(TriggerBottomBar::ID_LogicRadio, TriggerBottomBar::onLogicRadio)
+EVT_CHECKBOX(TriggerBottomBar::ID_ActiveCheck, TriggerBottomBar::onActiveCheck)
+EVT_CHECKBOX(TriggerBottomBar::ID_NotCheck, TriggerBottomBar::onNotCheck)
+//EVT_RADIOBOX(TriggerBotomBar::ID_TimeRadio, TriggerBottomBar::onTimeRadio)
+END_EVENT_TABLE()
+
+
+void TriggerTreeCtrl::onClick(wxMouseEvent& evt)
+{
+ if ( m_Sidebar->m_TriggerTree->GetSelection() == m_Sidebar->m_TriggerTree->GetRootItem() ||
+ !m_Sidebar->m_TriggerTree->GetSelection() )
+ {
+ m_Sidebar->m_TriggerBottom->ToNoView();
+ }
+ else
+ {
+ m_Sidebar->m_TriggerBottom->ToTriggerView();
+ m_Sidebar->m_TriggerBottom->FillTriggerData();
+ }
+ evt.Skip();
+}
+
+void TriggerListCtrl::onClick(wxMouseEvent& evt)
+{
+ if ( m_Condition )
+ {
+ //if ( m_Sidebar->m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::CONDITION_VIEW )
+ m_Sidebar->m_TriggerBottom->ToConditionView();
+ if ( m_Sidebar->m_SelectedCond != -1 )
+ m_Sidebar->m_TriggerBottom->FillConditionData();
+ }
+ else
+ {
+ //if ( m_Sidebar->m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::EFFECT_VIEW )
+ m_Sidebar->m_TriggerBottom->ToEffectView();
+ if ( m_Sidebar->m_SelectedEffect != -1 )
+ m_Sidebar->m_TriggerBottom->FillEffectData();
+ }
+ evt.Skip();
+}
+
+void TriggerSpecText::onTextEnter(wxCommandEvent& WXUNUSED(evt))
+{
+ std::wstring text( GetValue().wc_str() );
+
+ if ( VerifyInput(text) )
+ (*m_Callback)(m_Data, text, m_Parameter );
+ else
+ wxBell();
+}
+
+
+void onTriggerParameter(void* data, std::wstring paramString, int parameter)
+{
+ TriggerBottomBar* bottomBar = static_cast(data);
+
+ if ( bottomBar->m_Sidebar->m_Notebook->GetSelection() == 0 )
+ {
+ if ( bottomBar->m_Sidebar->m_SelectedCond == -1 )
+ return;
+ std::vector conditions = *bottomBar->m_Sidebar->GetSelectedItemData()->conditions;
+ std::vector parameters = *conditions[bottomBar->m_Sidebar->m_SelectedCond].parameters;
+
+ parameters[parameter] = paramString;
+ conditions[bottomBar->m_Sidebar->m_SelectedCond].parameters = parameters;
+ bottomBar->m_Sidebar->GetSelectedItemData()->conditions = conditions;
+ }
+ else
+ {
+ if ( bottomBar->m_Sidebar->m_SelectedEffect == -1 )
+ return;
+ std::vector effects = *bottomBar->m_Sidebar->GetSelectedItemData()->effects;
+ std::vector parameters = *effects[bottomBar->m_Sidebar->m_SelectedEffect].parameters;
+
+ parameters[parameter] = paramString;
+ effects[bottomBar->m_Sidebar->m_SelectedEffect].parameters = parameters;
+ bottomBar->m_Sidebar->GetSelectedItemData()->effects = effects;
+ }
+ bottomBar->m_Sidebar->UpdateEngineData();
+}
+
+void onGroupPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ if ( !sidebar->m_TriggerTree->GetSelection())
+ return;
+ if ( !sidebar->IsGroupSelected() )
+ return;
+
+ wxString name = wxString::Format(L"Group %d", sidebar->m_GroupCount);
+ wxTreeItemId ID = sidebar->m_TriggerTree->AppendItem( sidebar->m_TriggerTree->GetSelection(),
+ name, -1, -1, new TriggerItemData(sidebar, std::wstring(name), true) );
+ sidebar->m_TriggerTree->EnsureVisible(ID);
+ ++sidebar->m_GroupCount;
+
+ sidebar->UpdateEngineData();
+}
+
+void onTriggerPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ wxTreeItemId ID = sidebar->m_TriggerTree->GetSelection();
+
+ if ( !sidebar->IsGroupSelected() )
+ ID = sidebar->m_TriggerTree->GetItemParent(ID);
+
+ wxString name = wxString::Format(L"Trigger %d", sidebar->m_TriggerCount);
+ TriggerItemData* itemData = new TriggerItemData(sidebar, std::wstring(name), false);
+ itemData->group = std::wstring( sidebar->m_TriggerTree->GetItemText(ID) );
+
+ ID = sidebar->m_TriggerTree->AppendItem(ID, name, -1, -1, itemData);
+ sidebar->m_TriggerTree->Expand( sidebar->m_TriggerTree->GetRootItem() );
+
+ ++sidebar->m_TriggerCount;
+ sidebar->m_TriggerTree->SelectItem(ID);
+ sidebar->UpdateEngineData();
+}
+
+void onDeleteTreePush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ if ( sidebar->m_TriggerTree->GetSelection() == sidebar->m_TriggerTree->GetRootItem() )
+ return;
+
+ if ( wxMessageBox( wxString(L"Are you sure you want to delete this item?"),
+ wxString(L"Caution"), wxYES_NO ) == wxYES )
+ {
+ sidebar->m_TriggerTree->Delete(sidebar->m_TriggerTree->GetSelection());
+ sidebar->m_TriggerTree->EnsureVisible( sidebar->m_TriggerTree->GetRootItem() );
+ sidebar->m_TriggerBottom->FillTriggerData();
+ }
+
+ sidebar->UpdateEngineData();
+}
+
+void onConditionPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ if ( sidebar->IsGroupSelected() )
+ return;
+
+ sidebar->m_Notebook->SetSelection(0);
+ TriggerItemData* itemData = sidebar->GetSelectedItemData();
+ std::wstring name = std::wstring( wxString::Format(L"Condition %d", itemData->m_CondCount).wc_str() );
+
+ if ( itemData->m_CondCount == 0 )
+ sidebar->m_SelectedCond = 0;
+
+ ++itemData->m_CondCount;
+
+ std::vector conditions = *itemData->conditions;
+ conditions.push_back( sTriggerCondition(name) );
+ itemData->conditions = conditions;
+
+ long count = sidebar->m_ConditionPage->m_List->GetItemCount();
+
+ sidebar->m_ConditionPage->m_List->InsertItem(count, wxString(name.c_str()) );
+ sidebar->m_ConditionPage->m_List->EnsureVisible(count);
+ sidebar->m_ConditionPage->m_List->SetItemState(count, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
+
+ sidebar->m_TriggerBottom->ToConditionView(); //Some data is not valid, so reset
+ sidebar->m_TriggerBottom->FillConditionData();
+
+ sidebar->UpdateEngineData();
+}
+
+void onEffectPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ if ( sidebar->IsGroupSelected() )
+ return;
+
+ sidebar->m_Notebook->SetSelection(1);
+ TriggerItemData* itemData = sidebar->GetSelectedItemData();
+ std::wstring name = std::wstring( wxString::Format(L"Effect %d", itemData->m_EffectCount).wc_str() );
+
+ if ( itemData->m_EffectCount == 0 )
+ sidebar->m_SelectedEffect = 0;
+ ++itemData->m_EffectCount;
+
+ std::vector effects = *itemData->effects;
+ effects.push_back( sTriggerEffect(name) );
+ itemData->effects = effects;
+
+ long count = sidebar->m_EffectPage->m_List->GetItemCount();
+ sidebar->m_EffectPage->m_List->InsertItem(count, wxString(name.c_str()) );
+ sidebar->m_EffectPage->m_List->EnsureVisible(count);
+ sidebar->m_EffectPage->m_List->SetItemState(count, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
+
+ sidebar->m_TriggerBottom->ToEffectView();
+ sidebar->m_TriggerBottom->FillEffectData();
+
+ sidebar->UpdateEngineData();
+}
+
+void onDeleteBookPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ wxListCtrl* list = static_cast(sidebar->m_Notebook->GetCurrentPage())->m_List;
+ if ( !list )
+ return;
+
+ TriggerItemData* itemData = sidebar->GetSelectedItemData();
+ //Is condition? -- valid selection?
+ if ( list == sidebar->m_ConditionPage->m_List && sidebar->m_SelectedCond != -1 )
+ {
+ std::wstring text(sidebar->m_ConditionPage->m_List->GetItemText(sidebar->m_SelectedCond) );
+ int conditionCount = sidebar->GetConditionCount(sidebar->m_SelectedCond);
+
+ if ( text == std::wstring(sidebar->m_LogicBlockString.wc_str()) )
+ {
+ std::vector blocks = *itemData->logicBlocks;
+ if ( conditionCount == 0 )
+ {
+ blocks.erase( std::find(blocks.begin(), blocks.end(), 0) );
+ itemData->m_BlockIndices.erase( std::find( itemData->m_BlockIndices.begin(),
+ itemData->m_BlockIndices.end(), sidebar->m_SelectedCond ) );
+ }
+ else
+ {
+ blocks.erase( std::find(blocks.begin(), blocks.end(), conditionCount) );
+ itemData->m_BlockIndices.erase( std::find( itemData->m_BlockIndices.begin(),
+ itemData->m_BlockIndices.end(), sidebar->m_SelectedCond ) );
+ }
+ itemData->logicBlocks = blocks;
+ }
+
+ else if ( text == std::wstring(sidebar->m_LogicBlockEndString.wc_str()) )
+ {
+ std::vector blockEnds = *itemData->logicBlockEnds;
+ if ( conditionCount == 0 )
+ {
+ blockEnds.erase( std::find(blockEnds.begin(), blockEnds.end(), 0) );
+ itemData->m_BlockEndIndices.erase( std::find( itemData->m_BlockEndIndices.begin(),
+ itemData->m_BlockEndIndices.end(), sidebar->m_SelectedCond ) );
+ }
+ else
+ {
+ blockEnds.erase( std::find(blockEnds.begin(), blockEnds.end(), conditionCount-1) );
+ itemData->m_BlockEndIndices.erase( std::find( itemData->m_BlockEndIndices.begin(),
+ itemData->m_BlockEndIndices.end(), sidebar->m_SelectedCond ) );
+ }
+ itemData->logicBlockEnds = blockEnds;
+ }
+
+ else
+ {
+ std::vector conditions = *itemData->conditions;
+ conditions.erase( std::find(conditions.begin(), conditions.end(), text) );
+ itemData->conditions = conditions;
+ }
+
+ list->DeleteItem( sidebar->m_SelectedCond );
+ itemData->ResetBlockIndices();
+
+ if ( sidebar->m_SelectedCond == list->GetItemCount() )
+ sidebar->m_SelectedCond = -1;
+ else
+ sidebar->m_TriggerBottom->FillConditionData();
+ }
+
+ else if ( list == sidebar->m_EffectPage->m_List && sidebar->m_SelectedEffect != -1)
+ {
+ std::vector effects = *itemData->effects;
+ effects.erase( std::find( effects.begin(), effects.end(), std::wstring(
+ list->GetItemText(sidebar->m_SelectedEffect)) ) );
+ itemData->effects = effects;
+
+ list->DeleteItem( sidebar->m_SelectedEffect );
+
+ if ( itemData->effects.GetSize() == 0 || sidebar->m_SelectedEffect == list->GetItemCount() )
+ sidebar->m_SelectedEffect = -1;
+ else
+ sidebar->m_TriggerBottom->FillEffectData();
+ }
+ sidebar->UpdateLists();
+ sidebar->UpdateEngineData();
+}
+
+void onLogicBlockPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ sidebar->m_Notebook->SetSelection(0);
+
+ if ( sidebar->IsGroupSelected() )
+ return;
+
+ int limit = sidebar->m_SelectedCond;
+ if ( sidebar->m_SelectedCond == -1 )
+ limit = sidebar->m_ConditionPage->m_List->GetItemCount()-1;
+
+ int conditionCount = sidebar->GetConditionCount(limit);
+ if ( conditionCount == 0 )
+ {
+ sidebar->GetSelectedItemData()->AddBlock(0, 0);
+ sidebar->UpdateLists();
+ return;
+ }
+
+ sidebar->GetSelectedItemData()->AddBlock(conditionCount, limit);
+ sidebar->UpdateLists();
+ sidebar->UpdateEngineData();
+}
+
+void onBlockEndPush(void* data)
+{
+ TriggerSidebar* sidebar = static_cast(data);
+ sidebar->m_Notebook->SetSelection(0);
+
+ if ( sidebar->IsGroupSelected() )
+ return;
+
+ int limit = sidebar->m_SelectedCond;
+ if ( sidebar->m_SelectedCond == -1 )
+ limit = sidebar->m_ConditionPage->m_List->GetItemCount()-1;
+
+ int conditionCount = sidebar->GetConditionCount(limit);
+ if ( conditionCount == 0 )
+ {
+ sidebar->GetSelectedItemData()->AddBlockEnd(0, 0);
+ sidebar->UpdateLists();
+ return;
+ }
+
+ sidebar->GetSelectedItemData()->AddBlockEnd(conditionCount-1, limit);
+ sidebar->UpdateLists();
+}
+
+
+
+TriggerSidebar::TriggerSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
+: Sidebar(sidebarContainer, bottomBarContainer), m_GroupCount(0), m_TriggerCount(0),
+ m_SelectedCond(-1), m_SelectedEffect(-1)
+{
+ m_TriggerBottom = new TriggerBottomBar(this, bottomBarContainer);
+ m_BottomBar = m_TriggerBottom;
+
+ m_TriggerTree = new TriggerTreeCtrl(this, wxID_ANY, wxDefaultPosition,
+ wxSize(140, 220), wxTR_HAS_BUTTONS | wxTR_EDIT_LABELS);
+ m_TriggerTree->AddRoot(L"Triggers", -1, -1, new TriggerItemData(this, L"Triggers", true));
+ m_TriggerTree->SelectItem( m_TriggerTree->GetRootItem() );
+ m_TriggerTree->Expand( m_TriggerTree->GetRootItem() );
+
+
+ wxBoxSizer* hHolder = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* vHolder = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer* vButtons = new wxBoxSizer(wxVERTICAL);
+
+ ActionButton* trigButton = new ActionButton( this, L"Trigger", &onTriggerPush,
+ this, wxSize(50, 20) );
+ ActionButton* groupButton = new ActionButton( this, L"Group", &onGroupPush,
+ this, wxSize(50, 20) );
+ ActionButton* deleteButton = new ActionButton( this, L"Delete", &onDeleteTreePush,
+ this, wxSize(50, 20) );
+
+ ActionButton* conditionButton = new ActionButton( this, L"Condition",
+ &onConditionPush, this, wxSize(54, 20) );
+ ActionButton* effectButton = new ActionButton( this, L"Effect",
+ &onEffectPush, this, wxSize(50, 20) );
+ ActionButton* bookDelete = new ActionButton( this, L"Delete",
+ &onDeleteBookPush, this, wxSize(50, 20) );
+ ActionButton* logicBlock = new ActionButton( this, L"Block",
+ &onLogicBlockPush, this, wxSize(50, 20) );
+ ActionButton* logicBlockEnd = new ActionButton( this, L"Block End",
+ &onBlockEndPush, this, wxSize(50, 20) );
+
+
+ m_LogicBlockString = wxString(L"--------------------");
+ m_LogicBlockEndString = wxString(L"===========");
+ wxStaticText* bottomTitle = new wxStaticText( this, wxID_ANY, _T("Conditions and Effects") );
+ m_Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition,
+ wxSize(132, 210), wxNB_TOP);
+
+ m_ConditionPage = new TriggerPage(m_Notebook, this, ID_CondList, wxString(L"Conditions"), true);
+ m_EffectPage = new TriggerPage(m_Notebook, this, ID_EffectList, wxString(L"Effects"), false);
+
+ m_Notebook->AddPage( m_ConditionPage, _T("Conditions") );
+ m_Notebook->AddPage( m_EffectPage, _T("Effects") );
+ m_Notebook->SetPageSize(wxSize(130, 240));
+
+ vButtons->Add(trigButton);
+ vButtons->Add(groupButton);
+ vButtons->Add(deleteButton);
+ vButtons->Add(conditionButton, 0, wxTOP, 190);
+ vButtons->Add(effectButton);
+ vButtons->Add(bookDelete);
+ vButtons->Add(logicBlock);
+ vButtons->Add(logicBlockEnd);
+
+ vHolder->Add(m_TriggerTree, 0, wxTOP, 15);
+ vHolder->Add(bottomTitle, 0, wxALIGN_CENTER | wxTOP, 5);
+ vHolder->Add(m_Notebook, 0, wxTOP, 5 );
+
+ hHolder->Add(vHolder);
+ hHolder->Add(vButtons, 0, wxALIGN_CENTER);
+ m_MainSizer->Add(hHolder);
+}
+
+int TriggerSidebar::GetConditionCount(int limit)
+{
+ int conditionCount = 0;
+ wxListCtrl* list = m_ConditionPage->m_List;
+ for ( int i = 0; i <= limit; ++i )
+ {
+ if ( list->GetItemText(i) != m_LogicBlockString && list->GetItemText(i) != m_LogicBlockEndString)
+ {
+ ++conditionCount;
+ }
+ }
+ return conditionCount;
+}
+void TriggerSidebar::OnFirstDisplay()
+{
+ qGetTriggerData dataQuery;
+ dataQuery.Post();
+ m_TriggerBottom->SetSpecs(*dataQuery.conditions, *dataQuery.effects);
+
+ //Add all loaded triggers to the tree
+ const std::vector triggerGroups = *dataQuery.groups;
+ std::vector::const_iterator it = std::find( triggerGroups.begin(),
+ triggerGroups.end(), std::wstring(L"Triggers") );
+
+ if ( it != triggerGroups.end() )
+ {
+ wxTreeItemId invalid;
+ AddGroupTree(*it, invalid);
+ m_TriggerTree->Expand( m_TriggerTree->GetRootItem() );
+ }
+}
+
+void TriggerSidebar::AddGroupTree(const sTriggerGroup& group, wxTreeItemId parent)
+{
+ wxTreeItemId newID;
+ wxString text( (*group.name).c_str() );
+
+ //Make sure root item doesn't already exist
+ if ( !parent && !m_TriggerTree->GetRootItem() )
+ newID = m_TriggerTree->AddRoot(text, -1, -1, new TriggerItemData(this, *group.name, true));
+ else if ( parent )
+ newID = m_TriggerTree->AppendItem(parent, text);
+ else
+ newID = m_TriggerTree->GetRootItem();
+
+ const std::vector triggerBuf = *group.triggers;
+ const std::vector groupBuf = *group.children;
+
+ for ( size_t i = 0; i < group.children.GetSize(); ++i )
+ AddGroupTree( *std::find(m_TriggerGroups.begin(), m_TriggerGroups.end(), groupBuf[i]), newID );
+ for ( size_t i = 0; i < group.triggers.GetSize(); ++i )
+ {
+ std::wstring trigName = *triggerBuf[i].name;
+
+ //Make triggers start where user last left off
+ if ( trigName.find(L"Trigger ") == 0 )
+ {
+ trigName.erase(0, 8); //remove "Trigger "
+ std::wstringstream toInt(trigName);
+ size_t convert;
+ toInt >> convert;
+ ++convert;
+
+ if ( !toInt.fail() )
+ {
+ if ( convert > m_TriggerCount )
+ m_TriggerCount = convert;
+ }
+ }
+
+ m_TriggerTree->AppendItem( newID, wxString( triggerBuf[i].name.c_str() ), -1, -1,
+ new TriggerItemData(this, triggerBuf[i], false) );
+ }
+}
+
+
+void TriggerSidebar::onPageChange(wxNotebookEvent& evt)
+{
+ if ( evt.GetSelection() == 0 )
+ {
+ m_TriggerBottom->ToConditionView();
+ if ( m_SelectedCond != -1 )
+ m_TriggerBottom->FillConditionData();
+ return;
+ }
+ m_TriggerBottom->ToEffectView();
+ if ( m_SelectedEffect != -1 )
+ m_TriggerBottom->FillEffectData();
+}
+
+void TriggerSidebar::onTreeDrag(wxTreeEvent& evt)
+{
+ //evt.Allow();
+}
+
+void TriggerSidebar::onTreeNameChange(wxTreeEvent& evt)
+{
+ ToDerived( m_TriggerTree->GetItemData(evt.GetItem()) )->name = std::wstring(
+ evt.GetLabel().wc_str());
+ UpdateEngineData();
+}
+
+void TriggerSidebar::onTreeSelChange(wxTreeEvent& evt)
+{
+ //Prevent other triggers from trying to use previous data
+ m_SelectedCond = -1;
+ m_SelectedEffect = -1;
+
+ if ( evt.GetItem() == m_TriggerTree->GetRootItem() )
+ {
+ m_TriggerBottom->ToNoView();
+ return;
+ }
+
+ if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::TRIGGER_VIEW )
+ m_TriggerBottom->ToTriggerView();
+ m_TriggerBottom->FillTriggerData();
+
+ UpdateLists();
+}
+void TriggerSidebar::UpdateLists()
+{
+ TriggerItemData* data = GetSelectedItemData();
+ m_ConditionPage->m_List->Freeze();
+ m_ConditionPage->m_List->DeleteAllItems();
+ m_EffectPage->m_List->Freeze();
+ m_EffectPage->m_List->DeleteAllItems();
+
+ const Shareable* conditions = data->conditions.GetBuffer();
+ for ( size_t i = 0; i < data->conditions.GetSize(); ++i )
+ {
+ m_ConditionPage->m_List->InsertItem( m_ConditionPage->m_List->
+ GetItemCount(), wxString(conditions[i]->name.c_str()) );
+ }
+
+ const Shareable* effects = data->effects.GetBuffer();
+ for ( size_t i = 0; i < data->effects.GetSize(); ++i )
+ {
+ m_EffectPage->m_List->InsertItem(m_EffectPage->m_List->GetItemCount(),
+ wxString(effects[i]->name.c_str()) );
+ }
+
+ //These must be merged and sorted because adding them out-of-order screws up the list
+ std::list sortedBlocks;
+ std::list blocks = data->m_BlockIndices, blockEnds = data->m_BlockEndIndices;
+
+ for ( std::list::iterator it = blocks.begin(); it != blocks.end(); ++it )
+ sortedBlocks.push_back( LogicBlockHelper(*it, false) );
+ for ( std::list::iterator it = blockEnds.begin(); it != blockEnds.end(); ++it )
+ sortedBlocks.push_back( LogicBlockHelper(*it, true) );
+
+ sortedBlocks.sort();
+ for ( std::list::iterator it = sortedBlocks.begin(); it != sortedBlocks.end(); ++it )
+ {
+ if ( it->end )
+ m_ConditionPage->m_List->InsertItem(it->index, m_LogicBlockEndString);
+ else
+ m_ConditionPage->m_List->InsertItem(it->index, m_LogicBlockString);
+ }
+
+ m_ConditionPage->m_List->Thaw();
+ m_EffectPage->m_List->Thaw();
+}
+
+void TriggerSidebar::onCondSelect(wxListEvent& evt)
+{
+ m_SelectedCond = evt.GetIndex();
+ //if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::CONDITION_VIEW )
+ m_TriggerBottom->ToConditionView();
+ m_TriggerBottom->FillConditionData();
+}
+void TriggerSidebar::onEffectSelect(wxListEvent& evt)
+{
+ m_SelectedEffect = evt.GetIndex();
+ //if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::EFFECT_VIEW )
+ m_TriggerBottom->ToEffectView();
+ m_TriggerBottom->FillEffectData();
+}
+
+bool TriggerSidebar::IsGroupSelected()
+{
+ if ( ToDerived( m_TriggerTree->GetItemData(m_TriggerTree->GetSelection()) )->m_Group )
+ return true;
+ return false;
+}
+
+sTrigger TriggerSidebar::CreateTrigger(TriggerItemData* data)
+{
+ sTrigger trigger;
+
+ trigger.active = data->active;
+ trigger.group = data->group;
+ trigger.maxRuns = data->maxRuns;
+ trigger.name = data->name;
+ trigger.timeValue = data->timeValue;
+
+ trigger.logicBlockEnds = data->logicBlockEnds;
+ trigger.logicBlocks = data->logicBlocks;
+ trigger.conditions = data->conditions;
+ trigger.effects = data->effects;
+ trigger.logicNots = data->logicNots;
+
+ return trigger;
+}
+
+void TriggerSidebar::CreateGroup(std::vector& groupList, sTriggerGroup& parent, wxTreeItemId index)
+{
+ wxTreeItemIdValue cookie;
+ std::vector triggers;
+ sTriggerGroup group( std::wstring(m_TriggerTree->GetItemText(index)) );
+ group.parentName = parent.name;
+
+ //Add this group to parent's child group
+ std::vector parentChildren = *parent.children;
+ parentChildren.push_back(*group.parentName);
+ parent.children = parentChildren;
+
+ for ( wxTreeItemId ID = m_TriggerTree->GetFirstChild(index, cookie); ID.IsOk();
+ ID = m_TriggerTree->GetNextChild(index, cookie) )
+ {
+ TriggerItemData* itemData = ToDerived( m_TriggerTree->GetItemData(ID) );
+ if ( itemData->m_Group )
+ CreateGroup(groupList, group, ID);
+ else
+ triggers.push_back( CreateTrigger(itemData) );
+ }
+
+ group.triggers = triggers;
+ groupList.push_back(group);
+}
+
+void TriggerSidebar::UpdateEngineData()
+{
+ wxTreeItemIdValue cookie;
+ wxTreeItemId root = m_TriggerTree->GetRootItem();
+
+ //Find all root groups
+ std::vector groups;
+ std::vector triggers;
+ sTriggerGroup rootGroup(L"Triggers");
+
+ for ( wxTreeItemId ID = m_TriggerTree->GetFirstChild(root, cookie); ID.IsOk();
+ ID = m_TriggerTree->GetNextChild(root, cookie) )
+ {
+ TriggerItemData* itemData = ToDerived( m_TriggerTree->GetItemData(ID) );
+ if ( itemData->m_Group )
+ CreateGroup(groups, rootGroup, ID);
+ else
+ triggers.push_back( CreateTrigger(itemData) );
+ }
+
+ rootGroup.triggers = triggers;
+ groups.push_back(rootGroup);
+ POST_COMMAND( SetAllTriggers, (groups) );
+}
+TriggerItemData* TriggerSidebar::ToDerived(wxTreeItemData* data)
+{
+ return ( static_cast(data) );
+}
+TriggerItemData* TriggerSidebar::GetSelectedItemData()
+{
+ if ( !m_TriggerTree->GetSelection() )
+ m_TriggerTree->SelectItem(m_TriggerTree->GetRootItem());
+ return ToDerived( m_TriggerTree->GetItemData(m_TriggerTree->GetSelection()) );
+
+}
+
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h
new file mode 100644
index 0000000000..e49b5e4c78
--- /dev/null
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h
@@ -0,0 +1,80 @@
+/* Andrew Decker, a.k.a pyrolink
+ Contact ajdecker1022@msn.com
+ Desc: interface for creation and editing of triggers. Interprets
+ XML specifications then uses this to construct layout.
+*/
+
+#include "../Common/Sidebar.h"
+#include "GameInterface/Messages.h"
+
+class TriggerItemData;
+class TriggerTreeCtrl;
+class TriggerBottomBar;
+class TriggerPage;
+class wxTreeItemId;
+
+class TriggerSidebar : public Sidebar
+{
+public:
+ enum { ID_CondList, ID_EffectList };
+
+ TriggerSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
+
+ void onTreeDrag(wxTreeEvent& evt);
+ void onTreeNameChange(wxTreeEvent& evt);
+ //void onTreeDelete(wxTreeEvent& evt);
+ void onTreeSelChange(wxTreeEvent& evt);
+ void onTreeCollapse(wxTreeEvent& evt);
+ void onListSelect(wxListEvent& evt);
+ void onEffectSelect(wxListEvent& evt);
+ void onCondSelect(wxListEvent& evt);
+ void onPageChange(wxNotebookEvent& evt);
+
+ bool IsGroupSelected();
+ TriggerItemData* ToDerived(wxTreeItemData* data);
+ TriggerItemData* GetSelectedItemData();
+
+ //Finds condition number (index+1) of m_SelectedCond [needed because of logic blocks]
+ int GetConditionCount(int limit);
+ void UpdateLists();
+ void UpdateEngineData();
+
+ //AtlasMessage::sTriggerList m_TriggerList;
+
+ TriggerBottomBar* m_TriggerBottom;
+ TriggerTreeCtrl* m_TriggerTree;
+ TriggerPage* m_ConditionPage, *m_EffectPage;
+ wxNotebook* m_Notebook;
+
+ size_t m_TriggerCount, m_GroupCount;
+ long m_SelectedCond, m_SelectedEffect, m_SelectedCondIndex, m_SelectedEffectIndex;
+ wxString m_LogicBlockString, m_LogicBlockEndString;
+
+protected:
+ virtual void OnFirstDisplay();
+
+private:
+ struct copyIfRootChild
+ {
+ copyIfRootChild(std::vector& groupList) : m_groupList(groupList) {}
+ void operator() ( const AtlasMessage::sTriggerGroup& group )
+ {
+ if ( *group.parentName == std::wstring(L"Triggers") )
+ m_groupList.push_back(group);
+ }
+ private:
+ std::vector& m_groupList;
+ };
+
+ void AddGroupTree(const AtlasMessage::sTriggerGroup& group, wxTreeItemId parent);
+
+ void CreateGroup(std::vector& groupList,
+ AtlasMessage::sTriggerGroup& parent, wxTreeItemId index);
+
+ AtlasMessage::sTrigger CreateTrigger(TriggerItemData* data);
+
+ std::vector m_TriggerGroups;
+
+ DECLARE_EVENT_TABLE();
+};
+
diff --git a/source/tools/atlas/DatafileIO/Util.h b/source/tools/atlas/DatafileIO/Util.h
index f1e9452fa4..17cefb3a0d 100644
--- a/source/tools/atlas/DatafileIO/Util.h
+++ b/source/tools/atlas/DatafileIO/Util.h
@@ -1,5 +1,6 @@
#include
#include
+
#if OS_UNIX
#include "ps/utf16string.h"
#include
@@ -11,7 +12,7 @@
namespace DatafileIO
{
-#if OS_WIN
+#ifdef _WIN32
// TODO: proper portability
typedef int int32_t;
typedef unsigned int uint32_t;
diff --git a/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp b/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp
new file mode 100644
index 0000000000..8f654f90c1
--- /dev/null
+++ b/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp
@@ -0,0 +1,321 @@
+#include "precompiled.h"
+
+#include "MessageHandler.h"
+#include "../CommandProc.h"
+#include "../Shareable.h"
+
+#include "simulation/TriggerManager.h"
+#include "ps/Game.h"
+//#include "../CommandProc.h"
+
+
+namespace AtlasMessage {
+
+sTriggerSpec TriggerSpecToAtlas(const CTriggerSpec& spec)
+{
+ sTriggerSpec atlasSpec;
+ std::vector< sTriggerParameter > atlasParameters;
+ const std::set& parameters = spec.GetParameters();
+
+ for ( std::set::const_iterator it=parameters.begin(); it!=parameters.end(); ++it )
+ {
+ sTriggerParameter atlasParam;
+ atlasParam.column = it->column;
+ atlasParam.inputType = it->inputType;
+ atlasParam.name = it->name;
+ atlasParam.parameterOrder = it->parameterOrder;
+ atlasParam.row = it->row;
+
+ atlasParam.windowType = it->windowType;
+ atlasParam.xPos = it->xPos;
+ atlasParam.yPos = it->yPos;
+ atlasParam.xSize = it->xSize;
+ atlasParam.ySize = it->ySize;
+ atlasParameters.push_back(atlasParam);
+ }
+ atlasSpec.functionName = spec.functionName;
+ atlasSpec.displayName = spec.displayName;
+ atlasSpec.parameters = atlasParameters;
+ return atlasSpec;
+}
+
+sTrigger TriggerToAtlas(const MapTrigger& trigger)
+{
+ sTrigger atlasTrigger;
+ atlasTrigger.active = trigger.active;
+ atlasTrigger.timeValue = trigger.timeValue;
+ atlasTrigger.maxRuns = trigger.maxRunCount;
+ atlasTrigger.group = trigger.groupName;
+ atlasTrigger.name = trigger.name;
+
+ std::vector atlasNots;
+ std::vector atlasBlocks, atlasBlockEnds;
+
+ for ( std::set::const_iterator it = trigger.logicBlocks.begin();
+ it != trigger.logicBlocks.end(); ++it )
+ {
+ atlasBlocks.push_back( (int)it->index );
+ atlasNots.push_back( it->not );
+ }
+ for ( std::set::const_iterator it = trigger.logicBlockEnds.begin();
+ it != trigger.logicBlockEnds.end(); ++it )
+ {
+ atlasBlockEnds.push_back( (int)*it );
+ }
+ atlasTrigger.logicNots = atlasNots;
+ atlasTrigger.logicBlocks = atlasBlocks;
+ atlasTrigger.logicBlockEnds = atlasBlockEnds;
+
+ std::vector atlasConditions;
+ std::vector atlasEffects;
+
+ for ( std::list::const_iterator it = trigger.conditions.begin();
+ it != trigger.conditions.end(); ++it )
+ {
+ sTriggerCondition atlasCondition;
+ atlasCondition.linkLogic = it->linkLogic;
+ atlasCondition.name = it->name;
+ atlasCondition.functionName = it->functionName;
+ atlasCondition.displayName = it->displayName;
+ atlasCondition.not = it->not;
+ std::vector parameters;
+
+ for ( std::list::const_iterator it2=it->parameters.begin();
+ it2 != it->parameters.end(); ++it2 )
+ {
+ parameters.push_back( std::wstring(it2->c_str()) );
+ }
+
+ atlasCondition.parameters = parameters;
+ atlasConditions.push_back(atlasCondition);
+ }
+
+ for ( std::list::const_iterator it = trigger.effects.begin();
+ it != trigger.effects.end(); ++it )
+ {
+ sTriggerEffect atlasEffect;
+ std::vector parameters;
+ atlasEffect.name = it->name;
+ atlasEffect.functionName = it->functionName;
+ atlasEffect.displayName = it->displayName;
+
+ for ( std::list::const_iterator it2 = it->parameters.begin();
+ it2 != it->parameters.end(); ++it2 )
+ {
+ parameters.push_back( std::wstring(it2->c_str()) );
+ }
+ atlasEffect.parameters = parameters;
+ atlasEffects.push_back( atlasEffect );
+ }
+
+ atlasTrigger.conditions = atlasConditions;
+ atlasTrigger.effects = atlasEffects;
+ return atlasTrigger;
+}
+
+sTriggerGroup GroupToAtlas(const MapTriggerGroup& group)
+{
+ sTriggerGroup atlasGroup;
+ atlasGroup.parentName = group.parentName;
+ atlasGroup.name = group.name;
+
+ std::vector atlasTriggers;
+ std::vector atlasChildren;
+ for ( std::list::const_iterator it = group.triggers.begin();
+ it != group.triggers.end(); ++it )
+ {
+ atlasTriggers.push_back( TriggerToAtlas(*it) );
+ }
+ for ( std::list::const_iterator it = group.childGroups.begin();
+ it != group.childGroups.end(); ++it )
+ {
+ atlasChildren.push_back( std::wstring(it->c_str()) );
+ }
+
+ atlasGroup.triggers = atlasTriggers;
+ atlasGroup.children = atlasChildren;
+ return atlasGroup;
+}
+
+MapTrigger AtlasToTrigger(const sTrigger& trigger)
+{
+ MapTrigger engineTrigger;
+
+ engineTrigger.active = trigger.active;
+ engineTrigger.groupName = *trigger.group;
+
+ std::vector blockEnds = *trigger.logicBlockEnds, blocks = *trigger.logicBlocks;
+ std::copy( blockEnds.begin(), blockEnds.end(), engineTrigger.logicBlockEnds.begin() );
+ std::copy( blocks.begin(), blocks.end(), engineTrigger.logicBlocks.begin() );
+
+ engineTrigger.maxRunCount = trigger.maxRuns;
+ engineTrigger.name = *trigger.name;
+ engineTrigger.timeValue = trigger.timeValue;
+
+ std::vector conditions = *trigger.conditions;
+ std::vector effects = *trigger.effects;
+
+ for ( std::vector::const_iterator it = conditions.begin(); it != conditions.end(); ++it )
+ {
+ engineTrigger.conditions.push_back( MapTriggerCondition() );
+ MapTriggerCondition* cond = &engineTrigger.conditions.back();
+
+ cond->functionName = *it->functionName;
+ cond->displayName = *it->displayName;
+ cond->linkLogic = it->linkLogic;
+ cond->name = *it->name;
+ cond->not = it->not;
+
+ std::vector parameters = *it->parameters;
+ for ( std::vector::const_iterator it2 = parameters.begin(); it2 != parameters.end(); ++it2 )
+ {
+ cond->parameters.push_back( CStrW(*it2) );
+ }
+ }
+
+ for ( std::vector::const_iterator it = effects.begin(); it != effects.end(); ++it )
+ {
+ engineTrigger.effects.push_back( MapTriggerEffect() );
+ MapTriggerEffect* effect = &engineTrigger.effects.back();
+
+ effect->functionName = *it->functionName;
+ effect->displayName = *it->displayName;
+ effect->name = *it->name;
+ std::vector parameters = *it->parameters;
+
+ for ( std::vector::const_iterator it2 = parameters.begin(); it2 != parameters.end(); ++it2 )
+ {
+ effect->parameters.push_back( CStrW(*it2) );
+ }
+ }
+
+ return engineTrigger;
+}
+
+
+MapTriggerGroup AtlasToGroup(const sTriggerGroup& group)
+{
+ MapTriggerGroup engineGroup;
+ engineGroup.parentName = *group.parentName;
+ engineGroup.name = *group.name;
+
+ std::list engineTriggers;
+ std::vector atlasChildren = *group.children;
+ std::vector atlasTriggers = *group.triggers;
+
+ for ( std::vector::const_iterator it = atlasTriggers.begin();
+ it != atlasTriggers.end(); ++it )
+ {
+ engineTriggers.push_back( AtlasToTrigger(*it) );
+ }
+ for ( std::vector::const_iterator it = atlasChildren.begin(); it != atlasChildren.end(); ++it )
+ engineGroup.childGroups.push_back(*it);
+
+ engineGroup.triggers = engineTriggers;
+ return engineGroup;
+}
+
+std::vector GetCurrentTriggers()
+{
+ const std::list& groups = g_TriggerManager.GetAllTriggerGroups();
+ std::vector atlasGroups;
+
+ for ( std::list::const_iterator it = groups.begin(); it != groups.end(); ++it )
+ atlasGroups.push_back( GroupToAtlas(*it) );
+ return atlasGroups;
+}
+
+void SetCurrentTriggers(const std::vector& groups)
+{
+ std::list engineGroups;
+ for ( std::vector::const_iterator it = groups.begin(); it != groups.end(); ++it )
+ engineGroups.push_back( AtlasToGroup(*it) );
+ g_TriggerManager.SetAllGroups(engineGroups);
+}
+
+QUERYHANDLER(GetTriggerData)
+{
+ const std::list& conditions = g_TriggerManager.GetAllConditions();
+ const std::list& effects = g_TriggerManager.GetAllEffects();
+ std::vector atlasConditions;
+ std::vector atlasEffects;
+
+ for ( std::list::const_iterator it=conditions.begin(); it!=conditions.end(); ++it )
+ atlasConditions.push_back( TriggerSpecToAtlas(*it) );
+ for ( std::list::const_iterator it=effects.begin(); it!=effects.end(); ++it )
+ atlasEffects.push_back( TriggerSpecToAtlas(*it) );
+
+ msg->conditions = atlasConditions;
+ msg->effects = atlasEffects;
+ msg->groups = GetCurrentTriggers();
+}
+
+QUERYHANDLER(GetTriggerChoices)
+{
+ std::vector choices = g_TriggerManager.GetTriggerChoices( CStrW(*msg->name) );
+ if ( choices.empty() )
+ return;
+
+ //If a special list (i.e. uses engine data)
+ if ( choices.size() == 1 )
+ {
+
+ if ( choices[0] == std::wstring(L"ATLAS_CINEMA_LIST") )
+ {
+ choices.clear();
+ const std::map& tracks = g_Game->GetView()->GetCinema()->GetAllTracks();
+ for ( std::map::const_iterator it = tracks.begin(); it != tracks.end(); ++it )
+ choices.push_back(it->first);
+ }
+ else if ( choices[0] == std::wstring(L"ATLAS_TRIGGER_LIST") )
+ {
+ choices.clear();
+ const std::list& groups = g_TriggerManager.GetAllTriggerGroups();
+ for ( std::list::const_iterator it = groups.begin();
+ it != groups.end(); ++it )
+ {
+ for ( std::list::const_iterator it2 = it->triggers.begin();
+ it2 != it->triggers.end(); ++it2 )
+ {
+ choices.push_back(it2->name);
+ }
+ }
+ }
+ else if ( choices[0] == std::wstring(L"ATLAS_TRIG_GROUP_LIST") )
+ {
+ choices.clear();
+ const std::list& groups = g_TriggerManager.GetAllTriggerGroups();
+ for ( std::list::const_iterator it = groups.begin();
+ it != groups.end(); ++it )
+ {
+ choices.push_back(it->name);
+ }
+ }
+ else
+ debug_warn("Invalid choice list for trigger specification parameter");
+ }
+ msg->choices = choices;
+}
+
+BEGIN_COMMAND(SetAllTriggers)
+{
+ std::vector m_oldGroups, m_newGroups;
+
+ void Do()
+ {
+ m_oldGroups = GetCurrentTriggers();
+ m_newGroups = *msg->groups;
+ Redo();
+ }
+ void Redo()
+ {
+ SetCurrentTriggers(m_newGroups);
+ }
+ void Undo()
+ {
+ SetCurrentTriggers(m_oldGroups);
+ }
+};
+END_COMMAND(SetAllTriggers);
+
+}
\ No newline at end of file
diff --git a/source/tools/atlas/GameInterface/Messages.h b/source/tools/atlas/GameInterface/Messages.h
index 87c8dc6b95..49758ab98a 100644
--- a/source/tools/atlas/GameInterface/Messages.h
+++ b/source/tools/atlas/GameInterface/Messages.h
@@ -344,6 +344,32 @@ MESSAGE(CinemaEvent,
//////////////////////////////////////////////////////////////////////////
+enum eTriggerListType
+{
+ CINEMA_LIST,
+ TRIGGER_LIST,
+ TRIG_GROUP_LIST //list of trigger groups
+ // [Eventually include things like entities and areas as the editor progresses...]
+};
+
+
+QUERY(GetTriggerData,
+ , //no inputs
+ ((std::vector, groups))
+ ((std::vector, conditions))
+ ((std::vector, effects))
+ );
+
+QUERY(GetTriggerChoices,
+ ((std::wstring, name)),
+ ((std::vector, choices))
+ );
+
+COMMAND(SetAllTriggers, NOMERGE,
+ ((std::vector, groups))
+ );
+
+
#ifndef MESSAGES_SKIP_SETUP
#include "MessagesSetup.h"
#endif
diff --git a/source/tools/atlas/GameInterface/Shareable.h b/source/tools/atlas/GameInterface/Shareable.h
index bb6401456e..fef5de7791 100644
--- a/source/tools/atlas/GameInterface/Shareable.h
+++ b/source/tools/atlas/GameInterface/Shareable.h
@@ -82,6 +82,7 @@ public:
SHAREABLE_PRIMITIVE(unsigned char);
SHAREABLE_PRIMITIVE(int);
+SHAREABLE_PRIMITIVE(long);
SHAREABLE_PRIMITIVE(bool);
SHAREABLE_PRIMITIVE(float);
SHAREABLE_PRIMITIVE(void*);
diff --git a/source/tools/atlas/GameInterface/SharedTypes.h b/source/tools/atlas/GameInterface/SharedTypes.h
index 1d130e67bc..73fd4e7719 100644
--- a/source/tools/atlas/GameInterface/SharedTypes.h
+++ b/source/tools/atlas/GameInterface/SharedTypes.h
@@ -121,6 +121,119 @@ struct sCameraInfo
SHAREABLE_STRUCT(sCameraInfo);
+//******Triggers*****
+
+
+struct sTriggerParameter
+{
+ Shareable row, column, xPos, yPos, xSize, ySize, parameterOrder;
+ Shareable name, inputType, windowType;
+};
+SHAREABLE_STRUCT(sTriggerParameter);
+
+struct sTriggerSpec
+{
+ Shareable > parameters;
+ Shareable displayName, functionName;
+
+ bool operator== ( const std::wstring& name) const
+ {
+ return ( *displayName == name );
+ }
+};
+SHAREABLE_STRUCT(sTriggerSpec);
+
+
+struct sTriggerCondition
+{
+ sTriggerCondition() : linkLogic(1), not(false) {}
+ sTriggerCondition(const std::wstring& _name) : linkLogic(1), not(false), name(_name) {}
+
+ //displayName is used for selecting choice items in Atlas
+ Shareable name, functionName, displayName;
+ Shareable< std::vector > parameters;
+
+ //0 = none, 1 = and, 2 = or
+ Shareable linkLogic;
+ Shareable not;
+
+ bool operator== ( const std::wstring& _name ) const
+ {
+ return (*name == _name);
+ }
+};
+
+SHAREABLE_STRUCT(sTriggerCondition);
+
+struct sTriggerEffect
+{
+ sTriggerEffect() {}
+ sTriggerEffect(const std::wstring& _name) : name(_name) {}
+
+ Shareable name, functionName, displayName;
+ Shareable< std::vector > parameters;
+ //Shareable loop;
+
+ bool operator== ( const std::wstring& _name )
+ {
+ return (*name == _name);
+ }
+};
+SHAREABLE_STRUCT(sTriggerEffect);
+
+struct sTrigger
+{
+ Shareable name, group;
+ Shareable< std::vector > conditions;
+ Shareable< std::vector > effects;
+
+ //For beginnings, the index of the term it comes before. For ends, the index it comes after
+ Shareable< std::vector > logicBlocks, logicBlockEnds;
+ Shareable< std::vector > logicNots; //true if logicBlocks are not-ed
+ Shareable timeValue;
+ Shareable maxRuns;
+ Shareable active;
+
+ sTrigger() : timeValue(0), maxRuns(-1), active(0) {}
+ sTrigger(std::wstring _name) : name(_name), timeValue(0), maxRuns(0), active(0) {}
+ bool operator== (const sTrigger& trigger)
+ {
+ return (*name == *trigger.name);
+ }
+ bool operator!= (const sTrigger& trigger)
+ {
+ return (*name != *trigger.name);
+ }
+};
+SHAREABLE_STRUCT(sTrigger);
+
+
+struct sTriggerGroup
+{
+ Shareable name, parentName;
+ Shareable< std::vector > children;
+ Shareable< std::vector > triggers;
+
+ sTriggerGroup() { }
+ sTriggerGroup(std::wstring _name) : name(_name) { }
+
+ bool operator== (const sTriggerGroup& group) const
+ {
+ return (*name == *group.name);
+ }
+ bool operator== (const std::wstring& _name) const
+ {
+ return (*name == _name);
+ }
+ /*bool operator!= (const sTriggerGroup& group)
+ {
+ return (*name != *group.name);
+ }*/
+};
+
+SHAREABLE_STRUCT(sTriggerGroup);
+
+
}
#endif // SHAREDTYPES_H__