summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/components/automatable.h34
-rw-r--r--src/components/prototypable.h11
-rw-r--r--src/components/runnable.h36
-rw-r--r--src/game.h2
-rw-r--r--src/systems/realizing.cpp33
-rw-r--r--src/systems/scripting.cpp70
-rw-r--r--src/systems/scripting.h10
7 files changed, 153 insertions, 43 deletions
diff --git a/src/components/automatable.h b/src/components/automatable.h new file mode 100644 index 0000000..22d9859 --- /dev/null +++ b/src/components/automatable.h
@@ -0,0 +1,34 @@
1#ifndef AUTOMATABLE_H_FACB42A5
2#define AUTOMATABLE_H_FACB42A5
3
4#include "component.h"
5#include "entity_manager.h"
6
7class AutomatableComponent : public Component {
8public:
9
10 using id_type = EntityManager::id_type;
11
12 /**
13 * Controls what script will be run as this entity's behavior. It should refer
14 * to a table in the global namespace of the script engine state, and that
15 * table should contain a function called "Behavior".
16 */
17 std::string table;
18
19 /**
20 * Whether or not the behavior script is running.
21 *
22 * @managed_by ScriptingSystem
23 */
24 bool running = false;
25
26 /**
27 * The entity ID of the running script, if there is one.
28 *
29 * @managed_by ScriptingSystem
30 */
31 id_type script;
32};
33
34#endif /* end of include guard: AUTOMATABLE_H_FACB42A5 */
diff --git a/src/components/prototypable.h b/src/components/prototypable.h index 4659e7c..c0dd972 100644 --- a/src/components/prototypable.h +++ b/src/components/prototypable.h
@@ -9,14 +9,15 @@ public:
9 9
10 using id_type = EntityManager::id_type; 10 using id_type = EntityManager::id_type;
11 11
12 /**
13 * The index of the object in the map definition.
14 */
12 size_t mapObjectIndex; 15 size_t mapObjectIndex;
13 16
17 /**
18 * The name of the prototype that the object was spawned from.
19 */
14 std::string prototypeId; 20 std::string prototypeId;
15
16 bool hasBehavior = false;
17 bool runningBehavior = false;
18
19 id_type behaviorScript;
20}; 21};
21 22
22#endif /* end of include guard: PROTOTYPABLE_H_817F2205 */ 23#endif /* end of include guard: PROTOTYPABLE_H_817F2205 */
diff --git a/src/components/runnable.h b/src/components/runnable.h index 1b994fb..956bfdc 100644 --- a/src/components/runnable.h +++ b/src/components/runnable.h
@@ -4,12 +4,48 @@
4#include "component.h" 4#include "component.h"
5#include <sol.hpp> 5#include <sol.hpp>
6#include <memory> 6#include <memory>
7#include "entity_manager.h"
7 8
8class RunnableComponent : public Component { 9class RunnableComponent : public Component {
9public: 10public:
10 11
12 using id_type = EntityManager::id_type;
13
14 /**
15 * A Lua stack where the entity's script is running.
16 *
17 * NOTE: This object is called a thread, but there is no multi-threading going
18 * on.
19 *
20 * @managed_by ScriptingSystem
21 */
11 std::unique_ptr<sol::thread> runner; 22 std::unique_ptr<sol::thread> runner;
23
24 /**
25 * An entry point to the script running in the runner thread.
26 *
27 * @managed_by ScriptingSystem
28 */
12 std::unique_ptr<sol::coroutine> callable; 29 std::unique_ptr<sol::coroutine> callable;
30
31 /**
32 * Whether or not this entity represents a behavior script. A behavior script
33 * usually does not terminate on its own, and can be terminated at will by
34 * another system, usually when the automatable entity leaves the active map.
35 *
36 * @managed_by ScriptingSystem
37 */
38 bool behavior = false;
39
40 /**
41 * If this is a behavior script, this is the ID of the automatable entity that
42 * the behavior belongs to. This is required so that the ScriptingSystem can
43 * notify the automatable entity if the behavior script terminates by itself,
44 * and that it shouldn't attempt to terminate it.
45 *
46 * @managed_by ScriptingSystem
47 */
48 id_type actor;
13}; 49};
14 50
15#endif /* end of include guard: AUTOMATABLE_H_3D519131 */ 51#endif /* end of include guard: AUTOMATABLE_H_3D519131 */
diff --git a/src/game.h b/src/game.h index dc256c6..d7fdcd7 100644 --- a/src/game.h +++ b/src/game.h
@@ -44,8 +44,8 @@ private:
44 44
45 std::mt19937 rng_; 45 std::mt19937 rng_;
46 Renderer renderer_; 46 Renderer renderer_;
47 EntityManager entityManager_;
48 SystemManager systemManager_; 47 SystemManager systemManager_;
48 EntityManager entityManager_;
49 bool shouldQuit_ = false; 49 bool shouldQuit_ = false;
50}; 50};
51 51
diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 7f5aefb..baacf5a 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp
@@ -12,6 +12,7 @@
12#include "components/ponderable.h" 12#include "components/ponderable.h"
13#include "components/transformable.h" 13#include "components/transformable.h"
14#include "components/prototypable.h" 14#include "components/prototypable.h"
15#include "components/automatable.h"
15#include "systems/mapping.h" 16#include "systems/mapping.h"
16#include "systems/animating.h" 17#include "systems/animating.h"
17#include "systems/pondering.h" 18#include "systems/pondering.h"
@@ -223,7 +224,10 @@ RealizingSystem::RealizingSystem(
223 224
224 if (prototypeId == "movplat") 225 if (prototypeId == "movplat")
225 { 226 {
226 prototypable.hasBehavior = true; 227 auto& automatable = game_.getEntityManager().
228 emplaceComponent<AutomatableComponent>(mapObject);
229
230 automatable.table = prototypeId;
227 } else if (prototypeId == "checkpoint") 231 } else if (prototypeId == "checkpoint")
228 { 232 {
229 auto& ponderable = game_.getEntityManager(). 233 auto& ponderable = game_.getEntityManager().
@@ -403,19 +407,9 @@ void RealizingSystem::enterActiveMap(id_type entity)
403 ponderable.active = true; 407 ponderable.active = true;
404 } 408 }
405 409
406 if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity)) 410 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity))
407 { 411 {
408 auto& prototypable = game_.getEntityManager(). 412 game_.getSystemManager().getSystem<ScriptingSystem>().startBehavior(entity);
409 getComponent<PrototypableComponent>(entity);
410
411 if (prototypable.hasBehavior)
412 {
413 auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>();
414
415 prototypable.hasBehavior = true;
416 prototypable.runningBehavior = true;
417 prototypable.behaviorScript = scripting.runBehaviorScript(entity);
418 }
419 } 413 }
420} 414}
421 415
@@ -437,17 +431,8 @@ void RealizingSystem::leaveActiveMap(id_type entity)
437 ponderable.active = false; 431 ponderable.active = false;
438 } 432 }
439 433
440 if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity)) 434 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity))
441 { 435 {
442 auto& prototypable = game_.getEntityManager(). 436 game_.getSystemManager().getSystem<ScriptingSystem>().stopBehavior(entity);
443 getComponent<PrototypableComponent>(entity);
444
445 if (prototypable.runningBehavior)
446 {
447 auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>();
448 scripting.killScript(prototypable.behaviorScript);
449
450 prototypable.runningBehavior = false;
451 }
452 } 437 }
453} 438}
diff --git a/src/systems/scripting.cpp b/src/systems/scripting.cpp index 57c3fd5..c423558 100644 --- a/src/systems/scripting.cpp +++ b/src/systems/scripting.cpp
@@ -6,6 +6,7 @@
6#include "components/playable.h" 6#include "components/playable.h"
7#include "components/mappable.h" 7#include "components/mappable.h"
8#include "components/prototypable.h" 8#include "components/prototypable.h"
9#include "components/automatable.h"
9#include "systems/realizing.h" 10#include "systems/realizing.h"
10#include "vector.h" 11#include "vector.h"
11 12
@@ -133,28 +134,34 @@ void ScriptingSystem::tick(double dt)
133 134
134 if (!*runnable.callable) 135 if (!*runnable.callable)
135 { 136 {
136 game_.getEntityManager().deleteEntity(entity); 137 killScript(entity);
137 } 138 }
138 } 139 }
139} 140}
140 141
141void ScriptingSystem::killScript(id_type entity) 142void ScriptingSystem::killScript(id_type entity)
142{ 143{
143 if (game_.getEntityManager().hasComponent<RunnableComponent>(entity)) 144 auto& runnable = game_.getEntityManager().
145 getComponent<RunnableComponent>(entity);
146
147 if (runnable.behavior)
144 { 148 {
145 game_.getEntityManager().deleteEntity(entity); 149 auto& automatable = game_.getEntityManager().
150 getComponent<AutomatableComponent>(runnable.actor);
151
152 automatable.running = false;
146 } 153 }
154
155 game_.getEntityManager().deleteEntity(entity);
147} 156}
148 157
149template <typename... Args> 158template <typename... Args>
150EntityManager::id_type ScriptingSystem::runScript( 159sol::optional<EntityManager::id_type> ScriptingSystem::runScript(
160 std::string table,
151 std::string event, 161 std::string event,
152 id_type entity, 162 id_type entity,
153 Args&&... args) 163 Args&&... args)
154{ 164{
155 auto& prototypable = game_.getEntityManager().
156 getComponent<PrototypableComponent>(entity);
157
158 id_type script = game_.getEntityManager().emplaceEntity(); 165 id_type script = game_.getEntityManager().emplaceEntity();
159 166
160 auto& runnable = game_.getEntityManager(). 167 auto& runnable = game_.getEntityManager().
@@ -171,7 +178,7 @@ EntityManager::id_type ScriptingSystem::runScript(
171 new sol::coroutine( 178 new sol::coroutine(
172 runnable.runner->state(). 179 runnable.runner->state().
173 traverse_get<sol::function>( 180 traverse_get<sol::function>(
174 prototypable.prototypeId, 181 table,
175 event))); 182 event)));
176 183
177 if (!*runnable.callable) 184 if (!*runnable.callable)
@@ -189,17 +196,58 @@ EntityManager::id_type ScriptingSystem::runScript(
189 throw std::runtime_error(e.what()); 196 throw std::runtime_error(e.what());
190 } 197 }
191 198
192 return script; 199 if (*runnable.callable)
200 {
201 return { script };
202 } else {
203 killScript(script);
204
205 return {};
206 }
207}
208
209void ScriptingSystem::startBehavior(id_type entity)
210{
211 auto& automatable = game_.getEntityManager().
212 getComponent<AutomatableComponent>(entity);
213
214 sol::optional<id_type> script =
215 runScript(
216 automatable.table,
217 "Behavior",
218 entity);
219
220 if (script)
221 {
222 automatable.script = *script;
223 automatable.running = true;
224
225 auto& runnable = game_.getEntityManager().
226 getComponent<RunnableComponent>(automatable.script);
227
228 runnable.behavior = true;
229 runnable.actor = entity;
230 }
193} 231}
194 232
195EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity) 233void ScriptingSystem::stopBehavior(id_type entity)
196{ 234{
197 return runScript("Behavior", entity); 235 auto& automatable = game_.getEntityManager().
236 getComponent<AutomatableComponent>(entity);
237
238 if (automatable.running)
239 {
240 killScript(automatable.script);
241 }
198} 242}
199 243
200void ScriptingSystem::onTouch(id_type entity, id_type player) 244void ScriptingSystem::onTouch(id_type entity, id_type player)
201{ 245{
246 auto& prototypable = game_.getEntityManager().
247 getComponent<PrototypableComponent>(entity);
248
202 runScript( 249 runScript(
250 prototypable.prototypeId,
203 "OnTouch", 251 "OnTouch",
204 entity, 252 entity,
205 script_entity(player)); 253 script_entity(player));
diff --git a/src/systems/scripting.h b/src/systems/scripting.h index e330316..b119c3f 100644 --- a/src/systems/scripting.h +++ b/src/systems/scripting.h
@@ -13,14 +13,20 @@ public:
13 13
14 void killScript(id_type entity); 14 void killScript(id_type entity);
15 15
16 id_type runBehaviorScript(id_type entity); 16 void startBehavior(id_type entity);
17
18 void stopBehavior(id_type entity);
17 19
18 void onTouch(id_type entity, id_type player); 20 void onTouch(id_type entity, id_type player);
19 21
20private: 22private:
21 23
22 template <typename... Args> 24 template <typename... Args>
23 id_type runScript(std::string event, id_type entity, Args&&... args); 25 sol::optional<id_type> runScript(
26 std::string table,
27 std::string event,
28 id_type entity,
29 Args&&... args);
24 30
25 sol::state engine_; 31 sol::state engine_;
26}; 32};