// 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;
}
// Special bonus
if (#THANKS_STREAK % 7 == 0) {
getitem StrangeCoin, 10;
mesc l("%d day streak! Gained %d bonus %s!", #THANKS_STREAK, 10, getitemlink(StrangeCoin));
}
// 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;
}
// FSFDay()
function script FSFDay {
if (!playerattached())
return;
// Date check
if (gettime(6) != SEPTEMBER)
return;
if (gettime(5) != 9)
return;
// Max. 0.16% chances, 0.008% per monster level
.@lv=min(200, getmonsterinfo(killedrid, MOB_LV));
if (rand(1000000) < (.@lv*8)) {
getmapxy(.@m$, .@x, .@y, 0);
.@x+=rand2(-1,1);
.@y+=rand2(-1,1);
// Ancient 50%, Equipment 25%, Alchemy 25%
.@bp = any(AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint,
AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint,
EquipmentBlueprintA, EquipmentBlueprintB, EquipmentBlueprintC, EquipmentBlueprintD, EquipmentBlueprintE,
AlchemyBlueprintA, AlchemyBlueprintB, AlchemyBlueprintC, AlchemyBlueprintD, AlchemyBlueprintE);
makeitem(.@bp, 1, .@m$, .@x, .@y);
}
return;
}
// CraftmasterDay()
function script CraftmasterDay {
if (!playerattached())
return;
// Date check
if (!$BETASERVER)
return;
if (gettime(7) != 2021)
return;
if (gettime(6) != JUNE)
return;
if (gettime(5) != 21)
return;
if (getmap() != "018-3")
return;
// Scored a Blue Print (2.5%)
if (rand2(10000) < 250) {
if (BaseLevel > 80 && REBIRTH)
getitem any(EquipmentBlueprintE, AlchemyBlueprintE,
EquipmentBlueprintD, AlchemyBlueprintD,
EquipmentBlueprintC, AlchemyBlueprintC,
EquipmentBlueprintB, AlchemyBlueprintB,
EquipmentBlueprintA, AlchemyBlueprintA), 1;
else if (BaseLevel > 70)
getitem any(EquipmentBlueprintD, AlchemyBlueprintD,
EquipmentBlueprintC, AlchemyBlueprintC,
EquipmentBlueprintB, AlchemyBlueprintB,
EquipmentBlueprintA, AlchemyBlueprintA), 1;
else if (BaseLevel > 45)
getitem any(EquipmentBlueprintC, AlchemyBlueprintC,
EquipmentBlueprintB, AlchemyBlueprintB,
EquipmentBlueprintA, AlchemyBlueprintA), 1;
else if (BaseLevel > 20)
getitem any(EquipmentBlueprintB, AlchemyBlueprintB,
EquipmentBlueprintA, AlchemyBlueprintA), 1;
else
getitem any(EquipmentBlueprintA, AlchemyBlueprintA), 1;
return;
}
// Scored Monster Points (9%)
if (rand2(10000) < 900) {
.@mpt=rand2(BaseLevel*10, BaseLevel*100); // 600~6000 usually
Mobpt+=.@mpt;
dispbottom l("Acquired: %s Monster Points", fnum(.@mpt));
return;
}
// Autocraft (1%)
if (rand2(10000) < 100) {
.@rc=any(rand2(51, 62), 65, 66, rand2(72, 76), rand2(77, 81), 82, 98,
99, 100, rand2(93, 97), rand2(88, 91), rand(83, 87), 92, 101,
rand2(102,117), any(122, 112), rand2(125, 134), rand2(135, 143));
// Retrieve ID
.@it=getcraftcode(.@rc);
if (.@it <= 0)
return;
// Mark the crafting in your score variable
CRAFTING_SCORE_COMPLETE+=getiteminfo(.@it, ITEMINFO_ELV);
// Update your score book
CRAFTING_SCORE=(CRAFTING_SCORE_COMPLETE/40);
// Receive item
getitembound(.@it, 1, 1);
// Apply options if possible
if (getskilllv(TMW2_CRAFT)) {
delinventorylist(); // Needed, because we'll rely on rfind()
getinventorylist();
.@index=array_rfind(@inventorylist_id, .@it);
// Just to be sure, if this have an option, get something else
if (getitemoptionparambyindex(.@index, 0)) {
.@index=array_find(@inventorylist_id, .@it);
}
callfunc("csys_Apply", .@index);
}
dispbottom l("Successfully Crafted: %s", getitemname(.@it));
return;
}
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:
// No events on test server
if (debug && !$@GM_OVERRIDE)
end;
// Prepare variables
.@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 (!$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!");
if ($EVENT$ != "")
FYStopEvent();
$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!");
if ($EVENT$ != "")
FYStopEvent();
$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!");
if ($EVENT$ != "")
FYStopEvent();
sEaster();
}
// 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!");
if ($EVENT$ != "")
FYStopEvent();
$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!");
if ($EVENT$ != "")
FYStopEvent();
$EVENT$="Thanksgiving";
}
// End the event the day after
else if (.@d == .thanks_endday+1 && .@m == .thanks_endmon) {
kamibroadcast("Thanksgiving ended!");
sClear();
$EVENT$="";
}
}
// Handle Christmas. It goes past the year so the rule is different, BEWARE
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!");
if ($EVENT$ != "")
FYStopEvent();
$EVENT$="Christmas";
DelQuestFromEveryPlayer(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;
}