// TMW2 Script
// Modified by Jesusalva
// Evol scripts.
// Authors:
// gumi
// Reid
function script Banking {
do
{
if (BankVault > 0) {
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("You currently have @@ GP on your bank account.",
format_number(BankVault)),
l("What do you want to do with your money?");
} else {
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("What do you want to do with your money?");
}
select
rif(Zeny > 0, l("Deposit.")),
rif(BankVault > 0, l("Withdraw.")),
l("Buy a Housing Letter"),
l("I'm done.");
switch (@menu)
{
case 1:
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("How much do you want to deposit?");
menuint
l("Other."), -1,
rif(Zeny >= 1000, format_number(1000) + " GP."), 1000,
rif(Zeny >= 2500, format_number(2500) + " GP."), 2500,
rif(Zeny >= 5000, format_number(5000) + " GP."), 5000,
rif(Zeny >= 10000, format_number(10000) + " GP."), 10000,
rif(Zeny >= 25000, format_number(25000) + " GP."), 25000,
rif(Zeny >= 50000, format_number(50000) + " GP."), 50000,
rif(Zeny >= 100000, format_number(100000) + " GP."), 100000,
l("All of my money."), -2,
l("I changed my mind."), -3;
switch (@menuret) {
case -1:
input @menuret;
break;
case -2:
@menuret = Zeny;
}
if (@menuret > 0) {
if (@menuret > Zeny) {
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("You do not have enough Gold on yourself.");
break;
}
@menuret = min(MAX_BANK_ZENY, @menuret); // make sure the variable can't overflow
.@before = BankVault; // amount before the deposit
.@max = MAX_BANK_ZENY - BankVault; // maximum possible deposit
.@deposit = min(.@max, @menuret); // actual deposit
if (.@deposit > 0) {
BankVault += .@deposit; // add to bank
Zeny -= .@deposit; // remove from inventory
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("You made a cash deposit of @@ GP.", format_number(.@deposit));
}
}
break;
case 2:
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("How much do you want to withdraw?");
menuint
l("Other."), -1,
rif(BankVault >= 1000, format_number(1000) + " GP."), 1000,
rif(BankVault >= 2500, format_number(2500) + " GP."), 2500,
rif(BankVault >= 5000, format_number(5000) + " GP."), 5000,
rif(BankVault >= 10000, format_number(10000) + " GP."), 10000,
rif(BankVault >= 25000, format_number(25000) + " GP."), 25000,
rif(BankVault >= 50000, format_number(50000) + " GP."), 50000,
rif(BankVault >= 100000, format_number(100000) + " GP."), 100000,
l("All of my money."), -2,
l("I changed my mind."), -3;
switch (@menuret)
{
case -1:
input @menuret;
break;
case -2:
@menuret = BankVault;
}
if (@menuret > 0) {
if (@menuret > BankVault) {
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("You do not have enough Gold Pieces on your bank account.");
break;
}
@menuret = min(MAX_ZENY, @menuret); // make sure the variable can't overflow
.@before = Zeny; // amount before the withdrawal
.@max = MAX_ZENY - Zeny; // maximum possible withdrawal
.@withdrawal = min(.@max, @menuret); // actual withdrawal
if (.@withdrawal > 0) {
Zeny += .@withdrawal; // add to inventory
BankVault -= .@withdrawal; // remove from bank
speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
l("You withdrew a total of @@ GP.", format_number(.@withdrawal));
}
}
break;
case 3:
.@gp=REAL_ESTATE_CREDITS+Zeny;
mesc l("You currently have @@ mobiliary credits + GP at your disposal.", format_number(.@gp));
mesc l("@@ - @@ - @@", getitemlink(HousingLetterI), getitemlink(HousingLetterII), getitemlink(HousingLetterIII));
next;
select
l("Nothing"),
rif(.@gp >= 11000, l("Housing Letter I for 11,000 GP")),
rif(.@gp >= 101000, l("Housing Letter II for 101,000 GP")),
rif(.@gp >= 1001000, l("Housing Letter III for 1,001,000 GP"));
mes "";
switch (@menu) {
case 2:
realestate_payment(11000);
getitem HousingLetterI, 1;
break;
case 3:
realestate_payment(101000);
getitem HousingLetterII, 1;
break;
case 4:
realestate_payment(1001000);
getitem HousingLetterIII, 1;
break;
}
break;
default: return;
}
} while (true);
}
function script BKInfo {
speech S_LAST_NEXT,
l("We organize some auction and we help local merchants to launch their businesses."),
l("We also feature some services like a storage and a bank for members."),
l("Registration is open to everybody, but newcomers need to pay a fee for all of the paperwork."),
l("If you have... references, we may also be able to offer you... premium storing.");
narrator S_FIRST_BLANK_LINE,
l("The bank and item storage is shared between all characters within a same account."),
l("With it, you can safely move items and funds between your characters."),
l("The Premium and Deluxe Storages are only available for characters which were reborn at least once.");
return;
}
// name, city, price, ID
function script BKReg {
.@price=max(2000, getarg(2)-#BankP);
.@id=getarg(3, 1);
@menu=3;
do
{
mesn getarg(0);
mesq l("Register fee is @@.", .@price);
mesc l("The fee only need to be paid once and will work in every town.");
next;
select
rif(Zeny >= .@price, l("Register")),
l("Not at the moment"),
l("Information");
mes "";
if (@menu == 1) {
Zeny=Zeny-.@price;
setq General_Banker, .@id;
#BankP=#BankP+(rand2(150,400)*(.@id**2));
mesn getarg(0);
mesq l("Registered! You can now use any banking service, of any town!");
} else if (@menu == 3) {
BKInfo();
}
} while (@menu == 3);
return;
}
// name, city, price (defaults to 10k)
function script Banker {
.@bankId = getvariableofnpc(.bankId, strnpcinfo(0));
mesn getarg(0);
mesq l("Welcome! My name is @@, I am a representative of the Merchant Guild on @@.", getarg(0), getarg(1));
next;
if (getq(General_Banker) == 0) {
BKReg(getarg(0), getarg(1), getarg(2,10000));
} else {
do
{
select
l("I would like to store some items."),
l("I would like to perform money transactions."),
l("Did I received any mail?"),
rif(REBIRTH || is_sponsor(), l("I would like to use the Premium Storage.")),
rif(REBIRTH, l("I would like to use the Deluxe Storage.")),
rif(getcharid(2) > 0, l("I would like to use the Guild Storage.")),
l("What is this guild for?"),
rif(.@bankId && Zeny < 50000, l("Can I help the Guild in any way?")),
l("Bye.");
switch (@menu) {
case 1:
closeclientdialog;
openstorage;
close;
break;
case 2:
Banking();
break;
case 3:
// NOTE: This value is HARDCODED, do not try changing it!
mesc l("Note: Transfering items on mail cost @@ GP/item", 500);
mesc l("Money transference by mail is, however, free.");
next;
closeclientdialog;
openmail();
close;
break;
case 4:
if (getq(General_Banker) < 2) {
mesn;
mesq l("The Premium Storage is available to all our sponsors and anyone with... references. Such as yourself!");
next;
.@price=25000;
mesn;
mesq l("It will allow you to store %d extra items, with unlimited weight or size limit, for only %s GP! Although premium clients such as yourself... deserve a discount!", 300, fnum(.@price));
next;
BKReg(getarg(0), getarg(1), .@price, 2);
}
if (getq(General_Banker) >= 2) {
closeclientdialog;
openstorage 4;
close;
}
break;
case 5:
if (getq(General_Banker) < 2) {
mesn;
mesq l("This option is not yet available for you; Please purchase the Premium Storage first, and then we can get started on the deluxe.");
break;
}
if (getq(General_Banker) < 3) {
mesn;
mesq l("The Deluxe Storage is available only to our best customers, and how lucky you! YOU are eligible!");
next;
.@price=100000;
mesn;
mesq l("It will allow you to store %d extra items, with unlimited weight or size limit, for only %s GP! Although premium clients such as yourself... deserve a discount!", 500, fnum(.@price));
next;
BKReg(getarg(0), getarg(1), .@price, 3);
}
if (getq(General_Banker) >= 3) {
closeclientdialog;
openstorage 5;
close;
}
break;
case 6:
// FIXME: Raises a console warning of invalid map
closeclientdialog;
doevent "Guild Storage::OnStorage";
close;
break;
case 7:
mes "";
BKInfo();
break;
case 8:
mes "";
callfunc("MerchantQuest", .@bankId - 1);
break;
}
if (@menu != 9) {
speech S_FIRST_BLANK_LINE | S_LAST_NEXT | S_NO_NPC_NAME,
l("Something else?");
}
} while (@menu != 9);
}
closedialog;
goodbye;
close;
}
// This function registers a bank for guild purposes
// .bankId = RegisterBank(Town, {Main Quest Stage at which banks become available})
function script RegisterBank {
array_push($@BANK_NAME$, strnpcinfo(1));
array_push($@BANK_TOWN$, getarg(0));
array_push($@BANK_MINLV, getarg(1,1));
return getarraysize($@BANK_NAME$); // bankId actually is offset in 1 for rif()
}
// Quests for Banking System, to provide poor players a way for quick bucks
// MerchantQuest(.@bankId)
function script MerchantQuest {
mes "";
// Quest Type, Quest Data, Quest Timer
.@q=getq(General_MerchantRequest);
.@q2=getq2(General_MerchantRequest);
.@q3=getq3(General_MerchantRequest);
.@id=getarg(0);
// Cooldown
if (.@q3 > gettimetick(2)) {
mesn $@BANK_NAME$[.@id];
mesq l("There are no tasks for you right now.");
mesc l("Please come back later, in %s.", FuzzyTime(.@q3));
next;
return;
}
// TODO: Submit/Abort current request
switch (.@q) {
case MERCQ_LETTER:
if (.@id == .@q2) {
mesn $@BANK_NAME$[.@id];
mesq l("Thanks for the letter! Your efforts are greatly appreciated.");
Zeny+=rand2(7, 12) * 57;
getexp 67, 9;
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+900;
return;
}
else
{
mesn $@BANK_NAME$[.@id];
mesq l("Current task: Deliver a letter to %s", $@BANK_TOWN$[.@q2]);
next;
select
l("Continue"),
l("Abort") + " ["+l("Change task")+"]";
mes "";
if (@menu == 1)
return;
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2);
}
break;
/* ***************************************** */
case MERCQ_GOODS:
.@cont=ASK_NO;
if (countitem(.@q2)) {
mesc l("Deliver %s?", getitemlink(.@q2));
.@cont=askyesno();
}
if (.@cont == ASK_YES) {
mesn $@BANK_NAME$[.@id];
mesq l("Thanks for the %s! Your efforts are greatly appreciated.", getitemlink(.@q2));
delitem .@q2, 1;
.@price = getiteminfo(.@q2, ITEMINFO_SELLPRICE);
Zeny+=.@price + rand2(12, 18) * 57;
getexp 120, 18;
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+1200;
return;
}
else
{
mesn $@BANK_NAME$[.@id];
mesq l("Current task: Purchase a(n) %s", getitemlink(.@q2));
next;
select
l("Continue"),
l("Abort") + " ["+l("Change task")+"]";
mes "";
if (@menu == 1)
return;
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2);
}
break;
/* ***************************************** */
case MERCQ_SCOUT:
// This remains challenging even at high levels, but not if you use ship.
if (.@id == .@q2) {
// TODO: Dismiss the timer, or fail if MERCHANT_ID points to nothing
// Fail 1: Merchant_ID is no longer valid
if (getunittype(MERCHANT_ID) != UNITTYPE_MOB) {
mesn $@BANK_NAME$[.@id];
mesq l("Our associate warped away... No thanks to you!");
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+900;
close;
}
// Fail 2: Merchant was left behind
if (!gettimer(0, getcharid(3), "Malindou::OnScoutPing")) {
mesn $@BANK_NAME$[.@id];
mesq l("...Did you lose our associate? Please try again.");
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+900;
close;
}
// Complete the quest
deltimer("Malindou::OnScoutPing");
mesn $@BANK_NAME$[.@id];
mesq l("Thanks for scorting our associate! Your efforts are greatly appreciated.");
Zeny+=rand2(24, 52) * 57;
getexp 360, 44;
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2)+1800; //Original: 43200
unitkill(MERCHANT_ID);
MERCHANT_ID = 0;
return;
}
else
{
mesn $@BANK_NAME$[.@id];
mesq l("Current task: Scout guild member to %s", $@BANK_TOWN$[.@q2]);
next;
select
l("Continue"),
l("Abort");
mes "";
if (@menu == 1)
return;
deltimer("Malindou::OnScoutPing");
setq General_MerchantRequest, MERCQ_NONE, 0, gettimetick(2);
unitkill(MERCHANT_ID);
MERCHANT_ID = 0;
}
break;
}
do
{
mesc l("The %s Merchant Guild has a few requests for you:", $@BANK_TOWN$[.@id]);
.@town = .@id;
while (.@town == .@id || getq(General_Narrator) < $@BANK_MINLV[.@town]) {
.@town=rand2(getarraysize($@BANK_TOWN$));
}
select
l("How does this works?"),
rif(.@town != .@id, l("★ Deliver a letter")),
l("★★ Purchase goods"),
rif(.@town != .@id, l("★★★ Scout a merchant")),
l("Sorry, I won't accept any.");
mes "";
switch (@menu) {
case 1:
mesc l("The Merchant Guild spawns multiple continents, and we can offer you a few tasks for them. Be careful as you might not be able to finish them and you'll have to abort!");
mesc l("The more stars, the harder it is.");
next;
mesc l("After completing a request, there'll be a cooldown, proportional to the difficulty.");
mesc l("You can only have one Merchant Guild request active at same time.");
next;
break;
// Deliver a letter
case 2:
mesc l("We need you to deliver this important letter to %s! Avoid the roads and bandits!", $@BANK_NAME$[.@town]);
next;
mesc l("Accept request?");
if (askyesno() == ASK_YES) {
mesc l("I'm counting on you!");
setq General_MerchantRequest, MERCQ_LETTER, .@town, gettimetick(2);
return;
}
break;
// Purchase goods
case 3:
// Most can be bought or found in Candor, Tulimshar, Nivalis or LoF
.@item=any(YellowDye, Knife, InfantryHelmet, LeatherGloves, SilkRobe, CroconutBox, FishBox, Coal, IronIngot, Aquada, Ruby, Diamond, Beer, ShortSword, LeatherShirt, ShortBow, ArrowAmmoBox, LOFCoin, TrainingWand, DesertHat, LousyMoccasins);
mesc l("The merchant guild needs %s! Purchase it and deliver at the nearest merchant guild member!", getitemlink(.@item));
next;
mesc l("Accept request?");
if (askyesno() == ASK_YES) {
mesc l("I'm counting on you!");
setq General_MerchantRequest, MERCQ_GOODS, .@item, gettimetick(2);
return;
}
break;
// Scout a guild member
case 4:
mesc l("The merchant guild needs you to scout a Guild Member to %s! Absolutely don't let they get injuried!", $@BANK_NAME$[.@town]);
next;
mesc l("Accept request?");
if (askyesno() == ASK_YES) {
mesc l("I'm counting on you!");
getmapxy(.@m$, .@x, .@y, 0);
MERCHANT_ID=monster(.@m$, .@x, .@y, "Merchant", any(GameMaster, GameMistress), 1, "Malindou::OnScoutPing", Size_Medium, 2);
// Could also be a Gladiator, as long that you can distinguish them
setunitdata(MERCHANT_ID, UDT_MAXHP, 1);
setunitdata(MERCHANT_ID, UDT_HP, 1);
setunitdata(MERCHANT_ID, UDT_DEF, 2);
setunitdata(MERCHANT_ID, UDT_MDEF, 2);
setunitdata(MERCHANT_ID, UDT_FLEE, 2);
setunitdata(MERCHANT_ID, UDT_LEVEL, 1);
// Timer which makes Merchant follow you every once in a while
@merc_map$ = getmap();
addtimer(rand2(10000), "Malindou::OnScoutPing");
setq General_MerchantRequest, MERCQ_SCOUT, .@town, gettimetick(2);
return;
}
break;
default:
return;
}
} while (true);
return;
}
// still_owed = TakeMoney (amount, reason)
// This function is meant to be used from clientversion, when a quest failed
// to take money from user.
function script TakeMoney {
.@still_owed = getarg(0);
.@reason$ = getarg(1);
.@take = min(Zeny, .@still_owed);
Zeny -= .@take;
.@still_owed -= .@take;
.@take = min(BankVault, .@still_owed);
BankVault -= .@take;
.@still_owed -= .@take;
if (.@still_owed > 0)
consoleinfo("%s STILL OWES %s for %s.", strcharinfo(0), fnum(.@leftover), .@reason$);
dispbottom col(l("%s were deducted for %s", fnum(10000-.@leftover), .@reason$), 1);
return .@still_owed;
}