diff options
-rw-r--r-- | src/components/automatable.h | 34 | ||||
-rw-r--r-- | src/components/prototypable.h | 11 | ||||
-rw-r--r-- | src/components/runnable.h | 36 | ||||
-rw-r--r-- | src/game.h | 2 | ||||
-rw-r--r-- | src/systems/realizing.cpp | 33 | ||||
-rw-r--r-- | src/systems/scripting.cpp | 70 | ||||
-rw-r--r-- | src/systems/scripting.h | 10 |
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 | |||
7 | class AutomatableComponent : public Component { | ||
8 | public: | ||
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 | ||
8 | class RunnableComponent : public Component { | 9 | class RunnableComponent : public Component { |
9 | public: | 10 | public: |
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 | ||
141 | void ScriptingSystem::killScript(id_type entity) | 142 | void 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 | ||
149 | template <typename... Args> | 158 | template <typename... Args> |
150 | EntityManager::id_type ScriptingSystem::runScript( | 159 | sol::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 | |||
209 | void 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 | ||
195 | EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity) | 233 | void 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 | ||
200 | void ScriptingSystem::onTouch(id_type entity, id_type player) | 244 | void 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 | ||
20 | private: | 22 | private: |
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 | }; |