Peoplemon  0.1.0
Peoplemon 3 game source documentation
BaseFunctions.cpp
Go to the documentation of this file.
2 
3 #include <BLIB/Events/EventWaiter.hpp>
4 #include <BLIB/Scripts.hpp>
5 #include <BLIB/Util/Waiter.hpp>
8 #include <Core/Events/Maps.hpp>
11 #include <Core/Events/Store.hpp>
12 #include <Core/Items/Item.hpp>
14 #include <Core/Properties.hpp>
15 #include <Core/Systems/Systems.hpp>
16 
17 namespace core
18 {
19 namespace script
20 {
21 using bl::script::Error;
22 using bl::script::Function;
23 using bl::script::PrimitiveValue;
24 using bl::script::SymbolTable;
25 using bl::script::Value;
26 
27 namespace
28 {
29 constexpr PrimitiveValue::Type EntryTypes =
30  static_cast<PrimitiveValue::Type>(0xFF ^ (PrimitiveValue::TFunction | PrimitiveValue::TVoid));
31 
32 typedef void (*Builtin)(system::Systems& systems, SymbolTable& table,
33  const std::vector<Value>& args, Value& result);
34 
35 void getPlayer(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
36  Value& result);
37 void giveItem(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
38  Value& result);
39 void giveMoney(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
40  Value& result);
41 void takeItem(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
42  Value& result);
43 void takeMoney(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
44  Value& result);
45 void givePeoplemon(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
46  Value& result);
47 void takePeoplemon(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
48  Value& result);
49 void whiteout(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
50  Value& result);
51 void restorePeoplemon(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
52  Value& result);
53 
54 void displayMessage(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
55  Value& result);
56 void promptPlayer(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
57  Value& result);
58 void rollCredits(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
59  Value& result);
60 void openStorage(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
61  Value& result);
62 
63 void pricedItem(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
64  Value& result);
65 void sellPriceOverride(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
66  Value& result);
67 void openStore(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
68  Value& result);
69 
70 void getNpc(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
71  Value& result);
72 void getTrainer(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
73  Value& result);
74 void loadCharacter(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
75  Value& result);
76 void spawnCharacter(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
77  Value& result);
78 
79 void spawnGenericEntity(system::Systems& systems, SymbolTable& table,
80  const std::vector<Value>& args, Value& result);
81 void spawnAnimation(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
82  Value& result);
83 void triggerEntityAnimation(system::Systems& systems, SymbolTable& table,
84  const std::vector<Value>& args, Value& result);
85 
86 void moveEntity(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
87  Value& result);
88 void rotateEntity(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
89  Value& result);
90 void faceEntity(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
91  Value& result);
92 void faceDirection(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
93  Value& result);
94 void removeEntity(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
95  Value& result);
96 void entityToPosition(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
97  Value& result);
98 void entityInteract(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
99  Value& result);
100 void setEntityLock(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
101  Value& result);
102 void resetEntityLock(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
103  Value& result);
104 
105 void makeTime(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
106  Value& result);
107 void getClock(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
108  Value& result);
109 void waitUntilTime(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
110  Value& result);
111 void runAtClockTime(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
112  Value& result);
113 
114 void addSaveEntry(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
115  Value& result);
116 void getSaveEntry(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
117  Value& result);
118 void checkConvFlag(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
119  Value& result);
120 void setConvFlag(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
121  Value& result);
122 
123 void loadMap(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
124  Value& result);
125 void setAmbientLight(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
126  Value& result);
127 void createLight(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
128  Value& result);
129 void updateLight(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
130  Value& result);
131 void removeLight(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
132  Value& result);
133 void visitTown(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
134  Value& result);
135 
136 void clearWeather(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
137  Value& result);
138 void makeRain(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
139  Value& result);
140 void makeSnow(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
141  Value& result);
142 void makeSunny(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
143  Value& result);
144 void makeSandstorm(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
145  Value& result);
146 void makeFog(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
147  Value& result);
148 void makeRandomRain(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
149  Value& result);
150 void makeRandomSnow(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
151  Value& result);
152 void makeRandomDesert(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
153  Value& result);
154 void makeRandomWeather(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
155  Value& result);
156 void getCurrentWeather(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
157  Value& result);
158 
159 Value bind(system::Systems& systems, Builtin func) {
160  return {Function([&systems, func](SymbolTable& table,
161  const std::vector<Value>& args,
162  Value& result) { (*func)(systems, table, args, result); })};
163 }
164 
165 } // namespace
166 
167 void BaseFunctions::addDefaults(SymbolTable& table, system::Systems& systems) {
168 #define BUILTIN(function) table.set(#function, bind(systems, &function))
169 
170  BUILTIN(getPlayer);
171 
172  BUILTIN(giveItem);
173  BUILTIN(giveMoney);
174  BUILTIN(takeItem);
175  BUILTIN(takeMoney);
176  BUILTIN(givePeoplemon);
177  BUILTIN(takePeoplemon);
178  BUILTIN(whiteout);
179  BUILTIN(restorePeoplemon);
180 
181  BUILTIN(displayMessage);
182  BUILTIN(promptPlayer);
183  BUILTIN(rollCredits);
184  BUILTIN(openStorage);
185 
186  BUILTIN(pricedItem);
187  BUILTIN(sellPriceOverride);
188  BUILTIN(openStore);
189 
190  BUILTIN(getNpc);
191  BUILTIN(getTrainer);
192  BUILTIN(loadCharacter);
193  BUILTIN(spawnCharacter);
194 
195  BUILTIN(moveEntity);
196  BUILTIN(rotateEntity);
197  BUILTIN(faceEntity);
198  BUILTIN(faceDirection);
199  BUILTIN(removeEntity);
200  BUILTIN(entityToPosition);
201  BUILTIN(entityInteract);
202  BUILTIN(setEntityLock);
203  BUILTIN(resetEntityLock);
204  BUILTIN(spawnGenericEntity);
205  BUILTIN(spawnAnimation);
206  BUILTIN(triggerEntityAnimation);
207 
208  BUILTIN(makeTime);
209  BUILTIN(getClock);
210  BUILTIN(waitUntilTime);
211  BUILTIN(runAtClockTime);
212 
213  BUILTIN(addSaveEntry);
214  BUILTIN(getSaveEntry);
215  BUILTIN(checkConvFlag);
216  BUILTIN(setConvFlag);
217 
218  BUILTIN(loadMap);
219  BUILTIN(setAmbientLight);
220  BUILTIN(createLight);
221  BUILTIN(updateLight);
222  BUILTIN(removeLight);
223  BUILTIN(visitTown);
224 
225  BUILTIN(clearWeather);
226  BUILTIN(makeRain);
227  BUILTIN(makeSnow);
228  BUILTIN(makeSunny);
229  BUILTIN(makeSandstorm);
230  BUILTIN(makeFog);
231  BUILTIN(makeRandomRain);
232  BUILTIN(makeRandomSnow);
233  BUILTIN(makeRandomDesert);
234  BUILTIN(makeRandomWeather);
235  BUILTIN(getCurrentWeather);
236 
237 #undef BUILTIN
238 }
239 
240 Value BaseFunctions::makePosition(const bl::tmap::Position& pos) {
241  Value value;
242  Value coord;
243  coord.setProperty("x", {pos.position.x});
244  coord.setProperty("y", {pos.position.y});
245  value.setProperty("tiles", coord);
246  coord.setProperty("x", {pos.getWorldPosition(Properties::PixelsPerTile()).x});
247  coord.setProperty("y", {pos.getWorldPosition(Properties::PixelsPerTile()).y});
248  value.setProperty("pixels", coord);
249  value.setProperty("level", {pos.level});
250  value.setProperty("direction", {bl::tmap::directionToString(pos.direction)});
251  return value;
252 }
253 
254 namespace
255 {
256 Value makePosition(system::Systems& systems, bl::ecs::Entity e) {
257  const bl::tmap::Position* pos = systems.engine().ecs().getComponent<bl::tmap::Position>(e);
258  if (pos) { return BaseFunctions::makePosition(*pos); }
259  BL_LOG_WARN << "Entity " << e << " has no position";
260  return {};
261 }
262 
263 void getPlayer(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value& player) {
264  player = systems.player().player();
265  player.setProperty("name", {systems.player().state().name});
266  player.setProperty("gender",
267  {systems.player().state().sex == player::Gender::Boy ? "boy" : "girl"});
268  player.setProperty("money", {systems.player().state().monei});
269  player.setProperty("position", makePosition(systems, systems.player().player()));
270 
271  std::vector<player::Bag::Item> items;
272  systems.player().state().bag.getAll(items);
273  player.setProperty("bag", {bl::script::ArrayValue{}});
274  auto& bag = player.getProperty("bag", false).deref().value().getAsArray();
275  bag.reserve(items.size());
276  for (const player::Bag::Item& item : items) {
277  bag.emplace_back(item.id);
278  bag.back().setProperty("id", {item.id});
279  bag.back().setProperty("name", {item::Item::getName(item.id)});
280  bag.back().setProperty("qty", {item.qty});
281  }
282 }
283 
284 void giveItem(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
285  Value&) {
286  Value::validateArgs<PrimitiveValue::TInteger,
287  PrimitiveValue::TInteger,
288  PrimitiveValue::TBool,
289  PrimitiveValue::TBool>("giveItem", args);
290 
291  const unsigned int rawId = static_cast<unsigned int>(args[0].value().getAsInt());
292  const item::Id item = item::Item::cast(rawId);
293  if (item != item::Id::Unknown) {
294  const long qty = args[1].value().getAsInt();
295  if (qty > 0) {
296  systems.player().state().bag.addItem(item, qty);
297  if (args[2].value().getAsBool()) {
298  bl::util::Waiter waiter;
299  system::HUD::Callback unlock = [](const std::string&) {};
300  if (args[3].value().getAsBool())
301  unlock = [&waiter](const std::string&) { waiter.unblock(); };
302 
303  const std::string msg = qty > 1 ? ("Received " + std::to_string(qty) + " " +
304  item::Item::getName(item) + "s") :
305  ("Received a " + item::Item::getName(item));
306  systems.hud().displayMessage(msg, unlock);
307  if (args[3].value().getAsBool()) table.waitOn(waiter);
308  }
309  }
310  else { BL_LOG_WARN << "qty must be a positive integer"; }
311  }
312  else { BL_LOG_WARN << "Unknown item id: " << rawId; }
313 }
314 
315 void giveMoney(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
316  Value&) {
317  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TBool, PrimitiveValue::TBool>(
318  "giveMoney", args);
319 
320  const long money = args[0].value().getAsInt();
321  if (money > 0) {
322  systems.player().state().monei += money;
323  if (args[1].value().getAsBool()) {
324  bl::util::Waiter waiter;
325  system::HUD::Callback unlock = [](const std::string&) {};
326  if (args[2].value().getAsBool())
327  unlock = [&waiter](const std::string&) { waiter.unblock(); };
328 
329  const std::string msg = "Received " + std::to_string(money) + " monies";
330  systems.hud().displayMessage(msg, unlock);
331  if (args[2].value().getAsBool()) table.waitOn(waiter);
332  }
333  }
334  else { BL_LOG_WARN << "qty must be a positive integer"; }
335 }
336 
337 void takeItem(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
338  Value& result) {
339  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger, PrimitiveValue::TBool>(
340  "takeItem", args);
341 
342  const unsigned int rawId = static_cast<unsigned int>(args[0].value().getAsInt());
343  const item::Id item = item::Item::cast(rawId);
344  if (item != item::Id::Unknown) {
345  const long qty = args[1].value().getAsInt();
346  if (qty > 0) {
347  if (args[2].value().getAsBool()) {
348  bl::util::Waiter waiter;
349  std::string choice;
350  system::HUD::Callback unlock = [&waiter, &choice](const std::string& c) {
351  choice = c;
352  waiter.unblock();
353  };
354 
355  const std::string msg =
356  qty > 1 ?
357  ("Give " + std::to_string(qty) + " " + item::Item::getName(item) + "s?") :
358  ("Give the " + item::Item::getName(item) + "?");
359  systems.hud().promptUser(msg, {"Yes", "No"}, unlock);
360  table.waitOn(waiter);
361  if (choice == "No") { result = false; }
362  }
363  else { result = systems.player().state().bag.removeItem(item, qty); }
364  }
365  else {
366  BL_LOG_WARN << "qty must be a positive integer";
367  result = false;
368  }
369  }
370  else {
371  BL_LOG_WARN << "Unknown item id: " << rawId;
372  result = false;
373  }
374 }
375 
376 void takeMoney(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
377  Value& result) {
378  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TBool>("takeMoney", args);
379 
380  const long qty = args[0].value().getAsInt();
381  if (qty > 0) {
382  if (args[1].value().getAsBool()) {
383  bl::util::Waiter waiter;
384  std::string choice;
385  system::HUD::Callback unlock = [&waiter, &choice](const std::string& c) {
386  choice = c;
387  waiter.unblock();
388  };
389 
390  const std::string msg = "Give " + std::to_string(qty) + " monies?";
391  systems.hud().promptUser(msg, {"Yes", "No"}, unlock);
392  table.waitOn(waiter);
393  if (choice == "No") { result = false; }
394  }
395  if (systems.player().state().monei >= qty) {
396  systems.player().state().monei -= qty;
397  result = true;
398  }
399  else { result = false; }
400  }
401  else {
402  BL_LOG_WARN << "qty must be a positive integer";
403  result = false;
404  }
405 }
406 
407 void givePeoplemon(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
408  Value& result) {
409  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("givePeoplemon", args);
410 
411  const pplmn::Id id = pplmn::Peoplemon::cast(args[0].value().getAsInt());
412  if (id == pplmn::Id::Unknown) {
413  BL_LOG_ERROR << "Bad peoplemon id: " << args[0].value().getAsInt();
414  result = "fail";
415  return;
416  }
417 
418  if (systems.player().state().peoplemon.size() < 6) {
419  systems.player().state().peoplemon.emplace_back(id, args[1].value().getAsInt());
420  result = "party";
421  }
422  else {
423  systems.player().state().storage.add(
424  {id, static_cast<unsigned int>(args[1].value().getAsInt())});
425  result = "storage";
426  }
427  systems.player().state().peopledex.registerSighting(
428  id, systems.world().activeMap().getLocationName(systems.player().position()));
429 
430  result = false;
431 }
432 
433 void takePeoplemon(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
434  Value& result) {
435  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("takePeoplemon", args);
436 
437  const pplmn::Id id = pplmn::Peoplemon::cast(args[0].value().getAsInt());
438  if (id == pplmn::Id::Unknown) {
439  BL_LOG_ERROR << "Bad peoplemon id: " << args[0].value().getAsInt();
440  result = false;
441  return;
442  }
443 
444  const unsigned int level = args[1].value().getAsInt();
445  for (auto it = systems.player().state().peoplemon.begin();
446  it != systems.player().state().peoplemon.end();
447  ++it) {
448  if (it->id() == id && it->currentLevel() >= level) {
449  result = true;
450  systems.player().state().peoplemon.erase(it);
451  return;
452  }
453  }
454 
455  result = false;
456 }
457 
458 void whiteout(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value& result) {
459  systems.player().whiteout();
460  result = true;
461 }
462 
463 void restorePeoplemon(system::Systems& systems, SymbolTable&, const std::vector<Value>&,
464  Value& result) {
465  systems.player().state().healPeoplemon();
466  result = true;
467 }
468 
469 void displayMessage(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
470  Value&) {
471  Value::validateArgs<PrimitiveValue::TString, PrimitiveValue::TBool>("displayMessage", args);
472 
473  bl::util::Waiter waiter;
474  system::HUD::Callback unlock = [](const std::string&) {};
475  if (args[1].value().getAsBool()) unlock = [&waiter](const std::string&) { waiter.unblock(); };
476 
477  systems.hud().displayMessage(args[0].value().getAsString(), unlock);
478  if (args[1].value().getAsBool()) table.waitOn(waiter);
479 }
480 
481 void promptPlayer(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
482  Value& result) {
483  Value::validateArgs<PrimitiveValue::TString, PrimitiveValue::TArray>("promptPlayer", args);
484 
485  const auto& rawChoices = args[1].value().getAsArray();
486  std::vector<std::string> choices;
487  choices.reserve(rawChoices.size());
488  for (const Value& val : rawChoices) {
489  if (val.value().getType() != PrimitiveValue::TString) {
490  throw Error("All choices in promptPlayer() must be String type");
491  }
492  choices.emplace_back(val.value().getAsString());
493  }
494 
495  bl::util::Waiter waiter;
496  std::string choice;
497  const auto cb = [&waiter, &choice](const std::string& c) {
498  choice = c;
499  waiter.unblock();
500  };
501  systems.hud().promptUser(args[0].value().getAsString(), choices, cb);
502  table.waitOn(waiter);
503 
504  result = choice;
505 }
506 
507 void rollCredits(system::Systems&, SymbolTable&, const std::vector<Value>&, Value& result) {
508  // TODO - implement credits
509  result = false;
510 }
511 
512 void openStorage(system::Systems&, SymbolTable&, const std::vector<Value>& args, Value&) {
513  Value::validateArgs<PrimitiveValue::TBool>("openStorage", args);
514 
515  const bool block = args[0].value().getAsBool();
516  bl::event::Dispatcher::dispatch<event::StorageSystemOpened>({});
517  if (block) {
518  bl::event::EventWaiter<event::StorageSystemClosed> waiter;
519  waiter.wait();
520  }
521 }
522 
523 void pricedItem(system::Systems&, SymbolTable&, const std::vector<Value>& args, Value& result) {
524  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("pricedItem", args);
525  result = args[0];
526  result.setProperty("price", args[1]);
527 }
528 
529 void sellPriceOverride(system::Systems&, SymbolTable&, const std::vector<Value>& args,
530  Value& result) {
531  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("sellPriceOverride",
532  args);
533  result = args[0];
534  result.setProperty("price", args[1]);
535 }
536 
537 void openStore(system::Systems&, SymbolTable&, const std::vector<Value>& args, Value&) {
538  Value::validateArgs<PrimitiveValue::TArray, PrimitiveValue::TArray, PrimitiveValue::TBool>(
539  "openStore", args);
540 
541  std::vector<std::pair<item::Id, int>> items;
542  const bool block = args[2].value().getAsBool();
543  const auto& argItems = args[0].value().getAsArray();
544  items.reserve(argItems.size());
545  for (const auto& item : argItems) {
546  if (item.value().getType() != PrimitiveValue::TInteger) {
547  throw Error("openStore: Item list must be an array of integer ids");
548  }
549  const item::Id id = item::Item::cast(item.value().getAsInt());
550  if (id == item::Id::Unknown) {
551  throw Error("openStore: Invalid item id: " + std::to_string(item.value().getAsInt()));
552  }
553  const auto it = item.allProperties().find("price");
554  const auto getPrice = [it]() -> int {
555  const auto& pv = it->second.deref().value();
556  if (pv.getType() != PrimitiveValue::TInteger) {
557  throw Error("openStore: Item prices must be integer values");
558  }
559  return pv.getAsInt();
560  };
561  const int price = it == item.allProperties().end() ? item::Item::getValue(id) : getPrice();
562  items.emplace_back(id, price);
563  }
564 
565  std::vector<std::pair<item::Id, int>> sellPrices;
566  const auto& sellPriceArg = args[1].value().getAsArray();
567  sellPrices.reserve(sellPriceArg.size());
568  for (const auto& price : sellPriceArg) {
569  if (price.value().getType() != PrimitiveValue::TInteger) {
570  throw Error("openStore: Item list must be an array of integer ids");
571  }
572  const item::Id id = item::Item::cast(price.value().getAsInt());
573  if (id == item::Id::Unknown) {
574  throw Error("openStore: Invalid item id: " + std::to_string(price.value().getAsInt()));
575  }
576  const auto it = price.allProperties().find("price");
577  const auto getPrice = [it]() -> int {
578  const auto& pv = it->second.deref().value();
579  if (pv.getType() != PrimitiveValue::TInteger) {
580  throw Error("openStore: Item prices must be integer values");
581  }
582  return pv.getAsInt();
583  };
584  const int sp = it == price.allProperties().end() ? item::Item::getValue(id) : getPrice();
585  sellPrices.emplace_back(id, sp);
586  }
587 
588  bl::event::Dispatcher::dispatch<event::StoreOpened>({items, sellPrices});
589  if (block) {
590  bl::event::EventWaiter<event::StoreClosed> waiter;
591  waiter.wait();
592  }
593 }
594 
595 void getNpc(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value& npc) {
596  Value::validateArgs<PrimitiveValue::TString>("getNpc", args);
597 
598  const std::string name = args[0].value().getAsString();
599  bool found = false;
600  const auto visitor = [&name, &npc, &systems, &found](bl::ecs::Entity ent,
601  component::NPC& component) {
602  if (found) return;
603  bl::tmap::Position* pos = systems.engine().ecs().getComponent<bl::tmap::Position>(ent);
604  if (!pos) return;
605 
606  if (component.name() == name) {
607  npc = ent;
608  npc.setProperty("name", {name});
609  npc.setProperty("talkedTo", {systems.interaction().npcTalkedTo(name)});
610  npc.setProperty("defeated", {false});
611  npc.setProperty("position", BaseFunctions::makePosition(*pos));
612  found = true;
613  }
614  };
615 
616  systems.engine().ecs().getAllComponents<component::NPC>().forEach(visitor);
617  if (!found) { npc = false; }
618 }
619 
620 void loadCharacter(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
621  Value& character) {
622  Value::validateArgs<PrimitiveValue::TInteger>("loadCharacter", args);
623 
624  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
625  if (systems.engine().ecs().entityExists(entity)) {
626  const bl::tmap::Position* pos =
627  systems.engine().ecs().getComponent<bl::tmap::Position>(entity);
628  if (pos) {
629  character = entity;
630  character.setProperty("position", BaseFunctions::makePosition(*pos));
631 
632  const component::NPC* npc = systems.engine().ecs().getComponent<component::NPC>(entity);
633  if (npc) {
634  character.setProperty("name", {npc->name()});
635  character.setProperty("talkedTo", {systems.interaction().npcTalkedTo(npc->name())});
636  character.setProperty("defeated", {false});
637  return;
638  }
639 
640  const component::Trainer* trainer =
641  systems.engine().ecs().getComponent<component::Trainer>(entity);
642  if (trainer) {
643  character.setProperty("name", {trainer->name()});
644  character.setProperty("talkedTo",
645  {systems.interaction().trainerTalkedto(trainer->name())});
646  character.setProperty("defeated", {systems.trainers().trainerDefeated(*trainer)});
647  return;
648  }
649  }
650  }
651 
652  character = false;
653 }
654 
655 void spawnCharacter(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
656  Value& result) {
657  Value::validateArgs<PrimitiveValue::TString,
658  PrimitiveValue::TInteger,
659  PrimitiveValue::TInteger,
660  PrimitiveValue::TInteger,
661  PrimitiveValue::TString>("spawnCharacter", args);
662 
663  const map::CharacterSpawn spawn(
664  bl::tmap::Position(args[1].value().getAsInt(),
665  {static_cast<int>(args[2].value().getAsInt()),
666  static_cast<int>(args[3].value().getAsInt())},
667  bl::tmap::directionFromString(args[4].value().getAsString())),
668  args[0].value().getAsString());
669  result = systems.entity().spawnCharacter(spawn, systems.world().activeMap());
670 }
671 
672 void getTrainer(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
673  Value& trainer) {
674  Value::validateArgs<PrimitiveValue::TString>("getTrainer", args);
675 
676  const std::string name = args[0].value().getAsString();
677 
678  bool found = false;
679  const auto visitor = [&systems, &found, &name, &trainer](bl::ecs::Entity ent,
680  component::Trainer& tc) {
681  if (found) return;
682  bl::tmap::Position* pos = systems.engine().ecs().getComponent<bl::tmap::Position>(ent);
683  if (!pos) return;
684  if (tc.name() == name) {
685  trainer = ent;
686  trainer.setProperty("name", {name});
687  trainer.setProperty("talkedTo", {systems.interaction().trainerTalkedto(name)});
688  trainer.setProperty("defeated", {systems.trainers().trainerDefeated(tc)});
689  trainer.setProperty("position", BaseFunctions::makePosition(*pos));
690  found = true;
691  }
692  };
693 
694  systems.engine().ecs().getAllComponents<component::Trainer>().forEach(visitor);
695  if (!found) { trainer = false; }
696 }
697 
698 void moveEntity(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
699  Value& res) {
700  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TString, PrimitiveValue::TBool>(
701  "moveEntity", args);
702 
703  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
704  const bl::tmap::Direction dir = bl::tmap::directionFromString(args[1].value().getAsString());
705  const bool block = args[2].value().getAsBool();
706  const bool result = systems.movement().moveEntity(entity, dir, false);
707 
708  if (block && result) {
709  const component::Movable* move =
710  systems.engine().ecs().getComponent<component::Movable>(entity);
711  if (move) {
712  float t = 0.f;
713  const float mtime =
715  while (move->moving()) {
716  sf::sleep(sf::milliseconds(10));
717  t += 0.01f;
718  if (t >= mtime) {
719  BL_LOG_WARN << "Blocking on moveEntity for entity " << entity
720  << " taking too long (" << t << "s), continuing";
721  break;
722  }
723  }
724  }
725  }
726 
727  res = result;
728 }
729 
730 void rotateEntity(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
731  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TString>("rotateEntity", args);
732 
733  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
734  const bl::tmap::Direction dir = bl::tmap::directionFromString(args[1].value().getAsString());
735  bl::tmap::Position* pos = systems.engine().ecs().getComponent<bl::tmap::Position>(entity);
736  if (pos && pos->direction != dir) pos->direction = dir;
737 }
738 
739 void faceEntity(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
740  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("faceEntity", args);
741 
742  const bl::ecs::Entity toSpin = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
743  const bl::ecs::Entity toFace = static_cast<bl::ecs::Entity>(args[1].value().getAsInt());
744  bl::tmap::Position* sp = systems.engine().ecs().getComponent<bl::tmap::Position>(toSpin);
745  bl::tmap::Position* fp = systems.engine().ecs().getComponent<bl::tmap::Position>(toSpin);
746 
747  if (sp && fp) {
748  const bl::tmap::Direction d = bl::tmap::Position::facePosition(*sp, *fp);
749  if (sp->direction != d) { systems.movement().moveEntity(toSpin, d, false); }
750  }
751  else { BL_LOG_ERROR << "Invalid entities. Tried to make " << toSpin << " face " << toFace; }
752 }
753 
754 void faceDirection(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
755  Value& result) {
756  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("faceDirection", args);
757 
758  const bl::ecs::Entity toSpin = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
759  const bl::ecs::Entity toFace = static_cast<bl::ecs::Entity>(args[1].value().getAsInt());
760  bl::tmap::Position* sp = systems.engine().ecs().getComponent<bl::tmap::Position>(toSpin);
761  bl::tmap::Position* fp = systems.engine().ecs().getComponent<bl::tmap::Position>(toSpin);
762 
763  if (sp && fp) {
764  const bl::tmap::Direction d = bl::tmap::Position::facePosition(*sp, *fp);
765  result = bl::tmap::directionToString(d);
766  }
767  else {
768  BL_LOG_ERROR << "Invalid entities. Tried to get direction from " << toSpin << " to "
769  << toFace;
770  result = "ERROR";
771  }
772 }
773 
774 void removeEntity(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
775  Value& res) {
776  Value::validateArgs<PrimitiveValue::TInteger>("removeEntity", args);
777 
778  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
779  if (entity != systems.player().player()) {
780  const bool result = systems.engine().ecs().entityExists(entity);
781  systems.engine().ecs().destroyEntity(entity);
782  res = result;
783  }
784  else { res = false; }
785 }
786 
787 void entityToPosition(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
788  Value& result) {
789  Value::validateArgs<PrimitiveValue::TInteger,
790  PrimitiveValue::TInteger,
791  PrimitiveValue::TInteger,
792  PrimitiveValue::TInteger,
793  PrimitiveValue::TString,
794  PrimitiveValue::TBool>("entityToPosition", args);
795 
796  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
797  const std::uint8_t level = args[1].value().getAsInt();
798  const glm::i32vec2 destTiles(args[2].value().getAsInt(), args[3].value().getAsInt());
799  const bl::tmap::Direction dir = bl::tmap::directionFromString(args[4].value().getAsString());
800  const bool block = args[5].value().getAsBool();
801  const bl::tmap::Position dest(level, destTiles, dir);
802  BL_LOG_INFO << "Moving entity " << entity << " to " << dest;
803 
804  if (!systems.ai().moveToPosition(entity, dest)) {
805  result = false;
806  BL_LOG_ERROR << "Failed to path find entity " << entity << "to " << dest;
807  result = false;
808  return;
809  }
810  result = true;
811 
812  if (block) {
813  bl::event::EventWaiter<event::PathFindCompleted> eventWaiter;
814 
815  while (!bl::util::Waiter::allUnblocked()) {
816  std::optional<event::PathFindCompleted> pathEvent = eventWaiter.wait();
817  if (pathEvent.has_value() && pathEvent.value().entity == entity) {
818  result = pathEvent.value().success;
819  break;
820  }
821  }
822  }
823 }
824 
825 void entityInteract(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
826  Value& result) {
827  Value::validateArgs<PrimitiveValue::TInteger>("entityInteract", args);
828 
829  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
830  result = systems.interaction().interact(entity);
831 }
832 
833 void setEntityLock(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
834  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TBool>("setEntityLock", args);
835 
836  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
837  const bool lock = args[1].value().getAsBool();
838  systems.controllable().setEntityLocked(entity, lock, true);
839 }
840 
841 void resetEntityLock(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
842  Value&) {
843  Value::validateArgs<PrimitiveValue::TInteger>("resetEntityLock", args);
844 
845  const bl::ecs::Entity entity = static_cast<bl::ecs::Entity>(args[0].value().getAsInt());
846  systems.controllable().resetEntityLock(entity);
847 }
848 
849 void spawnAnimation(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
850  Value& result) {
851  Value::validateArgs<PrimitiveValue::TInteger,
852  PrimitiveValue::TInteger,
853  PrimitiveValue::TInteger,
854  PrimitiveValue::TNumeric,
855  PrimitiveValue::TNumeric,
856  PrimitiveValue::TString>("spawnAnimation", args);
857 
858  const std::uint8_t level = args[0].value().getAsInt();
859  glm::vec2 pos{args[1].value().getNumAsFloat(), args[2].value().getNumAsFloat()};
860  glm::vec2 offset{args[3].value().getNumAsFloat(), args[4].value().getNumAsFloat()};
861  result = systems.entity().spawnAnimation(level,
862  pos * static_cast<float>(Properties::PixelsPerTile()) +
863  offset,
864  args[3].value().getAsString(),
865  systems.world().activeMap());
866 }
867 
868 void spawnGenericEntity(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
869  Value& result) {
870  Value::validateArgs<PrimitiveValue::TInteger,
871  PrimitiveValue::TInteger,
872  PrimitiveValue::TInteger,
873  PrimitiveValue::TString,
874  PrimitiveValue::TBool>("spawnGenericEntity", args);
875 
876  const std::uint8_t level = args[0].value().getAsInt();
877  const glm::i32vec2 pos{static_cast<int>(args[1].value().getAsInt()),
878  static_cast<int>(args[2].value().getAsInt())};
879  result = systems.entity().spawnGeneric(level,
880  pos,
881  args[4].value().getAsBool(),
882  args[3].value().getAsString(),
883  systems.world().activeMap());
884 }
885 
886 void triggerEntityAnimation(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
887  Value& result) {
888  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TBool, PrimitiveValue::TBool>(
889  "triggerEntityAnimation", args);
890 
891  const bl::ecs::Entity e = args[0].value().getAsInt();
892  component::Renderable* r = systems.engine().ecs().getComponent<component::Renderable>(e);
893 
894  if (!r) {
895  BL_LOG_WARN << "Could not trigger animation for invalid entity: " << e;
896  result = false;
897  return;
898  }
899 
900  const bool loop = args[1].value().getAsBool();
901  r->triggerAnim(loop);
902  if (args[2].value().getAsBool() && !loop) { sf::sleep(sf::seconds(r->animLength())); }
903  result = true;
904 }
905 
906 void getClock(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value& clock) {
907  const system::Clock::Time now = systems.clock().now();
908  clock = now.hour * 60 + now.minute;
909  clock.setProperty("minute", {now.minute});
910  clock.setProperty("hour", {now.hour});
911  clock.setProperty("day", {now.day});
912 }
913 
914 class ClockTrigger : public bl::event::Listener<event::TimeChange> {
915 public:
916  using Callback = std::function<void()>;
917  ClockTrigger(Callback cb, const system::Clock::Time& time)
918  : time(time)
919  , cb(cb) {}
920 
921  virtual void observe(const event::TimeChange& event) override {
922  if (event.newTime.hour == time.hour && event.newTime.minute == time.minute) cb();
923  }
924 
925 private:
926  const system::Clock::Time time;
927  const Callback cb;
928 };
929 
930 system::Clock::Time parseTime(const Value& val) {
931  system::Clock::Time t(12, 0, 0);
932  const PrimitiveValue& h = val.getProperty("hour", false).deref().value();
933  t.hour = static_cast<unsigned int>(h.getNumAsInt());
934  const PrimitiveValue& m = val.getProperty("minute", false).deref().value();
935  t.minute = static_cast<unsigned int>(m.getNumAsInt());
936  return t;
937 }
938 
939 void makeTime(system::Systems&, SymbolTable&, const std::vector<Value>& args, Value& time) {
940  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger>("makeTime", args);
941  if (args[0].value().getAsInt() < 0 || args[0].value().getAsInt() > 23)
942  throw Error("hour must be in range [0, 23]");
943  if (args[1].value().getAsInt() < 0 || args[1].value().getAsInt() > 59)
944  throw Error("minute must be in range [0, 59]");
945 
946  const unsigned int hour = static_cast<unsigned int>(args[0].value().getAsInt());
947  const unsigned int minute = static_cast<unsigned int>(args[1].value().getAsInt());
948  time = hour * 60 + minute;
949  time.setProperty("hour", {hour});
950  time.setProperty("minute", {minute});
951 }
952 
953 void waitUntilTime(system::Systems& systems, SymbolTable& table, const std::vector<Value>& args,
954  Value&) {
955  Value::validateArgs<PrimitiveValue::TAny, PrimitiveValue::TBool>("waitUntilTime", args);
956 
957  const system::Clock::Time now = systems.clock().now();
958  const system::Clock::Time then = parseTime(args[0]);
959  const unsigned int nts = now.hour * 60 + now.minute;
960  const unsigned int ets = then.hour * 60 + then.minute;
961  if (nts < ets || (nts != ets && args[1].value().getAsBool())) {
962  bl::util::Waiter waiter;
963  const auto unlock = [&waiter]() { waiter.unblock(); };
964  ClockTrigger trigger(unlock, then);
965  bl::event::ListenerGuard<event::TimeChange> guard(&trigger);
966  guard.subscribe();
967  table.waitOn(waiter);
968  }
969 }
970 
971 void runAtClockTime(system::Systems&, SymbolTable& table, const std::vector<Value>& args, Value&) {
972  Value::validateArgs<PrimitiveValue::TAny, PrimitiveValue::TInteger>("runAtClockTime", args);
973 
974  const std::string source = args[0].value().getAsString();
975  const system::Clock::Time time = parseTime(args[1]);
976 
977  // trick to avoid having to create a thread here. hacky but cleaner
978  const std::string program = "waitUntilTime(makeTime(" + std::to_string(time.hour) + ", " +
979  std::to_string(time.minute) + "), true);\nrun(\"" + source +
980  "\", false);";
981 
982  bl::script::Script script(program, table);
983  if (!script.valid()) throw Error("Syntax error in script passed to runAtClockTime()");
984  script.runBackground(table.manager());
985 }
986 
987 void addSaveEntry(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
988  Value& result) {
989  Value::validateArgs<PrimitiveValue::TString, EntryTypes>("addSaveEntry", args);
990  systems.scripts().setEntry(args[0].value().getAsString(), args[1].value());
991  result = true;
992 }
993 
994 void getSaveEntry(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
995  Value& result) {
996  Value::validateArgs<PrimitiveValue::TString>("getSaveEntry", args);
997  const Value* val = systems.scripts().getEntry(args[0].value().getAsString());
998  result = val ? *val : false;
999 }
1000 
1001 void loadMap(system::Systems&, SymbolTable&, const std::vector<Value>& args, Value&) {
1002  Value::validateArgs<PrimitiveValue::TString, PrimitiveValue::TInteger>("loadMap", args);
1003  bl::event::Dispatcher::dispatch<event::SwitchMapTriggered>(
1004  {args[0].value().getAsString(), static_cast<int>(args[1].value().getAsInt())});
1005 }
1006 
1007 void checkConvFlag(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
1008  Value& result) {
1009  Value::validateArgs<PrimitiveValue::TString>("checkConvFlag", args);
1010  result = systems.interaction().flagSet(args[0].value().getAsString());
1011 }
1012 
1013 void setConvFlag(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1014  Value::validateArgs<PrimitiveValue::TString>("setConvFlag", args);
1015  systems.interaction().setFlag(args[0].value().getAsString());
1016 }
1017 
1018 void setAmbientLight(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
1019  Value&) {
1020  Value::validateArgs<PrimitiveValue::TInteger, PrimitiveValue::TInteger, PrimitiveValue::TBool>(
1021  "setAmbientLight", args);
1022  if (args[0].value().getAsInt() < 0) { throw Error("Light level must be positive"); }
1023  if (args[0].value().getAsInt() > 255) { throw Error("Light level must be under 255"); }
1024 
1025  const std::uint8_t low = static_cast<std::uint8_t>(args[0].value().getAsInt());
1026  const std::uint8_t high = static_cast<std::uint8_t>(args[1].value().getAsInt());
1027  const bool sunlight = args[2].value().getAsBool();
1028  systems.world().activeMap().lightingSystem().setAmbientLevel(low, high);
1029  systems.world().activeMap().lightingSystem().adjustForSunlight(sunlight);
1030 }
1031 
1032 void createLight(system::Systems& systems, SymbolTable&, const std::vector<Value>& args,
1033  Value& result) {
1034  Value::validateArgs<PrimitiveValue::TNumeric,
1035  PrimitiveValue::TNumeric,
1036  PrimitiveValue::TNumeric>("createLight", args);
1037 
1038  const float x = args[0].value().getNumAsFloat();
1039  const float y = args[1].value().getNumAsFloat();
1040  const float r = args[2].value().getNumAsFloat();
1041 
1042  if (x < 0.f || x >= systems.world().activeMap().sizePixels().x) {
1043  throw Error("Light x coordinate is out of range: " + std::to_string(x));
1044  }
1045  if (y < 0.f || y >= systems.world().activeMap().sizePixels().y) {
1046  throw Error("Light y coordinate is out of range: " + std::to_string(y));
1047  }
1048  if (r < 0.f) { throw Error("Light radius must be positive"); }
1049 
1050  const bl::rc::lgt::Light2D handle =
1051  systems.world().activeMap().getSceneLighting().addLight({x, y}, r);
1052 
1053  result = handle.getId();
1054 }
1055 
1056 void updateLight(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1057  Value::validateArgs<PrimitiveValue::TInteger,
1058  PrimitiveValue::TNumeric,
1059  PrimitiveValue::TNumeric,
1060  PrimitiveValue::TNumeric>("updateLight", args);
1061 
1062  const std::uint32_t id = static_cast<std::uint32_t>(args[0].value().getAsInt());
1063  const float x = args[1].value().getNumAsFloat();
1064  const float y = args[2].value().getNumAsFloat();
1065  const float r = args[3].value().getNumAsFloat();
1066 
1067  if (x < 0.f || x >= systems.world().activeMap().sizePixels().x) {
1068  throw Error("Light x coordinate is out of range: " + std::to_string(x));
1069  }
1070  if (y < 0.f || y >= systems.world().activeMap().sizePixels().y) {
1071  throw Error("Light y coordinate is out of range: " + std::to_string(y));
1072  }
1073  if (r < 0.f) { throw Error("Light radius must be positive"); }
1074 
1075  bl::rc::lgt::Light2D light = systems.world().activeMap().getSceneLighting().getLight(id);
1076  if (!light.isValid()) {
1077  BL_LOG_ERROR << "Cannot update invalid light: " << id;
1078  return;
1079  }
1080  light.setPosition({x, y});
1081  light.setRadius(r);
1082 }
1083 
1084 void removeLight(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1085  Value::validateArgs<PrimitiveValue::TInteger>("removeLight", args);
1086  const std::uint32_t id = static_cast<std::uint32_t>(args[0].value().getAsInt());
1087  bl::rc::lgt::Light2D light = systems.world().activeMap().getSceneLighting().getLight(id);
1088  if (!light.isValid()) {
1089  BL_LOG_ERROR << "Cannot remove invalid light: " << id;
1090  return;
1091  }
1092  light.removeFromScene();
1093 }
1094 
1095 void visitTown(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1096  Value::validateArgs<PrimitiveValue::TString>("visitTown", args);
1097  systems.player().state().visitedTowns.emplace(args[0].value().getAsString());
1098 }
1099 
1100 void clearWeather(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1101  systems.world().activeMap().weatherSystem().set(map::Weather::None);
1102 }
1103 
1104 void makeRain(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1105  Value::validateArgs<PrimitiveValue::TBool, PrimitiveValue::TBool>("makeRain", args);
1106 
1108  if (args[0].value().getAsBool()) {
1109  if (args[1].value().getAsBool())
1111  else
1113  }
1114  else {
1115  if (args[1].value().getAsBool())
1117  else
1119  }
1120 
1121  systems.world().activeMap().weatherSystem().set(t);
1122 }
1123 
1124 void makeSnow(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1125  Value::validateArgs<PrimitiveValue::TBool, PrimitiveValue::TBool>("makeSnow", args);
1126 
1128  if (args[0].value().getAsBool()) {
1129  if (args[1].value().getAsBool())
1131  else
1133  }
1134  else {
1135  if (args[1].value().getAsBool())
1137  else
1139  }
1140 
1141  systems.world().activeMap().weatherSystem().set(t);
1142 }
1143 
1144 void makeSunny(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1145  systems.world().activeMap().weatherSystem().set(map::Weather::Sunny);
1146 }
1147 
1148 void makeSandstorm(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1149  systems.world().activeMap().weatherSystem().set(map::Weather::SandStorm);
1150 }
1151 
1152 void makeFog(system::Systems& systems, SymbolTable&, const std::vector<Value>& args, Value&) {
1153  Value::validateArgs<PrimitiveValue::TBool>("makeFog", args);
1154 
1155  const map::Weather::Type t =
1156  args[0].value().getAsBool() ? map::Weather::ThickFog : map::Weather::ThinFog;
1157  systems.world().activeMap().weatherSystem().set(t);
1158 }
1159 
1160 void makeRandomRain(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1161  systems.world().activeMap().weatherSystem().set(map::Weather::WaterRandom);
1162 }
1163 
1164 void makeRandomSnow(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1165  systems.world().activeMap().weatherSystem().set(map::Weather::SnowRandom);
1166 }
1167 
1168 void makeRandomDesert(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1169  systems.world().activeMap().weatherSystem().set(map::Weather::DesertRandom);
1170 }
1171 
1172 void makeRandomWeather(system::Systems& systems, SymbolTable&, const std::vector<Value>&, Value&) {
1173  systems.world().activeMap().weatherSystem().set(map::Weather::AllRandom);
1174 }
1175 
1176 void getCurrentWeather(system::Systems& systems, SymbolTable&, const std::vector<Value>&,
1177  Value& result) {
1178  using T = map::Weather::Type;
1179 
1180  switch (systems.world().activeMap().weatherSystem().getType()) {
1181  case T::LightRain:
1182  case T::LightRainThunder:
1183  case T::HardRain:
1184  case T::HardRainThunder:
1185  result = "rain";
1186  break;
1187  case T::LightSnow:
1188  case T::LightSnowThunder:
1189  case T::HardSnow:
1190  case T::HardSnowThunder:
1191  result = "snow";
1192  break;
1193  case T::ThinFog:
1194  case T::ThickFog:
1195  result = "fog";
1196  break;
1197  case T::Sunny:
1198  result = "sunny";
1199  break;
1200  case T::SandStorm:
1201  result = "sandstorm";
1202  break;
1203  default:
1204  result = "none";
1205  break;
1206  }
1207 }
1208 
1209 } // namespace
1210 
1211 } // namespace script
1212 } // namespace core
#define BUILTIN(function)
Type
The type classification of an item. This is used to determine when an item may be used and how to use...
Definition: Type.hpp:17
Id
Represents an item in its simplist form.
Definition: Id.hpp:24
Id
The id of a peoplemon.
Definition: Id.hpp:16
Core classes and functionality for both the editor and game.
static const std::string & getName(item::Id item)
Returns the name of the given item.
Definition: Item.cpp:91
static int getValue(item::Id item)
Returns the value of the given item.
Definition: Item.cpp:119
static Id cast(unsigned int id)
Helper function to cast a raw id to an item Id.
Definition: Item.cpp:31
Type
The type of weather.
Definition: Weather.hpp:38
@ HardSnowThunder
Hard snow with thunder.
Definition: Weather.hpp:67
@ Sunny
A very sunny day with pulsating light.
Definition: Weather.hpp:76
@ ThinFog
Thin fog covers the area.
Definition: Weather.hpp:70
@ SandStorm
A sandstorm ravages you.
Definition: Weather.hpp:79
@ HardRain
Hard rain with no thunder.
Definition: Weather.hpp:52
@ HardRainThunder
Hard rain with thunder.
Definition: Weather.hpp:55
@ LightRainThunder
Light rain with thunder.
Definition: Weather.hpp:49
@ None
No weather will occur.
Definition: Weather.hpp:40
@ WaterRandom
Periodically triggers one of LightRain, HardRain, LightRainThunder, HardRainThunder.
Definition: Weather.hpp:82
@ LightSnowThunder
Light snow with thunder.
Definition: Weather.hpp:61
@ LightRain
Light rain with no thunder.
Definition: Weather.hpp:46
@ SnowRandom
Periodically triggers one of LightSnow, HardSnow, LightSnowThunder, HardSnowThunder.
Definition: Weather.hpp:85
@ ThickFog
Thick fog obscures everything.
Definition: Weather.hpp:73
@ LightSnow
Light snow with no thunder.
Definition: Weather.hpp:58
@ DesertRandom
Periodically triggers one of Sunny, Sandstorm.
Definition: Weather.hpp:88
@ HardSnow
Hard snow with no thunder.
Definition: Weather.hpp:64
@ AllRandom
All types of weather may occur over time.
Definition: Weather.hpp:43
static Id cast(unsigned int id)
Casts an integer to a validated id. Returns Unknown if the id is invalid.
Definition: Peoplemon.cpp:112
static int PixelsPerTile()
Definition: Properties.cpp:279
static float CharacterMoveSpeed()
Definition: Properties.cpp:563
static bl::script::Value makePosition(const bl::tmap::Position &pos)
Helper function for other script functions to make script position values from the position component...
static void addDefaults(bl::script::SymbolTable &table, system::Systems &systems)
Adds the universal built-in functions to the given symbol table.
std::function< void(const std::string &value)> Callback
Signature for HUD callbacks. Used for both messages completing and choices made.
Definition: HUD.hpp:39
Owns all primary systems and a reference to the engine.
Definition: Systems.hpp:47
const bl::engine::Engine & engine() const
Const accessor for the Engine.
Definition: Systems.cpp:35