// TMW2 scripts.
// Authors:
// Jesusalva
// Description:
// Town Siege utilities
// Siege Spawn
// Can be used anywhere to spawn on the whole map, margins respected.
// siege_spawn( map, mobID, Amount, eventID )
function script siege_spawn {
.@mp$=getarg(0);
.@mid=getarg(1);
.@qnt=getarg(2);
.@ev$=getarg(3);
areamonster(.@mp$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@mp$)-20, getmapinfo(MAPINFO_SIZE_Y, .@mp$)-20, strmobinfo(1, .@mid), .@mid, .@qnt, .@ev$);
return;
}
// Calculate player average level
// if highest is set, it will return highest player level, with minimum the value
// passed. (A level "0" is clearly not valid, of course)
// siege_calcdiff ( map{, highest_lvl} )
function script siege_calcdiff {
.@bsum=0;
.@highest=getarg(1, false);
.@c = getunits(BL_PC, .@players, false, getarg(0));
.@skip=0;
// There is at least one player, do things properly
for (.@i = 0; .@i < .@c; .@i++) {
/*
// Dead players are not counted
if (ispcdead(strcharinfo(0, "", .@players[.@i])))
continue;
*/
.@b=readparam(BaseLevel, .@players[.@i]);
// GMs are not counted
if (getgroupid(.@players[.@i]) >= 60) {
.@skip+=1;
.@b=0;
}
.@bsum+=.@b;
if (.@b > .@highest)
.@highest=.@b;
}
// Sanitize and fallback if needed
.@c-=.@skip;
if (!.@c)
.@c=1;
//debugmes "calcdiff: Total %d Average %d Highest %d", .@bsum, (.@bsum/.@c), .@highest;
if (getarg(1,false))
return .@highest;
else
return (.@bsum/.@c);
}
// push to $@SIEGE_TMPMOBS the <mobID> if their level is within a x levels range
// above or below <level>
// siege_push ( mobID, {level{, variation}} )
function script siege_push {
.@mi=getarg(0);
.@lv=getarg(1,0);
.@var=getarg(2,10); // Old Default: 15
if ( is_between(.@lv-.@var, .@lv+(.@var/2), strmobinfo(3, .@mi)) ) {
//debugmes "Monster %s (%d) level %d ~= %d", strmobinfo(1, .@mi), .@mi, strmobinfo(3, .@mi), .@lv;
array_push($@SIEGE_TMPMOBS, .@mi);
}
return;
}
// Selects a monster based on player average strength and base difficulty
// It'll select monsters from 20 levels below to 20 levels above
// tp_mask is the same as TP_* constants and changes mobs present. Only TP_TULIM,
// TP_HURNS and TP_NIVAL are supported. You can use them with the "|" operand, eg.,
// TP_TULIM | TP_HURNS.
//
// It currently only creates $@SIEGE_TMPMOBS, you need to use any_of() manually.
// siege_selectmob ( blvl, difficulty{, tp_mask} )
function script siege_selectmob {
.@blv=getarg(0);
.@dif=getarg(1, 0);
.@tp=getarg(2, 0);
// We don't need .@dif, so we convert difficulty to levels
.@blv+=.@dif;
deletearray $@SIEGE_TMPMOBS;
setarray $@SIEGE_TMPMOBS, ManaGhost, CandiedSlime, Bif, SlimeBlast;
// Now we must select mobs, using array_push() to $@SIEGE_TMPMOBS
// First, mobs on all envs
siege_push(BlackScorpion, .@blv);
siege_push(GreenSlime, .@blv);
siege_push(CaveMaggot, .@blv);
siege_push(MagicGoblin, .@blv);
siege_push(AngryBat, .@blv);
siege_push(BlackSlime, .@blv);
siege_push(BlackScorpion, .@blv);
siege_push(Forain, .@blv);
siege_push(Terranite, .@blv);
siege_push(JackO, .@blv);
siege_push(BlackMamba, .@blv);
siege_push(TerraniteProtector, .@blv);
siege_push(Reaper, .@blv);
// What if we are trying to select a boss and they're... overleveled?
// We need a level 105, 120 and a level 135 monsters
siege_push(FallenKing2, .@blv);
siege_push(TerraniteKing, .@blv);
// Now, mobs on only certain envs
if (.@tp & TP_TULIM) {
siege_push(AngryScorpion, .@blv);
siege_push(AngryRedScorpion, .@blv);
siege_push(DesertBandit, .@blv);
siege_push(LavaSlime, .@blv);
siege_push(OldSnake, .@blv);
siege_push(Snake, .@blv);
}
if (.@tp & TP_HURNS) {
siege_push(RedSlime, .@blv);
siege_push(Bandit, .@blv);
siege_push(RedMushroom, .@blv);
siege_push(RobinBandit, .@blv);
siege_push(AngryYellowSlime, .@blv);
siege_push(GrassSnake, .@blv);
siege_push(WickedMushroom, .@blv);
siege_push(GreenDragon, .@blv);
}
if (.@tp & TP_NIVAL) {
siege_push(Bluepar, .@blv);
siege_push(Wolvern, .@blv);
siege_push(Yeti, .@blv);
siege_push(Moggun, .@blv); // PS. Not aggressive
}
// Removed
//siege_push(DarkLizard, .@blv);
//siege_push(Crafty, .@blv);
return;
}
/////////////////////////////////////////////////////////////
// Prepare a siege with optional announce
// siege_setup ( map )
function script siege_setup {
.@m$=getarg(0);
// Save old map zone
$@MZONE$[getmapinfo(MAPINFO_ID, .@m$)]=getmapinfo(MAPINFO_ZONE, .@m$);
// Apply changes
addmapmask .@m$, MASK_MATTACK;
changemusic .@m$, any("mythica.ogg", "eric_matyas_ghouls.ogg", "misuse.ogg", "Arabesque.ogg");
disablenpc("Mana Stone");
pvpon(.@m$);
setmapflag(.@m$,mf_zone,"MMO"); // MMO Zone: Overrides GM Commands
setmapflag(.@m$,mf_bexp,rand(120,140)); // 20~40% EXP UP on siege maps
return;
}
// Revert what siege_setup did
// siege_revert ( map )
function script siege_revert {
.@m$=getarg(0);
// Revert map zone (to town, or to blank) and delete backup
removemapflag(.@m$,mf_zone);
setmapflag(.@m$,mf_zone,$@MZONE$[getmapinfo(MAPINFO_ID, .@m$)]);
$@MZONE$[getmapinfo(MAPINFO_ID, .@m$)]="";
removemapmask .@m$, MASK_MATTACK;
changemusic .@m$, "caketown.ogg"; // :>
enablenpc("Mana Stone");
pvpoff(.@m$);
removemapflag(.@m$,mf_bexp);
setmapflag(.@m$,mf_bexp,100);
killmonsterall(.@m$);
return;
}
// Create the Siege Boss for #SiegeCtrl utility, DO NEVER CAST TWICE
// siege_boss ( map, difficulty )
function script siege_boss {
.@m$=getarg(0);
.@s=getarg(1,0);
// If Difficulty is 0: There is no boss
if (!.@s)
return;
// We will now prepare the boss
// It must be stronger than players in at least 15 levels, so the mob group
// is different. The siege difficulty, as usual, gives an extra level to them.
.@val=siege_calcdiff(.@m$)+15;
.@val+=.@s;
// We must cap this at 100 to prevent running out of monsters
// Also, .@val can NEVER be less than 50, to prevent cheating :<
if (.@val > 100)
.@val=100;
else if (.@val < 50)
.@val=50;
// Get their event/designation
if (.@val >= 80)
.@ts$="Colonel";
else
.@ts$="Lieutenant";
// Select a type for them (saved as .@mobId)
siege_selectmob(siege_calcdiff(.@m$, .@val), .@s);
array_remove($@SIEGE_TMPMOBS, Bif);
array_remove($@SIEGE_TMPMOBS, CandiedSlime);
array_remove($@SIEGE_TMPMOBS, ManaGhost);
array_remove($@SIEGE_TMPMOBS, SlimeBlast);
if (array_entries($@SIEGE_TMPMOBS) > 0) {
.@mobId=any_of($@SIEGE_TMPMOBS);
} else {
.@mobId=Yetifly;
Exception("[WARNING] Insufficient monsters in database: Highlight @jesusalva - Broken reference: "+siege_calcdiff(.@m$, .@val), RB_DEBUGMES|RB_IRCBROADCAST);
}
// We want spawn point to be fixed
.@lx=array_find($@LOCMASTER_MAP$, .@m$);
.@xm=$@LOCMASTER_X[.@lx];
.@ym=$@LOCMASTER_Y[.@lx];
// Announce and spawn
areamonster(.@m$, .@xm-1, .@ym-1, .@xm+1, .@ym+1, .@ts$+" "+strmobinfo(1, .@mobId), .@mobId, 1, "#SiegeCtrl::On"+.@ts$+"Death");
// Spawn some scouts
areamonster(.@m$, .@xm-1, .@ym-1, .@xm+1, .@ym+1, "Scout", any(GreenSlime,RedSlime,AngryYellowSlime), 3);
announce("##1The Monster "+.@ts$+" arrived! It is a "+strmobinfo(1, .@mobId), bc_all);
return;
}
// Spawn some monsters
// siege_cast ( map, NPCName, {, difficulty{, tpflag}} )
function script siege_cast {
// mz - map ; n - name ; d - difficulty ; tp - teleport
// a - ammount ; e - mobId
.@mz$=getarg(0);
.@n$=getarg(1);
.@d=getarg(2,0);
.@tp=getarg(3,0);
siege_selectmob(siege_calcdiff(.@mz$), .@d, .@tp);
// How many monsters? This value is multiplied by 3;
// 1 per player (= 3 mobs), 1 each 5 difficulty, 1 always present.
.@a=getmapusers(.@mz$);
.@a=(.@d/5)+1;
.@e=any_of($@SIEGE_TMPMOBS);
array_remove($@SIEGE_TMPMOBS, .@e);
siege_spawn(.@mz$, .@e, .@a, "#SiegeCtrl::OnRespawn");
.@e=any_of($@SIEGE_TMPMOBS);
array_remove($@SIEGE_TMPMOBS, .@e);
siege_spawn(.@mz$, .@e, .@a, "#SiegeCtrl::OnRespawn");
.@e=any_of($@SIEGE_TMPMOBS);
array_remove($@SIEGE_TMPMOBS, .@e);
siege_spawn(.@mz$, .@e, .@a, "#SiegeCtrl::OnRespawn");
return;
}
// Utility NPC
- script #SiegeCtrl NPC_HIDDEN,{
end;
OnRespawn:
if (playerattached()) {
getmapxy(.@m$,.@x,.@y,0);
if (rand(10000) <= $coinsrate)
makeitem StrangeCoin, 1, .@m$, .@x, .@y;
}
end;
// Boss Death Labels
OnLieutenantDeath:
$MK_TEMPVAR+=1;
getitem StrangeCoin, 1;
mapannounce(getmap(), l("##2The Monster Lieutenant was defeated by @@!", strcharinfo(0)), bc_map);
end;
OnColonelDeath:
$MK_TEMPVAR+=10;
getitem StrangeCoin, rand(5,10);
$MOST_HEROIC$=strcharinfo(0);
mapannounce(getmap(), l("##2The Monster Colonel was defeated by @@!", strcharinfo(0)), bc_map);
end;
}