// TMW2: Moubootaur Legends scripts.
// Author:
// Jesusalva
// Description:
// Real Estate System
// Doorbell allows you to purchase mobilia, besides loading it when server starts
// Each layer can have 32 different furniture pieces because bitmask limit.
// This file is custom to every room
// ESTATE_ID → Instance ID of the Estate (required for NPCs, expire)
// ESTATE_RENTTIME → When the rent will expire
// ESTATE_MOBILIA_2 → Bitmask of mobilia currently purchased on Monster Collision (6) (Use on walls only)
// ESTATE_MOBILIA_4 → Bitmask of mobilia currently purchased on Air Collision (2)
// ESTATE_MOBILIA_8 → Bitmask of mobilia currently purchased on Water Collision (3)
// ESTATE_MOBILIA_32 → Bitmask of mobilia currently purchased on Yellow Collision (4)
// ESTATE_MOBILIA_64 → Bitmask of mobilia currently purchased on Normal Collision (1)
// ESTATE_MOBILIA_128 → Bitmask of mobilia currently purchased on Player Collision (5)
// REAL_ESTATE_CREDITS → Credits equivalent to GP the player have. Will be used first.
// The sign is the main controller
024-14,32,34,0 script Doorbell#RES_PPL NPC_NO_SPRITE,{
// Name, Layer, Price, ID, x1, y1, x2, y2,
function create_object {
array_push(.nams$, getarg(0));
array_push(.layer, getarg(1));
array_push(.price, getarg(2));
array_push(.objid, getarg(3));
array_push(.x1, getarg(4));
array_push(.y1, getarg(5));
array_push(.x2, getarg(6));
array_push(.y2, getarg(7));
return;
}
function re2_sellprice;
function re2_togglemobilia;
function re2_hasmobilia;
.id=getcharid(0);
goto L_Manage;
// Managment Menu
L_Manage:
mesc l("@@'s Apartment", strcharinfo(0));
mesc ".:: "+ l("Managment Menu") + " ::.";
.@gp=REAL_ESTATE_CREDITS+Zeny;
mesc l("Rent time available: @@", FuzzyTime(ESTATE_RENTTIME));
mesc l("Total Credits and GP: @@", format_number(.@gp));
mes "";
next;
select
l("Leave"),
l("Manage Furniture"),
l("Reload NPC Data");
switch (@menu) {
case 1:
close;
break;
case 2:
goto L_Furniture;
break;
case 3:
addtimer2(150, instance_npcname("NPCs#RES_PPL")+"::OnReload");
close;
break;
}
goto L_Manage;
L_Furniture:
mesc l("@@'s Estate", strcharinfo(0));
mesc ".:: "+ l("Furniture Menu") + " ::.";
.@gp=REAL_ESTATE_CREDITS+Zeny;
mesc l("Total Credits and GP: @@", format_number(.@gp));
next;
select
l("Finish"),
l("Manage Beds"),
l("Manage Utilities"),
l("Manage Luxury furniture"),
l("Manage Decoration"),
l("Manage Chairs"),
l("Manage Paintings");
mes "";
switch (@menu) {
case 1:
goto L_Manage;
break;
case 2:
mesc ".:: "+ l("Beds") + " ::.", 3;
@re_col=RES_OBJECTS;
break;
case 3:
mesc ".:: "+ l("Utilities") + " ::.", 3;
@re_col=RES_UTILITIES;
break;
case 4:
mesc ".:: "+ l("Luxury furniture") + " ::.", 3;
@re_col=RES_LUXURY;
break;
case 5:
mesc ".:: "+ l("Decoration") + " ::.", 3;
@re_col=RES_DECORATION;
break;
case 6:
mesc ".:: "+ l("Chairs") + " ::.", 3;
@re_col=RES_SITTABLE;
break;
case 7:
mesc ".:: "+ l("Paintings") + " ::.", 3;
@re_col=RES_WALLDECORATION;
break;
}
// L_ContinuousLoop
// Requires the following variables:
// @re_col
// Target Collision ID
L_ContinuousLoop:
deletearray @valid_ids;
// Create a second array (@valid_ids) with the ID of objects within @re_col group
for (.@i=0; .@i < getarraysize(.layer); .@i++) {
//debugmes "Found object ID %d named %s on layer %s coords (%d,%d) - Looking for layer %d", .@i, .nams$[.@i], .layer[.@i], .x1[.@i], .y1[.@i], @re_col;
if (.layer[.@i] == @re_col)
array_push(@valid_ids, .@i);
}
//debugmes "Found %d valid objects", getarraysize(@valid_ids);
// Create the menu with @valid_ids - Check if you already have the item to decide if you're buying or selling
@menuentries$="Finish:";
for (.@j=0; .@j < getarraysize(@valid_ids); .@j++) {
.@i=@valid_ids[.@j];
if (re2_hasmobilia(.id, .layer[.@i], .objid[.@i]))
@menuentries$+=l("Sell ")+.nams$[.@i]+l(" for ") + format_number( re2_sellprice(.id,.price[.@i]) ) +":";
else
@menuentries$+=l("Purchase ")+.nams$[.@i]+(" for ") + format_number( .price[.@i] )+":";
}
select (@menuentries$);
mes "";
// First option to return to previous menu
if (@menu == 1)
goto L_Furniture;
// Otherwise, we know then that (@menu-2) is the ID in @valid_ids
// So we save .@id with the correct ID in object arrays.
// We also calculate how much aggregated money you have.
.@id=@valid_ids[@menu-2];
.@gp=REAL_ESTATE_CREDITS+Zeny;
if (re2_hasmobilia(.id, .layer[.@id], .objid[.@id])) {
// If you have the mobilia, you're selling it for Mobiliary Credits
delcells realestate_cellname(.id, .@id);
re2_togglemobilia(.id, .layer[.@id], .objid[.@id]);
addtimer2(150, "NPCs#RES_PPL::OnReload");
REAL_ESTATE_CREDITS+=re2_sellprice(.id,.price[.@i]);
mesc l("Sale successful!");
next;
} else {
// Else, you're buying it, so we must check if you have the moolah first
.@price=.price[.@id];
if (.@gp > .@price) {
realestate_payment(.@price);
setcells "ples@"+getcharid(0), .x1[.@id], .y1[.@id], .x2[.@id], .y2[.@id], .layer[.@id], realestate_cellname(.id, .@id);
areatimer("ples@"+getcharid(0), .x1[.@id], .y1[.@id], .x2[.@id], .y2[.@id], 10, "::OnSlide");
re2_togglemobilia(.id, .layer[.@id], .objid[.@id]);
addtimer2(150, "NPCs#RES_PPL::OnReload");
mesc l("Purchase successful!");
next;
} else {
mesc l("Not enough funds!");
next;
}
}
// This loops forever
goto L_ContinuousLoop;
// When using setcells() a player could get trapped!
// This label will slide the player back to entrance, which should be a safe spot
OnSlide:
slide 33, 33;
end;
OnInit:
.sex = G_OTHER;
.distance = 3;
// Arrays
// We go element by element on the array building the menu
.nams$="";
.layer=0;
.price=0;
.objid=0;
.x1=0;
.y1=0;
.x2=0;
.y2=0;
// Furniture Settings
// Name, Collision Layer, Price, ID, x1, y1, x2, y2
// For Collision Layer, see constants.conf ("Real Estate Collisions")
create_object("Placeholder" ,99,999999,99999, 99, 99, 99, 99);
create_object("Red Bed" , 5, 5000, 1, 25, 29, 26, 32);
create_object("Blue Bed" , 5, 5000, 2, 27, 29, 28, 32);
create_object("Wardrobe" , 1, 7000, 1, 25, 26, 26, 26);
create_object("Cauldron" , 1, 5000, 2, 28, 27, 29, 27);
create_object("Empty Shelf" , 1, 2000, 4, 34, 26, 34, 26);
create_object("Bookshelf" , 1, 2000, 8, 35, 26, 35, 26);
create_object("Bottle Shelf", 1, 2000, 16, 36, 26, 36, 26);
create_object("Beer Shelf" , 1, 2000, 32, 37, 26, 37, 26);
create_object("Piano" , 3, 10000, 1, 31, 26, 33, 26);
create_object("Right Desk" , 2, 5000, 2, 36, 30, 38, 32);
create_object("Right Chair" , 4, 2000, 2, 37, 29, 37, 29);
create_object("Painting 01" , 6, 3000, 1, 27, 23, 27, 23);
create_object("Painting 02" , 6, 3000, 2, 29, 24, 29, 24);
create_object("Painting 03" , 6, 3000, 4, 32, 23, 32, 23);
create_object("Painting 04" , 6, 3000, 8, 35, 23, 35, 23);
end;
OnReload:
// Load Mobilia already existing
debugmes "[REAL ESTATE] Now loading mobilia";
for (.@i=0; .@i < getarraysize(.layer); .@i++) {
switch (.layer[.@i]) {
case 1:
if (ESTATE_MOBILIA_64 & .objid[.@i])
array_push(.valid_ids, .@i);
break;
case 2:
if (ESTATE_MOBILIA_4 & .objid[.@i])
array_push(.valid_ids, .@i);
break;
case 3:
if (ESTATE_MOBILIA_8 & .objid[.@i])
array_push(.valid_ids, .@i);
break;
case 4:
if (ESTATE_MOBILIA_32 & .objid[.@i])
array_push(.valid_ids, .@i);
break;
case 5:
if (ESTATE_MOBILIA_128 & .objid[.@i])
array_push(.valid_ids, .@i);
break;
case 6:
if (ESTATE_MOBILIA_2 & .objid[.@i])
array_push(.valid_ids, .@i);
break;
default:
break;
}
}
debugmes "Found %d valid objects", getarraysize(.valid_ids);
for (.@j=0; .@j < getarraysize(.valid_ids); .@j++) {
.@id=.valid_ids[.@j];
setcells "ples@"+getcharid(0), .x1[.@id], .y1[.@id], .x2[.@id], .y2[.@id], .layer[.@id], realestate_cellname(.id, .@id);
}
deletearray .valid_ids;
end;
// Additional crap needed because instance system
// Previously declared functions here. Copy paste from functions/, but without $.
function re2_sellprice
{
.@timeleft=ESTATE_RENTTIME-gettimetick(2); // Number of seconds
.@daysleft=.@timeleft/86400; // Number of days left of rent
.@weeksleft=.@timeleft/604800; // Number of weeks left of rent
return (getarg(1)/max(1, 6-.@weeksleft)) - max(0, 45-.@daysleft);
}
function re2_togglemobilia
{
switch (getarg(1)) {
case 1:
ESTATE_MOBILIA_64 = ESTATE_MOBILIA_64 ^ getarg(2); break;
case 2:
ESTATE_MOBILIA_4 = ESTATE_MOBILIA_4 ^ getarg(2); break;
case 3:
ESTATE_MOBILIA_8 = ESTATE_MOBILIA_8 ^ getarg(2); break;
case 4:
ESTATE_MOBILIA_32 = ESTATE_MOBILIA_32 ^ getarg(2); break;
case 5:
ESTATE_MOBILIA_128 = ESTATE_MOBILIA_128 ^ getarg(2); break;
case 6:
ESTATE_MOBILIA_2 = ESTATE_MOBILIA_2 ^ getarg(2); break;
default:
debugmes("[ERROR] [CRITICAL] [REAL ESTATE]: Object %d have Invalid Collision Type: %d (must range 1~6)", getarg(2), getarg(1)); break;
}
if (getarg(3, "error") != "error") { addtimer2(150, "NPCs#RES_PPL::OnReload"); }
return;
}
function re2_hasmobilia
{
switch (getarg(1)) {
case 1:
return ESTATE_MOBILIA_64 & getarg(2);
case 2:
return ESTATE_MOBILIA_4 & getarg(2);
case 3:
return ESTATE_MOBILIA_8 & getarg(2);
case 4:
return ESTATE_MOBILIA_32 & getarg(2);
case 5:
return ESTATE_MOBILIA_128 & getarg(2);
case 6:
return ESTATE_MOBILIA_2 & getarg(2);
default:
debugmes("[ERROR] [CRITICAL] [REAL ESTATE]: Object %d have Invalid Collision Type: %d (must range 1~6)", getarg(2), getarg(1)); return false;
}
return false;
}
}