mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Links many map-specific details such as the station name, z-level information, and allowed jobs from global vars to map datum vars, which should help us maintain multiple maps at once in the future, which will be needed for the future Southern Cross. Note that a config change will be needed to change GENERATE_ASTEROID to GENERATE_MAP, otherwise no changes should be required to continue normal map usage. To change to a different map, it's suggested to tick the file that ticks all the other needed files, which for the Northern Star is called northern_star.dm.
571 lines
16 KiB
Plaintext
571 lines
16 KiB
Plaintext
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
|
|
|
|
/proc/dopage(src,target)
|
|
var/href_list
|
|
var/href
|
|
href_list = params2list("src=\ref[src]&[target]=1")
|
|
href = "src=\ref[src];[target]=1"
|
|
src:temphtml = null
|
|
src:Topic(href, href_list)
|
|
return null
|
|
|
|
/proc/is_on_same_plane_or_station(var/z1, var/z2)
|
|
if(z1 == z2)
|
|
return 1
|
|
if((z1 in using_map.station_levels) && (z2 in using_map.station_levels))
|
|
return 1
|
|
return 0
|
|
|
|
/proc/max_default_z_level()
|
|
var/max_z = 0
|
|
for(var/z in using_map.station_levels)
|
|
max_z = max(z, max_z)
|
|
for(var/z in using_map.admin_levels)
|
|
max_z = max(z, max_z)
|
|
for(var/z in using_map.player_levels)
|
|
max_z = max(z, max_z)
|
|
return max_z
|
|
|
|
/proc/get_area(O)
|
|
var/turf/loc = get_turf(O)
|
|
if(loc)
|
|
var/area/res = loc.loc
|
|
.= res
|
|
|
|
/proc/get_area_name(N) //get area by its name
|
|
for(var/area/A in world)
|
|
if(A.name == N)
|
|
return A
|
|
return 0
|
|
|
|
/proc/get_area_master(const/O)
|
|
var/area/A = get_area(O)
|
|
if (isarea(A))
|
|
return A
|
|
|
|
/proc/in_range(source, user)
|
|
if(get_dist(source, user) <= 1)
|
|
return 1
|
|
|
|
return 0 //not in range and not telekinetic
|
|
|
|
// Like view but bypasses luminosity check
|
|
|
|
/proc/hear(var/range, var/atom/source)
|
|
|
|
var/lum = source.luminosity
|
|
source.luminosity = 6
|
|
|
|
var/list/heard = view(range, source)
|
|
source.luminosity = lum
|
|
|
|
return heard
|
|
|
|
/proc/isStationLevel(var/level)
|
|
return level in using_map.station_levels
|
|
|
|
/proc/isNotStationLevel(var/level)
|
|
return !isStationLevel(level)
|
|
|
|
/proc/isPlayerLevel(var/level)
|
|
return level in using_map.player_levels
|
|
|
|
/proc/isAdminLevel(var/level)
|
|
return level in using_map.admin_levels
|
|
|
|
/proc/isNotAdminLevel(var/level)
|
|
return !isAdminLevel(level)
|
|
|
|
/proc/circlerange(center=usr,radius=3)
|
|
|
|
var/turf/centerturf = get_turf(center)
|
|
var/list/turfs = new/list()
|
|
var/rsq = radius * (radius+0.5)
|
|
|
|
for(var/atom/T in range(radius, centerturf))
|
|
var/dx = T.x - centerturf.x
|
|
var/dy = T.y - centerturf.y
|
|
if(dx*dx + dy*dy <= rsq)
|
|
turfs += T
|
|
|
|
//turfs += centerturf
|
|
return turfs
|
|
|
|
/proc/circleview(center=usr,radius=3)
|
|
|
|
var/turf/centerturf = get_turf(center)
|
|
var/list/atoms = new/list()
|
|
var/rsq = radius * (radius+0.5)
|
|
|
|
for(var/atom/A in view(radius, centerturf))
|
|
var/dx = A.x - centerturf.x
|
|
var/dy = A.y - centerturf.y
|
|
if(dx*dx + dy*dy <= rsq)
|
|
atoms += A
|
|
|
|
//turfs += centerturf
|
|
return atoms
|
|
|
|
/proc/trange(rad = 0, turf/centre = null) //alternative to range (ONLY processes turfs and thus less intensive)
|
|
if(!centre)
|
|
return
|
|
|
|
var/turf/x1y1 = locate(((centre.x-rad)<1 ? 1 : centre.x-rad),((centre.y-rad)<1 ? 1 : centre.y-rad),centre.z)
|
|
var/turf/x2y2 = locate(((centre.x+rad)>world.maxx ? world.maxx : centre.x+rad),((centre.y+rad)>world.maxy ? world.maxy : centre.y+rad),centre.z)
|
|
return block(x1y1,x2y2)
|
|
|
|
/proc/get_dist_euclidian(atom/Loc1 as turf|mob|obj,atom/Loc2 as turf|mob|obj)
|
|
var/dx = Loc1.x - Loc2.x
|
|
var/dy = Loc1.y - Loc2.y
|
|
|
|
var/dist = sqrt(dx**2 + dy**2)
|
|
|
|
return dist
|
|
|
|
/proc/circlerangeturfs(center=usr,radius=3)
|
|
|
|
var/turf/centerturf = get_turf(center)
|
|
var/list/turfs = new/list()
|
|
var/rsq = radius * (radius+0.5)
|
|
|
|
for(var/turf/T in range(radius, centerturf))
|
|
var/dx = T.x - centerturf.x
|
|
var/dy = T.y - centerturf.y
|
|
if(dx*dx + dy*dy <= rsq)
|
|
turfs += T
|
|
return turfs
|
|
|
|
/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()?
|
|
|
|
var/turf/centerturf = get_turf(center)
|
|
var/list/turfs = new/list()
|
|
var/rsq = radius * (radius+0.5)
|
|
|
|
for(var/turf/T in view(radius, centerturf))
|
|
var/dx = T.x - centerturf.x
|
|
var/dy = T.y - centerturf.y
|
|
if(dx*dx + dy*dy <= rsq)
|
|
turfs += T
|
|
return turfs
|
|
|
|
|
|
|
|
//var/debug_mob = 0
|
|
|
|
// Will recursively loop through an atom's contents and check for mobs, then it will loop through every atom in that atom's contents.
|
|
// It will keep doing this until it checks every content possible. This will fix any problems with mobs, that are inside objects,
|
|
// being unable to hear people due to being in a box within a bag.
|
|
|
|
/proc/recursive_content_check(var/atom/O, var/list/L = list(), var/recursion_limit = 3, var/client_check = 1, var/sight_check = 1, var/include_mobs = 1, var/include_objects = 1, var/ignore_show_messages = 0)
|
|
|
|
if(!recursion_limit)
|
|
return L
|
|
|
|
for(var/I in O.contents)
|
|
|
|
if(ismob(I))
|
|
if(!sight_check || isInSight(I, O))
|
|
L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
|
|
if(include_mobs)
|
|
if(client_check)
|
|
var/mob/M = I
|
|
if(M.client)
|
|
L |= M
|
|
else
|
|
L |= I
|
|
|
|
else if(istype(I,/obj/))
|
|
var/obj/check_obj = I
|
|
if(ignore_show_messages || check_obj.show_messages)
|
|
if(!sight_check || isInSight(I, O))
|
|
L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
|
|
if(include_objects)
|
|
L |= I
|
|
|
|
return L
|
|
|
|
// Returns a list of mobs and/or objects in range of R from source. Used in radio and say code.
|
|
|
|
/proc/get_mobs_or_objects_in_view(var/R, var/atom/source, var/include_mobs = 1, var/include_objects = 1)
|
|
|
|
var/turf/T = get_turf(source)
|
|
var/list/hear = list()
|
|
|
|
if(!T)
|
|
return hear
|
|
|
|
var/list/range = hear(R, T)
|
|
|
|
for(var/I in range)
|
|
if(ismob(I))
|
|
hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
|
|
if(include_mobs)
|
|
var/mob/M = I
|
|
if(M.client)
|
|
hear += M
|
|
else if(istype(I,/obj/))
|
|
hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
|
|
var/obj/O = I
|
|
if(O.show_messages && include_objects)
|
|
hear += I
|
|
|
|
return hear
|
|
|
|
|
|
/proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios)
|
|
|
|
set background = 1
|
|
|
|
. = list()
|
|
// Returns a list of mobs who can hear any of the radios given in @radios
|
|
var/list/speaker_coverage = list()
|
|
for(var/obj/item/device/radio/R in radios)
|
|
if(R)
|
|
//Cyborg checks. Receiving message uses a bit of cyborg's charge.
|
|
var/obj/item/device/radio/borg/BR = R
|
|
if(istype(BR) && BR.myborg)
|
|
var/mob/living/silicon/robot/borg = BR.myborg
|
|
var/datum/robot_component/CO = borg.get_component("radio")
|
|
if(!CO)
|
|
continue //No radio component (Shouldn't happen)
|
|
if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage))
|
|
continue //No power.
|
|
|
|
var/turf/speaker = get_turf(R)
|
|
if(speaker)
|
|
for(var/turf/T in hear(R.canhear_range,speaker))
|
|
speaker_coverage[T] = T
|
|
|
|
|
|
// Try to find all the players who can hear the message
|
|
for(var/i = 1; i <= player_list.len; i++)
|
|
var/mob/M = player_list[i]
|
|
if(M)
|
|
var/turf/ear = get_turf(M)
|
|
if(ear)
|
|
// Ghostship is magic: Ghosts can hear radio chatter from anywhere
|
|
if(speaker_coverage[ear] || (istype(M, /mob/observer/dead) && M.is_preference_enabled(/datum/client_preference/ghost_radio)))
|
|
. |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down.
|
|
return .
|
|
|
|
//Uses dview to quickly return mobs and objects in view,
|
|
// then adds additional mobs or objects if they are in range 'smartly',
|
|
// based on their presence in lists of players or registered objects
|
|
// Type: 1-audio, 2-visual, 0-neither
|
|
/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/type = 1)
|
|
var/list/mobs = list()
|
|
var/list/objs = list()
|
|
|
|
var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM)
|
|
var/list/hearturfs = list()
|
|
|
|
for(var/atom/movable/AM in hear)
|
|
if(ismob(AM))
|
|
mobs += AM
|
|
hearturfs += AM.locs[1]
|
|
else if(isobj(AM))
|
|
objs += AM
|
|
hearturfs += AM.locs[1]
|
|
|
|
//A list of every mob with a client
|
|
for(var/mob/M in player_list)
|
|
if(M.loc && M.locs[1] in hearturfs)
|
|
mobs |= M
|
|
|
|
else if(M.stat == DEAD)
|
|
switch(type)
|
|
if(1) //Audio messages use ghost_ears
|
|
if(M.is_preference_enabled(/datum/client_preference/ghost_ears))
|
|
mobs |= M
|
|
if(2) //Visual messages use ghost_sight
|
|
if(M.is_preference_enabled(/datum/client_preference/ghost_sight))
|
|
mobs |= M
|
|
|
|
//For objects below the top level who still want to hear
|
|
for(var/obj/O in listening_objects)
|
|
if(O.loc && O.locs[1] in hearturfs)
|
|
objs |= O
|
|
|
|
return list("mobs" = mobs, "objs" = objs)
|
|
|
|
#define SIGN(X) ((X<0)?-1:1)
|
|
|
|
proc
|
|
inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
|
|
var/turf/T
|
|
if(X1==X2)
|
|
if(Y1==Y2)
|
|
return 1 //Light cannot be blocked on same tile
|
|
else
|
|
var/s = SIGN(Y2-Y1)
|
|
Y1+=s
|
|
while(Y1!=Y2)
|
|
T=locate(X1,Y1,Z)
|
|
if(T.opacity)
|
|
return 0
|
|
Y1+=s
|
|
else
|
|
var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
|
|
var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
|
|
var/signX = SIGN(X2-X1)
|
|
var/signY = SIGN(Y2-Y1)
|
|
if(X1<X2)
|
|
b+=m
|
|
while(X1!=X2 || Y1!=Y2)
|
|
if(round(m*X1+b-Y1))
|
|
Y1+=signY //Line exits tile vertically
|
|
else
|
|
X1+=signX //Line exits tile horizontally
|
|
T=locate(X1,Y1,Z)
|
|
if(T.opacity)
|
|
return 0
|
|
return 1
|
|
#undef SIGN
|
|
|
|
proc/isInSight(var/atom/A, var/atom/B)
|
|
var/turf/Aturf = get_turf(A)
|
|
var/turf/Bturf = get_turf(B)
|
|
|
|
if(!Aturf || !Bturf)
|
|
return 0
|
|
|
|
if(inLineOfSight(Aturf.x,Aturf.y, Bturf.x,Bturf.y,Aturf.z))
|
|
return 1
|
|
|
|
else
|
|
return 0
|
|
|
|
/proc/get_cardinal_step_away(atom/start, atom/finish) //returns the position of a step from start away from finish, in one of the cardinal directions
|
|
//returns only NORTH, SOUTH, EAST, or WEST
|
|
var/dx = finish.x - start.x
|
|
var/dy = finish.y - start.y
|
|
if(abs(dy) > abs (dx)) //slope is above 1:1 (move horizontally in a tie)
|
|
if(dy > 0)
|
|
return get_step(start, SOUTH)
|
|
else
|
|
return get_step(start, NORTH)
|
|
else
|
|
if(dx > 0)
|
|
return get_step(start, WEST)
|
|
else
|
|
return get_step(start, EAST)
|
|
|
|
/proc/get_mob_by_key(var/key)
|
|
for(var/mob/M in mob_list)
|
|
if(M.ckey == lowertext(key))
|
|
return M
|
|
return null
|
|
|
|
|
|
// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
|
|
/proc/get_active_candidates(var/buffer = 1)
|
|
|
|
var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
|
|
var/i = 0
|
|
while(candidates.len <= 0 && i < 5)
|
|
for(var/mob/observer/dead/G in player_list)
|
|
if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien
|
|
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
|
candidates += G.key
|
|
i++
|
|
return candidates
|
|
|
|
// Same as above but for alien candidates.
|
|
|
|
/proc/get_alien_candidates()
|
|
|
|
var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
|
|
var/i = 0
|
|
while(candidates.len <= 0 && i < 5)
|
|
for(var/mob/observer/dead/G in player_list)
|
|
if(G.client.prefs.be_special & BE_ALIEN)
|
|
if(((G.client.inactivity/10)/60) <= ALIEN_SELECT_AFK_BUFFER + i) // the most active players are more likely to become an alien
|
|
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
|
candidates += G.key
|
|
i++
|
|
return candidates
|
|
|
|
/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480)
|
|
if(!isobj(O)) O = new /obj/screen/text()
|
|
O.maptext = maptext
|
|
O.maptext_height = maptext_height
|
|
O.maptext_width = maptext_width
|
|
O.screen_loc = screen_loc
|
|
return O
|
|
|
|
/proc/Show2Group4Delay(obj/O, list/group, delay=0)
|
|
if(!isobj(O)) return
|
|
if(!group) group = clients
|
|
for(var/client/C in group)
|
|
C.screen += O
|
|
if(delay)
|
|
spawn(delay)
|
|
for(var/client/C in group)
|
|
C.screen -= O
|
|
|
|
datum/projectile_data
|
|
var/src_x
|
|
var/src_y
|
|
var/time
|
|
var/distance
|
|
var/power_x
|
|
var/power_y
|
|
var/dest_x
|
|
var/dest_y
|
|
|
|
/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \
|
|
var/power_x, var/power_y, var/dest_x, var/dest_y)
|
|
src.src_x = src_x
|
|
src.src_y = src_y
|
|
src.time = time
|
|
src.distance = distance
|
|
src.power_x = power_x
|
|
src.power_y = power_y
|
|
src.dest_x = dest_x
|
|
src.dest_y = dest_y
|
|
|
|
/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power)
|
|
|
|
// returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle],
|
|
// rotated at [rotation] and with the power of [power]
|
|
// Thanks to VistaPOWA for this function
|
|
|
|
var/power_x = power * cos(angle)
|
|
var/power_y = power * sin(angle)
|
|
var/time = 2* power_y / 10 //10 = g
|
|
|
|
var/distance = time * power_x
|
|
|
|
var/dest_x = src_x + distance*sin(rotation);
|
|
var/dest_y = src_y + distance*cos(rotation);
|
|
|
|
return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
|
|
|
|
/proc/GetRedPart(const/hexa)
|
|
return hex2num(copytext(hexa,2,4))
|
|
|
|
/proc/GetGreenPart(const/hexa)
|
|
return hex2num(copytext(hexa,4,6))
|
|
|
|
/proc/GetBluePart(const/hexa)
|
|
return hex2num(copytext(hexa,6,8))
|
|
|
|
/proc/GetHexColors(const/hexa)
|
|
return list(
|
|
GetRedPart(hexa),
|
|
GetGreenPart(hexa),
|
|
GetBluePart(hexa)
|
|
)
|
|
|
|
/proc/MixColors(const/list/colors)
|
|
var/list/reds = list()
|
|
var/list/blues = list()
|
|
var/list/greens = list()
|
|
var/list/weights = list()
|
|
|
|
for (var/i = 0, ++i <= colors.len)
|
|
reds.Add(GetRedPart(colors[i]))
|
|
blues.Add(GetBluePart(colors[i]))
|
|
greens.Add(GetGreenPart(colors[i]))
|
|
weights.Add(1)
|
|
|
|
var/r = mixOneColor(weights, reds)
|
|
var/g = mixOneColor(weights, greens)
|
|
var/b = mixOneColor(weights, blues)
|
|
return rgb(r,g,b)
|
|
|
|
/proc/mixOneColor(var/list/weight, var/list/color)
|
|
if (!weight || !color || length(weight)!=length(color))
|
|
return 0
|
|
|
|
var/contents = length(weight)
|
|
var/i
|
|
|
|
//normalize weights
|
|
var/listsum = 0
|
|
for(i=1; i<=contents; i++)
|
|
listsum += weight[i]
|
|
for(i=1; i<=contents; i++)
|
|
weight[i] /= listsum
|
|
|
|
//mix them
|
|
var/mixedcolor = 0
|
|
for(i=1; i<=contents; i++)
|
|
mixedcolor += weight[i]*color[i]
|
|
mixedcolor = round(mixedcolor)
|
|
|
|
//until someone writes a formal proof for this algorithm, let's keep this in
|
|
// if(mixedcolor<0x00 || mixedcolor>0xFF)
|
|
// return 0
|
|
//that's not the kind of operation we are running here, nerd
|
|
mixedcolor=min(max(mixedcolor,0),255)
|
|
|
|
return mixedcolor
|
|
|
|
/**
|
|
* Gets the highest and lowest pressures from the tiles in cardinal directions
|
|
* around us, then checks the difference.
|
|
*/
|
|
/proc/getOPressureDifferential(var/turf/loc)
|
|
var/minp=16777216;
|
|
var/maxp=0;
|
|
for(var/dir in cardinal)
|
|
var/turf/simulated/T=get_turf(get_step(loc,dir))
|
|
var/cp=0
|
|
if(T && istype(T) && T.zone)
|
|
var/datum/gas_mixture/environment = T.return_air()
|
|
cp = environment.return_pressure()
|
|
else
|
|
if(istype(T,/turf/simulated))
|
|
continue
|
|
if(cp<minp)minp=cp
|
|
if(cp>maxp)maxp=cp
|
|
return abs(minp-maxp)
|
|
|
|
/proc/convert_k2c(var/temp)
|
|
return ((temp - T0C))
|
|
|
|
/proc/convert_c2k(var/temp)
|
|
return ((temp + T0C))
|
|
|
|
/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature"))
|
|
var/list/temps = new/list(4)
|
|
for(var/dir in cardinal)
|
|
var/direction
|
|
switch(dir)
|
|
if(NORTH)
|
|
direction = 1
|
|
if(SOUTH)
|
|
direction = 2
|
|
if(EAST)
|
|
direction = 3
|
|
if(WEST)
|
|
direction = 4
|
|
var/turf/simulated/T=get_turf(get_step(loc,dir))
|
|
var/list/rstats = new /list(stats.len)
|
|
if(T && istype(T) && T.zone)
|
|
var/datum/gas_mixture/environment = T.return_air()
|
|
for(var/i=1;i<=stats.len;i++)
|
|
if(stats[i] == "pressure")
|
|
rstats[i] = environment.return_pressure()
|
|
else
|
|
rstats[i] = environment.vars[stats[i]]
|
|
else if(istype(T, /turf/simulated))
|
|
rstats = null // Exclude zone (wall, door, etc).
|
|
else if(istype(T, /turf))
|
|
// Should still work. (/turf/return_air())
|
|
var/datum/gas_mixture/environment = T.return_air()
|
|
for(var/i=1;i<=stats.len;i++)
|
|
if(stats[i] == "pressure")
|
|
rstats[i] = environment.return_pressure()
|
|
else
|
|
rstats[i] = environment.vars[stats[i]]
|
|
temps[direction] = rstats
|
|
return temps
|
|
|
|
/proc/MinutesToTicks(var/minutes)
|
|
return SecondsToTicks(60 * minutes)
|
|
|
|
/proc/SecondsToTicks(var/seconds)
|
|
return seconds * 10
|