// TMW 2 Script
// Author:
// Jesusalva
// Micksha
// Description:
// Controls the showdown
042-11,41,57,0 script #KDoor04211a NPC_HIDDEN,4,0,{
end;
OnTouch:
.@g=getcharid(2);
if (.@g < 1) die();
if (!($KAMELOT_QUEST[.@g] & 64)) goto L_NoAccess;
warp "042-10@"+.@g, 143, 21;
end;
L_NoAccess:
dispbottom l("Can't leave right now.");
end;
}
042-11,20,28,0 script #KDoor04211b NPC_HIDDEN,0,2,{
end;
OnTouch:
.@g=getcharid(2);
if (.@g < 1) die();
if (!($KAMELOT_QUEST[.@g] & 64)) goto L_NoAccess;
mes l("Are you sure you want leave?");
mesc l("You wont be able to go back!");
next;
if (askyesno() == ASK_YES) {
warp "042-0@"+.@g, 46, 25;
callfunc("KamelotTreasure", 1024, true); // Give a reward from the exclusive chest
X24Event(X24_KAMELOT);
}
close;
L_NoAccess:
dispbottom l("Can't leave right now.");
end;
}
042-11,0,0,0 script #KamelotBoss NPC_HIDDEN,{
end;
OnDialog:
announce "??? : "+l("Who sent you here? Merlin?"), bc_self|bc_pc;
addtimer 8000, "#KamelotBoss::OnDialog2";
end;
OnDialog2:
.@g=getcharid(2);
announce "??? : "+l("It matters not, because soon, all of you will be..."), bc_self|bc_pc;
addtimer 7000, instance_npcname("#KamelotBoss", $@KAMELOT_ID[.@g])+"::OnBegin";
end;
// Spawns Terogan
OnBegin:
.@g=getcharid(2);
.@m$=instance_mapname("042-11");
.@avg=$KAMELOT_MX[.@g]+10;
.@n$=instance_npcname("#KamelotBoss", $@KAMELOT_ID[.@g]);
debugmes "GID: %d Map: %s Power: %d Label: %s", .@g, .@m$, .@avg, .@n$;
// Dialog
announce l("General Terogan : DEAD! Muahahahaha!"), bc_self|bc_pc;
// Check if Terogan doesn't exists already
.@exist=getd("$@GTEMP_"+.@m$);
if (.@exist)
end;
// Check if quest isn't over already '-'
if ($KAMELOT_QUEST[.@g] & 64)
end;
// Bring Terogan into existence
.@mob=monster(.@m$, 40, 30, strmobinfo(1, GeneralTerogan), GeneralTerogan, 1, .@n$+"::OnKillBoss");
setd("$@GTEMP_"+.@m$, .@mob);
setd("$@GTEMP_HP_"+.@m$, 20);
// Reconfigure the monster
setunitdata(.@mob, UDT_LEVEL, .@avg);
setunitdata(.@mob, UDT_STR, 1+.@avg/2);
setunitdata(.@mob, UDT_AGI, 1+.@avg/2);
setunitdata(.@mob, UDT_VIT, 1+.@avg/2);
setunitdata(.@mob, UDT_INT, 1+.@avg/2);
setunitdata(.@mob, UDT_DEX, 1+.@avg/2);
setunitdata(.@mob, UDT_LUK, 1+.@avg/2);
setunitdata(.@mob, UDT_ADELAY, 1072);
setunitdata(.@mob, UDT_ATKRANGE, 4);
// Battle Status
setunitdata(.@mob, UDT_MAXHP, .@avg*700);
setunitdata(.@mob, UDT_HP, .@avg*700);
setunitdata(.@mob, UDT_ATKMIN, .@avg*7);
setunitdata(.@mob, UDT_ATKMAX, .@avg*9);
setunitdata(.@mob, UDT_DEF, 4+.@avg);
setunitdata(.@mob, UDT_MDEF, 1+.@avg);
setunitdata(.@mob, UDT_HIT, .@avg*18); // Advised: x3
setunitdata(.@mob, UDT_FLEE, .@avg*5); // Advised: x4
setunitdata(.@mob, UDT_CRIT, 120);
// Initial batch of reinforcements
KamelotCaveSpawn(6, 30, 20, 50, 40, .@avg, "042-11");
// Save info again
setd("$@GTEMP_"+.@m$, .@mob);
setd("$@GTEMP_HP_"+.@m$, 20);
initnpctimer;
end;
// Checks HP ratio again
OnTimer5000:
explode(.@map$, .map$, "@");
.@g=atoi(.@map$[1]);
if (.@g < 1) {
consolebug "[ERROR] [KAMELOT] Unable to find Terogan - Kamelot %s", .map$;
.@g=0;
}
// Retrieve Terogan's GUID and MAP ID
.@m$=instance_mapname("042-11");
.@mob=getd("$@GTEMP_"+.@m$);
// Prepare the reinforcement strength data (min 3 Lv 22 spawn)
.@gcount=$KAMELOT_PC[.@g]+2;
.@avg=$KAMELOT_MX[.@g]+rand2(22, 27);
// Calculate current HP ratio and the difference
.@ratio=getunitdata(.@mob, UDT_HP)*20/getunitdata(.@mob, UDT_MAXHP);
.@hplos=getd("$@GTEMP_HP_"+.@m$)-.@ratio;
//debugmes "Ratio %d/%d", .@ratio, getd("$@GTEMP_HP_"+.@m$);
if (.@ratio < getd("$@GTEMP_HP_"+.@m$)) {
mapannounce .@m$, "General Terogan : "+any("Charge!", "To the Abyss with you already!", "Kill them already!", "More of them might be coming!", "Minions, ATTACK!", "Muahahaha, Pathetic!"), 0;
// Unlike Krukan, spawn according to HP loss (no use fast killing)
KamelotCaveSpawn(.@gcount*max(1, .@hplos), 20, 20, 57, 40, .@avg, "042-11");
}
// Special skills (seldomly, but entirely randomly, triggered)
if (rand2(10000) < ($KAMELOT_MX[.@g] + $KAMELOT_PC[.@g] + getguildlvl(.@g))) {
// Taken from Aurora Boss Raid and Blanc
.@skill = rand2(10);
getmapxy(.@m$, .@x, .@y, UNITTYPE_MOB, .@mob);
.@c=getunits(BL_PC, .@pcs, MAX_CYCLE_PC, .@m$);
.@mvp=0;.@rnd=0;.@def=-1;
for (.@i = 0; .@i < .@c; .@i++) {
if (!.@rnd || !rand2(.@c))
.@rnd=.@pcs[.@i];
if (readbattleparam(.@pcs[.@i], UDT_DEF) > .@def) {
if (readparam(Hp, .@pcs[.@i]) < 1) continue;
.@mvp=.@pcs[.@i];
.@def=readbattleparam(.@pcs[.@i], UDT_DEF);
}
}
.@lv = $KAMELOT_MX[.@g];
.@t = rand2(2 + .@lv / 10);
// Execute the skill
switch (.@skill) {
case 1:
.@msg$ = sprintf("Witness my sublime rain of death. Regeneration!");
.@hp=getunitdata(.@mob, UDT_HP);
.@mp=getunitdata(.@mob, UDT_MAXHP);
setunitdata(.@mob, UDT_HP, min(.@mp, .@hp+(.@lv * 50)));
.@mobid=(rand2(.@lv) > 50 ? DeathCat : GreenSlime);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 2:
.@msg$ = sprintf("Chaos shall be my founding stone! Falling star!");
attachrid(.@rnd);
percentheal -5, -10;
detachrid();
.@mobid=(rand2(.@lv) > 50 ? BlackScorpion : RedSlime);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 3:
.@msg$ = sprintf("I demand this world! Tyranny!");
attachrid(.@rnd);
percentheal -1, -1;
SC_Bonus(.@t, any(SC_BLIND, SC_POISON), 1);
detachrid();
.@mobid=(rand2(.@lv) > 50 ? DarkLizard : Assassin);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 4:
.@msg$ = sprintf("Stop on your tracks, unfair being! Freeze!");
attachrid(.@rnd);
SC_Bonus((.@t / 2), any(SC_FREEZE, SC_SLEEP, SC_SLEEP, SC_SLEEP), 1);
detachrid();
.@mobid=(rand2(.@lv) > 50 ? BlueSlime : WhiteSlime);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 5:
.@msg$ = sprintf("There is no free speech. Censorship!");
attachrid(.@rnd);
SC_Bonus(.@t, SC_SILENCE, 1);
detachrid();
.@mobid=(rand2(.@lv) > 50 ? Thug : RedMushroom);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 6:
.@msg$ = sprintf("And then... There was a quake. And all life died. Bleed!");
attachrid(.@rnd);
SC_Bonus(.@t, SC_BLOODING, 1);
detachrid();
.@mobid=(rand2(.@lv) > 50 ? BlackSlime : OldSnake);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 7:
.@msg$ = sprintf("Puny mortal, do your best to entertain me! Curse!");
attachrid(.@rnd);
SC_Bonus(.@t, SC_CURSE, 1);
detachrid();
.@mobid=(rand2(.@lv) > 50 ? FireSkull : Skeleton);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 8:
.@msg$ = sprintf("The problem with typos is - unpredictable side effects.");
attachrid(.@rnd);
SC_Bonus(.@t, any(SC_SILENCE, SC_CURSE, SC_FREEZE, SC_BLOODING, SC_BLIND, SC_POISON, SC_DPOISON, SC_POISON, SC_BURNING, SC_SLEEP), 1);
detachrid();
.@mobid=(rand2(.@lv) > 50 ? Swashbuckler : Bluepar);
monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
break;
case 9:
// Second Attack Pattern: Holy Light (vs Tank)
.@msg$ = sprintf("%s, I'll show you no mercy! ##BThunder Bolt##b!", strcharinfo(0, "cursed player", .@mvp));
.@PW=125; .@SPW=25; .@RG=1;
.@mtk = calcdmg(.@mob, .@mvp, HARM_MAGI);
.@dmg = .@mtk * .@PW / 100;
.@dsb = .@mtk * .@SPW / 100;
sleep(1000);
specialeffect(FX_LIGHTNING, AREA, .@mvp);
areaharm(.@mvp, .@RG, .@dsb, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
harm(.@mvp, .@dmg, HARM_MAGI, Ele_Holy);
break;
default:
// First Attack Pattern: Napalm Beat (vs Random)
.@msg$ = sprintf("This battle is over, %s! ##BThunder Neddle##b!", strcharinfo(0, "cursed player", .@rnd));
.@PW=35; .@SPW=5; .@RG=2;
.@mtk = calcdmg(.@mob, .@rnd, HARM_MAGI);
.@dmg = .@mtk * .@PW / 100;
.@dsb = .@mtk * .@SPW / 100;
sleep(1000);
specialeffect(FX_LIGHTNING, AREA, .@rnd);
areaharm(.@rnd, .@RG, .@dsb, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
harm(.@rnd, .@dmg, HARM_MAGI, Ele_Holy);
break;
}
unittalk(.@mob, .@msg$);
}
// Always update the ratio - Terogan could have been healed
setd("$@GTEMP_HP_"+.@m$, .@ratio);
initnpctimer;
end;
// Monks Rewards
OnKillMob:
// Maybe a reward is due
.@g=getcharid(2);
if (.@g < 1) die();
getexp $KAMELOT_MX[.@g]*8, $KAMELOT_MX[.@g]*4; // Lower than previously
end;
// Boss rewards
OnKillBoss:
stopnpctimer;
if (playerattached()) {
// Setup
.@g=getcharid(2);
.@m$=getmap();
.@hero$=strcharinfo(0);
// Player Reward for completing this stage
getitem GuildCoin, 10;
getexp $KAMELOT_MX[.@g]*150, $KAMELOT_MX[.@g]*30;
specialeffect(FX_FANFARE, AREA, getcharid(3));
} else {
explode(.@map$, .map$, "@");
.@g=atoi(.@map$[1]);
if (.@g < 1) {
consolebug "[ERROR] [KAMELOT] Unable to find Terogan Death %s", .map$;
.@g=0;
}
.@m$=.map$;
.@hero$="The guild";
}
// Mark quest as completed
$KAMELOT_QUEST[.@g]=$KAMELOT_QUEST[.@g]|64;
// Get rid of temporary variables
setd("$@GTEMP_"+.@m$, 0);
setd("$@GTEMP_HP_"+.@m$, 0);
killmonsterall(.@m$);
// Guild Reward for completing this stage
.@ggp=2000+$KAMELOT_MX[.@g]*100;
.@gxp=$KAMELOT_MX[.@g]*250;
$GUILD_BANK[.@g]+=.@ggp;
guildgetexp(.@gxp); // Silently fails if no char attached
// Announce
mapannounce .@m$, .@hero$+" has defeated the evil in Kamelot!", 0;
// Spawn GMGiftBox upon end
.@gf=min(30, $KAMELOT_MX[.@g]/5);
areamonster(.@m$, 20, 20, 57, 40, strmobinfo(1, GMGiftBox), GMGiftBox, .@gf);
// Spawn Treasure Chests upon end
.@gl=$KAMELOT_MX[.@g];
.@gtype=(.@gl > 100 ? SupremeChest : (.@gl > 75 ? PrismChest : (.@gl > 50 ? GoldenChest : (.@gl > 25 ? SilverChest : BronzeChest))));
.@gf=$KAMELOT_PC[.@g];
areamonster(.@m$, 20, 20, 57, 40, strmobinfo(1, .@gtype), .@gtype, .@gf);
// Possibly, we forgot stuff in Throne Room...
killmonsterall("042-0@"+.@g);
// Guild Master Notification
.@gm$=getguildmaster(.@g);
if (!getcharid(3, .@gm$)) end;
.@gma=getcharid(3, .@gm$);
.@gmb=getcharid(0, .@gm$);
if (!isloggedin(.@gma, .@gmb)) end;
message .@gm$, strcharinfo(0)+" defeated the boss: Guild GP +"+.@ggp+" Guild XP +"+.@gxp;
end;
// Instance
OnInstanceInit:
end;
}