diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/npc.cpp | 55 | ||||
-rw-r--r-- | src/ast/npc.hpp | 11 | ||||
-rw-r--r-- | src/ast/npc_test.cpp | 68 | ||||
-rw-r--r-- | src/ast/quest.cpp | 125 | ||||
-rw-r--r-- | src/ast/quest.hpp | 65 | ||||
-rw-r--r-- | src/char/char.cpp | 49 | ||||
-rw-r--r-- | src/login/login.cpp | 87 | ||||
-rw-r--r-- | src/map/atcommand.cpp | 110 | ||||
-rw-r--r-- | src/map/chrif.cpp | 147 | ||||
-rw-r--r-- | src/map/clif.cpp | 64 | ||||
-rw-r--r-- | src/map/clif.hpp | 4 | ||||
-rw-r--r-- | src/map/fwd.hpp | 1 | ||||
-rw-r--r-- | src/map/globals.cpp | 2 | ||||
-rw-r--r-- | src/map/globals.hpp | 1 | ||||
-rw-r--r-- | src/map/magic-stmt.cpp | 2 | ||||
-rw-r--r-- | src/map/map.cpp | 3 | ||||
-rw-r--r-- | src/map/mob.cpp | 50 | ||||
-rw-r--r-- | src/map/npc-parse.cpp | 124 | ||||
-rw-r--r-- | src/map/npc.cpp | 2 | ||||
-rw-r--r-- | src/map/pc.cpp | 96 | ||||
-rw-r--r-- | src/map/pc.hpp | 3 | ||||
-rw-r--r-- | src/map/quest.cpp | 135 | ||||
-rw-r--r-- | src/map/quest.hpp (renamed from src/monitor/globals.hpp) | 34 | ||||
-rw-r--r-- | src/map/script-call.cpp | 4 | ||||
-rw-r--r-- | src/map/script-fun.cpp | 163 | ||||
-rw-r--r-- | src/mmo/fwd.hpp | 1 | ||||
-rw-r--r-- | src/mmo/ids.hpp | 1 | ||||
-rw-r--r-- | src/mmo/ids.py | 1 | ||||
-rw-r--r-- | src/monitor/fwd.hpp | 37 | ||||
-rw-r--r-- | src/monitor/globals.cpp | 33 | ||||
-rw-r--r-- | src/monitor/main.cpp | 243 |
31 files changed, 744 insertions, 977 deletions
diff --git a/src/ast/npc.cpp b/src/ast/npc.cpp index e9c3464..8d4a43e 100644 --- a/src/ast/npc.cpp +++ b/src/ast/npc.cpp @@ -306,7 +306,7 @@ namespace npc static Result<ScriptNone> parse_script_none_head(io::LineSpan span, std::vector<Spanned<std::vector<Spanned<RString>>>>& bits) { - // ScriptNone: -|script|script name|-1{code} + // ScriptNone: -|script|script name|32767{code} if (bits.size() != 4) { return Err(span.error_str("expect 4 |component|s"_s)); @@ -319,10 +319,10 @@ namespace npc { return Err(bits[2].span.error_str("in |component 3| expect 1 ,component,s"_s)); } - assert(bits[3].data[0].data == "-1"_s); + assert(bits[3].data[0].data == "32767"_s); if (bits[3].data.size() != 1) { - return Err(bits[3].span.error_str("in |component 4| should be just -1"_s)); + return Err(bits[3].span.error_str("in |component 4| should be just 32767"_s)); } ScriptNone script_none; @@ -333,39 +333,6 @@ namespace npc return Ok(std::move(script_none)); } static - Result<ScriptMapNone> parse_script_map_none_head(io::LineSpan span, std::vector<Spanned<std::vector<Spanned<RString>>>>& bits) - { - // ScriptMapNone: m,x,y,d|script|script name|-1{code} - if (bits.size() != 4) - { - return Err(span.error_str("expect 4 |component|s"_s)); - } - if (bits[0].data.size() != 4) - { - return Err(bits[0].span.error_str("in |component 1| expect 3 ,component,s"_s)); - } - assert(bits[1].data.size() == 1); - assert(bits[1].data[0].data == "script"_s); - if (bits[2].data.size() != 1) - { - return Err(bits[2].span.error_str("in |component 3| expect 1 ,component,s"_s)); - } - if (bits[3].data.size() != 1 || bits[3].data[0].data != "-1"_s) - { - return Err(bits[3].span.error_str("in |component 4| should be just -1"_s)); - } - - ScriptMapNone script_map_none; - TRY_EXTRACT(bits[0].data[0], script_map_none.m); - TRY_EXTRACT(bits[0].data[1], script_map_none.x); - TRY_EXTRACT(bits[0].data[2], script_map_none.y); - TRY_EXTRACT(bits[0].data[3], script_map_none.d); - TRY_EXTRACT(bits[2].data[0], script_map_none.name); - script_map_none.key4_span = bits[3].data[0].span; - // also expect '{' and parse real script (in caller) - return Ok(std::move(script_map_none)); - } - static Result<ScriptMap> parse_script_map_head(io::LineSpan span, std::vector<Spanned<std::vector<Spanned<RString>>>>& bits) { // ScriptMap: m,x,y,d|script|script name|class,xs,ys{code} @@ -417,10 +384,9 @@ namespace npc static Result<Script> parse_script_any(io::LineSpan span, std::vector<Spanned<std::vector<Spanned<RString>>>>& bits, io::LineCharReader& lr) { - // 4 cases: + // 3 cases: // ScriptFunction: function|script|Fun Name{code} - // ScriptNone: -|script|script name|-1{code} - // ScriptMapNone: m,x,y,d|script|script name|-1{code} + // ScriptNone: -|script|script name|32767{code} // ScriptMap: m,x,y,d|script|script name|class,xs,ys{code} if (bits[0].data[0].data == "function"_s) { @@ -445,17 +411,6 @@ namespace npc rv.body = TRY(ast::script::parse_script_body(lr, opt)); return Ok(std::move(rv)); } - else if (bits.size() >= 4 && bits[3].data[0].data == "-1"_s) - { - Script rv = TRY(parse_script_map_none_head(span, bits)); - rv.key_span = bits[1].data[0].span; - - ast::script::ScriptOptions opt; - opt.implicit_start = true; - opt.no_start = true; - rv.body = TRY(ast::script::parse_script_body(lr, opt)); - return Ok(std::move(rv)); - } else { ScriptMap script_map = TRY(parse_script_map_head(span, bits)); diff --git a/src/ast/npc.hpp b/src/ast/npc.hpp index a51acd3..ca6479e 100644 --- a/src/ast/npc.hpp +++ b/src/ast/npc.hpp @@ -103,14 +103,6 @@ namespace npc Spanned<NpcName> name; io::LineSpan key4_span; }; - struct ScriptMapNone - { - Spanned<MapName> m; - Spanned<unsigned> x, y; - Spanned<DIR> d; - Spanned<NpcName> name; - io::LineSpan key4_span; - }; struct ScriptMap { Spanned<MapName> m; @@ -120,13 +112,12 @@ namespace npc Spanned<Species> npc_class; Spanned<unsigned> xs, ys; }; - using ScriptBase = Variant<ScriptFunction, ScriptNone, ScriptMapNone, ScriptMap>; + using ScriptBase = Variant<ScriptFunction, ScriptNone, ScriptMap>; struct Script : ScriptBase { Script() = default; Script(ScriptFunction s) : ScriptBase(std::move(s)) {} Script(ScriptNone s) : ScriptBase(std::move(s)) {} - Script(ScriptMapNone s) : ScriptBase(std::move(s)) {} Script(ScriptMap s) : ScriptBase(std::move(s)) {} io::LineSpan key_span; diff --git a/src/ast/npc_test.cpp b/src/ast/npc_test.cpp index a753623..dadeba7 100644 --- a/src/ast/npc_test.cpp +++ b/src/ast/npc_test.cpp @@ -423,11 +423,11 @@ namespace npc { // 1 2 3 //23456789012345678901234567890123456789 - "-|script|#config|-1{end;}"_s, + "-|script|#config|32767{end;}"_s, // 123456 - "-|script|#config|-1\n{end;}\n"_s, + "-|script|#config|32767\n{end;}\n"_s, // 1234567 - "-|script|#config|-1\n \n {end;} "_s, + "-|script|#config|32767\n \n {end;} "_s, }; for (auto input : inputs) { @@ -435,7 +435,7 @@ namespace npc auto res = TRY_UNWRAP(parse_top(lr), FAIL()); EXPECT_TRUE(res.get_success().is_some()); auto top = TRY_UNWRAP(std::move(res.get_success()), FAIL()); - EXPECT_SPAN(top.span, 1,1, 1,19); + EXPECT_SPAN(top.span, 1,1, 1,22); auto script = top.get_if<Script>(); EXPECT_TRUE(script); auto p = script->get_if<ScriptNone>(); @@ -446,66 +446,10 @@ namespace npc EXPECT_SPAN(script->key_span, 1,3, 1,8); EXPECT_SPAN(p->name.span, 1,10, 1,16); EXPECT_EQ(p->name.data, stringish<NpcName>("#config"_s)); - EXPECT_SPAN(p->key4_span, 1,18, 1,19); + EXPECT_SPAN(p->key4_span, 1,18, 1,22); if (input.endswith('}')) { - EXPECT_SPAN(script->body.span, 1,20, 1,25); - } - else if (input.endswith('\n')) - { - EXPECT_SPAN(script->body.span, 2,1, 2,6); - } - else if (input.endswith(' ')) - { - EXPECT_SPAN(script->body.span, 3,2, 3,7); - } - else - { - FAIL(); - } - EXPECT_EQ(script->body.braced_body, "{end;}"_s); - } - } - } - TEST(npcast, scriptmapnone) - { - QuietFd q; - LString inputs[] = - { - // 1 2 3 - //23456789012345678901234567890123456789 - "map.gat,1,2,3|script|Init|-1{end;}"_s, - "map.gat,1,2,3|script|Init|-1\n{end;}\n"_s, - "map.gat,1,2,3|script|Init|-1\n \n {end;} "_s, - }; - for (auto input : inputs) - { - io::LineCharReader lr(io::from_string, "<string>"_s, input); - auto res = TRY_UNWRAP(parse_top(lr), FAIL()); - EXPECT_TRUE(res.get_success().is_some()); - auto top = TRY_UNWRAP(std::move(res.get_success()), FAIL()); - EXPECT_SPAN(top.span, 1,1, 1,28); - auto script = top.get_if<Script>(); - EXPECT_TRUE(script); - auto p = script->get_if<ScriptMapNone>(); - EXPECT_TRUE(p); - if (p) - { - EXPECT_SPAN(p->m.span, 1,1, 1,7); - EXPECT_EQ(p->m.data, stringish<MapName>("map"_s)); - EXPECT_SPAN(p->x.span, 1,9, 1,9); - EXPECT_EQ(p->x.data, 1); - EXPECT_SPAN(p->y.span, 1,11, 1,11); - EXPECT_EQ(p->y.data, 2); - EXPECT_SPAN(p->d.span, 1,13, 1,13); - EXPECT_EQ(p->d.data, DIR::NW); - EXPECT_SPAN(script->key_span, 1,15, 1,20); - EXPECT_SPAN(p->name.span, 1,22, 1,25); - EXPECT_EQ(p->name.data, stringish<NpcName>("Init"_s)); - EXPECT_SPAN(p->key4_span, 1,27, 1,28); - if (input.endswith('}')) - { - EXPECT_SPAN(script->body.span, 1,29, 1,34); + EXPECT_SPAN(script->body.span, 1,23, 1,28); } else if (input.endswith('\n')) { diff --git a/src/ast/quest.cpp b/src/ast/quest.cpp new file mode 100644 index 0000000..bd339c2 --- /dev/null +++ b/src/ast/quest.cpp @@ -0,0 +1,125 @@ +#include "quest.hpp" +// ast/quest.cpp - Structure of tmwa questdb +// +// Copyright © 2015 Ed Pasek <pasekei@gmail.com> +// +// 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 "../io/extract.hpp" +#include "../io/line.hpp" + +#include "../mmo/extract_enums.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +namespace ast +{ +namespace quest +{ + using io::respan; + + static + void skip_comma_space(io::LineCharReader& lr) + { + io::LineChar c; + if (lr.get(c) && c.ch() == ',') + { + lr.adv(); + while (lr.get(c) && c.ch() == ' ') + { + lr.adv(); + } + } + } + static + Option<Spanned<RString>> lex_nonscript(io::LineCharReader& lr, bool first) + { + io::LineChar c; + if (first) + { + while (lr.get(c) && c.ch() == '\n') + { + lr.adv(); + } + } + if (!lr.get(c)) + { + return None; + } + io::LineSpan span; + MString accum; + accum += c.ch(); + span.begin = c; + span.end = c; + lr.adv(); + if (c.ch() != '/') + first = false; + + if (first && lr.get(c) && c.ch() == '/') + { + accum += c.ch(); + span.end = c; + lr.adv(); + while (lr.get(c) && c.ch() != '\n') + { + accum += c.ch(); + span.end = c; + lr.adv(); + } + return Some(respan(span, RString(accum))); + } + + while (lr.get(c) && c.ch() != ',' && c.ch() != '\n') + { + accum += c.ch(); + span.end = c; + lr.adv(); + } + skip_comma_space(lr); + return Some(respan(span, RString(accum))); + } + +#define SPAN_EXTRACT(bitexpr, var) ({ auto bit = bitexpr; if (!extract(bit.data, &var.data)) return Err(bit.span.error_str("failed to extract "_s #var)); var.span = bit.span; }) + +#define EOL_ERROR(lr) ({ io::LineChar c; lr.get(c) ? Err(c.error_str("unexpected EOL"_s)) : Err("unexpected EOF before unexpected EOL"_s); }) + Option<Result<QuestOrComment>> parse_quest(io::LineCharReader& lr) + { + Spanned<RString> first = TRY_UNWRAP(lex_nonscript(lr, true), return None); + if (first.data.startswith("//"_s)) + { + Comment comment; + comment.comment = first.data; + QuestOrComment rv = std::move(comment); + rv.span = first.span; + return Some(Ok(std::move(rv))); + } + Quest quest; + SPAN_EXTRACT(first, quest.questid); + SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), quest.quest_var); + SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), quest.quest_vr); + SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), quest.quest_shift); + SPAN_EXTRACT(TRY_UNWRAP(lex_nonscript(lr, false), return EOL_ERROR(lr)), quest.quest_mask); + QuestOrComment rv = std::move(quest); + rv.span.begin = quest.questid.span.begin; + rv.span.end = quest.quest_mask.span.end; + return Some(Ok(std::move(rv))); + } +} // namespace quest +} // namespace ast +} // namespace tmwa diff --git a/src/ast/quest.hpp b/src/ast/quest.hpp new file mode 100644 index 0000000..5112524 --- /dev/null +++ b/src/ast/quest.hpp @@ -0,0 +1,65 @@ +#pragma once +// ast/quest.hpp - Structure of tmwa questdb +// +// Copyright © 2015 Ed Pasek <pasekei@gmail.com> +// +// 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 Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include "fwd.hpp" + +#include "../compat/result.hpp" + +#include "../io/span.hpp" + +#include "../sexpr/variant.hpp" + +#include "../mmo/clif.t.hpp" +#include "../mmo/ids.hpp" +#include "../mmo/strs.hpp" + +namespace tmwa +{ +namespace ast +{ +namespace quest +{ + using io::Spanned; + + struct Comment + { + RString comment; + }; + struct Quest + { + Spanned<QuestId> questid; + Spanned<VarName> quest_var; + Spanned<VarName> quest_vr; + Spanned<int> quest_shift; + Spanned<int> quest_mask; + }; + + using QuestOrCommentBase = Variant<Comment, Quest>; + struct QuestOrComment : QuestOrCommentBase + { + QuestOrComment(Comment o) : QuestOrCommentBase(std::move(o)) {} + QuestOrComment(Quest o) : QuestOrCommentBase(std::move(o)) {} + io::LineSpan span; + }; + + Option<Result<QuestOrComment>> parse_quest(io::LineCharReader& lr); +} // namespace quest +} // namespace ast +} // namespace tmwa diff --git a/src/char/char.cpp b/src/char/char.cpp index a9b6834..ed9e369 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -1223,28 +1223,6 @@ void parse_tologin(Session *ls) break; } - case 0x2721: // gm reply - { - Packet_Fixed<0x2721> fixed; - rv = recv_fpacket<0x2721, 10>(ls, fixed); - if (rv != RecvResult::Complete) - break; - - { - AccountId acc = fixed.account_id; - GmLevel gml = fixed.gm_level; - - Packet_Fixed<0x2b0b> fixed_2b; - fixed_2b.account_id = acc; - fixed_2b.gm_level = gml; - for (Session *ss : iter_map_sessions()) - { - send_fpacket<0x2b0b, 10>(ss, fixed_2b); - } - } - break; - } - case 0x2723: // changesex reply (modified by [Yor]) { Packet_Fixed<0x2723> fixed; @@ -1857,33 +1835,6 @@ void parse_frommap(Session *ms) break; } - // it is a request to become GM - case 0x2b0a: - { - Packet_Head<0x2b0a> head; - AString repeat; - rv = recv_vpacket<0x2b0a, 8, 1>(ms, head, repeat); - if (rv != RecvResult::Complete) - break; - - AccountId account_id = head.account_id; - if (login_session) - { // don't send request if no login-server - Packet_Head<0x2720> head_20; - head_20.account_id = account_id; - AString& repeat_20 = repeat; - send_vpacket<0x2720, 8, 1>(login_session, head_20, repeat_20); - } - else - { - Packet_Fixed<0x2b0b> fixed_0b; - fixed_0b.account_id = account_id; - fixed_0b.gm_level = GmLevel(); - send_fpacket<0x2b0b, 10>(ms, fixed_0b); - } - break; - } - // Map server send information to change an email of an account -> login-server case 0x2b0c: { diff --git a/src/login/login.cpp b/src/login/login.cpp index 66b3ea0..92f8cc0 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -982,93 +982,6 @@ void parse_fromchar(Session *s) break; } - case 0x2720: // To become GM request - { - Packet_Head<0x2720> head; - AString repeat; - rv = recv_vpacket<0x2720, 8, 1>(s, head, repeat); - if (rv != RecvResult::Complete) - break; - - { - AccountId acc = head.account_id; - - Packet_Fixed<0x2721> fixed_21; - fixed_21.account_id = acc; - fixed_21.gm_level = GmLevel(); - - AString pass = repeat; - - if (pass == login_conf.gm_pass) - { - // only non-GM can become GM - if (!isGM(acc)) - { - // if we autorise creation - if (login_conf.level_new_gm) - { - // if we can open the file to add the new GM - io::AppendFile fp(login_conf.gm_account_filename); - if (fp.is_open()) - { - timestamp_seconds_buffer tmpstr; - stamp_time(tmpstr); - FPRINTF(fp, - "\n// %s: @GM command on account %d\n%d %d\n"_fmt, - tmpstr, - acc, acc, login_conf.level_new_gm); - if (!fp.close()) - { - PRINTF("warning: didn't actually save GM file\n"_fmt); - } - fixed_21.gm_level = login_conf.level_new_gm; - read_gm_account(); - send_GM_accounts(); - PRINTF("GM Change of the account %d: level 0 -> %d.\n"_fmt, - acc, login_conf.level_new_gm); - LOGIN_LOG("Char-server '%s': GM Change of the account %d: level 0 -> %d (ip: %s).\n"_fmt, - server[id].name, acc, - login_conf.level_new_gm, ip); - } - else - { - PRINTF("Error of GM change (suggested account: %d, correct password, unable to add a GM account in GM accounts file)\n"_fmt, - acc); - LOGIN_LOG("Char-server '%s': Error of GM change (suggested account: %d, correct password, unable to add a GM account in GM accounts file, ip: %s).\n"_fmt, - server[id].name, acc, ip); - } - } - else - { - PRINTF("Error of GM change (suggested account: %d, correct password, but GM creation is disable (level_new_gm = 0))\n"_fmt, - acc); - LOGIN_LOG("Char-server '%s': Error of GM change (suggested account: %d, correct password, but GM creation is disable (level_new_gm = 0), ip: %s).\n"_fmt, - server[id].name, acc, ip); - } - } - else - { - PRINTF("Error of GM change (suggested account: %d (already GM), correct password).\n"_fmt, - acc); - LOGIN_LOG("Char-server '%s': Error of GM change (suggested account: %d (already GM), correct password, ip: %s).\n"_fmt, - server[id].name, acc, ip); - } - } - else - { - PRINTF("Error of GM change (suggested account: %d, invalid password).\n"_fmt, - acc); - LOGIN_LOG("Char-server '%s': Error of GM change (suggested account: %d, invalid password, ip: %s).\n"_fmt, - server[id].name, acc, ip); - } - for (Session *ss : iter_char_sessions()) - { - send_fpacket<0x2721, 10>(ss, fixed_21); - } - } - break; - } - // Map server send information to change an email of an account via char-server case 0x2722: // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B { diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index f226706..7739966 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -701,6 +701,69 @@ ATCE atcommand_goto(Session *s, dumb_ptr<map_session_data> sd, } static +ATCE atcommand_npc(Session *s, dumb_ptr<map_session_data> sd, + ZString message) +{ + NpcName npc; + + if (!asplit(message, &npc)) + { + clif_displaymessage(s, + "Please, enter a npc name (usage: @npc/@warptonpc/@gotonpc <npc>)."_s); + return ATCE::USAGE; + } + + dumb_ptr<npc_data> nd = npc_name2id(npc); + if (nd != nullptr) + { + if (nd->bl_m->flag.get(MapFlag::NOWARPTO) + && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level))) + { + clif_displaymessage(s, + "You are not authorised to warp you to the map of this npc."_s); + return ATCE::PERM; + } + if (sd->bl_m->flag.get(MapFlag::NOWARP) + && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level))) + { + clif_displaymessage(s, + "You are not authorised to warp you from your actual map."_s); + return ATCE::PERM; + } + + int x = nd->bl_x, y = nd->bl_y, x0 = (x >= 5)? (x - 5): 0, j = 0, + y0 = (y >= 5)? (y - 5): 0, x1 = (x + 5), y1 = (y + 5), max; + max = (y1 - y0 + 1) * (x1 - x0 + 1) * 3; + P<map_local> m = TRY_UNWRAP(map_mapname2mapid(nd->bl_m->name_), return ATCE::OKAY); + if (max > 1000) + max = 1000; + if (bool(map_getcell(m, x, y) & MapCell::UNWALKABLE)){ + do + { + x = random_::in(x0, x1); + y = random_::in(y0, y1); + } + while (bool(map_getcell(m, x, y) & MapCell::UNWALKABLE) + && (++j) < max); + if (j >= max) + { + return ATCE::OKAY; // Since reference of the place which boils first went wrong, it stops. + } + } + pc_setpos(sd, nd->bl_m->name_, x, y, BeingRemoveWhy::WARPED); + AString output = STRPRINTF("Jump to %s"_fmt, npc); + clif_displaymessage(s, output); + } + else + { + clif_displaymessage(s, "Npc not found."_s); + return ATCE::EXIST; + } + + return ATCE::OKAY; +} + +static ATCE atcommand_jump(Session *s, dumb_ptr<map_session_data> sd, ZString message) { @@ -1528,25 +1591,6 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr<map_session_data> sd, } static -ATCE atcommand_gm(Session *s, dumb_ptr<map_session_data> sd, - ZString message) -{ - if (!message) - return ATCE::USAGE; - - if (pc_isGM(sd)) - { - // a GM can not use this function. only a normal player (become gm is not for gm!) - clif_displaymessage(s, "You already have some GM powers."_s); - return ATCE::PERM; - } - else - chrif_changegm(sd->status_key.account_id, message); - - return ATCE::OKAY; -} - -static ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd, ZString) { @@ -1586,6 +1630,25 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd, } static +ATCE atcommand_exprate(Session *s, dumb_ptr<map_session_data>, + ZString message) +{ + int rate; + + if (!extract(message, &rate) || !rate) + { + clif_displaymessage(s, + "Please, enter a rate adjustement (usage: @exprate <percent>)."_s); + return ATCE::USAGE; + } + battle_config.base_exp_rate = rate; + battle_config.job_exp_rate = rate; + AString output = STRPRINTF("All Xp at %d percent"_fmt, rate); + clif_displaymessage(s, output); + return ATCE::OKAY; +} + +static ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd, ZString) { @@ -4907,6 +4970,9 @@ Map<XString, AtCommandInfo> atcommand_info = {"goto"_s, {"<charname>"_s, 40, atcommand_goto, "Warp yourself to another character"_s}}, + {"npc"_s, {"<npc>"_s, + 40, atcommand_npc, + "Warp yourself to a npc"_s}}, {"jump"_s, {"[x] [y]"_s, 40, atcommand_jump, "Warp yourself within a map"_s}}, @@ -4976,12 +5042,12 @@ Map<XString, AtCommandInfo> atcommand_info = {"jlvl"_s, {"<delta>"_s, 60, atcommand_joblevelup, "Adjust your job level"_s}}, - {"gm"_s, {"<password>"_s, - 100, atcommand_gm, - "Receive GM powers"_s}}, {"pvpoff"_s, {""_s, 60, atcommand_pvpoff, "Enable PvP on your map"_s}}, + {"exprate"_s, {"<percent>"_s, + 60, atcommand_exprate, + "Set base job/exp rate"_s}}, {"pvpon"_s, {""_s, 60, atcommand_pvpon, "Disable PvP on your map"_s}}, diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index bf4ae4e..2606911 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -218,7 +218,7 @@ int chrif_changemapserverack(Session *, const Packet_Fixed<0x2b06>& fixed) if (fixed.error == 1) { if (battle_config.error_log) - PRINTF("map server change failed.\n"_fmt); + PRINTF("Changing the map server failed.\n"_fmt); pc_authfail(sd->status_key.account_id); return 0; } @@ -241,7 +241,7 @@ int chrif_connectack(Session *s, const Packet_Fixed<0x2af9>& fixed) { if (fixed.code) { - PRINTF("Connected to char-server failed %d.\n"_fmt, fixed.code); + PRINTF("Connecting to char-server failed %d.\n"_fmt, fixed.code); exit(1); } PRINTF("Connected to char-server (connection #%d).\n"_fmt, s); @@ -249,11 +249,6 @@ int chrif_connectack(Session *s, const Packet_Fixed<0x2af9>& fixed) chrif_sendmap(s); - PRINTF("chrif: OnCharIfInit event done. (%d events)\n"_fmt, - npc_event_doall(stringish<ScriptLabel>("OnCharIfInit"_s))); - PRINTF("chrif: OnInterIfInit event done. (%d events)\n"_fmt, - npc_event_doall(stringish<ScriptLabel>("OnInterIfInit"_s))); - return 0; } @@ -266,7 +261,7 @@ int chrif_sendmapack(Session *, Packet_Fixed<0x2afb> fixed) { if (fixed.unknown) //impossible { - PRINTF("chrif : send map list to char server failed %d\n"_fmt, + PRINTF("chrif: sending the map list to char-server failed %d\n"_fmt, fixed.unknown); exit(1); } @@ -345,23 +340,6 @@ int chrif_charselectreq(dumb_ptr<map_session_data> sd) } /*========================================== - * GMに変化要求 - *------------------------------------------ - */ -void chrif_changegm(AccountId id, ZString pass) -{ - if (!char_session) - return; - - if (battle_config.etc_log) - PRINTF("chrif_changegm: account: %d, password: '%s'.\n"_fmt, id, pass); - - Packet_Head<0x2b0a> head_0a; - head_0a.account_id = id; - send_vpacket<0x2b0a, 8, 1>(char_session, head_0a, pass); -} - -/*========================================== * Change Email *------------------------------------------ */ @@ -405,7 +383,7 @@ void chrif_char_ask_name(AccountId id, CharName character_name, short operation_ fixed_0e.operation = operation_type; // type of operation if (operation_type == 2) fixed_0e.ban_add = modif; - PRINTF("chrif : sended 0x2b0e\n"_fmt); + PRINTF("chrif: sent 0x2b0e\n"_fmt); send_fpacket<0x2b0e, 44>(char_session, fixed_0e); } @@ -419,7 +397,7 @@ void chrif_char_ask_name(AccountId id, CharName character_name, short operation_ * 4: unban * 5: changesex * type of answer: - * 0: login-server resquest done + * 0: login-server request done * 1: player not found * 2: gm level too low * 3: login-server offline @@ -436,7 +414,7 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) { AString output; if (fixed.error == 1) // player not found - output = STRPRINTF("The player '%s' doesn't exist."_fmt, + output = STRPRINTF("The player, '%s,' doesn't exist."_fmt, player_name); else { @@ -445,20 +423,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) case 1: // block switch (fixed.error) { - case 0: // login-server resquest done + case 0: // login-server request done output = STRPRINTF( - "Login-server has been asked to block the player '%s'."_fmt, + "Login-server has been asked to block '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to block the player '%s'."_fmt, + "Your GM level doesn't authorize you to block the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to block the the player '%s'."_fmt, + "Login-server is offline, so it's impossible to block '%s'."_fmt, player_name); break; } @@ -466,20 +444,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) case 2: // ban switch (fixed.error) { - case 0: // login-server resquest done + case 0: // login-server request done output = STRPRINTF( - "Login-server has been asked to ban the player '%s'."_fmt, + "Login-server has been asked to ban '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to ban the player '%s'."_fmt, + "Your GM level doesn't authorize you to ban '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to ban the the player '%s'."_fmt, + "Login-server is offline, so it's impossible to ban '%s'."_fmt, player_name); break; } @@ -487,20 +465,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) case 3: // unblock switch (fixed.error) { - case 0: // login-server resquest done + case 0: // login-server request done output = STRPRINTF( - "Login-server has been asked to unblock the player '%s'."_fmt, + "Login-server has been asked to unblock '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to unblock the player '%s'."_fmt, + "Your GM level doesn't authorize you to unblock '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to unblock the the player '%s'."_fmt, + "Login-server is offline, so it's impossible to unblock '%s'."_fmt, player_name); break; } @@ -508,20 +486,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) case 4: // unban switch (fixed.error) { - case 0: // login-server resquest done + case 0: // login-server request done output = STRPRINTF( - "Login-server has been asked to unban the player '%s'."_fmt, + "Login-server has been asked to unban '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to unban the player '%s'."_fmt, + "Your GM level doesn't authorize you to unban '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to unban the the player '%s'."_fmt, + "Login-server is offline, so it's impossible to unban '%s'."_fmt, player_name); break; } @@ -529,20 +507,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) case 5: // changesex switch (fixed.error) { - case 0: // login-server resquest done + case 0: // login-server request done output = STRPRINTF( - "Login-server has been asked to change the sex of the player '%s'."_fmt, + "Login-server has been asked to change the sex of '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( - "Your GM level don't authorise you to change the sex of the player '%s'."_fmt, + "Your GM level doesn't authorize you to change the sex of '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( - "Login-server is offline. Impossible to change the sex of the the player '%s'."_fmt, + "Login-server is offline, so it's impossible to change the sex of '%s'."_fmt, player_name); break; } @@ -553,36 +531,12 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed) clif_displaymessage(sd->sess, output); } else - PRINTF("chrif_char_ask_name_answer failed - player not online.\n"_fmt); + PRINTF("chrif_char_ask_name_answer failed because the player is not online.\n"_fmt); return 0; } /*========================================== - * End of GM change(@GM) (modified by Yor) - *------------------------------------------ - */ -static -void chrif_changedgm(Session *, const Packet_Fixed<0x2b0b>& fixed) -{ - AccountId acc = fixed.account_id; - GmLevel level = fixed.gm_level; - - dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(acc)); - - if (battle_config.etc_log) - PRINTF("chrif_changedgm: account: %d, GM level 0 -> %d.\n"_fmt, acc, - level); - if (sd != nullptr) - { - if (level) - clif_displaymessage(sd->sess, "GM modification success."_s); - else - clif_displaymessage(sd->sess, "Failure of GM modification."_s); - } -} - -/*========================================== * 性別変化終了 (modified by Yor) *------------------------------------------ */ @@ -609,15 +563,14 @@ void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed) { if (sd->status.inventory[i].nameid && bool(sd->status.inventory[i].equip)) - pc_unequipitem(sd, i, CalcStatus::NOW); + pc_unequipitem(sd, i, CalcStatus::LATER); } + pc_calcstatus(sd, 0); // save character chrif_save(sd); sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it) - clif_displaymessage(sd->sess, - "Your sex has been changed (need disconexion by the server)..."_s); - clif_setwaitclose(sd->sess); // forced to disconnect for the change + clif_fixpcpos(sd); // use clif_set0078_main_1d8 to send new sex to the client } } else @@ -746,14 +699,14 @@ int chrif_accountdeletion(Session *, const Packet_Fixed<0x2b13>& fixed) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters clif_displaymessage(sd->sess, - "Your account has been deleted (disconnection)..."_s); + "Your account has been deleted. You will now be disconnected..."_s); clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { if (sd != nullptr) - PRINTF("chrif_accountdeletion failed - player not online.\n"_fmt); + PRINTF("chrif_accountdeletion failed because the player is not online.\n"_fmt); } return 0; @@ -783,11 +736,11 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) { // status or final date of a banishment case 1: // 0 = Unregistered ID clif_displaymessage(sd->sess, - "Your account has 'Unregistered'."_s); + "Your account has an unregistered ID."_s); break; case 2: // 1 = Incorrect Password clif_displaymessage(sd->sess, - "Your account has an 'Incorrect Password'..."_s); + "Your password is incorrect."_s); break; case 3: // 2 = This ID is expired clif_displaymessage(sd->sess, @@ -795,7 +748,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) break; case 4: // 3 = Rejected from Server clif_displaymessage(sd->sess, - "Your account has been rejected from server."_s); + "Your account has been rejected by the server."_s); break; case 5: // 4 = You have been blocked by the GM Team clif_displaymessage(sd->sess, @@ -803,19 +756,19 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) break; case 6: // 5 = Your Game's EXE file is not the latest version clif_displaymessage(sd->sess, - "Your Game's EXE file is not the latest version."_s); + "You need to update your client."_s); break; case 7: // 6 = Your are Prohibited to log in until %s clif_displaymessage(sd->sess, - "Your account has been prohibited to log in."_s); + "Your account has been prohibited from logging in."_s); break; case 8: // 7 = Server is jammed due to over populated clif_displaymessage(sd->sess, - "Server is jammed due to over populated."_s); + "The server is overpopulated."_s); break; case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this) clif_displaymessage(sd->sess, - "Your account has not more authorised."_s); + "Your account must be authorized."_s); break; case 100: // 99 = This ID has been totally erased clif_displaymessage(sd->sess, @@ -823,7 +776,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) break; default: clif_displaymessage(sd->sess, - "Your account has not more authorised."_s); + "Your account must be authorized."_s); break; } } @@ -842,7 +795,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) else { if (sd != nullptr) - PRINTF("chrif_accountban failed - player not online.\n"_fmt); + PRINTF("chrif_accountban failed because the player is not online.\n"_fmt); } return 0; @@ -855,7 +808,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) static int chrif_recvgmaccounts(Session *s, const std::vector<Packet_Repeat<0x2b15>>& repeat) { - PRINTF("From login-server: receiving of %d GM accounts information.\n"_fmt, + PRINTF("Receiving information on %d GM accounts from login-server.\n"_fmt, pc_read_gm_account(s, repeat)); return 0; @@ -865,7 +818,7 @@ static void chrif_delete(Session *s) { assert (s == char_session); - PRINTF("Map-server can't connect to char-server (connection #%d).\n"_fmt, + PRINTF("map-server can't connect to char-server (connection #%d).\n"_fmt, s); char_session = nullptr; } @@ -973,16 +926,6 @@ void chrif_parse(Session *s) chrif_changemapserverack(s, fixed); break; } - case 0x2b0b: - { - Packet_Fixed<0x2b0b> fixed; - rv = recv_fpacket<0x2b0b, 10>(s, fixed); - if (rv != RecvResult::Complete) - break; - - chrif_changedgm(s, fixed); - break; - } case 0x2b0d: { Packet_Fixed<0x2b0d> fixed; @@ -1064,7 +1007,7 @@ void chrif_parse(Session *s) return; if (battle_config.error_log) - PRINTF("chrif_parse : unknown packet %d %d\n"_fmt, s, + PRINTF("chrif_parse: unknown packet %d %d\n"_fmt, s, packet_id); s->set_eof(); return; @@ -1118,7 +1061,7 @@ void check_connect_char_server(TimerData *, tick_t) { if (!char_session) { - PRINTF("Attempt to connect to char-server...\n"_fmt); + PRINTF("Attempting to connect to char-server...\n"_fmt); chrif_state = 0; char_session = make_connection(map_conf.char_ip, map_conf.char_port, SessionParsers{.func_parse= chrif_parse, .func_delete= chrif_delete}); diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 577d7be..2c65d44 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -198,11 +198,6 @@ int is_deaf(dumb_ptr<block_list> bl) return sd->special_state.deaf; } -static -void clif_emotion_towards(dumb_ptr<block_list> bl, - dumb_ptr<block_list> target, int type); - - enum class ChatType { Party, @@ -906,7 +901,7 @@ int clif_spawnnpc(dumb_ptr<npc_data> nd) { nullpo_retz(nd); - if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) + if (nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) return 0; Packet_Fixed<0x007c> fixed_7c; @@ -2325,7 +2320,7 @@ void clif_getareachar_npc(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data> nd) nullpo_retv(sd); nullpo_retv(nd); - if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) + if (nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) return; Buffer buf; @@ -3113,7 +3108,6 @@ void clif_emotion(dumb_ptr<block_list> bl, int type) clif_send(buf, bl, SendWho::AREA); } -static void clif_emotion_towards(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int type) { @@ -4671,6 +4665,60 @@ RecvResult clif_parse_PartyMessage(Session *s, dumb_ptr<map_session_data> sd) return rv; } +void clif_sendallquest(dumb_ptr<map_session_data> sd) +{ + int i; + QuestId questid; + if (!sd) + return; + + if (!sd->sess) + return; + + Session *s = sd->sess; + Packet_Head<0x0215> head_215; + std::vector<Packet_Repeat<0x0215>> repeat_215; + + assert (sd->status.global_reg_num < GLOBAL_REG_NUM); + for (QuestId q = wrap<QuestId>(0); q < wrap<QuestId>(-1); q = next(q)) + { + P<struct quest_data> quest_data_ = TRY_UNWRAP(questdb_exists(q), continue); + for (i = 0; i < sd->status.global_reg_num; i++) + { + if (sd->status.global_reg[i].str == quest_data_->quest_vr) + { + int val = ((sd->status.global_reg[i].value & (((1 << quest_data_->quest_mask) - 1) << (quest_data_->quest_shift * quest_data_->quest_mask))) >> (quest_data_->quest_shift * quest_data_->quest_mask)); + Packet_Repeat<0x0215> info; + info.variable = unwrap<QuestId>(quest_data_->questid); + info.value = val; + repeat_215.push_back(info); + break; + } + } + } + + send_vpacket<0x0215, 4, 6>(s, head_215, repeat_215); + return; +} + +void clif_sendquest(dumb_ptr<map_session_data> sd, QuestId questid, int value) +{ + if (!sd) + return; + + if (!sd->sess) + return; + + Session *s = sd->sess; + + Packet_Fixed<0x0214> fixed; + fixed.variable = unwrap<QuestId>(questid); + fixed.value = value; + send_fpacket<0x0214, 8>(s, fixed); + return; +} + + func_table clif_parse_func_table[0x0220] = { {0, 10, nullptr, }, // 0x0000 diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 153cc7c..5117ff3 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -96,6 +96,7 @@ int clif_changeoption(dumb_ptr<block_list>); // area int clif_useitemack(dumb_ptr<map_session_data>, IOff0, int, int); // self void clif_emotion(dumb_ptr<block_list> bl, int type); +void clif_emotion_towards(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int type); void clif_sitting(Session *, dumb_ptr<map_session_data> sd); // trade @@ -174,6 +175,9 @@ int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, int type); int clif_foreachclient(std::function<void(dumb_ptr<map_session_data>)>); +// quest +void clif_sendallquest(dumb_ptr<map_session_data> sd); +void clif_sendquest(dumb_ptr<map_session_data> sd, QuestId questid, int value); void do_init_clif(void); } // namespace map diff --git a/src/map/fwd.hpp b/src/map/fwd.hpp index 1db4ed0..911d566 100644 --- a/src/map/fwd.hpp +++ b/src/map/fwd.hpp @@ -65,6 +65,7 @@ class npc_data_warp; class npc_data_message; struct item_data; +struct quest_data; struct ScriptState; struct str_data_t; diff --git a/src/map/globals.cpp b/src/map/globals.cpp index 09ff157..dce3906 100644 --- a/src/map/globals.cpp +++ b/src/map/globals.cpp @@ -26,6 +26,7 @@ #include "battle_conf.hpp" #include "itemdb.hpp" +#include "quest.hpp" #include "magic-interpreter.hpp" #include "map_conf.hpp" #include "mob.hpp" @@ -49,6 +50,7 @@ namespace tmwa int chrif_state; std::map<MapName, RString> resnametable; Map<ItemNameId, item_data> item_db; + Map<QuestId, quest_data> quest_db; namespace magic { // Global magic conf diff --git a/src/map/globals.hpp b/src/map/globals.hpp index 33cfec8..b457b4e 100644 --- a/src/map/globals.hpp +++ b/src/map/globals.hpp @@ -48,6 +48,7 @@ namespace tmwa extern int chrif_state; extern std::map<MapName, RString> resnametable; extern Map<ItemNameId, item_data> item_db; + extern Map<QuestId, quest_data> quest_db; namespace magic { // Global magic conf diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index fdeac3a..4d8330a 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -773,7 +773,7 @@ int op_injure(dumb_ptr<env_t> env, Slice<val_t> args) if (target->bl_type == BL::PC && !target->bl_m->flag.get(MapFlag::PVP) - && (caster->bl_type != BL::PC) + && (caster->bl_type == BL::PC) && ((caster->is_player()->state.pvpchannel > 1) && (target->is_player()->state.pvpchannel != caster->is_player()->state.pvpchannel))) return 0; /* Cannot damage other players outside of pvp */ diff --git a/src/map/map.cpp b/src/map/map.cpp index d502fbb..c1d760a 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -74,6 +74,7 @@ #include "magic-v2.hpp" #include "map_conf.hpp" #include "mob.hpp" +#include "quest.hpp" #include "npc.hpp" #include "npc-parse.hpp" #include "party.hpp" @@ -1489,6 +1490,8 @@ bool map_confs(io::Spanned<XString> key, io::Spanned<ZString> value) return itemdb_readdb(value.data); if (key.data == "mob_db"_s) return mob_readdb(value.data); + if (key.data == "quest_db"_s) + return quest_readdb(value.data); if (key.data == "mob_skill_db"_s) return mob_readskilldb(value.data); if (key.data == "skill_db"_s) diff --git a/src/map/mob.cpp b/src/map/mob.cpp index cdb348c..539b547 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -333,8 +333,7 @@ int mob_gen_exp(mob_db_ *mob) int xp = floor(effective_hp * pow(sqrt(attack_factor) + sqrt(dodge_factor) + sqrt(persuit_factor) + 55, 3) - * aggression_factor / 2000000.0 - * static_cast<double>(battle_config.base_exp_rate) / 100.); + * aggression_factor / 2000000.0); if (xp < 1) xp = 1; PRINTF("Exp for mob '%s' generated: %d\n"_fmt, mob->name, xp); @@ -3531,30 +3530,33 @@ bool mob_readdb(ZString filename) continue; } - // TODO move this lower - get_mob_db(mob_class) = std::move(mdbv); - if (get_mob_db(mob_class).base_exp < 0) - get_mob_db(mob_class).base_exp = 0; - else if (get_mob_db(mob_class).base_exp > 0 - && (get_mob_db(mob_class).base_exp * - battle_config.base_exp_rate / 100 > 1000000000 - || get_mob_db(mob_class).base_exp * - battle_config.base_exp_rate / 100 < 0)) - get_mob_db(mob_class).base_exp = 1000000000; - else - get_mob_db(mob_class).base_exp = get_mob_db(mob_class).base_exp * battle_config.base_exp_rate / 100; - + { + PRINTF("bad mob line: Xp needs to be greater than 0. %s\n"_fmt, line); + rv = false; + continue; + } + if (get_mob_db(mob_class).base_exp > 1000000000) + { + PRINTF("bad mob line: Xp needs to be less than 1000000000. %s\n"_fmt, line); + rv = false; + continue; + } if (get_mob_db(mob_class).job_exp < 0) - get_mob_db(mob_class).job_exp = 0; - else if (get_mob_db(mob_class).job_exp > 0 - && (get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / - 100 > 1000000000 - || get_mob_db(mob_class).job_exp * - battle_config.job_exp_rate / 100 < 0)) - get_mob_db(mob_class).job_exp = 1000000000; - else - get_mob_db(mob_class).job_exp = get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / 100; + { + PRINTF("bad mob line: Job Xp needs to be greater than 0. %s\n"_fmt, line); + rv = false; + continue; + } + if (get_mob_db(mob_class).job_exp > 1000000000) + { + PRINTF("bad mob line: Job Xp needs to be less than 1000000000. %s\n"_fmt, line); + rv = false; + continue; + } + + // TODO move this lower + get_mob_db(mob_class) = std::move(mdbv); for (int i = 0; i < 8; i++) { diff --git a/src/map/npc-parse.cpp b/src/map/npc-parse.cpp index 443a1e7..4d9fcbd 100644 --- a/src/map/npc-parse.cpp +++ b/src/map/npc-parse.cpp @@ -339,7 +339,7 @@ bool npc_load_mapflag(ast::npc::MapFlag& mapflag) return false; } - if (battle_config.pk_mode && mf == MapFlag::NOPVP) + if (mf == MapFlag::NOPVP) { if (mapflag.vec_extra.data.size()) { @@ -446,7 +446,7 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s nd->bl_id = npc_get_new_npc_id(); nd->dir = DIR::S; nd->flag = 0; - nd->npc_class = NEGATIVE_SPECIES; + nd->npc_class = INVISIBLE_CLASS; nd->speed = 200_ms; nd->scr.script = std::move(script); nd->option = Opt0::ZERO; @@ -514,115 +514,6 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s } static -bool npc_load_script_map_none(ast::script::ScriptBody& body, ast::npc::ScriptMapNone& script_map_none) -{ - MapName mapname = script_map_none.m.data; - int x = script_map_none.x.data, y = script_map_none.y.data; - DIR dir = script_map_none.d.data; - P<map_local> m = TRY_UNWRAP(map_mapname2mapid(mapname), - { - script_map_none.m.span.error("No such map"_s); - return false; - }); - - std::unique_ptr<const ScriptBuffer> script = compile_script(STRPRINTF("script npc \"%s\""_fmt, script_map_none.name.data), body, false); - if (script == nullptr) - return false; - - dumb_ptr<npc_data_script> nd; - nd.new_(); - nd->scr.event_needs_map = false; - - nd->name = script_map_none.name.data; - - nd->bl_prev = nd->bl_next = nullptr; - nd->bl_m = m; - nd->bl_x = x; - nd->bl_y = y; - nd->bl_id = npc_get_new_npc_id(); - nd->dir = dir; - nd->flag = 0; - nd->npc_class = NEGATIVE_SPECIES; - nd->speed = 200_ms; - nd->scr.script = std::move(script); - nd->option = Opt0::ZERO; - nd->opt1 = Opt1::ZERO; - nd->opt2 = Opt2::ZERO; - nd->opt3 = Opt3::ZERO; - - npc_script++; - nd->bl_type = BL::NPC; - nd->npc_subtype = NpcSubtype::SCRIPT; - - nd->n = map_addnpc(m, nd); - map_addblock(nd); - - { - struct event_data ev {}; - ev.nd = nd; - ev.pos = 0; - NpcEvent npcev; - npcev.npc = nd->name; - npcev.label = ScriptLabel(); - ev_db.insert(npcev, ev); - } - - register_npc_name(nd); - - for (auto& pair : scriptlabel_db) - npc_convertlabel_db(pair.first, pair.second, nd); - - for (npc_label_list& el : nd->scr.label_listv) - { - ScriptLabel lname = el.name; - int pos = el.pos; - - if (lname.startswith("On"_s)) - { - struct event_data ev {}; - ev.nd = nd; - ev.pos = pos; - NpcEvent buf; - buf.npc = nd->name; - buf.label = lname; - ev_db.insert(buf, ev); - } - } - - for (npc_label_list& el : nd->scr.label_listv) - { - int t_ = 0; - ScriptLabel lname = el.name; - int pos = el.pos; - if (lname.startswith("OnTimer"_s) && extract(lname.xslice_t(7), &t_) && t_ > 0) - { - interval_t t = static_cast<interval_t>(t_); - - npc_timerevent_list tel {}; - tel.timer = t; - tel.pos = pos; - - auto it = std::lower_bound(nd->scr.timer_eventv.begin(), nd->scr.timer_eventv.end(), tel, - [](const npc_timerevent_list& l, const npc_timerevent_list& r) - { - return l.timer < r.timer; - } - ); - assert (it == nd->scr.timer_eventv.end() || it->timer != tel.timer); - - nd->scr.timer_eventv.insert(it, std::move(tel)); - } - } - // The counter starts stopped with 0 ticks, which is the first event, - // unless there is none, in which case begin == end. - nd->scr.timer = interval_t::zero(); - nd->scr.next_event = nd->scr.timer_eventv.begin(); - // nd->scr.timerid = nullptr; - - return true; -} - -static bool npc_load_script_map(ast::script::ScriptBody& body, ast::npc::ScriptMap& script_map) { MapName mapname = script_map.m.data; @@ -761,17 +652,6 @@ bool npc_load_script_any(ast::npc::Script *script) { return npc_load_script_none(script->body, script_none); } - MATCH_CASE (ast::npc::ScriptMapNone&, script_map_none) - { - auto& mapname = script_map_none.m; - Option<P<map_local>> m = map_mapname2mapid(mapname.data); - if (m.is_none()) - { - mapname.span.error(STRPRINTF("Map not found: %s"_fmt, mapname.data)); - return false; - } - return npc_load_script_map_none(script->body, script_map_none); - } MATCH_CASE (ast::npc::ScriptMap&, script_map) { auto& mapname = script_map.m; diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 56c33cc..4296432 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -583,7 +583,7 @@ int npc_checknear(dumb_ptr<map_session_data> sd, BlockId id) if (nd->bl_type != BL::NPC) return 1; - if (nd->npc_class == NEGATIVE_SPECIES) + if (nd->npc_class == INVISIBLE_CLASS) return 0; // エリア判定 diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 29be372..6fa35b0 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -64,6 +64,7 @@ #include "skill.hpp" #include "storage.hpp" #include "trade.hpp" +#include "quest.hpp" #include "../poison.hpp" @@ -794,6 +795,9 @@ int pc_authok(AccountId id, int login_id2, pc_calcstatus(sd, 1); + npc_event_doall_l(stringish<ScriptLabel>("OnPCLoginEvent"_s), sd->bl_id, nullptr); + // Init Quest Log + clif_sendallquest(sd); return 0; } @@ -2854,6 +2858,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, } } + // Double Xp Weekends + base_exp = (base_exp * static_cast<double>(battle_config.base_exp_rate) / 100.); + if (base_exp <= 0) + base_exp = 0; + else if (base_exp > 1000000000) + base_exp = 1000000000; sd->status.base_exp += base_exp; // [Fate] Adjust experience points that healers can extract from this character @@ -2861,7 +2871,6 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, { const int max_heal_xp = 20 + (sd->status.base_level * sd->status.base_level); - sd->heal_xp += base_exp; if (sd->heal_xp > max_heal_xp) sd->heal_xp = max_heal_xp; @@ -2884,6 +2893,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp, } } + // Double Xp Weekends + job_exp = (job_exp * static_cast<double>(battle_config.job_exp_rate) / 100.); + if (job_exp <= 0) + job_exp = 0; + else if (job_exp > 1000000000) + job_exp = 1000000000; sd->status.job_exp += job_exp; if (sd->status.job_exp < 0) sd->status.job_exp = 0; @@ -3480,8 +3495,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) } break; case SP::SEX: - // this is a really bad idea - sd->sex = static_cast<SEX>(val); + chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff()); break; case SP::WEIGHT: sd->weight = val; @@ -3507,7 +3521,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) case SP::INT: case SP::DEX: case SP::LUK: - sd->status.attrs[sp_to_attr(type)] = val; + pc_statusup2(sd, type, (val - sd->status.attrs[sp_to_attr(type)])); break; } clif_updatestatus(sd, type); @@ -3787,14 +3801,37 @@ void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, RString str) int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg) { int i; - + int quest_shift = 0; + int quest_mask = 0; nullpo_retz(sd); + QuestId questid; + XString var = reg; + VarName vr; assert (sd->status.global_reg_num < GLOBAL_REG_NUM); + Option<P<struct quest_data>> quest_data_ = questdb_searchname(var); + OMATCH_BEGIN_SOME(quest_data, quest_data_) + { + questid = quest_data->questid; + reg = quest_data->quest_vr; + vr = quest_data->quest_var; + quest_shift = quest_data->quest_shift; + quest_mask = quest_data->quest_mask; + } + OMATCH_END (); for (i = 0; i < sd->status.global_reg_num; i++) { if (sd->status.global_reg[i].str == reg) - return sd->status.global_reg[i].value; + { + if (questid) + { + return ((sd->status.global_reg[i].value & (((1 << quest_mask) - 1) << (quest_shift * quest_mask))) >> (quest_shift * quest_mask)); + } + else + { + return sd->status.global_reg[i].value; + } + } } return 0; @@ -3807,8 +3844,13 @@ int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg) int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { int i; - + int quest_shift = 0; + int quest_mask = 0; + int bitval = val; nullpo_retz(sd); + QuestId questid; + XString var = reg; + VarName vr; //PC_DIE_COUNTERがスクリプトなどで変更された時の処理 if (reg == stringish<VarName>("PC_DIE_COUNTER"_s) && sd->die_counter != val) @@ -3816,6 +3858,17 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) sd->die_counter = val; pc_calcstatus(sd, 0); } + Option<P<struct quest_data>> quest_data_ = questdb_searchname(var); + OMATCH_BEGIN_SOME(quest_data, quest_data_) + { + questid = quest_data->questid; + reg = quest_data->quest_vr; + vr = quest_data->quest_var; + quest_shift = quest_data->quest_shift; + quest_mask = quest_data->quest_mask; + assert (((1 << quest_mask) - 1) >= val); + } + OMATCH_END (); assert (sd->status.global_reg_num < GLOBAL_REG_NUM); if (val == 0) { @@ -3823,9 +3876,18 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { if (sd->status.global_reg[i].str == reg) { - sd->status.global_reg[i] = - sd->status.global_reg[sd->status.global_reg_num - 1]; - sd->status.global_reg_num--; + if (questid) + { + bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask))); + clif_sendquest(sd, questid, val); + } + sd->status.global_reg[i].value = bitval; + if (sd->status.global_reg[i].value == 0) + { + sd->status.global_reg[i] = + sd->status.global_reg[sd->status.global_reg_num - 1]; + sd->status.global_reg_num--; + } break; } } @@ -3835,14 +3897,24 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val) { if (sd->status.global_reg[i].str == reg) { - sd->status.global_reg[i].value = val; + if (questid) + { + bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask))); + clif_sendquest(sd, questid, val); + } + sd->status.global_reg[i].value = bitval; return 0; } } if (sd->status.global_reg_num < GLOBAL_REG_NUM) { sd->status.global_reg[i].str = reg; - sd->status.global_reg[i].value = val; + if (questid) + { + bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask))); + clif_sendquest(sd, questid, val); + } + sd->status.global_reg[i].value = bitval; sd->status.global_reg_num++; return 0; } diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 6879f79..d100938 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -28,6 +28,7 @@ #include "../mmo/clif.t.hpp" #include "map.hpp" +#include "quest.hpp" namespace tmwa @@ -145,6 +146,8 @@ int pc_readreg(dumb_ptr<map_session_data>, SIR); void pc_setreg(dumb_ptr<map_session_data>, SIR, int); ZString pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg); void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, RString str); +void update_quest(dumb_ptr<map_session_data> sd, VarName quest_var, int value); +void update_allquest(dumb_ptr<map_session_data> sd); int pc_readglobalreg(dumb_ptr<map_session_data>, VarName ); int pc_setglobalreg(dumb_ptr<map_session_data>, VarName , int); int pc_readaccountreg(dumb_ptr<map_session_data>, VarName ); diff --git a/src/map/quest.cpp b/src/map/quest.cpp new file mode 100644 index 0000000..dfe19ff --- /dev/null +++ b/src/map/quest.cpp @@ -0,0 +1,135 @@ +#include "quest.hpp" +// quest.cpp - Quest Log. +// +// Copyright © 2015 Ed Pasek <pasekei@gmail.com> +// +// 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 <algorithm> + +#include "../strings/astring.hpp" +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + +#include "../generic/db.hpp" + +#include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" +#include "../io/line.hpp" + +#include "../mmo/config_parse.hpp" +#include "../mmo/extract_enums.hpp" + +#include "../ast/quest.hpp" + +#include "../poison.hpp" +#include "globals.hpp" +#include "script-parse.hpp" + +namespace tmwa +{ +namespace map +{ +// Function declarations + +static +void questdb_searchname_sub(Borrowed<struct quest_data> quest, VarName str, Borrowed<Option<Borrowed<struct quest_data>>> dst) +{ + if (quest->quest_var == str) + *dst = Some(quest); +} + +Option<Borrowed<struct quest_data>> questdb_searchname(XString str_) +{ + VarName str = stringish<VarName>(str_); + if (XString(str) != str_) + return None; + Option<P<struct quest_data>> quest = None; + for (auto& pair : quest_db) + questdb_searchname_sub(borrow(pair.second), str, borrow(quest)); + return quest; +} + +Borrowed<struct quest_data> questdb_search(QuestId questid) +{ + Option<P<struct quest_data>> id_ = quest_db.search(questid); + OMATCH_BEGIN_SOME (id, id_) + { + return id; + } + OMATCH_END (); + + P<struct quest_data> id = quest_db.init(questid); + + id->questid = questid; + + return id; +} + +Option<Borrowed<struct quest_data>> questdb_exists(QuestId questid) +{ + return quest_db.search(questid); +} + +bool quest_readdb(ZString filename) +{ + io::LineCharReader in(filename); + + if (!in.is_open()) + { + PRINTF("can't read %s\n"_fmt, filename); + return false; + } + + int ln = 0; + + while (true) + { + auto res = TRY_UNWRAP(ast::quest::parse_quest(in), + { + PRINTF("read %s done (count=%d)\n"_fmt, filename, ln); + return true; + }); + if (res.get_failure()) + PRINTF("%s\n"_fmt, res.get_failure()); + ast::quest::QuestOrComment ioc = TRY_UNWRAP(std::move(res.get_success()), return false); + + MATCH_BEGIN (ioc) + { + MATCH_CASE (const ast::quest::Comment&, c) + { + (void)c; + } + MATCH_CASE (const ast::quest::Quest&, quest) + { + ln++; + + quest_data qdv {}; + qdv.questid = quest.questid.data; + qdv.quest_var = quest.quest_var.data; + qdv.quest_vr = quest.quest_vr.data; + qdv.quest_shift = quest.quest_shift.data; + qdv.quest_mask = quest.quest_mask.data; + + Borrowed<struct quest_data> id = questdb_search(qdv.questid); + *id = std::move(qdv); + } + } + MATCH_END (); + } +} +} // namespace map +} // namespace tmwa diff --git a/src/monitor/globals.hpp b/src/map/quest.hpp index aa797d3..65e6f4e 100644 --- a/src/monitor/globals.hpp +++ b/src/map/quest.hpp @@ -1,7 +1,7 @@ #pragma once -// globals.hpp - Evil global variables for tmwa-monitor. +// quest.hpp - Quest Log. // -// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> +// Copyright © 2015 Ed Pasek <pasekei@gmail.com> // // This file is part of The Mana World (Athena server) // @@ -20,14 +20,32 @@ #include "fwd.hpp" -#include <sys/types.h> +#include "../mmo/ids.hpp" +#include "../high/mmo.hpp" +#include "map.hpp" +#include "script-buffer.hpp" namespace tmwa { - namespace monitor - { - extern MonitorConf monitor_conf; - extern pid_t pid_login, pid_char, pid_map; - } // namespace monitor +namespace map +{ +constexpr int MAX_QUEST_DB (60355+1); +struct quest_data +{ + QuestId questid; + VarName quest_var; + VarName quest_vr; + int quest_shift; + int quest_mask; +}; +inline +Option<Borrowed<struct quest_data>> questdb_searchname(VarName) = delete; +Option<Borrowed<struct quest_data>> questdb_searchname(XString quest_var); +Borrowed<struct quest_data> questdb_search(QuestId questid); +Option<Borrowed<struct quest_data>> questdb_exists(QuestId questid); + +// get quest var by quest name / mask / bit +bool quest_readdb(ZString filename); +} // namespace map } // namespace tmwa diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp index f412328..c3c6aa1 100644 --- a/src/map/script-call.cpp +++ b/src/map/script-call.cpp @@ -757,7 +757,7 @@ void run_script_main(ScriptState *st, Borrowed<const ScriptBuffer> rootscript) { rerun_pos = st->scriptp.pos; st->state = ScriptEndState::ZERO; - if (!st->freeloop && gotocount > 0 && (--gotocount) <= 0) + if (st->freeloop != 1 && gotocount > 0 && (--gotocount) <= 0) { PRINTF("run_script: infinity loop !\n"_fmt); st->state = ScriptEndState::END; @@ -806,7 +806,7 @@ void run_script_main(ScriptState *st, Borrowed<const ScriptBuffer> rootscript) st->state = ScriptEndState::END; break; } - if (!st->freeloop && cmdcount > 0 && (--cmdcount) <= 0) + if (st->freeloop != 1 && cmdcount > 0 && (--cmdcount) <= 0) { PRINTF("run_script: infinity loop !\n"_fmt); st->state = ScriptEndState::END; diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index c327f26..3291cfc 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -108,7 +108,7 @@ void builtin_goto(ScriptState *st) { if (!AARG(0).is<ScriptDataPos>()) { - PRINTF("script: goto: not label !\n"_fmt); + PRINTF("script: goto: that's not a label!\n"_fmt); st->state = ScriptEndState::END; return; } @@ -149,7 +149,7 @@ void builtin_callfunc(ScriptState *st) } OMATCH_CASE_NONE () { - PRINTF("script:callfunc: function not found! [%s]\n"_fmt, str); + PRINTF("script: callfunc: function not found! [%s]\n"_fmt, str); st->state = ScriptEndState::END; } } @@ -538,7 +538,7 @@ void builtin_setarray(ScriptState *st) if (prefix != '$' && prefix != '@') { - PRINTF("builtin_setarray: illegal scope !\n"_fmt); + PRINTF("builtin_setarray: illegal scope!\n"_fmt); return; } if (prefix != '$') @@ -569,7 +569,7 @@ void builtin_cleararray(ScriptState *st) if (prefix != '$' && prefix != '@') { - PRINTF("builtin_cleararray: illegal scope !\n"_fmt); + PRINTF("builtin_cleararray: illegal scope!\n"_fmt); return; } if (prefix != '$') @@ -626,7 +626,7 @@ void builtin_getarraysize(ScriptState *st) if (prefix != '$' && prefix != '@') { - PRINTF("builtin_copyarray: illegal scope !\n"_fmt); + PRINTF("builtin_copyarray: illegal scope!\n"_fmt); return; } @@ -645,7 +645,7 @@ void builtin_getelementofarray(ScriptState *st) int i = conv_num(st, &AARG(1)); if (i > 255 || i < 0) { - PRINTF("script: getelementofarray (operator[]): param2 illegal number %d\n"_fmt, + PRINTF("script: getelementofarray (operator[]): param2 illegal number: %d\n"_fmt, i); push_int<ScriptDataInt>(st->stack, 0); } @@ -657,11 +657,29 @@ void builtin_getelementofarray(ScriptState *st) } else { - PRINTF("script: getelementofarray (operator[]): param1 not name !\n"_fmt); + PRINTF("script: getelementofarray (operator[]): param1 not named!\n"_fmt); push_int<ScriptDataInt>(st->stack, 0); } } +static +void builtin_wgm(ScriptState *st) +{ + ZString message = ZString(conv_str(st, &AARG(0))); + + intif_wis_message_to_gm(WISP_SERVER_NAME, + battle_config.hack_info_GM_level, + STRPRINTF("[GM] %s"_fmt, message)); +} + +static +void builtin_gmlog(ScriptState *st) +{ + dumb_ptr<map_session_data> sd = script_rid2sd(st); + ZString message = ZString(conv_str(st, &AARG(0))); + log_atcommand(sd, STRPRINTF("{SCRIPT} %s"_fmt, message)); +} + /*========================================== * *------------------------------------------ @@ -717,7 +735,7 @@ void builtin_countitem(ScriptState *st) else { if (battle_config.error_log) - PRINTF("wrong item ID : countitem (%i)\n"_fmt, nameid); + PRINTF("wrong item ID: countitem (%i)\n"_fmt, nameid); } push_int<ScriptDataInt>(st->stack, count); @@ -755,7 +773,7 @@ void builtin_checkweight(ScriptState *st) 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 + //If it gets the wrong item ID or the amount<=0, don't count its weight (assume it's a non-existent item) push_int<ScriptDataInt>(st->stack, 0); return; } @@ -907,7 +925,7 @@ void builtin_delitem(ScriptState *st) if (!nameid || amount <= 0) { - //by Lupus. Don't run FOR if u got wrong item ID or amount<=0 + //By Lupus. Don't run FOR if you've got the wrong item ID or amount<=0 return; } @@ -934,31 +952,6 @@ void builtin_delitem(ScriptState *st) } /*========================================== - *キャラ関係のパラメータ取得 - *------------------------------------------ - */ -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取得 *------------------------------------------ */ @@ -1150,20 +1143,6 @@ void builtin_getequipname(ScriptState *st) } /*========================================== - * - *------------------------------------------ - */ -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); - -} - -/*========================================== * 装備品による能力値ボーナス *------------------------------------------ */ @@ -1955,7 +1934,7 @@ static void builtin_debugmes(ScriptState *st) { RString mes = conv_str(st, &AARG(0)); - PRINTF("script debug : %d %d : %s\n"_fmt, + PRINTF("script debug: %d %d: '%s'\n"_fmt, st->rid, st->oid, mes); } @@ -1972,20 +1951,6 @@ void builtin_resetstatus(ScriptState *st) } /*========================================== - * 性別変換 - *------------------------------------------ - */ -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のアタッチ *------------------------------------------ */ @@ -2164,11 +2129,22 @@ void builtin_getpvpflag(ScriptState *st) static void builtin_emotion(ScriptState *st) { - int type; - type = conv_num(st, &AARG(0)); + ZString str; + dumb_ptr<map_session_data> pl_sd = nullptr; + int type = conv_num(st, &AARG(0)); + if (HARG(1)) { + str = ZString(conv_str(st, &AARG(1))); + CharName player = stringish<CharName>(str); + pl_sd = map_nick2sd(player); + } if (type < 0 || type > 200) return; - clif_emotion(map_id2bl(st->oid), type); + if (pl_sd != nullptr) + clif_emotion_towards(map_id2bl(st->oid), pl_sd, type); + else if (st->rid && str == "self"_s) + clif_emotion(map_id2sd(st->rid), type); + else + clif_emotion(map_id2bl(st->oid), type); } static @@ -2296,11 +2272,11 @@ void builtin_getitemlink(ScriptState *st) { OMATCH_CASE_SOME (item_data) { - buf = STRPRINTF("[@@%d|%s@@]"_fmt, item_data->nameid, item_data->jname); + buf = STRPRINTF("@@%d|@@"_fmt, item_data->nameid); } OMATCH_CASE_NONE () { - buf = STRPRINTF("Unknown Item: %s"_fmt, name); + buf = "Unknown Item"_s; } } OMATCH_END (); @@ -2577,25 +2553,6 @@ void builtin_unequipbyid(ScriptState *st) } /*========================================== - * 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. *------------------------------------------ @@ -2613,7 +2570,7 @@ void builtin_npcwarp(ScriptState *st) if (!nd) { - PRINTF("builtin_npcwarp: no such npc: %s\n"_fmt, npc); + PRINTF("builtin_npcwarp: no such npc: '%s'\n"_fmt, npc); return; } @@ -2656,7 +2613,7 @@ void builtin_npcareawarp(ScriptState *st) if (!nd) { - PRINTF("builtin_npcareawarp: no such npc: %s\n"_fmt, npc); + PRINTF("builtin_npcareawarp: no such npc: '%s'\n"_fmt, npc); return; } @@ -2901,7 +2858,7 @@ void builtin_shop(ScriptState *st) nd = npc_name2id(name); if (!nd) { - PRINTF("builtin_shop: no such npc: %s\n"_fmt, name); + PRINTF("builtin_shop: no such npc: '%s'\n"_fmt, name); return; } @@ -2934,7 +2891,7 @@ void builtin_fakenpcname(ScriptState *st) dumb_ptr<npc_data> nd = npc_name2id(name); if (!nd) { - PRINTF("builtin_fakenpcname: no such npc: %s\n"_fmt, name); + PRINTF("builtin_fakenpcname: no such npc: '%s'\n"_fmt, name); return; } nd->name = newname; @@ -2996,7 +2953,7 @@ void builtin_strnpcinfo(ScriptState *st) nd = npc_name2id(npc); if (!nd) { - PRINTF("builtin_strnpcinfo: no such npc: %s\n"_fmt, npc); + PRINTF("builtin_strnpcinfo: no such npc: '%s'\n"_fmt, npc); return; } } else { @@ -3036,7 +2993,7 @@ void builtin_getnpcx(ScriptState *st) nd = npc_name2id(name); if (!nd) { - PRINTF("builtin_getnpcx: no such npc: %s\n"_fmt, name); + PRINTF("builtin_getnpcx: no such npc: '%s'\n"_fmt, name); return; } } else { @@ -3060,7 +3017,7 @@ void builtin_getnpcy(ScriptState *st) nd = npc_name2id(name); if (!nd) { - PRINTF("builtin_getnpcy: no such npc: %s\n"_fmt, name); + PRINTF("builtin_getnpcy: no such npc: '%s'\n"_fmt, name); return; } } else { @@ -3109,12 +3066,10 @@ BuiltinFunction builtin_functions[] = 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'), @@ -3134,11 +3089,11 @@ BuiltinFunction builtin_functions[] = BUILTIN(killmonster, "ME"_s, '\0'), BUILTIN(donpcevent, "E"_s, '\0'), BUILTIN(addtimer, "tE"_s, '\0'), - BUILTIN(initnpctimer, ""_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(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'), @@ -3151,8 +3106,9 @@ BuiltinFunction builtin_functions[] = BUILTIN(sc_end, "i"_s, '\0'), BUILTIN(sc_check, "i"_s, 'i'), BUILTIN(debugmes, "s"_s, '\0'), + BUILTIN(wgm, "s"_s, '\0'), + BUILTIN(gmlog, "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'), @@ -3163,7 +3119,7 @@ BuiltinFunction builtin_functions[] = BUILTIN(pvpoff, "M"_s, '\0'), BUILTIN(setpvpchannel, "i"_s, '\0'), BUILTIN(getpvpflag, "i"_s, 'i'), - BUILTIN(emotion, "i"_s, '\0'), + BUILTIN(emotion, "i?"_s, '\0'), BUILTIN(mapwarp, "MMxy"_s, '\0'), BUILTIN(mobcount, "ME"_s, 'i'), BUILTIN(marriage, "P"_s, 'i'), @@ -3182,7 +3138,6 @@ BuiltinFunction builtin_functions[] = 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(npcareawarp, "xyxyis"_s, '\0'), BUILTIN(message, "Ps"_s, '\0'), diff --git a/src/mmo/fwd.hpp b/src/mmo/fwd.hpp index f51767d..434885e 100644 --- a/src/mmo/fwd.hpp +++ b/src/mmo/fwd.hpp @@ -51,6 +51,7 @@ class AccountCrypt; class AccountEmail; class ServerName; class PartyName; +class QuestId; class VarName; class MapName; class CharName; diff --git a/src/mmo/ids.hpp b/src/mmo/ids.hpp index c1482ef..28b146a 100644 --- a/src/mmo/ids.hpp +++ b/src/mmo/ids.hpp @@ -40,6 +40,7 @@ class PartyId : public Wrapped<uint32_t> { public: constexpr PartyId() : Wrapped class ItemNameId : public Wrapped<uint16_t> { public: constexpr ItemNameId() : Wrapped<uint16_t>() {} protected: constexpr explicit ItemNameId(uint16_t a) : Wrapped<uint16_t>(a) {} }; class BlockId : public Wrapped<uint32_t> { public: constexpr BlockId() : Wrapped<uint32_t>() {} protected: constexpr explicit BlockId(uint32_t a) : Wrapped<uint32_t>(a) {} }; +class QuestId : public Wrapped<uint16_t> { public: constexpr QuestId() : Wrapped<uint16_t>() {} protected: constexpr explicit QuestId(uint16_t a) : Wrapped<uint16_t>(a) {} }; bool impl_extract(XString str, GmLevel *lvl); class GmLevel diff --git a/src/mmo/ids.py b/src/mmo/ids.py index 89392b1..a98920f 100644 --- a/src/mmo/ids.py +++ b/src/mmo/ids.py @@ -5,6 +5,7 @@ for s in [ 'PartyId', 'ItemNameId', 'BlockId', + 'QuestId', ]: class OtherId(object): __slots__ = ('_value') diff --git a/src/monitor/fwd.hpp b/src/monitor/fwd.hpp deleted file mode 100644 index 6900e8e..0000000 --- a/src/monitor/fwd.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -// monitor/fwd.hpp - list of type names for monitor nonserver -// -// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 "../sanity.hpp" - -#include "../strings/fwd.hpp" // rank 1 -#include "../io/fwd.hpp" // rank 4 -#include "../net/fwd.hpp" // rank 5 -#include "../mmo/fwd.hpp" // rank 6 -#include "../high/fwd.hpp" // rank 9 -// monitor/fwd.hpp is rank ∞ because it is an executable - - -namespace tmwa -{ -namespace monitor -{ - struct MonitorConf; -} // namespace monitor -} // namespace tmwa diff --git a/src/monitor/globals.cpp b/src/monitor/globals.cpp deleted file mode 100644 index 49e814d..0000000 --- a/src/monitor/globals.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "globals.hpp" -// globals.cpp - Evil global variables for tmwa-monitor. -// -// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 "monitor_conf.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ - namespace monitor - { - MonitorConf monitor_conf; - pid_t pid_login, pid_char, pid_map; - } // namespace monitor -} // namespace tmwa diff --git a/src/monitor/main.cpp b/src/monitor/main.cpp deleted file mode 100644 index f21a4a7..0000000 --- a/src/monitor/main.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// monitor/main.cpp - Old daemon to restart servers when they crashed. -// -// Copyright © ???? Bartosz Waszak <waszi@evil.org.pl> -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <sys/wait.h> - -#include <fcntl.h> -#include <unistd.h> - -#include <csignal> -#include <cstdlib> - -#include "../strings/mstring.hpp" -#include "../strings/astring.hpp" -#include "../strings/zstring.hpp" -#include "../strings/xstring.hpp" -#include "../strings/literal.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/fd.hpp" -#include "../io/line.hpp" - -#include "../mmo/config_parse.hpp" -#include "../mmo/version.hpp" - -#include "../net/timestamp-utils.hpp" - -#include "globals.hpp" -#include "monitor_conf.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -namespace monitor -{ -static -AString make_path(XString base, XString path) -{ - MString m; - m += base; - m += '/'; - m += path; - return AString(m); -} - -static -pid_t start_process(ZString exec) -{ - const char *args[2] = {exec.c_str(), nullptr}; - pid_t pid = fork(); - if (pid == -1) - { - FPRINTF(stderr, "Failed to fork"_fmt); - return 0; - } - if (pid == 0) - { - DIAG_PUSH(); - DIAG_I(cast_qual); - execv(exec.c_str(), const_cast<char **>(args)); - DIAG_POP(); - perror("Failed to exec"); - kill(getppid(), SIGABRT); - exit(1); - } - return pid; -} - -// Kill all children with the same signal we got, then ourself. -static -void stop_process(int sig) -{ - if (pid_login) - kill(pid_login, sig); - if (pid_char) - kill(pid_char, sig); - if (pid_map) - kill(pid_map, sig); - DIAG_PUSH(); - DIAG_I(old_style_cast); - DIAG_I(zero_as_null_pointer_constant); - signal(sig, SIG_DFL); - DIAG_POP(); - raise(sig); -} - -static -bool monitor_config(io::Spanned<XString> key, io::Spanned<ZString> value) -{ - return parse_monitor_conf(monitor_conf, key, value); -} - -static -bool monitor_confs(io::Spanned<XString> key, io::Spanned<ZString> value) -{ - if (key.data == "monitor_conf"_s) - { - return load_config_file(value.data, monitor_config); - } - key.span.error("Unknown meta-key for monitor nonserver"_s); - return false; -} -} // namespace monitor -} // namespace tmwa - -int main(int argc, char *argv[]) -{ - using namespace tmwa; - using namespace tmwa::monitor; - // These are all the signals we are likely to get - // The shell handles stop/cont - signal(SIGTERM, stop_process); - signal(SIGINT, stop_process); - signal(SIGQUIT, stop_process); - signal(SIGABRT, stop_process); - - monitor_conf.workdir = make_path(ZString(strings::really_construct_from_a_pointer, getenv("HOME"), nullptr), "tmwserver"_s); - - ZString argv0 = ZString(strings::really_construct_from_a_pointer, argv[0], nullptr); - bool loaded_config_yet = false; - bool runflag = true; - - for (int ai = 1; ai < argc; ++ai) - { - ZString argvi = ZString(strings::really_construct_from_a_pointer, argv[ai], nullptr); - if (argvi.startswith('-')) - { - if (argvi == "--help"_s) - { - PRINTF("Usage: %s [--help] [--version] [files...]\n"_fmt, - argv0); - exit(0); - } - else if (argvi == "--version"_s) - { - PRINTF("%s\n"_fmt, CURRENT_VERSION_STRING); - exit(0); - } - else - { - FPRINTF(stderr, "Unknown argument: %s\n"_fmt, argvi); - runflag = false; - } - } - else - { - loaded_config_yet = true; - runflag &= load_config_file(argvi, monitor_confs); - } - } - - if (!loaded_config_yet) - runflag &= load_config_file("conf/tmwa-monitor.conf"_s, monitor_confs); - - if (!runflag) - exit(1); - - if (chdir(monitor_conf.workdir.c_str()) < 0) - { - perror("Failed to change directory"); - exit(1); - } - - PRINTF("Starting:\n"_fmt); - PRINTF("* workdir: %s\n"_fmt, monitor_conf.workdir); - PRINTF("* login_server: %s\n"_fmt, monitor_conf.login_server); - PRINTF("* char_server: %s\n"_fmt, monitor_conf.char_server); - PRINTF("* map_server: %s\n"_fmt, monitor_conf.map_server); - { - //make sure all possible file descriptors are free for use by the servers - //if there are file descriptors higher than the max open from before the limit dropped, that's not our problem - io::FD fd = io::FD::sysconf_SC_OPEN_MAX(); - while ((fd = fd.prev()) > io::FD::stderr()) - { - if (fd.close() == 0) - FPRINTF(stderr, "close fd %d\n"_fmt, fd.uncast_dammit()); - } - fd = io::FD::open("/dev/null"_s, O_RDWR); - if (fd == io::FD()) - { - perror("open /dev/null"); - exit(1); - } - fd.dup2(io::FD::stdin()); - fd.dup2(io::FD::stdout()); - fd.close(); - } - while (1) - { - // write stuff to stderr - timestamp_seconds_buffer timestamp; - stamp_time(timestamp); - - if (!pid_login) - { - pid_login = start_process(monitor_conf.login_server); - FPRINTF(stderr, "[%s] forked login server: %lu\n"_fmt, - timestamp, static_cast<unsigned long>(pid_login)); - } - if (!pid_char) - { - pid_char = start_process(monitor_conf.char_server); - FPRINTF(stderr, "[%s] forked char server: %lu\n"_fmt, - timestamp, static_cast<unsigned long>(pid_char)); - } - if (!pid_map) - { - pid_map = start_process(monitor_conf.map_server); - FPRINTF(stderr, "[%s] forked map server: %lu\n"_fmt, - timestamp, static_cast<unsigned long>(pid_map)); - } - pid_t dead = wait(nullptr); - if (dead == -1) - { - perror("Failed to wait for child"); - exit(1); - } - if (pid_login == dead) - pid_login = 0; - if (pid_char == dead) - pid_char = 0; - if (pid_map == dead) - pid_map = 0; - } -} |