-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathareas.dm
248 lines (216 loc) · 8.76 KB
/
areas.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#define BP_MAX_ROOM_SIZE 300
GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/engineering, \
/area/engine/supermatter, \
/area/engine/atmos/engine, \
/area/ai_monitored/turret_protected/ai))
// Gets an atmos isolated contained space
// Returns an associative list of turf|dirs pairs
// The dirs are connected turfs in the same space
// break_if_found is a typecache of turf/area types to return false if found
// Please keep this proc type agnostic. If you need to restrict it do it elsewhere or add an arg.
/proc/detect_room(turf/origin, list/break_if_found = list(), max_size=INFINITY)
if(origin.blocks_air)
return list(origin)
. = list()
var/list/checked_turfs = list()
var/list/found_turfs = list(origin)
while(length(found_turfs))
var/turf/sourceT = found_turfs[1]
found_turfs.Cut(1, 2)
var/dir_flags = checked_turfs[sourceT]
for(var/dir in GLOB.alldirs)
if(length(.) > max_size)
return
if(dir_flags & dir) // This means we've checked this dir before, probably from the other turf
continue
var/turf/checkT = get_step(sourceT, dir)
if(!checkT)
continue
checked_turfs[sourceT] |= dir
checked_turfs[checkT] |= REVERSE_DIR(dir)
.[sourceT] |= dir
.[checkT] |= REVERSE_DIR(dir)
if(break_if_found[checkT.type] || break_if_found[checkT.loc.type])
return FALSE
var/static/list/cardinal_cache = list("[NORTH]"=TRUE, "[EAST]"=TRUE, "[SOUTH]"=TRUE, "[WEST]"=TRUE)
if(!cardinal_cache["[dir]"] || !TURFS_CAN_SHARE(sourceT, checkT))
continue
found_turfs += checkT // Since checkT is connected, add it to the list to be processed
/proc/create_area(mob/creator, new_area_type = /area)
// Passed into the above proc as list/break_if_found
var/static/list/area_or_turf_fail_types = typecacheof(list(
/turf/open/space,
/area/shuttle,
))
// Ignore these areas and dont let people expand them. They can expand into them though
var/static/list/blacklisted_areas = typecacheof(list(
/area/space,
))
var/error = ""
var/list/turfs = detect_room(get_turf(creator), area_or_turf_fail_types, BP_MAX_ROOM_SIZE*2)
var/turf_count = length(turfs)
if(!turf_count)
error = "The new area must be completely airtight and not a part of a shuttle."
else if(turf_count > BP_MAX_ROOM_SIZE)
error = "The room you're in is too big. It is [turf_count >= BP_MAX_ROOM_SIZE *2 ? "more than 100" : ((turf_count / BP_MAX_ROOM_SIZE)-1)*100]% larger than allowed."
if(error)
to_chat(creator, span_warning(error))
return
var/list/apc_map = list()
var/list/areas = list("New Area" = new_area_type)
for(var/i in 1 to turf_count)
var/turf/the_turf = turfs[i]
var/area/place = get_area(the_turf)
if(blacklisted_areas[place.type])
continue
if(!place.requires_power || (place.area_flags & NOTELEPORT) || place.hidden)
continue // No expanding powerless rooms etc
if(!TURF_SHARES(the_turf)) // No expanding areas of walls/something blocking this turf because that defeats the whole point of them used to separate areas
continue
if(length(apc_map) > 1) // When merging 2 or more areas make sure we arent merging their apc into 1 area
to_chat(creator, span_warning("Multiple APC's detected in the vicinity. only 1 is allowed."))
return
areas[place.name] = place
var/area_choice = tgui_input_list(creator, "Choose an area to expand or make a new area", "Area Expansion", areas)
if(isnull(area_choice))
to_chat(creator, span_warning("No choice selected. The area remains undefined."))
return
area_choice = areas[area_choice]
var/area/newA
var/area/oldA = get_area(get_turf(creator))
if(!isarea(area_choice))
var/str = tgui_input_text(creator, "New area name", "Blueprint Editing", max_length = MAX_NAME_LEN)
if(!str)
return
newA = new area_choice
newA.setup(str)
newA.has_gravity = oldA.has_gravity
require_area_resort() //new area registered. resort the names
else
newA = area_choice
//we haven't done anything. let's get outta here
if(newA == oldA)
to_chat(creator, span_warning("Selected choice is same as the area your standing in. No area changes were requested."))
return
/**
* A list of all machinery tied to an area along with the area itself. key=area name,value=list(area,list of machinery)
* we use this to keep track of what areas are affected by the blueprints & what machinery of these areas needs to be reconfigured accordingly
*/
var/area/affected_areas = list()
for(var/turf/the_turf as anything in turfs)
var/area/old_area = the_turf.loc
//keep rack of all areas affected by turf changes
affected_areas[old_area.name] = old_area
//move the turf to its new area and unregister it from the old one
the_turf.change_area(old_area, newA)
//inform atoms on the turf that their area has changed
for(var/atom/stuff as anything in the_turf)
//unregister the stuff from its old area
SEND_SIGNAL(stuff, COMSIG_EXIT_AREA, old_area)
SEND_SIGNAL(stuff, COMSIG_ENTER_AREA, newA)
newA.reg_in_areas_in_z()
if(!isarea(area_choice) && newA.static_lighting)
newA.create_area_lighting_objects()
//convert map to list
var/list/area/area_list = list()
for(var/area_name in affected_areas)
area_list += affected_areas[area_name]
SEND_GLOBAL_SIGNAL(COMSIG_AREA_CREATED, newA, area_list, creator)
to_chat(creator, span_notice("You have created a new area, named [newA.name]. It is now weather proof, and constructing an APC will allow it to be powered."))
creator.log_message("created a new area: [AREACOORD(creator)] (previously \"[oldA.name]\")", LOG_GAME)
//purge old areas that had all their turfs merged into the new one i.e. old empty areas. also recompute fire doors
for(var/i in 1 to length(area_list))
var/area/merged_area = area_list[i]
//recompute fire doors affecting areas
for(var/obj/machinery/door/firedoor/FD as anything in merged_area.firedoors)
FD.CalculateAffectingAreas()
//no more turfs in this area. Time to clean up
if(!merged_area.has_contained_turfs())
qdel(merged_area)
return TRUE
#undef BP_MAX_ROOM_SIZE
/proc/require_area_resort()
GLOB.sortedAreas = null
/// Returns a sorted version of GLOB.areas, by name
/proc/get_sorted_areas()
if(!GLOB.sortedAreas)
GLOB.sortedAreas = sortTim(GLOB.areas.Copy(), /proc/cmp_name_asc)
return GLOB.sortedAreas
//Takes: Area type as a text string from a variable.
//Returns: Instance for the area in the world.
/proc/get_area_instance_from_text(areatext)
if(istext(areatext))
areatext = text2path(areatext)
return GLOB.areas_by_type[areatext]
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all areas of that type in the world.
/proc/get_areas(areatype, subtypes=TRUE)
if(istext(areatype))
areatype = text2path(areatype)
else if(isarea(areatype))
var/area/areatemp = areatype
areatype = areatemp.type
else if(!ispath(areatype))
return null
var/list/areas = list()
if(subtypes)
var/list/cache = typecacheof(areatype)
for(var/area/area_to_check as anything in GLOB.areas)
if(cache[area_to_check.type])
areas += area_to_check
else
for(var/area/area_to_check as anything in GLOB.areas)
if(area_to_check.type == areatype)
areas += area_to_check
return areas
/// Iterates over all turfs in the target area and returns the first non-dense one
/proc/get_first_open_turf_in_area(area/target)
if(!target)
return
for(var/turf/turf in target)
if(!turf.density)
return turf
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all turfs in areas of that type of that type in the world.
/proc/get_area_turfs(areatype, target_z = 0, subtypes=FALSE)
if(istext(areatype))
areatype = text2path(areatype)
else if(isarea(areatype))
var/area/areatemp = areatype
areatype = areatemp.type
else if(!ispath(areatype))
return null
// Pull out the areas
var/list/areas_to_pull = list()
if(subtypes)
var/list/cache = typecacheof(areatype)
for(var/area/area_to_check as anything in GLOB.areas)
if(!cache[area_to_check.type])
continue
areas_to_pull += area_to_check
else
for(var/area/area_to_check as anything in GLOB.areas)
if(area_to_check.type != areatype)
continue
areas_to_pull += area_to_check
// Now their turfs
var/list/turfs = list()
for(var/area/pull_from as anything in areas_to_pull)
if (target_z == 0)
for (var/list/zlevel_turfs as anything in pull_from.get_zlevel_turf_lists())
turfs += zlevel_turfs
else
turfs += pull_from.get_turfs_by_zlevel(target_z)
return turfs
///Takes: list of area types
///Returns: all mobs that are in an area type
/proc/mobs_in_area_type(list/area/checked_areas)
var/list/mobs_in_area = list()
for(var/mob/living/mob as anything in GLOB.mob_living_list)
if(QDELETED(mob))
continue
for(var/area in checked_areas)
if(istype(get_area(mob), area))
mobs_in_area += mob
break
return mobs_in_area