summaryrefslogtreecommitdiff
path: root/npc/commands
diff options
context:
space:
mode:
Diffstat (limited to 'npc/commands')
-rw-r--r--npc/commands/debug-quest.txt102
-rw-r--r--npc/commands/debug.txt688
-rw-r--r--npc/commands/force-rename.txt46
-rw-r--r--npc/commands/gm.txt41
-rw-r--r--npc/commands/ipcheck.txt71
-rw-r--r--npc/commands/kami.txt86
-rw-r--r--npc/commands/language.txt60
-rw-r--r--npc/commands/numa.txt100
-rw-r--r--npc/commands/python.txt27
-rw-r--r--npc/commands/rate-management.txt231
-rw-r--r--npc/commands/resync.txt45
-rw-r--r--npc/commands/scheduled-broadcasts.txt227
-rw-r--r--npc/commands/warp.txt86
13 files changed, 1810 insertions, 0 deletions
diff --git a/npc/commands/debug-quest.txt b/npc/commands/debug-quest.txt
new file mode 100644
index 00000000..24363e09
--- /dev/null
+++ b/npc/commands/debug-quest.txt
@@ -0,0 +1,102 @@
+// Evol Script
+// Author: Gumi, Jesusalva
+
+// TODO: This script must be auto-generated from db/quests.conf to be of any use
+function script GlobalQuestDebug {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug") + " - " + l("Other");
+ mes l("This menu gives access to quest debug menus for @@ quests.", strtolower(l("Other")));
+ next;
+ mes l("Please select a quest:");
+
+ menuint
+ menuimage("actions/back", l("Go back")), -1,
+ l("Custom"), -136;
+
+ switch (@menuret)
+ {
+ case -1: return;
+ case -136:
+ mes "Determine the quest number, as stated in db/quests.conf";
+ input .@quest;
+ if (!.@quest) return;
+ mes "";
+ mes l("DEBUG: Changing @@, Values: (@@, @@, @@).", getquestlink(.@quest), getq(.@quest), getq2(.@quest), getq3(.@quest));
+ select
+ "set 1",
+ "set 2",
+ "set 3",
+ "reset";
+ mes l("DEBUG: Changing @@ field @@ to something else.", getquestlink(.@quest), @menu);
+ mes "";
+ mes "Determine the new value (numeric only)";
+ input .@value;
+ if (.@value < 0) return;
+ if (@menu == 1)
+ setq1 .@quest, .@value;
+ if (@menu == 2)
+ setq2 .@quest, .@value;
+ if (@menu == 3)
+ setq3 .@quest, .@value;
+ if (@menu == 4)
+ setq .@quest, .@value, 0, 0;
+
+ return;
+ default: return;
+ }
+ } while (1);
+ return;
+}
+
+
+
+- script @qdebug 32767,{
+ end;
+
+OnCall:
+ if (!is_gm()) {
+ end;
+ }
+ GlobalQuestDebug;
+ closedialog;
+ end;
+
+OnSetq:
+ if (.@atcmd_numparameters < 1) {
+ dispbottom "setq called with invalid arguments (min. 2)";
+ dispbottom "GM Command syntax: @setq <quest_id> <val1> <val2> <val3>";
+ end;
+ }
+ .@q=atoi(.@atcmd_parameters$[0]);
+ if (.@atcmd_numparameters < 2) {
+ if (!is_trusted())
+ charcommand sprintf("@request Quest %d count: %d / %d / %d", .@q,
+ getq(.@q), getq2(.@q), getq3(.@q));
+ else
+ dispbottom sprintf("%s Quest count: %d / %d / %d", getquestlink(.@q),
+ getq(.@q), getq2(.@q), getq3(.@q));
+ end;
+ }
+ switch (.@atcmd_numparameters) {
+ case 4:
+ setq3 .@q, atoi(.@atcmd_parameters$[3]);
+ case 3:
+ setq2 .@q, atoi(.@atcmd_parameters$[2]);
+ case 2:
+ setq1 .@q, atoi(.@atcmd_parameters$[1]);
+ dispbottom l("Quest @@ modified by GM", getquestlink(.@q));
+ specialeffect 50, SELF, playerattached();
+ break;
+ default:
+ dispbottom "setq called with invalid arguments (max. 4)";
+ dispbottom "GM Command syntax: @setq <quest_id> <val1> <val2> <val3>";
+ break;
+ }
+ end;
+
+OnInit:
+ bindatcmd "qdebug", "@qdebug::OnCall", 99, 99, 1;
+ bindatcmd "setq", "@qdebug::OnSetq", 99, 99, 1;
+}
diff --git a/npc/commands/debug.txt b/npc/commands/debug.txt
new file mode 100644
index 00000000..f62b4a97
--- /dev/null
+++ b/npc/commands/debug.txt
@@ -0,0 +1,688 @@
+
+function script Debug {
+ goto L_Begin;
+
+L_Begin:
+ mes "What do you want to do?";
+ mes "Your range: "+readbattleparam(getcharid(3), UDT_ATKRANGE);
+ mes "Bow range: "+getiteminfo(Bow, ITEMINFO_RANGE);
+ menu
+ "Reset stat points.", L_ResetStatusPoints,
+ "Change my level.", L_Level,
+ "Change other stuff.", L_Stats,
+ "Change my basic skills.", L_BasicSkills,
+ "Change my focus skills.", L_FocusSkills,
+ "Change my magic skills.", L_MagicSkills,
+ "Add everything.", L_AddAll,
+ "Reset everything.", L_ResetAll,
+ "Close.", L_close;
+
+L_Stats:
+ mesc l("Stats: %s", col(b("@str/@agi/@vit/@int/@dex/@luk/@allstats"),3));
+ mesc l("GP: %s", col(b("@zeny"),3));
+ mesc l("Items: %s", col(b("/createitems"),3));
+ mesc l("Hide from monsters: %s", col(b("@monsterignore or @safe"),3));
+ mesc l("Reset Stats: %s", col(b("@streset"),3));
+ next;
+ goto L_Begin;
+
+L_Level:
+ mes "What level do you want to be (min: 1 - max: 140)?";
+ input @lvl;
+ if (@lvl < 1)
+ goto L_LevelTooLow;
+ if (@lvl > 140)
+ goto L_LevelTooHigh;
+ if (BaseLevel == @lvl)
+ goto L_SameLevel;
+ BaseLevel = @lvl;
+ resetstatus;
+ mes "You are now level " + BaseLevel + ".";
+ goto L_Begin;
+
+L_LevelTooLow:
+ mes "Bad choice. Minimum level is 1.";
+ next;
+ goto L_Begin;
+
+L_LevelTooHigh:
+ mes "Bad choice. Maximum level is 140.";
+ next;
+ goto L_Begin;
+
+L_SameLevel:
+ mes "You already are level " + @lvl + ".";
+ resetstatus;
+ next;
+ goto L_Begin;
+
+L_ResetStatusPoints:
+ resetstatus;
+ mes "Stats successfully resetted.";
+ next;
+ goto L_Begin;
+
+L_BasicSkills:
+ adddefaultskills();
+ goto L_Begin;
+
+L_FocusSkills:
+ @pool = getskilllv(SKILL_POOL);
+ @mallard = getskilllv(SKILL_MALLARDS_EYE);
+ @brawling = getskilllv(SKILL_BRAWLING);
+ @speed = getskilllv(SKILL_SPEED);
+ @poison = getskilllv(SKILL_RESIST_POISON);
+ @astralsoul = getskilllv(SKILL_ASTRAL_SOUL);
+ @raging = getskilllv(SKILL_RAGING);
+
+ mes "Your focusing skill level is " + @pool + ".";
+ mes "Your mallard's eye skill level is " + @mallard + ".";
+ mes "Your brawling skill level is " + @brawling + ".";
+ mes "Your speed skill level is " + @speed + ".";
+ mes "Your resist poison skill level is " + @poison + ".";
+ mes "Your astral soul skill level is " + @astralsoul + ".";
+ mes "Your raging skill level is " + @raging + ".";
+ next;
+ mes "";
+ mes l("Focus list:");
+ mesc l("%s : %s", l("Mallard's Eye"),
+ (isfocused(SKILL_MALLARDS_EYE) ? l("Yes") : l("No")));
+ mesc l("%s : %s", l("Brawling"),
+ (isfocused(SKILL_BRAWLING) ? l("Yes") : l("No")));
+ mesc l("%s : %s", l("Speed"),
+ (isfocused(SKILL_SPEED) ? l("Yes") : l("No")));
+ mesc l("%s : %s", l("Resist Ailment"),
+ (isfocused(SKILL_RESIST_POISON) ? l("Yes") : l("No")));
+ mesc l("%s : %s", l("Astral Soul"),
+ (isfocused(SKILL_ASTRAL_SOUL) ? l("Yes") : l("No")));
+ mesc l("%s : %s", l("Raging"),
+ (isfocused(SKILL_RAGING) ? l("Yes") : l("No")));
+ .@t=getactivatedpoolskilllist();
+ menuint
+ l("Back"), -3,
+ l("Focus Skill +"), -2,
+ rif(getskilllv(SKILL_POOL), l("Focus Skill -")), -1,
+ l("Add all focus skills"), 0,
+ l("Remove all focus skills"), -4,
+ ("Toggle Focus - Mallards Eye"), SKILL_MALLARDS_EYE,
+ ("Toggle Focus - Brawling"), SKILL_BRAWLING,
+ ("Toggle Focus - Speed"), SKILL_SPEED,
+ ("Toggle Focus - Resist Ailment"), SKILL_RESIST_POISON,
+ ("Toggle Focus - Astral Soul"), SKILL_ASTRAL_SOUL,
+ ("Toggle Focus - Raging"), SKILL_RAGING;
+ mes "";
+ switch (@menuret) {
+ case -3: goto L_Begin;
+ case -2:
+ skill SKILL_POOL, @pool+1, 0; break;
+ case -1:
+ skill SKILL_POOL, max(0, @pool-1), 0; break;
+ case 0:
+ updateskill SKILL_MALLARDS_EYE, 9;
+ updateskill SKILL_BRAWLING, 9;
+ updateskill SKILL_SPEED, 9;
+ updateskill SKILL_RESIST_POISON, 9;
+ updateskill SKILL_ASTRAL_SOUL, 9;
+ updateskill SKILL_RAGING, 9;
+ break;
+ case -4:
+ skill SKILL_POOL, 0, 0; break;
+ updateskill SKILL_MALLARDS_EYE, 0;
+ updateskill SKILL_BRAWLING, 0;
+ updateskill SKILL_SPEED, 0;
+ updateskill SKILL_RESIST_POISON, 0;
+ updateskill SKILL_ASTRAL_SOUL, 0;
+ updateskill SKILL_RAGING, 0;
+ break;
+ default:
+ if (FOCUSING & getpoolskillFID(@menuret)) {
+ unpoolskill(@menuret);
+ mesc "Focus removed", 1;
+ } else {
+ .@s = poolskill(@menuret);
+ if (.@s)
+ mesc "Focus added", 2;
+ else
+ mesc sprintf("Impossible to focus. You can only focus %d skills at a time.", .@t), 1;
+ }
+ }
+ goto L_FocusSkills;
+
+L_MagicSkills:
+ @general = getskilllv(SKILL_MAGIC);
+ @life = getskilllv(SKILL_MAGIC_LIFE);
+ @war = getskilllv(SKILL_MAGIC_WAR);
+ @trans = getskilllv(SKILL_MAGIC_TRANSMUTE);
+ @nature = getskilllv(SKILL_MAGIC_NATURE);
+ @astral = getskilllv(SKILL_MAGIC_ASTRAL);
+ @dark = getskilllv(SKILL_MAGIC_DARK);
+ menu
+ "Overview of my magical skills.", L_MagicSkillsOverview,
+ "Get magic skills.", L_ChangeMagicSkills,
+ "Get magic experience.", L_MagicExperience,
+ "All magic skills to their maximum level and maximum magic experience.", L_GetAllMagic,
+ "Reset magic skills and experience.", L_ResetMagicSkills,
+ "Back to the main menu.", L_Begin,
+ "Close.", L_close;
+
+L_MagicSkillsOverview:
+ mes "Your current magic exp is "+MAGIC_EXP;
+ mes "Your level in the general magic skill is " + @general + ".";
+ mes "Your level in the life magic skill is " + @life + ".";
+ mes "Your level in the war magic skill is " + @war + ".";
+ mes "Your level in the transmutation magic skill is " + @trans + ".";
+ mes "Your level in the nature magic skill is " + @nature + ".";
+ mes "Your level in the astral magic skill is " + @astral + ".";
+ mes "Your level in the dark magic skill is " + @dark + ".";
+ next;
+ goto L_MagicSkills;
+
+L_MagicExperience:
+ mes "Your current magic experience is " + MAGIC_EXP + ".";
+ if (@general == 0
+ && @life == 0
+ && @war == 0
+ && @trans == 0
+ && @nature == 0
+ && @astral == 0
+ && @dark == 0)
+ goto L_NoMagicSkills;
+
+ goto L_ChangeMagicExperience;
+
+L_NoMagicSkills:
+ mes "You can't have magic experience, since you have no magic skills yet.";
+ goto L_MagicSkills;
+
+L_ChangeMagicExperience:
+ mes "Set the desired magic experience (min: 0 - max: 65535).";
+ input @value;
+ if (@value < 0 || @value > 65535)
+ goto L_WrongMagicExperience;
+ MAGIC_EXP = @value;
+ mes "You now have " + MAGIC_EXP + " magic experience points.";
+ goto L_MagicSkills;
+
+L_WrongMagicExperience:
+ mes "Wrong value informed. Aborting.";
+ goto L_MagicSkills;
+
+L_ChangeMagicSkills:
+ menu
+ "General Magic.", L_ChangeGeneralMagicSkill,
+ "Life Magic.", L_ChangeLifeMagicSkill,
+ "War Magic.", L_ChangeWarMagicSkill,
+ "Transmutation Magic.", L_ChangeTransmutationMagicSkill,
+ "Nature Magic.", L_ChangeNatureMagicSkill,
+ "Astral Magic.", L_ChangeAstralMagicSkill,
+ "Dark Magic.", L_ChangeDarkMagicSkill,
+ "Back to the magic skills menu.", L_MagicSkills,
+ "Close.", L_close;
+
+L_ChangeGeneralMagicSkill:
+ mes "Your level in the general magic skill is " + @general + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next4,
+ "Get level 1.", L_ChangeGeneralMagicSkill1,
+ "Get level 2.", L_ChangeGeneralMagicSkill2;
+
+L_Next4:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC, 0;
+ mes "General Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeGeneralMagicSkill1:
+ updateskill SKILL_MAGIC, 1;
+ mes "General Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeGeneralMagicSkill2:
+ updateskill SKILL_MAGIC, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "General Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeLifeMagicSkill:
+ mes "Your level in the life magic skill is " + @life + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next5,
+ "Get level 1.", L_ChangeLifeMagicSkill1,
+ "Get level 2.", L_ChangeLifeMagicSkill2;
+
+L_Next5:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC_LIFE, 0;
+ mes "Life Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeLifeMagicSkill1:
+ updateskill SKILL_MAGIC_LIFE, 1;
+ mes "Life Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeLifeMagicSkill2:
+ updateskill SKILL_MAGIC_LIFE, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "Life Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeWarMagicSkill:
+ mes "Your level in the war magic skill is " + @war + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next6,
+ "Get level 1.", L_ChangeWarMagicSkill1,
+ "Get level 2.", L_ChangeWarMagicSkill2;
+
+L_Next6:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC_WAR, 0;
+ mes "War Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeWarMagicSkill1:
+ updateskill SKILL_MAGIC_WAR, 1;
+ mes "War Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeWarMagicSkill2:
+ updateskill SKILL_MAGIC_WAR, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "War Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeTransmutationMagicSkill:
+ mes "Your level in the transmutation magic skill is " + @trans + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next7,
+ "Get level 1.", L_ChangeTransmutationMagicSkill1,
+ "Get level 2.", L_ChangeTransmutationMagicSkill2;
+
+L_Next7:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC_TRANSMUTE, 0;
+ mes "Transmutation Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeTransmutationMagicSkill1:
+ updateskill SKILL_MAGIC_TRANSMUTE, 1;
+ mes "Transmutation Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeTransmutationMagicSkill2:
+ updateskill SKILL_MAGIC_TRANSMUTE, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "Transmutation Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeNatureMagicSkill:
+ mes "Your level in the nature magic skill is " + @nature + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next8,
+ "Get level 1.", L_ChangeNatureMagicSkill1,
+ "Get level 2.", L_ChangeNatureMagicSkill2;
+
+L_Next8:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC_NATURE, 0;
+ mes "Nature Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeNatureMagicSkill1:
+ updateskill SKILL_MAGIC_NATURE, 1;
+ mes "Nature Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeNatureMagicSkill2:
+ updateskill SKILL_MAGIC_NATURE, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "Nature Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeAstralMagicSkill:
+ mes "Your level in the astral magic skill is " + @astral + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next9,
+ "Get level 1.", L_ChangeAstralMagicSkill1,
+ "Get level 2.", L_ChangeAstralMagicSkill2;
+
+L_Next9:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC_ASTAL, 0;
+ mes "Astral Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeAstralMagicSkill1:
+ updateskill SKILL_MAGIC_ASTRAL, 1;
+ mes "Astral Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeAstralMagicSkill2:
+ updateskill SKILL_MAGIC_ASTRAL, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "Astral Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeDarkMagicSkill:
+ mes "Your level in the dark magic skill is " + @dark + ". What do you want to do?";
+ menu
+ "Get level 0.", L_Next10,
+ "Get level 1.", L_ChangeDarkMagicSkill1,
+ "Get level 2.", L_ChangeDarkMagicSkill2;
+
+L_Next10:
+ if (@menu == 1)
+ updateskill SKILL_MAGIC_DARK, 0;
+ mes "Dark Magic skill changed to level 0.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeDarkMagicSkill1:
+ updateskill SKILL_MAGIC_DARK, 1;
+ mes "Dark Magic skill changed to level 1.";
+ next;
+ goto L_MagicSkills;
+
+L_ChangeDarkMagicSkill2:
+ updateskill SKILL_MAGIC_DARK, 2;
+ if (MAGIC_EXP < 100)
+ MAGIC_EXP = 100;
+ mes "Dark Magic skill changed to level 2.";
+ next;
+ goto L_MagicSkills;
+
+L_GetAllMagic:
+ updateskill SKILL_MAGIC, 5;
+ updateskill SKILL_MAGIC_LIFE, 5;
+ updateskill SKILL_MAGIC_WAR, 5;
+ updateskill SKILL_MAGIC_TRANSMUTE, 5;
+ updateskill SKILL_MAGIC_NATURE, 5;
+ updateskill SKILL_MAGIC_ASTRAL, 5;
+ updateskill SKILL_MAGIC_DARK, 5;
+ mes "Magic skills added.";
+ next;
+ goto L_MagicSkills;
+
+L_ResetMagicSkills:
+ updateskill SKILL_MAGIC, 0;
+ updateskill SKILL_MAGIC_LIFE, 0;
+ updateskill SKILL_MAGIC_WAR, 0;
+ updateskill SKILL_MAGIC_TRANSMUTE, 0;
+ updateskill SKILL_MAGIC_NATURE, 0;
+ updateskill SKILL_MAGIC_ASTRAL, 0;
+ updateskill SKILL_MAGIC_DARK, 0;
+ mes "Magic skills removed.";
+ next;
+ goto L_MagicSkills;
+
+L_AddAll:
+ adddefaultskills();
+ updateskill SKILL_POOL, 1;
+ updateskill SKILL_MALLARDS_EYE, 9;
+ updateskill SKILL_BRAWLING, 9;
+ updateskill SKILL_SPEED, 9;
+ updateskill SKILL_RESIST_POISON, 9;
+ updateskill SKILL_ASTRAL_SOUL, 9;
+ updateskill SKILL_RAGING, 9;
+ updateskill SKILL_MAGIC, 5;
+ updateskill SKILL_MAGIC_LIFE, 5;
+ updateskill SKILL_MAGIC_WAR, 5;
+ updateskill SKILL_MAGIC_TRANSMUTE, 5;
+ updateskill SKILL_MAGIC_NATURE, 5;
+ updateskill SKILL_MAGIC_ASTRAL, 5;
+ updateskill SKILL_MAGIC_DARK, 5;
+
+ // Real skills
+ learnskill SKILL_CONFRINGO, 1;
+ learnskill SKILL_ABIZIT, 1;
+ learnskill SKILL_MONSTERINFO, 1;
+ learnskill EVOL_AREA_PROVOKE, 1;
+ learnskill SKILL_FLAR, 1;
+ learnskill SKILL_CHIZA, 1;
+ learnskill SKILL_MODRIPHOO, 1;
+ learnskill SKILL_MODRISUMP, 1;
+ learnskill SKILL_MODRIYIKAM, 1;
+ learnskill SKILL_MODRILAX, 1;
+ learnskill SKILL_LUM, 1;
+ learnskill SKILL_PARUM, 1;
+ learnskill SKILL_GOLE, 1;
+ learnskill SKILL_KALAKARENK, 1;
+ learnskill SKILL_KALBOO, 1;
+ learnskill SKILL_KALGINA, 1;
+ learnskill SKILL_KALRENK, 1;
+ learnskill SKILL_HALHISS, 1;
+ learnskill SKILL_HELORP, 1;
+ learnskill SKILL_KAFLOSH, 1;
+ learnskill SKILL_BETSANC, 1;
+ learnskill SKILL_ASORM, 1;
+ learnskill SKILL_INGRAV, 1;
+ learnskill SKILL_UPMARMU, 1;
+ learnskill SKILL_PHLEX, 1;
+ learnskill SKILL_KULARZUFRILL, 1;
+ learnskill SKILL_ZUKMINBIRF, 1;
+ learnskill SKILL_PATMUPLOO, 1;
+ learnskill SKILL_PATVILOREE, 1;
+ learnskill SKILL_PATLOREE, 1;
+ learnskill SKILL_MANPAHIL, 1;
+ resetstatus;
+ BaseLevel = 99;
+ mes "All skills added to their maximum level.";
+ mes "Maximum number of Legacy Magic Experience points.";
+ mes "You are now level " + BaseLevel + ".";
+ next;
+ goto L_Begin;
+
+L_ResetAll:
+ //adddefaultskills();
+ updateskill SKILL_POOL, 0;
+ updateskill SKILL_MALLARDS_EYE, 0;
+ updateskill SKILL_BRAWLING, 0;
+ updateskill SKILL_SPEED, 0;
+ updateskill SKILL_RESIST_POISON, 0;
+ updateskill SKILL_ASTRAL_SOUL, 0;
+ updateskill SKILL_RAGING, 0;
+ updateskill SKILL_MAGIC, 0;
+ updateskill SKILL_MAGIC_LIFE, 0;
+ updateskill SKILL_MAGIC_WAR, 0;
+ updateskill SKILL_MAGIC_TRANSMUTE, 0;
+ updateskill SKILL_MAGIC_NATURE, 0;
+ updateskill SKILL_MAGIC_ASTRAL, 0;
+ updateskill SKILL_MAGIC_DARK, 0;
+
+ // Real skills
+ updateskill SKILL_CONFRINGO, 0;
+ updateskill SKILL_ABIZIT, 0;
+ updateskill SKILL_MONSTERINFO, 0;
+ updateskill EVOL_AREA_PROVOKE, 0;
+ updateskill SKILL_FLAR, 0;
+ updateskill SKILL_CHIZA, 0;
+ updateskill SKILL_MODRIPHOO, 0;
+ updateskill SKILL_MODRISUMP, 0;
+ updateskill SKILL_MODRIYIKAM, 0;
+ updateskill SKILL_MODRILAX, 0;
+ updateskill SKILL_LUM, 0;
+ updateskill SKILL_PARUM, 0;
+ updateskill SKILL_GOLE, 0;
+ updateskill SKILL_KALAKARENK, 0;
+ updateskill SKILL_KALBOO, 0;
+ updateskill SKILL_KALGINA, 0;
+ updateskill SKILL_KALRENK, 0;
+ updateskill SKILL_HALHISS, 0;
+ updateskill SKILL_HELORP, 0;
+ updateskill SKILL_KAFLOSH, 0;
+ updateskill SKILL_BETSANC, 0;
+ updateskill SKILL_ASORM, 0;
+ updateskill SKILL_INGRAV, 0;
+ updateskill SKILL_UPMARMU, 0;
+ updateskill SKILL_PHLEX, 0;
+ updateskill SKILL_KULARZUFRILL, 0;
+ updateskill SKILL_ZUKMINBIRF, 0;
+ updateskill SKILL_PATMUPLOO, 0;
+ updateskill SKILL_PATVILOREE, 0;
+ updateskill SKILL_PATLOREE, 0;
+ updateskill SKILL_MANPAHIL, 0;
+ MAGIC_EXP = 0;
+ resetstatus;
+ BaseLevel = 1;
+ mes "All skills removed.";
+ mes "Magic experience reset.";
+ mes "You are now level " + BaseLevel + ".";
+ next;
+ goto L_Begin;
+
+L_close:
+ closeclientdialog;
+ return;
+}
+
+- script Debug Spell NPC32767,{
+ end;
+
+OnDebug:
+ if (!debug && getgmlevel() < CMD_DEBUG) end;
+ callfunc "Debug";
+ end;
+
+OnSetVar:
+ if (getarraysize(.@atcmd_parameters$) != 3)
+ Exception("Usage: @set-var VARIABLE INDEX VALUE", RB_DISPBOTTOM|RB_ISFATAL);
+
+ .@cmd$=array_shift(.@atcmd_parameters$);
+ .@idx=atoi(array_shift(.@atcmd_parameters$));
+ if (charat(.@atcmd_parameters$[0],
+ getstrlen(.@atcmd_parameters$[0])-1) == "$")
+ .@str=true;
+
+ if (.@str)
+ .@val$=array_shift(.@atcmd_parameters$);
+ else
+ .@val=array_shift(.@atcmd_parameters$);
+
+ if (.@str)
+ setd(sprintf("%s[%d]", .@cmd$, .@idx), .@val$);
+ else
+ setd(sprintf("%s[%d]", .@cmd$, .@idx), .@val);
+
+ .@msg$=sprintf("%s[%d] is now: %s", .@cmd$, .@idx,
+ getd(sprintf("%s[%d]", .@cmd$, .@idx)));
+
+ if (!is_trusted())
+ charcommand("@request System Information: "+.@msg$);
+ else
+ dispbottom(.@msg$);
+ end;
+
+// If the char is not a staff member, it'll be sent to GM Log instead
+OnGetVar:
+ if (getarraysize(.@atcmd_parameters$) != 2)
+ Exception("Usage: @get-var VARIABLE INDEX", RB_DISPBOTTOM|RB_ISFATAL);
+
+ .@cmd$=array_shift(.@atcmd_parameters$);
+ .@idx=atoi(array_shift(.@atcmd_parameters$));
+
+ .@mg$=sprintf("%s[%d] == %s", .@cmd$, .@idx,
+ getd(sprintf("%s[%d]", .@cmd$, .@idx)));
+
+ if (!is_trusted())
+ charcommand("@request System Information: "+.@mg$);
+ else
+ dispbottom(.@mg$);
+ end;
+
+OnSClear:
+ sc_end SC_ALL;
+ sc_end SC_DAILYSENDMAILCNT;
+ dispbottom l("Status Condition Cleared");
+ end;
+
+OnAllPerms:
+ if (@allperms) end;
+ charcommand("@addperm all_skill");
+ charcommand("@addperm all_equipment");
+ charcommand("@addperm skill_unconditional");
+ charcommand("@addperm join_chat");
+ charcommand("@addperm hide_session");
+ charcommand("@addperm any_warp");
+ charcommand("@addperm view_hpmeter");
+ charcommand("@addperm view_equipment");
+ charcommand("@addperm receive_requests");
+ charcommand("@addperm can_trade_bound");
+ charcommand("@addperm bypass_nostorage");
+ @allperms=true;
+ end;
+
+OnInit:
+ registercmd "@debug", "Debug Spell::OnDebug";
+ bindatcmd "getvar", "Debug Spell::OnGetVar", 99, 99, 1;
+ bindatcmd "get-var", "Debug Spell::OnGetVar", 99, 99, 1;
+ bindatcmd "setvar", "Debug Spell::OnSetVar", 99, 99, 1;
+ bindatcmd "set-var", "Debug Spell::OnSetVar", 99, 99, 1;
+ bindatcmd "sclear", "Debug Spell::OnSClear", 99, 99, 1;
+ bindatcmd "allperms", "Debug Spell::OnAllPerms", 99, 100, 1;
+ end;
+}
+
+029-2,30,26,0 script Debug#0 NPC154,{
+ @debug_npc = 1;
+ callfunc "Debug";
+ end;
+OnInit:
+ if (!debug)
+ disablenpc "Debug#0";
+ end;
+}
+
+001-1,53,47,0 script Debug#1 NPC154,{
+ @debug_npc = 1;
+ callfunc "Debug";
+ end;
+OnInit:
+ if (!debug)
+ disablenpc "Debug#1";
+ end;
+}
+
+009-1,45,33,0 script Debug#2 NPC154,{
+ @debug_npc = 1;
+ callfunc "Debug";
+ end;
+OnInit:
+ if (!debug)
+ disablenpc "Debug#2";
+ end;
+}
+
+020-1,75,85,0 script Debug#3 NPC154,{
+ @debug_npc = 1;
+ callfunc "Debug";
+ end;
+OnInit:
+ if (!debug)
+ disablenpc "Debug#3";
+ end;
+}
+
diff --git a/npc/commands/force-rename.txt b/npc/commands/force-rename.txt
new file mode 100644
index 00000000..6535ea22
--- /dev/null
+++ b/npc/commands/force-rename.txt
@@ -0,0 +1,46 @@
+// @charrename/@forcerename atcommand
+// FORCEFULLY renames a char. Collision is handled by SQL.
+//
+// group lv: 80+
+// group char lv: 80+
+// log: True
+//
+// usage: npc/commands/force-rename.txt
+// @charrename New Nickname
+// #forcerename "char" <Nickname>
+//
+
+- script @charrename 32767,{
+ end;
+
+OnRename:
+ // array size validation
+ if (getarraysize(.@atcmd_parameters$) <= 0) {
+ dispbottom("Syntax requires argument between 3 and 30 chars long.");
+ end;
+ }
+ // Set new nickname
+ .@nickname$ += implode(.@atcmd_parameters$, " ");
+ .@nickname$ = strip(.@nickname$);
+ // Empty nickname
+ if (.@nickname$ == "" || .@nickname$ == "NULL")
+ end;
+ // Too long or too short nickname
+ if (getstrlen(.@nickname$) > 30 || getstrlen(.@nickname$) < 3)
+ end;
+ // Attempt to rename. If name is taken, will fail at SQL query
+ dispbottom l("Your nickname has been redefined by GM Team.");
+ .@id=getcharid(3);
+ .@n$=strcharinfo(0);
+ detachrid();
+ kick(.@id, 12); // 12 = Pay changed.
+ sleep(25);
+ query_sql(sprintf("UPDATE `char` SET `name`='%s' WHERE `name`='%s'", escape_sql(.@nickname$), escape_sql(.@n$)));
+ debugmes "[SUCCESS] char %s renamed to %s", .@n$, .@nickname$;
+ end;
+
+OnInit:
+ bindatcmd "charrename", "@charrename::OnRename", 80, 80, 1;
+ bindatcmd "forcerename", "@charrename::OnRename", 80, 80, 1;
+ end;
+}
diff --git a/npc/commands/gm.txt b/npc/commands/gm.txt
new file mode 100644
index 00000000..b402cda8
--- /dev/null
+++ b/npc/commands/gm.txt
@@ -0,0 +1,41 @@
+// @showgm/@hidegm atcommand
+// TEMPORALY hides GM level (or revert it)
+//
+// group lv: 20+
+// group char lv: 99
+// log: False
+//
+// usage:
+// @showgm
+// #showgm "char" <delta>
+//
+
+- script @group 32767,{
+ end;
+
+OnHide:
+ .@gm=getgroupid();
+ if (.@gm < 20) end;
+ if (.@gm % 10 != 0) end;
+ setgroupid(.@gm+1);
+ dispbottom "hidelevel : "+l("Your GM level is now hidden.");
+ end;
+
+OnShow:
+ .@gm=getgroupid();
+ if (.@gm < 20) end;
+ if (.@gm % 10 != 1) end;
+ setgroupid(.@gm-1);
+ dispbottom "showlevel : "+l("Your GM level is now visible.");
+ end;
+
+OnInit:
+ bindatcmd "showgroup", "@group::OnShow", 20, 99, 0;
+ bindatcmd "showgm", "@group::OnShow", 20, 99, 0;
+ bindatcmd "showlevel", "@group::OnShow", 20, 99, 0;
+
+ bindatcmd "hidegroup", "@group::OnHide", 20, 99, 0;
+ bindatcmd "hidegm", "@group::OnHide", 20, 99, 0;
+ bindatcmd "hidelevel", "@group::OnHide", 20, 99, 0;
+ end;
+}
diff --git a/npc/commands/ipcheck.txt b/npc/commands/ipcheck.txt
new file mode 100644
index 00000000..a241d3c0
--- /dev/null
+++ b/npc/commands/ipcheck.txt
@@ -0,0 +1,71 @@
+// TMW2 script
+// Author: Jesusalva <admin@tmw2.org>
+//
+// @ipcheck <player_name>
+// #ipcheck <player_name>
+//
+// Returns user IP
+
+
+- script @ipcheck 32767,{
+ end;
+
+OnCall:
+ if (.@atcmd_numparameters == 0)
+ .@request$ = strcharinfo(0);
+ else
+ .@request$ = implode(.@atcmd_parameters$, " ");
+ dispbottom strip(.@request$)+": IP "+getcharip(.@request$);
+ //dispbottom strcharinfo(0)+": IP "+getcharip(.@request$);
+ end;
+
+OnBan:
+ if (.@atcmd_numparameters == 0) {
+ dispbottom col("Syntax: #ipban <reason>", 1);
+ }
+ // Do not allow banning high-level staff
+ if (is_admin() || is_gm())
+ end;
+ .@target$=strcharinfo(0);
+ .@reason$ = implode(.@atcmd_parameters$, " ");
+ dispbottom col(l("You were permanently banned by the GM Team."), 1);
+ sleep2(200);
+ query_sql "INSERT INTO ipbanlist (list,btime,rtime,reason) VALUES ('"+getcharip(.@target$)+"','"+gettime(7)+"-"+gettime(6)+"-"+gettime(5)+" "+gettime(3)+":"+gettime(2)+":"+gettime(1)+"','2037-01-01 00:00:00','"+.@reason$+"')";
+ logmes("was IP-Blocked, and will not connect again."), LOGMES_ATCOMMAND;
+ sleep2(2000);
+ charcommand("@kick "+.@target$);
+ end;
+
+OnInit:
+ bindatcmd "ipcheck", "@ipcheck::OnCall", 60, 100, 0;
+ bindatcmd "ipban", "@ipcheck::OnBan", 99, 100, 1;
+ end;
+}
+
+// TMW2 script
+// Author: Jesusalva <admin@tmw2.org>
+//
+// @checkidle <player_name>
+// #checkidle <player_name>
+//
+// Returns user idle time in seconds.
+// Useful when the game prohibits warping to player.
+
+
+- script @checkidle 32767,{
+ end;
+
+OnCall:
+ if (.@atcmd_numparameters == 0)
+ .@request$ = strcharinfo(0);
+ else
+ .@request$ = implode(.@atcmd_parameters$, " ");
+ dispbottom strip(.@request$)+" idle time: "+checkidle(.@request$);
+ //dispbottom strcharinfo(0)+": IP "+getcharip(.@request$);
+ end;
+
+OnInit:
+ bindatcmd "checkidle", "@checkidle::OnCall", 60, 80, 0;
+ end;
+}
+
diff --git a/npc/commands/kami.txt b/npc/commands/kami.txt
new file mode 100644
index 00000000..1211fae0
--- /dev/null
+++ b/npc/commands/kami.txt
@@ -0,0 +1,86 @@
+// TMW2 Script
+//
+// @k <message>
+// Broadcast, and broadcast to #world too
+//
+// @servmsg <message>
+// Experimental, uses servicemessage() - requires up to date server
+
+- script @k 32767,{
+ end;
+
+OnCall:
+ .@request$ = strcharinfo(0)+": ";
+ .@request$ += implode(.@atcmd_parameters$, " ");
+ channelmes("#world", .@request$);
+ announce l(.@request$), bc_all|bc_npc;
+ end;
+
+OnServMsg:
+ .@request$ = strcharinfo(0)+": ";
+ .@request$ += implode(.@atcmd_parameters$, " ");
+ // This can be slow, beware
+ .@c = getunits(BL_PC, .@players, MAX_CYCLE_PC);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ message(.@players[.@i], .@request$);
+ }
+ end;
+
+OnBuff:
+ // Disabled command, used for debug purposes
+ .@c = getunits(BL_PC, .@players, MAX_CYCLE_PC);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ attachrid(.@players[.@i]);
+ sc_start SC_INCMHPRATE, 300000, 100;
+ sc_start SC_INCMSPRATE, 300000, 100;
+ sc_start SC_INCFLEERATE, 300000, 100;
+ sc_start SC_INCHITRATE, 300000, 100;
+ sc_start SC_WALKSPEED, 300000, 150;
+ sc_start SC_ATTHASTE_POTION3, 300000, 50;
+ percentheal 100, 100;
+ dispbottom l("YOU WERE BLESSED BY JESUSALVA");
+ dispbottom l("YOU CAN FEEL THE POWER FLOWING TROUGH YOU.");
+ detachrid();
+ }
+ end;
+
+OnInstDestroy:
+ .@request = implode(.@atcmd_parameters$, " ");
+ if (.@request != 0)
+ instance_destroy(.@request);
+ end;
+
+OnInstCheck:
+ .@request$ = implode(.@atcmd_parameters$, " ");
+ dispbottom has_instance2(.@request$);
+ end;
+
+OnInit:
+ bindatcmd "k", "@k::OnCall", 60, 80, 1;
+ bindatcmd "servmsg", "@k::OnServMsg", 80, 99, 1;
+
+ bindatcmd "blessing", "@k::OnBuff", 99, 100, 1;
+ bindatcmd "instcheck", "@k::OnInstCheck", 99, 100, 1;
+ bindatcmd "instdestr", "@k::OnInstDestroy", 99, 100, 1;
+ end;
+}
+
+// kamibroadcast( message{, sender} )
+function script kamibroadcast {
+ .@msg$=getarg(0);
+ .@snd$=getarg(1, "");
+
+ // Send to #world
+ if (.@snd$ == "")
+ channelmes("#world", " "+.@msg$);
+ else
+ channelmes("#world", "[ "+.@snd$+" ] : "+.@msg$);
+
+ // Make an announce
+ if (.@snd$ == "")
+ announce .@msg$, bc_all|bc_npc;
+ else
+ announce .@snd$+" : "+.@msg$, bc_all|bc_npc;
+
+ return;
+}
diff --git a/npc/commands/language.txt b/npc/commands/language.txt
new file mode 100644
index 00000000..ce7122f5
--- /dev/null
+++ b/npc/commands/language.txt
@@ -0,0 +1,60 @@
+// TMW2 Script
+// Author: Jesusalva
+// With code parts from Julia (Evol)
+
+// @lang atcommand
+// Changes Language
+//
+// group lv: 0
+// group char lv: 0
+// log: False
+//
+// usage:
+// @lang
+//
+
+function script CMD_lang {
+ callfunc "checkclientversion";
+ mesq l("Which language do you speak?");
+ next;
+ asklanguage(LANG_IN_SHIP);
+ mes "";
+ mesn;
+ mesq l("Ok, done.");
+ return;
+}
+
+- script @lang 32767,{
+ end;
+
+OnCall:
+ CMD_lang();
+ close;
+
+OnTranslate:
+ // Implode, using a slash at whitespaces
+ .@request$ = implode(.@atcmd_parameters$, "%2F");
+ // No NPC provided?
+ if (.@request$ == "") {
+ dispbottom l("Usage: @translate <npc file>");
+ dispbottom l("Example: @translate Nard");
+ dispbottom l("Example: @translate Elmo");
+ dispbottom l("Example: @translate npc/002-1/arpan");
+ dispbottom l("PS. Doesn't always work. You need an account at %s and to be at ManaPlus Team.", "@@https://www.transifex.com/arctic-games|Transifex@@");
+ end;
+ }
+ // Add .txt extension of needed
+ if (!compare(.@request$, ".txt"))
+ .@request$ += ".txt";
+ // Fix stuff for URL format
+ .@request$ = replacestr(.@request$, "/", "%2F");
+ .@request$ = strtolower(.@request$);
+ // Give your translation link
+ dispbottom "@@https://www.transifex.com/arctic-games/moubootaur-legends/translate/#"+languagecode()+"/serverdata?q=occurrence%3A"+.@request$+"|Translate with Transifex@@";
+ close;
+
+OnInit:
+ bindatcmd "lang", "@lang::OnCall", 0, 60, 0;
+ bindatcmd "translate", "@lang::OnTranslate", 0, 60, 0;
+ end;
+}
diff --git a/npc/commands/numa.txt b/npc/commands/numa.txt
new file mode 100644
index 00000000..3fc544eb
--- /dev/null
+++ b/npc/commands/numa.txt
@@ -0,0 +1,100 @@
+
+- script SuperDebug NPC32767,{
+ if (GM < MAP_LOUNGE && GM < G_SYSOP && !debug) goto L_GM2; // make sure you can enter the gm lounge
+ //if (target(BL_ID,getnpcid("Numa"),1)) goto L_Main;
+ //npcaction 6, 12;
+ title "Numa";
+ goto L_Main;
+
+L_GM2:
+ message strcharinfo(0), "numa : GM command is level "+ MAP_LOUNGE +", but you are level " + GM;
+ end;
+
+L_Main:
+ mes "How may I help you?";
+ next;
+ menu
+ "Announcements", L_StoneBoard,
+ "MOTD", L_MOTD,
+ "Holiday debug", L_Holiday,
+ "Event debug", L_Event,
+ "Quest debug", L_Quest,
+ "Who are you?", L_WhoAmI,
+ "Close", L_close;
+ // todo: generic npcs
+ // todo: map list
+
+L_WhoAmI:
+ mes "I am Numa, also known as `SuperDebug`.";
+ mes "My sole purpose is to assist TMW staff from behind-the-scene.";
+ mes "Using me, you can access several debug menus.";
+ mes "You can call me from anywhere using the ##B@numa##b spell, or you can come see me in person.";
+ next;
+ goto L_Main;
+
+L_Holiday:
+ if (GM < DBG_HOLIDAY && GM < G_SYSOP) goto L_GM;
+ mes "What holiday do you want to debug?";
+ next;
+ menu
+ "Xmas.", L_XmasDebug,
+ "Halloween.", L_HalloweenDebug,
+ "Easter.", L_EasterDebug;
+
+// FIXME
+L_XmasDebug:
+ gmlog strcharinfo(0) + " accessed the Xmas debug.";
+ callfunc "XmasDebug";
+ goto L_close;
+
+// FIXME
+L_HalloweenDebug:
+ gmlog strcharinfo(0) + " accessed the Halloween debug.";
+ callfunc "HalloweenDebug";
+ goto L_close;
+
+// FIXME
+L_EasterDebug:
+ gmlog strcharinfo(0) + " accessed the Easter debug.";
+ callfunc "Easter Debug";
+ goto L_close;
+
+// FIXME
+L_Event:
+ if (GM < EVT_DEBUG && GM < G_EVENT) goto L_GM;
+ gmlog strcharinfo(0) + " accessed the GM event debug.";
+ callfunc "GmDebug";
+ goto L_close;
+
+L_StoneBoard:
+ if (GM < DBG_SCHEDULED && GM < G_SYSOP) goto L_GM;
+ callfunc "StoneBoard";
+ goto L_close;
+
+// FIXME?
+L_MOTD:
+ if (GM < DBG_MOTD && GM < G_SYSOP) goto L_GM;
+ callfunc "MOTDConfig";
+ goto L_close;
+
+L_GM:
+ mes "I'm awfully sorry.";
+ mes "You do not have the required GM level to perform this action.";
+ goto L_close;
+
+L_Quest:
+ callfunc "GlobalQuestDebug";
+ goto L_close;
+
+L_close:
+ close;
+
+OnInit:
+ registercmd "numa", strnpcinfo(0);
+ registercmd "superdebug", strnpcinfo(0);
+ end;
+}
+
+017-9,39,31,0 duplicate(SuperDebug) Numa NPC393
+
+
diff --git a/npc/commands/python.txt b/npc/commands/python.txt
new file mode 100644
index 00000000..3d198f82
--- /dev/null
+++ b/npc/commands/python.txt
@@ -0,0 +1,27 @@
+// The Mana World script
+// Author: Gumi <gumi@themanaworld.org>
+// Author: Jesusalva <jesusalva@themanaworld.org>
+//
+// Stomp stomp stomp (use with caution)
+
+- script @python 32767,{
+ end;
+
+OnCall:
+ specialeffect(69, AREA, playerattached());
+ .@zone$=getmapinfo(MAPINFO_ZONE, .@mapa$);
+ if (.@zone$ == "MMO")
+ end;
+ sc_start SC_CASH_DEATHPENALTY, 1000, 1;
+ addtimer 380, .name$+"::OnKill";
+ end;
+
+OnKill:
+ percentheal -100, -100;
+ //dispbottom l("Oh look, it is Cupid!");
+ end;
+
+OnInit:
+ bindatcmd "python", "@python::OnCall", 60, 60, 1;
+ end;
+}
diff --git a/npc/commands/rate-management.txt b/npc/commands/rate-management.txt
new file mode 100644
index 00000000..273ce9ba
--- /dev/null
+++ b/npc/commands/rate-management.txt
@@ -0,0 +1,231 @@
+// Authors: Gumi, Jesusalva
+- script @exprate 32767,{
+ end;
+
+ function rateCleanUp {
+ stopnpctimer;
+ .hours = 0;
+ .max_hours = 0;
+ .current_rate = .original_exp_rate;
+ setbattleflag("base_exp_rate", .original_exp_rate);
+ setbattleflag("quest_exp_rate", .original_quest_rate);
+ charcommand("@reloadmobdb"); // this is on purpose (callable without RID)
+ charcommand("@reloadquestdb");
+ }
+
+ function remainingTime {
+ .@total_seconds = (3600 * .max_hours);
+ .@seconds_elapsed = (3600 * .hours) + (getnpctimer(0) / 1000);
+ .@seconds_remaining = max(1, .@total_seconds - .@seconds_elapsed);
+ return FuzzyTime(time_from_seconds(.@seconds_remaining), 2, 2);
+ }
+
+OnCall:
+ if (!is_evtc())
+ {
+ end;
+ }
+
+ .@special$ = strip(.@atcmd_parameters$[0]); // special value
+ .@new_rate = min(atoi(.@special$), 1000); // or just a regular integer
+ .@hours = min(0x7FFFFFFE, max(1, atoi(strip(.@atcmd_parameters$[1])))); // number of hours
+
+ if (.@new_rate > 0)
+ {
+ // set new exp rate
+ .hours = 0;
+ .max_hours = .@hours;
+ .current_rate = .@new_rate;
+ setbattleflag("base_exp_rate", .@new_rate);
+ setbattleflag("quest_exp_rate", .@new_rate);
+ charcommand("@reloadmobdb");
+ charcommand("@reloadquestdb");
+ initnpctimer; // start counting
+
+ dispbottom l("You successfully set the exp rate to @@%. It will reset to @@% (default value) in @@.",
+ .@new_rate, .original_exp_rate, FuzzyTime(time_from_hours(.max_hours), 2, 2));
+ dispbottom l("You can also manually stop it at any time with: @exprate default");
+ }
+
+ else if (.@new_rate == 0 && .@special$ == "")
+ {
+ // get current exp rate
+ if (.current_rate == .original_exp_rate)
+ {
+ dispbottom l("Current exp rate is set to @@% (default value).", .current_rate);
+ }
+
+ else
+ {
+ dispbottom l("Current exp rate is set to @@%, and will reset to @@% (default value) in @@.",
+ .current_rate, .original_exp_rate, remainingTime());
+
+ dispbottom l("If you meant to reset the exp rate to its default value: @exprate default");
+ }
+ }
+
+ else
+ {
+ // reset
+ rateCleanUp;
+ dispbottom l("Exp rate has been reset to @@% (default value).",
+ .original_exp_rate);
+ }
+
+ end;
+
+OnTimer3600000:
+ // runs every hour
+ if (++.hours == .max_hours)
+ {
+ rateCleanUp;
+ end;
+ }
+ initnpctimer;
+ end;
+
+OnPCLoginEvent:
+ if (.max_hours > 0)
+ {
+ dispbottom col(l("Exp rate is set to @@% for the next @@.",
+ .current_rate, remainingTime()), 6);
+ }
+ end;
+
+OnInit:
+ bindatcmd "exprate", "@exprate::OnCall", 0, 99, 1; // change exp rate
+
+ // WARNING: using @reloadscript will change the "original" value
+ .original_exp_rate = getbattleflag("base_exp_rate");
+ .original_quest_rate = getbattleflag("quest_exp_rate");
+ .current_rate = .original_exp_rate;
+
+ // XXX: maybe in the future:
+ //.original_job_rate = getbattleflag("base_job_rate");
+ //.original_pk_mode = getbattleflag("pk_mode");
+ //.original_death_penalty = getbattleflag("death_penalty_type");
+ end;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////
+- script @droprate 32767,{
+ end;
+
+ function dropRateReal {
+ return 100; // getbattleflag("item_rate_common") ?
+ }
+
+ function dropRecalc {
+ .@val=getarg(0);
+ return .@val;
+ }
+
+ function rateCleanUp {
+ stopnpctimer;
+ .hours = 0;
+ .max_hours = 0;
+ .current_rate = getbattleflag("item_rate_common");
+ setbattleflag("item_rate_common", dropRateReal());
+ setbattleflag("item_rate_common_boss", dropRateReal());
+ setbattleflag("item_rate_heal", dropRateReal());
+ setbattleflag("item_rate_heal_boss", dropRateReal());
+ setbattleflag("item_rate_use", dropRateReal());
+ setbattleflag("item_rate_use_boss", dropRateReal());
+ setbattleflag("item_rate_equip", dropRateReal());
+ setbattleflag("item_rate_equip_boss", dropRateReal());
+ setbattleflag("item_rate_card", dropRateReal());
+ setbattleflag("item_rate_card_boss", dropRateReal());
+ charcommand("@reloadmobdb"); // this is on purpose (callable without RID) - no idea what is the purpose
+ channelmes("#world", "The Drop Rate Bonus is now over.");
+ }
+
+ function remainingTime {
+ .@total_seconds = (3600 * .max_hours);
+ .@seconds_elapsed = (3600 * .hours) + (getnpctimer(0) / 1000);
+ .@seconds_remaining = max(1, .@total_seconds - .@seconds_elapsed);
+ return FuzzyTime(time_from_seconds(.@seconds_remaining), 2, 2);
+ }
+
+OnCall:
+ if (!is_evtc()) {
+ end;
+ }
+
+ .@special$ = strip(.@atcmd_parameters$[0]); // special value
+ .@new_rate = min(atoi(.@special$), 1000); // or just a regular integer
+ .@hours = min(0x7FFFFFFE, max(1, atoi(strip(.@atcmd_parameters$[1])))); // number of hours
+
+ if (.@new_rate > 0)
+ {
+ // set new exp rate
+ .hours = 0;
+ .max_hours = .@hours;
+ .current_rate = .@new_rate;
+ setbattleflag("item_rate_common", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_common_boss", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_heal", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_heal_boss", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_use", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_use_boss", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_equip", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_equip_boss", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_card", dropRecalc(.@new_rate));
+ setbattleflag("item_rate_card_boss", dropRecalc(.@new_rate));
+ charcommand("@reloadmobdb");
+ initnpctimer; // start counting
+
+ .@msg$=strcharinfo(0)+" modified drop rates to "+str(.@new_rate)+"%. It will only last "+str(FuzzyTime(time_from_hours(.max_hours), 2, 2))+"!";
+
+ announce .@msg$, bc_all;
+ channelmes("#world", .@msg$);
+
+ //dispbottom l("You successfully set the drop rate to @@%. It will reset to @@% (default value) in @@.",
+ // .@new_rate, dropRateReal(), FuzzyTime(time_from_hours(.max_hours), 2, 2));
+ dispbottom l("You can also manually stop it at any time with: @droprate default");
+ } else if (.@new_rate == 0 && .@special$ == "") {
+ // get current exp rate
+ if (.current_rate == dropRateReal()) {
+ atcommand("@rates");
+ dispbottom col(l("Usage of @exprate without argument is deprecated, please use \"@rates\" instead."), 1);
+ } else {
+ dispbottom l("Current drop rate is set to @@%, and will reset to @@% (default value) in @@.",
+ .current_rate, dropRateReal(), remainingTime());
+ dispbottom l("If you meant to reset the drop rate to its default value: @droprate default");
+ }
+ }
+
+ else
+ {
+ // reset
+ rateCleanUp;
+ dispbottom l("Drop rate has been reset to @@% (default value).",
+ dropRateReal());
+ }
+
+ end;
+
+OnTimer3600000:
+ // runs every hour
+ if (++.hours == .max_hours) {
+ rateCleanUp;
+ end;
+ }
+ initnpctimer;
+ end;
+
+OnPCLoginEvent:
+ if (.max_hours > 0) {
+ dispbottom col(l("Drop rate is set to @@% for the next @@.",
+ .current_rate, remainingTime()), 6);
+ }
+ end;
+
+OnInit:
+ bindatcmd "droprate", "@droprate::OnCall", 80, 80, 1; // change drop rate
+
+ // WARNING: using @reloadscript will change the "original" value, use @reloadbattleconf before!
+ .current_rate = getbattleflag("item_rate_common");
+ //force_refreshall();
+ end;
+}
diff --git a/npc/commands/resync.txt b/npc/commands/resync.txt
new file mode 100644
index 00000000..246bfa88
--- /dev/null
+++ b/npc/commands/resync.txt
@@ -0,0 +1,45 @@
+// TMW2 script
+// Author: Jesusalva <admin@tmw2.org>
+//
+// Introduces @resync
+//
+// It'll cast slide to your own position
+// Hopefully making client update your real position without causing server warning
+//
+// This also introduces @resyncall
+// Which is an alias for @refresh and causes client to reload the whole map,
+// Including yourself and monsters.
+
+- script @resync 32767,{
+ end;
+
+// Soft Resync
+OnCall:
+ if (ispcdead()) {
+ dispbottom l("Impossible to resync: You are dead.");
+ end;
+ }
+ if (@rsync_delay > gettimetick(2)) {
+ dispbottom l("Not resync'ing to prevent flood.");
+ end;
+ }
+ getmapxy(.@m$, .@x, .@y, 0);
+ slide .@x, .@y;
+ @rsync_delay=gettimetick(2)+rand2(3,5);
+ end;
+
+// Hard Resync
+OnCallRefresh:
+ if (@rsync_delay > gettimetick(2)) {
+ dispbottom l("Not resync'ing to prevent flood.");
+ end;
+ }
+ @rsync_delay=gettimetick(2)+rand2(3,5);
+ atcommand("@refresh");
+ end;
+
+OnInit:
+ bindatcmd "resync", "@resync::OnCall", 0, 60, 0;
+ bindatcmd "resyncall", "@resync::OnCallRefresh", 0, 60, 0;
+ end;
+}
diff --git a/npc/commands/scheduled-broadcasts.txt b/npc/commands/scheduled-broadcasts.txt
new file mode 100644
index 00000000..1801663a
--- /dev/null
+++ b/npc/commands/scheduled-broadcasts.txt
@@ -0,0 +1,227 @@
+// Evol Script
+// Authors: Gumi
+function script StoneBoard {
+
+ function setMessage {
+ do
+ {
+ clear;
+ mes l("Please enter the message:");
+ next;
+ input .@msg$;
+ .@msg$ = strip(.@msg$);
+ if (.@msg$ != "") {
+ return .@msg$;
+ }
+ mes l("The message cannot be empty");
+ next;
+ } while (1);
+ }
+
+ function setInterval {
+ clear;
+ mes l("Please select the interval:");
+ next;
+ menuint
+ l("Every 1 hour"), 1,
+ l("Every 3 hours"), 3,
+ l("Every 5 hours"), 5,
+ l("Every 6 hours"), 6,
+ l("Every 12 hours"), 12,
+ l("Every 24 hours"), 24,
+ l("Never (only on login)"), 0;
+
+ return @menuret;
+ }
+
+ function setMaxRep {
+ if (getarg(0,0) == 0) {
+ return 0;
+ }
+ clear;
+ mes l("Repeat how many times?");
+ next;
+ menuint
+ l("Send only once"), 1,
+ l("Send 2 times"), 2,
+ l("Send 3 times"), 3,
+ l("Send 5 times"), 5,
+ l("Send 10 times"), 10,
+ l("Send 20 times"), 20,
+ l("Send indefinitely"), 0;
+
+ return @menuret;
+ }
+
+ function setOnLogin {
+ if (getarg(0,0) == 0)
+ {
+ return 1;
+ }
+ clear;
+ mes l("Send this message also on login?");
+ next;
+ select
+ l("No"),
+ l("Yes");
+
+ return (@menu - 1);
+ }
+
+ function newBroadcast {
+ do
+ {
+ setnpcdialogtitle l("Scheduled broadcasts - Create new");
+
+ // go through all steps
+ .@msg$ = setMessage();
+ .@int = setInterval();
+ .@max = setMaxRep(.@int);
+ .@login = setOnLogin(.@int);
+
+ // recap
+ clear;
+ mes l("Message:");
+ mes "---";
+ mes .@msg$;
+ mes "---";
+ if (.@int)
+ {
+ mes l("Interval: every @@ hour(s)", .@int);
+ mes l("Repeat: @@ times", .@max ? .@max : "∞");
+ mes l("Sent on login: @@", .@login ? l("yes") : l("no"));
+ }
+ else
+ {
+ mes l("Interval: (none, only sent on login)");
+ mes l("Sent on login: yes");
+ }
+
+ next;
+ select
+ menuimage("actions/cancel", l("Discard")),
+ menuimage("actions/edit", l("Start over")),
+ menuimage("actions/test", l("Start broadcasting")),
+ menuimage("actions/test", l("Start broadcasting, and make an extra broadcast right now"));
+
+ switch (@menu)
+ {
+ case 3:
+ case 4:
+ stopnpctimer "@sched";
+ $@SCHED_Opt[0] = .@login;
+ $@SCHED_Opt[1] = .@int;
+ $@SCHED_Opt[2] = 0;
+ $@SCHED_Opt[3] = .@max;
+ $@SCHED_Opt[4] = 0;
+ $@SCHED_Msg$ = .@msg$;
+ if (.@int)
+ {
+ initnpctimer "@sched";
+ }
+ if (@menu == 4)
+ {
+ announce $@SCHED_Msg$, bc_all;
+ }
+ logmes "Scheduled Broadcast: A new broadcast was added", LOGMES_ATCOMMAND;
+ case 1: return;
+ }
+
+ } while(1);
+ }
+
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Scheduled broadcasts");
+ mes l("This menu allows you to set the scheduled broadcast that is sent to all players at a specific interval.");
+ mes "";
+
+ .@a = $@SCHED_Msg$ != ""; // any active broadcast?
+ mes "---";
+ mes .@a ? $@SCHED_Msg$ : "(" + l("no active broadcast") +")";
+ mes "---";
+ if (.@a)
+ {
+ mes l("Sent on login: @@", ($@SCHED_Opt[0] ? l("yes") : l("no")));
+ if ($@SCHED_Opt[1])
+ {
+ .@next = max(1, ((3600000 * ($@SCHED_Opt[1] - $@SCHED_Opt[4])) - getnpctimer(0, "@sched")));
+ mes l("Interval: every @@ hour(s)", $@SCHED_Opt[1]);
+ mes l("Next broadcast: @@", FuzzyTime(time_from_ms(.@next)));
+ }
+ else
+ {
+ mes l("Interval: (none, only sent on login)");
+ mes l("Next broadcast: (never)");
+ }
+ mes l("Sent: @@ times out of @@", $@SCHED_Opt[2], ($@SCHED_Opt[3] ? $@SCHED_Opt[3] : "∞"));
+ }
+ next;
+
+ select
+ menuimage("actions/abort", l("Abort")),
+ rif(.@a, menuimage("actions/test", l("Manually trigger the current broadcast"))),
+ rif(.@a, menuimage("actions/remove", l("Stop broadcasting"))),
+ rif(!(.@a), menuimage("actions/add", l("Set a new broadcast"))),
+ rif(getarg(0,0), menuimage("actions/home", l("Return to Super Menu")));
+
+ switch (@menu)
+ {
+ case 2: announce $@SCHED_Msg$, bc_all; break;
+ case 3: $@SCHED_Msg$ = ""; break;
+ case 4: newBroadcast; break;
+ default: return;
+ }
+ } while (1);
+}
+
+
+
+- script @sched 32767,{
+ end;
+
+OnTimer3600000:
+ if ($@SCHED_Msg$ == "")
+ {
+ stopnpctimer;
+ end;
+ }
+
+ ++$@SCHED_Opt[4]; // increase hours counter
+ if ($@SCHED_Opt[4] == $@SCHED_Opt[1])
+ {
+ stopnpctimer;
+ ++$@SCHED_Opt[2]; // increase total counter
+ announce $@SCHED_Msg$, bc_all;
+ $@SCHED_Opt[4] = 0; // reset hours counter
+ if ($@SCHED_Opt[2] >= $@SCHED_Opt[3] && $@SCHED_Opt[3] > 0)
+ {
+ $@SCHED_Msg$ = ""; // reset message
+ end;
+ }
+ }
+ initnpctimer;
+ end;
+
+OnCall:
+ if (!is_gm())
+ {
+ end;
+ }
+
+ StoneBoard;
+ closedialog;
+ end;
+
+OnInit:
+ bindatcmd "sched", "@sched::OnCall", 80, 99, 1;
+}
+
+function script StoneBoardRead {
+ if ($@SCHED_Opt[0] && $@SCHED_Msg$ != "")
+ {
+ announce $@SCHED_Msg$, bc_self;
+ }
+ return;
+}
diff --git a/npc/commands/warp.txt b/npc/commands/warp.txt
new file mode 100644
index 00000000..ddd0449d
--- /dev/null
+++ b/npc/commands/warp.txt
@@ -0,0 +1,86 @@
+// @w atcommand
+// warps using anchors or map name
+//
+// group lv: 1
+// group char lv: 2
+// log: True
+//
+// usage:
+// @w <map or anchor> [, x [, y]]
+// #w "char" <map or anchor> [, x [, y]]
+//
+// example:
+// @w artis
+// #w "char" artis
+
+- script @w 32767,{
+ end;
+
+OnCall:
+ .@params$ = strtoupper(strip(implode(.@atcmd_parameters$[0], " ")));
+ .@request$ = replacestr(.@params$, " ", "");
+
+ cleararray($@regexmatch$[1], "", 3);
+ if (.@params$ ~= "^(.+) ([0-9]+) ([0-9]+)$")
+ {
+ .@request$ = replacestr(strip($@regexmatch$[1]), " ", "");
+ .@req_x = atoi(strip($@regexmatch$[2]));
+ .@req_y = atoi(strip($@regexmatch$[3]));
+ }
+
+ .@ht = getvariableofnpc(.ht, "__anchors__");
+ .@it = htiterator(.@ht);
+ for (.@key$ = htifirstkey(.@it); hticheck(.@it); .@key$ = htinextkey(.@it))
+ {
+ if (.@request$ ~= .@key$)
+ {
+ sscanf(htget(.@ht, .@key$, ""), "%s %d %d", .@map$, .@x, .@y);
+ break;
+ }
+ }
+ htidelete(.@it);
+
+ .@map$ = .@map$ ? .@map$ : .@request$;
+ .@x = .@req_y ? .@req_x : .@x;
+ .@y = .@req_y ? .@req_y : .@y;
+
+ if (getmapinfo(MAPINFO_ID, .@map$) < 0)
+ {
+ if (getmapinfo(MAPINFO_ID, .@atcmd_parameters$[0]) >= 0)
+ {
+ .@map$ = .@atcmd_parameters$[0];
+ }
+ else
+ {
+ dispbottom(l("Map or anchor not found: %s", .@atcmd_parameters$[0]));
+ end;
+ }
+ }
+
+ while (!checkcell(.@map$, .@x, .@y, cell_chkpass))
+ {
+ // FIXME: this whole cell finding loop is DIRTY!
+ // we should have a command to get a random free coordinate
+ // or we should make buildin_warp silently ignore 0,0
+
+ if (.@e == 50) break; // FIXME: triggers a console warning
+ .@x = rand(20, 20 + (.@e * 5));
+ .@y = rand(20, 20 + (.@e * 5));
+ ++.@e;
+ }
+
+ warp(.@map$, .@x, .@y);
+ end;
+
+OnInit:
+ if (debug) {
+ bindatcmd("w", "@w::OnCall", 0, 20, 0);
+ bindatcmd("go", "@w::OnCall", 0, 20, 0);
+ bindatcmd("to", "@w::OnCall", 0, 20, 0);
+ } else {
+ bindatcmd("w", "@w::OnCall", 20, 60, 1);
+ bindatcmd("go", "@w::OnCall", 20, 60, 1);
+ bindatcmd("to", "@w::OnCall", 20, 60, 1);
+ }
+ end;
+}