// 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)); // Fallback: No players on map, always return 0 if (.@c == 0) return 0; // There is at least one player, do things properly for (.@i = 0; .@i < .@c; .@i++) { .@b=readparam(BaseLevel, .@players[.@i]); .@bsum+=.@b; if (.@b > .@highest) .@highest=.@b; } //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 if their level is within a x levels range // above or below // 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); 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_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); removemapmask .@m$, MASK_MATTACK; changemusic .@m$, "caketown.ogg"; // :> enablenpc("Mana Stone"); pvpoff(.@m$); removemapflag(.@m$,mf_bexp); 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("ERROR, TOO FEW MOBS ON DATABASE, whaaaaaaat", RB_DEBUGMES|RB_IRCBROADCAST); } // Announce and spawn siege_spawn(.@m$, .@mobId, 1, "#SiegeCtrl::On"+.@ts$+"Death"); 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? .@a=(.@d/3)+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: getitem StrangeCoin, 1; mapannounce(getmap(), l("##2The Monster Lieutenant was defeated by @@!", strcharinfo(0)), bc_map); $MK_TEMPVAR+=1; end; OnColonelDeath: getitem StrangeCoin, 5; $MOST_HEROIC$=strcharinfo(0); mapannounce(getmap(), l("##2The Monster Colonel was defeated by @@!", strcharinfo(0)), bc_map); $MK_TEMPVAR+=10; end; }