summaryrefslogtreecommitdiff
path: root/npc/functions/mkbot.txt
blob: 3074ade2be3f8df149f6fae81f52fd70b4a1f54b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// TMW-2 Script
// Author:
//  Jesusalva
// Description:
//  GM Bot for the Monster King.
// VARIABLES
//  $GAME_STORYLINE - Current Storyline status
//  $@MK - Monster King Game ID
//  $@MK_SCENE - Current event being handled by the Monster King
//  $MK_TEMPVAR - Temporary Variable
//  $@MK_THROTTLE - Event Throttler
//
// Storyline statuses:
//  0 - The Monster King is inactive (leading sieges to Hurnscald and Nivalis)
//  1 - The Monster King is known by players and is giving them a month break
//  2 - The Monster King is currently sieging towns at random
//  3 - The Monster King is preparing to perfom the Rite and Lightbringer seeks
//      a wielder
//  4 - The Rite is CONCLUDED. Players must walk to MK evil lair and fight.
//  5 - The Monster King is dead. Or something. Depends on players.
//
// $MK_TEMPVAR meaning depends on GAME STORYLINE
//  GS 0
//      Ignored
//  GS 1
//      Tracks the day since 1970 when the town was cleared. A month break.
//  GS 2
//      Player score (1pt per Lieutenant, 10pts per Colonel)
//      Affects the end of Game Story 2 and begin of Game Story 3
//      Because we must wait players...
//  GS 3
//      Number of successful Fortress Town breaches
//  GS 4
//      Inheirs stage 3

000-0,0,0,0	script	Monster King	NPC_HIDDEN,{
OnSlaveDie:
    end;
OnBourneAgain:
    // Reset aggro
    $@MK_AGGRO=0;
    if (playerattached()) {
        channelmes("#world", strcharinfo(0)+" did an act worth of notice.");
        dispbottom l("Oh well, this sucks, but that was only an illusion.");
        dispbottom l("The real Monster King is probably on his fortress. It'll take more than that to take him down.");
        if ($REBIRTH_WINNER$ == "" && TOP3AVERAGELVL() < 100)
            getexp min(641500, BaseLevel**3), 0;
        else
            Mobpt+=max(13500, rand2(10000, BaseLevel*90));
        Mobpt = Mobpt + 165;
        //$MOST_HEROIC$=strcharinfo(0);
    }
    // We need to start over
    .bar=true;
OnInit:
    $@MK=monster("boss", 45, 45, "The Monster King", MonsterKing, 1, "Monster King::OnBourneAgain");

    if (!.bar) {
        // Variables which other NPCs must take in account
        $@MK_AGGRO=0;
        $@MK_SCENE=0;
    } else {
        .bar=false;
    }

    // Variables only for this NPC
    .users=getusers(1);
    .nearby=getusers(8);
    .mp$="boss";
    .aid=200000;
    .cid=150002;
    // Constants

    // We should jump straight to loop (it runs every 90 seconds)
OnTimer90000:
    // Regenerate some data, and kill spurious mobs
    .users=getusers(1);
    if (mobcount(.mp$, "Monster King::OnSlaveDie")) {
        announce ("Monster King: Noobs, you are all a bunch of noobs!"), bc_map|bc_npc;
        killmonster(.mp$, "Monster King::OnSlaveDie");
    }

    // We are on an event, so skip this loop
    if ($@MK_SCENE || $@GM_EVENT) {
        initnpctimer;
        end;
    }

    // The Monster King is online. This loop is not needed
    if (isloggedin(.aid, .cid)) {
        if (!$@MK_SCENE)
            unitwarp($@MK, "boss", 45, 45);
        else
            rodex_sendmail(.cid, "MKBot", "Running Event", "An event is currently running by the MK Bot. Please logout and suppress it.");
        initnpctimer;
    }

    // Raise aggro (1 pt per 2 users)
    $@MK_AGGRO+=(.users/2);

    // Mana Stone
    if (.mp$ == "011-1")
        enablenpc "Mana Stone";

    // The Monster King will not move anymore because story
    if ($GAME_STORYLINE == 0 ||
        $GAME_STORYLINE >= 5) {
        if (.mp$ != "boss")
            unitwarp($@MK, "boss", 45, 45);
        initnpctimer;
        end;
    }

    // Select a random map. Never shows up at Candor and cities, nor indoors. Not all maps either.
    setarray .@m$,  "boss", "boss", "001-1", "001-3", "001-4", "001-5", "001-6", "001-7", "001-10",
                    "003-1", "003-1-3", "004-1", "004-2", "007-1", "009-1", "010-1", "010-1-1", "010-2", "011-1",
                    "012-1", "014-1", "014-2", "014-3", "014-4", "014-5", "015-1", "015-2", "015-3", "015-5",
                    "018-1-1", "018-2", "018-3", "018-4", "018-4-1",
                    "019-1", "019-2", "019-4", "020-1", "021-1", "022-1", "023-1";
    .mp$=any_of(.@m$);

    // Try to warp randomly, up to 30 attempts
    .@e=0; .@x=0; .@y=0;
    .@mx=getmapinfo(MAPINFO_SIZE_X, .mp$)-20;
    .@my=getmapinfo(MAPINFO_SIZE_Y, .mp$)-20;
    do {
        if (.@e >= 30) {
            .mp$="boss";
            .@x=45;
            .@y=45;
            break;
        }
        .@x = rand2(20, .@mx);
        .@y = rand2(20, .@my);
        .@e+=1;
    } while (!checknpccell(.mp$, .@x, .@y, cell_chkpass));
    if (!checknpccell(.mp$, .@x, .@y, cell_chkpass)) {
        Exception("mk.bot runtime error: GM_ERR_128 highlight @Jesusalva", RB_DEBUGMES|RB_IRCBROADCAST); .mp$="boss"; .@x=45; .@y=45;
    }

    // Monster King will not warp around for sightseeing if he is threatened
    if ($GAME_STORYLINE > 2 && $@MK_AGGRO < 250) {
        .mp$="boss";.@x=45;.@y=45;
    }

    unitwarp($@MK, .mp$, .@x, .@y);
    sleep(50); // For some reason or other, adding sleep(norid) and sleep2(rid).
    .nearby=getusers(8);

    // Handle Mana Stone
    if (.mp$ == "011-1")
        disablenpc "Mana Stone";

    // Debug markers
    if ($@GM_OVERRIDE)
        debugmes "Monster King (bot): "+.mp$+" ("+.@x+", "+.@y+")";

    // If too few players are online, we don't need an event AT ALL!
    if (.users < rand2(2,4)) {
        initnpctimer;
        end;
    }

    // Siege events (req. 700 aggro, 3 users, and 75% chances to begin)
    if ($@MK_AGGRO >= ($GAME_STORYLINE == 2 ? 700 : 2100) && .users >= 3 && rand2(0,100) < 75 &&
        is_between(1, 4, $GAME_STORYLINE) && $@MK_THROTTLE < gettimetick(2)){
        // Delta handles the compulsory wait time between waves.
        // 7 hours normally, 24 hours if the army is in disarray.
        .@delta=7;
        $@SIEGE_ABORTED = false;
        if ($GAME_STORYLINE >= 3)
            .@delta=24;
        // Tulimshar
        if (compare(.mp$, "003-")) {
            announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc;
            $@MK_THROTTLE=gettimetick(2)+.@delta*60*60;
            $@MK_SCENE=MK_SIEGE_TULIM;
            donpcevent("Lieutenant Dausen::OnMKSiege");
        }
        // Halinarzo
        else if (compare(.mp$, "009-")) {
            announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc;
            $@MK_THROTTLE=gettimetick(2)+.@delta*60*60;
            $@MK_SCENE=MK_SIEGE_HALIN;
            donpcevent("Lieutenant Jacob::OnMKSiege");
        }
        // Hurnscald
        else if (compare(.mp$, "012-")) {
            announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc;
            $@MK_THROTTLE=gettimetick(2)+.@delta*60*60;
            $@MK_SCENE=MK_SIEGE_HURNS;
            donpcevent("#HurnscaldSiege::OnMKSiege");
        }
        // Nivalis
        else if (compare(.mp$, "020-")) {
            announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc;
            $@MK_THROTTLE=gettimetick(2)+.@delta*60*60;
            $@MK_SCENE=MK_SIEGE_NIVAL;
            donpcevent("Lieutenant Joshua::OnMKSiege");
        }
    }

    // If a player is nearby while the Monster King prepares, event may happen
    // Minimum 90 Aggro
    if (.nearby > 1 && $@MK_AGGRO >= 90 &&
        ($GAME_STORYLINE == 1 || ($GAME_STORYLINE >= 3 && $@MK_THROTTLE >= gettimetick(2)) )){
        // We should decide event kind, but that's NYI
        announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc;

        getmapxy(.@m$, .@x, .@y, UNITTYPE_MOB, $@MK);

        // Spawn stuff
        areamonster(.@m$, .@x-20, .@y-20, .@x+20, .@y+20, "Monster", ManaGhost, max(60, ($@MK_AGGRO/20))+.nearby, "Monster King::OnSlaveDie");
        //$@MK_AGGRO=($@MK_AGGRO*$GAME_STORYLINE)/5;
        $@MK_AGGRO-=rand2(30, 80); // Reduce aggro, but do not deplete it
    }

    // Maybe, just maybe, game storyline must be updated here
    if ($GAME_STORYLINE == 1 && $MK_TEMPVAR &&
        $MK_TEMPVAR <= gettimeparam(GETTIME_DAYOFMONTH)) {
        // Game Story Change: Idle MK -> Active MK
        kamibroadcast("I can't handle it anymore! NO MORE!", "Monster King");
        sleep(2500);
        kamibroadcast("Come, my minions! Lay siege to towns! LEAVE NO OPPOSITION TO ME!", "Monster King");
        sleep(2500);
        kamibroadcast("Burn, destroy, do whatever you need, until your last breath, my lieutenants and colonels!", "Monster King");
        sleep(2500);
        kamibroadcast("##4 .:: Game Story Instructions on #world ::.");
        channelmes("#world", "##1 **GAME STORY CHANGE** - The Monster King minions will now attack cities and lay waste to them.");
        channelmes("#world", "##1 Players must defeat the lieutenants and colonels in order to prevent sieges from continuing.");

        // Apply the changes
        $GAME_STORYLINE=2;
        $MK_TEMPVAR=0;
    }
    if ($GAME_STORYLINE == 2 &&
        $MK_TEMPVAR >= MK_SIEGE_TOTALPOWER) {
        kamibroadcast("##1##BThe Monster King army is in total disarray and disorder!", "Saulc");
        sleep(2500);
        kamibroadcast("##1##BIt's our chance to strike back!", "Saulc");
        sleep(2500);

        // Apply the changes
        $GAME_STORYLINE=3;
        $MK_TEMPVAR=0; // In past, we forced 1 month wait. Now we have KW mechs...
        $MANA_BLVL-=10; // Set level to 20~30
        $MANA_JLVL-=5; // Set job level to 15
    }

    // We're done, restart loop timer
    initnpctimer;
    end;
}

// MKAggro(mobID) → Monster King aggro
function	script	MKAggro	{
    // Every 30 levels gives +1 to monster king aggro
    // Monsters below level 30 do not generate aggro
    .@aggro=getarg(0, killedrid);
    .@moblv=strmobinfo(3,.@aggro);
    .@aggro=min(5, .@moblv / 30);

    // Cycles of 30 seconds
    if (@mkaggra+30 > gettimetick(2)) {
        .@aggro -= @mkaggrb;
        if (.@aggro <= 0)
            return;
    } else {
        @mkaggrb=0;
    }
    // Increase monster king aggro and update ticks
    $@MK_AGGRO += .@aggro;
    @mkaggra=gettimetick(2);
    @mkaggrb=.@aggro + @mkaggrb;
    return;
}