ID:1677617
 
(See the best response by Pirion.)
I'm quite fond of letting the player build stuff in byond games but to be honest it usually muddies the map and it looks horrible after a while due to the players. So I'm looking to implement a house system where players can build to their liking inside the houses while leaving the outside world clean in a sense. I can do this but I'm a novice coder so I'm sure the way I do it will be inefficient, so I'm looking for advice on how I should tackle this.

I was thinking just make one 1000x1000 map and make a bunch of identical houses. Seems tedious, I'd have to set up warpers for each house as well. Should I just make the outside of the house just one object if I were to go this route?

Or I could instance one house whenever needed. Seems like the best option. Is there a better way to go about this?
Best response
swap maps for saving and loading house instances!
You can then only load the house when they need access to it.

You would never want to make identical houses manually, you would best leave this work to a datum than handles each one in the same way - using the swap map to free up when not in use.
You can create a custom map by one of the following libraries then save/load the map:
http://www.byond.com/developer/LummoxJR/SwapMaps
http://www.byond.com/developer/Forum_account/MapInstancing

Make a template map on a Z layer and copy that default layout with one of those map libraries. Have a datum reference on the client (or its mob) referring to the new map location once loaded (load when the client tries to access their house; remove the map once the client logs off. In between, the client will have the Z location of their house set to a variable. Try not to save the player or any other /mob if they are inside the house - unless you want to for some reason - but do note their last location).

Possibly even Export() the file if you plan to have multiple servers hosted? (Though you can always implement this later)


If you plan to have furniture or other display items, it may be a good idea to have one general datum for these Display items and pass on the argument to create that item to its specifics. Reduces the number of different objects you have to manually program in. Ex:
obj/Items
Display
New(atom/Location, Icon, State, Name, Density = 1)
ASSERT(Location && Icon && (State||Name) ) // Make sure that these 3-4 variables mentioned have a value

src.icon = Icon
src.icon_state = State
src.name = Name?Name :State // If the Name parameter is not defined, it is named after the icon state provided
src.density = Density // 1 by default
return ..()

....

// New(atom/Location, Icon, State, Name, Density = 1)
new /obj/Items/Display(Loc, 'turf.dmi', "leaf", "Pile of leaves", 0)

new /obj/Items/Display(Loc, 'household.dmi', "Bed") // By the above script, the item will be named the same as the icon_state since the name is not defined - which is Bed here

new /obj/Items/Display(Loc, 'plushie.dmi', Name = "Plushie") // because State was not defined, the icon_state is assumed to be ""

....

// Untested example
NPC/Storeclerk
verb/Sell()
var
list/item_list = list("Chair" = 200, "Bed" = list(1000, "comfy_bed"), "Zombie Plushy" = list(2500, "zombie", 'plushie.dmi')) // In this example, you can have "Default Name/icon_state" = price or = list(price, icon state to use)
item

for(var/Entry in item_list) // Goes through the list to update the entry name with its price
var/Value = item_list[Entry]
item_list -= Entry
if(!istype(Value, /list) // Expecting =list(price, icon_state, [icon]). If it's not a list, expected it to be = price
Value = list(Value, lowertext(Entry))
if(usr.money >= Value[1]) // If the person can afford the item, show it
item_list["[Entry] ([Value[1]])"] = Value

item = input(usr, "What item would you like to buy?", "Buy") as null|anything in item_list // as null| will add a cancel button

if(!item) return // 'as null' added a cancel button which returns null when clicked. !X checks if X is FALSE (== 0, "" or null)

var
itemVal = item_list[item]
Icon = (length(itemVal) >= 3)?itemVal[3] :'DefaultItems.dmi' // Think X?Y:Z as a compact-if() saying if(X){return Y}else{return Z}

new/obj/Items/Display(usr, icon = Icon, State = itemVal[2], Name = copytext(item, 1, findtext(item, "("))) // You do not need to do named parameters if you are entering it in sequential order