// TMW-2 Script
// Author:
// Jesusalva
// Description:
// Nivalis shopkeeper & forge master. He deals with the equipment which Nicholas,
// Silversmith and Nahred doesn't works with.
// TODO FIXME: Rewrite Meltdown to don't allow if countitem(id) > 1
// Also, use deletion by ID (reliable).
// delitemidx is HOPELESSY BROKEN
020-5,31,25,0 script Bracco NPC_M_SHOPKEEPER,{
goto L_Start;
// NewMeltdown( item )
// Meltdown the item for realz
function NewMeltdown {
.@const$ = data_to_string(getarg(0));
// Shady code by gumi
if (startswith(.@const$, "Craft")) {
// infer the item constant from the craft constant
.@recipe = getarg(0);
.@item = string_to_data(substr(.@const$, 5, getstrlen(.@const$) - 1));
} else {
// infer the craft constant from the item constant
.@recipe = string_to_data(sprintf("Craft%s", .@const$));
.@item = getarg(0);
}
if (.@item <= 0) {
// target item not found
consolebug("ERROR, INVALID ITEM ID DETECTED at NewMeltdown");
return 0;
}
// More shady code by gumi
for (.@inv = 0; .@inv < 9; ++.@inv) {
.@size = getcraftrecipe(.@recipe, .@inv, .@qty[0], .@item_id[0]);
if (.@size < 0) {
if (.@size == -1) {
// recipe does not exist
consolebug("ERROR, INVALID RECIPE DETECTED at NewMeltdown");
return 0;
break;
}
// inventory does not exist
consolewarn("INVENTORY ERROR at NewMeltdown");
return 0;
break;
}
// More shady code
for (.@it = 0; .@it < .@size; ++.@it) {
.@recipe_item = .@item_id[.@it];
.@recipe_qty = .@qty[.@it];
if (.@recipe_item <= 0) {
break;
}
// "Unique" items are never refunded
if (.@recipe_qty <= 1) continue;
// Coal is NEVER refunded
if (.@recipe_item == Coal) continue;
// TODO: Maybe give Coal as (item level / 20)?
// New rates
.@mini = .@recipe_qty * 3 / 10 + 1; // Minimum: 30% + 1
.@maxi = .@recipe_qty / 2; // Maximum: 50% + 1
// Some sanitizing (should never happen but you can never be sure)
// (Could only happen if qty == 1, which is skipped)
if (.@mini > .@maxi)
.@maxi = .@mini;
.@ammo = rand2(.@mini, .@maxi);
if (.@ammo < 1) {
.@ammo = 1;
consolebug("AMOUNT ERROR at NewMeltdown: %s", getitemname(.@recipe_item));
}
getitem .@recipe_item, .@ammo;
mesc l("* Acquired @@ @@!", .@ammo, getitemlink(.@recipe_item));
}
}
return .@item;
}
// Meltdown( item, price )
function Meltdown {
if (countitem(getarg(0)) != 1) {
mesc l("Wait, if you try to melt more than one item, manaplus will get buggy."), 1;
mesc l("Please try again later!"), 1;
close;
}
.@index=getarg(0);
.@price=getarg(1, getiteminfo(.@item, ITEMINFO_SELLPRICE)/20);
.@price=POL_AdjustPrice(.@price);
// Confirmation
mesn;
mesc l("Really melt down your @@? It'll cost you @@ GP. This action cannot be undone!", getitemlink(.@index), .@price), 1;
next;
if (askyesno() == ASK_NO || Zeny < .@price)
return;
// Report it was done
mesc l("@@ melt down your @@...", .name$, getitemlink(.@index)), 2;
delitem .@index, 1;
POL_PlayerMoney(.@price);
// TODO: Inventoryplace.
// Add Items (if inventory is full, your fault and not mine)
NewMeltdown(.@index);
@indexisbroken=true;
return;
}
// MassMeltdown( item, price{, override} )
function MassMeltdown {
.@id=getarg(0);
.@price=getarg(1);
.@overid=getarg(2, 0);
.@total=countitem(.@id);
if (!.@total) {
mesc l("You don't have any %s.", getitemlink(.@id)), 1;
mesc l("Please try again later!"), 1;
next;
return;
}
.@price=POL_AdjustPrice(.@price);
// Skip Confirmation
mesn;
mesc l("Really melt down all your @@? It'll cost you @@ GP each. This action cannot be undone!", getitemlink(.@id), .@price), 1;
next;
if (askyesno() == ASK_NO || Zeny < .@price)
return;
delinventorylist();
getinventorylist();
debugmes "Requested to melt down %d %s (%s)", .@total, getitemname(.@id), strcharinfo(0);
freeloop(true);
.@cnt = 0;
for (.@index=0; .@index < @inventorylist_count; .@index++) {
.@x=@inventorylist_id[.@index];
if (.@x == getarg(0) && Zeny >= .@price) {
.@cnt += 1;
//delitemidx .@index, 1;
POL_PlayerMoney(.@price);
// Report it was done
mesc l("@@ melt down your @@...", .name$, getitemlink(.@x)), 2;
// Really melt it down
if (.@overid < 1) {
NewMeltdown(getarg(0));
} else {
// Override system (no recipe)
if (.@overid == SilverMirror)
.@elv = rand2(30);
else
.@elv = getiteminfo(.@id, ITEMINFO_ELV);
.@ammo = any(
(.@elv < 12 ? 0 : 1),
(.@elv < 7 ? 0 : 1),
(.@elv < 5 ? 0 : 1),
(.@elv < 3 ? 0 : 1),
1,
(.@elv < 12 ? 1 : 2),
(.@elv < 15 ? 1 : 2)
);
if (.@ammo) {
getitem .@overid, .@ammo;
mesc l("* Acquired @@ @@!", .@ammo, getitemlink(.@overid));
}
}
}
}
freeloop(false);
// TODO: Put this in a timer so it can't be exploited
// For now, we'll produce logs so I can go after cheaters with a banhammer
delitem .@id, .@total; // Delete first, no refunds
if (.@cnt == .@total)
debugmes "Success melting down %d %s (%s)", .@total, getitemname(.@id), strcharinfo(0);
else
debugmes "Failed melting down (%d/%d) %s (%s)", .@cnt, .@total, getitemname(.@id), strcharinfo(0);
@indexisbroken=true;
return;
}
// blacksmith_create( BaseItem1, Amount, BaseItem2, Amount, PrizeItem, Price )
function blacksmith_create {
.@base1=getarg(0);
.@amon1=getarg(1);
.@base2=getarg(2);
.@amon2=getarg(3);
.@prize=getarg(4);
.@price=getarg(5);
.@price=POL_AdjustPrice(.@price);
mesn;
mesq l("Do you want to craft @@? For that I will need:", getitemlink(.@prize));
mesc l("@@/@@ @@", countitem(.@base1), .@amon1, getitemlink(.@base1));
mesc l("@@/@@ @@", countitem(.@base2), .@amon2, getitemlink(.@base2));
mesc l("@@/@@ GP", format_number(Zeny), format_number(.@price));
select
l("Yes"),
l("No");
if (@menu == 2)
return;
if (countitem(.@base1) >= .@amon1 &&
countitem(.@base2) >= .@amon2 &&
Zeny >= .@price) {
inventoryplace .@prize, 1;
delitem .@base1, .@amon1;
delitem .@base2, .@amon2;
POL_PlayerMoney(.@price);
getitem .@prize, 1;
.@xp=getiteminfo(.@base1, ITEMINFO_SELLPRICE)*.@amon1+getiteminfo(.@base2, ITEMINFO_SELLPRICE)*.@amon2;
.@xp=.@xp*2/3;
getexp .@xp, rand(1,10);
mes "";
mesn;
mesq l("Many thanks! Come back soon.");
} else {
speech S_FIRST_BLANK_LINE,// | S_LAST_NEXT,
l("You don't have enough material, sorry.");
}
return;
}
// Start
L_Start:
mesn;
mesq l("Welcome to my fine establishment!");
mes "";
select
l("Trade"),
l("I'm actually looking for an item forged!"),
l("I would like an item melted!"),
l("I would like all Knifes and Daggers on me melted!"),
l("Leave");
mes "";
if (@menu == 2)
goto L_Forge;
if (@menu == 3)
goto L_Meltdown;
if (@menu == 4)
goto L_Irreversible;
closedialog;
if (@menu == 1) {
npcshopattach(.name$);
shop .name$;
}
goodbye;
close;
// Note: the prices are absurd atm, but hey hey, every single one of them are cap items currently
L_Forge:
mesn;
mesq l("Well, if you want warrior craft, perhaps you should look for @@ or @@.", l("Nicholas"), l("Nahrec"));
mes "";
select
l("Nothing, sorry!"),
l("I want leather armbands!"),
l("I want copper armbands!"),
l("I want iron armbands!");
mes "";
switch (@menu) {
case 1:
close; break;
case 2:
blacksmith_create(LeatherPatch, 40, TitaniumIngot, 1, Armbands, 6500);
break;
case 3:
blacksmith_create(CopperIngot, 10, Coal, 30, CopperArmbands, 11000);
break;
case 4:
blacksmith_create(IronIngot, 40, Coal, 80, IronArmbands, 21000);
break;
}
goto L_Forge;
L_Irreversible:
mesn;
mesq l("Quite the guts! The price is taxed individually, if you run out of GP it is your loss.");
mesc l("Are you sure?"), 1;
next;
menuint
l("I'm not."), 0,
l("Rusty Knife"), RustyKnife,
l("Small Knife"), SmallKnife,
l("Knife"), Knife,
l("Sharp Knife"), SharpKnife,
l("Dagger"), Dagger;
mes "";
.@it=@menuret;
switch (@menuret) {
// Copy Paste from normal Meltdown
case RustyKnife:
MassMeltdown(.@it, 15, Coal);
break;
case SmallKnife:
MassMeltdown(.@it, 15, IronOre);
break;
case Knife:
MassMeltdown(.@it, 25, IronOre);
break;
case SharpKnife:
MassMeltdown(.@it, 50, IronOre);
break;
case Dagger:
MassMeltdown(.@it, 100, IronOre);
break;
// MISSING
}
close;
L_Meltdown:
mesn;
mesc l("What item do you want to melt down? This is irreversible, and may return some ingots to you, but there is no way to tell how many you'll receive!"), 1;
mesc l("Each item have it's own tax.");
.@id=requestitem();
if (.@id <= 0)
close;
mes "";
// Returns 30~50% of invested ingots, rounded down. Never returns Coal.
switch (.@id) {
// Special Exceptions
case SilverMirror:
Meltdown(.@id, 500, SilverOre); // Exception
break;
case RustyKnife:
Meltdown(.@id, 15, Coal); // Exception
break;
case SmallKnife:
Meltdown(.@id, 15, IronOre); // Exception
break;
case Knife:
Meltdown(.@id, 25, IronOre); // Exception
break;
case SharpKnife:
Meltdown(.@id, 50, IronOre); // Exception
break;
case Dagger:
Meltdown(.@id, 100, IronOre); // Exception
break;
case GoldenRing:
Meltdown(.@id, 1500, GoldPieces); // Exception
break;
default:
if (!Meltdown(.@id)) {
mesn;
mesq l("I cannot melt this. I only melt down equipment, and not everything I know how to!");
next;
}
break;
}
//mesc l("Melt something else?");
//if (askyesno() == ASK_NO)
// close;
//mes "";
//goto L_Meltdown;
mesc l("Thanks for using my services!");
close;
OnInit:
.@npcId = getnpcid(.name$);
setunitdata(.@npcId, UDT_HEADTOP, NPCEyes);
setunitdata(.@npcId, UDT_HEADMIDDLE, TneckSweater);
setunitdata(.@npcId, UDT_HEADBOTTOM, RaidTrousers);
setunitdata(.@npcId, UDT_WEAPON, FurBoots);
setunitdata(.@npcId, UDT_HAIRSTYLE, 26);
setunitdata(.@npcId, UDT_HAIRCOLOR, 2);
sleep(SHOPWAIT);
tradertype(NST_MARKET);
sellitem BritShield, -1, 1;
sellitem BladeShield, -1, 1;
sellitem MiereCleaver, -1, 1;
sellitem ShortSword, -1, 1;
sellitem LeatherShirt, -1, 1;
sellitem LeatherShield, 5000, 1;
sellitem ShortBow, -1, 1;
sellitem ArrowAmmoBox,-1,rand(8,12);
sellitem IronAmmoBox,-1,rand(3,5);
npcsit;
.sex = G_MALE;
.distance = 5;
end;
OnWed0000:
OnThu0400:
OnFri0800:
OnSat1200:
OnSun1600:
OnMon2000:
restoreshopitem BritShield, 1;
restoreshopitem BladeShield, 1;
restoreshopitem MiereCleaver, 1;
restoreshopitem ShortSword, 1;
restoreshopitem LeatherShirt, 1;
restoreshopitem LeatherShield, 5000, 1;
restoreshopitem ShortBow, 1;
restoreshopitem ArrowAmmoBox,rand(8,12);
restoreshopitem IronAmmoBox,rand(3,5);
end;
// Pay your taxes!
OnBuyItem:
debugmes("Purchase confirmed");
PurchaseTaxes();
end;
OnSellItem:
debugmes("Sale confirmed");
SaleTaxes();
end;
}