14static bool startsWith(std::string_view str, std::string_view needle) {
15 if(needle.size()>str.size())
17 for(
size_t i=0; i<needle.size(); ++i) {
18 int n = std::tolower(needle[i]);
19 int s = std::tolower(str [i]);
27 if(sa.size()!=sb.size())
29 for(
size_t i=0; i<sa.size(); ++i) {
30 int a = std::tolower(sa[i]);
31 int b = std::tolower(sb[i]);
40 auto err = std::from_chars(str.data(), str.data()+str.size(),t).ec;
47 t = std::stof(std::string(str));
59 cmd = std::vector<Cmd>{
63 {
"set var %v %s", C_SetVar},
66 {
"play ani %s", C_PlayAni},
67 {
"play faceani %s", C_Invalid},
68 {
"remove overlaymds %s", C_Invalid},
69 {
"toggle aniinfo", C_Invalid},
70 {
"zoverlaymds apply", C_Invalid},
71 {
"zoverlaymds remove", C_Invalid},
72 {
"zstartani %s %s", C_Invalid},
73 {
"ztoggle modelskeleton", C_Invalid},
74 {
"ztoggle rootsmoothnode", C_Invalid},
75 {
"ztoggle vobmorph", C_Invalid},
78 {
"set clipfactor %d", C_Invalid},
79 {
"toggle frame", C_ToggleFrame},
80 {
"zfogzone", C_Invalid},
81 {
"zhighqualityrender", C_Invalid},
83 {
"zprogmeshlod", C_Invalid},
84 {
"zrmode flat", C_Invalid},
85 {
"zrmode mat", C_Invalid},
86 {
"zrmode wire", C_Invalid},
87 {
"zrmode wmat", C_Invalid},
88 {
"zset levelclipscaler %f", C_Invalid},
89 {
"zset nearclipz %f", C_Invalid},
90 {
"zset vobfarclipscaler %f", C_Invalid},
91 {
"ztoggle ambientvobs", C_Invalid},
92 {
"ztoggle flushambientcol", C_Invalid},
93 {
"ztoggle lightstat", C_Invalid},
94 {
"ztoggle markpmeshmaterials", C_Invalid},
95 {
"ztoggle matmorph", C_Invalid},
96 {
"ztoggle renderorder", C_Invalid},
97 {
"ztoggle renderportals", C_Invalid},
98 {
"ztoggle rendervob", C_Invalid},
99 {
"ztoggle showportals", C_Invalid},
100 {
"ztoggle showtraceray", C_Invalid},
101 {
"ztoggle tnl", C_Invalid},
102 {
"ztoggle vobbox", C_Invalid},
103 {
"zvideores %d %d %d", C_Invalid},
108 {
"load game", C_Invalid},
109 {
"save game", C_Invalid},
110 {
"save zen", C_Invalid},
111 {
"set time %d %d", C_SetTime},
112 {
"spawnmass %d", C_Invalid},
113 {
"spawnmass giga %d", C_Invalid},
114 {
"toggle desktop", C_ToggleDesktop},
115 {
"toggle freepoints", C_Invalid},
116 {
"toggle screen", C_Invalid},
117 {
"toggle time", C_ToggleTime},
118 {
"toggle wayboxes", C_Invalid},
119 {
"toggle waynet", C_Invalid},
120 {
"version", C_Invalid},
121 {
"zstartrain", C_Invalid},
122 {
"zstartsnow", C_Invalid},
123 {
"ztimer multiplyer %f", C_TimeMultiplyer},
124 {
"ztimer realtime", C_TimeRealtime},
125 {
"ztoggle helpervisuals", C_Invalid},
126 {
"ztoggle showzones", C_Invalid},
127 {
"ztrigger %s", C_ZTrigger},
128 {
"zuntrigger %s", C_ZUntrigger},
130 {
"cheat full", C_CheatFull},
131 {
"cheat god", C_CheatGod},
134 {
"aigoto %s", C_AiGoTo},
135 {
"goto waypoint %s", C_GoToWayPoint},
136 {
"goto pos %f %f %f", C_GoToPos},
137 {
"goto vob %c %d", C_GoToVob},
138 {
"goto camera", C_GoToCamera},
140 {
"camera autoswitch", C_CamAutoswitch},
141 {
"camera mode", C_CamMode},
142 {
"toggle camdebug", C_ToggleCamDebug},
143 {
"toggle camera", C_ToggleCamera},
144 {
"toggle inertiatarget", C_ToggleInertia},
145 {
"ztoggle timedemo", C_ZToggleTimeDemo},
146 {
"insert %c", C_Insert},
148 {
"toggle gi", C_ToggleGI},
149 {
"toggle vsm", C_ToggleVsm},
150 {
"toggle rtsm", C_ToggleRtsm},
154Marvin::CmdVal Marvin::isMatch(std::string_view inp,
const Cmd& cmd)
const {
155 std::string_view ref = cmd.cmd;
156 CmdVal ret = C_Invalid;
159 while(!ref.empty()) {
160 size_t wr = ref.find(
' ');
161 if(wr==std::string_view::npos)
163 size_t wi = inp.find(
' ');
164 if(wi==std::string_view::npos)
167 auto wref = ref.substr(0,wr);
168 auto winp = inp.substr(0,wi);
170 bool fullword =
true;
172 wref = completeInstanceName(winp,fullword);
174 wref = completeInstanceName(winp,fullword);
177 else if(wref==
"%f" || wref==
"%d")
184 ret.cmd.type = C_Incomplete;
185 ret.complete = wref.substr(winp.size());
186 ret.fullword = fullword;
190 if(ref[0]==
'%' && argc<4) {
191 ret.argv[argc] = wref;
196 if(inp.size()!=winp.size())
204 ref = ref.substr(wr+1);
205 inp = inp.substr(std::min(wi+1,inp.size()));
206 while(inp.size()>0 && inp[0]==
' ')
214Marvin::CmdVal Marvin::recognize(std::string_view inp) {
215 while(inp.size()>0 && inp.back()==
' ')
216 inp = inp.substr(0,inp.size()-1);
217 while(inp.size()>0 && inp[0]==
' ')
223 CmdVal suggestion = C_Invalid;
226 auto m = isMatch(inp,i);
227 if(m.cmd.type==C_Invalid)
229 if(m.cmd.type!=C_Incomplete)
231 if(suggestion.cmd.type==C_Incomplete) {
232 if(suggestion.cmd.cmd!=m.cmd.cmd && suggestion.complete!=m.complete)
244 auto ret = recognize(v);
245 if(ret.cmd.type==C_Incomplete && !ret.complete.empty()) {
246 for(
auto& i:ret.complete)
256 auto ret = recognize(v);
257 switch(ret.cmd.type) {
283 if(player==
nullptr || player->
target()==
nullptr)
285 auto target = player->
target();
292 if(world==
nullptr || player==
nullptr || !player->
setInteraction(
nullptr))
294 auto wpoint = world->
findPoint(ret.argv[0]);
305 for(
int i=0; i<3; ++i) {
309 player->
setPosition(
float(c[0]),
float(c[1]),
float(c[2]));
314 case C_GoToWayPoint: {
317 if(world==
nullptr || player==
nullptr || !player->
setInteraction(
nullptr))
319 auto wpoint = world->
findPoint(ret.argv[0]);
331 if(world==
nullptr || c==
nullptr || player==
nullptr)
334 if(!ret.argv[1].empty() && !
fromString(ret.argv[1], n)) {
337 return goToVob(*world,*player,*c,ret.argv[0],--n);
342 if(c==
nullptr || player==
nullptr)
344 auto pos = c->destPosition();
358 case C_TimeMultiplyer: {
363 mul = std::max(mul, 0.f);
364 g->setTimeMultiplyer(mul);
369 case C_TimeRealtime:{
371 g->setTimeMultiplyer(1);
376 case C_CamAutoswitch:
380 case C_ToggleCamDebug:
384 case C_ToggleCamera: {
386 c->setToggleEnable(!c->isToggleEnabled());
389 case C_ToggleInertia: {
391 c->setInertiaTargetEnable(!c->isInertiaTargetEnabled());
394 case C_ZToggleTimeDemo: {
402 case C_ToggleDesktop: {
425 if(world==
nullptr || player==
nullptr)
427 return addItemOrNpcBySymbolName(world, ret.argv[0], player->
position());
433 return setTime(*world, ret.argv[0], ret.argv[1]);
439 return printVariable(world, ret.argv[0]);
445 if(world==
nullptr || player==
nullptr)
447 return setVariable(world, ret.argv[0], ret.argv[1]);
471bool Marvin::addItemOrNpcBySymbolName(
World* world, std::string_view name,
const Tempest::Vec3& at) {
472 auto& sc = world->
script();
477 auto* sym = sc.findSymbol(
id);
478 if(sym==
nullptr || sym->parent()==uint32_t(-1))
481 if(sym->type()!=zenkit::DaedalusDataType::INSTANCE || sym->address()==0)
484 const auto* cls = sym;
485 while(cls!=
nullptr && cls->parent()!=uint32_t(-1)) {
486 cls = sc.findSymbol(cls->parent());
492 if(cls->name()==
"C_NPC")
493 return (world->
addNpc(
id, at)!=
nullptr);
494 if(cls->name()==
"C_ITEM")
495 return (world->
addItem(
id, at)!=
nullptr);
499bool Marvin::printVariable(
World* world, std::string_view name) {
501 auto& sc = world->
script();
505 switch(sym->type()) {
506 case zenkit::DaedalusDataType::INT:
509 case zenkit::DaedalusDataType::FLOAT:
510 buf =
string_frm(name,
" = ",sym->get_float(0));
512 case zenkit::DaedalusDataType::STRING:
513 buf =
string_frm(name,
" = ",sym->get_string(0));
515 case zenkit::DaedalusDataType::INSTANCE:
516 buf =
string_frm(name,
" = ",sym->get_instance().get());
525bool Marvin::setVariable(
World* world, std::string_view name, std::string_view value) {
526 auto& sc = world->
script();
530 switch(sym->type()) {
531 case zenkit::DaedalusDataType::INT: {
535 sym->set_int(valueI);
538 case zenkit::DaedalusDataType::FLOAT: {
542 sym->set_float(valueF);
545 case zenkit::DaedalusDataType::STRING:
546 sym->set_string(value);
548 case zenkit::DaedalusDataType::INSTANCE:
549 print(
"unable to override instance variable");
554 printVariable(world, name);
558bool Marvin::setTime(
World& world, std::string_view hh, std::string_view mm) {
561 auto err = std::from_chars(hh.data(), hh.data()+hh.size(), hv, 10).ec;
565 err = std::from_chars(mm.data(), mm.data()+mm.size(), mv, 10).ec;
566 if(err!=std::errc()) {
570 if(hv<0 || hv>=24 || mv<0 || mv>=60)
577bool Marvin::goToVob(
World& world,
Npc& player,
Camera& c, std::string_view name,
size_t n) {
578 auto& sc = world.
script();
585 pos = npc->position();
587 pos = it->position();
599std::string_view Marvin::completeInstanceName(std::string_view inp,
bool& fullword)
const {
601 if(world==
nullptr || inp.size()==0)
604 auto& sc = world->
script();
605 std::string_view match =
"";
606 for(
size_t i=0; i<sc.symbolsCount(); ++i) {
608 auto name = std::string_view(sym->name());
617 if(name.size()>match.size())
618 name = name.substr(0,match.size());
619 for(
size_t i=0; i<name.size(); ++i) {
620 int n = std::tolower(name [i]);
621 int m = std::tolower(match[i]);
623 name = name.substr(0,i);
static AiAction aiGoToPoint(const WayPoint &to)
size_t findSymbolIndex(std::string_view s)
zenkit::DaedalusSymbol * findSymbol(std::string_view s)
Tempest::Signal< void(std::string_view, int, int, int, const GthFont &)> onPrintScreen
const World * world() const
Tempest::Signal< void()> toggleGi
Tempest::Signal< void()> toggleVsm
Tempest::Signal< void()> toggleRtsm
bool exec(std::string_view v)
Tempest::Signal< void(std::string_view)> print
bool autoComplete(std::string &v)
auto playAnimByName(std::string_view name, BodyState bs) -> const Animation::Sequence *
void aiPush(AiQueue::AiAction &&a)
bool setPosition(float x, float y, float z)
auto position() const -> Tempest::Vec3
void changeAttribute(Attribute a, int32_t val, bool allowUnconscious)
bool setInteraction(Interactive *id, bool quick=false)
static const GthFont & font(const float scale)
void triggerEvent(const TriggerEvent &e)
uint64_t tickCount() const
Npc * addNpc(std::string_view name, std::string_view at)
const WayPoint * findPoint(std::string_view name, bool inexact=true) const
Npc * findNpcByInstance(size_t instance, size_t n=0)
Item * addItem(size_t itemInstance, std::string_view at)
void setDayTime(int32_t h, int32_t min)
Item * findItemByInstance(size_t instance, size_t n=0)
GameScript & script() const
static bool compareNoCase(std::string_view sa, std::string_view sb)
static bool startsWith(std::string_view str, std::string_view needle)
static bool fromString(std::string_view str, T &t)