Skip to content
5,313 changes: 5,087 additions & 226 deletions _maps/map_files/debug/minimal.dmm

Large diffs are not rendered by default.

2,152 changes: 2,152 additions & 0 deletions _maps/map_files/vanderlin/house_templates/noble_blue.dmm

Large diffs are not rendered by default.

1,704 changes: 1,704 additions & 0 deletions _maps/map_files/vanderlin/house_templates/noble_red.dmm

Large diffs are not rendered by default.

1,611 changes: 1,611 additions & 0 deletions _maps/map_files/vanderlin/house_templates/noble_yellow.dmm

Large diffs are not rendered by default.

17,509 changes: 7,287 additions & 10,222 deletions _maps/map_files/vanderlin/vanderlin.dmm

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/signals_factions.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define COMSIG_NOBLE_FACTION_SIZE_CHANGED "noble_faction_size_changed"
#define COMSIG_NOBLE_FACTION_ASPIRANT_ELIGIBLE "noble_faction_aspirant_eligible"
3 changes: 2 additions & 1 deletion code/__DEFINES/traits/definitions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai

/// Given to a mob that can throw to make them not able to throw
#define TRAIT_NO_THROWING "no_throwing"

/// Granted to the Aspirant, lets them see noble_faction hover info on faction heads.
#define TRAIT_ASPIRANT_INSIGHT "aspirant_insight"
/// Hides the SSD indicator. Used with scrying.
#define TRAIT_NOSSDINDICATOR "nossdindicator"
/// Instant grabs on someone else.
Expand Down
10 changes: 10 additions & 0 deletions code/_globalvars/lists/factions.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
GLOBAL_LIST_EMPTY(guilds) // keyed by guild id (a type path or string, see below)

/proc/get_or_create_guild(datum/guild/guild_type)
if(!guild_type)
return null
. = GLOB.guilds[guild_type]
if(!.)
. = new guild_type

GLOBAL_LIST_EMPTY(current_noble_factions)
39 changes: 0 additions & 39 deletions code/controllers/subsystem/economy.dm

This file was deleted.

59 changes: 59 additions & 0 deletions code/controllers/subsystem/properties/controller.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/datum/property_controller
var/obj/effect/landmark/house_spot/linked_property
var/list/allowed_list = list()

var/property_bounds_minx
var/property_bounds_miny
var/property_bounds_minz
var/property_bounds_maxx
var/property_bounds_maxy
var/property_bounds_maxz

/datum/property_controller/New(obj/effect/landmark/house_spot/property)
linked_property = property
if(!property)
return

var/turf/start_turf = get_turf(property)
if(!start_turf)
return

property_bounds_minx = start_turf.x
property_bounds_miny = start_turf.y
property_bounds_minz = start_turf.z
property_bounds_maxx = start_turf.x + property.template_x - 1
property_bounds_maxy = start_turf.y + property.template_y - 1
property_bounds_maxz = start_turf.z + property.template_z - 1

/datum/property_controller/proc/check_access(mob/user)
if(!linked_property || !user || !user.client)
return FALSE

// Owner has access
if(user.ckey == linked_property.owner_ckey)
return TRUE

// Check allow list
if(user.ckey in allowed_list)
return TRUE

return FALSE

/datum/property_controller/proc/is_in_property_bounds(atom/A)
if(!linked_property)
return FALSE

var/turf/T = get_turf(A)
if(!T)
return FALSE

return (T.x >= property_bounds_minx && T.x <= property_bounds_maxx && \
T.y >= property_bounds_miny && T.y <= property_bounds_maxy && \
T.z >= property_bounds_minz && T.z <= property_bounds_maxz)

/datum/property_controller/proc/add_access(ckey)
if(!(ckey in allowed_list))
allowed_list += ckey

/datum/property_controller/proc/remove_access(ckey)
allowed_list -= ckey
67 changes: 67 additions & 0 deletions code/controllers/subsystem/properties/landmarks.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/obj/effect/abstract/property_noop
invisibility = INVISIBILITY_ABSTRACT
var/property_id

/obj/effect/landmark/house_spot
var/property_id = "" // Unique identifier for this specific property location
var/save_id = "" // Template type identifier (multiple properties can share same save_id)
var/owner_ckey = null
var/owner_property_slot = null // Which slot/ID the owner is using for this property

var/template_x = 0
var/template_y = 0
var/template_z = 1

var/datum/map_template/default_template

/// If set, only players currently assigned one of these job titles can claim this property. Null/empty = no restriction.
var/list/required_jobs = null

/obj/effect/landmark/house_spot/Initialize(mapload)
. = ..()
SShousing.register_property(src)

/obj/effect/landmark/house_spot/Destroy(force)
default_template = null
return ..()

/obj/effect/landmark/house_spot/proc/check_job_requirement(mob/user)
if(!length(required_jobs))
return TRUE
if(!user?.mind?.assigned_role)
return FALSE
if(is_type_in_list(SSjob.GetJob(user.job), required_jobs))
return TRUE
return FALSE

/obj/effect/landmark/house_spot/proc/get_required_jobs_string()
if(!length(required_jobs))
return ""
var/list/titles = list()
for(var/datum/job/job as anything in required_jobs)
titles += initial(job.title)
return jointext(titles, ", ")

/obj/effect/landmark/house_spot/proc/on_claim(mob/user)
return

/obj/effect/landmark/house_spot/noble
required_jobs = list(/datum/job/minor_noble)
var/datum/noble_faction/faction_type

/obj/effect/landmark/house_spot/noble/Destroy(force)
. = ..()
LAZYREMOVE(GLOB.noble_points, src)

/obj/effect/landmark/house_spot/noble/Initialize(mapload)
. = ..()
if(!ispath(faction_type) && !isnull(faction_type))
faction_type = text2path(faction_type) //someone map editting
LAZYADD(GLOB.noble_points, src)

/obj/effect/landmark/house_spot/noble/on_claim(mob/user)
user.create_new_faction(faction_type)
LAZYREMOVE(GLOB.noble_points, src)

/mob/proc/create_new_faction(datum/noble_faction/faction_type)
new faction_type(src)
124 changes: 124 additions & 0 deletions code/controllers/subsystem/properties/property_sign.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@

/obj/structure/sign/property_sign
name = "Property Sign"
desc = "A sign for property management."
icon = 'icons/roguetown/misc/structure.dmi'
icon_state = "questnoti"

var/obj/effect/landmark/house_spot/linked_property

/obj/structure/sign/property_sign/proc/setup_property_link(obj/effect/landmark/house_spot/property)
linked_property = property

/obj/structure/sign/property_sign/proc/check_other_players(mob/user)
if(!linked_property)
return FALSE

var/turf/start_turf = get_turf(linked_property)
if(!start_turf)
return FALSE

var/minx = start_turf.x
var/miny = start_turf.y
var/minz = start_turf.z
var/maxx = minx + linked_property.template_x - 1
var/maxy = miny + linked_property.template_y - 1
var/maxz = minz + linked_property.template_z - 1

for(var/turf/T in block(locate(minx, miny, minz), locate(maxx, maxy, maxz)))
for(var/mob/M in T.contents)
if(M == user)
continue
if(M.client)
return TRUE
return FALSE

/obj/structure/sign/property_sign/claim
var/claimed = FALSE

/obj/structure/sign/property_sign/claim/attack_hand(mob/user)
. = ..()
if(!user.client || !linked_property)
return

// If already claimed by this user, allow saving
if(linked_property?.owner_ckey == user.ckey)
save_property_design(user)
return

// Check if already claimed
if(SShousing.temporary_claims[linked_property.property_id])
to_chat(user, span_warning("This property is already claimed!"))
return

// Check job restriction
if(!linked_property.check_job_requirement(user))
to_chat(user, span_warning("Only the following can claim this property: [linked_property.get_required_jobs_string()]"))
return

// Check if user already owns a property with this save_id
if(SShousing.player_owns_save_id(user.ckey, linked_property.save_id))
to_chat(user, span_warning("You already have a property of this type!"))
return

if(check_other_players(user))
to_chat(user, span_warning("Cannot claim while others are present!"))
return

// Show slot selection interface
show_slot_selection(user)

/obj/structure/sign/property_sign/claim/proc/show_slot_selection(mob/user)
if(!user || !user.client || !linked_property)
return

var/list/available_slots = SShousing.get_player_property_slots(user.ckey, linked_property.save_id)
var/list/options = list()

// Add existing slots
for(var/slot in available_slots)
options["Load Design [slot]"] = slot

//create new option
var/next_slot = 1
if(length(available_slots) > 0)
next_slot = available_slots[length(available_slots)] + 1
options["Create New Design ([next_slot])"] = next_slot

options["Cancel"] = null

var/choice = input(user, "Select a property design slot:", "Property Claim") as null|anything in options
if(!choice || options[choice] == null)
return

var/selected_slot = options[choice]

if(check_other_players(user))
to_chat(user, span_warning("Someone entered the area!"))
return

if(SShousing.claim_temporary(linked_property, user, selected_slot))
claimed = TRUE
name = "Claimed Property (Slot [selected_slot])"
desc = "Click to save your current design to slot [selected_slot]."
to_chat(user, span_notice("Property claimed with design slot [selected_slot]! Click again to save changes."))
else
to_chat(user, span_warning("Failed to claim property!"))

/obj/structure/sign/property_sign/claim/proc/save_property_design(mob/user)
if(!linked_property || linked_property.owner_ckey != user.ckey)
return

var/slot = linked_property.owner_property_slot
if(!slot)
to_chat(user, span_warning("No slot assigned to this property!"))
return

var/confirm = tgui_alert(user, "Save the current state to design slot [slot]?", "Save Property", list("Yes", "No"))
if(confirm != "Yes")
return

if(SShousing.save_property(linked_property, user.ckey, slot))
to_chat(user, span_notice("Property saved successfully to slot [slot]!"))
else
to_chat(user, span_warning("Failed to save property!"))
Loading
Loading