// TMW 2 Script
// Author:
// Jesusalva
// Micksha
// Description:
// This NPC is a work on progress. It measures all players equal.
// Controls the weekly guild dungeon feature.
// Variable structure:
// $@KAMELOT_ID [ guild_id ] = instance id
// $@KAMELOT_WAVE [ guild_id ] = contains a temporary control value
// $KAMELOT_MX [ guild_id ] = player average level - difficulty record
// $KAMELOT_PC [ guild_id ] = total members in guild
// $KAMELOT_QUEST [ guild_id ] = quest status (bitmask)
// 0 - Not started
// 1 - Quest Assigned by Arthur (new players cannot enter anymore)
// 2 - Guinevere dialog clear
// 4 - Weapon Room cutscene seen
// 8 - Magic Seal 01 Broken
// 16 - Magic Seal 02 Broken
// 32 - Door opened
// 64 - Boss defeated
// 128 - Guild Reward Claimed
// $KAMELOT_KEYMASK [ guild_id ] = (bitmask) Keys and Lockpicks
// 1 - Treasure A (Boss Room key)
// 2 - Treasure B
// 4 - Treasure C
// 8 - Treasure D
// 16 - Weapon Room Key
// $KAMELOT_PASSMASK [ guild_id ] = (bitmask) Switches in 042-10
// $KAMELOT_KEY [ guild_id ] = Which bit was assigned as the key
// $KAMELOT_PASSCODE [ guild_id ] = A bitmask of passcode to use the key
// $KAMELOT_COOLDOWN [ guild_id ] = Last attempt (weekly attempts)
// KamelotCleanup(guildid)
function script KamelotCleanup {
.@g=getarg(0);
//$@KAMELOT_ID[.@g]=0;
$@KAMELOT_WAVE[.@g]=0;
$KAMELOT_MX[.@g]=0;
$KAMELOT_PC[.@g]=0;
$KAMELOT_KEY[.@g]=0;
$KAMELOT_QUEST[.@g]=0;
$KAMELOT_KEYMASK[.@g]=0;
$KAMELOT_PASSCODE[.@g]=0;
$KAMELOT_PASSMASK[.@g]=0;
// TODO: Instance Destroy? D:
// And it couldn't be ran from Arthur? D:
// Timers keep running and previous attempts leave artifacts D:
return;
}
014-4,67,26,0 script #KamelotEnter NPC_HIDDEN,0,0,{
end;
OnTouch:
// Not in a guild: Gate is sealed (MK might be excluded as well)
if (getcharid(2) < 1) {
dispbottom l("The gates are firmly shut. A warning is on the door, \"DO NOT ENTER. Guild Only.\"");
end;
}
// XXX STATUS: STAGING - FINAL TESTING XXX
if ($EVENT$ != "Kamelot") {
dispbottom l("Kamelot Castle gates are closed; Please wait for the GM Team announcements.");
end;
}
// Save your GID for reference
.@g=getcharid(2);
// Quest already started
if ($KAMELOT_QUEST[.@g] & 1) {
// Quest started but Cooldown expired
// Needs to cleanup - wipe all variables
if ($KAMELOT_COOLDOWN[.@g] < gettimeparam(GETTIME_WEEKDAY)) {
KamelotCleanup(.@g);
} else {
dispbottom l("The gates are firmly shut by some weird magical power. %s", (TUTORIAL ? l("Perhaps we should wait a few days."):""));
end;
}
}
// Build instance if it doesn't exists or has been reallocated
if (instanceowner($@KAMELOT_ID[.@g]) != .@g) {
debugmes "Creating Instance for guild %d", .@g;
.@inst=instance_create("Kamelot@"+.@g, .@g, IOT_GUILD);
if (.@inst < 0)
Exception("Kamelot Instance Error", RB_DEFAULT|RB_ISFATAL);
instance_attachmap("042-0", .@inst, .@g, "042-0@"+.@g);
instance_attachmap("042-1", .@inst, .@g, "042-1@"+.@g);
instance_attachmap("042-2", .@inst, .@g, "042-2@"+.@g);
instance_attachmap("042-3", .@inst, .@g, "042-3@"+.@g);
instance_attachmap("042-4", .@inst, .@g, "042-4@"+.@g);
instance_attachmap("042-5", .@inst, .@g, "042-5@"+.@g);
instance_attachmap("042-6", .@inst, .@g, "042-6@"+.@g);
instance_attachmap("042-7", .@inst, .@g, "042-7@"+.@g);
instance_attachmap("042-8", .@inst, .@g, "042-8@"+.@g);
instance_attachmap("042-9", .@inst, .@g, "042-9@"+.@g);
instance_attachmap("042-10", .@inst, .@g, "042-10@"+.@g);
instance_attachmap("042-11", .@inst, .@g, "042-11@"+.@g);
instance_set_timeout(21600, 21600, .@inst); // Instance lasts 6 hours
instance_init(.@inst);
$@KAMELOT_ID[.@g] = .@inst;
}
// You can enter in every other state
warp "042-0@"+.@g, any(59, 60), 80;
// Renew the instance clock : 6 hours
instance_set_timeout(21600, 21600, $@KAMELOT_ID[.@g]);
end;
// Debug is only allowed if server is in override mode
OnDebug:
if (!$@GM_OVERRIDE) goto L_SimplifiedDebug;
.@g=getcharid(2);
if (.@g < 1) end;
mes "Kamelot Debug";
mesf "Guild: %d", .@g;
mes "";
mesf "Keys: %d", $KAMELOT_KEYMASK[.@g];
mesf "Quest: %d", $KAMELOT_QUEST[.@g];
mes "";
mesf "Maze Password: %d", $KAMELOT_PASSCODE[.@g];
mesf "Maze Status: %d", $KAMELOT_PASSMASK[.@g];
mes "";
mesf "Guild Power: %d", $KAMELOT_MX[.@g];
mesf "Guild Count: %d", $KAMELOT_PC[.@g];
select
l("Abort"),
l("Reset"),
l("Reset & Destroy"),
l("Quest - Skip Weapons Room"),
l("Quest - Skip Krukan fight"),
l("Quest - Find all Keys"),
l("Quest - Unlock Boss Room"),
l("Quest - Mark as Completed"),
"",
l("Warp - Jump to Entrance"), // 10
l("Warp - Jump to Weapon Room"),
l("Warp - Jump to Basement"),
l("Warp - Jump to Jail"),
l("Warp - Jump to Sewer Entrance"),
l("Warp - Jump to Cave Exit"),
l("Warp - Arrest me!");
mes "";
switch (@menu) {
// 3 inheirs 2
case 3:
instance_destroy($@KAMELOT_ID[.@g]);
case 2:
$KAMELOT_COOLDOWN[.@g] = 0;
KamelotCleanup(.@g);
break;
// We now order from bottom-up
case 8:
$KAMELOT_QUEST[.@g]=$KAMELOT_QUEST[.@g]|64;
mes "WARNING: Quest concluded";
case 7:
$KAMELOT_QUEST[.@g]=$KAMELOT_QUEST[.@g]|8;
$KAMELOT_QUEST[.@g]=$KAMELOT_QUEST[.@g]|16;
$KAMELOT_QUEST[.@g]=$KAMELOT_QUEST[.@g]|32;
mes "WARNING: Boss Room was unlocked";
case 6:
$KAMELOT_KEYMASK[.@g]=$KAMELOT_KEYMASK[.@g]|1;
$KAMELOT_KEYMASK[.@g]=$KAMELOT_KEYMASK[.@g]|2;
$KAMELOT_KEYMASK[.@g]=$KAMELOT_KEYMASK[.@g]|4;
$KAMELOT_KEYMASK[.@g]=$KAMELOT_KEYMASK[.@g]|8;
mes "WARNING: Kamelot Basement Chests skipped (not lootable).";
case 5:
$KAMELOT_QUEST[.@g]=$KAMELOT_QUEST[.@g]|4;
mes "WARNING: Krukan Fight and jail skipped.";
case 4:
$KAMELOT_KEYMASK[.@g]=$KAMELOT_KEYMASK[.@g]|16;
mes "WARNING: Weapons Room skipped.";
break;
// 10+ are the warp triggers
case 10:
warp "042-0@"+.@g, 60, 40; break;
case 11:
warp "042-1@"+.@g, 40, 65; break;
case 12:
warp "042-2@"+.@g, 44, 45; break;
case 13:
warp "042-3@"+.@g, 60, 130; break;
case 14:
warp "042-4@"+.@g, 60, 67; break;
case 15:
warp "042-10@"+.@g, 95, 52; break;
case 16:
.@t$="042-3@"+.@g;
.@n$=instance_npcname("#KSlimeSpawn", $KAMELOT_ID[.@g]);
setarray .@x, 33, 84, 41, 74, 36, 57, 79, 43, 24, 86, 59, 38;
setarray .@y, 135, 127, 119, 107, 96, 84, 63, 67, 67, 22, 49, 27;
specialeffect(FX_HIT, AREA, getcharid(3));
.@v = (rand2(12) % 12);
.@r=attachrid(getcharid(3));
if (.@r) {
warp .@t$, .@x[.@v], .@y[.@v];
if (!countitem(Lockpicks))
addtimer 700, .@n$+"::OnFirstSlime";
setpcblock(255, false);
} else {
unitwarp(getcharid(3), .@t$, .@x[.@v], .@y[.@v]); // And good luck D:
debugmes "FATAL: Could not attach: %d", getcharid(3);
}
break;
}
close;
L_SimplifiedDebug:
mesc "THIS IS FOR JESUSALVA DEBUG ONLY - DO NOT USE NORMALLY", 1;
mes "Guild ID:";
input .@gid;
if (.@gid < 1 || .@gid > 100)
close;
$KAMELOT_COOLDOWN[.@gid] = 0;
KamelotCleanup(.@gid);
mesc "THE GUILD WAS WIPED FROM EXISTENCE.", 1;
mesc "Have a nice day! %%l", 3;
close;
OnInit:
bindatcmd "kdebug", "#KamelotEnter::OnDebug", 99, 100, 1;
end;
}
/////////////////////////////////////////////////////////////////////////////
// KamelotCaveSpawn(Amount, x1, y1, x2, y2, power{, map})
function script KamelotCaveSpawn {
.@label$=instance_npcname(.name$)+"::OnKillMob";
.@gcount=getarg(0);
.@x1=getarg(1);
.@y1=getarg(2);
.@x2=getarg(3);
.@y2=getarg(4);
.@avg=getarg(5);
.@m$=instance_mapname(getarg(6, .map$));
//debugmes "Total %d, map %s (power %d)", .@gcount, .@m$, .@avg;
freeloop(true);
for (.@i=0; .@i < .@gcount; .@i++) {
.@mobId=any(CursedSoldier, CursedArcher); // 50-50 ratio
.@mob=areamonster(.@m$, .@x1, .@y1, .@x2, .@y2, strmobinfo(1, .@mobId), .@mobId, 1, .@label$);
// Reconfigure the monster
setunitdata(.@mob, UDT_LEVEL, .@avg+1);
setunitdata(.@mob, UDT_STR, 1+.@avg*6/10);
setunitdata(.@mob, UDT_AGI, 1+.@avg*5/10);
setunitdata(.@mob, UDT_VIT, 1+.@avg*5/10);
setunitdata(.@mob, UDT_INT, 1+.@avg*6/10);
setunitdata(.@mob, UDT_DEX, 1+.@avg*6/10);
setunitdata(.@mob, UDT_LUK, 1+.@avg*5/10);
setunitdata(.@mob, UDT_ADELAY, 1372);
setunitdata(.@mob, UDT_ATKRANGE, (.@mobId == CursedArcher ? any(6,7) : any(1,2)));
// Battle Status
setunitdata(.@mob, UDT_MAXHP, .@avg*40);
setunitdata(.@mob, UDT_HP, .@avg*40);
setunitdata(.@mob, UDT_ATKMIN, .@avg*52/10);
setunitdata(.@mob, UDT_ATKMAX, .@avg*72/10);
setunitdata(.@mob, UDT_DEF, 1+.@avg*12/10);
setunitdata(.@mob, UDT_MDEF, 1+.@avg*8/10);
setunitdata(.@mob, UDT_HIT, .@avg*6); // Advised: x3
setunitdata(.@mob, UDT_FLEE, .@avg*45/10); // Advised: x4
// Critical calculation
.@min=15;
.@max=max(.@min, min(40, .@avg/3));
setunitdata(.@mob, UDT_CRIT, rand2(.@min, .@max));
// Loop through
}
freeloop(false);
return;
}