summaryrefslogtreecommitdiff
path: root/src/map/script.cpp
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-10-07 01:56:05 -0700
committerBen Longbons <b.r.longbons@gmail.com>2014-10-08 01:48:00 -0700
commit4763e230ab02bcf3e7db20dee23d42a02815bdb3 (patch)
tree34ccc612c212045e4d4ed38e8ccf94a7b15953d0 /src/map/script.cpp
parent0c2de8979105e6b5a24be18d3241a609f9bfed8f (diff)
downloadtmwa-4763e230ab02bcf3e7db20dee23d42a02815bdb3.tar.gz
tmwa-4763e230ab02bcf3e7db20dee23d42a02815bdb3.tar.bz2
tmwa-4763e230ab02bcf3e7db20dee23d42a02815bdb3.tar.xz
tmwa-4763e230ab02bcf3e7db20dee23d42a02815bdb3.zip
Split script.cpp
Diffstat (limited to 'src/map/script.cpp')
-rw-r--r--src/map/script.cpp5191
1 files changed, 0 insertions, 5191 deletions
diff --git a/src/map/script.cpp b/src/map/script.cpp
deleted file mode 100644
index 61233b8..0000000
--- a/src/map/script.cpp
+++ /dev/null
@@ -1,5191 +0,0 @@
-#include "script.hpp"
-// script.cpp - EAthena script frontend, engine, and library.
-//
-// Copyright © ????-2004 Athena Dev Teams
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011 Chuck Miller
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-// Copyright © 2013 wushin
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <cassert>
-#include <cmath>
-#include <cstdlib>
-#include <ctime>
-
-#include <algorithm>
-#include <set>
-
-#include "../compat/fun.hpp"
-
-#include "../strings/mstring.hpp"
-#include "../strings/rstring.hpp"
-#include "../strings/astring.hpp"
-#include "../strings/zstring.hpp"
-#include "../strings/xstring.hpp"
-#include "../strings/literal.hpp"
-
-#include "../generic/db.hpp"
-#include "../generic/intern-pool.hpp"
-#include "../generic/random.hpp"
-
-#include "../io/cxxstdio.hpp"
-#include "../io/cxxstdio_enums.hpp"
-#include "../io/lock.hpp"
-#include "../io/read.hpp"
-#include "../io/write.hpp"
-
-#include "../net/socket.hpp"
-#include "../net/timer.hpp"
-
-#include "../mmo/core.hpp"
-#include "../mmo/extract.hpp"
-#include "../mmo/human_time_diff.hpp"
-#include "../mmo/utils.hpp"
-
-#include "atcommand.hpp"
-#include "battle.hpp"
-#include "chrif.hpp"
-#include "clif.hpp"
-#include "intif.hpp"
-#include "itemdb.hpp"
-#include "magic-interpreter-base.hpp"
-#include "map.hpp"
-#include "mob.hpp"
-#include "npc.hpp"
-#include "party.hpp"
-#include "pc.hpp"
-#include "skill.hpp"
-#include "storage.hpp"
-
-#include "../poison.hpp"
-
-
-namespace tmwa
-{
-constexpr bool DEBUG_DISP = false;
-constexpr bool DEBUG_RUN = false;
-
-enum class VariableCode : uint8_t
-{
- PARAM,
- VARIABLE,
-};
-
-enum class StringCode : uint8_t
-{
- NOP, POS, INT, PARAM, FUNC,
- VARIABLE,
-};
-
-enum class ByteCode : uint8_t
-{
- // types and specials
- // Note that 'INT' is synthetic, and does not occur in the data stream
- NOP, POS, INT, PARAM, FUNC, STR, ARG,
- VARIABLE, EOL,
-
- // unary and binary operators
- LOR, LAND, LE, LT, GE, GT, EQ, NE,
- XOR, OR, AND, ADD, SUB, MUL, DIV, MOD,
- NEG, LNOT, NOT, R_SHIFT, L_SHIFT,
-
- // additions
- // needed because FUNC is used for the actual call
- FUNC_REF,
-};
-
-struct str_data_t
-{
- StringCode type;
- RString strs;
- int backpatch;
- int label_;
- int val;
-};
-
-class ScriptBuffer
-{
- typedef ZString::iterator ZSit;
-
- std::vector<ByteCode> script_buf;
-public:
- // construction methods used only by script.cpp
- void add_scriptc(ByteCode a);
- void add_scriptb(uint8_t a);
- void add_scripti(uint32_t a);
- void add_scriptl(str_data_t *a);
- void set_label(str_data_t *ld, int pos_);
- ZSit parse_simpleexpr(ZSit p);
- ZSit parse_subexpr(ZSit p, int limit);
- ZSit parse_expr(ZSit p);
- ZSit parse_line(ZSit p, bool *canstep);
- void parse_script(ZString src, int line, bool implicit_end);
-
- // consumption methods used only by script.cpp
- ByteCode operator[](size_t i) const { return script_buf[i]; }
- ZString get_str(size_t i) const
- {
- return ZString(strings::really_construct_from_a_pointer, reinterpret_cast<const char *>(&script_buf[i]), nullptr);
- }
-};
-} // namespace tmwa
-
-void std::default_delete<const tmwa::ScriptBuffer>::operator()(const tmwa::ScriptBuffer *sd)
-{
- really_delete1 sd;
-}
-
-namespace tmwa
-{
-ByteCode ScriptPointer::peek() const { return (*code)[pos]; }
-ByteCode ScriptPointer::pop() { return (*code)[pos++]; }
-ZString ScriptPointer::pops()
-{
- ZString rv = code->get_str(pos);
- pos += rv.size();
- ++pos;
- return rv;
-}
-
-struct script_stack
-{
- std::vector<struct script_data> stack_datav;
-};
-
-enum class ScriptEndState;
-// future improvements coming!
-class ScriptState
-{
-public:
- struct script_stack *stack;
- int start, end;
- ScriptEndState state;
- BlockId rid, oid;
- ScriptPointer scriptp, new_scriptp;
- int defsp, new_defsp;
-};
-
-static
-Map<RString, str_data_t> str_datam;
-static
-str_data_t LABEL_NEXTLINE_;
-
-static
-DMap<SIR, int> mapreg_db;
-static
-Map<SIR, RString> mapregstr_db;
-static
-int mapreg_dirty = -1;
-AString mapreg_txt = "save/mapreg.txt"_s;
-constexpr std::chrono::milliseconds MAPREG_AUTOSAVE_INTERVAL = 10_s;
-
-Map<ScriptLabel, int> scriptlabel_db;
-static
-std::set<ScriptLabel> probable_labels;
-UPMap<RString, const ScriptBuffer> userfunc_db;
-
-static
-Array<LString, 11> pos_str //=
-{{
- "Head"_s,
- "Body"_s,
- "Left hand"_s,
- "Right hand"_s,
- "Robe"_s,
- "Shoes"_s,
- "Accessory 1"_s,
- "Accessory 2"_s,
- "Head 2"_s,
- "Head 3"_s,
- "Not Equipped"_s,
-}};
-
-static
-struct Script_Config
-{
- static const
- int warn_func_no_comma = 1;
- static const
- int warn_cmd_no_comma = 1;
- static const
- int warn_func_mismatch_paramnum = 1;
- static const
- int warn_cmd_mismatch_paramnum = 1;
- static const
- int check_cmdcount = 8192;
- static const
- int check_gotocount = 512;
-} script_config;
-
-static
-int parse_cmd_if = 0;
-static
-str_data_t *parse_cmdp;
-
-static
-void run_func(ScriptState *st);
-
-static
-void mapreg_setreg(SIR num, int val);
-static
-void mapreg_setregstr(SIR num, XString str);
-
-struct BuiltinFunction
-{
- void (*func)(ScriptState *);
- LString name;
- LString arg;
- char ret;
-};
-// defined later
-extern BuiltinFunction builtin_functions[];
-
-static
-InternPool variable_names;
-
-
-template<class D>
-bool first_type_is_any()
-{
- return false;
-}
-
-template<class D, class F, class... R>
-constexpr
-bool first_type_is_any()
-{
- return std::is_same<D, F>::value || first_type_is_any<D, R...>();
-}
-
-
-static
-str_data_t *search_strp(XString p)
-{
- return str_datam.search(p);
-}
-
-static
-str_data_t *add_strp(XString p)
-{
- if (str_data_t *rv = search_strp(p))
- return rv;
-
- RString p2 = p;
- str_data_t *datum = str_datam.init(p2);
- datum->type = StringCode::NOP;
- datum->strs = p2;
- datum->backpatch = -1;
- datum->label_ = -1;
- return datum;
-}
-
-/*==========================================
- * スクリプトバッファに1バイト書き込む
- *------------------------------------------
- */
-void ScriptBuffer::add_scriptc(ByteCode a)
-{
- script_buf.push_back(a);
-}
-
-/*==========================================
- * スクリプトバッファにデータタイプを書き込む
- *------------------------------------------
- */
-void ScriptBuffer::add_scriptb(uint8_t a)
-{
- add_scriptc(static_cast<ByteCode>(a));
-}
-
-/*==========================================
- * スクリプトバッファに整数を書き込む
- *------------------------------------------
- */
-void ScriptBuffer::add_scripti(uint32_t a)
-{
- while (a >= 0x40)
- {
- add_scriptb(a | 0xc0);
- a = (a - 0x40) >> 6;
- }
- add_scriptb(a | 0x80);
-}
-
-/*==========================================
- * スクリプトバッファにラベル/変数/関数を書き込む
- *------------------------------------------
- */
-// 最大16Mまで
-void ScriptBuffer::add_scriptl(str_data_t *ld)
-{
- int backpatch = ld->backpatch;
-
- switch (ld->type)
- {
- case StringCode::POS:
- add_scriptc(ByteCode::POS);
- add_scriptb(static_cast<uint8_t>(ld->label_));
- add_scriptb(static_cast<uint8_t>(ld->label_ >> 8));
- add_scriptb(static_cast<uint8_t>(ld->label_ >> 16));
- break;
- case StringCode::NOP:
- // need to set backpatch, because it might become a label later
- add_scriptc(ByteCode::VARIABLE);
- ld->backpatch = script_buf.size();
- add_scriptb(static_cast<uint8_t>(backpatch));
- add_scriptb(static_cast<uint8_t>(backpatch >> 8));
- add_scriptb(static_cast<uint8_t>(backpatch >> 16));
- break;
- case StringCode::INT:
- add_scripti(ld->val);
- break;
- case StringCode::FUNC:
- add_scriptc(ByteCode::FUNC_REF);
- add_scriptb(static_cast<uint8_t>(ld->val));
- add_scriptb(static_cast<uint8_t>(ld->val >> 8));
- add_scriptb(static_cast<uint8_t>(ld->val >> 16));
- break;
- case StringCode::PARAM:
- add_scriptc(ByteCode::PARAM);
- add_scriptb(static_cast<uint8_t>(ld->val));
- add_scriptb(static_cast<uint8_t>(ld->val >> 8));
- add_scriptb(static_cast<uint8_t>(ld->val >> 16));
- break;
- default:
- abort();
- }
-}
-
-/*==========================================
- * ラベルを解決する
- *------------------------------------------
- */
-void ScriptBuffer::set_label(str_data_t *ld, int pos_)
-{
- int next;
-
- ld->type = StringCode::POS;
- ld->label_ = pos_;
- for (int i = ld->backpatch; i >= 0 && i != 0x00ffffff; i = next)
- {
- next = 0;
- // woot! no longer endian-dependent!
- next |= static_cast<uint8_t>(script_buf[i + 0]) << 0;
- next |= static_cast<uint8_t>(script_buf[i + 1]) << 8;
- next |= static_cast<uint8_t>(script_buf[i + 2]) << 16;
- script_buf[i - 1] = ByteCode::POS;
- script_buf[i] = static_cast<ByteCode>(pos_);
- script_buf[i + 1] = static_cast<ByteCode>(pos_ >> 8);
- script_buf[i + 2] = static_cast<ByteCode>(pos_ >> 16);
- }
-}
-
-/*==========================================
- * スペース/コメント読み飛ばし
- *------------------------------------------
- */
-static
-ZString::iterator skip_space(ZString::iterator p)
-{
- while (1)
- {
- while (isspace(*p))
- p++;
- if (p[0] == '/' && p[1] == '/')
- {
- while (*p && *p != '\n')
- p++;
- }
- else if (p[0] == '/' && p[1] == '*')
- {
- p++;
- while (*p && (p[-1] != '*' || p[0] != '/'))
- p++;
- if (*p)
- p++;
- }
- else
- break;
- }
- return p;
-}
-
-/*==========================================
- * 1単語スキップ
- *------------------------------------------
- */
-static
-ZString::iterator skip_word(ZString::iterator p)
-{
- // prefix
- if (*p == '$')
- p++; // MAP鯖内共有変数用
- if (*p == '@')
- p++; // 一時的変数用(like weiss)
- if (*p == '#')
- p++; // account変数用
- if (*p == '#')
- p++; // ワールドaccount変数用
-
- while (isalnum(*p) || *p == '_')
- p++;
-
- // postfix
- if (*p == '$')
- p++; // 文字列変数
-
- return p;
-}
-
-// TODO: replace this whole mess with some sort of input stream that works
-// a line at a time.
-static
-ZString startptr;
-static
-int startline;
-
-int script_errors = 0;
-/*==========================================
- * エラーメッセージ出力
- *------------------------------------------
- */
-static
-void disp_error_message(ZString mes, ZString::iterator pos_)
-{
- script_errors++;
-
- assert (startptr.begin() <= pos_ && pos_ <= startptr.end());
-
- int line;
- ZString::iterator p;
-
- for (line = startline, p = startptr.begin(); p != startptr.end(); line++)
- {
- ZString::iterator linestart = p;
- ZString::iterator lineend = std::find(p, startptr.end(), '\n');
- if (pos_ < lineend)
- {
- PRINTF("\n%s\nline %d : "_fmt, mes, line);
- for (int i = 0; linestart + i != lineend; i++)
- {
- if (linestart + i != pos_)
- PRINTF("%c"_fmt, linestart[i]);
- else
- PRINTF("\'%c\'"_fmt, linestart[i]);
- }
- PRINTF("\a\n"_fmt);
- return;
- }
- p = lineend + 1;
- }
-}
-
-/*==========================================
- * 項の解析
- *------------------------------------------
- */
-ZString::iterator ScriptBuffer::parse_simpleexpr(ZString::iterator p)
-{
- p = skip_space(p);
-
- if (*p == ';' || *p == ',')
- {
- disp_error_message("unexpected expr end"_s, p);
- exit(1);
- }
- if (*p == '(')
- {
-
- p = parse_subexpr(p + 1, -1);
- p = skip_space(p);
- if ((*p++) != ')')
- {
- disp_error_message("unmatch ')'"_s, p);
- exit(1);
- }
- }
- else if (isdigit(*p) || ((*p == '-' || *p == '+') && isdigit(p[1])))
- {
- char *np;
- int i = strtoul(&*p, &np, 0);
- add_scripti(i);
- p += np - &*p;
- }
- else if (*p == '"')
- {
- add_scriptc(ByteCode::STR);
- p++;
- while (*p && *p != '"')
- {
- if (*p == '\\')
- p++;
- else if (*p == '\n')
- {
- disp_error_message("unexpected newline @ string"_s, p);
- exit(1);
- }
- add_scriptb(*p++);
- }
- if (!*p)
- {
- disp_error_message("unexpected eof @ string"_s, p);
- exit(1);
- }
- add_scriptb(0);
- p++; //'"'
- }
- else
- {
- // label , register , function etc
- ZString::iterator p2 = skip_word(p);
- if (p2 == p)
- {
- disp_error_message("unexpected character"_s, p);
- exit(1);
- }
- XString word(&*p, &*p2, nullptr);
- if (word.startswith("On"_s) || word.startswith("L_"_s) || word.startswith("S_"_s))
- probable_labels.insert(stringish<ScriptLabel>(word));
- if (parse_cmd_if && (word == "callsub"_s || word == "callfunc"_s || word == "return"_s))
- {
- disp_error_message("Sorry, callsub/callfunc/return have never worked properly in an if statement."_s, p);
- }
- str_data_t *ld = add_strp(word);
-
- parse_cmdp = ld; // warn_*_mismatch_paramnumのために必要
- // why not just check l->str == "if"_s or std::string(p, p2) == "if"_s?
- if (ld == search_strp("if"_s)) // warn_cmd_no_commaのために必要
- parse_cmd_if++;
- p = p2;
-
- if (ld->type != StringCode::FUNC && *p == '[')
- {
- // array(name[i] => getelementofarray(name,i) )
- add_scriptl(search_strp("getelementofarray"_s));
- add_scriptc(ByteCode::ARG);
- add_scriptl(ld);
- p = parse_subexpr(p + 1, -1);
- p = skip_space(p);
- if (*p != ']')
- {
- disp_error_message("unmatch ']'"_s, p);
- exit(1);
- }
- p++;
- add_scriptc(ByteCode::FUNC);
- }
- else
- add_scriptl(ld);
-
- }
-
- return p;
-}
-
-/*==========================================
- * 式の解析
- *------------------------------------------
- */
-ZString::iterator ScriptBuffer::parse_subexpr(ZString::iterator p, int limit)
-{
- ByteCode op;
- int opl, len;
-
- p = skip_space(p);
-
- if (*p == '-')
- {
- ZString::iterator tmpp = skip_space(p + 1);
- if (*tmpp == ';' || *tmpp == ',')
- {
- --script_errors; disp_error_message("deprecated: implicit 'next statement' label"_s, p);
- add_scriptl(&LABEL_NEXTLINE_);
- p++;
- return p;
- }
- }
- ZString::iterator tmpp = p;
- if ((op = ByteCode::NEG, *p == '-') || (op = ByteCode::LNOT, *p == '!')
- || (op = ByteCode::NOT, *p == '~'))
- {
- p = parse_subexpr(p + 1, 100);
- add_scriptc(op);
- }
- else
- p = parse_simpleexpr(p);
- p = skip_space(p);
- while (((op = ByteCode::ADD, opl = 6, len = 1, *p == '+') ||
- (op = ByteCode::SUB, opl = 6, len = 1, *p == '-') ||
- (op = ByteCode::MUL, opl = 7, len = 1, *p == '*') ||
- (op = ByteCode::DIV, opl = 7, len = 1, *p == '/') ||
- (op = ByteCode::MOD, opl = 7, len = 1, *p == '%') ||
- (op = ByteCode::FUNC, opl = 8, len = 1, *p == '(') ||
- (op = ByteCode::LAND, opl = 1, len = 2, *p == '&' && p[1] == '&') ||
- (op = ByteCode::AND, opl = 5, len = 1, *p == '&') ||
- (op = ByteCode::LOR, opl = 0, len = 2, *p == '|' && p[1] == '|') ||
- (op = ByteCode::OR, opl = 4, len = 1, *p == '|') ||
- (op = ByteCode::XOR, opl = 3, len = 1, *p == '^') ||
- (op = ByteCode::EQ, opl = 2, len = 2, *p == '=' && p[1] == '=') ||
- (op = ByteCode::NE, opl = 2, len = 2, *p == '!' && p[1] == '=') ||
- (op = ByteCode::R_SHIFT, opl = 5, len = 2, *p == '>' && p[1] == '>') ||
- (op = ByteCode::GE, opl = 2, len = 2, *p == '>' && p[1] == '=') ||
- (op = ByteCode::GT, opl = 2, len = 1, *p == '>') ||
- (op = ByteCode::L_SHIFT, opl = 5, len = 2, *p == '<' && p[1] == '<') ||
- (op = ByteCode::LE, opl = 2, len = 2, *p == '<' && p[1] == '=') ||
- (op = ByteCode::LT, opl = 2, len = 1, *p == '<')) && opl > limit)
- {
- p += len;
- if (op == ByteCode::FUNC)
- {
- int i = 0;
- str_data_t *funcp = parse_cmdp;
- ZString::iterator plist[128];
-
- if (funcp->type != StringCode::FUNC)
- {
- disp_error_message("expect function"_s, tmpp);
- exit(0);
- }
-
- add_scriptc(ByteCode::ARG);
- while (*p && *p != ')' && i < 128)
- {
- plist[i] = p;
- p = parse_subexpr(p, -1);
- p = skip_space(p);
- if (*p == ',')
- p++;
- else if (*p != ')' && script_config.warn_func_no_comma)
- {
- disp_error_message("expect ',' or ')' at func params"_s,
- p);
- }
- p = skip_space(p);
- i++;
- }
- plist[i] = p;
- if (*p != ')')
- {
- disp_error_message("func request '(' ')'"_s, p);
- exit(1);
- }
- p++;
-
- if (funcp->type == StringCode::FUNC
- && script_config.warn_func_mismatch_paramnum)
- {
- ZString arg = builtin_functions[funcp->val].arg;
- int j = 0;
- // TODO handle ? and multiple * correctly
- for (j = 0; arg[j]; j++)
- if (arg[j] == '*' || arg[j] == '?')
- break;
- if ((arg[j] == 0 && i != j) || ((arg[j] == '*' || arg[j] == '?') && i < j))
- {
- disp_error_message("illegal number of parameters"_s,
- plist[std::min(i, j)]);
- }
- if (!builtin_functions[funcp->val].ret)
- {
- disp_error_message("statement in function context"_s, tmpp);
- }
- }
- }
- else // not op == ByteCode::FUNC
- {
- p = parse_subexpr(p, opl);
- }
- add_scriptc(op);
- p = skip_space(p);
- }
- return p; /* return first untreated operator */
-}
-
-/*==========================================
- * 式の評価
- *------------------------------------------
- */
-ZString::iterator ScriptBuffer::parse_expr(ZString::iterator p)
-{
- switch (*p)
- {
- case ')':
- case ';':
- case ':':
- case '[':
- case ']':
- case '}':
- disp_error_message("unexpected char"_s, p);
- exit(1);
- }
- p = parse_subexpr(p, -1);
- return p;
-}
-
-/*==========================================
- * 行の解析
- *------------------------------------------
- */
-ZString::iterator ScriptBuffer::parse_line(ZString::iterator p, bool *can_step)
-{
- int i = 0;
- ZString::iterator plist[128];
-
- p = skip_space(p);
- if (*p == ';')
- return p;
-
- parse_cmd_if = 0; // warn_cmd_no_commaのために必要
-
- // 最初は関数名
- ZString::iterator p2 = p;
- p = parse_simpleexpr(p);
- p = skip_space(p);
-
- str_data_t *cmd = parse_cmdp;
- if (cmd->type != StringCode::FUNC)
- {
- disp_error_message("expect command"_s, p2);
- }
-
- {
- // TODO should be LString, but no heterogenous lookup yet
- static
- std::set<ZString> terminators =
- {
- "goto"_s,
- "return"_s,
- "close"_s,
- "menu"_s,
- "end"_s,
- "mapexit"_s,
- "shop"_s,
- };
- *can_step = terminators.count(cmd->strs) == 0;
- }
-
- add_scriptc(ByteCode::ARG);
- while (*p && *p != ';' && i < 128)
- {
- plist[i] = p;
-
- p = parse_expr(p);
- p = skip_space(p);
- // 引数区切りの,処理
- if (*p == ',')
- p++;
- else if (*p != ';' && script_config.warn_cmd_no_comma
- && parse_cmd_if * 2 <= i)
- {
- disp_error_message("expect ',' or ';' at cmd params"_s, p);
- }
- p = skip_space(p);
- i++;
- }
- plist[i] = p;
- if (*(p++) != ';')
- {
- disp_error_message("need ';'"_s, p);
- exit(1);
- }
- add_scriptc(ByteCode::FUNC);
-
- if (cmd->type == StringCode::FUNC
- && script_config.warn_cmd_mismatch_paramnum)
- {
- ZString arg = builtin_functions[cmd->val].arg;
- int j = 0;
- // TODO see above
- for (j = 0; arg[j]; j++)
- if (arg[j] == '*' || arg[j] == '?')
- break;
- if ((arg[j] == 0 && i != j) || ((arg[j] == '*' || arg[j] == '?') && i < j))
- {
- disp_error_message("illegal number of parameters"_s,
- plist[std::min(i, j)]);
- }
- if (builtin_functions[cmd->val].ret)
- {
- disp_error_message("function in statement context"_s, p2);
- }
- }
-
- return p;
-}
-
-/*==========================================
- * 組み込み関数の追加
- *------------------------------------------
- */
-static
-void add_builtin_functions(void)
-{
- for (int i = 0; builtin_functions[i].func; i++)
- {
- str_data_t *n = add_strp(builtin_functions[i].name);
- n->type = StringCode::FUNC;
- n->val = i;
- }
-}
-
-bool read_constdb(ZString filename)
-{
- io::ReadFile in(filename);
- if (!in.is_open())
- {
- PRINTF("can't read %s\n"_fmt, filename);
- return false;
- }
-
- bool rv = true;
- AString line_;
- while (in.getline(line_))
- {
- // is_comment only works for whole-line comments
- // that could change once the Z dependency is dropped ...
- LString comment = "//"_s;
- XString line = line_.xislice_h(std::search(line_.begin(), line_.end(), comment.begin(), comment.end())).rstrip();
- if (!line)
- continue;
- // "%m[A-Za-z0-9_] %i %i"
-
- // TODO promote either qsplit() or asplit()
- auto _it = std::find(line.begin(), line.end(), ' ');
- auto name = line.xislice_h(_it);
- auto _rest = line.xislice_t(_it);
- while (_rest.startswith(' '))
- _rest = _rest.xslice_t(1);
- auto _it2 = std::find(_rest.begin(), _rest.end(), ' ');
- auto val_ = _rest.xislice_h(_it2);
- auto type_ = _rest.xislice_t(_it2);
- while (type_.startswith(' '))
- type_ = type_.xslice_t(1);
- // yes, the above actually DTRT even for underlength input
-
- int val;
- int type = 0;
- // Note for future archeaologists: this code is indented correctly
- if (std::find_if_not(name.begin(), name.end(),
- [](char c)
- {
- return ('0' <= c && c <= '9')
- || ('A' <= c && c <= 'Z')
- || ('a' <= c && c <= 'z')
- || (c == '_');
- }) != name.end()
- || !extract(val_, &val)
- || (!extract(type_, &type) && type_))
- {
- PRINTF("Bad const line: %s\n"_fmt, line_);
- rv = false;
- continue;
- }
- str_data_t *n = add_strp(name);
- n->type = type ? StringCode::PARAM : StringCode::INT;
- n->val = val;
- }
- return rv;
-}
-
-std::unique_ptr<const ScriptBuffer> parse_script(ZString src, int line, bool implicit_end)
-{
- auto script_buf = make_unique<ScriptBuffer>();
- script_buf->parse_script(src, line, implicit_end);
- return std::move(script_buf);
-}
-
-/*==========================================
- * スクリプトの解析
- *------------------------------------------
- */
-void ScriptBuffer::parse_script(ZString src, int line, bool implicit_end)
-{
- static int first = 1;
-
- if (first)
- {
- add_builtin_functions();
- }
- first = 0;
- LABEL_NEXTLINE_.type = StringCode::NOP;
- LABEL_NEXTLINE_.backpatch = -1;
- LABEL_NEXTLINE_.label_ = -1;
- for (auto& pair : str_datam)
- {
- str_data_t& dit = pair.second;
- if (dit.type == StringCode::POS || dit.type == StringCode::VARIABLE)
- {
- dit.type = StringCode::NOP;
- dit.backpatch = -1;
- dit.label_ = -1;
- }
- }
-
- // 外部用label dbの初期化
- scriptlabel_db.clear();
-
- // for error message
- startptr = src;
- startline = line;
-
- bool can_step = true;
-
- ZString::iterator p = src.begin();
- p = skip_space(p);
- if (*p != '{')
- {
- disp_error_message("not found '{'"_s, p);
- abort();
- }
- for (p++; *p && *p != '}';)
- {
- p = skip_space(p);
- if (*skip_space(skip_word(p)) == ':')
- {
- if (can_step)
- {
- --script_errors; disp_error_message("deprecated: implicit fallthrough"_s, p);
- }
- can_step = true;
-
- ZString::iterator tmpp = skip_word(p);
- XString str(&*p, &*tmpp, nullptr);
- str_data_t *ld = add_strp(str);
- bool e1 = ld->type != StringCode::NOP;
- bool e2 = ld->type == StringCode::POS;
- bool e3 = ld->label_ != -1;
- assert (e1 == e2 && e2 == e3);
- if (e3)
- {
- disp_error_message("dup label "_s, p);
- exit(1);
- }
- set_label(ld, script_buf.size());
- scriptlabel_db.insert(stringish<ScriptLabel>(str), script_buf.size());
- p = tmpp + 1;
- continue;
- }
-
- if (!can_step)
- {
- --script_errors; disp_error_message("deprecated: unreachable statement"_s, p);
- }
- // 他は全部一緒くた
- p = parse_line(p, &can_step);
- p = skip_space(p);
- add_scriptc(ByteCode::EOL);
-
- set_label(&LABEL_NEXTLINE_, script_buf.size());
- LABEL_NEXTLINE_.type = StringCode::NOP;
- LABEL_NEXTLINE_.backpatch = -1;
- LABEL_NEXTLINE_.label_ = -1;
- }
-
- if (can_step && !implicit_end)
- {
- --script_errors; disp_error_message("deprecated: implicit end"_s, p);
- }
- add_scriptc(ByteCode::NOP);
-
- // resolve the unknown labels
- for (auto& pair : str_datam)
- {
- str_data_t& sit = pair.second;
- if (sit.type == StringCode::NOP)
- {
- sit.type = StringCode::VARIABLE;
- sit.label_ = 0; // anything but -1. Shouldn't matter, but helps asserts.
- size_t pool_index = variable_names.intern(sit.strs);
- for (int next, j = sit.backpatch; j >= 0 && j != 0x00ffffff; j = next)
- {
- next = 0;
- next |= static_cast<uint8_t>(script_buf[j + 0]) << 0;
- next |= static_cast<uint8_t>(script_buf[j + 1]) << 8;
- next |= static_cast<uint8_t>(script_buf[j + 2]) << 16;
- script_buf[j] = static_cast<ByteCode>(pool_index);
- script_buf[j + 1] = static_cast<ByteCode>(pool_index >> 8);
- script_buf[j + 2] = static_cast<ByteCode>(pool_index >> 16);
- }
- }
- }
-
- for (const auto& pair : scriptlabel_db)
- {
- ScriptLabel key = pair.first;
- if (key.startswith("On"_s))
- continue;
- if (!(key.startswith("L_"_s) || key.startswith("S_"_s)))
- PRINTF("Warning: ugly label: %s\n"_fmt, key);
- else if (!probable_labels.count(key))
- PRINTF("Warning: unused label: %s\n"_fmt, key);
- }
- for (ScriptLabel used : probable_labels)
- {
- if (!scriptlabel_db.search(used))
- PRINTF("Warning: no such label: %s\n"_fmt, used);
- }
- probable_labels.clear();
-
- if (!DEBUG_DISP)
- return;
- for (size_t i = 0; i < script_buf.size(); i++)
- {
- if ((i & 15) == 0)
- PRINTF("%04zx : "_fmt, i);
- PRINTF("%02x "_fmt, script_buf[i]);
- if ((i & 15) == 15)
- PRINTF("\n"_fmt);
- }
- PRINTF("\n"_fmt);
-}
-
-//
-// 実行系
-//
-enum class ScriptEndState
-{
- ZERO,
- STOP,
- END,
- RERUNLINE,
- GOTO,
- RETFUNC,
-};
-
-/*==========================================
- * ridからsdへの解決
- *------------------------------------------
- */
-static
-dumb_ptr<map_session_data> script_rid2sd(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = map_id2sd(st->rid);
- if (!sd)
- {
- PRINTF("script_rid2sd: fatal error ! player not attached!\n"_fmt);
- }
- return sd;
-}
-
-/*==========================================
- * 変数の読み取り
- *------------------------------------------
- */
-static
-void get_val(dumb_ptr<map_session_data> sd, struct script_data *data)
-{
- MATCH (*data)
- {
- CASE (const ScriptDataParam&, u)
- {
- if (sd == nullptr)
- PRINTF("get_val error param SP::%d\n"_fmt, u.reg.sp());
- int numi = 0;
- if (sd)
- numi = pc_readparam(sd, u.reg.sp());
- *data = ScriptDataInt{numi};
- }
- CASE (const ScriptDataVariable&, u)
- {
- ZString name_ = variable_names.outtern(u.reg.base());
- VarName name = stringish<VarName>(name_);
- char prefix = name.front();
- char postfix = name.back();
-
- if (prefix != '$')
- {
- if (sd == nullptr)
- PRINTF("get_val error name?:%s\n"_fmt, name);
- }
- if (postfix == '$')
- {
- RString str;
- if (prefix == '@')
- {
- if (sd)
- str = pc_readregstr(sd, u.reg);
- }
- else if (prefix == '$')
- {
- RString *s = mapregstr_db.search(u.reg);
- if (s)
- str = *s;
- }
- else
- {
- PRINTF("script: get_val: illegal scope string variable.\n"_fmt);
- str = "!!ERROR!!"_s;
- }
- *data = ScriptDataStr{str};
- }
- else
- {
- int numi = 0;
- if (prefix == '@')
- {
- if (sd)
- numi = pc_readreg(sd, u.reg);
- }
- else if (prefix == '$')
- {
- numi = mapreg_db.get(u.reg);
- }
- else if (prefix == '#')
- {
- if (name[1] == '#')
- {
- if (sd)
- numi = pc_readaccountreg2(sd, name);
- }
- else
- {
- if (sd)
- numi = pc_readaccountreg(sd, name);
- }
- }
- else
- {
- if (sd)
- numi = pc_readglobalreg(sd, name);
- }
- *data = ScriptDataInt{numi};
- }
- }
- }
-}
-
-static __attribute__((deprecated))
-void get_val(ScriptState *st, struct script_data *data)
-{
- dumb_ptr<map_session_data> sd = st->rid ? map_id2sd(st->rid) : nullptr;
- get_val(sd, data);
-}
-
-/*==========================================
- * 変数の読み取り2
- *------------------------------------------
- */
-static
-struct script_data get_val2(ScriptState *st, SIR reg)
-{
- struct script_data dat = ScriptDataVariable{reg};
- get_val(st, &dat);
- return dat;
-}
-
-/*==========================================
- * 変数設定用
- *------------------------------------------
- */
-static
-void set_reg(dumb_ptr<map_session_data> sd, VariableCode type, SIR reg, struct script_data vd)
-{
- if (type == VariableCode::PARAM)
- {
- int val = vd.get_if<ScriptDataInt>()->numi;
- pc_setparam(sd, reg.sp(), val);
- return;
- }
- assert (type == VariableCode::VARIABLE);
-
- ZString name_ = variable_names.outtern(reg.base());
- VarName name = stringish<VarName>(name_);
- char prefix = name.front();
- char postfix = name.back();
-
- if (postfix == '$')
- {
- RString str = vd.get_if<ScriptDataStr>()->str;
- if (prefix == '@')
- {
- pc_setregstr(sd, reg, str);
- }
- else if (prefix == '$')
- {
- mapreg_setregstr(reg, str);
- }
- else
- {
- PRINTF("script: set_reg: illegal scope string variable !"_fmt);
- }
- }
- else
- {
- int val = vd.get_if<ScriptDataInt>()->numi;
- if (prefix == '@')
- {
- pc_setreg(sd, reg, val);
- }
- else if (prefix == '$')
- {
- mapreg_setreg(reg, val);
- }
- else if (prefix == '#')
- {
- if (name[1] == '#')
- pc_setaccountreg2(sd, name, val);
- else
- pc_setaccountreg(sd, name, val);
- }
- else
- {
- pc_setglobalreg(sd, name, val);
- }
- }
-}
-
-static
-void set_reg(dumb_ptr<map_session_data> sd, VariableCode type, SIR reg, int id)
-{
- struct script_data vd = ScriptDataInt{id};
- set_reg(sd, type, reg, vd);
-}
-
-static
-void set_reg(dumb_ptr<map_session_data> sd, VariableCode type, SIR reg, RString zd)
-{
- struct script_data vd = ScriptDataStr{zd};
- set_reg(sd, type, reg, vd);
-}
-
-/*==========================================
- * 文字列への変換
- *------------------------------------------
- */
-static __attribute__((warn_unused_result))
-RString conv_str(ScriptState *st, struct script_data *data)
-{
- get_val(st, data);
- assert (!data->is<ScriptDataRetInfo>());
- if (auto *u = data->get_if<ScriptDataInt>())
- {
- AString buf = STRPRINTF("%d"_fmt, u->numi);
- *data = ScriptDataStr{buf};
- }
- return data->get_if<ScriptDataStr>()->str;
-}
-
-/*==========================================
- * 数値へ変換
- *------------------------------------------
- */
-static __attribute__((warn_unused_result))
-int conv_num(ScriptState *st, struct script_data *data)
-{
- int rv = 0;
- get_val(st, data);
- assert (!data->is<ScriptDataRetInfo>());
- MATCH (*data)
- {
- default:
- abort();
- CASE (const ScriptDataStr&, u)
- {
- RString p = u.str;
- rv = atoi(p.c_str());
- }
- CASE (const ScriptDataInt&, u)
- {
- return u.numi;
- }
- CASE (const ScriptDataPos&, u)
- {
- return u.numi;
- }
- }
- *data = ScriptDataInt{rv};
- return rv;
-}
-
-static __attribute__((warn_unused_result))
-const ScriptBuffer *conv_script(ScriptState *st, struct script_data *data)
-{
- get_val(st, data);
- return data->get_if<ScriptDataRetInfo>()->script;
-}
-
-
-template<class T>
-static
-void push_int(struct script_stack *stack, int val)
-{
- static_assert(first_type_is_any<T, ScriptDataPos, ScriptDataInt, ScriptDataArg, ScriptDataFuncRef>(), "not int type");
-
- script_data nsd = T{.numi= val};
- stack->stack_datav.push_back(nsd);
-}
-
-template<class T>
-static
-void push_reg(struct script_stack *stack, SIR reg)
-{
- static_assert(first_type_is_any<T, ScriptDataParam, ScriptDataVariable>(), "not reg type");
-
- script_data nsd = T{.reg= reg};
- stack->stack_datav.push_back(nsd);
-}
-
-template<class T>
-static
-void push_script(struct script_stack *stack, const ScriptBuffer *code)
-{
- static_assert(first_type_is_any<T, ScriptDataRetInfo>(), "not scriptbuf type");
-
- script_data nsd = T{.script= code};
- stack->stack_datav.push_back(nsd);
-}
-
-template<class T>
-static
-void push_str(struct script_stack *stack, RString str)
-{
- static_assert(first_type_is_any<T, ScriptDataStr>(), "not str type");
-
- script_data nsd = T{.str= str};
- stack->stack_datav.push_back(nsd);
-}
-
-static
-void push_copy(struct script_stack *stack, int pos_)
-{
- script_data csd = stack->stack_datav[pos_];
- stack->stack_datav.push_back(csd);
-}
-
-static
-void pop_stack(struct script_stack *stack, int start, int end)
-{
- auto it = stack->stack_datav.begin();
- stack->stack_datav.erase(it + start, it + end);
-}
-
-
-#define AARG(n) (st->stack->stack_datav[st->start + 2 + (n)])
-#define HARG(n) (st->end > st->start + 2 + (n))
-
-//
-// 埋め込み関数
-//
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_mes(ScriptState *st)
-{
- RString mes = conv_str(st, &AARG(0));
- clif_scriptmes(script_rid2sd(st), st->oid, mes);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_goto(ScriptState *st)
-{
- if (!AARG(0).is<ScriptDataPos>())
- {
- PRINTF("script: goto: not label !\n"_fmt);
- st->state = ScriptEndState::END;
- return;
- }
-
- st->scriptp.pos = conv_num(st, &AARG(0));
- st->state = ScriptEndState::GOTO;
-}
-
-/*==========================================
- * ユーザー定義関数の呼び出し
- *------------------------------------------
- */
-static
-void builtin_callfunc(ScriptState *st)
-{
- RString str = conv_str(st, &AARG(0));
- const ScriptBuffer *scr = userfunc_db.get(str);
-
- if (scr)
- {
- int j = 0;
- assert (st->start + 3 == st->end);
-#if 0
- for (int i = st->start + 3; i < st->end; i++, j++)
- push_copy(st->stack, i);
-#endif
-
- push_int<ScriptDataInt>(st->stack, j); // 引数の数をプッシュ
- push_int<ScriptDataInt>(st->stack, st->defsp); // 現在の基準スタックポインタをプッシュ
- push_int<ScriptDataInt>(st->stack, st->scriptp.pos); // 現在のスクリプト位置をプッシュ
- push_script<ScriptDataRetInfo>(st->stack, st->scriptp.code); // 現在のスクリプトをプッシュ
-
- st->scriptp = ScriptPointer(scr, 0);
- st->defsp = st->start + 4 + j;
- st->state = ScriptEndState::GOTO;
- }
- else
- {
- PRINTF("script:callfunc: function not found! [%s]\n"_fmt, str);
- st->state = ScriptEndState::END;
- }
-}
-
-/*==========================================
- * サブルーティンの呼び出し
- *------------------------------------------
- */
-static
-void builtin_callsub(ScriptState *st)
-{
- int pos_ = conv_num(st, &AARG(0));
- int j = 0;
- assert (st->start + 3 == st->end);
-#if 0
- for (int i = st->start + 3; i < st->end; i++, j++)
- push_copy(st->stack, i);
-#endif
-
- push_int<ScriptDataInt>(st->stack, j); // 引数の数をプッシュ
- push_int<ScriptDataInt>(st->stack, st->defsp); // 現在の基準スタックポインタをプッシュ
- push_int<ScriptDataInt>(st->stack, st->scriptp.pos); // 現在のスクリプト位置をプッシュ
- push_script<ScriptDataRetInfo>(st->stack, st->scriptp.code); // 現在のスクリプトをプッシュ
-
- st->scriptp.pos = pos_;
- st->defsp = st->start + 4 + j;
- st->state = ScriptEndState::GOTO;
-}
-
-/*==========================================
- * サブルーチン/ユーザー定義関数の終了
- *------------------------------------------
- */
-static
-void builtin_return(ScriptState *st)
-{
-#if 0
- if (HARG(0))
- { // 戻り値有り
- push_copy(st->stack, st->start + 2);
- }
-#endif
- st->state = ScriptEndState::RETFUNC;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_next(ScriptState *st)
-{
- st->state = ScriptEndState::STOP;
- clif_scriptnext(script_rid2sd(st), st->oid);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_close(ScriptState *st)
-{
- st->state = ScriptEndState::END;
- clif_scriptclose(script_rid2sd(st), st->oid);
-}
-
-static
-void builtin_close2(ScriptState *st)
-{
- st->state = ScriptEndState::STOP;
- clif_scriptclose(script_rid2sd(st), st->oid);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_menu(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- if (sd->state.menu_or_input == 0)
- {
- // First half: show menu.
- st->state = ScriptEndState::RERUNLINE;
- sd->state.menu_or_input = 1;
-
- MString buf;
- for (int i = 0; i < (st->end - (st->start + 2)) / 2; i++)
- {
- RString choice_str = conv_str(st, &AARG(i * 2 + 0));
- if (!choice_str)
- break;
- buf += choice_str;
- buf += ':';
- }
-
- clif_scriptmenu(script_rid2sd(st), st->oid, AString(buf));
- }
- else
- {
- // Rerun: item is chosen from menu.
- if (sd->npc_menu == 0xff)
- {
- // cancel
- sd->state.menu_or_input = 0;
- st->state = ScriptEndState::END;
- return;
- }
-
- // Actually jump to the label.
- // Logic change: menu_choices is the *total* number of labels,
- // not just the displayed number that ends with the "".
- // (Would it be better to pop the stack before rerunning?)
- int menu_choices = (st->end - (st->start + 2)) / 2;
- pc_setreg(sd, SIR::from(variable_names.intern("@menu"_s)), sd->npc_menu);
- sd->state.menu_or_input = 0;
- if (sd->npc_menu > 0 && sd->npc_menu <= menu_choices)
- {
- int arg_index = (sd->npc_menu - 1) * 2 + 1;
- if (!AARG(arg_index).is<ScriptDataPos>())
- {
- st->state = ScriptEndState::END;
- return;
- }
- st->scriptp.pos = AARG(arg_index).get_if<ScriptDataPos>()->numi;
- st->state = ScriptEndState::GOTO;
- }
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_rand(ScriptState *st)
-{
- if (HARG(1))
- {
- int min = conv_num(st, &AARG(0));
- int max = conv_num(st, &AARG(1));
- if (min > max)
- std::swap(max, min);
- push_int<ScriptDataInt>(st->stack, random_::in(min, max));
- }
- else
- {
- int range = conv_num(st, &AARG(0));
- push_int<ScriptDataInt>(st->stack, range <= 0 ? 0 : random_::to(range));
- }
-}
-
-/*==========================================
- * Check whether the PC is at the specified location
- *------------------------------------------
- */
-static
-void builtin_isat(ScriptState *st)
-{
- int x, y;
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x = conv_num(st, &AARG(1));
- y = conv_num(st, &AARG(2));
-
- if (!sd)
- return;
-
- push_int<ScriptDataInt>(st->stack,
- (x == sd->bl_x) && (y == sd->bl_y)
- && (str == sd->bl_m->name_));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_warp(ScriptState *st)
-{
- int x, y;
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x = conv_num(st, &AARG(1));
- y = conv_num(st, &AARG(2));
- if (str == "Random"_s)
- pc_randomwarp(sd, BeingRemoveWhy::WARPED);
- else if (str == "SavePoint"_s or str == "Save"_s)
- {
- if (sd->bl_m->flag.get(MapFlag::NORETURN))
- return;
-
- pc_setpos(sd, sd->status.save_point.map_, sd->status.save_point.x, sd->status.save_point.y,
- BeingRemoveWhy::WARPED);
- }
- else
- pc_setpos(sd, str, x, y, BeingRemoveWhy::GONE);
-}
-
-/*==========================================
- * エリア指定ワープ
- *------------------------------------------
- */
-static
-void builtin_areawarp_sub(dumb_ptr<block_list> bl, MapName mapname, int x, int y)
-{
- dumb_ptr<map_session_data> sd = bl->is_player();
- if (mapname == "Random"_s)
- pc_randomwarp(sd, BeingRemoveWhy::WARPED);
- else
- pc_setpos(sd, mapname, x, y, BeingRemoveWhy::GONE);
-}
-
-static
-void builtin_areawarp(ScriptState *st)
-{
- int x, y;
- int x0, y0, x1, y1;
-
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x0 = conv_num(st, &AARG(1));
- y0 = conv_num(st, &AARG(2));
- x1 = conv_num(st, &AARG(3));
- y1 = conv_num(st, &AARG(4));
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(5))));
- x = conv_num(st, &AARG(6));
- y = conv_num(st, &AARG(7));
-
- map_local *m = map_mapname2mapid(mapname);
- if (m == nullptr)
- return;
-
- map_foreachinarea(std::bind(builtin_areawarp_sub, ph::_1, str, x, y),
- m,
- x0, y0,
- x1, y1,
- BL::PC);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_heal(ScriptState *st)
-{
- int hp, sp;
-
- hp = conv_num(st, &AARG(0));
- sp = conv_num(st, &AARG(1));
- pc_heal(script_rid2sd(st), hp, sp);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_itemheal(ScriptState *st)
-{
- int hp, sp;
-
- hp = conv_num(st, &AARG(0));
- sp = conv_num(st, &AARG(1));
- pc_itemheal(script_rid2sd(st), hp, sp);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_percentheal(ScriptState *st)
-{
- int hp, sp;
-
- hp = conv_num(st, &AARG(0));
- sp = conv_num(st, &AARG(1));
- pc_percentheal(script_rid2sd(st), hp, sp);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_input(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = nullptr;
- script_data& scrd = AARG(0);
- assert (scrd.is<ScriptDataVariable>());
-
- SIR reg = scrd.get_if<ScriptDataVariable>()->reg;
- ZString name = variable_names.outtern(reg.base());
-// char prefix = name.front();
- char postfix = name.back();
-
- sd = script_rid2sd(st);
- if (sd->state.menu_or_input)
- {
- // Second time (rerun)
- sd->state.menu_or_input = 0;
- if (postfix == '$')
- {
- set_reg(sd, VariableCode::VARIABLE, reg, sd->npc_str);
- }
- else
- {
- //commented by Lupus (check Value Number Input fix in clif.c)
- //** Fix by fritz :X keeps people from abusing old input bugs
- // wtf?
- if (sd->npc_amount < 0) //** If input amount is less then 0
- {
- clif_tradecancelled(sd); // added "Deal has been cancelled" message by Valaris
- builtin_close(st); //** close
- }
-
- set_reg(sd, VariableCode::VARIABLE, reg, sd->npc_amount);
- }
- }
- else
- {
- // First time - send prompt to client, then wait
- st->state = ScriptEndState::RERUNLINE;
- if (postfix == '$')
- clif_scriptinputstr(sd, st->oid);
- else
- clif_scriptinput(sd, st->oid);
- sd->state.menu_or_input = 1;
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_if (ScriptState *st)
-{
- int sel, i;
-
- sel = conv_num(st, &AARG(0));
- if (!sel)
- return;
-
- // 関数名をコピー
- push_copy(st->stack, st->start + 3);
- // 間に引数マーカを入れて
- push_int<ScriptDataArg>(st->stack, 0);
- // 残りの引数をコピー
- for (i = st->start + 4; i < st->end; i++)
- {
- push_copy(st->stack, i);
- }
- run_func(st);
-}
-
-/*==========================================
- * 変数設定
- *------------------------------------------
- */
-static
-void builtin_set(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = nullptr;
- if (auto *u = AARG(0).get_if<ScriptDataParam>())
- {
- SIR reg = u->reg;
- sd = script_rid2sd(st);
-
- int val = conv_num(st, &AARG(1));
- set_reg(sd, VariableCode::PARAM, reg, val);
- return;
- }
-
- SIR reg = AARG(0).get_if<ScriptDataVariable>()->reg;
-
- ZString name = variable_names.outtern(reg.base());
- char prefix = name.front();
- char postfix = name.back();
-
- if (prefix != '$')
- sd = script_rid2sd(st);
-
- if (postfix == '$')
- {
- // 文字列
- RString str = conv_str(st, &AARG(1));
- set_reg(sd, VariableCode::VARIABLE, reg, str);
- }
- else
- {
- // 数値
- int val = conv_num(st, &AARG(1));
- set_reg(sd, VariableCode::VARIABLE, reg, val);
- }
-
-}
-
-/*==========================================
- * 配列変数設定
- *------------------------------------------
- */
-static
-void builtin_setarray(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = nullptr;
- SIR reg = AARG(0).get_if<ScriptDataVariable>()->reg;
- ZString name = variable_names.outtern(reg.base());
- char prefix = name.front();
- char postfix = name.back();
-
- if (prefix != '$' && prefix != '@')
- {
- PRINTF("builtin_setarray: illegal scope !\n"_fmt);
- return;
- }
- if (prefix != '$')
- sd = script_rid2sd(st);
-
- for (int j = 0, i = 1; i < st->end - st->start - 2 && j < 256; i++, j++)
- {
- if (postfix == '$')
- set_reg(sd, VariableCode::VARIABLE, reg.iplus(j), conv_str(st, &AARG(i)));
- else
- set_reg(sd, VariableCode::VARIABLE, reg.iplus(j), conv_num(st, &AARG(i)));
- }
-}
-
-/*==========================================
- * 配列変数クリア
- *------------------------------------------
- */
-static
-void builtin_cleararray(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = nullptr;
- SIR reg = AARG(0).get_if<ScriptDataVariable>()->reg;
- ZString name = variable_names.outtern(reg.base());
- char prefix = name.front();
- char postfix = name.back();
- int sz = conv_num(st, &AARG(2));
-
- if (prefix != '$' && prefix != '@')
- {
- PRINTF("builtin_cleararray: illegal scope !\n"_fmt);
- return;
- }
- if (prefix != '$')
- sd = script_rid2sd(st);
-
- for (int i = 0; i < sz; i++)
- {
- if (postfix == '$')
- set_reg(sd, VariableCode::VARIABLE, reg.iplus(i), conv_str(st, &AARG(1)));
- else
- set_reg(sd, VariableCode::VARIABLE, reg.iplus(i), conv_num(st, &AARG(1)));
- }
-
-}
-
-/*==========================================
- * 配列変数のサイズ所得
- *------------------------------------------
- */
-static
-int getarraysize(ScriptState *st, SIR reg)
-{
- int i = reg.index(), c = i;
- for (; i < 256; i++)
- {
- struct script_data vd = get_val2(st, reg.iplus(i));
- MATCH (vd)
- {
- CASE (const ScriptDataStr&, u)
- {
- if (u.str[0])
- c = i;
- goto continue_outer;
- }
- CASE (const ScriptDataInt&, u)
- {
- if (u.numi)
- c = i;
- goto continue_outer;
- }
- }
- abort();
- continue_outer:
- ;
- }
- return c + 1;
-}
-
-static
-void builtin_getarraysize(ScriptState *st)
-{
- SIR reg = AARG(0).get_if<ScriptDataVariable>()->reg;
- ZString name = variable_names.outtern(reg.base());
- char prefix = name.front();
-
- if (prefix != '$' && prefix != '@')
- {
- PRINTF("builtin_copyarray: illegal scope !\n"_fmt);
- return;
- }
-
- push_int<ScriptDataInt>(st->stack, getarraysize(st, reg));
-}
-
-/*==========================================
- * 指定要素を表す値(キー)を所得する
- *------------------------------------------
- */
-static
-void builtin_getelementofarray(ScriptState *st)
-{
- if (auto *u = AARG(0).get_if<ScriptDataVariable>())
- {
- int i = conv_num(st, &AARG(1));
- if (i > 255 || i < 0)
- {
- PRINTF("script: getelementofarray (operator[]): param2 illegal number %d\n"_fmt,
- i);
- push_int<ScriptDataInt>(st->stack, 0);
- }
- else
- {
- push_reg<ScriptDataVariable>(st->stack,
- u->reg.iplus(i));
- }
- }
- else
- {
- PRINTF("script: getelementofarray (operator[]): param1 not name !\n"_fmt);
- push_int<ScriptDataInt>(st->stack, 0);
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_setlook(ScriptState *st)
-{
- LOOK type = LOOK(conv_num(st, &AARG(0)));
- int val = conv_num(st, &AARG(1));
-
- pc_changelook(script_rid2sd(st), type, val);
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_countitem(ScriptState *st)
-{
- ItemNameId nameid;
- int count = 0;
- dumb_ptr<map_session_data> sd;
-
- struct script_data *data;
-
- sd = script_rid2sd(st);
-
- data = &AARG(0);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- struct item_data *item_data = itemdb_searchname(name);
- if (item_data != nullptr)
- nameid = item_data->nameid;
- }
- else
- nameid = wrap<ItemNameId>(conv_num(st, data));
-
- if (nameid)
- {
- for (IOff0 i : IOff0::iter())
- {
- if (sd->status.inventory[i].nameid == nameid)
- count += sd->status.inventory[i].amount;
- }
- }
- else
- {
- if (battle_config.error_log)
- PRINTF("wrong item ID : countitem (%i)\n"_fmt, nameid);
- }
- push_int<ScriptDataInt>(st->stack, count);
-
-}
-
-/*==========================================
- * 重量チェック
- *------------------------------------------
- */
-static
-void builtin_checkweight(ScriptState *st)
-{
- ItemNameId nameid;
- int amount;
- dumb_ptr<map_session_data> sd;
- struct script_data *data;
-
- sd = script_rid2sd(st);
-
- data = &AARG(0);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- struct item_data *item_data = itemdb_searchname(name);
- if (item_data)
- nameid = item_data->nameid;
- }
- else
- nameid = wrap<ItemNameId>(conv_num(st, data));
-
- amount = conv_num(st, &AARG(1));
- if (amount <= 0 || !nameid)
- {
- //if get wrong item ID or amount<=0, don't count weight of non existing items
- push_int<ScriptDataInt>(st->stack, 0);
- return;
- }
-
- if (itemdb_weight(nameid) * amount + sd->weight > sd->max_weight)
- {
- push_int<ScriptDataInt>(st->stack, 0);
- }
- else
- {
- push_int<ScriptDataInt>(st->stack, 1);
- }
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_getitem(ScriptState *st)
-{
- ItemNameId nameid;
- int amount;
- dumb_ptr<map_session_data> sd;
- struct script_data *data;
-
- sd = script_rid2sd(st);
-
- data = &AARG(0);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- struct item_data *item_data = itemdb_searchname(name);
- if (item_data != nullptr)
- nameid = item_data->nameid;
- }
- else
- nameid = wrap<ItemNameId>(conv_num(st, data));
-
- if ((amount =
- conv_num(st, &AARG(1))) <= 0)
- {
- return; //return if amount <=0, skip the useles iteration
- }
-
- if (nameid)
- {
- Item item_tmp {};
- item_tmp.nameid = nameid;
- if (HARG(3)) //アイテムを指定したIDに渡す
- sd = map_id2sd(wrap<BlockId>(conv_num(st, &AARG(3))));
- if (sd == nullptr) //アイテムを渡す相手がいなかったらお帰り
- return;
- PickupFail flag;
- if ((flag = pc_additem(sd, &item_tmp, amount)) != PickupFail::OKAY)
- {
- clif_additem(sd, IOff0::from(0), 0, flag);
- map_addflooritem(&item_tmp, amount,
- sd->bl_m, sd->bl_x, sd->bl_y,
- nullptr, nullptr, nullptr);
- }
- }
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_makeitem(ScriptState *st)
-{
- ItemNameId nameid;
- int amount;
- int x, y;
- dumb_ptr<map_session_data> sd;
- struct script_data *data;
-
- sd = script_rid2sd(st);
-
- data = &AARG(0);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- struct item_data *item_data = itemdb_searchname(name);
- if (item_data)
- nameid = item_data->nameid;
- }
- else
- nameid = wrap<ItemNameId>(conv_num(st, data));
-
- amount = conv_num(st, &AARG(1));
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(2))));
- x = conv_num(st, &AARG(3));
- y = conv_num(st, &AARG(4));
-
- map_local *m;
- if (sd && mapname == MOB_THIS_MAP)
- m = sd->bl_m;
- else
- m = map_mapname2mapid(mapname);
-
- if (nameid)
- {
- Item item_tmp {};
- item_tmp.nameid = nameid;
-
- map_addflooritem(&item_tmp, amount, m, x, y, nullptr, nullptr, nullptr);
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_delitem(ScriptState *st)
-{
- ItemNameId nameid;
- int amount;
- dumb_ptr<map_session_data> sd;
- struct script_data *data;
-
- sd = script_rid2sd(st);
-
- data = &AARG(0);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- struct item_data *item_data = itemdb_searchname(name);
- if (item_data)
- nameid = item_data->nameid;
- }
- else
- nameid = wrap<ItemNameId>(conv_num(st, data));
-
- amount = conv_num(st, &AARG(1));
-
- if (!nameid || amount <= 0)
- {
- //by Lupus. Don't run FOR if u got wrong item ID or amount<=0
- return;
- }
-
- for (IOff0 i : IOff0::iter())
- {
- if (sd->status.inventory[i].nameid == nameid)
- {
- if (sd->status.inventory[i].amount >= amount)
- {
- pc_delitem(sd, i, amount, 0);
- break;
- }
- else
- {
- amount -= sd->status.inventory[i].amount;
- if (amount == 0)
- amount = sd->status.inventory[i].amount;
- pc_delitem(sd, i, amount, 0);
- break;
- }
- }
- }
-
-}
-
-/*==========================================
- *キャラ関係のパラメータ取得
- *------------------------------------------
- */
-static
-void builtin_readparam(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
-
- SP type = SP(conv_num(st, &AARG(0)));
- if (HARG(1))
- sd = map_nick2sd(stringish<CharName>(ZString(conv_str(st, &AARG(1)))));
- else
- sd = script_rid2sd(st);
-
- if (sd == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
-
- push_int<ScriptDataInt>(st->stack, pc_readparam(sd, type));
-
-}
-
-/*==========================================
- *キャラ関係のID取得
- *------------------------------------------
- */
-static
-void builtin_getcharid(ScriptState *st)
-{
- int num;
- dumb_ptr<map_session_data> sd;
-
- num = conv_num(st, &AARG(0));
- if (HARG(1))
- sd = map_nick2sd(stringish<CharName>(ZString(conv_str(st, &AARG(1)))));
- else
- sd = script_rid2sd(st);
- if (sd == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
- if (num == 0)
- push_int<ScriptDataInt>(st->stack, unwrap<CharId>(sd->status_key.char_id));
- if (num == 1)
- push_int<ScriptDataInt>(st->stack, unwrap<PartyId>(sd->status.party_id));
- if (num == 2)
- push_int<ScriptDataInt>(st->stack, 0/*guild_id*/);
- if (num == 3)
- push_int<ScriptDataInt>(st->stack, unwrap<AccountId>(sd->status_key.account_id));
-}
-
-/*==========================================
- *指定IDのPT名取得
- *------------------------------------------
- */
-static
-RString builtin_getpartyname_sub(PartyId party_id)
-{
- PartyPair p = party_search(party_id);
-
- if (p)
- return p->name;
-
- return RString();
-}
-
-/*==========================================
- * キャラクタの名前
- *------------------------------------------
- */
-static
-void builtin_strcharinfo(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
- int num;
-
- sd = script_rid2sd(st);
- num = conv_num(st, &AARG(0));
- if (num == 0)
- {
- RString buf = sd->status_key.name.to__actual();
- push_str<ScriptDataStr>(st->stack, buf);
- }
- if (num == 1)
- {
- RString buf = builtin_getpartyname_sub(sd->status.party_id);
- if (buf)
- push_str<ScriptDataStr>(st->stack, buf);
- else
- push_str<ScriptDataStr>(st->stack, ""_s);
- }
- if (num == 2)
- {
- // was: guild name
- push_str<ScriptDataStr>(st->stack, ""_s);
- }
-
-}
-
-// indexed by the equip_* in db/const.txt
-// TODO change to use EQUIP
-static
-Array<EPOS, 11> equip //=
-{{
- EPOS::HAT,
- EPOS::MISC1,
- EPOS::SHIELD,
- EPOS::WEAPON,
- EPOS::GLOVES,
- EPOS::SHOES,
- EPOS::CAPE,
- EPOS::MISC2,
- EPOS::TORSO,
- EPOS::LEGS,
- EPOS::ARROW,
-}};
-
-/*==========================================
- * GetEquipID(Pos); Pos: 1-10
- *------------------------------------------
- */
-static
-void builtin_getequipid(ScriptState *st)
-{
- int num;
- dumb_ptr<map_session_data> sd;
- struct item_data *item;
-
- sd = script_rid2sd(st);
- if (sd == nullptr)
- {
- PRINTF("getequipid: sd == nullptr\n"_fmt);
- return;
- }
- num = conv_num(st, &AARG(0));
- IOff0 i = pc_checkequip(sd, equip[num - 1]);
- if (i.ok())
- {
- item = sd->inventory_data[i];
- if (item)
- push_int<ScriptDataInt>(st->stack, unwrap<ItemNameId>(item->nameid));
- else
- push_int<ScriptDataInt>(st->stack, 0);
- }
- else
- {
- push_int<ScriptDataInt>(st->stack, -1);
- }
-}
-
-/*==========================================
- * 装備名文字列(精錬メニュー用)
- *------------------------------------------
- */
-static
-void builtin_getequipname(ScriptState *st)
-{
- int num;
- dumb_ptr<map_session_data> sd;
- struct item_data *item;
-
- AString buf;
-
- sd = script_rid2sd(st);
- num = conv_num(st, &AARG(0));
- IOff0 i = pc_checkequip(sd, equip[num - 1]);
- if (i.ok())
- {
- item = sd->inventory_data[i];
- if (item)
- buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], item->jname);
- else
- buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], pos_str[10]);
- }
- else
- {
- buf = STRPRINTF("%s-[%s]"_fmt, pos_str[num - 1], pos_str[10]);
- }
- push_str<ScriptDataStr>(st->stack, buf);
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_statusup2(ScriptState *st)
-{
- SP type = SP(conv_num(st, &AARG(0)));
- int val = conv_num(st, &AARG(1));
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- pc_statusup2(sd, type, val);
-
-}
-
-/*==========================================
- * 装備品による能力値ボーナス
- *------------------------------------------
- */
-static
-void builtin_bonus(ScriptState *st)
-{
- SP type = SP(conv_num(st, &AARG(0)));
- int val = conv_num(st, &AARG(1));
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- pc_bonus(sd, type, val);
-
-}
-
-/*==========================================
- * 装備品による能力値ボーナス
- *------------------------------------------
- */
-static
-void builtin_bonus2(ScriptState *st)
-{
- SP type = SP(conv_num(st, &AARG(0)));
- int type2 = conv_num(st, &AARG(1));
- int val = conv_num(st, &AARG(2));
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- pc_bonus2(sd, type, type2, val);
-
-}
-
-/*==========================================
- * スキル所得
- *------------------------------------------
- */
-static
-void builtin_skill(ScriptState *st)
-{
- int level, flag = 1;
- dumb_ptr<map_session_data> sd;
-
- SkillID id = SkillID(conv_num(st, &AARG(0)));
- level = conv_num(st, &AARG(1));
- if (HARG(2))
- flag = conv_num(st, &AARG(2));
- sd = script_rid2sd(st);
- pc_skill(sd, id, level, flag);
- clif_skillinfoblock(sd);
-
-}
-
-/*==========================================
- * [Fate] Sets the skill level permanently
- *------------------------------------------
- */
-static
-void builtin_setskill(ScriptState *st)
-{
- int level;
- dumb_ptr<map_session_data> sd;
-
- SkillID id = static_cast<SkillID>(conv_num(st, &AARG(0)));
- level = conv_num(st, &AARG(1));
- sd = script_rid2sd(st);
-
- level = std::min(level, MAX_SKILL_LEVEL);
- level = std::max(level, 0);
- sd->status.skill[id].lv = level;
- clif_skillinfoblock(sd);
-}
-
-/*==========================================
- * スキルレベル所得
- *------------------------------------------
- */
-static
-void builtin_getskilllv(ScriptState *st)
-{
- SkillID id = SkillID(conv_num(st, &AARG(0)));
- push_int<ScriptDataInt>(st->stack, pc_checkskill(script_rid2sd(st), id));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_getgmlevel(ScriptState *st)
-{
- push_int<ScriptDataInt>(st->stack, pc_isGM(script_rid2sd(st)).get_all_bits());
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_end(ScriptState *st)
-{
- st->state = ScriptEndState::END;
-}
-
-/*==========================================
- * [Freeyorp] Return the current opt2
- *------------------------------------------
- */
-
-static
-void builtin_getopt2(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
-
- sd = script_rid2sd(st);
-
- push_int<ScriptDataInt>(st->stack, static_cast<uint16_t>(sd->opt2));
-
-}
-
-/*==========================================
- * [Freeyorp] Sets opt2
- *------------------------------------------
- */
-
-static
-void builtin_setopt2(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
-
- Opt2 new_opt2 = Opt2(conv_num(st, &AARG(0)));
- sd = script_rid2sd(st);
- if (new_opt2 == sd->opt2)
- return;
- sd->opt2 = new_opt2;
- clif_changeoption(sd);
- pc_calcstatus(sd, 0);
-
-}
-
-/*==========================================
- * セーブポイントの保存
- *------------------------------------------
- */
-static
-void builtin_savepoint(ScriptState *st)
-{
- int x, y;
-
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x = conv_num(st, &AARG(1));
- y = conv_num(st, &AARG(2));
- pc_setsavepoint(script_rid2sd(st), str, x, y);
-}
-
-/*==========================================
- * gettimetick(type)
- *
- * type The type of time measurement.
- * Specify 0 for the system tick, 1 for
- * seconds elapsed today, or 2 for seconds
- * since Unix epoch. Defaults to 0 for any
- * other value.
- *------------------------------------------
- */
-static
-void builtin_gettimetick(ScriptState *st) /* Asgard Version */
-{
- int type;
- type = conv_num(st, &AARG(0));
-
- switch (type)
- {
- /* Number of seconds elapsed today(0-86399, 00:00:00-23:59:59). */
- case 1:
- {
- struct tm t = TimeT::now();
- push_int<ScriptDataInt>(st->stack,
- t.tm_hour * 3600 + t.tm_min * 60 + t.tm_sec);
- break;
- }
- /* Seconds since Unix epoch. */
- case 2:
- push_int<ScriptDataInt>(st->stack, static_cast<time_t>(TimeT::now()));
- break;
- /* System tick(unsigned int, and yes, it will wrap). */
- case 0:
- default:
- push_int<ScriptDataInt>(st->stack, gettick().time_since_epoch().count());
- break;
- }
-}
-
-/*==========================================
- * GetTime(Type);
- * 1: Sec 2: Min 3: Hour
- * 4: WeekDay 5: MonthDay 6: Month
- * 7: Year
- *------------------------------------------
- */
-static
-void builtin_gettime(ScriptState *st) /* Asgard Version */
-{
- int type = conv_num(st, &AARG(0));
-
- struct tm t = TimeT::now();
-
- switch (type)
- {
- case 1: //Sec(0~59)
- push_int<ScriptDataInt>(st->stack, t.tm_sec);
- break;
- case 2: //Min(0~59)
- push_int<ScriptDataInt>(st->stack, t.tm_min);
- break;
- case 3: //Hour(0~23)
- push_int<ScriptDataInt>(st->stack, t.tm_hour);
- break;
- case 4: //WeekDay(0~6)
- push_int<ScriptDataInt>(st->stack, t.tm_wday);
- break;
- case 5: //MonthDay(01~31)
- push_int<ScriptDataInt>(st->stack, t.tm_mday);
- break;
- case 6: //Month(01~12)
- push_int<ScriptDataInt>(st->stack, t.tm_mon + 1);
- break;
- case 7: //Year(20xx)
- push_int<ScriptDataInt>(st->stack, t.tm_year + 1900);
- break;
- default: //(format error)
- push_int<ScriptDataInt>(st->stack, -1);
- break;
- }
-}
-
-/*==========================================
- * カプラ倉庫を開く
- *------------------------------------------
- */
-static
-void builtin_openstorage(ScriptState *st)
-{
-// int sync = 0;
-// if (st->end >= 3) sync = conv_num(st,& (st->stack->stack_data[st->start+2]));
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
-// if (sync) {
- st->state = ScriptEndState::STOP;
- sd->npc_flags.storage = 1;
-// } else st->state = ScriptEndState::END;
-
- storage_storageopen(sd);
-}
-
-/*==========================================
- * NPCで経験値上げる
- *------------------------------------------
- */
-static
-void builtin_getexp(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- int base = 0, job = 0;
-
- base = conv_num(st, &AARG(0));
- job = conv_num(st, &AARG(1));
- if (base < 0 || job < 0)
- return;
- if (sd)
- pc_gainexp_reason(sd, base, job, PC_GAINEXP_REASON::SCRIPT);
-
-}
-
-/*==========================================
- * モンスター発生
- *------------------------------------------
- */
-static
-void builtin_monster(ScriptState *st)
-{
- Species mob_class;
- int amount, x, y;
- NpcEvent event;
-
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x = conv_num(st, &AARG(1));
- y = conv_num(st, &AARG(2));
- MobName str = stringish<MobName>(ZString(conv_str(st, &AARG(3))));
- mob_class = wrap<Species>(conv_num(st, &AARG(4)));
- amount = conv_num(st, &AARG(5));
- if (HARG(6))
- extract(ZString(conv_str(st, &AARG(6))), &event);
-
- mob_once_spawn(map_id2sd(st->rid), mapname, x, y, str, mob_class, amount,
- event);
-}
-
-/*==========================================
- * モンスター発生
- *------------------------------------------
- */
-static
-void builtin_areamonster(ScriptState *st)
-{
- Species mob_class;
- int amount, x0, y0, x1, y1;
- NpcEvent event;
-
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x0 = conv_num(st, &AARG(1));
- y0 = conv_num(st, &AARG(2));
- x1 = conv_num(st, &AARG(3));
- y1 = conv_num(st, &AARG(4));
- MobName str = stringish<MobName>(ZString(conv_str(st, &AARG(5))));
- mob_class = wrap<Species>(conv_num(st, &AARG(6)));
- amount = conv_num(st, &AARG(7));
- if (HARG(8))
- extract(ZString(conv_str(st, &AARG(8))), &event);
-
- mob_once_spawn_area(map_id2sd(st->rid), mapname, x0, y0, x1, y1, str, mob_class,
- amount, event);
-}
-
-/*==========================================
- * モンスター削除
- *------------------------------------------
- */
-static
-void builtin_killmonster_sub(dumb_ptr<block_list> bl, NpcEvent event)
-{
- dumb_ptr<mob_data> md = bl->is_mob();
- if (event)
- {
- if (event == md->npc_event)
- mob_delete(md);
- return;
- }
- else if (!event)
- {
- if (md->spawn.delay1 == static_cast<interval_t>(-1)
- && md->spawn.delay2 == static_cast<interval_t>(-1))
- mob_delete(md);
- return;
- }
-}
-
-static
-void builtin_killmonster(ScriptState *st)
-{
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- ZString event_ = ZString(conv_str(st, &AARG(1)));
- NpcEvent event;
- if (event_ != "All"_s)
- extract(event_, &event);
-
- map_local *m = map_mapname2mapid(mapname);
- if (m == nullptr)
- return;
- map_foreachinarea(std::bind(builtin_killmonster_sub, ph::_1, event),
- m,
- 0, 0,
- m->xs, m->ys,
- BL::MOB);
-}
-
-static
-void builtin_killmonsterall_sub(dumb_ptr<block_list> bl)
-{
- mob_delete(bl->is_mob());
-}
-
-static
-void builtin_killmonsterall(ScriptState *st)
-{
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
-
- map_local *m = map_mapname2mapid(mapname);
- if (m == nullptr)
- return;
- map_foreachinarea(builtin_killmonsterall_sub,
- m,
- 0, 0,
- m->xs, m->ys,
- BL::MOB);
-}
-
-/*==========================================
- * NPC主体イベント実行
- *------------------------------------------
- */
-static
-void builtin_donpcevent(ScriptState *st)
-{
- ZString event_ = ZString(conv_str(st, &AARG(0)));
- NpcEvent event;
- extract(event_, &event);
- npc_event_do(event);
-}
-
-/*==========================================
- * イベントタイマー追加
- *------------------------------------------
- */
-static
-void builtin_addtimer(ScriptState *st)
-{
- interval_t tick = static_cast<interval_t>(conv_num(st, &AARG(0)));
- ZString event_ = ZString(conv_str(st, &AARG(1)));
- NpcEvent event;
- extract(event_, &event);
- pc_addeventtimer(script_rid2sd(st), tick, event);
-}
-
-/*==========================================
- * NPCタイマー初期化
- *------------------------------------------
- */
-static
-void builtin_initnpctimer(ScriptState *st)
-{
- dumb_ptr<npc_data> nd_;
- if (HARG(0))
- nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARG(0)))));
- else
- nd_ = map_id_is_npc(st->oid);
- assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT);
- dumb_ptr<npc_data_script> nd = nd_->is_script();
-
- npc_settimerevent_tick(nd, interval_t::zero());
- npc_timerevent_start(nd);
-}
-
-/*==========================================
- * NPCタイマー開始
- *------------------------------------------
- */
-static
-void builtin_startnpctimer(ScriptState *st)
-{
- dumb_ptr<npc_data> nd_;
- if (HARG(0))
- nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARG(0)))));
- else
- nd_ = map_id_is_npc(st->oid);
- assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT);
- dumb_ptr<npc_data_script> nd = nd_->is_script();
-
- npc_timerevent_start(nd);
-}
-
-/*==========================================
- * NPCタイマー停止
- *------------------------------------------
- */
-static
-void builtin_stopnpctimer(ScriptState *st)
-{
- dumb_ptr<npc_data> nd_;
- if (HARG(0))
- nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARG(0)))));
- else
- nd_ = map_id_is_npc(st->oid);
- assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT);
- dumb_ptr<npc_data_script> nd = nd_->is_script();
-
- npc_timerevent_stop(nd);
-}
-
-/*==========================================
- * NPCタイマー情報所得
- *------------------------------------------
- */
-static
-void builtin_getnpctimer(ScriptState *st)
-{
- dumb_ptr<npc_data> nd_;
- int type = conv_num(st, &AARG(0));
- int val = 0;
- if (HARG(1))
- nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARG(1)))));
- else
- nd_ = map_id_is_npc(st->oid);
- assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT);
- dumb_ptr<npc_data_script> nd = nd_->is_script();
-
- switch (type)
- {
- case 0:
- val = npc_gettimerevent_tick(nd).count();
- break;
- case 1:
- val = nd->scr.timer_active;
- break;
- case 2:
- val = nd->scr.timer_eventv.size();
- break;
- }
- push_int<ScriptDataInt>(st->stack, val);
-}
-
-/*==========================================
- * NPCタイマー値設定
- *------------------------------------------
- */
-static
-void builtin_setnpctimer(ScriptState *st)
-{
- dumb_ptr<npc_data> nd_;
- interval_t tick = static_cast<interval_t>(conv_num(st, &AARG(0)));
- if (HARG(1))
- nd_ = npc_name2id(stringish<NpcName>(ZString(conv_str(st, &AARG(1)))));
- else
- nd_ = map_id_is_npc(st->oid);
- assert (nd_ && nd_->npc_subtype == NpcSubtype::SCRIPT);
- dumb_ptr<npc_data_script> nd = nd_->is_script();
-
- npc_settimerevent_tick(nd, tick);
-}
-
-/*==========================================
- * 天の声アナウンス
- *------------------------------------------
- */
-static
-void builtin_announce(ScriptState *st)
-{
- int flag;
- ZString str = ZString(conv_str(st, &AARG(0)));
- flag = conv_num(st, &AARG(1));
-
- if (flag & 0x0f)
- {
- dumb_ptr<block_list> bl;
- if (flag & 0x08)
- bl = map_id2bl(st->oid);
- else
- bl = script_rid2sd(st);
- clif_GMmessage(bl, str, flag);
- }
- else
- intif_GMmessage(str);
-}
-
-/*==========================================
- * 天の声アナウンス(特定マップ)
- *------------------------------------------
- */
-static
-void builtin_mapannounce_sub(dumb_ptr<block_list> bl, XString str, int flag)
-{
- clif_GMmessage(bl, str, flag | 3);
-}
-
-static
-void builtin_mapannounce(ScriptState *st)
-{
- int flag;
-
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- ZString str = ZString(conv_str(st, &AARG(1)));
- flag = conv_num(st, &AARG(2));
-
- map_local *m = map_mapname2mapid(mapname);
- if (m == nullptr)
- return;
- map_foreachinarea(std::bind(builtin_mapannounce_sub, ph::_1, str, flag & 0x10),
- m,
- 0, 0,
- m->xs, m->ys,
- BL::PC);
-}
-
-/*==========================================
- * ユーザー数所得
- *------------------------------------------
- */
-static
-void builtin_getusers(ScriptState *st)
-{
- int flag = conv_num(st, &AARG(0));
- dumb_ptr<block_list> bl = map_id2bl((flag & 0x08) ? st->oid : st->rid);
- int val = 0;
- switch (flag & 0x07)
- {
- case 0:
- val = bl->bl_m->users;
- break;
- case 1:
- val = map_getusers();
- break;
- }
- push_int<ScriptDataInt>(st->stack, val);
-}
-
-/*==========================================
- * マップ指定ユーザー数所得
- *------------------------------------------
- */
-static
-void builtin_getmapusers(ScriptState *st)
-{
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- map_local *m = map_mapname2mapid(str);
- if (m == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
- push_int<ScriptDataInt>(st->stack, m->users);
-}
-
-/*==========================================
- * エリア指定ユーザー数所得
- *------------------------------------------
- */
-static
-void builtin_getareausers_sub(dumb_ptr<block_list> bl, int *users)
-{
- if (bool(bl->is_player()->status.option & Opt0::HIDE))
- return;
- (*users)++;
-}
-
-static
-void builtin_getareausers_living_sub(dumb_ptr<block_list> bl, int *users)
-{
- if (bool(bl->is_player()->status.option & Opt0::HIDE))
- return;
- if (!pc_isdead(bl->is_player()))
- (*users)++;
-}
-
-static
-void builtin_getareausers(ScriptState *st)
-{
- int x0, y0, x1, y1, users = 0;
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x0 = conv_num(st, &AARG(1));
- y0 = conv_num(st, &AARG(2));
- x1 = conv_num(st, &AARG(3));
- y1 = conv_num(st, &AARG(4));
-
- int living = 0;
- if (HARG(5))
- {
- living = conv_num(st, &AARG(5));
- }
- map_local *m = map_mapname2mapid(str);
- if (m == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
- map_foreachinarea(std::bind(living ? builtin_getareausers_living_sub: builtin_getareausers_sub, ph::_1, &users),
- m,
- x0, y0,
- x1, y1,
- BL::PC);
- push_int<ScriptDataInt>(st->stack, users);
-}
-
-/*==========================================
- * エリア指定ドロップアイテム数所得
- *------------------------------------------
- */
-static
-void builtin_getareadropitem_sub(dumb_ptr<block_list> bl, ItemNameId item, int *amount)
-{
- dumb_ptr<flooritem_data> drop = bl->is_item();
-
- if (drop->item_data.nameid == item)
- (*amount) += drop->item_data.amount;
-
-}
-
-static
-void builtin_getareadropitem_sub_anddelete(dumb_ptr<block_list> bl, ItemNameId item, int *amount)
-{
- dumb_ptr<flooritem_data> drop = bl->is_item();
-
- if (drop->item_data.nameid == item)
- {
- (*amount) += drop->item_data.amount;
- clif_clearflooritem(drop, nullptr);
- map_delobject(drop->bl_id, drop->bl_type);
- }
-}
-
-static
-void builtin_getareadropitem(ScriptState *st)
-{
- ItemNameId item;
- int x0, y0, x1, y1, amount = 0, delitems = 0;
- struct script_data *data;
-
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x0 = conv_num(st, &AARG(1));
- y0 = conv_num(st, &AARG(2));
- x1 = conv_num(st, &AARG(3));
- y1 = conv_num(st, &AARG(4));
-
- data = &AARG(5);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- struct item_data *item_data = itemdb_searchname(name);
- if (item_data)
- item = item_data->nameid;
- }
- else
- item = wrap<ItemNameId>(conv_num(st, data));
-
- if (HARG(6))
- delitems = conv_num(st, &AARG(6));
-
- map_local *m = map_mapname2mapid(str);
- if (m == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
- if (delitems)
- map_foreachinarea(std::bind(builtin_getareadropitem_sub_anddelete, ph::_1, item, &amount),
- m,
- x0, y0,
- x1, y1,
- BL::ITEM);
- else
- map_foreachinarea(std::bind(builtin_getareadropitem_sub, ph::_1, item, &amount),
- m,
- x0, y0,
- x1, y1,
- BL::ITEM);
-
- push_int<ScriptDataInt>(st->stack, amount);
-}
-
-/*==========================================
- * NPCの有効化
- *------------------------------------------
- */
-static
-void builtin_enablenpc(ScriptState *st)
-{
- NpcName str = stringish<NpcName>(ZString(conv_str(st, &AARG(0))));
- npc_enable(str, 1);
-}
-
-/*==========================================
- * NPCの無効化
- *------------------------------------------
- */
-static
-void builtin_disablenpc(ScriptState *st)
-{
- NpcName str = stringish<NpcName>(ZString(conv_str(st, &AARG(0))));
- npc_enable(str, 0);
-}
-
-/*==========================================
- * 状態異常にかかる
- *------------------------------------------
- */
-static
-void builtin_sc_start(ScriptState *st)
-{
- dumb_ptr<block_list> bl;
- int val1;
- StatusChange type = static_cast<StatusChange>(conv_num(st, &AARG(0)));
- interval_t tick = static_cast<interval_t>(conv_num(st, &AARG(1)));
- if (tick < 1_s)
- // work around old behaviour of:
- // speed potion
- // atk potion
- // matk potion
- //
- // which used to use seconds
- // all others used milliseconds
- tick *= 1000;
- val1 = conv_num(st, &AARG(2));
- if (HARG(3)) //指定したキャラを状態異常にする
- bl = map_id2bl(wrap<BlockId>(conv_num(st, &AARG(3))));
- else
- bl = map_id2bl(st->rid);
- skill_status_change_start(bl, type, val1, tick);
-}
-
-/*==========================================
- * 状態異常が直る
- *------------------------------------------
- */
-static
-void builtin_sc_end(ScriptState *st)
-{
- dumb_ptr<block_list> bl;
- StatusChange type = StatusChange(conv_num(st, &AARG(0)));
- bl = map_id2bl(st->rid);
- skill_status_change_end(bl, type, nullptr);
-}
-
-static
-void builtin_sc_check(ScriptState *st)
-{
- dumb_ptr<block_list> bl;
- StatusChange type = StatusChange(conv_num(st, &AARG(0)));
- bl = map_id2bl(st->rid);
-
- push_int<ScriptDataInt>(st->stack, skill_status_change_active(bl, type));
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_debugmes(ScriptState *st)
-{
- RString mes = conv_str(st, &AARG(0));
- PRINTF("script debug : %d %d : %s\n"_fmt,
- st->rid, st->oid, mes);
-}
-
-/*==========================================
- * ステータスリセット
- *------------------------------------------
- */
-static
-void builtin_resetstatus(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
- sd = script_rid2sd(st);
- pc_resetstate(sd);
-}
-
-/*==========================================
- * 性別変換
- *------------------------------------------
- */
-static
-void builtin_changesex(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = nullptr;
- sd = script_rid2sd(st);
-
- chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff()); // type: 5 - changesex
- chrif_save(sd);
-}
-
-/*==========================================
- * RIDのアタッチ
- *------------------------------------------
- */
-static
-void builtin_attachrid(ScriptState *st)
-{
- st->rid = wrap<BlockId>(conv_num(st, &AARG(0)));
- push_int<ScriptDataInt>(st->stack, (map_id2sd(st->rid) != nullptr));
-}
-
-/*==========================================
- * RIDのデタッチ
- *------------------------------------------
- */
-static
-void builtin_detachrid(ScriptState *st)
-{
- st->rid = BlockId();
-}
-
-/*==========================================
- * 存在チェック
- *------------------------------------------
- */
-static
-void builtin_isloggedin(ScriptState *st)
-{
- push_int<ScriptDataInt>(st->stack,
- map_id2sd(wrap<BlockId>(conv_num(st, &AARG(0)))) != nullptr);
-}
-
-static
-void builtin_setmapflag(ScriptState *st)
-{
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- int i = conv_num(st, &AARG(1));
- MapFlag mf = map_flag_from_int(i);
- map_local *m = map_mapname2mapid(str);
- if (m != nullptr)
- {
- m->flag.set(mf, 1);
- }
-}
-
-static
-void builtin_removemapflag(ScriptState *st)
-{
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- int i = conv_num(st, &AARG(1));
- MapFlag mf = map_flag_from_int(i);
- map_local *m = map_mapname2mapid(str);
- if (m != nullptr)
- {
- m->flag.set(mf, 0);
- }
-}
-
-static
-void builtin_getmapflag(ScriptState *st)
-{
- int r = -1;
-
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- int i = conv_num(st, &AARG(1));
- MapFlag mf = map_flag_from_int(i);
- map_local *m = map_mapname2mapid(str);
- if (m != nullptr)
- {
- r = m->flag.get(mf);
- }
-
- push_int<ScriptDataInt>(st->stack, r);
-}
-
-static
-void builtin_pvpon(ScriptState *st)
-{
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- map_local *m = map_mapname2mapid(str);
- if (m != nullptr && !m->flag.get(MapFlag::PVP) && !m->flag.get(MapFlag::NOPVP))
- {
- m->flag.set(MapFlag::PVP, 1);
-
- if (battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris]
- return;
-
- for (io::FD i : iter_fds())
- {
- Session *s = get_session(i);
- if (!s)
- continue;
- map_session_data *pl_sd = static_cast<map_session_data *>(s->session_data.get());
- if (pl_sd && pl_sd->state.auth)
- {
- if (m == pl_sd->bl_m && !pl_sd->pvp_timer)
- {
- pl_sd->pvp_timer = Timer(gettick() + 200_ms,
- std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2,
- pl_sd->bl_id));
- pl_sd->pvp_rank = 0;
- pl_sd->pvp_point = 5;
- }
- }
- }
- }
-
-}
-
-static
-void builtin_pvpoff(ScriptState *st)
-{
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- map_local *m = map_mapname2mapid(str);
- if (m != nullptr && m->flag.get(MapFlag::PVP) && m->flag.get(MapFlag::NOPVP))
- {
- m->flag.set(MapFlag::PVP, 0);
-
- if (battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris]
- return;
-
- for (io::FD i : iter_fds())
- {
- Session *s = get_session(i);
- if (!s)
- continue;
- map_session_data *pl_sd = static_cast<map_session_data *>(s->session_data.get());
- if (pl_sd && pl_sd->state.auth)
- {
- if (m == pl_sd->bl_m)
- {
- pl_sd->pvp_timer.cancel();
- }
- }
- }
- }
-
-}
-
-/*==========================================
- * NPCエモーション
- *------------------------------------------
- */
-
-static
-void builtin_emotion(ScriptState *st)
-{
- int type;
- type = conv_num(st, &AARG(0));
- if (type < 0 || type > 100)
- return;
- clif_emotion(map_id2bl(st->oid), type);
-}
-
-static
-void builtin_mapwarp(ScriptState *st) // Added by RoVeRT
-{
- int x, y;
- int x0, y0, x1, y1;
-
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x0 = 0;
- y0 = 0;
- map_local *m = map_mapname2mapid(mapname);
- x1 = m->xs;
- y1 = m->ys;
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(1))));
- x = conv_num(st, &AARG(2));
- y = conv_num(st, &AARG(3));
-
- if (m == nullptr)
- return;
-
- map_foreachinarea(std::bind(builtin_areawarp_sub, ph::_1, str, x, y),
- m,
- x0, y0,
- x1, y1,
- BL::PC);
-}
-
-static
-void builtin_cmdothernpc(ScriptState *st) // Added by RoVeRT
-{
- NpcName npc = stringish<NpcName>(ZString(conv_str(st, &AARG(0))));
- ZString command = ZString(conv_str(st, &AARG(1)));
-
- npc_command(map_id2sd(st->rid), npc, command);
-}
-
-static
-void builtin_mobcount_sub(dumb_ptr<block_list> bl, NpcEvent event, int *c)
-{
- if (event == bl->is_mob()->npc_event)
- (*c)++;
-}
-
-static
-void builtin_mobcount(ScriptState *st) // Added by RoVeRT
-{
- int c = 0;
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- ZString event_ = ZString(conv_str(st, &AARG(1)));
- NpcEvent event;
- extract(event_, &event);
-
- map_local *m = map_mapname2mapid(mapname);
- if (m == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
- map_foreachinarea(std::bind(builtin_mobcount_sub, ph::_1, event, &c),
- m,
- 0, 0,
- m->xs, m->ys,
- BL::MOB);
-
- push_int<ScriptDataInt>(st->stack, (c - 1));
-
-}
-
-static
-void builtin_marriage(ScriptState *st)
-{
- CharName partner = stringish<CharName>(ZString(conv_str(st, &AARG(0))));
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- dumb_ptr<map_session_data> p_sd = map_nick2sd(partner);
-
- if (sd == nullptr || p_sd == nullptr || pc_marriage(sd, p_sd) < 0)
- {
- push_int<ScriptDataInt>(st->stack, 0);
- return;
- }
- push_int<ScriptDataInt>(st->stack, 1);
-}
-
-static
-void builtin_divorce(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- st->state = ScriptEndState::STOP; // rely on pc_divorce to restart
-
- sd->npc_flags.divorce = 1;
-
- if (sd == nullptr || pc_divorce(sd) < 0)
- {
- push_int<ScriptDataInt>(st->stack, 0);
- return;
- }
-
- push_int<ScriptDataInt>(st->stack, 1);
-}
-
-/*==========================================
- * IDからItem名
- *------------------------------------------
- */
-static
-void builtin_getitemname(ScriptState *st)
-{
- struct item_data *i_data;
- struct script_data *data;
-
- data = &AARG(0);
- get_val(st, data);
- if (data->is<ScriptDataStr>())
- {
- ZString name = ZString(conv_str(st, data));
- i_data = itemdb_searchname(name);
- }
- else
- {
- ItemNameId item_id = wrap<ItemNameId>(conv_num(st, data));
- i_data = itemdb_search(item_id);
- }
-
- RString item_name;
- if (i_data)
- item_name = i_data->jname;
- else
- item_name = "Unknown Item"_s;
-
- push_str<ScriptDataStr>(st->stack, item_name);
-}
-
-static
-void builtin_getspellinvocation(ScriptState *st)
-{
- RString name = conv_str(st, &AARG(0));
-
- AString invocation = magic::magic_find_invocation(name);
- if (!invocation)
- invocation = "..."_s;
-
- push_str<ScriptDataStr>(st->stack, invocation);
-}
-
-static
-void builtin_getpartnerid2(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- push_int<ScriptDataInt>(st->stack, unwrap<CharId>(sd->status.partner_id));
-}
-
-/*==========================================
- * PCの所持品情報読み取り
- *------------------------------------------
- */
-static
-void builtin_getinventorylist(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- int j = 0;
- if (!sd)
- return;
- for (IOff0 i : IOff0::iter())
- {
- if (sd->status.inventory[i].nameid
- && sd->status.inventory[i].amount > 0)
- {
- pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_id"_s), j),
- unwrap<ItemNameId>(sd->status.inventory[i].nameid));
- pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_amount"_s), j),
- sd->status.inventory[i].amount);
- pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_equip"_s), j),
- static_cast<uint16_t>(sd->status.inventory[i].equip));
- j++;
- }
- }
- pc_setreg(sd, SIR::from(variable_names.intern("@inventorylist_count"_s)), j);
-}
-
-static
-void builtin_getactivatedpoolskilllist(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- SkillID pool_skills[MAX_SKILL_POOL];
- int skill_pool_size = skill_pool(sd, pool_skills);
- int i, count = 0;
-
- if (!sd)
- return;
-
- for (i = 0; i < skill_pool_size; i++)
- {
- SkillID skill_id = pool_skills[i];
-
- if (sd->status.skill[skill_id].lv)
- {
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_id"_s), count),
- static_cast<uint16_t>(skill_id));
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_lv"_s), count),
- sd->status.skill[skill_id].lv);
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"_s), count),
- static_cast<uint16_t>(sd->status.skill[skill_id].flags));
- pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"_s), count),
- skill_name(skill_id));
- ++count;
- }
- }
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_count"_s)), count);
-
-}
-
-static
-void builtin_getunactivatedpoolskilllist(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- int i, count = 0;
-
- if (!sd)
- return;
-
- for (i = 0; i < skill_pool_skills_size; i++)
- {
- SkillID skill_id = skill_pool_skills[i];
-
- if (sd->status.skill[skill_id].lv
- && !bool(sd->status.skill[skill_id].flags & SkillFlags::POOL_ACTIVATED))
- {
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_id"_s), count),
- static_cast<uint16_t>(skill_id));
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_lv"_s), count),
- sd->status.skill[skill_id].lv);
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_flag"_s), count),
- static_cast<uint16_t>(sd->status.skill[skill_id].flags));
- pc_setregstr(sd, SIR::from(variable_names.intern("@skilllist_name$"_s), count),
- skill_name(skill_id));
- ++count;
- }
- }
- pc_setreg(sd, SIR::from(variable_names.intern("@skilllist_count"_s)), count);
-}
-
-static
-void builtin_poolskill(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- SkillID skill_id = SkillID(conv_num(st, &AARG(0)));
-
- skill_pool_activate(sd, skill_id);
- clif_skillinfoblock(sd);
-
-}
-
-static
-void builtin_unpoolskill(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- SkillID skill_id = SkillID(conv_num(st, &AARG(0)));
-
- skill_pool_deactivate(sd, skill_id);
- clif_skillinfoblock(sd);
-
-}
-
-/*==========================================
- * NPCから発生するエフェクト
- * misceffect(effect, [target])
- *
- * effect The effect type/ID.
- * target The player name or being ID on
- * which to display the effect. If not
- * specified, it attempts to default to
- * the current NPC or invoking PC.
- *------------------------------------------
- */
-static
-void builtin_misceffect(ScriptState *st)
-{
- int type;
- BlockId id;
- CharName name;
- dumb_ptr<block_list> bl = nullptr;
-
- type = conv_num(st, &AARG(0));
-
- if (HARG(1))
- {
- struct script_data *sdata = &AARG(1);
-
- get_val(st, sdata);
-
- if (sdata->is<ScriptDataStr>())
- name = stringish<CharName>(ZString(conv_str(st, sdata)));
- else
- id = wrap<BlockId>(conv_num(st, sdata));
- }
-
- if (name.to__actual())
- {
- dumb_ptr<map_session_data> sd = map_nick2sd(name);
- if (sd)
- bl = sd;
- }
- else if (id)
- bl = map_id2bl(id);
- else if (st->oid)
- bl = map_id2bl(st->oid);
- else
- {
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- if (sd)
- bl = sd;
- }
-
- if (bl)
- clif_misceffect(bl, type);
-
-}
-
-/*==========================================
- * Special effects [Valaris]
- *------------------------------------------
- */
-static
-void builtin_specialeffect(ScriptState *st)
-{
- dumb_ptr<block_list> bl = map_id2bl(st->oid);
-
- if (bl == nullptr)
- return;
-
- clif_specialeffect(bl,
- conv_num(st,
- &AARG(0)),
- 0);
-
-}
-
-static
-void builtin_specialeffect2(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- if (sd == nullptr)
- return;
-
- clif_specialeffect(sd,
- conv_num(st,
- &AARG(0)),
- 0);
-
-}
-
-/*==========================================
- * Nude [Valaris]
- *------------------------------------------
- */
-
-static
-void builtin_nude(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- if (sd == nullptr)
- return;
-
- for (EQUIP i : EQUIPs)
- {
- IOff0 idx = sd->equip_index_maybe[i];
- if (idx.ok())
- pc_unequipitem(sd, idx, CalcStatus::LATER);
- }
- pc_calcstatus(sd, 0);
-
-}
-
-/*==========================================
- * UnequipById [Freeyorp]
- *------------------------------------------
- */
-
-static
-void builtin_unequipbyid(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- if (sd == nullptr)
- return;
-
- EQUIP slot_id = EQUIP(conv_num(st, &AARG(0)));
-
- if (slot_id >= EQUIP() && slot_id < EQUIP::COUNT)
- {
- IOff0 idx = sd->equip_index_maybe[slot_id];
- if (idx.ok())
- pc_unequipitem(sd, idx, CalcStatus::LATER);
- }
-
- pc_calcstatus(sd, 0);
-
-}
-
-/*==========================================
- * gmcommand [MouseJstr]
- *
- * suggested on the forums...
- *------------------------------------------
- */
-
-static
-void builtin_gmcommand(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
-
- sd = script_rid2sd(st);
- RString cmd = conv_str(st, &AARG(0));
-
- is_atcommand(sd->sess, sd, cmd, GmLevel::from(-1U));
-
-}
-
-/*==========================================
- * npcwarp [remoitnane]
- * Move NPC to a new position on the same map.
- *------------------------------------------
- */
-static
-void builtin_npcwarp(ScriptState *st)
-{
- int x, y;
- dumb_ptr<npc_data> nd = nullptr;
-
- x = conv_num(st, &AARG(0));
- y = conv_num(st, &AARG(1));
- NpcName npc = stringish<NpcName>(ZString(conv_str(st, &AARG(2))));
- nd = npc_name2id(npc);
-
- if (!nd)
- {
- PRINTF("builtin_npcwarp: no such npc: %s\n"_fmt, npc);
- return;
- }
-
- map_local *m = nd->bl_m;
-
- /* Crude sanity checks. */
- if (m == nullptr || !nd->bl_prev
- || x < 0 || x > m->xs -1
- || y < 0 || y > m->ys - 1)
- return;
-
- npc_enable(npc, 0);
- map_delblock(nd); /* [Freeyorp] */
- nd->bl_x = x;
- nd->bl_y = y;
- map_addblock(nd);
- npc_enable(npc, 1);
-
-}
-
-/*==========================================
- * message [MouseJstr]
- *------------------------------------------
- */
-
-static
-void builtin_message(ScriptState *st)
-{
- CharName player = stringish<CharName>(ZString(conv_str(st, &AARG(0))));
- ZString msg = ZString(conv_str(st, &AARG(1)));
-
- dumb_ptr<map_session_data> pl_sd = map_nick2sd(player);
- if (pl_sd == nullptr)
- return;
- clif_displaymessage(pl_sd->sess, msg);
-
-}
-
-/*==========================================
- * npctalk (sends message to surrounding
- * area) [Valaris]
- *------------------------------------------
- */
-
-static
-void builtin_npctalk(ScriptState *st)
-{
- dumb_ptr<npc_data> nd = map_id_is_npc(st->oid);
- RString str = conv_str(st, &AARG(0));
-
- if (nd)
- {
- clif_message(nd, str);
- }
-}
-
-/*==========================================
- * getlook char info. getlook(arg)
- *------------------------------------------
- */
-static
-void builtin_getlook(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- LOOK type = LOOK(conv_num(st, &AARG(0)));
- int val = -1;
- switch (type)
- {
- case LOOK::HAIR: //1
- val = sd->status.hair;
- break;
- case LOOK::WEAPON: //2
- val = static_cast<uint16_t>(sd->status.weapon);
- break;
- case LOOK::HEAD_BOTTOM: //3
- val = unwrap<ItemNameId>(sd->status.head_bottom);
- break;
- case LOOK::HEAD_TOP: //4
- val = unwrap<ItemNameId>(sd->status.head_top);
- break;
- case LOOK::HEAD_MID: //5
- val = unwrap<ItemNameId>(sd->status.head_mid);
- break;
- case LOOK::HAIR_COLOR: //6
- val = sd->status.hair_color;
- break;
- case LOOK::CLOTHES_COLOR: //7
- val = sd->status.clothes_color;
- break;
- case LOOK::SHIELD: //8
- val = unwrap<ItemNameId>(sd->status.shield);
- break;
- case LOOK::SHOES: //9
- break;
- }
-
- push_int<ScriptDataInt>(st->stack, val);
-}
-
-/*==========================================
- * get char save point. argument: 0- map name, 1- x, 2- y
- *------------------------------------------
-*/
-static
-void builtin_getsavepoint(ScriptState *st)
-{
- int x, y, type;
- dumb_ptr<map_session_data> sd;
-
- sd = script_rid2sd(st);
-
- type = conv_num(st, &AARG(0));
-
- x = sd->status.save_point.x;
- y = sd->status.save_point.y;
- switch (type)
- {
- case 0:
- {
- RString mapname = sd->status.save_point.map_;
- push_str<ScriptDataStr>(st->stack, mapname);
- }
- break;
- case 1:
- push_int<ScriptDataInt>(st->stack, x);
- break;
- case 2:
- push_int<ScriptDataInt>(st->stack, y);
- break;
- }
-}
-
-/*==========================================
- * areatimer
- *------------------------------------------
- */
-static
-void builtin_areatimer_sub(dumb_ptr<block_list> bl, interval_t tick, NpcEvent event)
-{
- pc_addeventtimer(bl->is_player(), tick, event);
-}
-
-static
-void builtin_areatimer(ScriptState *st)
-{
- int x0, y0, x1, y1;
-
- MapName mapname = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x0 = conv_num(st, &AARG(1));
- y0 = conv_num(st, &AARG(2));
- x1 = conv_num(st, &AARG(3));
- y1 = conv_num(st, &AARG(4));
- interval_t tick = static_cast<interval_t>(conv_num(st, &AARG(5)));
- ZString event_ = ZString(conv_str(st, &AARG(6)));
- NpcEvent event;
- extract(event_, &event);
-
- map_local *m = map_mapname2mapid(mapname);
- if (m == nullptr)
- return;
-
- map_foreachinarea(std::bind(builtin_areatimer_sub, ph::_1, tick, event),
- m,
- x0, y0,
- x1, y1,
- BL::PC);
-}
-
-/*==========================================
- * Check whether the PC is in the specified rectangle
- *------------------------------------------
- */
-static
-void builtin_isin(ScriptState *st)
-{
- int x1, y1, x2, y2;
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- MapName str = stringish<MapName>(ZString(conv_str(st, &AARG(0))));
- x1 = conv_num(st, &AARG(1));
- y1 = conv_num(st, &AARG(2));
- x2 = conv_num(st, &AARG(3));
- y2 = conv_num(st, &AARG(4));
-
- if (!sd)
- return;
-
- push_int<ScriptDataInt>(st->stack,
- (sd->bl_x >= x1 && sd->bl_x <= x2)
- && (sd->bl_y >= y1 && sd->bl_y <= y2)
- && (str == sd->bl_m->name_));
-}
-
-// Trigger the shop on a (hopefully) nearby shop NPC
-static
-void builtin_shop(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- dumb_ptr<npc_data> nd;
-
- if (!sd)
- return;
-
- NpcName name = stringish<NpcName>(ZString(conv_str(st, &AARG(0))));
- nd = npc_name2id(name);
- if (!nd)
- {
- PRINTF("builtin_shop: no such npc: %s\n"_fmt, name);
- return;
- }
-
- builtin_close(st);
- clif_npcbuysell(sd, nd->bl_id);
-}
-
-/*==========================================
- * Check whether the PC is dead
- *------------------------------------------
- */
-static
-void builtin_isdead(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- push_int<ScriptDataInt>(st->stack, pc_isdead(sd));
-}
-
-/*========================================
- * Changes a NPC name, and sprite
- *----------------------------------------
- */
-static
-void builtin_fakenpcname(ScriptState *st)
-{
- NpcName name = stringish<NpcName>(ZString(conv_str(st, &AARG(0))));
- NpcName newname = stringish<NpcName>(ZString(conv_str(st, &AARG(1))));
- Species newsprite = wrap<Species>(static_cast<uint16_t>(conv_num(st, &AARG(2))));
- dumb_ptr<npc_data> nd = npc_name2id(name);
- if (!nd)
- {
- PRINTF("builtin_fakenpcname: no such npc: %s\n"_fmt, name);
- return;
- }
- nd->name = newname;
- nd->npc_class = newsprite;
-
- // Refresh this npc
- npc_enable(name, 0);
- npc_enable(name, 1);
-
-}
-
-/*============================
- * Gets the PC's x pos
- *----------------------------
- */
-static
-void builtin_getx(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- push_int<ScriptDataInt>(st->stack, sd->bl_x);
-}
-
-/*============================
- * Gets the PC's y pos
- *----------------------------
- */
-static
-void builtin_gety(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- push_int<ScriptDataInt>(st->stack, sd->bl_y);
-}
-
-/*
- * Get the PC's current map's name
- */
-static
-void builtin_getmap(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
-
- push_str<ScriptDataStr>(st->stack, sd->bl_m->name_);
-}
-
-static
-void builtin_mapexit(ScriptState *)
-{
- runflag = 0;
-}
-
-
-//
-// 実行部main
-//
-/*==========================================
- * コマンドの読み取り
- *------------------------------------------
- */
-static
-ByteCode get_com(ScriptPointer *script)
-{
- if (static_cast<uint8_t>(script->peek()) >= 0x80)
- {
- // synthetic! Does not advance pos yet.
- return ByteCode::INT;
- }
- return script->pop();
-}
-
-/*==========================================
- * 数値の所得
- *------------------------------------------
- */
-static
-int get_num(ScriptPointer *scr)
-{
- int i = 0;
- int j = 0;
- uint8_t val;
- do
- {
- val = static_cast<uint8_t>(scr->pop());
- i += (val & 0x7f) << j;
- j += 6;
- }
- while (val >= 0xc0);
- return i;
-}
-
-/*==========================================
- * スタックから値を取り出す
- *------------------------------------------
- */
-static
-int pop_val(ScriptState *st)
-{
- if (st->stack->stack_datav.empty())
- return 0;
- script_data& back = st->stack->stack_datav.back();
- get_val(st, &back);
- int rv = 0;
- if (auto *u = back.get_if<ScriptDataInt>())
- rv = u->numi;
- st->stack->stack_datav.pop_back();
- return rv;
-}
-
-static
-bool isstr(struct script_data& c)
-{
- return c.is<ScriptDataStr>();
-}
-
-/*==========================================
- * 加算演算子
- *------------------------------------------
- */
-static
-void op_add(ScriptState *st)
-{
- get_val(st, &st->stack->stack_datav.back());
- script_data back = st->stack->stack_datav.back();
- st->stack->stack_datav.pop_back();
-
- script_data& back1 = st->stack->stack_datav.back();
- get_val(st, &back1);
-
- if (!(isstr(back) || isstr(back1)))
- {
- back1.get_if<ScriptDataInt>()->numi += back.get_if<ScriptDataInt>()->numi;
- }
- else
- {
- RString sb = conv_str(st, &back);
- RString sb1 = conv_str(st, &back1);
- MString buf;
- buf += sb1;
- buf += sb;
- back1 = ScriptDataStr{.str= AString(buf)};
- }
-}
-
-/*==========================================
- * 二項演算子(文字列)
- *------------------------------------------
- */
-static
-void op_2str(ScriptState *st, ByteCode op, ZString s1, ZString s2)
-{
- int a = 0;
-
- switch (op)
- {
- case ByteCode::EQ:
- a = s1 == s2;
- break;
- case ByteCode::NE:
- a = s1 != s2;
- break;
- case ByteCode::GT:
- a = s1 > s2;
- break;
- case ByteCode::GE:
- a = s1 >= s2;
- break;
- case ByteCode::LT:
- a = s1 < s2;
- break;
- case ByteCode::LE:
- a = s1 <= s2;
- break;
- default:
- PRINTF("illegal string operater\n"_fmt);
- break;
- }
-
- push_int<ScriptDataInt>(st->stack, a);
-}
-
-/*==========================================
- * 二項演算子(数値)
- *------------------------------------------
- */
-static
-void op_2num(ScriptState *st, ByteCode op, int i1, int i2)
-{
- switch (op)
- {
- case ByteCode::SUB:
- i1 -= i2;
- break;
- case ByteCode::MUL:
- i1 *= i2;
- break;
- case ByteCode::DIV:
- i1 /= i2;
- break;
- case ByteCode::MOD:
- i1 %= i2;
- break;
- case ByteCode::AND:
- i1 &= i2;
- break;
- case ByteCode::OR:
- i1 |= i2;
- break;
- case ByteCode::XOR:
- i1 ^= i2;
- break;
- case ByteCode::LAND:
- i1 = i1 && i2;
- break;
- case ByteCode::LOR:
- i1 = i1 || i2;
- break;
- case ByteCode::EQ:
- i1 = i1 == i2;
- break;
- case ByteCode::NE:
- i1 = i1 != i2;
- break;
- case ByteCode::GT:
- i1 = i1 > i2;
- break;
- case ByteCode::GE:
- i1 = i1 >= i2;
- break;
- case ByteCode::LT:
- i1 = i1 < i2;
- break;
- case ByteCode::LE:
- i1 = i1 <= i2;
- break;
- case ByteCode::R_SHIFT:
- i1 = i1 >> i2;
- break;
- case ByteCode::L_SHIFT:
- i1 = i1 << i2;
- break;
- }
- push_int<ScriptDataInt>(st->stack, i1);
-}
-
-/*==========================================
- * 二項演算子
- *------------------------------------------
- */
-static
-void op_2(ScriptState *st, ByteCode op)
-{
- // pop_val has unfortunate implications here
- script_data d2 = st->stack->stack_datav.back();
- st->stack->stack_datav.pop_back();
- get_val(st, &d2);
- script_data d1 = st->stack->stack_datav.back();
- st->stack->stack_datav.pop_back();
- get_val(st, &d1);
-
- if (isstr(d1) && isstr(d2))
- {
- // ss => op_2str
- op_2str(st, op, d1.get_if<ScriptDataStr>()->str, d2.get_if<ScriptDataStr>()->str);
- }
- else if (!(isstr(d1) || isstr(d2)))
- {
- // ii => op_2num
- op_2num(st, op, d1.get_if<ScriptDataInt>()->numi, d2.get_if<ScriptDataInt>()->numi);
- }
- else
- {
- // si,is => error
- PRINTF("script: op_2: int&str, str&int not allow.\n"_fmt);
- push_int<ScriptDataInt>(st->stack, 0);
- }
-}
-
-/*==========================================
- * 単項演算子
- *------------------------------------------
- */
-static
-void op_1num(ScriptState *st, ByteCode op)
-{
- int i1;
- i1 = pop_val(st);
- switch (op)
- {
- case ByteCode::NEG:
- i1 = -i1;
- break;
- case ByteCode::NOT:
- i1 = ~i1;
- break;
- case ByteCode::LNOT:
- i1 = !i1;
- break;
- }
- push_int<ScriptDataInt>(st->stack, i1);
-}
-
-/*==========================================
- * 関数の実行
- *------------------------------------------
- */
-void run_func(ScriptState *st)
-{
- size_t end_sp = st->stack->stack_datav.size();
- size_t start_sp = end_sp - 1;
- while (!st->stack->stack_datav[start_sp].is<ScriptDataArg>())
- {
- start_sp--;
- if (start_sp == 0)
- {
- if (battle_config.error_log)
- PRINTF("function not found\n"_fmt);
- st->state = ScriptEndState::END;
- return;
- }
- }
- // the func is before the arg
- start_sp--;
- st->start = start_sp;
- st->end = end_sp;
-
- if (!st->stack->stack_datav[st->start].is<ScriptDataFuncRef>())
- {
- PRINTF("run_func: not function and command! \n"_fmt);
- st->state = ScriptEndState::END;
- return;
- }
- size_t func = st->stack->stack_datav[st->start].get_if<ScriptDataFuncRef>()->numi;
-
- if (DEBUG_RUN && battle_config.etc_log)
- {
- PRINTF("run_func : %s\n"_fmt,
- builtin_functions[func].name);
- PRINTF("stack dump :"_fmt);
- for (script_data& d : st->stack->stack_datav)
- {
- MATCH (d)
- {
- CASE (const ScriptDataInt&, u)
- {
- PRINTF(" int(%d)"_fmt, u.numi);
- }
- CASE (const ScriptDataRetInfo&, u)
- {
- PRINTF(" retinfo(%p)"_fmt, static_cast<const void *>(u.script));
- }
- CASE (const ScriptDataParam&, u)
- {
- PRINTF(" param(%d)"_fmt, u.reg.sp());
- }
- CASE (const ScriptDataVariable&, u)
- {
- PRINTF(" name(%s)[%d]"_fmt, variable_names.outtern(u.reg.base()), u.reg.index());
- }
- CASE (const ScriptDataArg&, u)
- {
- (void)u;
- PRINTF(" arg"_fmt);
- }
- CASE (const ScriptDataPos&, u)
- {
- (void)u;
- PRINTF(" pos(%d)"_fmt, u.numi);
- }
- CASE (const ScriptDataStr&, u)
- {
- (void)u;
- PRINTF(" str(%s)"_fmt, u.str);
- }
- CASE (const ScriptDataFuncRef&, u)
- {
- (void)u;
- PRINTF(" func(%s)"_fmt, builtin_functions[u.numi].name);
- }
- }
- }
- PRINTF("\n"_fmt);
- }
- builtin_functions[func].func(st);
-
- pop_stack(st->stack, start_sp, end_sp);
-
- if (st->state == ScriptEndState::RETFUNC)
- {
- // ユーザー定義関数からの復帰
- int olddefsp = st->defsp;
-
- pop_stack(st->stack, st->defsp, start_sp); // 復帰に邪魔なスタック削除
- if (st->defsp < 4
- || !st->stack->stack_datav[st->defsp - 1].is<ScriptDataRetInfo>())
- {
- PRINTF("script:run_func (return) return without callfunc or callsub!\n"_fmt);
- st->state = ScriptEndState::END;
- return;
- }
- assert (olddefsp == st->defsp); // pretty sure it hasn't changed yet
- st->scriptp.code = conv_script(st, &st->stack->stack_datav[olddefsp - 1]); // スクリプトを復元
- st->scriptp.pos = conv_num(st, &st->stack->stack_datav[olddefsp - 2]); // スクリプト位置の復元
- st->defsp = conv_num(st, &st->stack->stack_datav[olddefsp - 3]); // 基準スタックポインタを復元
- // Number of arguments.
- int i = conv_num(st, &st->stack->stack_datav[olddefsp - 4]); // 引数の数所得
- assert (i == 0);
-
- pop_stack(st->stack, olddefsp - 4 - i, olddefsp); // 要らなくなったスタック(引数と復帰用データ)削除
-
- st->state = ScriptEndState::GOTO;
- }
-}
-
-// pretend it's external so this can be called in the debugger
-void dump_script(const ScriptBuffer *script);
-void dump_script(const ScriptBuffer *script)
-{
- ScriptPointer scriptp(script, 0);
- while (scriptp.pos < reinterpret_cast<const std::vector<ByteCode> *>(script)->size())
- {
- PRINTF("%6zu: "_fmt, scriptp.pos);
- switch (ByteCode c = get_com(&scriptp))
- {
- case ByteCode::EOL:
- PRINTF("EOL\n"_fmt); // extra newline between functions
- break;
- case ByteCode::INT:
- // synthesized!
- PRINTF("INT %d"_fmt, get_num(&scriptp));
- break;
-
- case ByteCode::POS:
- case ByteCode::VARIABLE:
- case ByteCode::FUNC_REF:
- case ByteCode::PARAM:
- {
- int arg = 0;
- arg |= static_cast<uint8_t>(scriptp.pop()) << 0;
- arg |= static_cast<uint8_t>(scriptp.pop()) << 8;
- arg |= static_cast<uint8_t>(scriptp.pop()) << 16;
- switch(c)
- {
- case ByteCode::POS:
- PRINTF("POS %d"_fmt, arg);
- break;
- case ByteCode::VARIABLE:
- PRINTF("VARIABLE %s"_fmt, variable_names.outtern(arg));
- break;
- case ByteCode::FUNC_REF:
- PRINTF("FUNC_REF %s"_fmt, builtin_functions[arg].name);
- break;
- case ByteCode::PARAM:
- PRINTF("PARAM SP::#%d (sorry)"_fmt, arg);
- break;
- }
- }
- break;
- case ByteCode::ARG:
- PRINTF("ARG"_fmt);
- break;
- case ByteCode::STR:
- PRINTF("STR \"%s\""_fmt, scriptp.pops());
- break;
- case ByteCode::FUNC:
- PRINTF("FUNC"_fmt);
- break;
-
- case ByteCode::ADD:
- PRINTF("ADD"_fmt);
- break;
- case ByteCode::SUB:
- PRINTF("SUB"_fmt);
- break;
- case ByteCode::MUL:
- PRINTF("MUL"_fmt);
- break;
- case ByteCode::DIV:
- PRINTF("DIV"_fmt);
- break;
- case ByteCode::MOD:
- PRINTF("MOD"_fmt);
- break;
- case ByteCode::EQ:
- PRINTF("EQ"_fmt);
- break;
- case ByteCode::NE:
- PRINTF("NE"_fmt);
- break;
- case ByteCode::GT:
- PRINTF("GT"_fmt);
- break;
- case ByteCode::GE:
- PRINTF("GE"_fmt);
- break;
- case ByteCode::LT:
- PRINTF("LT"_fmt);
- break;
- case ByteCode::LE:
- PRINTF("LE"_fmt);
- break;
- case ByteCode::AND:
- PRINTF("AND"_fmt);
- break;
- case ByteCode::OR:
- PRINTF("OR"_fmt);
- break;
- case ByteCode::XOR:
- PRINTF("XOR"_fmt);
- break;
- case ByteCode::LAND:
- PRINTF("LAND"_fmt);
- break;
- case ByteCode::LOR:
- PRINTF("LOR"_fmt);
- break;
- case ByteCode::R_SHIFT:
- PRINTF("R_SHIFT"_fmt);
- break;
- case ByteCode::L_SHIFT:
- PRINTF("L_SHIFT"_fmt);
- break;
- case ByteCode::NEG:
- PRINTF("NEG"_fmt);
- break;
- case ByteCode::NOT:
- PRINTF("NOT"_fmt);
- break;
- case ByteCode::LNOT:
- PRINTF("LNOT"_fmt);
- break;
-
- case ByteCode::NOP:
- PRINTF("NOP"_fmt);
- break;
-
- default:
- PRINTF("??? %d"_fmt, c);
- break;
- }
- PRINTF("\n"_fmt);
- }
-}
-
-/*==========================================
- * スクリプトの実行メイン部分
- *------------------------------------------
- */
-static
-void run_script_main(ScriptState *st, const ScriptBuffer *rootscript)
-{
- int cmdcount = script_config.check_cmdcount;
- int gotocount = script_config.check_gotocount;
- struct script_stack *stack = st->stack;
-
- st->defsp = stack->stack_datav.size();
-
- int rerun_pos = st->scriptp.pos;
- st->state = ScriptEndState::ZERO;
- while (st->state == ScriptEndState::ZERO)
- {
- switch (ByteCode c = get_com(&st->scriptp))
- {
- case ByteCode::EOL:
- if (stack->stack_datav.size() != st->defsp)
- {
- if (true)
- PRINTF("stack.sp (%zu) != default (%d)\n"_fmt,
- stack->stack_datav.size(),
- st->defsp);
- abort();
- }
- rerun_pos = st->scriptp.pos;
- break;
- case ByteCode::INT:
- // synthesized!
- push_int<ScriptDataInt>(stack, get_num(&st->scriptp));
- break;
-
- case ByteCode::POS:
- case ByteCode::VARIABLE:
- case ByteCode::FUNC_REF:
- case ByteCode::PARAM:
- // Note that these 3 have *very* different meanings,
- // despite being encoded similarly.
- {
- int arg = 0;
- arg |= static_cast<uint8_t>(st->scriptp.pop()) << 0;
- arg |= static_cast<uint8_t>(st->scriptp.pop()) << 8;
- arg |= static_cast<uint8_t>(st->scriptp.pop()) << 16;
- switch(c)
- {
- case ByteCode::POS:
- push_int<ScriptDataPos>(stack, arg);
- break;
- case ByteCode::VARIABLE:
- push_reg<ScriptDataVariable>(stack, SIR::from(arg));
- break;
- case ByteCode::FUNC_REF:
- push_int<ScriptDataFuncRef>(stack, arg);
- break;
- case ByteCode::PARAM:
- SP arg_sp = static_cast<SP>(arg);
- push_reg<ScriptDataParam>(stack, SIR::from(arg_sp));
- break;
- }
- }
- break;
- case ByteCode::ARG:
- push_int<ScriptDataArg>(stack, 0);
- break;
- case ByteCode::STR:
- push_str<ScriptDataStr>(stack, st->scriptp.pops());
- break;
- case ByteCode::FUNC:
- run_func(st);
- if (st->state == ScriptEndState::GOTO)
- {
- rerun_pos = st->scriptp.pos;
- st->state = ScriptEndState::ZERO;
- if (gotocount > 0 && (--gotocount) <= 0)
- {
- PRINTF("run_script: infinity loop !\n"_fmt);
- st->state = ScriptEndState::END;
- }
- }
- break;
-
- case ByteCode::ADD:
- op_add(st);
- break;
-
- case ByteCode::SUB:
- case ByteCode::MUL:
- case ByteCode::DIV:
- case ByteCode::MOD:
- case ByteCode::EQ:
- case ByteCode::NE:
- case ByteCode::GT:
- case ByteCode::GE:
- case ByteCode::LT:
- case ByteCode::LE:
- case ByteCode::AND:
- case ByteCode::OR:
- case ByteCode::XOR:
- case ByteCode::LAND:
- case ByteCode::LOR:
- case ByteCode::R_SHIFT:
- case ByteCode::L_SHIFT:
- op_2(st, c);
- break;
-
- case ByteCode::NEG:
- case ByteCode::NOT:
- case ByteCode::LNOT:
- op_1num(st, c);
- break;
-
- case ByteCode::NOP:
- st->state = ScriptEndState::END;
- break;
-
- default:
- if (battle_config.error_log)
- PRINTF("unknown command : %d @ %zu\n"_fmt,
- c, st->scriptp.pos);
- st->state = ScriptEndState::END;
- break;
- }
- if (cmdcount > 0 && (--cmdcount) <= 0)
- {
- PRINTF("run_script: infinity loop !\n"_fmt);
- st->state = ScriptEndState::END;
- }
- }
- switch (st->state)
- {
- case ScriptEndState::STOP:
- break;
- case ScriptEndState::END:
- {
- dumb_ptr<map_session_data> sd = map_id2sd(st->rid);
- st->scriptp.code = nullptr;
- st->scriptp.pos = -1;
- if (sd && sd->npc_id == st->oid)
- npc_event_dequeue(sd);
- }
- break;
- case ScriptEndState::RERUNLINE:
- st->scriptp.pos = rerun_pos;
- break;
- }
-
- if (st->state != ScriptEndState::END)
- {
- // 再開するためにスタック情報を保存
- dumb_ptr<map_session_data> sd = map_id2sd(st->rid);
- if (sd)
- {
- sd->npc_stackbuf = stack->stack_datav;
- sd->npc_script = st->scriptp.code;
- // sd->npc_pos is set later ... ???
- sd->npc_scriptroot = rootscript;
- }
- }
-}
-
-/*==========================================
- * スクリプトの実行
- *------------------------------------------
- */
-int run_script(ScriptPointer sp, BlockId rid, BlockId oid)
-{
- return run_script_l(sp, rid, oid, nullptr);
-}
-
-int run_script_l(ScriptPointer sp, BlockId rid, BlockId oid,
- Slice<argrec_t> args)
-{
- struct script_stack stack;
- ScriptState st;
- dumb_ptr<map_session_data> sd = map_id2sd(rid);
- const ScriptBuffer *rootscript = sp.code;
- int i;
- if (sp.code == nullptr || sp.pos >> 24)
- return -1;
-
- if (sd && !sd->npc_stackbuf.empty() && sd->npc_scriptroot == rootscript)
- {
- // 前回のスタックを復帰
- sp.code = sd->npc_script;
- stack.stack_datav = std::move(sd->npc_stackbuf);
- }
- st.stack = &stack;
- st.scriptp = sp;
- st.rid = rid;
- st.oid = oid;
- for (i = 0; i < args.size(); i++)
- {
- if (args[i].name.back() == '$')
- pc_setregstr(sd, SIR::from(variable_names.intern(args[i].name)), args[i].v.s);
- else
- pc_setreg(sd, SIR::from(variable_names.intern(args[i].name)), args[i].v.i);
- }
- run_script_main(&st, rootscript);
-
- stack.stack_datav.clear();
- return st.scriptp.pos;
-}
-
-/*==========================================
- * マップ変数の変更
- *------------------------------------------
- */
-void mapreg_setreg(SIR reg, int val)
-{
- mapreg_db.put(reg, val);
-
- mapreg_dirty = 1;
-}
-
-/*==========================================
- * 文字列型マップ変数の変更
- *------------------------------------------
- */
-void mapreg_setregstr(SIR reg, XString str)
-{
- if (!str)
- mapregstr_db.erase(reg);
- else
- mapregstr_db.insert(reg, str);
-
- mapreg_dirty = 1;
-}
-
-/*==========================================
- * 永続的マップ変数の読み込み
- *------------------------------------------
- */
-static
-void script_load_mapreg(void)
-{
- io::ReadFile in(mapreg_txt);
-
- if (!in.is_open())
- return;
-
- AString line;
- while (in.getline(line))
- {
- XString buf1, buf2;
- int index = 0;
- if (extract(line,
- record<'\t'>(
- record<','>(&buf1, &index),
- &buf2))
- || extract(line,
- record<'\t'>(
- record<','>(&buf1),
- &buf2)))
- {
- int s = variable_names.intern(buf1);
- SIR key = SIR::from(s, index);
- if (buf1.back() == '$')
- {
- mapregstr_db.insert(key, buf2);
- }
- else
- {
- int v;
- if (!extract(buf2, &v))
- goto borken;
- mapreg_db.put(key, v);
- }
- }
- else
- {
- borken:
- PRINTF("%s: %s broken data !\n"_fmt, mapreg_txt, AString(buf1));
- continue;
- }
- }
- mapreg_dirty = 0;
-}
-
-/*==========================================
- * 永続的マップ変数の書き込み
- *------------------------------------------
- */
-static
-void script_save_mapreg_intsub(SIR key, int data, io::WriteFile& fp)
-{
- int num = key.base(), i = key.index();
- ZString name = variable_names.outtern(num);
- if (name[1] != '@')
- {
- if (i == 0)
- FPRINTF(fp, "%s\t%d\n"_fmt, name, data);
- else
- FPRINTF(fp, "%s,%d\t%d\n"_fmt, name, i, data);
- }
-}
-
-static
-void script_save_mapreg_strsub(SIR key, ZString data, io::WriteFile& fp)
-{
- int num = key.base(), i = key.index();
- ZString name = variable_names.outtern(num);
- if (name[1] != '@')
- {
- if (i == 0)
- FPRINTF(fp, "%s\t%s\n"_fmt, name, data);
- else
- FPRINTF(fp, "%s,%d\t%s\n"_fmt, name, i, data);
- }
-}
-
-static
-void script_save_mapreg(void)
-{
- io::WriteLock fp(mapreg_txt);
- if (!fp.is_open())
- return;
- for (auto& pair : mapreg_db)
- script_save_mapreg_intsub(pair.first, pair.second, fp);
- for (auto& pair : mapregstr_db)
- script_save_mapreg_strsub(pair.first, pair.second, fp);
- mapreg_dirty = 0;
-}
-
-static
-void script_autosave_mapreg(TimerData *, tick_t)
-{
- if (mapreg_dirty)
- script_save_mapreg();
-}
-
-void do_final_script(void)
-{
- if (mapreg_dirty >= 0)
- script_save_mapreg();
-
- mapreg_db.clear();
- mapregstr_db.clear();
- scriptlabel_db.clear();
- userfunc_db.clear();
-
- str_datam.clear();
-}
-
-/*==========================================
- * 初期化
- *------------------------------------------
- */
-void do_init_script(void)
-{
- script_load_mapreg();
-
- Timer(gettick() + MAPREG_AUTOSAVE_INTERVAL,
- script_autosave_mapreg,
- MAPREG_AUTOSAVE_INTERVAL
- ).detach();
-}
-
-#define BUILTIN(func, args, ret) \
-{builtin_##func, #func ## _s, args, ret}
-
-BuiltinFunction builtin_functions[] =
-{
- BUILTIN(mes, "s"_s, '\0'),
- BUILTIN(goto, "L"_s, '\0'),
- BUILTIN(callfunc, "F"_s, '\0'),
- BUILTIN(callsub, "L"_s, '\0'),
- BUILTIN(return, ""_s, '\0'),
- BUILTIN(next, ""_s, '\0'),
- BUILTIN(close, ""_s, '\0'),
- BUILTIN(close2, ""_s, '\0'),
- BUILTIN(menu, "sL**"_s, '\0'),
- BUILTIN(rand, "i?"_s, 'i'),
- BUILTIN(isat, "Mxy"_s, 'i'),
- BUILTIN(warp, "Mxy"_s, '\0'),
- BUILTIN(areawarp, "MxyxyMxy"_s, '\0'),
- BUILTIN(heal, "ii"_s, '\0'),
- BUILTIN(itemheal, "ii"_s, '\0'),
- BUILTIN(percentheal, "ii"_s, '\0'),
- BUILTIN(input, "N"_s, '\0'),
- BUILTIN(if, "iF*"_s, '\0'),
- BUILTIN(set, "Ne"_s, '\0'),
- BUILTIN(setarray, "Ne*"_s, '\0'),
- BUILTIN(cleararray, "Nei"_s, '\0'),
- BUILTIN(getarraysize, "N"_s, 'i'),
- BUILTIN(getelementofarray, "Ni"_s, '.'),
- BUILTIN(setlook, "ii"_s, '\0'),
- BUILTIN(countitem, "I"_s, 'i'),
- BUILTIN(checkweight, "Ii"_s, 'i'),
- BUILTIN(getitem, "Ii??"_s, '\0'),
- BUILTIN(makeitem, "IiMxy"_s, '\0'),
- BUILTIN(delitem, "Ii"_s, '\0'),
- BUILTIN(readparam, "i?"_s, 'i'),
- BUILTIN(getcharid, "i?"_s, 'i'),
- BUILTIN(strcharinfo, "i"_s, 's'),
- BUILTIN(getequipid, "i"_s, 'i'),
- BUILTIN(getequipname, "i"_s, 's'),
- BUILTIN(statusup2, "ii"_s, '\0'),
- BUILTIN(bonus, "ii"_s, '\0'),
- BUILTIN(bonus2, "iii"_s, '\0'),
- BUILTIN(skill, "ii?"_s, '\0'),
- BUILTIN(setskill, "ii"_s, '\0'),
- BUILTIN(getskilllv, "i"_s, 'i'),
- BUILTIN(getgmlevel, ""_s, 'i'),
- BUILTIN(end, ""_s, '\0'),
- BUILTIN(getopt2, ""_s, 'i'),
- BUILTIN(setopt2, "i"_s, '\0'),
- BUILTIN(savepoint, "Mxy"_s, '\0'),
- BUILTIN(gettimetick, "i"_s, 'i'),
- BUILTIN(gettime, "i"_s, 'i'),
- BUILTIN(openstorage, ""_s, '\0'),
- BUILTIN(getexp, "ii"_s, '\0'),
- BUILTIN(monster, "Mxysmi?"_s, '\0'),
- BUILTIN(areamonster, "Mxyxysmi?"_s, '\0'),
- BUILTIN(killmonster, "ME"_s, '\0'),
- BUILTIN(killmonsterall, "M"_s, '\0'),
- BUILTIN(donpcevent, "E"_s, '\0'),
- BUILTIN(addtimer, "tE"_s, '\0'),
- BUILTIN(initnpctimer, ""_s, '\0'),
- BUILTIN(startnpctimer, "?"_s, '\0'),
- BUILTIN(stopnpctimer, ""_s, '\0'),
- BUILTIN(getnpctimer, "i"_s, 'i'),
- BUILTIN(setnpctimer, "i"_s, '\0'),
- BUILTIN(announce, "si"_s, '\0'),
- BUILTIN(mapannounce, "Msi"_s, '\0'),
- BUILTIN(getusers, "i"_s, 'i'),
- BUILTIN(getmapusers, "M"_s, 'i'),
- BUILTIN(getareausers, "Mxyxy?"_s, 'i'),
- BUILTIN(getareadropitem, "Mxyxyi?"_s, 'i'),
- BUILTIN(enablenpc, "s"_s, '\0'),
- BUILTIN(disablenpc, "s"_s, '\0'),
- BUILTIN(sc_start, "iTi?"_s, '\0'),
- BUILTIN(sc_end, "i"_s, '\0'),
- BUILTIN(sc_check, "i"_s, 'i'),
- BUILTIN(debugmes, "s"_s, '\0'),
- BUILTIN(resetstatus, ""_s, '\0'),
- BUILTIN(changesex, ""_s, '\0'),
- BUILTIN(attachrid, "i"_s, 'i'),
- BUILTIN(detachrid, ""_s, '\0'),
- BUILTIN(isloggedin, "i"_s, 'i'),
- BUILTIN(setmapflag, "Mi"_s, '\0'),
- BUILTIN(removemapflag, "Mi"_s, '\0'),
- BUILTIN(getmapflag, "Mi"_s, 'i'),
- BUILTIN(pvpon, "M"_s, '\0'),
- BUILTIN(pvpoff, "M"_s, '\0'),
- BUILTIN(emotion, "i"_s, '\0'),
- BUILTIN(mapwarp, "MMxy"_s, '\0'),
- BUILTIN(cmdothernpc, "ss"_s, '\0'),
- BUILTIN(mobcount, "ME"_s, 'i'),
- BUILTIN(marriage, "P"_s, 'i'),
- BUILTIN(divorce, ""_s, 'i'),
- BUILTIN(getitemname, "I"_s, 's'),
- BUILTIN(getspellinvocation, "s"_s, 's'),
- BUILTIN(getpartnerid2, ""_s, 'i'),
- BUILTIN(getinventorylist, ""_s, '\0'),
- BUILTIN(getactivatedpoolskilllist, ""_s, '\0'),
- BUILTIN(getunactivatedpoolskilllist, ""_s, '\0'),
- BUILTIN(poolskill, "i"_s, '\0'),
- BUILTIN(unpoolskill, "i"_s, '\0'),
- BUILTIN(misceffect, "i?"_s, '\0'),
- BUILTIN(specialeffect, "i"_s, '\0'),
- BUILTIN(specialeffect2, "i"_s, '\0'),
- BUILTIN(nude, ""_s, '\0'),
- BUILTIN(unequipbyid, "i"_s, '\0'),
- BUILTIN(gmcommand, "s"_s, '\0'),
- BUILTIN(npcwarp, "xys"_s, '\0'),
- BUILTIN(message, "Ps"_s, '\0'),
- BUILTIN(npctalk, "s"_s, '\0'),
- BUILTIN(getlook, "i"_s, 'i'),
- BUILTIN(getsavepoint, "i"_s, '.'),
- BUILTIN(areatimer, "MxyxytE"_s, '\0'),
- BUILTIN(isin, "Mxyxy"_s, 'i'),
- BUILTIN(shop, "s"_s, '\0'),
- BUILTIN(isdead, ""_s, 'i'),
- BUILTIN(fakenpcname, "ssi"_s, '\0'),
- BUILTIN(getx, ""_s, 'i'),
- BUILTIN(gety, ""_s, 'i'),
- BUILTIN(getmap, ""_s, 's'),
- BUILTIN(mapexit, ""_s, '\0'),
- {nullptr, ""_s, ""_s, '\0'},
-};
-
-void set_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e, int val)
-{
- size_t k = variable_names.intern(var);
- SIR reg = SIR::from(k, e);
- set_reg(sd, VariableCode::VARIABLE, reg, val);
-}
-void set_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e, XString val)
-{
- size_t k = variable_names.intern(var);
- SIR reg = SIR::from(k, e);
- set_reg(sd, VariableCode::VARIABLE, reg, val);
-}
-int get_script_var_i(dumb_ptr<map_session_data> sd, VarName var, int e)
-{
- size_t k = variable_names.intern(var);
- SIR reg = SIR::from(k, e);
- struct script_data dat = ScriptDataVariable{.reg= reg};
- get_val(sd, &dat);
- if (auto *u = dat.get_if<ScriptDataInt>())
- return u->numi;
- PRINTF("Warning: you lied about the type and I'm too lazy to fix it!"_fmt);
- return 0;
-}
-ZString get_script_var_s(dumb_ptr<map_session_data> sd, VarName var, int e)
-{
- size_t k = variable_names.intern(var);
- SIR reg = SIR::from(k, e);
- struct script_data dat = ScriptDataVariable{.reg= reg};
- get_val(sd, &dat);
- if (auto *u = dat.get_if<ScriptDataStr>())
- // this is almost certainly a memory leak after CONSTSTR removal
- return u->str;
- PRINTF("Warning: you lied about the type and I can't fix it!"_fmt);
- return ZString();
-}
-} // namespace tmwa