// TMW2 scripts.
// Authors:
// Jesusalva
// Description:
// Controls world events so Saulc and I can take vacations.
// See also: seasons.txt, command/event.txt, aurora.txt
// 003-1/events.txt, soulmenhir.txt and, of course, the event maps (if any).
// Schedule, if needed to change, can be found in the OnInit loop.
// An event, obviously, cannot last more than 7... 15 days at WORST.
// Therefore, month checks aren't included in day checks.
- script sPatrick NPC_HIDDEN,{
OnInit:
setarray .maps$,
"005-1",
"013-1",
"014-1",
"014-2",
"014-3",
"014-4",
"014-5",
"017-1",
"018-2",
"018-4",
"018-5",
"soren";
end;
OnMyMobDeath:
end;
OnClock0000:
OnClock6000:
OnClock1200:
OnClock1500:
OnClock1800:
OnClock2100:
.@d=gettime(GETTIME_DAYOFMONTH);
// Patrick Day should work only in 2 luck days according to Saulc
// If this is required use $PATRICK_DAYCTRL so the days before $@PATRICK_DAYMAX
// act with 100% chances (determinism).
// As it is being spawn 4 times at a day (like TMW-BR events), because it is
// flatly and outright IMPOSSIBLE to add a permanent spawn, that is not required.
if ($EVENT$ == "Patrick" && .@d <= $@PATRICK_DAYMAX) {
for (.@i=0; .@i < getarraysize(.maps$); .@i++) {
.@m$=.maps$[.@i];
.@x=getmapinfo(MAPINFO_SIZE_X, .@m$)-20;
.@y=getmapinfo(MAPINFO_SIZE_Y, .@m$)-20;
// Remove previously spawned clovers
killmonster(.@m$, "sPatrick::OnMyMobDeath");
// It is one clover for each 225 tiles (about a 25x25 square)
.@maparea=(.@x-20)*(.@y-20);
.@mobs=max(1, .@maparea/225);
areamonster .@m$, 20, 20, .@x, .@y, strmobinfo(1, StPatricksClover), StPatricksClover, .@mobs, "sPatrick::OnMyMobDeath";
}
}
end;
// Remove previously spawned clovers for event end
// And then disables the NPC
OnCleanUp:
for (.@i=0; .@i < getarraysize(.maps$); .@i++) {
.@m$=.maps$[.@i];
killmonster(.@m$, "sPatrick::OnMyMobDeath");
}
disablenpc "sPatrick";
donpcevent "Aurora::OnRestore";
end;
}
function script sThanksgiving {
// Variables:
// #THANKS_DAY
// #THANKS_STREAK
// @thanks_card
// Already spinned
if (#THANKS_DAY == gettime(5) || $EVENT$ != "Thanksgiving")
return;
// Not spinned yet
showavatar 1102;
mes l(".:: Thanksgiving ::.");
mesc l("Spin daily the card to get prizes!");
select
l("SPIN!"),
l("Later");
mes "";
if (@menu == 2) {
setskin "";
closeclientdialog;
return;
}
// Spin it
// Your prize is saved in .@luck. Rigged against fruits
.@luck=rand2(0,11);
.@luck=(.@luck == 10 ? rand2(0,11) : .@luck);
// A fruit before 10 days: rig to Arcmage or to blueprint
if (.@luck == 10 && #THANKS_STREAK < 10)
.@luck+=any(-1,1);
// A fruit before 20 days: Lower chances from 4% to 2%
if (.@luck == 10 && #THANKS_STREAK < 20)
.@luck=rand2(0,11);
// Extra spins
.@extra=rand2(1,3);
.@spins=.@extra*11+.@luck;
//.@extra=0;
// Show the spins
for (.@i=0;.@i<=.@spins;.@i++) {
.@cur=(.@i%11);
showavatar 1103+.@cur;
sleep2(60);
}
mes l(".:: Congratulations ::.");
#THANKS_DAY = gettime(5);
#THANKS_STREAK+=1;
if (debug || $@GM_OVERRIDE) {
mes l("You got a %d", .@luck);
mesf "Spins: %d/%d (cur %d extra %d)", .@i, .@spins, .@cur, .@extra;
mes "";
//.@luck=$@GM_OVERRIDE;
}
// Switch the reward
switch (.@luck) {
case 0: // EXP
.@p=BaseLevel*#THANKS_STREAK;
.@p*=3;
getexp .@p, 0;
mes l("You got %d EXP!", .@p);
break;
case 1: // JEXP
.@p=BaseLevel*#THANKS_STREAK;
.@p=.@p*15/10;
getexp 0, .@p;
mes l("You got %d JEXP!", .@p);
break;
case 2: // GP
.@p=BaseLevel*#THANKS_STREAK;
Zeny+=.@p;
mes l("You got %d GP!", .@p);
break;
case 3: // MOBPT
.@p=BaseLevel*#THANKS_STREAK;
Mobpt+=.@p;
mes l("You got %d Monster Points!", .@p);
break;
case 4: // RES
.@p=BaseLevel*#THANKS_STREAK;
.@p*=3;
REAL_ESTATE_CREDITS+=.@p;
mes l("You got %d Real Estate Credits!", .@p);
break;
case 5: // GIFT
.@p=BronzeGift;
.@p=(#THANKS_STREAK > 7 ? SilverGift : .@p);
.@p=(#THANKS_STREAK > 15 ? GoldenGift : .@p);
.@p=(#THANKS_STREAK > 22 ? PrismGift : .@p);
.@p=(#THANKS_STREAK > 27 ? SupremeGift : .@p);
mes l("You got a(n) %s gift!", getitemlink(.@p));
getitem .@p, 1;
break;
case 6: // STR C
.@p=#THANKS_STREAK;
getitem StrangeCoin, .@p;
mes l("You got %d %s!", .@p, getitemlink(StrangeCoin));
break;
case 7: // HERO C
.@p=#THANKS_STREAK;
.@p+=getq2(LoFQuest_HH)*max(1,#THANKS_STREAK/10);
getitem HeroCoin, .@p;
mes l("You got %d %s!", .@p, getitemlink(HeroCoin));
break;
case 8: // MERC
.@p=any(MercCard_GonzoDark, MercCard_Rosa, MercCard_Soren, MercCard_Apane);
.@p=(#THANKS_STREAK > 7 ? any(MercCard_EarthWitch, MercCard_Demure, MercCard_Jesusalva, MercCard_Pookie) : .@p);
.@p=(#THANKS_STREAK > 14 ? any(MercCard_Arthur, MercCard_LawnCable, MercCard_Crazyfefe, MercCard_Saulc) : .@p);
.@p=(#THANKS_STREAK > 21 ? any(MercCard_Swezanne, MercCard_DragonStar, MercCard_Msawis, MercCard_Aisen) : .@p);
.@p=(#THANKS_STREAK > 27 ? any(MercCard_Xanthem, MercCard_Woody, MercCard_Lilanna) : .@p);
getitem .@p, 1;
mes l("You got a %s!", getitemlink(.@p));
break;
case 9: // CARD
.@p=any(NatureCard, NinjaCard, MageCard, DruidCard, ClericCard, KnightCard, HeroCard, NecromancerCard);
.@p=(#THANKS_STREAK > 24 ? any(SpeedCard, ReflectCard, PowerCard, WallCard) : .@p);
getitem .@p, 1;
mes l("You got a %s!", getitemlink(.@p));
break;
case 10: // FRUIT
.@p=MysteriousFruit;
getitem .@p, 1;
mes l("You got a %s!", getitemlink(.@p));
break;
case 11: // BLUE
.@p=any(EquipmentBlueprintA, EquipmentBlueprintA, AlchemyBlueprintA);
.@p=(#THANKS_STREAK > 7 ? any(EquipmentBlueprintB, EquipmentBlueprintB, AlchemyBlueprintB) : .@p);
.@p=(#THANKS_STREAK > 14 ? any(EquipmentBlueprintC, EquipmentBlueprintC, AlchemyBlueprintC) : .@p);
.@p=(#THANKS_STREAK > 21 ? any(EquipmentBlueprintD, EquipmentBlueprintD, AlchemyBlueprintD) : .@p);
.@p=(#THANKS_STREAK > 27 ? any(EquipmentBlueprintE, EquipmentBlueprintE, AlchemyBlueprintE) : .@p);
getitem .@p, 1;
mes l("You got a %s!", getitemlink(.@p));
break;
}
// Close
next;
setskin "";
closeclientdialog;
return;
}
// ChocolateDay()
function script ChocolateDay {
if (!playerattached())
return;
// Date check
if (gettime(6) != JULY)
return;
if (gettime(5) != 7)
return;
// Max. 80% chances, 0.4% per monster level
.@lv=min(200, getmonsterinfo(killedrid, MOB_LV));
if (rand2(10000) < (.@lv*40)) {
// Chocolate Bar: 73%; Chocolate Dye: 6.7%
.@choco=any(ChocolateBar, ChocolateBar, ChocolateBar, ChocolateBar,
ChocolateMouboo, ChocolateBiscuit, ChocolateBunny,
ChocolateBar, ChocolateBar, ChocolateBar, ChocolateBar,
ChocolateDye, ChocolateBar, ChocolateBar, ChocolateBar);
getmapxy(.@m$, .@x, .@y, 0);
.@x+=rand2(-1,1);
.@y+=rand2(-1,1);
makeitem(.@choco, 1, .@m$, .@x, .@y);
}
return;
}
// CoffeeDay()
function script CoffeeDay {
if (!playerattached())
return;
// Date check
if (gettime(6) != OCTOBER)
return;
if (gettime(5) != 1)
return;
// Max. 22% chances, 0.1% per monster level
.@lv=min(200, getmonsterinfo(killedrid, MOB_LV));
if (rand2(10000) < (.@lv*11)) {
getmapxy(.@m$, .@x, .@y, 0);
.@x+=rand2(-1,1);
.@y+=rand2(-1,1);
makeitem(Coffee, 1, .@m$, .@x, .@y);
}
return;
}
000-0,0,0,0 script #EventCore NPC_HIDDEN,{
end;
// confEvent(event ID, stday, stmon, endday, endmon)
function confEvent {
setd("."+getarg(0)+"_stday", getarg(1));
setd("."+getarg(0)+"_stmon", getarg(2));
setd("."+getarg(0)+"_endday", getarg(3));
setd("."+getarg(0)+"_endmon", getarg(4));
// Save the event key?
//.@confname=".conf_"+getarg(2)+"$";
//setd(.@confname+"["+getarraysize(.@confname)+"]", getarg(0));
// Save only the day? (And use if statement)
.@confname$=".conf_"+getarg(2);
.@size=getarraysize(getd(.@confname$));
setd(.@confname$+"["+.@size+"]", getarg(1));
//debugmes "CONFIGURE EVENT, %s[%d] = %d", .@confname$, .@size, getarg(1);
//debugmes "CNAME: %s", getarg(0);
return;
}
// Event Schedule (all dates are inclusive)
// NEVER, ever, include the last day of the month.
OnInit:
confEvent("valentine",
13, FEBRUARY,
16, FEBRUARY);
confEvent("tmw2day",
1, MARCH,
7, MARCH);
confEvent("patrick",
15, MARCH,
19, MARCH);
confEvent("easter",
17, APRIL,
24, APRIL);
confEvent("worker",
27, APRIL,
3, MAY);
confEvent("thanks",
1, NOVEMBER,
29, NOVEMBER); // NEVER use the last day of the month here
confEvent("xmas",
19, DECEMBER,
2, JANUARY);
// Some setup
.@isinit=true;
disablenpc "sPatrick";
FYE_Normalize();
// Check for events every midnight
OnClock0000:
.@d=gettime(GETTIME_DAYOFMONTH);
.@m=gettime(GETTIME_MONTH);
.@o=gettime(GETTIME_WEEKDAY); // Resets at 0 (sunday)
debugmes "A new day begins! Today is %02d/%02d", .@d, .@m;
// Override the server-wide randomness
resetrng();
// Initialize the event core
if ($@DEBUG_OD)
.@d=$@DEBUG_OD;
if ($@DEBUG_OM)
.@m=$@DEBUG_OM;
debugmes "EVENT CORE, the %02d/%02d", .@d, .@m;
// Is there another event this week?
if (!debug && !$HARDCORE && .@o == MONDAY && !.@isinit) {
.@dofy=true;
.@confname$=".conf_"+.@m;
// NOTE: Maybe make a single .annuals array and cycle it
// Gather the ST variable from interest...?
for (.@i=0;.@i < getarraysize(getd(.@confname$)); .@i++) {
.@val=getd(.@confname$+"["+.@i+"]");
//debugmes "Looping, %d = %d", .@i, .@val;
// Erm.
if (.@val == 0)
continue;
// This script has a weakness: It cannot predict events starting
// at the start or the end of the month.
// So they might still overlap.
// A possible solution is to, eventually, record start and end date.
// And only inhibit FY event if the MONDAY is within the event...?
// XXX: Now it inhibits by itself; But it should NOT begin a FYE if
// another (annual) event is scheduled for the same week.
// Namely: TMW2 Day and Thanksgiving
debugmes "%d >= %d && %d <= %d", .@val, .@d-6, .@val, .@d+6;
// In this case there's already an event!
// .@d == .@val <= .@d+6 AND
if ( .@val >= .@d-6 && .@val <= .@d+6 ) {
.@dofy=false;
break;
}
// continue...
}
// Stop previous event
FYStopEvent();
// Trigger event framework
if (.@dofy && $EVENT$ == "")
FYNewEvent();
else
debugmes "\033[1mAnother event is scheduled!";
}
// Handle Valentine Day
if (.@m >=.valentine_stmon && .@m <= .valentine_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .valentine_stday - 1) {
kamibroadcast("Valentine Day will start tomorrow!");
}
// Last Day: Send out an announcement
if (.@d == .valentine_endday) {
kamibroadcast("It's the last day for Valentine Event! Hurry up!");
}
// Begin the event
if (.@d == .valentine_stday) {
kamibroadcast("Valentine Day begun!");
$EVENT$="Valentine";
$@VALENTINE_LOVELETTER = htnew();
$@VALENTINE_GIFTSTACKS = htnew();
}
// End the event the day after
if (.@d == .valentine_endday+1) {
kamibroadcast("Valentine Day ended!");
sClear();
$EVENT$="";
}
}
// Handle TMW2 Day
if (.@m >=.tmw2day_stmon && .@m <= .tmw2day_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .tmw2day_stday - 1) {
kamibroadcast("Moubootaur Legends Anniversary will start tomorrow!");
}
// Last Day: Send out an announcement
if (.@d == .tmw2day_endday) {
kamibroadcast("It's the last day of our Anniversary Event! Hurry up!");
}
// Begin the event
if (.@d == .tmw2day_stday) {
kamibroadcast("Moubootaur Legends Anniversary Event begun!");
if ($EVENT$ != "Anniversary")
$BCONFB_EXPR+=50;
$EVENT$="Anniversary";
}
// End the event the day after
if (.@d == .tmw2day_endday+1) {
kamibroadcast("Our Special Anniversary Event ended! Thanks!");
sClear();
$EVENT$="";
}
}
// Handle St. Patrick Day
// During this day, a special four leaf clover is spawned daily, at 4 times in the day
// in all forests: 6:00, 12:00, 18:00 and 00:00.
// $PATRICK_DAYMAX
if (.@m >=.patrick_stmon && .@m <= .patrick_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .patrick_stday - 1) {
kamibroadcast("St. Patrick Day will start tomorrow!");
}
// Last Day: Send out an announcement
else if (.@d == .patrick_endday) {
kamibroadcast("It's the last day for St. Patrick Event! Hurry up!");
}
// Begin the event
else if (.@d == .patrick_stday) {
kamibroadcast("St. Patrick Day begun!");
$EVENT$="Patrick";
$@PATRICK_DAYMAX=.patrick_endday;
enablenpc "sPatrick";
setnpcdisplay("Aurora", "Patrick Saulc", NPC_WEIRDGREEN);
enablenpc "St. Patrick Gold Pot";
donpcevent "St. Patrick Gold Pot::OnForcedMove";
}
// End the event the day after
else if (.@d == .patrick_endday+1) {
kamibroadcast("St. Patrick Day ended!");
sClear();
$EVENT$="";
donpcevent "sPatrick::OnCleanUp";
}
}
// Handle Easter
if (.@m >=.easter_stmon && .@m <= .easter_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .easter_stday - 1 && .@m == .easter_stmon) {
kamibroadcast("Easter will start tomorrow!");
}
// Last Day: Send out an announcement
else if (.@d == .easter_endday && .@m == .easter_endmon) {
kamibroadcast("It's the last day for Easter Event! Hurry up!");
}
// Begin the event
else if (.@d == .easter_stday && .@m == .easter_stmon) {
kamibroadcast("Easter begun!");
$EVENT$="Easter";
}
// End the event the day after
else if (.@d == .easter_endday+1 && .@m == .easter_endmon) {
kamibroadcast("Easter ended!");
sClear();
$EVENT$="";
}
}
// Handle Worker Day
if (.@m >=.worker_stmon && .@m <= .worker_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .worker_stday - 1 && .@m == .worker_stmon) {
kamibroadcast("Worker Day will start tomorrow!");
}
// Last Day: Send out an announcement
else if (.@d == .worker_endday && .@m == .worker_endmon) {
kamibroadcast("It's the last day for Worker Day Event! Hurry up!");
}
// Begin the event
else if (.@d == .worker_stday && .@m == .worker_stmon) {
kamibroadcast("Worker Day begun!");
$EVENT$="Worker";
}
// End the event the day after
else if (.@d == .worker_endday+1 && .@m == .worker_endmon) {
kamibroadcast("Worker Day ended!");
sClear();
$EVENT$="";
}
}
// Handle Thanksgiving Day
if (.@m >=.thanks_stmon && .@m <= .thanks_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .thanks_stday - 1 && .@m == .thanks_stmon) {
kamibroadcast("Thanksgiving will start tomorrow!");
}
// Last Day: Send out an announcement
else if (.@d == .thanks_endday && .@m == .thanks_endmon) {
kamibroadcast("It's the last day for Thanksgiving Event! Hurry up!");
}
// Begin the event
else if (.@d == .thanks_stday && .@m == .thanks_stmon) {
kamibroadcast("Thanksgiving begun!");
$EVENT$="Thanksgiving";
}
// End the event the day after
else if (.@d == .thanks_endday+1 && .@m == .thanks_endmon) {
kamibroadcast("Thanksgiving ended!");
sClear();
$EVENT$="";
}
}
// Handle Christmas
if (.@m >=.xmas_stmon && .@m <= .xmas_endmon) {
// It's tomorrow: Send out an announcement
if (.@d == .xmas_stday - 1 && .@m == .xmas_stmon) {
kamibroadcast("Christmas will start tomorrow!");
}
// Last Day: Send out an announcement
else if (.@d == .xmas_endday && .@m == .xmas_endmon) {
kamibroadcast("It's the last day for Christmas Event! Hurry up!");
}
// Begin the event
else if (.@d == .xmas_stday && .@m == .xmas_stmon) {
kamibroadcast("Christmas begun!");
$EVENT$="Christmas";
query_sql("DELETE FROM `quest` WHERE `quest_id` = '"+SQuest_Christmas+"'");
sChristmas();
}
// End the event the day after
else if (.@d == .xmas_endday+1 && .@m == .xmas_endmon) {
kamibroadcast("Christmas ended!");
sClear();
$EVENT$="";
}
}
debugmes "EVENT CORE has finished";
end;
}