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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
|
// GateBuilders toolkit aka "arbitrary teleports".
// Author: Hello=). Credits go to Freeyorp and HoraK for some insights.
// This lacks limits of previously existing teleport systems.
// * New teleports can be instatiated as needed, running side by side.
// * Teleports can have finite lifetime, disappearing themself.
// * Teleports can be removed, leaving no side effects.
// * No leftovers or side effects after teleport removed.
// * Up to about 100 teleports can coexist.
// * Flexible condition check based on cookie. If some gate got cookie set
// then it only lets players with matching variable to pass.
// * Aspects like timeout, FX and their timing, etc can be customized.
// * Teleports meant to be registered in TeleportManager. However, its
// possible to create "unmanaged" teleports (e.g. for spells).
// * In future it can allow custom hooks/checks on teleporters (planned)
// Technically, TeleportManager NPC keeps teleports as array of integers.
// with structure .teleports[.index] = Teleport's NPC ID.
// Up to 100 teleports allowed (.index = 1..100, .index = 0 is unused).
// if .teleports[.index] = 0 -> empty/reusable slot.
// All teleport specific data stored in puppet NPC itself.
// Teleport NPCs are puppets of TeleportManager and inherit its code.
// Attempt will be made to make it reasonably robust. That is,
// * Try to handle usage bugs/bogus data/etc.
// * No actions causing big server side fallouts.
// * No out of bounds, nonexistent NPC references, etc.
// Teleports have the following variables (some are set on teleport_create)
// .srcmap$ - source map of teleport's npc
// .src_x - source map of teleport's npc, X coord
// .src_y - source map of teleport's npc, Y coord
// .dstmap$ - destination map of teleport's npc
// .dst_x - destination map of teleport's npc, X coord
// .dst_y - destination map of teleport's npc, Y coord
// .lifetime - teleport's lifetime, in ms. 0 = permanent (until server restart)
// .cookie - if set, only teleport players with teleport_cookie == NPC's .cookie
// .fx, - FX effect to play on teleport.
// .fx_time, - Time FX allowed to play before teleport actually happens.
// .IS_MANAGER - Indicates TeleportManager NPC. Puppets wouldnst have that.
// .managed - Indicates its teleport managed by TeleportManager. Its possible to
// create unmanaged teleports, e.g. transient teleports by spells.
// .teleport - Set to 1 to be able to distinguish teleport NPCs from other NPCs
// .info$ - Description, shown to user when clicking NPC
// .inactive - set to disable OnTouch reaction. Useful for staged shutdown or
// e.g. temporarily deactivating teleport for whatever reason.
// Key functcions: teleport_add and teleport_del. Rest are "helpers".
// Main NPC code, runs on both TeleportManager and teleport puppets.
// Do not rename NPC: functions below rely on NPC name.
-|script|TeleportManager|32767
{
message strcharinfo(0), .info$; // Display info about teleport, var allows message change.
end;
// Manager code below - puppets dont use OnCmd* events
// Invoked when someone adds teleport via @teleportadd
OnCmdAdd:
if (call("teleport_access_check")) end; // Not allowed to use this.
set .@idx, call("teleport_find_slot", 0); // Try to find empty slot (containing 0)
if (.@idx <= 0) goto L_AddNoRoom; // No empty slots? NB: teleports[0] not used.
if (call ("teleportadd_parseargs") <= 0) goto L_AddArgsFail; // @VARs like @POS_X, @NAME$, etc set by teleportadd_parseargs()
// Create actual teleport NPC ------- src map - src x src y --- name - NPC ---- Sz Sz dst map - dst x - dst y -- time - cook managed?
set .@tp, call("teleport_create", getmap(), @POS_X, @POS_Y, @NAME$, @NPCSPRITE, 0, 0, @DSTMAP$, @DST_X, @DST_Y, @TIMEOUT, 0, 1);
if (.@tp <= 0) goto L_AddPuppetFail; // Has puppet() failed?
set .teleports[.@idx], .@tp; // Store NPC ID -> .teleports[.@idx] slot. Access safe: teleport_find_slot() == 1..100
gmlog strcharinfo(0) + " accessed TeleportManager: @teleportadd " + @args$;
wgm strcharinfo(0) + " accessed TeleportManager: @teleportadd " + @args$;
message strcharinfo(0), "[TeleportManager] : Added: [" + .@idx + "] " +
(get(.srcmap$, .@tp)) + " " + (get(.src_x, .@tp)) + "," + (get(.src_y, .@tp)) +
" -> " + (get(.dstmap$, .@tp)) + " " + (get(.dst_x, .@tp)) + "," + (get(.dst_y, .@tp)) +
" lifetime:" + ((get(.lifetime, .@tp)) / 1000) + "s, Name:" + strnpcinfo(0, .@tp) + " (" + .@tp + ")";
end;
L_AddNoRoom:
message strcharinfo(0), "[TeleportManager] : Too many teleports open, max 100 tracked teleports";
message strcharinfo(0), "[TeleportManager] : use @teleportlist to list and @teleportdel to remove some.";
end;
L_AddArgsFail:
if (@DSTMAP$ != "help") message strcharinfo(0), "[TeleportManager] : try @teleportadd help or @teleporthelp";
end;
L_AddPuppetFail:
message strcharinfo(0), "[TeleportManager] : failed to add teleport, check params. Duplicate NPC name maybe?";
end;
// Invoked when someone removes teleport via @teleportdel
OnCmdDel:
if (call("teleport_access_check")) end; // Not allowed to use this.
callfunc "argv_splitter";
if (@argv[0] <= 0) goto L_DelFail;
if (call("teleport_delete", @argv[0]) <= 0) goto L_DelNotFound;
message strcharinfo(0), "[TeleportManager] : requested teleport ID [" + @argv[0] + "] to terminate";
gmlog strcharinfo(0) + " accessed TeleportManager: @teleportdel " + @args$;
wgm strcharinfo(0) + " accessed TeleportManager: @teleportdel " + @args$;
end;
L_DelNotFound:
message strcharinfo(0), "[TeleportManager] : teleport ID [" + @argv[0] + "] not found.";
end;
L_DelFail:
message strcharinfo(0), "[TeleportManager] : Bad parameters.";
callfunc("teleport_help_del");
end;
// Invoked when someone lists teleports via @teleportlist
OnCmdList:
if (call("teleport_access_check")) end; // Not allowed to use this.
callfunc("teleports_list");
gmlog strcharinfo(0) + " accessed TeleportManager: @teleporlist" + @args$;
end;
// Invoked when someone requests help via @teleporthelp
// (doesn't needs access checks - does nothing dangerous)
OnCmdHelp:
message strcharinfo(0), "[TeleportManager] : Commands: @teleportadd @teleportdel @teleportlist @teleporthelp";
message strcharinfo(0), "[TeleportManager] : @teleportlist - display list of active teleports";
callfunc("teleport_help_del");
callfunc("teleport_help_add");
end;
// Puppets (teleportation pads) logic below.
// Invoked when player steps on npc. Manager NPC ignores this.
OnTouch:
if (.IS_MANAGER) end; // Manager NPC isnt teleport -> no interaction.
if (.inactive) end; // If gate deactivated -> no interaction.
if ((.cookie) && (teleport_cookie != .cookie)) goto L_CantPass;
set teleport_cookie, 0; // Clear teleport cookie of player on teleport use.
sc_start SC_SLOWMOVE, .fx_time+200, 100000; // Slow player temporarily to avoid movement VS warp DCs
addtimer .fx_time, strnpcinfo(0)+"::OnTeleport"; // time before teleporting away
misceffect .fx; // Default .fx set in teleport_add, other code can override it.
end;
L_CantPass:
message strcharinfo(0), .cantpass$; // NPC var allows to change message.
end; // "keyed" teleport and player didnt had proper cookie.
// Teleportation timer event (attached to player). Queued by OnTouch.
OnTeleport:
warp .dstmap$, .dst_x, .dst_y;
addtimer 3000, strnpcinfo(0)+"::OnWarpDone"; // Mostly to clean up SC icon
end;
// Mostly used to remove slow icon that sticks in some cases.
OnWarpDone:
sc_end SC_SLOWMOVE;
end;
// Invoked on timed teleport's NPC timer expired.
OnTeleportExpired:
set .inactive, 1; // Flag shutdown so OnTouch ignores incoming players.
addnpctimer (.fx_time + 1000), strnpcinfo(0)+"::OnTeleportShutdown"; // Give time to in-flight players to teleport.
end;
// Does actual teleport shutdown.
OnTeleportShutdown:
void call("teleport_mgr_clean"); // Cleanups adequately both "managed" and "unmanaged" teleports.
if !(.IS_MANAGER) destroy; // Dont ever try to destroy manager npc.
end;
OnInit:
set .IS_MANAGER, 1; // Only Manager NPC would have this, puppets wouldnt.
set .info$, "TeleportManager : This thing is unlike anything you've seen before"; // Manager's NPC message on click.
registercmd "@teleportadd", "TeleportManager::OnCmdAdd";
registercmd "@teleportdel", "TeleportManager::OnCmdDel";
registercmd "@teleportlist", "TeleportManager::OnCmdList";
registercmd "@teleporthelp", "TeleportManager::OnCmdHelp";
registercmd "@teleport", "TeleportManager::OnCmdHelp";
end;
}
// PUBLIC API. Creates requested teleport NPC. Arg 0..6 are like puppet().
// This function designed to run in ANY context, whether RID attached or not.
// It creates puppet + setups all relevant data in created NPC.
// arg(0): Teleport's map.
// arg(1): Teleport's X
// arg(2): Teleport's Y
// arg(3): Teleport's NPC label
// arg(4): Teleport's NPC sprite ID
// arg(5): Teleport's X size
// arg(6): Teleport's Y size
// arg(7): Destination map name.
// arg(8): Destination X
// arg(9): Destination Y
// arg(10):Teleport lifetime ( > 0 or -1 = indefinite)
// arg(11):Teleport magic cookie, 0 = everyone allowed, otherwise checks match.
// arg(12):Whether teleport managed, 0 = unmanaged, != 0 means it is.
// Return: On success: NPC ID of teleport created.
// On failure: 0 if puppet failed, -1 if arg check failed.
function|script|teleport_create
{
set .@map$, getarg(0, ""); // Get args (+failsafe defailts)
set .@x, getarg(1, -10); // Get args (+failsafe defailts)
set .@y, getarg(2, -10); // Get args (+failsafe defailts)
set .@name$, getarg(3, ""); // Get args (+failsafe defailts)
set .@sprite, getarg(4, -10); // Get args (+failsafe defailts)
set .@xsz, getarg(5, -10); // Get args (+failsafe defailts)
set .@ysz, getarg(6, -10); // Get args (+failsafe defailts)
set .@dstmap$, getarg(7, -10); // Get args (+failsafe defailts)
set .@dst_x, getarg(8, -10); // Get args (+failsafe defailts)
set .@dst_y, getarg(9, -10); // Get args (+failsafe defailts)
set .@lifetime, getarg(10, -10); // Get args (+failsafe defailts)
set .@cookie, getarg(11, -10); // Get args (+failsafe defailts)
set .@managed, getarg(12, -10); // Get args (+failsafe defailts)
set .@res, -1; // Validate what caller gave
if !(call("teleport_map_valid", .@map$ )) goto L_Fail; // Validate src map$
if !(call("teleport_map_valid", .@dstmap$)) goto L_Fail; // Validate dst map$
if ((.@x < 0) || (.@y < 0)) goto L_Fail; // SRC X/Y cant be < 0
if ((.@dst_x < 0) || (.@dst_y < 0)) goto L_Fail; // DST X/Y cant be < 0
if ((.@xsz < 0) || (.@ysz < 0)) goto L_Fail; // NPC X/Y size cant be <= 0
if (.@name$ == "") goto L_Fail; // NPC name cant be empty
if (.@sprite <= 0) goto L_Fail; // NPC sprite cant be <= 0
if (.@lifetime < -1 || (.@lifetime) == 0) goto L_Fail; // Lifetime either > 0 or -1 = infinite
if ((.@cookie < 0) || (.@managed < 0)) goto L_Fail; // Cookie and managed cant be < 0
set .@res, puppet(.@map$, .@x, .@y, .@name$, .@sprite, .@xsz, .@ysz); // instatiate teleport NPC
if (.@res <= 0) goto L_Fail;
//NPC's var value NPC ID -- teleport defaults
set .srcmap$, .@map$, .@res; // set .srcmap$ of NPC
set .src_x, .@x, .@res; // set .src_x of NPC
set .src_y, .@y, .@res; // set .src_y of NPC
set .dstmap$, .@dstmap$, .@res; // set .dstmap$ of NPC
set .dst_x, .@dst_x, .@res; // set .dst_x of NPC
set .dst_y, .@dst_y, .@res; // set .dst_y of NPC
set .lifetime, .@lifetime, .@res; // set .lifetime of NPC
set .cookie, .@cookie, .@res; // set .cookie of NPC
set .fx, 41, .@res; // set default teleport FX
set .fx_time, 350, .@res; // set default FX time (warp delay)
set .managed, .@managed, .@res; // If > 0, npc managed by TeleportManager (unmanaged temp TPs can be e.g. spells)
set .teleport, 1, .@res; // All teleports created by teleport_create have this.
set .info$, "Teleport : strange structure of unknown origins", .@res; // Default on-click message.
set .cantpass$, "Teleport : structure seems to ignore you", .@res; // Default "can't pass" message.
// If timeout requested, set up teardown timer.
if (.@lifetime > 0) addnpctimer .@lifetime, .@name$+"::OnTeleportExpired";
return .@res;
L_Fail:
return .@res;
}
// PUBLIC API. This function deletes teleport.
// This function designed to run in ANY context, whether RID attached or not.
// Teleport removed by NPC destroy + setting its .teleports[.index] = 0.
// Inputs: arg[0] is either slot index (1..100) or NPC ID to remove.
// Return: 1 on success, <= 0 on failure.
function|script|teleport_delete
{
set .@npctodel, getarg(0, -1); // This is either slot # or NPC ID
if (.@npctodel <= 0) goto L_Error;
if (.@npctodel > 100) goto L_GotNpcId; // If > 100 assume its NPC ID, not slot.
set .@npctodel, call("teleport_get_slot_val", .@npctodel); // Get NPC id from teleport manager slot.
if (.@npctodel <= 0) goto L_Error; // Failed to get NPC ID?
goto L_GotNpcId;
L_GotNpcId:
if !(get(.teleport, .@npctodel)) goto L_Error; // Sanity check its teleport NPC indeed
donpcevent strnpcinfo(0, .@npctodel)+"::OnTeleportShutdown"; // Request teleport NPC to perform shutdown.
return 1;
L_Error:
return 0;
}
// This function prints teleports known to TeleportManager.
// This function MUST run in player context with RID attached to send messages.
// Inputs: nothing, all data taken from TeleportManager NPC.
// Return: nothing, just prints info as it iterates manager's slots.
function|script|teleports_list
{
set .@idx, 0;
freeloop 1; // Loops via 100 slots -> can time out.
message strcharinfo(0), "[TeleportManager] : ---- Active teleports ----";
goto L_NextSlot;
L_NextSlot:
set .@idx, (.@idx+1);
if (.@idx > 100) goto L_Done; // Iterated whole array.
set .@npc, call("teleport_get_slot_val", .@idx);
if (.@npc < 0) goto L_Error; // Abort iteration on error and report it.
if (.@npc > 0) goto L_PrintSlot; // Print slot data.
goto L_NextSlot; // .@npc == 0 // just iterate to next slot
L_PrintSlot:
if !(get(.managed, .@npc)) goto L_Error; // Sanity check its really "managed teleport" NPC
// Display info about teleport, data taken from NPC.
message strcharinfo(0), "[TeleportManager] : [" + .@idx + "] " +
(get(.srcmap$, .@npc)) + " " + (get(.src_x, .@npc)) + "," + (get(.src_y, .@npc)) +
" -> " + (get(.dstmap$, .@npc)) + " " + (get(.dst_x, .@npc)) + "," + (get(.dst_y, .@npc)) +
" lifetime:" + ((get(.lifetime, .@npc)) / 1000) + "s, Name:" + strnpcinfo(0, .@npc) + " (" + .@npc + ")";
goto L_NextSlot;
L_Done:
freeloop 0;
message strcharinfo(0), "[TeleportManager] : ---- End ----";
return;
L_Error:
freeloop 0;
message strcharinfo(0), "[TeleportManager] : Error iterating TeleportManager slots (bug?!)";
return;
}
// This function finds slot in TeleportManager with given NPC ID.
// This function designed to run in ANY context, whether RID attached or not.
// Inputs: arg[0]: NPC ID to find, 0 means "find free slot",
// Return: slot index in 1..100 range if slot found, <= 0 on fail.
function|script|teleport_find_slot
{
if (getarg(0) < 0) goto L_Fail; // Caller gave some crap?
set .@wanted, getarg(0); // NPC ID to find (or 0 to find free slot)
set .@manager, getnpcid("TeleportManager");
if (.@manager <= 0) goto L_Fail; // Manager NPC not found?
set .@i, 1; // 0 slot not used.
freeloop 1;
goto L_TrySlot; // Start iterating via teleport slots on TeleportManager.
L_TrySlot:
set .@npcid, get(.teleports[.@i], .@manager);
if (.@npcid == .@wanted) goto L_Found; //.teleports[.@i] == desired ID?
if (.@i > 100) goto L_Fail; // No free slots in teleports[1..100]
set .@i, (.@i + 1); goto L_TrySlot; // Try next slot
L_Found:
freeloop 0;
return .@i;
L_Fail:
freeloop 0;
return 0;
}
// This function returns value in TeleportManager's slot with given indes.
// This function designed to run in ANY context, whether RID attached or not.
// Inputs: arg[0]: slot ID, must be 1 .. 100;
// Return: -1 on error, 0 on empty slot, or NPC ID of teleport in given sslot.
function|script|teleport_get_slot_val
{
if ((getarg(0) < 1) || (getarg (0) > 100)) goto L_Fail; // Bogus index?
set .@index, getarg(0);
set .@manager, getnpcid("TeleportManager");
if (.@manager <= 0) goto L_Fail; // Manager NPC not found?
set .@ret, get(.teleports[.@index], .@manager);
return .@ret;
L_Fail:
return -1;
}
// This function sets slot in TeleportManager with given value.
// This function designed to run in ANY context, whether RID attached or not.
// Inputs: arg[0]: slot ID, must be 1 .. 100;
// arg[1]: value to store to slot;
// Return: 1 on success, <= 0 on failure.
function|script|teleport_set_slot_val
{
if ((getarg(0) < 1) || (getarg (0) > 100)) goto L_Fail; // Bogus index?
if (getarg(1) < 0) goto L_Fail; // TP slots are NPC ID or 0 for empty
set .@index, getarg(0);
set .@val, getarg(1);
set .@manager, getnpcid("TeleportManager");
if (.@manager <= 0) goto L_Fail; // Manager NPC not found?
set .teleports[.@i], .@val, .@manager;
return 1;
L_Fail:
return 0;
}
// PRIVATE: This function cleans up slot in TeleportManager on teleport shutdown.
// This function ONLY meant to be invoked by teleport NPC puppet on shutdown!
// Inputs: nothing. Gets data from its calling NPC.
// Return: 1 on success, <= 0 on failure.
function|script|teleport_mgr_clean
{
if !(.managed) goto L_RetOk; // Teleport not managed by TeleportManager -> no cleanup
set .@my_id, getnpcid();
if (.@my_id <= 0) goto L_RetFail; // Give up on cleanup, slot will leak
// Call chaining OK: teleport_set_slot_val() checks slot # sanity, so teleport_find_slot() fail handled.
set .@res, call("teleport_set_slot_val", call("teleport_find_slot", .@my_id), 0);
if (.@res != 1) goto L_RetFail;
goto L_RetOk;
L_RetOk:
return 1;
L_RetFail:
debugmes "teleport_mgr_clean: TeleportManager cleanup failure -> slot leak. Likely bug! .@my_id=" + .@my_id + ".@res=" + .@res;
return 0;
}
// PRIVATE: This function validates @teleportadd args and prepares for teleport_add() call.
// This function MUST be invoked with player RID attached, by TeleportManager NPC
// Inputs: nothing, but assumes args$ set.
// Return: <= 0 on failure, 1 on success.
// Return: sets @POS_X, @POS_X, @DSTMAP$, @DST_X, @DST_Y,
function|script|teleportadd_parseargs
{
callfunc "argv_splitter";
set @DSTMAP$, @argv$[0]; // Destination map
set @DST_X, @argv[1]; // Dst warp coordinates
set @DST_Y, @argv[2]; // Dst warp coordinates
set @NAME$, @argv$[3]; // Teleport's label
set @TIMEOUT, @argv[4]; // Teleport's lifetime
set @NPCSPRITE, @argv[5]; // Teleport's NPC sprite (optional)
// Check DST map is okay
if ((@DSTMAP$ == "help") || (@DSTMAP$ == "")) goto L_DisplayHelp; // @teleportadd help or @teleportadd
if !(call("teleport_map_valid", @DSTMAP$)) goto L_FailBadmap; // DST: invalid map?
// Check DST X,Y sane
if ((@DST_X <= 0) || (@DST_Y <= 0)) goto L_FailBadDstXY1; // DST: invalids coords <= 0?
if ((getmapmaxx(@DSTMAP$) < @DST_X) || (getmapmaxy(@DSTMAP$) < @DST_Y)) goto L_FailBadDstXY2; // Outside of map?
// Check if DST is collision
if (iscollision(@DSTMAP$, @DST_X, @DST_Y)) goto L_FailDstCollide;
// Try adaptive NPC placement. Above caller if there's room or on caller if not.
set @POS_X, POS_X;
if ((POS_Y > 2) && !(iscollision(getmap(), POS_X, (POS_Y-2)))) set @POS_Y, (POS_Y - 2);
else set @POS_Y, POS_Y; // Overhead placement failed, use caller's tile
// NPC name checks
if (@NAME$ == "") goto L_FailNPCName;
// TIMEOUT checks and setup
if ((@TIMEOUT < -1) || (@TIMEOUT == 0) || (@TIMEOUT > 2000000)) goto L_FailTimeout;
if (@TIMEOUT > 0) set @TIMEOUT, (@TIMEOUT * 1000); // translate seconds -> ms to make more wieldy numbers
// NPC SPRITE configuration
if ((@NPCSPRITE != 424) && (@NPCSPRITE != 369) && (@NPCSPRITE != 368)
&& (@NPCSPRITE != 325) && (@NPCSPRITE != 324)) set @NPCSPRITE, 424;
// All checks complete
return 1; // Everything OK
L_FailBadmap:
message strcharinfo(0), "[TeleportManager] : @teleportadd: unknown destination map:" + @DSTMAP$;
return -1;
L_FailBadDstXY1:
message strcharinfo(0), "[TeleportManager] : @teleportadd: destination X,Y must be > 0! Given X=" + @DST_X + " Y=" + @DST_Y;
return -2;
L_FailBadDstXY2:
message strcharinfo(0), "[TeleportManager] : @teleportadd: destination X,Y outside of map! Given X=" + @DST_X+ " Y=" + @DST_Y;
return -3;
L_FailDstCollide:
message strcharinfo(0), "[TeleportManager] : @teleportadd: destination MAP=" + @DSTMAP$ + " X=" + @DST_X + " Y=" + @DST_Y + " is a collision (impassable)";
return -4;
L_FailNPCName:
message strcharinfo(0), "[TeleportManager] : @teleportadd: NPCNAME can't be empty!";
return -5;
L_FailTimeout:
message strcharinfo(0), "[TeleportManager] : @teleportadd: timeout must be either -1, or > 0 and < 2000000 (seconds)";
return -6;
L_DisplayHelp:
void call("teleport_help_add");
return -7;
}
// PUBLIC API: This function checks if map name known and OK to use.
// This function designed to run in any context.
// Inputs: arg$[0] is map name to check for sanity.
// Return: 1 for known maps, 0 for unknown
function|script|teleport_map_valid
{
set .@inputmap$, getarg(0, "");
set .@i, 0;
setarray .@maps1$, "001-1", "001-2", "001-3", "002-1", "002-2", "002-3",
"002-4", "002-5", "003-1", "003-4", "004-1", "004-3",
"004-4", "004-5", "005-3", "006-1", "006-2", "006-3",
"007-1", "007-2", "008-1", "009-1", "009-2", "009-3",
"009-4", "009-5", "009-6", "009-7", "009-8", "010-1",
"010-2", "011-1", "011-3", "011-4", "011-6", "012-1",
"012-3", "012-4", "013-1", "013-2", "013-3", "014-1",
"014-3", "015-1", "015-3", "016-1", "016-2", "017-1",
"017-2", "017-3", "017-4", "017-9", "018-1", "018-2",
"018-3", "019-1", "019-3", "019-4", "020-1", "020-2",
"020-3", "021-3", "023-1", "023-2", "023-3", "025-1",
"025-3", "025-4", "026-1", "026-2", "027-1", "027-2",
"027-3", "027-4", "027-5", "027-6", "027-7", "027-8",
"028-1", "028-3", "029-1", "029-2", "029-3", "029-4",
"030-1", "030-2", "030-3", "030-4", "031-1", "031-2",
"031-3", "031-4", "032-3", "033-1", "034-1", "034-2",
"035-2", "036-2", "041-1", "042-1", "043-1", "043-3",
"043-4", "045-1", "046-1", "046-3", "047-1", "047-3";
// Had to split to 2 arrays as its too big for array initializer
setarray .@maps2$, "048-2", "051-1", "051-3", "052-1", "052-2", "055-1",
"055-3", "056-2", "057-1", "058-1", "058-2", "069-2",
"070-1", "070-3", "099-1", "099-2", "099-3", "099-4",
"099-5", "099-6", "099-7", "099-8", "botcheck";
set .@arr_sz1, getarraysize(.@maps1$[0]);
set .@arr_sz2, getarraysize(.@maps2$[0]);
freeloop 1; // Needed to iterate over array of about 150 maps
goto L_NextMap; // Start iterating over array of maps.
L_NextMap:
if (.@inputmap$ == .@maps1$[.@i]) goto L_Found; // Found map in arr 1?
if (.@inputmap$ == .@maps2$[.@i]) goto L_Found; // Found map in arr 2?
set .@i, (.@i + 1); // increment .@maps$[] index
if ((.@i >= .@arr_sz1) && (.@i >= .@arr_sz2)) goto L_NotFound; // Abort if whole arrays scanned
goto L_NextMap; // Try next map in .@maps$[]
L_NotFound:
freeloop 0;
return 0;
L_Found:
freeloop 0;
return 1;
}
// PRIVATE: This function displays usage help for TeleportManager - @teleportadd
// This function should be invoked by TeleportManager with RID attached.
// Inputs: nothing.
// Return: nothing, just shows usage -> caller.
function|script|teleport_help_add
{
message strcharinfo(0), "[TeleportManager] : @teleportadd <MAP> <X> <Y> <NPCNAME> <TIMEOUT> [sprite]";
message strcharinfo(0), "[TeleportManager] : <MAP> <X> <Y>: teleport's destination map and coordinates";
message strcharinfo(0), "[TeleportManager] : <NPCNAME>: name of NPC, unique and nonempty. If it stats with # its hidden";
message strcharinfo(0), "[TeleportManager] : <TIMEOUT>: teleport lifetime (sec), < 2 000 000 sec, -1 = persistent";
message strcharinfo(0), "[TeleportManager] : [sprite]: optional, NPC sprite (424,369,368,325 and 324 accepted)";
message strcharinfo(0), "[TeleportManager] : Example: @teleportadd 009-1 52 39 Hurns -1 adds permanent teleport to Hurns menhir";
message strcharinfo(0), "[TeleportManager] : Example: @teleportadd 009-1 52 39 Hurns 600 324 - same but 10 min, and red circle";
return;
}
// PRIVATE: This function displays usage help for TeleportManager - @teleportdel
// This function should be invoked by TeleportManager with RID attached.
// Inputs: nothing.
// Return: nothing, just shows usage -> caller.
function|script|teleport_help_del
{
message strcharinfo(0), "[TeleportManager] : @teleportdel <ID>";
message strcharinfo(0), "[TeleportManager] : ID either slot# (1..100) or teleport NPC ID";
return;
}
// Access checks for TeleportManager. Based on cut-down BossPowers checks.
function|script|teleport_access_check
{
if ($BP_DISABLE) goto L_Killswitch; // If things go wrong, TeleportManager can be disabled.
if (#BP_DISABLE) goto L_Killswitch; // If someone abuses feature, there's _per-account_ DENY flag.
if (GM >= 40) goto L_Allowed; // GM >= 40 can use boss actions.
if (IS_EVENTER == 42) goto L_Allowed; // Trusted player(s) could be allowed to access Eventer "magic"
// if (debug) goto L_Allowed; // Allow on debug.
message strcharinfo(0), "[TeleportManager] : You can't use this feature at this time. Sorry. [1]";
return 1; // Not allowed by default.
L_Allowed:
return 0; // Whoever gets here allowed to invoke BossPowers spells
L_Killswitch:
message strcharinfo(0), "[TeleportManager] : You can't use this feature at this time. Sorry. [2]";
return 2;
}
|