summary refs log tree commit diff stats
path: root/src/systems/scripting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/systems/scripting.cpp')
-rw-r--r--src/systems/scripting.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/systems/scripting.cpp b/src/systems/scripting.cpp new file mode 100644 index 0000000..504224c --- /dev/null +++ b/src/systems/scripting.cpp
@@ -0,0 +1,257 @@
1#include "scripting.h"
2#include "game.h"
3#include "components/runnable.h"
4#include "components/ponderable.h"
5#include "components/transformable.h"
6#include "components/playable.h"
7#include "components/mappable.h"
8#include "components/prototypable.h"
9#include "components/automatable.h"
10#include "systems/realizing.h"
11#include "vector.h"
12#include "muxer.h"
13
14struct script_entity {
15 using id_type = EntityManager::id_type;
16
17 id_type id;
18
19 script_entity(id_type id) : id(id)
20 {
21 }
22};
23
24ScriptingSystem::ScriptingSystem(Game& game) : System(game)
25{
26 id_type entity = game_.getEntityManager().emplaceEntity();
27
28 engine_.open_libraries(sol::lib::base, sol::lib::coroutine);
29
30 engine_.new_usertype<vec2d>(
31 "vec2d",
32 sol::constructors<vec2d(), vec2d(double, double)>(),
33 "x", sol::property(
34 [] (vec2d& v) -> double { return v.x(); },
35 [] (vec2d& v, double x) { v.x() = x; }),
36 "y", sol::property(
37 [] (vec2d& v) -> double { return v.y(); },
38 [] (vec2d& v, double y) { v.y() = y; }));
39
40 engine_.new_usertype<vec2i>(
41 "vec2i",
42 sol::constructors<vec2i(), vec2i(int, int)>(),
43 "x", [] (vec2i& v) -> int& { return v.x(); },
44 "y", [] (vec2i& v) -> int& { return v.y(); });
45
46 engine_.new_usertype<script_entity>(
47 "entity",
48 sol::constructors<script_entity(id_type)>(),
49 "id", &script_entity::id,
50 "transformable",
51 [&] (script_entity& entity) -> TransformableComponent& {
52 return game_.getEntityManager().
53 getComponent<TransformableComponent>(entity.id);
54 },
55 "ponderable",
56 [&] (script_entity& entity) -> PonderableComponent& {
57 return game_.getEntityManager().
58 getComponent<PonderableComponent>(entity.id);
59 },
60 "mappable",
61 [&] (script_entity& entity) -> MappableComponent& {
62 return game_.getEntityManager().
63 getComponent<MappableComponent>(entity.id);
64 },
65 "playable",
66 [&] (script_entity& entity) -> PlayableComponent& {
67 return game_.getEntityManager().
68 getComponent<PlayableComponent>(entity.id);
69 },
70 "prototypable",
71 [&] (script_entity& entity) -> PrototypableComponent& {
72 return game_.getEntityManager().
73 getComponent<PrototypableComponent>(entity.id);
74 });
75
76 engine_.new_usertype<TransformableComponent>(
77 "transformable",
78 "pos", &TransformableComponent::pos);
79
80 engine_.new_usertype<PonderableComponent>(
81 "ponderable",
82 "vel", &PonderableComponent::vel,
83 "accel", &PonderableComponent::accel);
84
85 engine_.new_usertype<MappableComponent>(
86 "mappable",
87 "mapId", &MappableComponent::mapId);
88
89 engine_.new_usertype<PlayableComponent>(
90 "playable",
91 "checkpointPos", &PlayableComponent::checkpointPos,
92 "checkpointMapId", &PlayableComponent::checkpointMapId,
93 "checkpointMapObject", &PlayableComponent::checkpointMapObject,
94 "checkpointMapObjectIndex", &PlayableComponent::checkpointMapObjectIndex);
95
96 engine_.new_usertype<PrototypableComponent>(
97 "prototypable",
98 "mapObjectIndex", &PrototypableComponent::mapObjectIndex,
99 "prototypeId", &PrototypableComponent::prototypeId);
100
101 engine_.new_usertype<RealizingSystem>(
102 "realizing",
103 "activeMap", sol::property(&RealizingSystem::getActiveMap));
104
105 engine_.set_function(
106 "realizing",
107 [&] () -> RealizingSystem& {
108 return game_.getSystemManager().getSystem<RealizingSystem>();
109 });
110
111 engine_.set_function("playSound", playSound);
112
113 engine_.script_file("scripts/common.lua");
114 engine_.script_file("scripts/movplat.lua");
115 engine_.script_file("scripts/checkpoint.lua");
116}
117
118void ScriptingSystem::tick(double dt)
119{
120 auto entities = game_.getEntityManager().getEntitiesWithComponents<
121 RunnableComponent>();
122
123 for (id_type entity : entities)
124 {
125 auto& runnable = game_.getEntityManager().
126 getComponent<RunnableComponent>(entity);
127
128 if (*runnable.callable)
129 {
130 auto result = (*runnable.callable)(dt);
131 if (!result.valid())
132 {
133 sol::error e = result;
134 throw std::runtime_error(e.what());
135 }
136 }
137
138 if (!*runnable.callable)
139 {
140 killScript(entity);
141 }
142 }
143}
144
145void ScriptingSystem::killScript(id_type entity)
146{
147 auto& runnable = game_.getEntityManager().
148 getComponent<RunnableComponent>(entity);
149
150 if (runnable.behavior)
151 {
152 auto& automatable = game_.getEntityManager().
153 getComponent<AutomatableComponent>(runnable.actor);
154
155 automatable.running = false;
156 }
157
158 game_.getEntityManager().deleteEntity(entity);
159}
160
161template <typename... Args>
162sol::optional<EntityManager::id_type> ScriptingSystem::runScript(
163 std::string table,
164 std::string event,
165 id_type entity,
166 Args&&... args)
167{
168 id_type script = game_.getEntityManager().emplaceEntity();
169
170 auto& runnable = game_.getEntityManager().
171 emplaceComponent<RunnableComponent>(script);
172
173 runnable.runner =
174 std::unique_ptr<sol::thread>(
175 new sol::thread(
176 sol::thread::create(
177 engine_.lua_state())));
178
179 runnable.callable =
180 std::unique_ptr<sol::coroutine>(
181 new sol::coroutine(
182 runnable.runner->state().
183 traverse_get<sol::function>(
184 table,
185 event)));
186
187 if (!*runnable.callable)
188 {
189 throw std::runtime_error("Error running script");
190 }
191
192 auto result = (*runnable.callable)(
193 script_entity(entity),
194 std::forward<Args>(args)...);
195
196 if (!result.valid())
197 {
198 sol::error e = result;
199 throw std::runtime_error(e.what());
200 }
201
202 if (*runnable.callable)
203 {
204 return { script };
205 } else {
206 killScript(script);
207
208 return {};
209 }
210}
211
212void ScriptingSystem::startBehavior(id_type entity)
213{
214 auto& automatable = game_.getEntityManager().
215 getComponent<AutomatableComponent>(entity);
216
217 sol::optional<id_type> script =
218 runScript(
219 automatable.table,
220 "Behavior",
221 entity);
222
223 if (script)
224 {
225 automatable.script = *script;
226 automatable.running = true;
227
228 auto& runnable = game_.getEntityManager().
229 getComponent<RunnableComponent>(automatable.script);
230
231 runnable.behavior = true;
232 runnable.actor = entity;
233 }
234}
235
236void ScriptingSystem::stopBehavior(id_type entity)
237{
238 auto& automatable = game_.getEntityManager().
239 getComponent<AutomatableComponent>(entity);
240
241 if (automatable.running)
242 {
243 killScript(automatable.script);
244 }
245}
246
247void ScriptingSystem::onTouch(id_type entity, id_type player)
248{
249 auto& prototypable = game_.getEntityManager().
250 getComponent<PrototypableComponent>(entity);
251
252 runScript(
253 prototypable.prototypeId,
254 "OnTouch",
255 entity,
256 script_entity(player));
257}