Merge branch 'master' of https://github.com/PolarisSS13/Polaris into 12/16/2015_newwizard

This commit is contained in:
Neerti
2016-06-26 20:14:29 -04:00
1107 changed files with 40450 additions and 27263 deletions
+1 -1
View File
@@ -92,7 +92,7 @@
. += pick(map[min_char])
message = copytext(message, min_index + 1)
return list2text(.)
return jointext(., null)
#undef AUTOHISS_OFF
#undef AUTOHISS_BASIC
+145 -4
View File
@@ -6,6 +6,7 @@
layer = MOB_LAYER
universal_speak = 1
density = 0
var/obj/item/weapon/card/id/botcard = null
var/list/botcard_access = list()
var/on = 1
@@ -13,11 +14,30 @@
var/locked = 1
var/emagged = 0
var/light_strength = 3
var/busy = 0
var/obj/access_scanner = null
var/list/req_access = list()
var/list/req_one_access = list()
var/atom/target = null
var/list/ignore_list = list()
var/list/patrol_path = list()
var/list/target_path = list()
var/turf/obstacle = null
var/wait_if_pulled = 0 // Only applies to moving to the target
var/will_patrol = 0 // Not a setting - whether or no this type of bots patrols at all
var/patrol_speed = 1 // How many times per tick we move when patrolling
var/target_speed = 2 // Ditto for chasing the target
var/min_target_dist = 1 // How close we try to get to the target
var/max_target_dist = 50 // How far we are willing to go
var/max_patrol_dist = 250
var/target_patience = 5
var/frustration = 0
var/max_frustration = 0
/mob/living/bot/New()
..()
update_icons()
@@ -40,6 +60,9 @@
stunned = 0
paralysis = 0
if(on && !client && !busy)
handleAI()
/mob/living/bot/updatehealth()
if(status_flags & GODMODE)
health = maxHealth
@@ -109,6 +132,123 @@
/mob/living/bot/emag_act(var/remaining_charges, var/mob/user)
return 0
/mob/living/bot/proc/handleAI()
if(ignore_list.len)
for(var/atom/A in ignore_list)
if(!A || !A.loc || prob(1))
ignore_list -= A
handleRegular()
if(target && confirmTarget(target))
if(Adjacent(target))
handleAdjacentTarget()
else
handleRangedTarget()
if(!wait_if_pulled || !pulledby)
for(var/i = 1 to target_speed)
stepToTarget()
if(i < target_speed)
sleep(20 / target_speed)
if(max_frustration && frustration > max_frustration * target_speed)
handleFrustrated(1)
else
resetTarget()
lookForTargets()
if(will_patrol && !pulledby && !target)
if(patrol_path.len)
for(var/i = 1 to patrol_speed)
handlePatrol()
if(i < patrol_speed)
sleep(20 / patrol_speed)
if(max_frustration && frustration > max_frustration * patrol_speed)
handleFrustrated(0)
else
startPatrol()
else
handleIdle()
/mob/living/bot/proc/handleRegular()
return
/mob/living/bot/proc/handleAdjacentTarget()
return
/mob/living/bot/proc/handleRangedTarget()
return
/mob/living/bot/proc/stepToTarget()
if(!target || !target.loc)
return
if(get_dist(src, target) > min_target_dist)
if(!target_path.len || get_turf(target) != target_path[target_path.len])
calcTargetPath()
if(makeStep(target_path))
frustration = 0
else if(max_frustration)
++frustration
return
/mob/living/bot/proc/handleFrustrated(var/targ)
obstacle = targ ? target_path[1] : patrol_path[1]
target_path = list()
patrol_path = list()
return
/mob/living/bot/proc/lookForTargets()
return
/mob/living/bot/proc/confirmTarget(var/atom/A)
if(A.invisibility >= INVISIBILITY_LEVEL_ONE)
return 0
if(A in ignore_list)
return 0
if(!A.loc)
return 0
return 1
/mob/living/bot/proc/handlePatrol()
makeStep(patrol_path)
return
/mob/living/bot/proc/startPatrol()
var/turf/T = getPatrolTurf()
if(T)
patrol_path = AStar(get_turf(loc), T, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_patrol_dist, id = botcard, exclude = obstacle)
if(!patrol_path)
patrol_path = list()
obstacle = null
return
/mob/living/bot/proc/getPatrolTurf()
return null
/mob/living/bot/proc/handleIdle()
return
/mob/living/bot/proc/calcTargetPath()
target_path = AStar(get_turf(loc), get_turf(target), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard, exclude = obstacle)
if(!target_path)
if(target && target.loc)
ignore_list |= target
resetTarget()
obstacle = null
return
/mob/living/bot/proc/makeStep(var/list/path)
if(!path.len)
return 0
var/turf/T = path[1]
if(get_turf(src) == T)
path -= T
return makeStep(path)
return step_towards(src, T)
/mob/living/bot/proc/resetTarget()
target = null
target_path = list()
frustration = 0
obstacle = null
/mob/living/bot/proc/turn_on()
if(stat)
return 0
@@ -121,13 +261,13 @@
on = 0
set_light(0)
update_icons()
resetTarget()
patrol_path = list()
ignore_list = list()
/mob/living/bot/proc/explode()
qdel(src)
/mob/living/bot/attack_throat()
return
/******************************************************************/
// Navigation procs
// Used for A-star pathfinding
@@ -141,7 +281,7 @@
// for(var/turf/simulated/t in oview(src,1))
for(var/d in cardinal)
var/turf/simulated/T = get_step(src, d)
var/turf/T = get_step(src, d)
if(istype(T) && !T.density)
if(!LinkBlockedWithAccess(src, T, ID))
L.Add(T)
@@ -194,3 +334,4 @@
//if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID)
else return !D.check_access(ID) // it's a real, air blocking door
return 0
+23 -140
View File
@@ -6,18 +6,8 @@
botcard_access = list(access_janitor, access_maint_tunnels)
locked = 0 // Start unlocked so roboticist can set them to patrol.
var/obj/effect/decal/cleanable/target
var/list/path = list()
var/list/patrol_path = list()
var/list/ignorelist = list()
var/obj/cleanbot_listener/listener = null
var/beacon_freq = 1445 // navigation beacon frequency
var/signal_sent = 0
var/closest_dist
var/next_dest
var/next_dest_loc
wait_if_pulled = 1
min_target_dist = 0
var/cleaning = 0
var/screwloose = 0
@@ -26,48 +16,11 @@
var/blood = 1
var/list/target_types = list()
var/maximum_search_range = 7
/mob/living/bot/cleanbot/New()
..()
get_targets()
listener = new /obj/cleanbot_listener(src)
listener.cleanbot = src
if(radio_controller)
radio_controller.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS)
/mob/living/bot/cleanbot/proc/handle_target()
if(loc == target.loc)
if(!cleaning)
UnarmedAttack(target)
return 1
if(!path.len)
// spawn(0)
path = AStar(loc, target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
custom_emote(2, "[src] can't reach the target and is giving up.")
target = null
path = list()
return
if(path.len)
step_to(src, path[1])
path -= path[1]
return 1
return
/mob/living/bot/cleanbot/Life()
..()
if(!on)
return
if(client)
return
if(cleaning)
return
/mob/living/bot/cleanbot/handleIdle()
if(!screwloose && !oddbutton && prob(5))
custom_emote(2, "makes an excited beeping booping sound!")
@@ -79,68 +32,27 @@
if(oddbutton && prob(5)) // Make a big mess
visible_message("Something flies out of [src]. He seems to be acting oddly.")
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc)
ignorelist += gib
ignore_list += gib
spawn(600)
ignorelist -= gib
ignore_list -= gib
// Find a target
if(pulledby) // Don't wiggle if someone pulls you
patrol_path = list()
return
var/found_spot
search_loop:
for(var/i=0, i <= maximum_search_range, i++)
for(var/obj/effect/decal/cleanable/D in view(i, src))
if(D in ignorelist)
continue
for(var/T in target_types)
if(istype(D, T))
patrol_path = list()
target = D
found_spot = handle_target()
if (found_spot)
break search_loop
else
target = null
continue // no need to check the other types
if(!found_spot && !target) // No targets in range
if(!patrol_path || !patrol_path.len)
if(!signal_sent || signal_sent > world.time + 200) // Waited enough or didn't send yet
var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq)
if(!frequency)
return
closest_dist = 9999
next_dest = null
next_dest_loc = null
var/datum/signal/signal = new()
signal.source = src
signal.transmission_method = 1
signal.data = list("findbeakon" = "patrol")
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
signal_sent = world.time
else
if(next_dest)
next_dest_loc = listener.memorized[next_dest]
if(next_dest_loc)
patrol_path = AStar(loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id = botcard, exclude = null)
signal_sent = 0
else
if(pulledby) // Don't wiggle if someone pulls you
patrol_path = list()
return
if(patrol_path[1] == loc)
patrol_path -= patrol_path[1]
var/moved = step_towards(src, patrol_path[1])
if(moved)
patrol_path -= patrol_path[1]
/mob/living/bot/cleanbot/lookForTargets()
for(var/obj/effect/decal/cleanable/D in view(world.view, src)) // There was some odd code to make it start with nearest decals, it's unnecessary, this works
if(confirmTarget(D))
target = D
return
/mob/living/bot/cleanbot/confirmTarget(var/obj/effect/decal/cleanable/D)
if(!..())
return 0
for(var/T in target_types)
if(istype(D, T))
return 1
return 0
/mob/living/bot/cleanbot/handleAdjacentTarget()
if(get_turf(target) == src.loc)
UnarmedAttack(target)
/mob/living/bot/cleanbot/UnarmedAttack(var/obj/effect/decal/cleanable/D, var/proximity)
if(!..())
@@ -152,7 +64,7 @@
if(D.loc != loc)
return
cleaning = 1
busy = 1
custom_emote(2, "begins to clean up \the [D]")
update_icons()
var/cleantime = istype(D, /obj/effect/decal/cleanable/dirt) ? 10 : 50
@@ -165,7 +77,7 @@
qdel(D)
if(D == target)
target = null
cleaning = 0
busy = 0
update_icons()
/mob/living/bot/cleanbot/explode()
@@ -185,17 +97,11 @@
return
/mob/living/bot/cleanbot/update_icons()
if(cleaning)
if(busy)
icon_state = "cleanbot-c"
else
icon_state = "cleanbot[on]"
/mob/living/bot/cleanbot/turn_off()
..()
target = null
path = list()
patrol_path = list()
/mob/living/bot/cleanbot/attack_hand(var/mob/user)
var/dat
dat += "<TT><B>Automatic Station Cleaner v1.0</B></TT><BR><BR>"
@@ -230,10 +136,6 @@
if("patrol")
should_patrol = !should_patrol
patrol_path = null
if("freq")
var/freq = text2num(input("Select frequency for navigation beacons", "Frequnecy", num2text(beacon_freq / 10))) * 10
if (freq > 0)
beacon_freq = freq
if("screw")
screwloose = !screwloose
usr << "<span class='notice'>You twiddle the screw.</span>"
@@ -264,25 +166,6 @@
if(blood)
target_types += /obj/effect/decal/cleanable/blood
/* Radio object that listens to signals */
/obj/cleanbot_listener
var/mob/living/bot/cleanbot/cleanbot = null
var/list/memorized = list()
/obj/cleanbot_listener/receive_signal(var/datum/signal/signal)
var/recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!recv || !valid || !cleanbot)
return
var/dist = get_dist(cleanbot, signal.source.loc)
memorized[recv] = signal.source.loc
if(dist < cleanbot.closest_dist) // We check all signals, choosing the closest beakon; then we move to the NEXT one after the closest one
cleanbot.closest_dist = dist
cleanbot.next_dest = signal.data["next_patrol"]
/* Assembly */
/obj/item/weapon/bucket_sensor
+4 -2
View File
@@ -7,7 +7,6 @@
health = 100
maxHealth = 100
bot_version = "2.5"
is_ranged = 1
preparing_arrest_sounds = new()
@@ -20,7 +19,7 @@
var/last_shot = 0
/mob/living/bot/secbot/ed209/update_icons()
if(on && is_attacking)
if(on && busy)
icon_state = "ed209-c"
else
icon_state = "ed209[on]"
@@ -50,6 +49,9 @@
new /obj/effect/decal/cleanable/blood/oil(Tsec)
qdel(src)
/mob/living/bot/secbot/ed209/handleRangedTarget()
RangedAttack(target)
/mob/living/bot/secbot/ed209/RangedAttack(var/atom/A)
if(last_shot + shot_delay > world.time)
src << "You are not ready to fire yet!"
+106 -80
View File
@@ -22,17 +22,14 @@
var/obj/structure/reagent_dispensers/watertank/tank
var/attacking = 0
var/list/path = list()
var/atom/target
var/frustration = 0
/mob/living/bot/farmbot/New()
..()
spawn(5)
tank = locate() in contents
if(!tank)
tank = new /obj/structure/reagent_dispensers/watertank(src)
/mob/living/bot/farmbot/New(var/newloc, var/newTank)
..(newloc)
if(!newTank)
newTank = new /obj/structure/reagent_dispensers/watertank(src)
tank = newTank
tank.forceMove(src)
/mob/living/bot/farmbot/attack_hand(var/mob/user as mob)
. = ..()
@@ -110,63 +107,60 @@
else
icon_state = "farmbot[on]"
/mob/living/bot/farmbot/Life()
..()
if(!on)
return
/mob/living/bot/farmbot/handleRegular()
if(emagged && prob(1))
flick("farmbot_broke", src)
if(client)
return
if(target)
if(Adjacent(target))
UnarmedAttack(target)
path = list()
target = null
else
if(path.len && frustration < 5)
if(path[1] == loc)
path -= path[1]
var/t = step_towards(src, path[1])
if(t)
path -= path[1]
else
++frustration
else
path = list()
target = null
/mob/living/bot/farmbot/handleAdjacentTarget()
UnarmedAttack(target)
/mob/living/bot/farmbot/lookForTargets()
if(emagged)
for(var/mob/living/carbon/human/H in view(7, src))
target = H
return
else
if(emagged)
for(var/mob/living/carbon/human/H in view(7, src))
target = H
break
else
for(var/obj/machinery/portable_atmospherics/hydroponics/tray in view(7, src))
if(process_tray(tray))
target = tray
frustration = 0
break
if(!target && refills_water && tank && tank.reagents.total_volume < tank.reagents.maximum_volume)
for(var/obj/structure/sink/source in view(7, src))
target = source
frustration = 0
break
if(target)
var/t = get_dir(target, src) // Turf with the tray is impassable, so a* can't navigate directly to it
path = AStar(loc, get_step(target, t), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
for(var/obj/machinery/portable_atmospherics/hydroponics/tray in view(7, src))
if(confirmTarget(tray))
target = tray
return
if(!target && refills_water && tank && tank.reagents.total_volume < tank.reagents.maximum_volume)
for(var/obj/structure/sink/source in view(7, src))
target = source
return
/mob/living/bot/farmbot/calcTargetPath() // We need to land NEXT to the tray, because the tray itself is impassable
for(var/trayDir in list(NORTH, SOUTH, EAST, WEST))
target_path = AStar(get_turf(loc), get_step(get_turf(target), trayDir), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard)
if(target_path)
break
if(!target_path)
ignore_list |= target
target = null
target_path = list()
return
/mob/living/bot/farmbot/stepToTarget() // Same reason
var/turf/T = get_turf(target)
if(!target_path.len || !T.Adjacent(target_path[target_path.len]))
calcTargetPath()
makeStep(target_path)
return
/mob/living/bot/farmbot/UnarmedAttack(var/atom/A, var/proximity)
if(!..())
return
if(attacking)
if(busy)
return
if(istype(A, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/T = A
var/t = process_tray(T)
var/t = confirmTarget(T)
switch(t)
if(0)
return
@@ -174,7 +168,8 @@
action = "water" // Needs a better one
update_icons()
visible_message("<span class='notice'>[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].</span>")
attacking = 1
busy = 1
if(do_after(src, 30))
visible_message("<span class='notice'>[src] [T.dead? "removes the plant from" : "harvests"] \the [A].</span>")
T.attack_hand(src)
@@ -182,7 +177,8 @@
action = "water"
update_icons()
visible_message("<span class='notice'>[src] starts watering \the [A].</span>")
attacking = 1
busy = 1
if(do_after(src, 30))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
visible_message("<span class='notice'>[src] waters \the [A].</span>")
@@ -191,7 +187,8 @@
action = "hoe"
update_icons()
visible_message("<span class='notice'>[src] starts uprooting the weeds in \the [A].</span>")
attacking = 1
busy = 1
if(do_after(src, 30))
visible_message("<span class='notice'>[src] uproots the weeds in \the [A].</span>")
T.weedlevel = 0
@@ -199,11 +196,14 @@
action = "fertile"
update_icons()
visible_message("<span class='notice'>[src] starts fertilizing \the [A].</span>")
attacking = 1
busy = 1
if(do_after(src, 30))
visible_message("<span class='notice'>[src] waters \the [A].</span>")
visible_message("<span class='notice'>[src] fertilizes \the [A].</span>")
T.reagents.add_reagent("ammonia", 10)
attacking = 0
busy = 0
action = ""
update_icons()
T.update_icon()
@@ -213,20 +213,24 @@
action = "water"
update_icons()
visible_message("<span class='notice'>[src] starts refilling its tank from \the [A].</span>")
attacking = 1
busy = 1
while(do_after(src, 10) && tank.reagents.total_volume < tank.reagents.maximum_volume)
tank.reagents.add_reagent("water", 10)
if(prob(5))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
attacking = 0
busy = 0
action = ""
update_icons()
visible_message("<span class='notice'>[src] finishes refilling its tank.</span>")
else if(emagged && ishuman(A))
var/action = pick("weed", "water")
attacking = 1
busy = 1
spawn(50) // Some delay
attacking = 0
busy = 0
switch(action)
if("weed")
flick("farmbot_hoe", src)
@@ -238,7 +242,9 @@
A.attack_generic(src, 5, t)
if("water")
flick("farmbot_water", src)
visible_message("<span class='danger'>[src] splashes [A] with water!</span>") // That's it. RP effect.
visible_message("<span class='danger'>[src] splashes [A] with water!</span>")
tank.reagents.splash(A, 100)
/mob/living/bot/farmbot/explode()
visible_message("<span class='danger'>[src] blows apart!</span>")
@@ -261,8 +267,23 @@
qdel(src)
return
/mob/living/bot/farmbot/proc/process_tray(var/obj/machinery/portable_atmospherics/hydroponics/tray)
if(!tray || !istype(tray))
/mob/living/bot/farmbot/confirmTarget(var/atom/targ)
if(!..())
return 0
if(emagged && ishuman(targ))
if(targ in view(world.view, src))
return 1
return 0
if(istype(targ, /obj/structure/sink))
if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume)
return 0
return 1
var/obj/machinery/portable_atmospherics/hydroponics/tray = targ
if(!istype(tray))
return 0
if(tray.closed_system || !tray.seed)
@@ -291,34 +312,38 @@
icon_state = "water_arm"
var/build_step = 0
var/created_name = "Farmbot"
var/obj/tank
w_class = 3.0
New()
..()
spawn(4) // If an admin spawned it, it won't have a watertank it, so lets make one for em!
var tank = locate(/obj/structure/reagent_dispensers/watertank) in contents
if(!tank)
new /obj/structure/reagent_dispensers/watertank(src)
/obj/item/weapon/farmbot_arm_assembly/New(var/newloc, var/theTank)
..(newloc)
if(!theTank) // If an admin spawned it, it won't have a watertank it, so lets make one for em!
tank = new /obj/structure/reagent_dispensers/watertank(src)
else
tank = theTank
tank.forceMove(src)
/obj/structure/reagent_dispensers/watertank/attackby(var/obj/item/robot_parts/S, mob/user as mob)
if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
..()
return
var/obj/item/weapon/farmbot_arm_assembly/A = new /obj/item/weapon/farmbot_arm_assembly(loc)
user << "You add the robot arm to [src]."
loc = A //Place the water tank into the assembly, it will be needed for the finished bot
user.drop_from_inventory(S)
qdel(S)
new /obj/item/weapon/farmbot_arm_assembly(loc, src)
/obj/item/weapon/farmbot_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if((istype(W, /obj/item/device/analyzer/plant_analyzer)) && (build_step == 0))
build_step++
user << "You add the plant analyzer to [src]."
name = "farmbot assembly"
user.remove_from_mob(W)
qdel(W)
@@ -326,6 +351,7 @@
build_step++
user << "You add a bucket to [src]."
name = "farmbot assembly with bucket"
user.remove_from_mob(W)
qdel(W)
@@ -333,17 +359,17 @@
build_step++
user << "You add a minihoe to [src]."
name = "farmbot assembly with bucket and minihoe"
user.remove_from_mob(W)
qdel(W)
else if((isprox(W)) && (build_step == 3))
build_step++
user << "You complete the Farmbot! Beep boop."
var/mob/living/bot/farmbot/S = new /mob/living/bot/farmbot(get_turf(src))
for(var/obj/structure/reagent_dispensers/watertank/wTank in contents)
wTank.loc = S
S.tank = wTank
var/mob/living/bot/farmbot/S = new /mob/living/bot/farmbot(get_turf(src), tank)
S.name = created_name
user.remove_from_mob(W)
qdel(W)
qdel(src)
+85 -97
View File
@@ -3,22 +3,20 @@
desc = "A little floor repairing robot, he looks so excited!"
icon_state = "floorbot0"
req_access = list(access_construction)
wait_if_pulled = 1
min_target_dist = 0
var/amount = 10 // 1 for tile, 2 for lattice
var/maxAmount = 60
var/tilemake = 0 // When it reaches 100, bot makes a tile
var/repairing = 0
var/improvefloors = 0
var/eattiles = 0
var/maketiles = 0
var/targetdirection = null
var/list/path = list()
var/list/ignorelist = list()
var/turf/target
var/floor_build_type = /decl/flooring/tiling // Basic steel floor.
/mob/living/bot/floorbot/update_icons()
if(repairing)
if(busy)
icon_state = "floorbot-c"
else if(amount > 0)
icon_state = "floorbot[on]"
@@ -31,7 +29,7 @@
dat += "<TT><B>Automatic Station Floor Repairer v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A><BR>"
dat += "Maintenance panel is [open ? "opened" : "closed"]<BR>"
//dat += "Tiles left: [amount]<BR>"
dat += "Tiles left: [amount]<BR>"
dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]<BR>"
if(!locked || issilicon(user))
dat += "Improves floors: <A href='?src=\ref[src];operation=improve'>[improvefloors ? "Yes" : "No"]</A><BR>"
@@ -89,100 +87,90 @@
targetdirection = null
attack_hand(usr)
/mob/living/bot/floorbot/turn_off()
..()
target = null
path = list()
ignorelist = list()
/mob/living/bot/floorbot/Life()
..()
if(!on)
return
/mob/living/bot/floorbot/handleRegular()
++tilemake
if(tilemake >= 100)
tilemake = 0
addTiles(1)
if(client)
return
if(prob(5))
if(prob(1))
custom_emote(2, "makes an excited booping beeping sound!")
if(ignorelist.len) // Don't stick forever
for(var/T in ignorelist)
if(prob(1))
ignorelist -= T
if(amount && !emagged)
if(!target && targetdirection) // Building a bridge
var/turf/T = get_step(src, targetdirection)
while(T in range(src))
if(istype(T, /turf/space))
target = T
break
T = get_step(T, targetdirection)
if(!target) // Fixing floors
for(var/turf/T in view(src))
if(T.loc.name == "Space")
continue
if(T in ignorelist)
continue
if(istype(T, /turf/space))
if(get_turf(T) == loc || prob(40)) // So they target the same tile all the time
target = T
if(improvefloors && istype(T, /turf/simulated/floor))
var/turf/simulated/floor/F = T
if(!F.flooring && (get_turf(T) == loc || prob(40)))
target = T
if(emagged) // Time to griff
for(var/turf/simulated/floor/D in view(src))
if(D.loc.name == "Space")
continue
if(D in ignorelist)
continue
target = D
break
if(!target && amount < maxAmount && eattiles || maketiles) // Eat tiles
if(eattiles)
for(var/obj/item/stack/tile/floor/T in view(src))
if(T in ignorelist)
continue
target = T
break
if(maketiles && !target)
for(var/obj/item/stack/material/steel/T in view(src))
if(T in ignorelist)
continue
target = T
break
if(target && get_turf(target) == loc)
/mob/living/bot/floorbot/handleAdjacentTarget()
if(get_turf(target) == src.loc)
UnarmedAttack(target)
if(target && get_turf(target) != loc && !path.len)
spawn(0)
path = AStar(loc, get_turf(target), /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
ignorelist += target
target = null
/mob/living/bot/floorbot/lookForTargets()
if(emagged) // Time to griff
for(var/turf/simulated/floor/D in view(src))
if(confirmTarget(D))
target = D
return
if(path.len)
step_to(src, path[1])
path -= path[1]
else if(amount)
if(targetdirection) // Building a bridge
var/turf/T = get_step(src, targetdirection)
while(T in range(world.view, src))
if(confirmTarget(T))
target = T
return
T = get_step(T, targetdirection)
else // Fixing floors
for(var/turf/space/T in view(src)) // Breaches are of higher priority
if(confirmTarget(T))
target = T
return
for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
if(confirmTarget(T))
target = T
return
if(improvefloors)
for(var/turf/simulated/floor/T in view(src))
if(confirmTarget(T))
target = T
return
if(amount < maxAmount && (eattiles || maketiles))
for(var/obj/item/stack/S in view(src))
if(confirmTarget(S))
target = S
return
/mob/living/bot/floorbot/confirmTarget(var/atom/A) // The fact that we do some checks twice may seem confusing but remember that the bot's settings may be toggled while it's moving and we want them to stop in that case
if(!..())
return 0
if(istype(A, /obj/item/stack/tile/floor))
return (amount < maxAmount && eattiles)
if(istype(A, /obj/item/stack/material/steel))
return (amount < maxAmount && maketiles)
if(A.loc.name == "Space")
return 0
if(emagged)
return (istype(A, /turf/simulated/floor))
if(!amount)
return 0
if(istype(A, /turf/space))
return 1
if(istype(A, /turf/simulated/mineral/floor))
return 1
var/turf/simulated/floor/T = A
return (istype(T) && improvefloors && !T.flooring && (get_turf(T) == loc || prob(40)))
/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity)
if(!..())
return
if(repairing)
if(busy)
return
if(get_turf(A) != loc)
@@ -190,9 +178,9 @@
if(emagged && istype(A, /turf/simulated/floor))
var/turf/simulated/floor/F = A
repairing = 1
busy = 1
update_icons()
if(F.is_plating())
if(F.flooring)
visible_message("<span class='warning'>[src] begins to tear the floor tile from the floor!</span>")
if(do_after(src, 50))
F.break_tile_to_plating()
@@ -203,15 +191,15 @@
F.ReplaceWithLattice()
addTiles(1)
target = null
repairing = 0
busy = 0
update_icons()
else if(istype(A, /turf/space))
else if(istype(A, /turf/space) || istype(A, /turf/simulated/mineral/floor))
var/building = 2
if(locate(/obj/structure/lattice, A))
building = 1
if(amount < building)
return
repairing = 1
busy = 1
update_icons()
visible_message("<span class='notice'>[src] begins to repair the hole.</span>")
if(do_after(src, 50))
@@ -223,12 +211,12 @@
I = PoolOrNew(/obj/item/stack/rods, src)
A.attackby(I, src)
target = null
repairing = 0
busy = 0
update_icons()
else if(istype(A, /turf/simulated/floor))
var/turf/simulated/floor/F = A
if(!F.flooring && amount)
repairing = 1
busy = 1
update_icons()
visible_message("<span class='notice'>[src] begins to improve the floor.</span>")
if(do_after(src, 50))
@@ -236,12 +224,12 @@
F.set_flooring(get_flooring_data(floor_build_type))
addTiles(-1)
target = null
repairing = 0
busy = 0
update_icons()
else if(istype(A, /obj/item/stack/tile/floor) && amount < maxAmount)
var/obj/item/stack/tile/floor/T = A
visible_message("<span class='notice'>[src] begins to collect tiles.</span>")
repairing = 1
busy = 1
update_icons()
if(do_after(src, 20))
if(T)
@@ -249,13 +237,13 @@
T.use(eaten)
addTiles(eaten)
target = null
repairing = 0
busy = 0
update_icons()
else if(istype(A, /obj/item/stack/material) && amount + 4 <= maxAmount)
var/obj/item/stack/material/M = A
if(M.get_material_name() == DEFAULT_WALL_MATERIAL)
visible_message("<span class='notice'>[src] begins to make tiles.</span>")
repairing = 1
busy = 1
update_icons()
if(do_after(50))
if(M)
@@ -288,7 +276,7 @@
/* Assembly */
/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/floor/T, mob/user as mob)
/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/floor/T, mob/living/user as mob)
if(!istype(T, /obj/item/stack/tile/floor))
..()
return
+37 -63
View File
@@ -3,21 +3,16 @@
desc = "A little medical robot. He looks somewhat underwhelmed."
icon_state = "medibot0"
req_access = list(access_medical)
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
botcard_access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics)
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
//AI vars
var/frustration = 0
var/list/path = list()
var/mob/living/carbon/human/patient = null
var/mob/ignored = list() // Used by emag
var/last_newpatient_speak = 0
var/vocal = 1
//Healing vars
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
var/currently_healing = 0
var/injection_amount = 15 //How much reagent do we inject at a time?
var/heal_threshold = 10 //Start healing when they have this much damage in a category
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
@@ -29,49 +24,26 @@
var/treatment_emag = "toxin"
var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds?
/mob/living/bot/medbot/Life()
..()
/mob/living/bot/medbot/handleIdle()
if(vocal && prob(1))
var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of medbay is this? Everyone's dropping like dead flies.", "Delicious!")
say(message)
if(!on)
return
/mob/living/bot/medbot/handleAdjacentTarget()
UnarmedAttack(target)
if(!client)
/mob/living/bot/medbot/lookForTargets()
for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
if(confirmTarget(H))
target = H
if(last_newpatient_speak + 300 < world.time)
var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!")
say(message)
custom_emote(1, "points at [H.name].")
last_newpatient_speak = world.time
break
if(vocal && prob(1))
var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of medbay is this? Everyone's dropping like dead flies.", "Delicious!")
say(message)
if(patient)
if(Adjacent(patient))
if(!currently_healing)
UnarmedAttack(patient)
else
if(path.len && (get_dist(patient, path[path.len]) > 2)) // We have a path, but it's off
path = list()
if(!path.len && (get_dist(src, patient) > 1))
spawn(0)
path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
if(path.len)
step_to(src, path[1])
path -= path[1]
++frustration
if(get_dist(src, patient) > 7 || frustration > 8)
patient = null
else
for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
if(valid_healing_target(H))
patient = H
frustration = 0
if(last_newpatient_speak + 300 < world.time)
var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!")
say(message)
custom_emote(1, "points at [H.name].")
last_newpatient_speak = world.time
break
/mob/living/bot/medbot/UnarmedAttack(var/mob/living/carbon/human/H, var/proximity)
/mob/living/bot/medbot/UnarmedAttack(var/mob/living/carbon/human/H)
if(!..())
return
@@ -81,25 +53,27 @@
if(!istype(H))
return
if(busy)
return
if(H.stat == DEAD)
var/death_message = pick("No! NO!", "Live, damnit! LIVE!", "I... I've never lost a patient before. Not today, I mean.")
say(death_message)
patient = null
target = null
return
var/t = valid_healing_target(H)
var/t = confirmTarget(H)
if(!t)
var/message = pick("All patched up!", "An apple a day keeps me away.", "Feel better soon!")
say(message)
patient = null
target = null
return
icon_state = "medibots"
visible_message("<span class='warning'>[src] is trying to inject [H]!</span>")
if(declare_treatment)
var/area/location = get_area(src)
broadcast_medical_hud_message("[src] is treating <b>[H]</b> in <b>[location]</b>", src)
currently_healing = 1
busy = 1
update_icons()
if(do_mob(src, H, 30))
if(t == 1)
@@ -107,14 +81,14 @@
else
H.reagents.add_reagent(t, injection_amount)
visible_message("<span class='warning'>[src] injects [H] with the syringe!</span>")
currently_healing = 0
busy = 0
update_icons()
/mob/living/bot/medbot/update_icons()
overlays.Cut()
if(skin)
overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
if(currently_healing)
if(busy)
icon_state = "medibots"
else
icon_state = "medibot[on]"
@@ -226,13 +200,13 @@
user << "<span class='warning'>You short out [src]'s reagent synthesis circuits.</span>"
visible_message("<span class='warning'>[src] buzzes oddly!</span>")
flick("medibot_spark", src)
patient = null
currently_healing = 0
target = null
busy = 0
emagged = 1
on = 1
update_icons()
. = 1
ignored |= user
ignore_list |= user
/mob/living/bot/medbot/explode()
on = 0
@@ -255,15 +229,15 @@
qdel(src)
return
/mob/living/bot/medbot/proc/valid_healing_target(var/mob/living/carbon/human/H)
/mob/living/bot/medbot/confirmTarget(var/mob/living/carbon/human/H)
if(!..())
return 0
if(H.stat == DEAD) // He's dead, Jim
return null
return 0
if(H.suiciding)
return null
if(H in ignored)
return null
return 0
if(emagged)
return treatment_emag
+43 -137
View File
@@ -17,23 +17,22 @@
maxHealth = 150
mob_bump_flag = HEAVY
min_target_dist = 0
max_target_dist = 250
target_speed = 3
max_frustration = 5
botcard_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
var/busy = 0
var/mode = MULE_IDLE
var/atom/movable/load
var/paused = 0
var/crates_only = 1
var/auto_return = 1
var/safety = 1
var/list/path = list()
var/frustration = 0
var/turf/target
var/targetName
var/turf/home
var/homeName
var/turf/obstacle
var/global/amount = 0
@@ -71,19 +70,6 @@
dat += "Power: [on ? "On" : "Off"]<BR>"
if(!open)
dat += "Status: "
switch(mode)
if(MULE_IDLE)
dat += "Ready"
if(MULE_MOVING, MULE_UNLOAD, MULE_PATH_DONE)
dat += "Navigating"
if(MULE_UNLOAD)
dat += "Unloading"
if(MULE_LOST)
dat += "Processing commands"
if(MULE_CALC_MIN to MULE_CALC_MAX)
dat += "Calculating navigation path"
dat += "<BR>Current Load: [load ? load.name : "<i>none</i>"]<BR>"
if(locked)
@@ -177,10 +163,9 @@
/mob/living/bot/mulebot/proc/obeyCommand(var/command)
switch(command)
if("Home")
mode = MULE_IDLE
resetTarget()
target = home
targetName = "Home"
mode = MULE_LOST
if("SetD")
var/new_dest
var/list/beaconlist = new()
@@ -192,13 +177,13 @@
else
alert("No destination beacons available.")
if(new_dest)
resetTarget()
target = get_turf(beaconlist[new_dest])
targetName = new_dest
if("GoTD")
if(mode == MULE_IDLE)
mode = MULE_LOST
paused = 0
if("Stop")
mode = MULE_IDLE
paused = 1
/mob/living/bot/mulebot/emag_act(var/remaining_charges, var/user)
locked = !locked
@@ -211,89 +196,49 @@
if(open)
icon_state = "mulebot-hatch"
return
if(mode == MULE_MOVING || mode == MULE_UNLOAD)
if(target_path.len && !paused)
icon_state = "mulebot1"
return
icon_state = "mulebot0"
/mob/living/bot/mulebot/Life()
..()
if(busy)
return
/mob/living/bot/mulebot/handleRegular()
if(!safety && prob(1))
flick("mulebot-emagged", src)
update_icons()
switch(mode)
if(MULE_IDLE) // Idle
return
if(MULE_MOVING) // Moving to target
if(!target) // Return home
if(auto_return && home)
target = home
targetName = "Home"
mode = MULE_LOST
else
mode = MULE_IDLE
update_icons()
return
if(loc == target) // Unload or stop
custom_emote(2, "makes a chiming sound.")
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
mode = MULE_UNLOAD
update_icons()
return
if(path.len) // Move
makeStep()
sleep(10)
if(path.len)
makeStep()
else
mode = MULE_LOST
/mob/living/bot/mulebot/handleFrustrated()
custom_emote(2, "makes a sighing buzz.")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
..()
update_icons()
return
if(MULE_UNLOAD)
unload(dir)
/mob/living/bot/mulebot/handleAdjacentTarget()
if(target == src.loc)
custom_emote(2, "makes a chiming sound.")
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
UnarmedAttack(target)
resetTarget()
if(auto_return && home && (loc != home))
target = home
targetName = "Home"
if(auto_return && home && (loc != home))
target = home
targetName = "Home"
mode = MULE_LOST
else
mode = MULE_IDLE
update_icons()
return
if(MULE_LOST) // Lost my way
if(target)
spawn(0)
calc_path(obstacle)
mode = MULE_CALC_MIN
else
mode = MULE_IDLE
update_icons()
return
if(MULE_CALC_MIN to MULE_CALC_MAX) // Calcing path
if(path.len)
mode = MULE_PATH_DONE
update_icons()
else
++mode
return
if(MULE_PATH_DONE) // Done with path
obstacle = null
if(path.len)
frustration = 0
mode = MULE_MOVING
else
if(home)
target = home
targetName = "Home"
mode = MULE_LOST
else
mode = MULE_IDLE
update_icons()
/mob/living/bot/mulebot/confirmTarget()
return 1
/mob/living/bot/mulebot/calcTargetPath()
..()
if(!target_path.len && target != home) // I presume that target is not null
resetTarget()
target = home
targetName = "Home"
/mob/living/bot/mulebot/stepToTarget()
if(paused)
return
..()
/mob/living/bot/mulebot/UnarmedAttack(var/turf/T)
if(T == src.loc)
unload(dir)
/mob/living/bot/mulebot/Bump(var/mob/living/M)
if(!safety && istype(M))
@@ -302,28 +247,6 @@
M.Weaken(5)
..()
/mob/living/bot/mulebot/proc/makeStep()
var/turf/next = path[1]
if(next == loc)
path -= next
return
var/moved = step_towards(src, next)
if(moved)
frustration = 0
path -= next
else if(frustration < 6)
if(frustration == 3)
custom_emote(2, "makes an annoyed buzzing sound")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
++frustration
else
custom_emote(2, "makes a sighing buzz.")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
obstacle = next
mode = MULE_LOST
/mob/living/bot/mulebot/proc/runOver(var/mob/living/carbon/human/H)
if(istype(H)) // No safety checks - WILL run over lying humans. Stop ERPing in the maint!
visible_message("<span class='warning'>[src] drives over [H]!</span>")
@@ -362,11 +285,6 @@
new /obj/effect/decal/cleanable/blood/oil(Tsec)
..()
/mob/living/bot/mulebot/proc/calc_path(var/turf/avoid = null)
path = AStar(loc, target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, id = botcard, exclude = avoid)
if(!path)
path = list()
/mob/living/bot/mulebot/proc/load(var/atom/movable/C)
if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc))
return
@@ -384,10 +302,6 @@
if(istype(crate))
crate.close()
//I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool.
//So this is a simple fix that only allows a selection of item types to be considered. Further narrowing-down is below.
//if(!istype(C,/obj/item) && !istype(C,/obj/machinery) && !istype(C,/obj/structure) && !ismob(C))
// return
busy = 1
C.loc = loc
@@ -428,11 +342,3 @@
AM.layer = initial(AM.layer)
AM.pixel_y = initial(AM.pixel_y)
busy = 0
#undef MULE_IDLE
#undef MULE_MOVING
#undef MULE_UNLOAD
#undef MULE_LOST
#undef MULE_CALC_MIN
#undef MULE_CALC_MAX
#undef MULE_PATH_DONE
+45 -308
View File
@@ -6,8 +6,8 @@
health = 50
req_one_access = list(access_security, access_forensics_lockers)
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels)
var/mob/target
patrol_speed = 2
target_speed = 3
var/idcheck = 0 // If true, arrests for having weapons without authorization.
var/check_records = 0 // If true, arrests people without a record.
@@ -16,30 +16,9 @@
var/declare_arrests = 0 // If true, announces arrests over sechuds.
var/auto_patrol = 0 // If true, patrols on its own
var/mode = 0
#define SECBOT_IDLE 0 // idle
#define SECBOT_HUNT 1 // found target, hunting
#define SECBOT_ARREST 2 // arresting target
#define SECBOT_START_PATROL 3 // start patrol
#define SECBOT_WAIT_PATROL 4 // waiting for signals
#define SECBOT_PATROL 5 // patrolling
#define SECBOT_SUMMON 6 // summoned by PDA
var/is_attacking = 0
var/is_ranged = 0
var/awaiting_surrender = 0
var/obj/secbot_listener/listener = null
var/beacon_freq = 1445 // Navigation beacon frequency
var/control_freq = BOT_FREQ // Bot control frequency
var/list/path = list()
var/frustration = 0
var/turf/patrol_target = null // This is where we are headed
var/closest_dist // Used to find the closest beakon
var/destination = "__nearest__" // This is the current beacon's ID
var/next_destination = "__nearest__" // This is the next beacon's ID
var/nearest_beacon // Tag of the beakon that we assume to be the closest one
var/bot_version = 1.3
var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
@@ -48,24 +27,8 @@
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
auto_patrol = 1
/mob/living/bot/secbot/New()
..()
listener = new /obj/secbot_listener(src)
listener.secbot = src
spawn(5) // Since beepsky is made on the start... this delay is necessary
if(radio_controller)
radio_controller.add_object(listener, control_freq, filter = RADIO_SECBOT)
radio_controller.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS)
/mob/living/bot/secbot/turn_off()
..()
target = null
frustration = 0
mode = SECBOT_IDLE
/mob/living/bot/secbot/update_icons()
if(on && is_attacking)
if(on && busy)
icon_state = "secbot-c"
else
icon_state = "secbot[on]"
@@ -78,7 +41,7 @@
/mob/living/bot/secbot/attack_hand(var/mob/user)
user.set_machine(src)
var/dat
dat += "<TT><B>Automatic Security Unit v[bot_version]</B></TT><BR><BR>"
dat += "<TT><B>Automatic Security Unit</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<BR>"
dat += "Maintenance panel is [open ? "opened" : "closed"]"
@@ -89,7 +52,7 @@
dat += "Operating Mode: <A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A><BR>"
dat += "Report Arrests: <A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A><BR>"
dat += "Auto Patrol: <A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>"
user << browse("<HEAD><TITLE>Securitron v[bot_version] controls</TITLE></HEAD>[dat]", "window=autosec")
user << browse("<HEAD><TITLE>Securitron controls</TITLE></HEAD>[dat]", "window=autosec")
onclose(user, "autosec")
return
@@ -118,7 +81,6 @@
arrest_type = !arrest_type
if("patrol")
auto_patrol = !auto_patrol
mode = SECBOT_IDLE
if("declarearrests")
declare_arrests = !declare_arrests
attack_hand(usr)
@@ -129,127 +91,47 @@
if(health < curhealth)
target = user
awaiting_surrender = 5
mode = SECBOT_HUNT
/mob/living/bot/secbot/Life()
/mob/living/bot/secbot/startPatrol()
if(!locked) // Stop running away when we set you up
return
..()
if(!on)
return
if(client)
return
if(!target)
scan_view()
/mob/living/bot/secbot/confirmTarget(var/atom/A)
if(!..())
return 0
if(!locked && (mode == SECBOT_START_PATROL || mode == SECBOT_PATROL)) // Stop running away when we set you up
mode = SECBOT_IDLE
return (check_threat(A) > 3)
switch(mode)
if(SECBOT_IDLE)
if(auto_patrol && locked)
mode = SECBOT_START_PATROL
/mob/living/bot/secbot/lookForTargets()
for(var/mob/living/M in view(src))
if(M.stat == DEAD)
continue
if(confirmTarget(M))
var/threat = check_threat(M)
target = M
awaiting_surrender = -1
say("Level [threat] infraction alert!")
custom_emote(1, "points at [M.name]!")
return
if(SECBOT_HUNT) // Target is in the view or has been recently - chase it
if(frustration > 7)
target = null
frustration = 0
awaiting_surrender = 0
mode = SECBOT_IDLE
return
if(target)
var/threat = check_threat(target)
if(threat < 4) // Re-evaluate in case they dropped the weapon or something
target = null
frustration = 0
awaiting_surrender = 0
mode = SECBOT_IDLE
return
if(!(target in view(7, src)))
++frustration
if(Adjacent(target))
mode = SECBOT_ARREST
return
else
if(is_ranged)
RangedAttack(target)
else
step_towards(src, target) // Melee bots chase a bit faster
spawn(8)
if(!Adjacent(target))
step_towards(src, target)
spawn(16)
if(!Adjacent(target))
step_towards(src, target)
/mob/living/bot/secbot/calcTargetPath()
..()
if(awaiting_surrender != -1)
awaiting_surrender = 5 // This implies that a) we have already approached the target and b) it has moved after the warning
if(SECBOT_ARREST) // Target is next to us - attack it
if(!target)
mode = SECBOT_IDLE
if(!Adjacent(target))
awaiting_surrender = 5 // I'm done playing nice
mode = SECBOT_HUNT
return
var/threat = check_threat(target)
if(threat < 4)
target = null
awaiting_surrender = 0
frustration = 0
mode = SECBOT_IDLE
return
if(awaiting_surrender < 5 && ishuman(target) && !target.lying)
if(awaiting_surrender == 0)
say("Down on the floor, [target]! You have five seconds to comply.")
++awaiting_surrender
else
UnarmedAttack(target)
if(ishuman(target) && declare_arrests)
var/area/location = get_area(src)
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [check_threat(target)] suspect <b>[target]</b> in <b>[location]</b>.", src)
return
if(SECBOT_START_PATROL)
if(path.len && patrol_target)
mode = SECBOT_PATROL
return
else if(patrol_target)
spawn(0)
calc_path()
if(!path.len)
patrol_target = null
mode = SECBOT_IDLE
else
mode = SECBOT_PATROL
if(!patrol_target)
if(next_destination)
find_next_target()
else
find_patrol_target()
say("Engaging patrol mode.")
mode = SECBOT_WAIT_PATROL
return
if(SECBOT_WAIT_PATROL)
if(patrol_target)
mode = SECBOT_START_PATROL
else
++frustration
if(frustration > 120)
frustration = 0
mode = SECBOT_IDLE
if(SECBOT_PATROL)
patrol_step()
spawn(10)
patrol_step()
return
if(SECBOT_SUMMON)
patrol_step()
spawn(8)
patrol_step()
spawn(16)
patrol_step()
return
/mob/living/bot/secbot/handleAdjacentTarget()
if(awaiting_surrender < 5 && ishuman(target) && !target:lying)
if(awaiting_surrender == -1)
say("Down on the floor, [target]! You have five seconds to comply.")
++awaiting_surrender
else
UnarmedAttack(target)
if(ishuman(target) && declare_arrests)
var/area/location = get_area(src)
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [check_threat(target)] suspect <b>[target]</b> in <b>[location]</b>.", src)
// say("Engaging patrol mode.")
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
if(!..())
@@ -271,31 +153,33 @@
C.stun_effect_act(0, 60, null)
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
do_attack_animation(C)
is_attacking = 1
busy = 1
update_icons()
spawn(2)
is_attacking = 0
busy = 0
update_icons()
visible_message("<span class='warning'>[C] was prodded by [src] with a stun baton!</span>")
else
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
visible_message("<span class='warning'>[src] is trying to put handcuffs on [C]!</span>")
busy = 1
if(do_mob(src, C, 60))
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/handcuffs(C)
C.update_inv_handcuffed()
if(preparing_arrest_sounds.len)
playsound(loc, pick(preparing_arrest_sounds), 50, 0)
busy = 0
else if(istype(M, /mob/living/simple_animal))
var/mob/living/simple_animal/S = M
S.AdjustStunned(10)
S.adjustBruteLoss(15)
do_attack_animation(M)
playsound(loc, "swing_hit", 50, 1, -1)
is_attacking = 1
busy = 1
update_icons()
spawn(2)
is_attacking = 0
busy = 0
update_icons()
visible_message("<span class='warning'>[M] was beaten by [src] with a stun baton!</span>")
@@ -319,30 +203,8 @@
new /obj/effect/decal/cleanable/blood/oil(Tsec)
qdel(src)
/mob/living/bot/secbot/proc/scan_view()
for(var/mob/living/M in view(7, src))
if(M.invisibility >= INVISIBILITY_LEVEL_ONE)
continue
if(M.stat)
continue
var/threat = check_threat(M)
if(threat >= 4)
target = M
say("Level [threat] infraction alert!")
custom_emote(1, "points at [M.name]!")
mode = SECBOT_HUNT
break
return
/mob/living/bot/secbot/proc/calc_path(var/turf/avoid = null)
path = AStar(loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
if(!path)
path = list()
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
if(!M || !istype(M) || M.stat || src == M)
if(!M || !istype(M) || M.stat == DEAD || src == M)
return 0
if(emagged)
@@ -350,131 +212,6 @@
return M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest)
/mob/living/bot/secbot/proc/patrol_step()
if(loc == patrol_target)
patrol_target = null
path = list()
mode = SECBOT_IDLE
return
if(path.len && patrol_target)
var/turf/next = path[1]
if(loc == next)
path -= next
return
var/moved = step_towards(src, next)
if(moved)
path -= next
frustration = 0
else
++frustration
if(frustration > 5) // Make a new path
mode = SECBOT_START_PATROL
return
else
mode = SECBOT_START_PATROL
/mob/living/bot/secbot/proc/find_patrol_target()
send_status()
nearest_beacon = null
next_destination = "__nearest__"
listener.post_signal(beacon_freq, "findbeacon", "patrol")
/mob/living/bot/secbot/proc/find_next_target()
send_status()
nearest_beacon = null
listener.post_signal(beacon_freq, "findbeacon", "patrol")
/mob/living/bot/secbot/proc/send_status()
var/list/kv = list(
"type" = "secbot",
"name" = name,
"loca" = get_area(loc),
"mode" = mode
)
listener.post_signal_multiple(control_freq, kv)
/obj/secbot_listener
var/mob/living/bot/secbot/secbot = null
/obj/secbot_listener/proc/post_signal(var/freq, var/key, var/value) // send a radio signal with a single data key/value pair
post_signal_multiple(freq, list("[key]" = value))
/obj/secbot_listener/proc/post_signal_multiple(var/freq, var/list/keyval) // send a radio signal with multiple data key/values
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
if(!frequency)
return
var/datum/signal/signal = new()
signal.source = secbot
signal.transmission_method = 1
signal.data = keyval.Copy()
if(signal.data["findbeacon"])
frequency.post_signal(secbot, signal, filter = RADIO_NAVBEACONS)
else if(signal.data["type"] == "secbot")
frequency.post_signal(secbot, signal, filter = RADIO_SECBOT)
else
frequency.post_signal(secbot, signal)
/obj/secbot_listener/receive_signal(datum/signal/signal)
if(!secbot || !secbot.on)
return
var/recv = signal.data["command"]
if(recv == "bot_status")
secbot.send_status()
return
if(signal.data["active"] == secbot)
switch(recv)
if("stop")
secbot.mode = SECBOT_IDLE
secbot.auto_patrol = 0
return
if("go")
secbot.mode = SECBOT_IDLE
secbot.auto_patrol = 1
return
if("summon")
secbot.patrol_target = signal.data["target"]
secbot.next_destination = secbot.destination
secbot.destination = null
//secbot.awaiting_beacon = 0
secbot.mode = SECBOT_SUMMON
secbot.calc_path()
secbot.say("Responding.")
return
recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!recv || !valid)
return
if(recv == secbot.next_destination) // This beacon is our target
secbot.destination = secbot.next_destination
secbot.patrol_target = signal.source.loc
secbot.next_destination = signal.data["next_patrol"]
else if(secbot.next_destination == "__nearest__")
var/dist = get_dist(secbot, signal.source.loc)
if(dist <= 1)
return
if(secbot.nearest_beacon)
if(dist < secbot.closest_dist)
secbot.nearest_beacon = recv
secbot.patrol_target = secbot.nearest_beacon
secbot.next_destination = signal.data["next_patrol"]
secbot.closest_dist = dist
return
else
secbot.nearest_beacon = recv
secbot.patrol_target = secbot.nearest_beacon
secbot.next_destination = signal.data["next_patrol"]
secbot.closest_dist = dist
//Secbot Construction
/obj/item/clothing/head/helmet/attackby(var/obj/item/device/assembly/signaler/S, mob/user as mob)
@@ -1,7 +1,7 @@
/mob/living/carbon/alien/ex_act(severity)
if(!blinded)
flick("flash", flash)
flash_eyes()
var/b_loss = null
var/f_loss = null
@@ -2,7 +2,7 @@
var/mob/living/carbon/human/H = over_object
if(!istype(H) || !Adjacent(H))
return ..()
if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
if(H.a_intent == "grab" && hat && !H.hands_are_full())
hat.loc = get_turf(src)
H.put_in_hands(hat)
H.visible_message("<span class='danger'>\The [H] removes \the [src]'s [hat].</span>")
@@ -18,8 +18,6 @@
if (client.prefs.muted & MUTE_IC)
src << "\red You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (stat)
return
if(!(message))
+8 -16
View File
@@ -43,8 +43,6 @@
silent = 0
else
updatehealth()
handle_stunned()
handle_weakened()
if(health <= 0)
death()
blinded = 1
@@ -52,7 +50,6 @@
return 1
if(paralysis && paralysis > 0)
handle_paralysed()
blinded = 1
stat = UNCONSCIOUS
if(halloss > 0)
@@ -127,21 +124,16 @@
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if ((blind && stat != 2))
if ( stat != 2)
if ((blinded))
blind.layer = 18
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
blind.layer = 0
if (disabilities & NEARSIGHTED)
client.screen += global_hud.vimpaired
if (eye_blurry)
client.screen += global_hud.blurry
if (druggy)
client.screen += global_hud.druggy
if (stat != 2)
if (machine)
if ( machine.check_eye(src) < 0)
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if(machine)
if(machine.check_eye(src) < 0)
reset_view(null)
else
if(client && !client.adminobs)
@@ -19,8 +19,6 @@
if (client.prefs.muted & MUTE_IC)
src << "\red You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (stat)
return
if(!(message))
@@ -70,7 +68,7 @@
for(var/mob/M in dead_mob_list)
if (!M.client || istype(M, /mob/new_player))
continue //skip monkeys, leavers, and new_players
if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(src,null)))
if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_sight) && !(M in viewers(src,null)))
M.show_message(message)
+9 -31
View File
@@ -157,8 +157,6 @@
src << "\red All systems restored."
emp_damage -= 1
//Other
handle_statuses()
return 1
/mob/living/carbon/brain/handle_regular_hud_updates()
@@ -210,22 +208,15 @@
if (client)
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if ((blind && stat != 2))
if ((blinded))
blind.layer = 18
else
blind.layer = 0
if (disabilities & NEARSIGHTED)
client.screen += global_hud.vimpaired
if (eye_blurry)
client.screen += global_hud.blurry
if (druggy)
client.screen += global_hud.druggy
if (stat != 2)
if ((blinded))
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if (machine)
if (!( machine.check_eye(src) ))
reset_view(null)
@@ -241,17 +232,4 @@
reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
/*/mob/living/carbon/brain/emp_act(severity)
if(!(container && istype(container, /obj/item/device/mmi)))
return
else
switch(severity)
if(1)
emp_damage += rand(20,30)
if(2)
emp_damage += rand(10,20)
if(3)
emp_damage += rand(0,10)
..()*/
reset_view(null)
@@ -23,7 +23,7 @@
spawn(600) reset_search()
/obj/item/device/mmi/digital/posibrain/proc/request_player()
for(var/mob/dead/observer/O in player_list)
for(var/mob/observer/dead/O in player_list)
if(!O.MayRespawn())
continue
if(jobban_isbanned(O, "AI") && jobban_isbanned(O, "Cyborg"))
@@ -74,6 +74,7 @@
/obj/item/device/mmi/digital/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
if(src.brainmob && src.brainmob.key) return
world.log << "Resetting Posibrain: [brainmob][brainmob ? ", [brainmob.key]" : ""]"
src.searching = 0
icon_state = "posibrain"
+20 -18
View File
@@ -194,7 +194,7 @@
status += "hurts when touched"
if(org.status & ORGAN_DEAD)
status += "is bruised and necrotic"
if(!org.is_usable())
if(!org.is_usable() || org.is_dislocated())
status += "dangling uselessly"
if(status.len)
src.show_message("My [org.name] is <span class='warning'> [english_list(status)].</span>",1)
@@ -309,14 +309,19 @@
if(!item) return
var/throw_range = item.throw_range
if (istype(item, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = item
item = G.throw_held() //throw the person instead of the grab
if(ismob(item))
var/mob/M = item
//limit throw range by relative mob size
throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1))
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
if(start_T && end_T)
var/mob/M = item
var/start_T_descriptor = "<font color='#6b5d00'>tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]</font>"
var/end_T_descriptor = "<font color='#6b4400'>tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]</font>"
@@ -324,31 +329,28 @@
usr.attack_log += text("\[[time_stamp()]\] <font color='red'>Has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor]</font>")
msg_admin_attack("[usr.name] ([usr.ckey]) has thrown [M.name] ([M.ckey]) from [start_T_descriptor] with the target [end_T_descriptor] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[usr.x];Y=[usr.y];Z=[usr.z]'>JMP</a>)")
if(!item) return //Grab processing has a chance of returning null
src.remove_from_mob(item)
item.loc = src.loc
src.drop_from_inventory(item)
if(!item || !isturf(item.loc))
return
//actually throw it!
if (item)
src.visible_message("\red [src] has thrown [item].")
src.visible_message("<span class='warning'>[src] has thrown [item].</span>")
if(!src.lastarea)
src.lastarea = get_area(src.loc)
if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0))
src.inertia_dir = get_dir(target, src)
step(src, inertia_dir)
if(!src.lastarea)
src.lastarea = get_area(src.loc)
if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0))
src.inertia_dir = get_dir(target, src)
step(src, inertia_dir)
/*
if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction
src.inertia_dir = get_dir(target, src)
step(src, inertia_dir)
if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction
src.inertia_dir = get_dir(target, src)
step(src, inertia_dir)
*/
item.throw_at(target, item.throw_range, item.throw_speed, src)
item.throw_at(target, throw_range, item.throw_speed, src)
/mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
..()
@@ -0,0 +1,98 @@
//Called when the mob is hit with an item in combat.
/mob/living/carbon/resolve_item_attack(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
if(check_attack_throat(I, user))
return null
..()
/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone)
if(!effective_force || blocked >= 100)
return 0
//Hulk modifier
if(HULK in user.mutations)
effective_force *= 2
//Apply weapon damage
var/weapon_sharp = is_sharp(I)
var/weapon_edge = has_edge(I)
if(prob(getarmor(hit_zone, "melee"))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones
weapon_sharp = 0
weapon_edge = 0
apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I)
//Melee weapon embedded object code.
if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I))
var/damage = effective_force
if (blocked)
damage *= (100 - blocked)/100
//blunt objects should really not be embedding in things unless a huge amount of force is involved
var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3)
var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class
//Sharp objects will always embed if they do enough damage.
if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance)))
src.embed(I, hit_zone)
return 1
// Attacking someone with a weapon while they are neck-grabbed
/mob/living/carbon/proc/check_attack_throat(obj/item/W, mob/user)
if(user.a_intent == I_HURT)
for(var/obj/item/weapon/grab/G in src.grabbed_by)
if(G.assailant == user && G.state >= GRAB_NECK)
if(attack_throat(W, G, user))
return 1
return 0
// Knifing
/mob/living/carbon/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user)
if(!W.edge || !W.force || W.damtype != BRUTE)
return 0 //unsuitable weapon
user.visible_message("<span class='danger'>\The [user] begins to slit [src]'s throat with \the [W]!</span>")
user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly
if(!do_after(user, 20))
return 0
if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab
return 0
var/damage_mod = 1
//presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well
var/obj/item/clothing/head/helmet = get_equipped_item(slot_head)
if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.flags & STOPPRESSUREDAMAGE))
//we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off.
damage_mod = 1.0 - (helmet.armor["melee"]/100)
var/total_damage = 0
for(var/i in 1 to 3)
var/damage = min(W.force*1.5, 20)*damage_mod
apply_damage(damage, W.damtype, "head", 0, sharp=W.sharp, edge=W.edge)
total_damage += damage
var/oxyloss = total_damage
if(total_damage >= 40) //threshold to make someone pass out
oxyloss = 60 // Brain lacks oxygen immediately, pass out
adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss
if(total_damage)
if(oxyloss >= 40)
user.visible_message("<span class='danger'>\The [user] slit [src]'s throat open with \the [W]!</span>")
else
user.visible_message("<span class='danger'>\The [user] cut [src]'s neck with \the [W]!</span>")
if(W.hitsound)
playsound(loc, W.hitsound, 50, 1, -1)
G.last_action = world.time
flick(G.hud.icon_state, G.hud)
user.attack_log += "\[[time_stamp()]\]<font color='red'> Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])</font>"
src.attack_log += "\[[time_stamp()]\]<font color='orange'> Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])</font>"
msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" )
return 1
+15 -15
View File
@@ -3,40 +3,40 @@
set name = "Give"
// TODO : Change to incapacitated() on merge.
if(usr.stat || usr.lying || usr.resting || usr.buckled)
if(src.stat || src.lying || src.resting || src.buckled)
return
if(!istype(target) || target.stat || target.lying || target.resting || target.buckled || target.client == null)
return
var/obj/item/I = usr.get_active_hand()
var/obj/item/I = src.get_active_hand()
if(!I)
I = usr.get_inactive_hand()
I = src.get_inactive_hand()
if(!I)
usr << "<span class='warning'>You don't have anything in your hands to give to \the [target].</span>"
src << "<span class='warning'>You don't have anything in your hands to give to \the [target].</span>"
return
if(alert(target,"[usr] wants to give you \a [I]. Will you accept it?",,"No","Yes") == "No")
target.visible_message("<span class='notice'>\The [usr] tried to hand \the [I] to \the [target], \
if(alert(target,"[src] wants to give you \a [I]. Will you accept it?",,"No","Yes") == "No")
target.visible_message("<span class='notice'>\The [src] tried to hand \the [I] to \the [target], \
but \the [target] didn't want it.</span>")
return
if(!I) return
if(!Adjacent(target))
usr << "<span class='warning'>You need to stay in reaching distance while giving an object.</span>"
target << "<span class='warning'>\The [usr] moved too far away.</span>"
src << "<span class='warning'>You need to stay in reaching distance while giving an object.</span>"
target << "<span class='warning'>\The [src] moved too far away.</span>"
return
if(I.loc != usr || (usr.l_hand != I && usr.r_hand != I))
usr << "<span class='warning'>You need to keep the item in your hands.</span>"
target << "<span class='warning'>\The [usr] seems to have given up on passing \the [I] to you.</span>"
if(I.loc != src || !src.item_is_in_hands(I))
src << "<span class='warning'>You need to keep the item in your hands.</span>"
target << "<span class='warning'>\The [src] seems to have given up on passing \the [I] to you.</span>"
return
if(target.r_hand != null && target.l_hand != null)
if(target.hands_are_full())
target << "<span class='warning'>Your hands are full.</span>"
usr << "<span class='warning'>Their hands are full.</span>"
src << "<span class='warning'>Their hands are full.</span>"
return
if(usr.unEquip(I))
if(src.unEquip(I))
target.put_in_hands(I) // If this fails it will just end up on the floor, but that's fitting for things like dionaea.
target.visible_message("<span class='notice'>\The [usr] handed \the [I] to \the [target].</span>")
target.visible_message("<span class='notice'>\The [src] handed \the [I] to \the [target].</span>")
@@ -143,13 +143,13 @@
var/datum/species/current_species = all_species[current_species_name]
if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it!
if(!(current_species.spawn_flags & CAN_JOIN))
if(!(current_species.spawn_flags & SPECIES_CAN_JOIN))
continue
if(whitelist.len && !(current_species_name in whitelist))
continue
if(blacklist.len && (current_species_name in blacklist))
continue
if((current_species.spawn_flags & IS_WHITELISTED) && !is_alien_whitelisted(src, current_species_name))
if((current_species.spawn_flags & SPECIES_IS_WHITELISTED) && !is_alien_whitelisted(src, current_species_name))
continue
valid_species += current_species_name
@@ -158,9 +158,9 @@
/mob/living/carbon/human/proc/generate_valid_hairstyles(var/check_gender = 1)
var/use_species = species.get_bodytype()
var/use_species = species.get_bodytype(src)
var/obj/item/organ/external/head/H = get_organ(BP_HEAD)
if(H) use_species = H.species.get_bodytype()
if(H) use_species = H.species.get_bodytype(src)
var/list/valid_hairstyles = new()
for(var/hairstyle in hair_styles_list)
@@ -180,9 +180,9 @@
/mob/living/carbon/human/proc/generate_valid_facial_hairstyles()
var/use_species = species.get_bodytype()
var/use_species = species.get_bodytype(src)
var/obj/item/organ/external/head/H = get_organ(BP_HEAD)
if(H) use_species = H.species.get_bodytype()
if(H) use_species = H.species.get_bodytype(src)
var/list/valid_facial_hairstyles = new()
for(var/facialhairstyle in facial_hair_styles_list)
@@ -31,19 +31,18 @@
BITSET(hud_updateflag, STATUS_HUD)
BITSET(hud_updateflag, LIFE_HUD)
handle_hud_list()
//Handle species-specific deaths.
species.handle_death(src)
animate_tail_stop()
//Handle brain slugs.
var/obj/item/organ/external/head = get_organ(BP_HEAD)
var/obj/item/organ/external/Hd = get_organ(BP_HEAD)
var/mob/living/simple_animal/borer/B
for(var/I in head.implants)
if(istype(I,/mob/living/simple_animal/borer))
B = I
if(Hd)
for(var/I in Hd.implants)
if(istype(I,/mob/living/simple_animal/borer))
B = I
if(B)
if(!B.ckey && ckey && B.controlling)
B.ckey = ckey
@@ -112,8 +112,6 @@
if (client.prefs.muted & MUTE_IC)
src << "\red You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (stat)
return
if(!(message))
@@ -538,9 +536,9 @@
if ("handshake")
m_type = 1
if (!src.restrained() && !src.r_hand)
var/mob/M = null
var/mob/living/M = null
if (param)
for (var/mob/A in view(1, null))
for (var/mob/living/A in view(1, null))
if (param == A.name)
M = A
break
+69 -22
View File
@@ -4,29 +4,72 @@
var/skipjumpsuit = 0
var/skipshoes = 0
var/skipmask = 0
var/skipears = 0
var/skipeyes = 0
var/skipface = 0
var/skipchest = 0
var/skipgroin = 0
var/skiphands = 0
var/skiplegs = 0
var/skiparms = 0
var/skipfeet = 0
var/looks_synth = looksSynthetic()
//exosuits and helmets obscure our view and stuff.
if(wear_suit)
skipgloves = wear_suit.flags_inv & HIDEGLOVES
skipsuitstorage = wear_suit.flags_inv & HIDESUITSTORAGE
skipjumpsuit = wear_suit.flags_inv & HIDEJUMPSUIT
skipshoes = wear_suit.flags_inv & HIDESHOES
skipsuitstorage |= wear_suit.flags_inv & HIDESUITSTORAGE
if(wear_suit.flags_inv & HIDEJUMPSUIT)
skiparms |= 1
skiplegs |= 1
skipchest |= 1
skipgroin |= 1
if(wear_suit.flags_inv & HIDESHOES)
skipshoes |= 1
skipfeet |= 1
if(wear_suit.flags_inv & HIDEGLOVES)
skipgloves |= 1
skiphands |= 1
if(w_uniform)
skiplegs |= w_uniform.body_parts_covered & LEGS
skiparms |= w_uniform.body_parts_covered & ARMS
skipchest |= w_uniform.body_parts_covered & UPPER_TORSO
skipgroin |= w_uniform.body_parts_covered & LOWER_TORSO
if(gloves)
skiphands |= gloves.body_parts_covered & HANDS
if(shoes)
skipfeet |= shoes.body_parts_covered & FEET
if(head)
skipmask = head.flags_inv & HIDEMASK
skipeyes = head.flags_inv & HIDEEYES
skipears = head.flags_inv & HIDEEARS
skipface = head.flags_inv & HIDEFACE
skipmask |= head.flags_inv & HIDEMASK
skipeyes |= head.flags_inv & HIDEEYES
skipears |= head.flags_inv & HIDEEARS
skipface |= head.flags_inv & HIDEFACE
if(wear_mask)
skipface |= wear_mask.flags_inv & HIDEFACE
//This is what hides what
var/list/hidden = list(
BP_GROIN = skipgroin,
BP_TORSO = skipchest,
BP_HEAD = skipface,
BP_L_ARM = skiparms,
BP_R_ARM = skiparms,
BP_L_HAND= skiphands,
BP_R_HAND= skiphands,
BP_L_FOOT= skipfeet,
BP_R_FOOT= skipfeet,
BP_L_LEG = skiplegs,
BP_R_LEG = skiplegs)
var/msg = "<span class='info'>*---------*\nThis is "
var/datum/gender/T = gender_datums[gender]
var/datum/gender/T = gender_datums[get_gender()]
if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender
T = gender_datums[PLURAL]
else
@@ -39,19 +82,23 @@
msg += "<EM>[src.name]</EM>"
var/is_synth = isSynthetic()
if(!(skipjumpsuit && skipface))
if(is_synth)
if(looks_synth)
var/use_gender = "a synthetic"
if(gender == MALE)
use_gender = "an android"
else if(gender == FEMALE)
use_gender = "a gynoid"
msg += ", <font color='#555555'>[use_gender]!</font></b>"
msg += ", <b><font color='#555555'>[use_gender]!</font></b>"
else if(species.name != "Human")
msg += ", <b><font color='[species.get_flesh_colour(src)]'>\a [species.name]!</font></b>"
msg += ", <b><font color='[species.get_flesh_colour(src)]'>\a [species.get_examine_name()]!</font></b>"
var/extra_species_text = species.get_additional_examine_text(src)
if(extra_species_text)
msg += "[extra_species_text]<br>"
msg += "<br>"
//uniform
@@ -119,8 +166,6 @@
else if(blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!</span>\n"
//handcuffed?
//handcuffed?
if(handcuffed)
if(istype(handcuffed, /obj/item/weapon/handcuffs/cable))
@@ -210,7 +255,7 @@
msg += "[T.He] [T.is] small halfling!\n"
var/distance = get_dist(usr,src)
if(istype(usr, /mob/dead/observer) || usr.stat == 2) // ghosts can see anything
if(istype(usr, /mob/observer/dead) || usr.stat == 2) // ghosts can see anything
distance = 1
if (src.stat)
msg += "<span class='warning'>[T.He] [T.is]n't responding to anything around [T.him] and seems to be asleep.</span>\n"
@@ -268,21 +313,23 @@
for(var/obj/item/organ/external/temp in organs)
if(temp)
if((temp.organ_tag in hidden) && hidden[temp.organ_tag])
continue //Organ is hidden, don't talk about it
if(temp.status & ORGAN_DESTROYED)
wound_flavor_text["[temp.name]"] = "<span class='warning'><b>[T.He] [T.is] missing [T.his] [temp.name].</b></span>\n"
continue
if(!is_synth && temp.status & ORGAN_ROBOT)
if(!looks_synth && temp.robotic == ORGAN_ROBOT)
if(!(temp.brute_dam + temp.burn_dam))
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] a [temp.name]!</span>\n"
continue
wound_flavor_text["[temp.name]"] = "[T.He] [T.has] a [temp.name].\n"
else
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] a [temp.name]. It has[temp.get_wounds_desc()]!</span>\n"
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] [T.has] a [temp.name] with [temp.get_wounds_desc()]!</span>\n"
continue
else if(temp.wounds.len > 0 || temp.open)
if(temp.is_stump() && temp.parent_organ && organs_by_name[temp.parent_organ])
var/obj/item/organ/external/parent = organs_by_name[temp.parent_organ]
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] has [temp.get_wounds_desc()] on [T.His] [parent.name].</span><br>"
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] has [temp.get_wounds_desc()] on [T.his] [parent.name].</span><br>"
else
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] has [temp.get_wounds_desc()] on [T.His] [temp.name].</span><br>"
wound_flavor_text["[temp.name]"] = "<span class='warning'>[T.He] has [temp.get_wounds_desc()] on [T.his] [temp.name].</span><br>"
if(temp.status & ORGAN_BLEEDING)
is_bleeding["[temp.name]"] = "<span class='danger'>[T.His] [temp.name] is bleeding!</span><br>"
else
+29 -25
View File
@@ -56,8 +56,8 @@
/mob/living/carbon/human/Stat()
..()
if(statpanel("Status"))
stat(null, "Intent: [a_intent]")
stat(null, "Move Mode: [m_intent]")
stat("Intent:", "[a_intent]")
stat("Move Mode:", "[m_intent]")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
if(eta_status)
@@ -84,7 +84,7 @@
/mob/living/carbon/human/ex_act(severity)
if(!blinded)
flick("flash", flash)
flash_eyes()
var/shielded = 0
var/b_loss = null
@@ -150,21 +150,21 @@
update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message)
if(update) UpdateDamageIcon()
/mob/living/carbon/human/proc/implant_loyalty(mob/living/carbon/human/M, override = FALSE) // Won't override by default.
/mob/living/carbon/human/proc/implant_loyalty(override = FALSE) // Won't override by default.
if(!config.use_loyalty_implants && !override) return // Nuh-uh.
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(M)
L.imp_in = M
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(src)
L.imp_in = src
L.implanted = 1
var/obj/item/organ/external/affected = M.organs_by_name[BP_HEAD]
var/obj/item/organ/external/affected = src.organs_by_name[BP_HEAD]
affected.implants += L
L.part = affected
L.implanted(src)
/mob/living/carbon/human/proc/is_loyalty_implanted(mob/living/carbon/human/M)
for(var/L in M.contents)
/mob/living/carbon/human/proc/is_loyalty_implanted()
for(var/L in src.contents)
if(istype(L, /obj/item/weapon/implant/loyalty))
for(var/obj/item/organ/external/O in M.organs)
for(var/obj/item/organ/external/O in src.organs)
if(L in O.implants)
return 1
return 0
@@ -326,11 +326,19 @@
//Removed the horrible safety parameter. It was only being used by ninja code anyways.
//Now checks siemens_coefficient of the affected area by default
/mob/living/carbon/human/electrocute_act(var/shock_damage, var/obj/source, var/base_siemens_coeff = 1.0, var/def_zone = null)
if(status_flags & GODMODE) return 0 //godmode
if (!def_zone)
def_zone = pick("l_hand", "r_hand")
if(species.siemens_coefficient == -1)
if(stored_shock_by_ref["\ref[src]"])
stored_shock_by_ref["\ref[src]"] += shock_damage
else
stored_shock_by_ref["\ref[src]"] = shock_damage
return
var/obj/item/organ/external/affected_organ = get_organ(check_zone(def_zone))
var/siemens_coeff = base_siemens_coeff * get_siemens_coefficient_organ(affected_organ)
@@ -766,13 +774,6 @@
b_eyes = hex2num(copytext(new_eyes, 6, 8))
update_eyes()
var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[35-s_tone]") as text
if (!new_tone)
new_tone = 35
s_tone = max(min(round(text2num(new_tone)), 220), 1)
s_tone = -s_tone + 35
// hair
var/list/all_hairs = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair
var/list/hairs = list()
@@ -842,7 +843,7 @@
target.show_message("\blue You hear a voice that seems to echo around the room: [say]")
usr.show_message("\blue You project your mind into [target.real_name]: [say]")
log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]")
for(var/mob/dead/observer/G in world)
for(var/mob/observer/dead/G in world)
G.show_message("<i>Telepathic message from <b>[src]</b> to <b>[target]</b>: [say]</i>")
/mob/living/carbon/human/proc/remoteobserve()
@@ -1022,7 +1023,7 @@
src << msg
organ.take_damage(rand(1,3), 0, 0)
if(!(organ.status & ORGAN_ROBOT) && !should_have_organ(O_HEART)) //There is no blood in protheses.
if(!(organ.robotic >= ORGAN_ROBOT) && !(should_have_organ(O_HEART))) //There is no blood in protheses.
organ.status |= ORGAN_BLEEDING
src.adjustToxLoss(rand(1,3))
@@ -1104,6 +1105,9 @@
if(species.holder_type)
holder_type = species.holder_type
if(!(gender in species.genders))
gender = species.genders[1]
icon_state = lowertext(species.name)
species.create_organs(src)
@@ -1115,9 +1119,11 @@
spawn(0)
regenerate_icons()
if(vessel.total_volume < species.blood_volume)
vessel.maximum_volume = species.blood_volume
vessel.add_reagent("blood", species.blood_volume - vessel.total_volume)
else if(vessel.total_volume > species.blood_volume)
vessel.remove_reagent("blood", vessel.total_volume - species.blood_volume)
vessel.maximum_volume = species.blood_volume
fixblood()
// Rebuild the HUD. If they aren't logged in then login() should reinstantiate it for them.
@@ -1127,8 +1133,6 @@
qdel(hud_used)
hud_used = new /datum/hud(src)
full_prosthetic = null
if(species)
return 1
else
@@ -1203,7 +1207,7 @@
if(!affecting)
. = 0
fail_msg = "They are missing that limb."
else if (affecting.status & ORGAN_ROBOT)
else if (affecting.robotic >= ORGAN_ROBOT)
. = 0
fail_msg = "That limb is robotic."
else
@@ -1320,8 +1324,8 @@
var/list/limbs = list()
for(var/limb in organs_by_name)
var/obj/item/organ/external/current_limb = organs_by_name[limb]
if(current_limb && current_limb.dislocated == 2)
limbs |= limb
if(current_limb && current_limb.dislocated > 0 && !current_limb.is_parent_dislocated()) //if the parent is also dislocated you will have to relocate that first
limbs |= current_limb
var/choice = input(usr,"Which joint do you wish to relocate?") as null|anything in limbs
if(!choice)
@@ -1431,7 +1435,7 @@
else if(organ_check in list(O_LIVER, O_KIDNEYS))
affecting = organs_by_name[BP_GROIN]
if(affecting && (affecting.status & ORGAN_ROBOT))
if(affecting && (affecting.robotic >= ORGAN_ROBOT))
return 0
return (species && species.has_organ[organ_check])
@@ -310,23 +310,6 @@
updatehealth()
return 1
/mob/living/carbon/human/proc/attack_joint(var/obj/item/W, var/mob/living/user, var/def_zone)
if(!def_zone) def_zone = user.zone_sel.selecting
var/target_zone = get_zone_with_miss_chance(check_zone(def_zone), src)
if(user == src) // Attacking yourself can't miss
target_zone = user.zone_sel.selecting
if(!target_zone)
return null
var/obj/item/organ/external/organ = get_organ(check_zone(target_zone))
if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1))
return null
var/dislocation_str
if(prob(W.force))
dislocation_str = "[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!"
organ.dislocate(1)
return dislocation_str
//Used to attack a joint through grabbing
/mob/living/carbon/human/proc/grab_joint(var/mob/living/user, var/def_zone)
var/has_grab = 0
@@ -343,7 +326,7 @@
if(!target_zone)
return 0
var/obj/item/organ/external/organ = get_organ(check_zone(target_zone))
if(!organ || organ.is_dislocated() || organ.dislocated == -1)
if(!organ || organ.dislocated > 0 || organ.dislocated == -1) //don't use is_dislocated() here, that checks parent
return 0
user.visible_message("<span class='warning'>[user] begins to dislocate [src]'s [organ.joint]!</span>")
@@ -9,8 +9,8 @@
var/total_burn = 0
var/total_brute = 0
for(var/obj/item/organ/external/O in organs) //hardcoded to streamline things a bit
if((O.status & ORGAN_ROBOT) && !O.vital)
continue // Non-vital robot limbs don't count towards shock and crit
if((O.robotic >= ORGAN_ROBOT) && !O.vital)
continue //*non-vital* robot limbs don't count towards shock and crit
total_brute += O.brute_dam
total_burn += O.burn_dam
@@ -67,7 +67,7 @@
/mob/living/carbon/human/getBruteLoss()
var/amount = 0
for(var/obj/item/organ/external/O in organs)
if((O.status & ORGAN_ROBOT) && !O.vital)
if(O.robotic >= ORGAN_ROBOT)
continue //robot limbs don't count towards shock and crit
amount += O.brute_dam
return amount
@@ -75,7 +75,7 @@
/mob/living/carbon/human/getFireLoss()
var/amount = 0
for(var/obj/item/organ/external/O in organs)
if((O.status & ORGAN_ROBOT) && !O.vital)
if(O.robotic >= ORGAN_ROBOT)
continue //robot limbs don't count towards shock and crit
amount += O.burn_dam
return amount
@@ -106,7 +106,7 @@
O.take_damage(amount, 0, sharp=is_sharp(damage_source), edge=has_edge(damage_source), used_weapon=damage_source)
else
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
O.heal_damage(-amount, 0, internal=0, robo_repair=(O.status & ORGAN_ROBOT))
O.heal_damage(-amount, 0, internal=0, robo_repair=(O.robotic >= ORGAN_ROBOT))
BITSET(hud_updateflag, HEALTH_HUD)
@@ -119,7 +119,7 @@
O.take_damage(0, amount, sharp=is_sharp(damage_source), edge=has_edge(damage_source), used_weapon=damage_source)
else
//if you don't want to heal robot organs, they you will have to check that yourself before using this proc.
O.heal_damage(0, -amount, internal=0, robo_repair=(O.status & ORGAN_ROBOT))
O.heal_damage(0, -amount, internal=0, robo_repair=(O.robotic >= ORGAN_ROBOT))
BITSET(hud_updateflag, HEALTH_HUD)
@@ -266,7 +266,6 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t
UpdateDamageIcon()
BITSET(hud_updateflag, HEALTH_HUD)
updatehealth()
speech_problem_flag = 1
//Heal MANY external organs, in random order
@@ -288,7 +287,6 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t
parts -= picked
updatehealth()
BITSET(hud_updateflag, HEALTH_HUD)
speech_problem_flag = 1
if(update) UpdateDamageIcon()
// damage MANY external organs, in random order
@@ -57,7 +57,7 @@ emp_act
msg_admin_attack("[src.name] ([src.ckey]) was disarmed by a stun effect")
drop_from_inventory(c_hand)
if (affected.status & ORGAN_ROBOT)
if (affected.robotic >= ORGAN_ROBOT)
emote("me", 1, "drops what they were holding, their [affected.name] malfunctioning!")
else
var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ")
@@ -92,7 +92,7 @@ emp_act
if (!def_zone)
return 1.0
var/siemens_coefficient = species.siemens_coefficient
var/siemens_coefficient = max(species.siemens_coefficient,0)
var/list/clothing_items = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) // What all are we checking?
for(var/obj/item/clothing/C in clothing_items)
@@ -139,67 +139,75 @@ emp_act
if(.) return
return 0
//Returns 1 if the attack hit, 0 if it missed.
/mob/living/carbon/human/proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone)
if(!I || !user) return 0
/mob/living/carbon/human/emp_act(severity)
for(var/obj/O in src)
if(!O) continue
O.emp_act(severity)
..()
var/target_zone = def_zone? check_zone(def_zone) : get_zone_with_miss_chance(user.zone_sel.selecting, src)
/mob/living/carbon/human/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone)
if(check_attack_throat(I, user))
return null
if(user == src) // Attacking yourself can't miss
target_zone = user.zone_sel.selecting
if(!target_zone)
visible_message("<span class='danger'>[user] misses [src] with \the [I]!</span>")
return 0
return target_zone
var/obj/item/organ/external/affecting = get_organ(target_zone)
var/hit_zone = get_zone_with_miss_chance(target_zone, src)
if(!hit_zone)
visible_message("<span class='danger'>\The [user] misses [src] with \the [I]!</span>")
return null
if(check_shields(I.force, I, user, target_zone, "the [I.name]"))
return
var/obj/item/organ/external/affecting = get_organ(hit_zone)
if (!affecting || affecting.is_stump())
user << "<span class='danger'>They are missing that limb!</span>"
return null
return hit_zone
/mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
var/obj/item/organ/external/affecting = get_organ(hit_zone)
if(!affecting)
return //should be prevented by attacked_with_item() but for sanity.
visible_message("<span class='danger'>[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name] with [I.name] by [user]!</span>")
var/blocked = run_armor_check(hit_zone, "melee", I.armor_penetration, "Your armor has protected your [affecting.name].", "Your armor has softened the blow to your [affecting.name].")
standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone)
return blocked
/mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone)
var/obj/item/organ/external/affecting = get_organ(hit_zone)
if(!affecting)
return 0
var/effective_force = I.force
if(user.a_intent == "disarm") effective_force = round(I.force/2)
var/hit_area = affecting.name
// Handle striking to cripple.
if(user.a_intent == I_DISARM)
effective_force *= 0.66 //reduced effective force...
if(!..(I, user, effective_force, blocked, hit_zone))
return 0
if((user != src) && check_shields(effective_force, I, user, target_zone, "the [I.name]"))
//set the dislocate mult less than the effective force mult so that
//dislocating limbs on disarm is a bit easier than breaking limbs on harm
attack_joint(affecting, I, effective_force, 0.5, blocked) //...but can dislocate joints
else if(!..())
return 0
if(istype(I,/obj/item/weapon/card/emag))
if(!(affecting.status & ORGAN_ROBOT))
user << "\red That limb isn't robotic."
if(effective_force > 10 || effective_force >= 5 && prob(33))
forcesay(hit_appends) //forcesay checks stat already
if(prob(25 + (effective_force * 2)))
if(!((I.damtype == BRUTE) || (I.damtype == HALLOSS)))
return
if(affecting.sabotaged)
user << "\red [src]'s [affecting.name] is already sabotaged!"
else
user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties."
var/obj/item/weapon/card/emag/emag = I
emag.uses--
affecting.sabotaged = 1
return 1
if(I.attack_verb.len)
visible_message("\red <B>[src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!</B>")
else
visible_message("\red <B>[src] has been attacked in the [hit_area] with [I.name] by [user]!</B>")
if(!(I.flags & NOBLOODY))
I.add_blood(src)
var/armor = run_armor_check(affecting, "melee", I.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].")
var/weapon_sharp = is_sharp(I)
var/weapon_edge = has_edge(I)
if ((weapon_sharp || weapon_edge) && prob(getarmor(target_zone, "melee")))
weapon_sharp = 0
weapon_edge = 0
if(armor >= 100) return 0
if(!effective_force) return 0
var/Iforce = effective_force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
apply_damage(effective_force, I.damtype, affecting, armor, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I)
var/bloody = 0
if(((I.damtype == BRUTE) || (I.damtype == HALLOSS)) && prob(25 + (effective_force * 2)))
I.add_blood(src) //Make the weapon bloody, not the person.
// if(user.hand) user.update_inv_l_hand() //updates the attacker's overlay for the (now bloodied) weapon
// else user.update_inv_r_hand() //removed because weapons don't have on-mob blood overlays
var/bloody = 0
if(prob(33))
bloody = 1
var/turf/location = loc
@@ -212,49 +220,55 @@ emp_act
H.bloody_hands(src)
if(!stat)
if(headcheck(hit_area))
//Harder to score a stun but if you do it lasts a bit longer
if(prob(effective_force))
apply_effect(20, PARALYZE, armor)
visible_message("<span class='danger'>[src] [species.get_knockout_message(src)]</span>")
else
//Easier to score a stun but lasts less time
if(prob(effective_force + 10))
apply_effect(6, WEAKEN, armor)
visible_message("<span class='danger'>[src] has been knocked down!</span>")
switch(hit_zone)
if("head")//Harder to score a stun but if you do it lasts a bit longer
if(prob(effective_force))
apply_effect(20, PARALYZE, blocked)
visible_message("<span class='danger'>\The [src] has been knocked unconscious!</span>")
if(bloody)//Apply blood
if(wear_mask)
wear_mask.add_blood(src)
update_inv_wear_mask(0)
if(head)
head.add_blood(src)
update_inv_head(0)
if(glasses && prob(33))
glasses.add_blood(src)
update_inv_glasses(0)
if("chest")//Easier to score a stun but lasts less time
if(prob(effective_force + 10))
apply_effect(6, WEAKEN, blocked)
visible_message("<span class='danger'>\The [src] has been knocked down!</span>")
if(bloody)
bloody_body(src)
//Apply blood
if(bloody)
switch(hit_area)
if(BP_HEAD)
if(wear_mask)
wear_mask.add_blood(src)
update_inv_wear_mask(0)
if(head)
head.add_blood(src)
update_inv_head(0)
if(glasses && prob(33))
glasses.add_blood(src)
update_inv_glasses(0)
if(BP_TORSO)
bloody_body(src)
return 1
if(Iforce > 10 || Iforce >= 5 && prob(33))
forcesay(hit_appends) //forcesay checks stat already
/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/effective_force, var/dislocate_mult, var/blocked)
if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 100)
return 0
//Melee weapon embedded object code.
if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I))
var/damage = effective_force
if (armor)
damage /= armor+1
if(W.damtype != BRUTE)
return 0
//blunt objects should really not be embedding in things unless a huge amount of force is involved
var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3)
var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class
//want the dislocation chance to be such that the limb is expected to dislocate after dealing a fraction of the damage needed to break the limb
var/dislocate_chance = effective_force/(dislocate_mult * organ.min_broken_damage * config.organ_health_multiplier)*100
if(prob(dislocate_chance * (100 - blocked)/100))
visible_message("<span class='danger'>[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!</span>")
organ.dislocate(1)
return 1
return 0
//Sharp objects will always embed if they do enough damage.
if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance)))
affecting.embed(I)
/mob/living/carbon/human/emag_act(var/remaining_charges, mob/user, var/emag_source)
var/obj/item/organ/external/affecting = get_organ(user.zone_sel.selecting)
if(!affecting || !(affecting.status & ORGAN_ROBOT))
user << "<span class='warning'>That limb isn't robotic.</span>"
return -1
if(affecting.sabotaged)
user << "<span class='warning'>[src]'s [affecting.name] is already sabotaged!</span>"
return -1
user << "<span class='notice'>You sneakily slide [emag_source] into the dataport on [src]'s [affecting.name] and short out the safeties.</span>"
affecting.sabotaged = 1
return 1
//this proc handles being hit by a thrown atom
@@ -31,11 +31,10 @@
var/age = 30 //Player's age (pure fluff)
var/b_type = "A+" //Player's bloodtype
var/synthetic //If they are a synthetic (aka synthetic torso)
var/underwear_top = 1 //Which underwear the player wants
var/underwear_bottom = 1
var/undershirt = 0 //Which undershirt the player wants.
var/socks = 0 //Which socks the player wants.
var/list/all_underwear = list()
var/list/all_underwear_metadata = list()
var/backbag = 2 //Which backpack type the player has chosen. Nothing, Satchel or Backpack.
var/pdachoice = 1 //Which PDA type the player has chosen. Default, Slim, or Old.
@@ -69,8 +68,6 @@
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
var/speech_problem_flag = 0
var/miming = null //Toggle for the mime's abilities.
var/special_voice = "" // For changing our voice. Used by a symptom.
@@ -85,9 +82,10 @@
var/list/flavor_texts = list()
var/gunshot_residue
var/pulling_punches // Are you trying not to hurt your opponent?
var/full_prosthetic // We are a robutt.
var/robolimb_count = 0 // Number of robot limbs.
mob_bump_flag = HUMAN
mob_push_flags = ~HEAVY
mob_swap_flags = ~HEAVY
var/identifying_gender // In case the human identifies as another gender than it's biological
@@ -55,6 +55,40 @@
sum += H.ear_protection
return sum
/mob/living/carbon/human/get_gender()
return identifying_gender ? identifying_gender : gender
// This is the 'mechanical' check for synthetic-ness, not appearance
// Returns the company that made the synthetic
/mob/living/carbon/human/isSynthetic()
if(synthetic) return synthetic //Your synthetic-ness is not going away
var/obj/item/organ/external/T = organs_by_name[BP_TORSO]
if(T && T.robotic >= ORGAN_ROBOT)
src.verbs += /mob/living/carbon/human/proc/self_diagnostics
var/datum/robolimb/R = all_robolimbs[T.model]
synthetic = R
return synthetic
return 0
// Would an onlooker know this person is synthetic?
// Based on sort of logical reasoning, 'Look at head, look at torso'
/mob/living/carbon/human/proc/looksSynthetic()
var/obj/item/organ/external/T = organs_by_name[BP_TORSO]
var/obj/item/organ/external/H = organs_by_name[BP_HEAD]
//Look at their head
if(!head || !(head && (head.flags_inv & HIDEFACE)))
if(H && H.robotic == ORGAN_ROBOT) //Exactly robotic, not higher as lifelike is higher
return 1
//Look at their torso
if(!wear_suit || (wear_suit && !(wear_suit.flags_inv & HIDEJUMPSUIT)))
if(!w_uniform || (w_uniform && !(w_uniform.body_parts_covered & UPPER_TORSO)))
if(T && T.robotic == ORGAN_ROBOT)
return 1
return 0
#undef HUMAN_EATING_NO_ISSUE
#undef HUMAN_EATING_NO_MOUTH
@@ -25,8 +25,15 @@
var/hungry = (500 - nutrition)/5 // So overeat would be 100 and default level would be 80
if (hungry >= 70) tally += hungry/50
if(wear_suit)
tally += wear_suit.slowdown
// Loop through some slots, and add up their slowdowns. Shoes are handled below, unfortunately.
// Includes slots which can provide armor, the back slot, and suit storage.
for(var/obj/item/I in list(wear_suit, w_uniform, back, gloves, head, s_store) )
tally += I.slowdown
// Hands are also included, to make the 'take off your armor instantly and carry it with you to go faster' trick no longer viable.
// This is done seperately to disallow negative numbers.
for(var/obj/item/I in list(r_hand, l_hand) )
tally += max(I.slowdown, 0)
if(istype(buckled, /obj/structure/bed/chair/wheelchair))
for(var/organ_name in list(BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM))
@@ -9,15 +9,24 @@
/mob/living/carbon/human/var/list/organs_by_name = list() // map organ names to organs
/mob/living/carbon/human/var/list/internal_organs_by_name = list() // so internal organs have less ickiness too
/mob/living/carbon/human/proc/get_bodypart_name(var/zone)
var/obj/item/organ/external/E = get_organ(zone)
if(E) . = E.name
/mob/living/carbon/human/proc/recheck_bad_external_organs()
var/damage_this_tick = getToxLoss()
for(var/obj/item/organ/external/O in organs)
damage_this_tick += O.burn_dam + O.brute_dam
if(damage_this_tick > last_dam)
. = TRUE
last_dam = damage_this_tick
// Takes care of organ related updates, such as broken and missing limbs
/mob/living/carbon/human/proc/handle_organs()
number_wounds = 0
var/force_process = 0
var/damage_this_tick = getBruteLoss() + getFireLoss() + getToxLoss()
if(damage_this_tick > last_dam)
force_process = 1
last_dam = damage_this_tick
var/force_process = recheck_bad_external_organs()
if(force_process)
bad_external_organs.Cut()
for(var/obj/item/organ/external/Ex in organs)
@@ -59,7 +68,7 @@
/mob/living/carbon/human/proc/handle_stance()
// Don't need to process any of this if they aren't standing anyways
// unless their stance is damaged, and we want to check if they should stay down
if (!stance_damage && (lying || resting) && (life_tick % 4) == 0)
if (!stance_damage && (lying || resting) && (life_tick % 4) != 0)
return
stance_damage = 0
@@ -71,7 +80,7 @@
var/limb_pain
for(var/limb_tag in list("l_leg","r_leg","l_foot","r_foot"))
var/obj/item/organ/external/E = organs_by_name[limb_tag]
if(!E || (E.status & (ORGAN_MUTATED|ORGAN_DEAD)) || E.is_stump()) //should just be !E.is_usable() here but dislocation screws that up.
if(!E || !E.is_usable())
stance_damage += 2 // let it fail even if just foot&leg
else if (E.is_malfunctioning())
//malfunctioning only happens intermittently so treat it as a missing limb when it procs
@@ -84,7 +93,7 @@
spark_system.start()
spawn(10)
qdel(spark_system)
else if (E.is_broken() || !E.is_usable())
else if (E.is_broken())
stance_damage += 1
else if (E.is_dislocated())
stance_damage += 0.5
@@ -71,7 +71,7 @@
var/mob/M = targets[target]
if(istype(M, /mob/dead/observer) || M.stat == DEAD)
if(istype(M, /mob/observer/dead) || M.stat == DEAD)
src << "Not even a [src.species.name] can speak to the dead."
return
@@ -145,4 +145,27 @@
qdel(src)
/mob/living/carbon/human/proc/self_diagnostics()
set name = "Self-Diagnostics"
set desc = "Run an internal self-diagnostic to check for damage."
set category = "IC"
if(stat == DEAD) return
src << "<span class='notice'>Performing self-diagnostic, please wait...</span>"
sleep(50)
var/output = "<span class='notice'>Self-Diagnostic Results:\n</span>"
for(var/obj/item/organ/external/EO in organs)
if(EO.brute_dam || EO.burn_dam)
output += "[EO.name] - <span class='warning'>[EO.burn_dam + EO.brute_dam > ROBOLIMB_REPAIR_CAP ? "Heavy Damage" : "Light Damage"]</span>\n"
else
output += "[EO.name] - <span style='color:green;'>OK</span>\n"
for(var/obj/item/organ/IO in internal_organs)
if(IO.damage)
output += "[IO.name] - <span class='warning'>[IO.damage > 10 ? "Heavy Damage" : "Light Damage"]</span>\n"
else
output += "[IO.name] - <span style='color:green;'>OK</span>\n"
src << output
@@ -2,6 +2,13 @@
real_name = "Test Dummy"
status_flags = GODMODE|CANPUSH
/mob/living/carbon/human/dummy/mannequin/New()
..()
mob_list -= src
living_mob_list -= src
dead_mob_list -= src
delete_inventory()
/mob/living/carbon/human/skrell/New(var/new_loc)
h_style = "Skrell Male Tentacles"
..(new_loc, "Skrell")
@@ -17,6 +24,10 @@
/mob/living/carbon/human/diona/New(var/new_loc)
..(new_loc, "Diona")
/mob/living/carbon/human/teshari/New(var/new_loc)
h_style = "Teshari Default"
..(new_loc, "Teshari")
/mob/living/carbon/human/machine/New(var/new_loc)
h_style = "blue IPC screen"
..(new_loc, "Machine")
@@ -267,8 +267,6 @@ This saves us from having to call add_fingerprint() any time something is put in
update_inv_shoes(redraw_mob)
if(slot_wear_suit)
src.wear_suit = W
if(wear_suit.flags_inv & HIDESHOES)
update_inv_shoes(0)
W.equipped(src, slot)
update_inv_wear_suit(redraw_mob)
if(slot_w_uniform)
+166 -293
View File
@@ -32,7 +32,6 @@
var/temperature_alert = 0
var/in_stasis = 0
var/heartbeat = 0
var/global/list/overlays_cache = null
/mob/living/carbon/human/Life()
set invisibility = 0
@@ -149,6 +148,11 @@
return ONE_ATMOSPHERE + pressure_difference
/mob/living/carbon/human/handle_disabilities()
..()
if(stat != CONSCIOUS) //Let's not worry about tourettes if you're not conscious.
return
if (disabilities & EPILEPSY)
if ((prob(1) && paralysis < 1))
src << "\red You have a seizure!"
@@ -165,7 +169,6 @@
emote("cough")
return
if (disabilities & TOURETTES)
speech_problem_flag = 1
if ((prob(10) && paralysis <= 1))
Stun(10)
spawn( 0 )
@@ -174,40 +177,32 @@
emote("twitch")
if(2 to 3)
say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]")
var/old_x = pixel_x
var/old_y = pixel_y
pixel_x += rand(-2,2)
pixel_y += rand(-1,1)
sleep(2)
pixel_x = old_x
pixel_y = old_y
make_jittery(100)
return
if (disabilities & NERVOUS)
speech_problem_flag = 1
if (prob(10))
stuttering = max(10, stuttering)
if(stat != 2)
var/rn = rand(0, 200)
if(getBrainLoss() >= 5)
if(0 <= rn && rn <= 3)
custom_pain("Your head feels numb and painful.")
if(getBrainLoss() >= 15)
if(4 <= rn && rn <= 6) if(eye_blurry <= 0)
src << "<span class='warning'>It becomes hard to see for some reason.</span>"
eye_blurry = 10
if(getBrainLoss() >= 35)
if(7 <= rn && rn <= 9) if(get_active_hand())
src << "<span class='danger'>Your hand won't respond properly, you drop what you're holding!</span>"
drop_item()
if(getBrainLoss() >= 45)
if(10 <= rn && rn <= 12)
if(prob(50))
src << "<span class='danger'>You suddenly black out!</span>"
Paralyse(10)
else if(!lying)
src << "<span class='danger'>Your legs won't respond properly, you fall down!</span>"
Weaken(10)
var/rn = rand(0, 200)
if(getBrainLoss() >= 5)
if(0 <= rn && rn <= 3)
custom_pain("Your head feels numb and painful.")
if(getBrainLoss() >= 15)
if(4 <= rn && rn <= 6) if(eye_blurry <= 0)
src << "<span class='warning'>It becomes hard to see for some reason.</span>"
eye_blurry = 10
if(getBrainLoss() >= 35)
if(7 <= rn && rn <= 9) if(get_active_hand())
src << "<span class='danger'>Your hand won't respond properly, you drop what you're holding!</span>"
drop_item()
if(getBrainLoss() >= 45)
if(10 <= rn && rn <= 12)
if(prob(50))
src << "<span class='danger'>You suddenly black out!</span>"
Paralyse(10)
else if(!lying)
src << "<span class='danger'>Your legs won't respond properly, you fall down!</span>"
Weaken(10)
@@ -225,12 +220,17 @@
if(!gene.block)
continue
if(gene.is_active(src))
speech_problem_flag = 1
gene.OnMobLife(src)
radiation = Clamp(radiation,0,100)
if (radiation)
if(!radiation)
if(species.appearance_flags & RADIATION_GLOWS)
set_light(0)
else
if(species.appearance_flags & RADIATION_GLOWS)
set_light(max(1,min(10,radiation/10)), max(1,min(20,radiation/20)), species.get_flesh_colour(src))
// END DOGSHIT SNOWFLAKE
var/obj/item/organ/internal/diona/nutrients/rad_organ = locate() in internal_organs
if(rad_organ && !rad_organ.is_broken())
@@ -601,31 +601,32 @@
//Body temperature is too hot.
fire_alert = max(fire_alert, 1)
if(status_flags & GODMODE) return 1 //godmode
if(bodytemperature < species.heat_level_2)
take_overall_damage(burn=HEAT_DAMAGE_LEVEL_1, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 2)
else if(bodytemperature < species.heat_level_3)
take_overall_damage(burn=HEAT_DAMAGE_LEVEL_2, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 2)
else
take_overall_damage(burn=HEAT_DAMAGE_LEVEL_3, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 2)
var/burn_dam = 0
switch(bodytemperature)
if(species.heat_level_1 to species.heat_level_2)
burn_dam = HEAT_DAMAGE_LEVEL_1
if(species.heat_level_2 to species.heat_level_3)
burn_dam = HEAT_DAMAGE_LEVEL_2
if(species.heat_level_3 to INFINITY)
burn_dam = HEAT_DAMAGE_LEVEL_3
take_overall_damage(burn=burn_dam, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 2)
else if(bodytemperature <= species.cold_level_1)
fire_alert = max(fire_alert, 1)
if(status_flags & GODMODE) return 1 //godmode
if(!istype(loc, /obj/machinery/atmospherics/unary/cryo_cell))
if(bodytemperature > species.cold_level_2)
take_overall_damage(burn=COLD_DAMAGE_LEVEL_1, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 1)
else if(bodytemperature > species.cold_level_3)
take_overall_damage(burn=COLD_DAMAGE_LEVEL_2, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 1)
else
take_overall_damage(burn=COLD_DAMAGE_LEVEL_3, used_weapon = "High Body Temperature")
fire_alert = max(fire_alert, 1)
var/burn_dam = 0
switch(bodytemperature)
if(species.cold_level_1 to species.cold_level_2)
burn_dam = COLD_DAMAGE_LEVEL_1
if(species.cold_level_2 to species.cold_level_3)
burn_dam = COLD_DAMAGE_LEVEL_2
if(species.cold_level_3 to -INFINITY)
burn_dam = COLD_DAMAGE_LEVEL_3
take_overall_damage(burn=burn_dam, used_weapon = "Low Body Temperature")
fire_alert = max(fire_alert, 1)
// Account for massive pressure differences. Done by Polymorph
// Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense!
@@ -711,85 +712,25 @@
//This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, UPPER_TORSO, LOWER_TORSO, etc. See setup.dm for the full list)
/mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to.
var/thermal_protection_flags = 0
. = 0
//Handle normal clothing
if(head)
if(head.max_heat_protection_temperature && head.max_heat_protection_temperature >= temperature)
thermal_protection_flags |= head.heat_protection
if(wear_suit)
if(wear_suit.max_heat_protection_temperature && wear_suit.max_heat_protection_temperature >= temperature)
thermal_protection_flags |= wear_suit.heat_protection
if(w_uniform)
if(w_uniform.max_heat_protection_temperature && w_uniform.max_heat_protection_temperature >= temperature)
thermal_protection_flags |= w_uniform.heat_protection
if(shoes)
if(shoes.max_heat_protection_temperature && shoes.max_heat_protection_temperature >= temperature)
thermal_protection_flags |= shoes.heat_protection
if(gloves)
if(gloves.max_heat_protection_temperature && gloves.max_heat_protection_temperature >= temperature)
thermal_protection_flags |= gloves.heat_protection
if(wear_mask)
if(wear_mask.max_heat_protection_temperature && wear_mask.max_heat_protection_temperature >= temperature)
thermal_protection_flags |= wear_mask.heat_protection
return thermal_protection_flags
/mob/living/carbon/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to.
var/thermal_protection_flags = get_heat_protection_flags(temperature)
var/thermal_protection = 0.0
if(thermal_protection_flags)
if(thermal_protection_flags & HEAD)
thermal_protection += THERMAL_PROTECTION_HEAD
if(thermal_protection_flags & UPPER_TORSO)
thermal_protection += THERMAL_PROTECTION_UPPER_TORSO
if(thermal_protection_flags & LOWER_TORSO)
thermal_protection += THERMAL_PROTECTION_LOWER_TORSO
if(thermal_protection_flags & LEG_LEFT)
thermal_protection += THERMAL_PROTECTION_LEG_LEFT
if(thermal_protection_flags & LEG_RIGHT)
thermal_protection += THERMAL_PROTECTION_LEG_RIGHT
if(thermal_protection_flags & FOOT_LEFT)
thermal_protection += THERMAL_PROTECTION_FOOT_LEFT
if(thermal_protection_flags & FOOT_RIGHT)
thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT
if(thermal_protection_flags & ARM_LEFT)
thermal_protection += THERMAL_PROTECTION_ARM_LEFT
if(thermal_protection_flags & ARM_RIGHT)
thermal_protection += THERMAL_PROTECTION_ARM_RIGHT
if(thermal_protection_flags & HAND_LEFT)
thermal_protection += THERMAL_PROTECTION_HAND_LEFT
if(thermal_protection_flags & HAND_RIGHT)
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT
return min(1,thermal_protection)
for(var/obj/item/clothing/C in list(head,wear_suit,w_uniform,shoes,gloves,wear_mask))
if(C)
if(C.max_heat_protection_temperature && C.max_heat_protection_temperature >= temperature)
. |= C.heat_protection
//See proc/get_heat_protection_flags(temperature) for the description of this proc.
/mob/living/carbon/human/proc/get_cold_protection_flags(temperature)
var/thermal_protection_flags = 0
. = 0
//Handle normal clothing
for(var/obj/item/clothing/C in list(head,wear_suit,w_uniform,shoes,gloves,wear_mask))
if(C)
if(C.min_cold_protection_temperature && C.min_cold_protection_temperature <= temperature)
. |= C.cold_protection
if(head)
if(head.min_cold_protection_temperature && head.min_cold_protection_temperature <= temperature)
thermal_protection_flags |= head.cold_protection
if(wear_suit)
if(wear_suit.min_cold_protection_temperature && wear_suit.min_cold_protection_temperature <= temperature)
thermal_protection_flags |= wear_suit.cold_protection
if(w_uniform)
if(w_uniform.min_cold_protection_temperature && w_uniform.min_cold_protection_temperature <= temperature)
thermal_protection_flags |= w_uniform.cold_protection
if(shoes)
if(shoes.min_cold_protection_temperature && shoes.min_cold_protection_temperature <= temperature)
thermal_protection_flags |= shoes.cold_protection
if(gloves)
if(gloves.min_cold_protection_temperature && gloves.min_cold_protection_temperature <= temperature)
thermal_protection_flags |= gloves.cold_protection
if(wear_mask)
if(wear_mask.min_cold_protection_temperature && wear_mask.min_cold_protection_temperature <= temperature)
thermal_protection_flags |= wear_mask.cold_protection
return thermal_protection_flags
/mob/living/carbon/human/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to.
var/thermal_protection_flags = get_heat_protection_flags(temperature)
return get_thermal_protection(thermal_protection_flags)
/mob/living/carbon/human/get_cold_protection(temperature)
if(COLD_RESISTANCE in mutations)
@@ -797,33 +738,34 @@
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
var/thermal_protection_flags = get_cold_protection_flags(temperature)
return get_thermal_protection(thermal_protection_flags)
var/thermal_protection = 0.0
if(thermal_protection_flags)
if(thermal_protection_flags & HEAD)
thermal_protection += THERMAL_PROTECTION_HEAD
if(thermal_protection_flags & UPPER_TORSO)
thermal_protection += THERMAL_PROTECTION_UPPER_TORSO
if(thermal_protection_flags & LOWER_TORSO)
thermal_protection += THERMAL_PROTECTION_LOWER_TORSO
if(thermal_protection_flags & LEG_LEFT)
thermal_protection += THERMAL_PROTECTION_LEG_LEFT
if(thermal_protection_flags & LEG_RIGHT)
thermal_protection += THERMAL_PROTECTION_LEG_RIGHT
if(thermal_protection_flags & FOOT_LEFT)
thermal_protection += THERMAL_PROTECTION_FOOT_LEFT
if(thermal_protection_flags & FOOT_RIGHT)
thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT
if(thermal_protection_flags & ARM_LEFT)
thermal_protection += THERMAL_PROTECTION_ARM_LEFT
if(thermal_protection_flags & ARM_RIGHT)
thermal_protection += THERMAL_PROTECTION_ARM_RIGHT
if(thermal_protection_flags & HAND_LEFT)
thermal_protection += THERMAL_PROTECTION_HAND_LEFT
if(thermal_protection_flags & HAND_RIGHT)
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT
return min(1,thermal_protection)
/mob/living/carbon/human/proc/get_thermal_protection(var/flags)
.=0
if(flags)
if(flags & HEAD)
. += THERMAL_PROTECTION_HEAD
if(flags & UPPER_TORSO)
. += THERMAL_PROTECTION_UPPER_TORSO
if(flags & LOWER_TORSO)
. += THERMAL_PROTECTION_LOWER_TORSO
if(flags & LEG_LEFT)
. += THERMAL_PROTECTION_LEG_LEFT
if(flags & LEG_RIGHT)
. += THERMAL_PROTECTION_LEG_RIGHT
if(flags & FOOT_LEFT)
. += THERMAL_PROTECTION_FOOT_LEFT
if(flags & FOOT_RIGHT)
. += THERMAL_PROTECTION_FOOT_RIGHT
if(flags & ARM_LEFT)
. += THERMAL_PROTECTION_ARM_LEFT
if(flags & ARM_RIGHT)
. += THERMAL_PROTECTION_ARM_RIGHT
if(flags & HAND_LEFT)
. += THERMAL_PROTECTION_HAND_LEFT
if(flags & HAND_RIGHT)
. += THERMAL_PROTECTION_HAND_RIGHT
return min(1,.)
/mob/living/carbon/human/handle_chemicals_in_body()
@@ -860,9 +802,9 @@
var/turf/T = loc
var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T
if(L)
light_amount = min(10,L.lum_r + L.lum_g + L.lum_b) - 5 //hardcapped so it's not abused by having a ton of flashlights
light_amount = min(10,L.lum_r + L.lum_g + L.lum_b) - 2 //hardcapped so it's not abused by having a ton of flashlights
else
light_amount = 5
light_amount = 10
nutrition += light_amount
traumatic_shock -= light_amount
@@ -905,7 +847,10 @@
if(!isSynthetic() && (species.flags & IS_PLANT) && (!light_organ || light_organ.is_broken()))
if(nutrition < 200)
take_overall_damage(2,0)
traumatic_shock++
//traumatic_shock is updated every tick, incrementing that is pointless - shock_stage is the counter.
//Not that it matters much for diona, who have NO_PAIN.
shock_stage++
// TODO: stomach and bloodstream organ.
if(!isSynthetic())
@@ -915,6 +860,7 @@
return //TODO: DEFERRED
//DO NOT CALL handle_statuses() from this proc, it's called from living/Life() as long as this returns a true value.
/mob/living/carbon/human/handle_regular_status_updates()
if(!handle_some_updates())
return 0
@@ -968,19 +914,15 @@
animate_tail_reset()
adjustHalLoss(-3)
if(paralysis)
AdjustParalysis(-1)
else if(sleeping)
speech_problem_flag = 1
handle_dreams()
if (mind)
//Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of stoxin or similar.
if(client || sleeping > 3)
AdjustSleeping(-1)
if( prob(2) && health && !hal_crit )
spawn(0)
emote("snore")
if(sleeping)
handle_dreams()
if (mind)
//Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of stoxin or similar.
if(client || sleeping > 3)
AdjustSleeping(-1)
if( prob(2) && health && !hal_crit )
spawn(0)
emote("snore")
//CONSCIOUS
else
stat = CONSCIOUS
@@ -1011,19 +953,18 @@
if(species.vision_organ)
vision = internal_organs_by_name[species.vision_organ]
if(!vision) // Presumably if a species has no vision organs, they see via some other means.
if(!species.vision_organ) // Presumably if a species has no vision organs, they see via some other means.
eye_blind = 0
blinded = 0
eye_blurry = 0
else if(vision.is_broken()) // Vision organs cut out or broken? Permablind.
else if(!vision || vision.is_broken()) // Vision organs cut out or broken? Permablind.
eye_blind = 1
blinded = 1
eye_blurry = 1
else
//blindness
if(sdisabilities & BLIND) // Disabled-blind, doesn't get better on its own
else //You have the requisite organs
if(sdisabilities & BLIND) // Disabled-blind, doesn't get better on its own
blinded = 1
else if(eye_blind) // Blindness, heals slowly over time
else if(eye_blind) // Blindness, heals slowly over time
eye_blind = max(eye_blind-1,0)
blinded = 1
else if(istype(glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) //resting your eyes with a blindfold heals blurry eyes faster
@@ -1057,9 +998,6 @@
jitteriness = max(0, jitteriness - 3)
adjustHalLoss(-1)
//Other
handle_statuses()
if (drowsyness)
drowsyness--
eye_blurry = max(2, eye_blurry)
@@ -1076,33 +1014,6 @@
return 1
/mob/living/carbon/human/handle_regular_hud_updates()
if(!overlays_cache)
overlays_cache = list()
overlays_cache.len = 23
overlays_cache[1] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage1")
overlays_cache[2] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage2")
overlays_cache[3] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage3")
overlays_cache[4] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage4")
overlays_cache[5] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage5")
overlays_cache[6] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage6")
overlays_cache[7] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage7")
overlays_cache[8] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage8")
overlays_cache[9] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage9")
overlays_cache[10] = image('icons/mob/screen1_full.dmi', "icon_state" = "passage10")
overlays_cache[11] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay1")
overlays_cache[12] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay2")
overlays_cache[13] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay3")
overlays_cache[14] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay4")
overlays_cache[15] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay5")
overlays_cache[16] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay6")
overlays_cache[17] = image('icons/mob/screen1_full.dmi', "icon_state" = "oxydamageoverlay7")
overlays_cache[18] = image('icons/mob/screen1_full.dmi', "icon_state" = "brutedamageoverlay1")
overlays_cache[19] = image('icons/mob/screen1_full.dmi', "icon_state" = "brutedamageoverlay2")
overlays_cache[20] = image('icons/mob/screen1_full.dmi', "icon_state" = "brutedamageoverlay3")
overlays_cache[21] = image('icons/mob/screen1_full.dmi', "icon_state" = "brutedamageoverlay4")
overlays_cache[22] = image('icons/mob/screen1_full.dmi', "icon_state" = "brutedamageoverlay5")
overlays_cache[23] = image('icons/mob/screen1_full.dmi', "icon_state" = "brutedamageoverlay6")
if(hud_updateflag) // update our mob's hud overlays, AKA what others see flaoting above our head
handle_hud_list()
@@ -1115,77 +1026,59 @@
if(copytext(hud.icon_state,1,4) == "hud") //ugly, but icon comparison is worse, I believe
client.images.Remove(hud)
client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science)
client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science, global_hud.whitense)
if(damageoverlay.overlays)
damageoverlay.overlays = list()
if(istype(client.eye,/obj/machinery/camera))
var/obj/machinery/camera/cam = client.eye
client.screen |= cam.client_huds
if(stat == UNCONSCIOUS)
if(stat == UNCONSCIOUS && health <= 0)
//Critical damage passage overlay
if(health <= 0)
var/image/I
switch(health)
if(-20 to -10)
I = overlays_cache[1]
if(-30 to -20)
I = overlays_cache[2]
if(-40 to -30)
I = overlays_cache[3]
if(-50 to -40)
I = overlays_cache[4]
if(-60 to -50)
I = overlays_cache[5]
if(-70 to -60)
I = overlays_cache[6]
if(-80 to -70)
I = overlays_cache[7]
if(-90 to -80)
I = overlays_cache[8]
if(-95 to -90)
I = overlays_cache[9]
if(-INFINITY to -95)
I = overlays_cache[10]
damageoverlay.overlays += I
var/severity = 0
switch(health)
if(-20 to -10) severity = 1
if(-30 to -20) severity = 2
if(-40 to -30) severity = 3
if(-50 to -40) severity = 4
if(-60 to -50) severity = 5
if(-70 to -60) severity = 6
if(-80 to -70) severity = 7
if(-90 to -80) severity = 8
if(-95 to -90) severity = 9
if(-INFINITY to -95) severity = 10
overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
else
clear_fullscreen("crit")
//Oxygen damage overlay
if(oxyloss)
var/image/I
var/severity = 0
switch(oxyloss)
if(10 to 20)
I = overlays_cache[11]
if(20 to 25)
I = overlays_cache[12]
if(25 to 30)
I = overlays_cache[13]
if(30 to 35)
I = overlays_cache[14]
if(35 to 40)
I = overlays_cache[15]
if(40 to 45)
I = overlays_cache[16]
if(45 to INFINITY)
I = overlays_cache[17]
damageoverlay.overlays += I
if(10 to 20) severity = 1
if(20 to 25) severity = 2
if(25 to 30) severity = 3
if(30 to 35) severity = 4
if(35 to 40) severity = 5
if(40 to 45) severity = 6
if(45 to INFINITY) severity = 7
overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
else
clear_fullscreen("oxy")
//Fire and Brute damage overlay (BSSR)
var/hurtdamage = src.getBruteLoss() + src.getFireLoss() + damageoverlaytemp
damageoverlaytemp = 0 // We do this so we can detect if someone hits us or not.
if(hurtdamage)
var/image/I
var/severity = 0
switch(hurtdamage)
if(10 to 25)
I = overlays_cache[18]
if(25 to 40)
I = overlays_cache[19]
if(40 to 55)
I = overlays_cache[20]
if(55 to 70)
I = overlays_cache[21]
if(70 to 85)
I = overlays_cache[22]
if(85 to INFINITY)
I = overlays_cache[23]
damageoverlay.overlays += I
if(10 to 25) severity = 1
if(25 to 40) severity = 2
if(40 to 55) severity = 3
if(55 to 70) severity = 4
if(70 to 85) severity = 5
if(85 to INFINITY) severity = 6
overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
else
clear_fullscreen("brute")
if( stat == DEAD )
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS|SEE_SELF
@@ -1329,20 +1222,20 @@
bodytemp.icon_state = "temp-1"
else
bodytemp.icon_state = "temp0"
if(blind)
if(blinded) blind.layer = 18
else blind.layer = 0
if(blinded) overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else clear_fullscreens()
if(disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription
if(glasses) //to every /obj/item
var/obj/item/clothing/glasses/G = glasses
if(!G.prescription)
client.screen += global_hud.vimpaired
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
else
client.screen += global_hud.vimpaired
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
if(eye_blurry) client.screen += global_hud.blurry
if(druggy) client.screen += global_hud.druggy
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if(config.welder_vision)
var/found_welder
@@ -1576,7 +1469,7 @@
var/obj/item/organ/internal/heart/H = internal_organs_by_name[O_HEART]
if(!H || (H.status & ORGAN_ROBOT))
if(!H || (H.robotic >= ORGAN_ROBOT))
return
if(pulse >= PULSE_2FAST || shock_stage >= 10 || istype(get_turf(src), /turf/space))
@@ -1601,7 +1494,7 @@
/mob/living/carbon/human/proc/handle_hud_list()
if (BITTEST(hud_updateflag, HEALTH_HUD))
var/image/holder = hud_list[HEALTH_HUD]
if(stat == 2)
if(stat == DEAD)
holder.icon_state = "hudhealth-100" // X_X
else
var/percentage_health = RoundHealth((health-config.health_threshold_crit)/(maxHealth-config.health_threshold_crit)*100)
@@ -1625,12 +1518,9 @@
var/image/holder = hud_list[STATUS_HUD]
var/image/holder2 = hud_list[STATUS_HUD_OOC]
if(stat == 2)
if(stat == DEAD)
holder.icon_state = "huddead"
holder2.icon_state = "huddead"
else if(status_flags & XENO_HOST)
holder.icon_state = "hudxeno"
holder2.icon_state = "hudxeno"
else if(foundVirus)
holder.icon_state = "hudill"
else if(has_brain_worms())
@@ -1726,28 +1616,11 @@
hud_list[SPECIALROLE_HUD] = holder
hud_updateflag = 0
/mob/living/carbon/human/handle_silent()
if(..())
speech_problem_flag = 1
return silent
/mob/living/carbon/human/handle_slurring()
if(..())
speech_problem_flag = 1
return slurring
/mob/living/carbon/human/handle_stunned()
if(!can_feel_pain())
stunned = 0
return 0
if(..())
speech_problem_flag = 1
return stunned
/mob/living/carbon/human/handle_stuttering()
if(..())
speech_problem_flag = 1
return stuttering
return ..()
/mob/living/carbon/human/handle_fire()
if(..())
@@ -1764,4 +1637,4 @@
..()
#undef HUMAN_MAX_OXYLOSS
#undef HUMAN_CRIT_MAX_OXYLOSS
#undef HUMAN_CRIT_MAX_OXYLOSS
+11 -23
View File
@@ -1,10 +1,10 @@
/mob/living/carbon/human/say(var/message)
/mob/living/carbon/human/say(var/message,var/whispering=0)
var/alt_name = ""
if(name != GetVoice())
alt_name = "(as [get_id_name("Unknown")])"
message = sanitize(message)
..(message, alt_name = alt_name)
..(message, alt_name = alt_name, whispering = whispering)
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
@@ -125,29 +125,20 @@
return verb
/mob/living/carbon/human/handle_speech_problems(var/message, var/verb)
/mob/living/carbon/human/handle_speech_problems(var/list/message_data)
if(silent || (sdisabilities & MUTE))
message = ""
speech_problem_flag = 1
message_data[1] = ""
. = 1
else if(istype(wear_mask, /obj/item/clothing/mask))
var/obj/item/clothing/mask/M = wear_mask
if(M.voicechange)
message = pick(M.say_messages)
verb = pick(M.say_verbs)
speech_problem_flag = 1
message_data[1] = pick(M.say_messages)
message_data[2] = pick(M.say_verbs)
. = 1
if(message != "")
var/list/parent = ..()
message = parent[1]
verb = parent[2]
if(parent[3])
speech_problem_flag = 1
var/list/returns[3]
returns[1] = message
returns[2] = verb
returns[3] = speech_problem_flag
return returns
else
. = ..(message_data)
/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
switch(message_mode)
@@ -190,9 +181,6 @@
if(has_radio)
R.talk_into(src,message,null,verb,speaking)
used_radios += R
if("whisper")
whisper_say(message, speaking, alt_name)
return 1
else
if(message_mode)
if(l_ear && istype(l_ear,/obj/item/device/radio))
@@ -19,7 +19,9 @@
death_message = "dissolves into ash..."
flags = NO_SCAN | NO_SLIP | NO_POISON | NO_MINOR_CUT
spawn_flags = IS_RESTRICTED
spawn_flags = SPECIES_IS_RESTRICTED
genders = list(NEUTER)
/datum/species/shadow/handle_death(var/mob/living/carbon/human/H)
spawn(1)
@@ -21,10 +21,12 @@
var/prone_icon // If set, draws this from icobase when mob is prone.
var/blood_color = "#A10808" // Red.
var/flesh_color = "#FFC896" // Pink.
var/base_color // Used by changelings. Should also be used for icon previes..
var/base_color // Used by changelings. Should also be used for icon previews.
var/tail // Name of tail state in species effects icon file.
var/tail_animation // If set, the icon to obtain tail animation states from.
var/tail_hair
var/race_key = 0 // Used for mob icon cache string.
var/icon/icon_template // Used for mob icon generation for non-32x32 species.
var/mob_size = MOB_MEDIUM
@@ -48,7 +50,7 @@
// Combat vars.
var/total_health = 100 // Point at which the mob will enter crit.
var/list/unarmed_types = list( // Possible unarmed attacks that the mob will use in combat.
var/list/unarmed_types = list( // Possible unarmed attacks that the mob will use in combat,
/datum/unarmed_attack,
/datum/unarmed_attack/bite
)
@@ -147,6 +149,8 @@
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
var/list/genders = list(MALE, FEMALE)
// Bump vars
var/bump_flag = HUMAN // What are we considered to be when bumped?
var/push_flags = ~HEAVY // What can we push?
@@ -173,71 +177,9 @@
inherent_verbs = list()
inherent_verbs |= /mob/living/carbon/human/proc/regurgitate
/datum/species/proc/get_station_variant()
return name
/datum/species/proc/get_bodytype()
return name
/datum/species/proc/get_knockout_message(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? "encounters a hardware fault and suddenly reboots!" : knockout_message)
/datum/species/proc/get_death_message(var/mob/living/carbon/human/H)
if(config.show_human_death_message)
return ((H && H.isSynthetic()) ? "gives one shrill beep before falling lifeless." : death_message)
else
return "no message"
/datum/species/proc/get_ssd(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? "flashing a 'system offline' glyph on their monitor" : show_ssd)
/datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? SYNTH_BLOOD_COLOUR : blood_color)
/datum/species/proc/get_virus_immune(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? 1 : virus_immune)
/datum/species/proc/get_flesh_colour(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? SYNTH_FLESH_COLOUR : flesh_color)
/datum/species/proc/get_environment_discomfort(var/mob/living/carbon/human/H, var/msg_type)
if(!prob(5))
return
var/covered = 0 // Basic coverage can help.
for(var/obj/item/clothing/clothes in H)
if(H.l_hand == clothes|| H.r_hand == clothes)
continue
if((clothes.body_parts_covered & UPPER_TORSO) && (clothes.body_parts_covered & LOWER_TORSO))
covered = 1
break
switch(msg_type)
if("cold")
if(!covered)
H << "<span class='danger'>[pick(cold_discomfort_strings)]</span>"
if("heat")
if(covered)
H << "<span class='danger'>[pick(heat_discomfort_strings)]</span>"
/datum/species/proc/sanitize_name(var/name)
return sanitizeName(name)
/datum/species/proc/get_random_name(var/gender)
if(!name_language)
if(gender == FEMALE)
return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names))
else
return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
var/datum/language/species_language = all_languages[name_language]
if(!species_language)
species_language = all_languages[default_language]
if(!species_language)
return "unknown"
return species_language.get_random_name(gender)
/datum/species/proc/equip_survival_gear(var/mob/living/carbon/human/H,var/extendedtank = 1)
if(H.backbag == 1)
if (extendedtank) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(H), slot_r_hand)
@@ -248,6 +190,7 @@
/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs.
H.mob_size = mob_size
for(var/obj/item/organ/organ in H.contents)
if((organ in H.organs) || (organ in H.internal_organs))
qdel(organ)
@@ -307,7 +250,6 @@
H.mob_swap_flags = swap_flags
H.mob_push_flags = push_flags
H.pass_flags = pass_flags
H.mob_size = mob_size
/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
return
@@ -349,6 +291,3 @@
// Called in life() when the mob has no client.
/datum/species/proc/handle_npc(var/mob/living/carbon/human/H)
return
/datum/species/proc/get_vision_flags(var/mob/living/carbon/human/H)
return vision_flags
@@ -67,9 +67,9 @@
attack_noun = list("body")
damage = 2
/datum/unarmed_attack/slime_glomp/apply_effects()
//Todo, maybe have a chance of causing an electrical shock?
return
/datum/unarmed_attack/slime_glomp/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone)
..()
user.apply_stored_shock_to(target)
/datum/unarmed_attack/stomp/weak
attack_verb = list("jumped on")
@@ -0,0 +1,106 @@
/datum/species/proc/get_valid_shapeshifter_forms(var/mob/living/carbon/human/H)
return list()
/datum/species/proc/get_additional_examine_text(var/mob/living/carbon/human/H)
return
/datum/species/proc/get_tail(var/mob/living/carbon/human/H)
return tail
/datum/species/proc/get_tail_animation(var/mob/living/carbon/human/H)
return tail_animation
/datum/species/proc/get_tail_hair(var/mob/living/carbon/human/H)
return tail_hair
/datum/species/proc/get_blood_mask(var/mob/living/carbon/human/H)
return blood_mask
/datum/species/proc/get_damage_overlays(var/mob/living/carbon/human/H)
return damage_overlays
/datum/species/proc/get_damage_mask(var/mob/living/carbon/human/H)
return damage_mask
/datum/species/proc/get_examine_name(var/mob/living/carbon/human/H)
return name
/datum/species/proc/get_icobase(var/mob/living/carbon/human/H, var/get_deform)
return (get_deform ? deform : icobase)
/datum/species/proc/get_station_variant()
return name
/datum/species/proc/get_race_key(var/mob/living/carbon/human/H)
return race_key
/datum/species/proc/get_bodytype(var/mob/living/carbon/human/H)
return name
/datum/species/proc/get_knockout_message(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? "encounters a hardware fault and suddenly reboots!" : knockout_message)
/datum/species/proc/get_death_message(var/mob/living/carbon/human/H)
if(config.show_human_death_message)
return ((H && H.isSynthetic()) ? "gives one shrill beep before falling lifeless." : death_message)
else
return "no message"
/datum/species/proc/get_ssd(var/mob/living/carbon/human/H)
if(H)
if(H.looksSynthetic())
return "flashing a 'system offline' light"
else
return show_ssd
/datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H)
if(H)
var/datum/robolimb/company = H.isSynthetic()
if(company)
return company.blood_color
else
return blood_color
/datum/species/proc/get_virus_immune(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? 1 : virus_immune)
/datum/species/proc/get_flesh_colour(var/mob/living/carbon/human/H)
return ((H && H.isSynthetic()) ? SYNTH_FLESH_COLOUR : flesh_color)
/datum/species/proc/get_environment_discomfort(var/mob/living/carbon/human/H, var/msg_type)
if(!prob(5))
return
var/covered = 0 // Basic coverage can help.
for(var/obj/item/clothing/clothes in H)
if(H.item_is_in_hands(clothes))
continue
if((clothes.body_parts_covered & UPPER_TORSO) && (clothes.body_parts_covered & LOWER_TORSO))
covered = 1
break
switch(msg_type)
if("cold")
if(!covered)
H << "<span class='danger'>[pick(cold_discomfort_strings)]</span>"
if("heat")
if(covered)
H << "<span class='danger'>[pick(heat_discomfort_strings)]</span>"
/datum/species/proc/get_random_name(var/gender)
if(!name_language)
if(gender == FEMALE)
return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names))
else
return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
var/datum/language/species_language = all_languages[name_language]
if(!species_language)
species_language = all_languages[default_language]
if(!species_language)
return "unknown"
return species_language.get_random_name(gender)
/datum/species/proc/get_vision_flags(var/mob/living/carbon/human/H)
return vision_flags
@@ -0,0 +1,6 @@
var/list/stored_shock_by_ref = list()
/mob/living/proc/apply_stored_shock_to(var/mob/living/target)
if(stored_shock_by_ref["\ref[src]"])
target.electrocute_act(stored_shock_by_ref["\ref[src]"]*0.9, src)
stored_shock_by_ref["\ref[src]"] = 0
@@ -0,0 +1,187 @@
// This is something of an intermediary species used for species that
// need to emulate the appearance of another race. Currently it is only
// used for slimes but it may be useful for changelings later.
var/list/wrapped_species_by_ref = list()
/datum/species/shapeshifter
inherent_verbs = list(
/mob/living/carbon/human/proc/shapeshifter_select_shape,
/mob/living/carbon/human/proc/shapeshifter_select_hair,
/mob/living/carbon/human/proc/shapeshifter_select_gender
)
var/list/valid_transform_species = list()
var/monochromatic
var/default_form = "Human"
/datum/species/shapeshifter/get_valid_shapeshifter_forms(var/mob/living/carbon/human/H)
return valid_transform_species
/datum/species/shapeshifter/get_icobase(var/mob/living/carbon/human/H, var/get_deform)
if(!H) return ..(null, get_deform)
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_icobase(H, get_deform)
/datum/species/shapeshifter/get_race_key(var/mob/living/carbon/human/H)
return "[..()]-[wrapped_species_by_ref["\ref[H]"]]"
/datum/species/shapeshifter/get_bodytype(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_bodytype(H)
/datum/species/shapeshifter/get_blood_mask(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_blood_mask(H)
/datum/species/shapeshifter/get_damage_mask(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_damage_mask(H)
/datum/species/shapeshifter/get_damage_overlays(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_damage_overlays(H)
/datum/species/shapeshifter/get_tail(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_tail(H)
/datum/species/shapeshifter/get_tail_animation(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_tail_animation(H)
/datum/species/shapeshifter/get_tail_hair(var/mob/living/carbon/human/H)
if(!H) return ..()
var/datum/species/S = all_species[wrapped_species_by_ref["\ref[H]"]]
return S.get_tail_hair(H)
/datum/species/shapeshifter/handle_post_spawn(var/mob/living/carbon/human/H)
..()
wrapped_species_by_ref["\ref[H]"] = default_form
if(monochromatic)
H.r_hair = H.r_skin
H.g_hair = H.g_skin
H.b_hair = H.b_skin
H.r_facial = H.r_skin
H.g_facial = H.g_skin
H.b_facial = H.b_skin
for(var/obj/item/organ/external/E in H.organs)
E.sync_colour_to_human(H)
// Verbs follow.
/mob/living/carbon/human/proc/shapeshifter_select_hair()
set name = "Select Hair"
set category = "Abilities"
if(stat || world.time < last_special)
return
last_special = world.time + 10
var/list/valid_hairstyles = list()
var/list/valid_facialhairstyles = list()
for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(!(species.get_bodytype(src) in S.species_allowed))
continue
valid_hairstyles += hairstyle
for(var/facialhairstyle in facial_hair_styles_list)
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(!(species.get_bodytype(src) in S.species_allowed))
continue
valid_facialhairstyles += facialhairstyle
visible_message("<span class='notice'>\The [src]'s form contorts subtly.</span>")
if(valid_hairstyles.len)
var/new_hair = input("Select a hairstyle.", "Shapeshifter Hair") as null|anything in valid_hairstyles
change_hair(new_hair ? new_hair : "Bald")
if(valid_facialhairstyles.len)
var/new_hair = input("Select a facial hair style.", "Shapeshifter Hair") as null|anything in valid_facialhairstyles
change_facial_hair(new_hair ? new_hair : "Shaved")
/mob/living/carbon/human/proc/shapeshifter_select_gender()
set name = "Select Gender"
set category = "Abilities"
if(stat || world.time < last_special)
return
last_special = world.time + 50
var/new_gender = input("Please select a gender.", "Shapeshifter Gender") as null|anything in list(FEMALE, MALE, NEUTER, PLURAL)
if(!new_gender)
return
visible_message("<span class='notice'>\The [src]'s form contorts subtly.</span>")
change_gender(new_gender)
/mob/living/carbon/human/proc/shapeshifter_select_shape()
set name = "Select Body Shape"
set category = "Abilities"
if(stat || world.time < last_special)
return
last_special = world.time + 50
var/new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in species.get_valid_shapeshifter_forms(src)
if(!new_species || !all_species[new_species] || wrapped_species_by_ref["\ref[src]"] == new_species)
return
wrapped_species_by_ref["\ref[src]"] = new_species
visible_message("<span class='notice'>\The [src] shifts and contorts, taking the form of \a [new_species]!</span>")
regenerate_icons()
/mob/living/carbon/human/proc/shapeshifter_select_colour()
set name = "Select Body Colour"
set category = "Abilities"
if(stat || world.time < last_special)
return
last_special = world.time + 50
var/new_skin = input("Please select a new body color.", "Shapeshifter Colour") as color
if(!new_skin)
return
shapeshifter_set_colour(new_skin)
/mob/living/carbon/human/proc/shapeshifter_set_colour(var/new_skin)
r_skin = hex2num(copytext(new_skin, 2, 4))
g_skin = hex2num(copytext(new_skin, 4, 6))
b_skin = hex2num(copytext(new_skin, 6, 8))
var/datum/species/shapeshifter/S = species
if(S.monochromatic)
r_hair = r_skin
g_hair = g_skin
b_hair = b_skin
r_facial = r_skin
g_facial = g_skin
b_facial = b_skin
for(var/obj/item/organ/external/E in organs)
E.sync_colour_to_human(src)
regenerate_icons()
@@ -8,7 +8,7 @@
language = "Sol Common" //todo?
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch)
flags = NO_PAIN | NO_SCAN | NO_POISON | NO_MINOR_CUT
spawn_flags = IS_RESTRICTED
spawn_flags = SPECIES_IS_RESTRICTED
siemens_coefficient = 0
breath_type = null
@@ -23,6 +23,8 @@
death_message = "becomes completely motionless..."
genders = list(NEUTER)
/datum/species/golem/handle_post_spawn(var/mob/living/carbon/human/H)
if(H.mind)
H.mind.assigned_role = "Golem"
@@ -30,7 +30,7 @@
brute_mod = 1.5
burn_mod = 1.5
spawn_flags = IS_RESTRICTED
spawn_flags = SPECIES_IS_RESTRICTED
bump_flag = MONKEY
swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL
@@ -0,0 +1,188 @@
var/datum/species/shapeshifter/promethean/prometheans
// Species definition follows.
/datum/species/shapeshifter/promethean
name = "Promethean"
name_plural = "Prometheans"
blurb = "What has Science done?"
show_ssd = "totally quiescent"
death_message = "rapidly loses cohesion, splattering across the ground..."
knockout_message = "collapses inwards, forming a disordered puddle of goo."
remains_type = /obj/effect/decal/cleanable/ash
blood_color = "#05FF9B"
flesh_color = "#05FFFB"
hunger_factor = DEFAULT_HUNGER_FACTOR //todo
reagent_tag = IS_SLIME
mob_size = MOB_SMALL
bump_flag = SLIME
swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL
push_flags = MONKEY|SLIME|SIMPLE_ANIMAL
flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT
appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | RADIATION_GLOWS
spawn_flags = SPECIES_IS_RESTRICTED
breath_type = null
poison_type = null
gluttonous = 2
virus_immune = 1
blood_volume = 600
min_age = 1
max_age = 5
brute_mod = 0.5
burn_mod = 2
oxy_mod = 0
total_health = 120
cold_level_1 = 260
cold_level_2 = 200
cold_level_3 = 120
heat_level_1 = 360
heat_level_2 = 400
heat_level_3 = 1000
body_temperature = 310.15
siemens_coefficient = -1
rarity_value = 5
unarmed_types = list(/datum/unarmed_attack/slime_glomp)
has_organ = list(O_BRAIN = /obj/item/organ/internal/brain/slime) // Slime core.
has_limbs = list(
BP_TORSO = list("path" = /obj/item/organ/external/chest/unbreakable/slime),
BP_GROIN = list("path" = /obj/item/organ/external/groin/unbreakable/slime),
BP_HEAD = list("path" = /obj/item/organ/external/head/unbreakable/slime),
BP_L_ARM = list("path" = /obj/item/organ/external/arm/unbreakable/slime),
BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/unbreakable/slime),
BP_L_LEG = list("path" = /obj/item/organ/external/leg/unbreakable/slime),
BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/unbreakable/slime),
BP_L_HAND = list("path" = /obj/item/organ/external/hand/unbreakable/slime),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/unbreakable/slime),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot/unbreakable/slime),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/unbreakable/slime)
)
heat_discomfort_strings = list("You feel too warm.")
cold_discomfort_strings = list("You feel too cool.")
inherent_verbs = list(
/mob/living/carbon/human/proc/shapeshifter_select_shape,
/mob/living/carbon/human/proc/shapeshifter_select_colour,
/mob/living/carbon/human/proc/shapeshifter_select_hair,
/mob/living/carbon/human/proc/shapeshifter_select_gender
)
valid_transform_species = list("Human", "Unathi", "Tajara", "Skrell", "Diona", "Teshari", "Monkey")
monochromatic = 1
var/heal_rate = 5 // Temp. Regen per tick.
/datum/species/shapeshifter/promethean/New()
..()
prometheans = src
/datum/species/shapeshifter/promethean/equip_survival_gear(var/mob/living/carbon/human/H)
var/boxtype = pick(typesof(/obj/item/weapon/storage/toolbox/lunchbox))
var/obj/item/weapon/storage/toolbox/lunchbox/L = new boxtype(get_turf(H))
var/mob/living/simple_animal/mouse/mouse = new (L)
var/obj/item/weapon/holder/holder = new (L)
mouse.forceMove(holder)
holder.sync(mouse)
if(H.backbag == 1)
H.equip_to_slot_or_del(L, slot_r_hand)
else
H.equip_to_slot_or_del(L, slot_in_backpack)
/datum/species/shapeshifter/promethean/hug(var/mob/living/carbon/human/H,var/mob/living/target)
var/t_him = "them"
switch(target.gender)
if(MALE)
t_him = "him"
if(FEMALE)
t_him = "her"
H.visible_message("<span class='notice'>\The [H] glomps [target] to make [t_him] feel better!</span>", \
"<span class='notice'>You glomps [target] to make [t_him] feel better!</span>")
H.apply_stored_shock_to(target)
/datum/species/shapeshifter/promethean/handle_death(var/mob/living/carbon/human/H)
spawn(1)
if(H)
H.gib()
/datum/species/shapeshifter/promethean/handle_environment_special(var/mob/living/carbon/human/H)
var/turf/T = H.loc
if(istype(T))
var/obj/effect/decal/cleanable/C = locate() in T
if(C)
qdel(C)
//TODO: gain nutriment
// Regenerate limbs and heal damage if we have any. Copied from Bay xenos code.
// Theoretically the only internal organ a slime will have
// is the slime core. but we might as well be thorough.
for(var/obj/item/organ/I in H.internal_organs)
if(I.damage > 0)
I.damage = max(I.damage - heal_rate, 0)
if (prob(5))
H << "<span class='notice'>You feel a soothing sensation within your [I.name]...</span>"
return 1
// Replace completely missing limbs.
for(var/limb_type in has_limbs)
var/obj/item/organ/external/E = H.organs_by_name[limb_type]
if(E && (E.is_stump() || (E.status & (ORGAN_DESTROYED|ORGAN_DEAD|ORGAN_MUTATED))))
E.removed()
qdel(E)
E = null
if(!E)
var/list/organ_data = has_limbs[limb_type]
var/limb_path = organ_data["path"]
var/obj/item/organ/O = new limb_path(H)
organ_data["descriptor"] = O.name
H << "<span class='notice'>You feel a slithering sensation as your [O.name] reforms.</span>"
H.update_body()
return 1
// Heal remaining damage.
if (H.getBruteLoss() || H.getFireLoss() || H.getOxyLoss() || H.getToxLoss())
H.adjustBruteLoss(-heal_rate)
H.adjustFireLoss(-heal_rate)
H.adjustOxyLoss(-heal_rate)
H.adjustToxLoss(-heal_rate)
return 1
/datum/species/shapeshifter/promethean/get_blood_colour(var/mob/living/carbon/human/H)
return (H ? rgb(H.r_skin, H.g_skin, H.b_skin) : ..())
/datum/species/shapeshifter/promethean/get_flesh_colour(var/mob/living/carbon/human/H)
return (H ? rgb(H.r_skin, H.g_skin, H.b_skin) : ..())
/datum/species/shapeshifter/promethean/get_additional_examine_text(var/mob/living/carbon/human/H)
if(!stored_shock_by_ref["\ref[H]"])
return
var/t_she = "She is"
if(H.gender == MALE)
t_she = "He is"
else if(H.gender == PLURAL)
t_she = "They are"
else if(H.gender == NEUTER)
t_she = "It is"
switch(stored_shock_by_ref["\ref[H]"])
if(1 to 10)
return "[t_she] flickering gently with a little electrical activity."
if(11 to 20)
return "[t_she] glowing gently with moderate levels of electrical activity.\n"
if(21 to 35)
return "<span class='warning'>[t_she] glowing brightly with high levels of electrical activity.</span>"
if(35 to INFINITY)
return "<span class='danger'>[t_she] radiating massive levels of electrical activity!</span>"
@@ -36,7 +36,7 @@
blood_volume = 400
hunger_factor = 0.2
spawn_flags = CAN_JOIN | IS_WHITELISTED
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR
bump_flag = MONKEY
swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL
@@ -1,50 +0,0 @@
/datum/species/slime
name = "Slime"
name_plural = "slimes"
mob_size = MOB_SMALL
icobase = 'icons/mob/human_races/r_slime.dmi'
deform = 'icons/mob/human_races/r_slime.dmi'
language = null //todo?
unarmed_types = list(/datum/unarmed_attack/slime_glomp)
flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT
spawn_flags = IS_RESTRICTED
siemens_coefficient = 3 //conductive
darksight = 3
blood_color = "#05FF9B"
flesh_color = "#05FFFB"
remains_type = /obj/effect/decal/cleanable/ash
death_message = "rapidly loses cohesion, splattering across the ground..."
has_organ = list(
"brain" = /obj/item/organ/internal/brain/slime
)
breath_type = null
poison_type = null
bump_flag = SLIME
swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL
push_flags = MONKEY|SLIME|SIMPLE_ANIMAL
has_limbs = list(
BP_TORSO = list("path" = /obj/item/organ/external/chest/unbreakable),
BP_GROIN = list("path" = /obj/item/organ/external/groin/unbreakable),
BP_HEAD = list("path" = /obj/item/organ/external/head/unbreakable),
BP_L_ARM = list("path" = /obj/item/organ/external/arm/unbreakable),
BP_R_ARM = list("path" = /obj/item/organ/external/arm/right/unbreakable),
BP_L_LEG = list("path" = /obj/item/organ/external/leg/unbreakable),
BP_R_LEG = list("path" = /obj/item/organ/external/leg/right/unbreakable),
BP_L_HAND = list("path" = /obj/item/organ/external/hand/unbreakable),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right/unbreakable),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot/unbreakable),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/unbreakable)
)
/datum/species/slime/handle_death(var/mob/living/carbon/human/H)
spawn(1)
if(H)
H.gib()
@@ -14,10 +14,10 @@
min_age = 17
max_age = 110
spawn_flags = CAN_JOIN
spawn_flags = SPECIES_CAN_JOIN
appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR
/datum/species/human/get_bodytype()
/datum/species/human/get_bodytype(var/mob/living/carbon/human/H)
return "Human"
/datum/species/unathi
@@ -54,7 +54,7 @@
heat_level_2 = 480 //Default 400
heat_level_3 = 1100 //Default 1000
spawn_flags = CAN_JOIN | IS_WHITELISTED
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
flesh_color = "#34AF10"
@@ -116,7 +116,7 @@
primitive_form = "Farwa"
spawn_flags = CAN_JOIN | IS_WHITELISTED
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
flesh_color = "#AFA59E"
@@ -149,13 +149,13 @@
herbivores on the whole and tend to be co-operative with the other species of the galaxy, although they rarely reveal \
the secrets of their empire to their allies."
num_alternate_languages = 2
secondary_langs = list("Skrellian", "Teshari")
name_language = null
secondary_langs = list("Skrellian", "Schechi")
name_language = "Skrellian"
min_age = 19
max_age = 80
spawn_flags = CAN_JOIN | IS_WHITELISTED
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR
flesh_color = "#8CD7A3"
@@ -246,13 +246,14 @@
body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not
flags = NO_SCAN | IS_PLANT | NO_PAIN | NO_SLIP | NO_MINOR_CUT
spawn_flags = CAN_JOIN | IS_WHITELISTED
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
blood_color = "#004400"
flesh_color = "#907E4A"
reagent_tag = IS_DIONA
genders = list(PLURAL)
/datum/species/diona/can_understand(var/mob/other)
var/mob/living/carbon/alien/diona/D = other
if(istype(D))
@@ -13,22 +13,22 @@
// Handle things that are part of this interface but not removing/replacing a given item.
if("pockets")
visible_message("<span class='danger'>\The [user] is trying to empty \the [src]'s pockets!</span>")
if(do_after(user,HUMAN_STRIP_DELAY))
if(do_after(user,HUMAN_STRIP_DELAY,src))
empty_pockets(user)
return
if("splints")
visible_message("<span class='danger'>\The [user] is trying to remove \the [src]'s splints!</span>")
if(do_after(user,HUMAN_STRIP_DELAY))
if(do_after(user,HUMAN_STRIP_DELAY,src))
remove_splints(user)
return
if("sensors")
visible_message("<span class='danger'>\The [user] is trying to set \the [src]'s sensors!</span>")
if(do_after(user,HUMAN_STRIP_DELAY))
if(do_after(user,HUMAN_STRIP_DELAY,src))
toggle_sensors(user)
return
if("internals")
visible_message("<span class='danger'>\The [usr] is trying to set \the [src]'s internals!</span>")
if(do_after(user,HUMAN_STRIP_DELAY))
if(do_after(user,HUMAN_STRIP_DELAY,src))
toggle_internals(user)
return
if("tie")
@@ -40,7 +40,7 @@
return
visible_message("<span class='danger'>\The [usr] is trying to remove \the [src]'s [A.name]!</span>")
if(!do_after(user,HUMAN_STRIP_DELAY))
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
if(!A || suit.loc != src || !(A in suit.accessories))
@@ -74,7 +74,7 @@
else
visible_message("<span class='danger'>\The [user] is trying to put \a [held] on \the [src]!</span>")
if(!do_after(user,HUMAN_STRIP_DELAY))
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
if(!stripping && user.get_active_hand() != held)
@@ -109,29 +109,30 @@ Please contact me on #coderbus IRC. ~Carn x
#define MUTATIONS_LAYER 1
#define DAMAGE_LAYER 2
#define SURGERY_LEVEL 3 //bs12 specific.
#define UNIFORM_LAYER 4
#define ID_LAYER 5
#define SHOES_LAYER 6
#define GLOVES_LAYER 7
#define BELT_LAYER 8
#define SUIT_LAYER 9
#define TAIL_LAYER 10 //bs12 specific. this hack is probably gonna come back to haunt me
#define GLASSES_LAYER 11
#define BELT_LAYER_ALT 12
#define SUIT_STORE_LAYER 13
#define BACK_LAYER 14
#define HAIR_LAYER 15 //TODO: make part of head layer?
#define EARS_LAYER 16
#define FACEMASK_LAYER 17
#define HEAD_LAYER 18
#define COLLAR_LAYER 19
#define HANDCUFF_LAYER 20
#define LEGCUFF_LAYER 21
#define L_HAND_LAYER 22
#define R_HAND_LAYER 23
#define FIRE_LAYER 24 //If you're on fire
#define TARGETED_LAYER 25 //BS12: Layer for the target overlay from weapon targeting system
#define TOTAL_LAYERS 25
#define UNDERWEAR_LAYER 4
#define UNIFORM_LAYER 5
#define ID_LAYER 6
#define SHOES_LAYER 7
#define GLOVES_LAYER 8
#define BELT_LAYER 9
#define SUIT_LAYER 10
#define TAIL_LAYER 11 //bs12 specific. this hack is probably gonna come back to haunt me
#define GLASSES_LAYER 12
#define BELT_LAYER_ALT 13
#define SUIT_STORE_LAYER 14
#define BACK_LAYER 15
#define HAIR_LAYER 16 //TODO: make part of head layer?
#define EARS_LAYER 17
#define FACEMASK_LAYER 18
#define HEAD_LAYER 19
#define COLLAR_LAYER 20
#define HANDCUFF_LAYER 21
#define LEGCUFF_LAYER 22
#define L_HAND_LAYER 23
#define R_HAND_LAYER 24
#define FIRE_LAYER 25 //If you're on fire
#define TARGETED_LAYER 26 //BS12: Layer for the target overlay from weapon targeting system
#define TOTAL_LAYERS 26
//////////////////////////////////
/mob/living/carbon/human
@@ -148,8 +149,12 @@ Please contact me on #coderbus IRC. ~Carn x
if (icon_update)
icon = stand_icon
for(var/image/I in overlays_standing)
overlays += I
for(var/entry in overlays_standing)
if(istype(entry, /image))
overlays += entry
else if(istype(entry, /list))
for(var/inner_entry in entry)
overlays += inner_entry
if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone.
var/matrix/M = matrix()
@@ -174,9 +179,6 @@ var/global/list/damage_icon_parts = list()
for(var/obj/item/organ/external/O in organs)
if(O.is_stump())
continue
//if(O.status & ORGAN_DESTROYED) damage_appearance += "d" //what is this?
//else
// damage_appearance += O.damage_state
damage_appearance += O.damage_state
if(damage_appearance == previous_damage_appearance)
@@ -194,15 +196,14 @@ var/global/list/damage_icon_parts = list()
if(O.is_stump())
continue
O.update_icon()
if(O.damage_state == "00") continue
var/icon/DI
var/cache_index = "[O.damage_state]/[O.icon_name]/[species.blood_color]/[species.get_bodytype()]"
var/cache_index = "[O.damage_state]/[O.icon_name]/[species.get_blood_colour(src)]/[species.get_bodytype(src)]"
if(damage_icon_parts[cache_index] == null)
DI = new /icon(species.damage_overlays, O.damage_state) // the damage icon for whole human
DI.Blend(new /icon(species.damage_mask, O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels
DI.Blend(species.blood_color, ICON_MULTIPLY)
DI = new /icon(species.get_damage_overlays(src), O.damage_state) // the damage icon for whole human
DI.Blend(new /icon(species.get_damage_mask(src), O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels
DI.Blend(species.get_blood_colour(src), ICON_MULTIPLY)
damage_icon_parts[cache_index] = DI
else
DI = damage_icon_parts[cache_index]
@@ -224,6 +225,8 @@ var/global/list/damage_icon_parts = list()
var/hulk = (HULK in src.mutations)
var/skeleton = (SKELETON in src.mutations)
robolimb_count = 0
//CACHING: Generate an index key from visible bodyparts.
//0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic.
@@ -236,7 +239,7 @@ var/global/list/damage_icon_parts = list()
if(gender == FEMALE)
g = "female"
var/icon_key = "[species.race_key][g][s_tone][r_skin][g_skin][b_skin]"
var/icon_key = "[species.get_race_key(src)][g][s_tone][r_skin][g_skin][b_skin]"
if(lip_style)
icon_key += "[lip_style]"
else
@@ -251,14 +254,15 @@ var/global/list/damage_icon_parts = list()
var/obj/item/organ/external/part = organs_by_name[organ_tag]
if(isnull(part) || part.is_stump())
icon_key += "0"
else if(part.status & ORGAN_ROBOT)
else if(part.robotic >= ORGAN_ROBOT)
icon_key += "2[part.model ? "-[part.model]": ""]"
robolimb_count++
else if(part.status & ORGAN_DEAD)
icon_key += "3"
else
icon_key += "1"
if(part)
icon_key += "[part.species.race_key]"
icon_key += "[part.species.get_race_key(part.owner)]"
icon_key += "[part.dna.GetUIState(DNA_UI_GENDER)]"
icon_key += "[part.dna.GetUIValue(DNA_UI_SKIN_TONE)]"
if(part.s_col && part.s_col.len >= 3)
@@ -319,24 +323,24 @@ var/global/list/damage_icon_parts = list()
//END CACHED ICON GENERATION.
stand_icon.Blend(base_icon,ICON_OVERLAY)
//Underwear
if(underwear_top && species.appearance_flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', underwear_top), ICON_OVERLAY)
if(underwear_bottom && species.appearance_flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', underwear_bottom), ICON_OVERLAY)
if(undershirt && species.appearance_flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', undershirt), ICON_OVERLAY)
if(socks && species.appearance_flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', socks), ICON_OVERLAY)
if(update_icons)
update_icons()
//tail
update_tail_showing(0)
//UNDERWEAR OVERLAY
/mob/living/carbon/human/proc/update_underwear(var/update_icons=1)
overlays_standing[UNDERWEAR_LAYER] = null
if(species.appearance_flags & HAS_UNDERWEAR)
overlays_standing[UNDERWEAR_LAYER] = list()
for(var/category in all_underwear)
var/datum/category_item/underwear/UWI = all_underwear[category]
overlays_standing[UNDERWEAR_LAYER] += UWI.generate_image(all_underwear_metadata[category])
if(update_icons) update_icons()
//HAIR OVERLAY
/mob/living/carbon/human/proc/update_hair(var/update_icons=1)
//Reset our hair
@@ -357,7 +361,7 @@ var/global/list/damage_icon_parts = list()
if(f_style)
var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
if(facial_hair_style && facial_hair_style.species_allowed && (src.species.get_bodytype() in facial_hair_style.species_allowed))
if(facial_hair_style && facial_hair_style.species_allowed && (src.species.get_bodytype(src) in facial_hair_style.species_allowed))
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
if(facial_hair_style.do_colouration)
facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD)
@@ -366,13 +370,16 @@ var/global/list/damage_icon_parts = list()
if(h_style && !(head && (head.flags_inv & BLOCKHEADHAIR)))
var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
if(hair_style && (src.species.get_bodytype() in hair_style.species_allowed))
if(hair_style && (src.species.get_bodytype(src) in hair_style.species_allowed))
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
if(hair_style.do_colouration)
hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
face_standing.Blend(hair_s, ICON_OVERLAY)
if(head_organ.nonsolid)
face_standing += rgb(,,,120)
overlays_standing[HAIR_LAYER] = image(face_standing)
if(update_icons) update_icons()
@@ -428,6 +435,7 @@ var/global/list/damage_icon_parts = list()
update_mutations(0)
update_body(0)
update_underwear(0)
update_hair(0)
update_inv_w_uniform(0)
update_inv_wear_id(0)
@@ -464,8 +472,8 @@ var/global/list/damage_icon_parts = list()
var/icon/under_icon
if(w_uniform.icon_override)
under_icon = w_uniform.icon_override
else if(w_uniform.sprite_sheets && w_uniform.sprite_sheets[species.get_bodytype()])
under_icon = w_uniform.sprite_sheets[species.get_bodytype()]
else if(w_uniform.sprite_sheets && w_uniform.sprite_sheets[species.get_bodytype(src)])
under_icon = w_uniform.sprite_sheets[species.get_bodytype(src)]
else if(w_uniform.item_icons && w_uniform.item_icons[slot_w_uniform_str])
under_icon = w_uniform.item_icons[slot_w_uniform_str]
else
@@ -486,7 +494,7 @@ var/global/list/damage_icon_parts = list()
//apply blood overlay
if(w_uniform.blood_DNA)
var/image/bloodsies = image(icon = species.blood_mask, icon_state = "uniformblood")
var/image/bloodsies = image(icon = species.get_blood_mask(src), icon_state = "uniformblood")
bloodsies.color = w_uniform.blood_color
standing.overlays += bloodsies
@@ -500,6 +508,9 @@ var/global/list/damage_icon_parts = list()
else
overlays_standing[UNIFORM_LAYER] = null
//hiding/revealing shoes if necessary
update_inv_shoes(0)
if(update_icons)
update_icons()
@@ -510,8 +521,8 @@ var/global/list/damage_icon_parts = list()
var/image/standing
if(wear_id.icon_override)
standing = image("icon" = wear_id.icon_override, "icon_state" = "[icon_state]")
else if(wear_id.sprite_sheets && wear_id.sprite_sheets[species.get_bodytype()])
standing = image("icon" = wear_id.sprite_sheets[species.get_bodytype()], "icon_state" = "[icon_state]")
else if(wear_id.sprite_sheets && wear_id.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = wear_id.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[icon_state]")
else
standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "id")
overlays_standing[ID_LAYER] = standing
@@ -533,13 +544,13 @@ var/global/list/damage_icon_parts = list()
var/image/standing
if(gloves.icon_override)
standing = image("icon" = gloves.icon_override, "icon_state" = "[t_state]")
else if(gloves.sprite_sheets && gloves.sprite_sheets[species.get_bodytype()])
standing = image("icon" = gloves.sprite_sheets[species.get_bodytype()], "icon_state" = "[t_state]")
else if(gloves.sprite_sheets && gloves.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = gloves.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_state]")
else
standing = image("icon" = 'icons/mob/hands.dmi', "icon_state" = "[t_state]")
if(gloves.blood_DNA)
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "bloodyhands")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "bloodyhands")
bloodsies.color = gloves.blood_color
standing.overlays += bloodsies
gloves.screen_loc = ui_gloves
@@ -547,7 +558,7 @@ var/global/list/damage_icon_parts = list()
overlays_standing[GLOVES_LAYER] = standing
else
if(blood_DNA)
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "bloodyhands")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "bloodyhands")
bloodsies.color = hand_blood_color
overlays_standing[GLOVES_LAYER] = bloodsies
else
@@ -557,13 +568,15 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/update_inv_glasses(var/update_icons=1)
if(glasses)
var/image/standing
if(glasses.icon_override)
overlays_standing[GLASSES_LAYER] = image("icon" = glasses.icon_override, "icon_state" = "[glasses.icon_state]")
else if(glasses.sprite_sheets && glasses.sprite_sheets[species.get_bodytype()])
overlays_standing[GLASSES_LAYER]= image("icon" = glasses.sprite_sheets[species.get_bodytype()], "icon_state" = "[glasses.icon_state]")
standing = image("icon" = glasses.icon_override, "icon_state" = "[glasses.icon_state]")
else if(glasses.sprite_sheets && glasses.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = glasses.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[glasses.icon_state]")
else
overlays_standing[GLASSES_LAYER]= image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]")
standing = image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]")
standing.color = glasses.color
overlays_standing[GLASSES_LAYER] = standing
else
overlays_standing[GLASSES_LAYER] = null
@@ -576,54 +589,63 @@ var/global/list/damage_icon_parts = list()
return
if(l_ear || r_ear)
if(l_ear)
// Blank image upon which to layer left & right overlays.
var/image/both = image("icon" = 'icons/effects/effects.dmi', "icon_state" = "nothing")
if(l_ear)
var/image/standing
var/t_type = l_ear.icon_state
if(l_ear.icon_override)
t_type = "[t_type]_l"
overlays_standing[EARS_LAYER] = image("icon" = l_ear.icon_override, "icon_state" = "[t_type]")
else if(l_ear.sprite_sheets && l_ear.sprite_sheets[species.get_bodytype()])
standing = image("icon" = l_ear.icon_override, "icon_state" = "[t_type]")
else if(l_ear.sprite_sheets && l_ear.sprite_sheets[species.get_bodytype(src)])
t_type = "[t_type]_l"
overlays_standing[EARS_LAYER] = image("icon" = l_ear.sprite_sheets[species.get_bodytype()], "icon_state" = "[t_type]")
standing = image("icon" = l_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]")
else
overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
standing.color = l_ear.color
both.overlays += standing
if(r_ear)
var/image/standing
var/t_type = r_ear.icon_state
if(r_ear.icon_override)
t_type = "[t_type]_r"
overlays_standing[EARS_LAYER] = image("icon" = r_ear.icon_override, "icon_state" = "[t_type]")
else if(r_ear.sprite_sheets && r_ear.sprite_sheets[species.get_bodytype()])
standing = image("icon" = r_ear.icon_override, "icon_state" = "[t_type]")
else if(r_ear.sprite_sheets && r_ear.sprite_sheets[species.get_bodytype(src)])
t_type = "[t_type]_r"
overlays_standing[EARS_LAYER] = image("icon" = r_ear.sprite_sheets[species.get_bodytype()], "icon_state" = "[t_type]")
standing = image("icon" = r_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]")
else
overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
standing.color = r_ear.color
both.overlays += standing
overlays_standing[EARS_LAYER] = both
else
overlays_standing[EARS_LAYER] = null
if(update_icons) update_icons()
/mob/living/carbon/human/update_inv_shoes(var/update_icons=1)
if(shoes && !(wear_suit && wear_suit.flags_inv & HIDESHOES))
if(shoes && !((wear_suit && wear_suit.flags_inv & HIDESHOES) || (w_uniform && w_uniform.flags_inv & HIDESHOES)))
var/image/standing
if(shoes.icon_override)
standing = image("icon" = shoes.icon_override, "icon_state" = "[shoes.icon_state]")
else if(shoes.sprite_sheets && shoes.sprite_sheets[species.get_bodytype()])
standing = image("icon" = shoes.sprite_sheets[species.get_bodytype()], "icon_state" = "[shoes.icon_state]")
else if(shoes.sprite_sheets && shoes.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = shoes.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[shoes.icon_state]")
else
standing = image("icon" = 'icons/mob/feet.dmi', "icon_state" = "[shoes.icon_state]")
if(shoes.blood_DNA)
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "shoeblood")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "shoeblood")
bloodsies.color = shoes.blood_color
standing.overlays += bloodsies
standing.color = shoes.color
overlays_standing[SHOES_LAYER] = standing
else
if(feet_blood_DNA)
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "shoeblood")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "shoeblood")
bloodsies.color = feet_blood_color
overlays_standing[SHOES_LAYER] = bloodsies
else
@@ -649,8 +671,8 @@ var/global/list/damage_icon_parts = list()
var/t_icon
if(head.icon_override)
t_icon = head.icon_override
else if(head.sprite_sheets && head.sprite_sheets[species.get_bodytype()])
t_icon = head.sprite_sheets[species.get_bodytype()]
else if(head.sprite_sheets && head.sprite_sheets[species.get_bodytype(src)])
t_icon = head.sprite_sheets[species.get_bodytype(src)]
else if(head.item_icons && (slot_head_str in head.item_icons))
t_icon = head.item_icons[slot_head_str]
@@ -675,13 +697,13 @@ var/global/list/damage_icon_parts = list()
var/image/standing = image(icon = t_icon, icon_state = t_state)
if(head.blood_DNA)
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "helmetblood")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "helmetblood")
bloodsies.color = head.blood_color
standing.overlays += bloodsies
if(istype(head,/obj/item/clothing/head))
var/obj/item/clothing/head/hat = head
var/cache_key = "[hat.light_overlay]_[species.get_bodytype()]"
var/cache_key = "[hat.light_overlay]_[species.get_bodytype(src)]"
if(hat.on && light_overlay_cache[cache_key])
standing.overlays |= light_overlay_cache[cache_key]
@@ -701,8 +723,8 @@ var/global/list/damage_icon_parts = list()
if(belt.icon_override)
standing.icon = belt.icon_override
else if(belt.sprite_sheets && belt.sprite_sheets[species.get_bodytype()])
standing.icon = belt.sprite_sheets[species.get_bodytype()]
else if(belt.sprite_sheets && belt.sprite_sheets[species.get_bodytype(src)])
standing.icon = belt.sprite_sheets[species.get_bodytype(src)]
else
standing.icon = 'icons/mob/belt.dmi'
@@ -739,7 +761,7 @@ var/global/list/damage_icon_parts = list()
var/t_icon = INV_SUIT_DEF_ICON
if(wear_suit.icon_override)
t_icon = wear_suit.icon_override
else if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[species.get_bodytype()])
else if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[species.get_bodytype(src)])
t_icon = wear_suit.sprite_sheets[species.name]
else if(wear_suit.item_icons && wear_suit.item_icons[slot_wear_suit_str])
t_icon = wear_suit.item_icons[slot_wear_suit_str]
@@ -755,20 +777,28 @@ var/global/list/damage_icon_parts = list()
if(wear_suit.blood_DNA)
var/obj/item/clothing/suit/S = wear_suit
if(istype(S)) //You can put non-suits in your suit slot (diona nymphs etc).
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "[S.blood_overlay_type]blood")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "[S.blood_overlay_type]blood")
bloodsies.color = wear_suit.blood_color
standing.overlays += bloodsies
// Accessories - copied from uniform, BOILERPLATE because fuck this system.
var/obj/item/clothing/suit/suit = wear_suit
if(istype(suit) && suit.accessories.len)
for(var/obj/item/clothing/accessory/A in suit.accessories)
standing.overlays |= A.get_mob_overlay()
overlays_standing[SUIT_LAYER] = standing
update_tail_showing(0)
else
overlays_standing[SUIT_LAYER] = null
update_tail_showing(0)
update_inv_shoes(0)
update_collar(0)
//hide/show shoes if necessary
update_inv_shoes(0)
if(update_icons) update_icons()
/mob/living/carbon/human/update_inv_pockets(var/update_icons=1)
@@ -784,14 +814,14 @@ var/global/list/damage_icon_parts = list()
var/image/standing
if(wear_mask.icon_override)
standing = image("icon" = wear_mask.icon_override, "icon_state" = "[wear_mask.icon_state]")
else if(wear_mask.sprite_sheets && wear_mask.sprite_sheets[species.get_bodytype()])
standing = image("icon" = wear_mask.sprite_sheets[species.get_bodytype()], "icon_state" = "[wear_mask.icon_state]")
else if(wear_mask.sprite_sheets && wear_mask.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = wear_mask.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[wear_mask.icon_state]")
else
standing = image("icon" = 'icons/mob/mask.dmi', "icon_state" = "[wear_mask.icon_state]")
standing.color = wear_mask.color
if( !istype(wear_mask, /obj/item/clothing/mask/smokable/cigarette) && wear_mask.blood_DNA )
var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "maskblood")
var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "maskblood")
bloodsies.color = wear_mask.blood_color
standing.overlays += bloodsies
overlays_standing[FACEMASK_LAYER] = standing
@@ -812,8 +842,8 @@ var/global/list/damage_icon_parts = list()
//If this is a rig and a mob_icon is set, it will take species into account in the rig update_icon() proc.
var/obj/item/weapon/rig/rig = back
overlay_icon = rig.mob_icon
else if(back.sprite_sheets && back.sprite_sheets[species.get_bodytype()])
overlay_icon = back.sprite_sheets[species.get_bodytype()]
else if(back.sprite_sheets && back.sprite_sheets[species.get_bodytype(src)])
overlay_icon = back.sprite_sheets[species.get_bodytype(src)]
else if(back.item_icons && (slot_back_str in back.item_icons))
overlay_icon = back.item_icons[slot_back_str]
else
@@ -857,8 +887,8 @@ var/global/list/damage_icon_parts = list()
var/image/standing
if(handcuffed.icon_override)
standing = image("icon" = handcuffed.icon_override, "icon_state" = "handcuff1")
else if(handcuffed.sprite_sheets && handcuffed.sprite_sheets[species.get_bodytype()])
standing = image("icon" = handcuffed.sprite_sheets[species.get_bodytype()], "icon_state" = "handcuff1")
else if(handcuffed.sprite_sheets && handcuffed.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = handcuffed.sprite_sheets[species.get_bodytype(src)], "icon_state" = "handcuff1")
else
standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "handcuff1")
overlays_standing[HANDCUFF_LAYER] = standing
@@ -873,8 +903,8 @@ var/global/list/damage_icon_parts = list()
var/image/standing
if(legcuffed.icon_override)
standing = image("icon" = legcuffed.icon_override, "icon_state" = "legcuff1")
else if(legcuffed.sprite_sheets && legcuffed.sprite_sheets[species.get_bodytype()])
standing = image("icon" = legcuffed.sprite_sheets[species.get_bodytype()], "icon_state" = "legcuff1")
else if(legcuffed.sprite_sheets && legcuffed.sprite_sheets[species.get_bodytype(src)])
standing = image("icon" = legcuffed.sprite_sheets[species.get_bodytype(src)], "icon_state" = "legcuff1")
else
standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "legcuff1")
overlays_standing[LEGCUFF_LAYER] = standing
@@ -963,24 +993,29 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1)
overlays_standing[TAIL_LAYER] = null
if(species.tail && !(wear_suit && wear_suit.flags_inv & HIDETAIL))
var/species_tail = species.get_tail(src)
if(species_tail && !(wear_suit && wear_suit.flags_inv & HIDETAIL))
var/icon/tail_s = get_tail_icon()
overlays_standing[TAIL_LAYER] = image(tail_s, icon_state = "[species.tail]_s")
overlays_standing[TAIL_LAYER] = image(tail_s, icon_state = "[species_tail]_s")
animate_tail_reset(0)
if(update_icons)
update_icons()
/mob/living/carbon/human/proc/get_tail_icon()
var/icon_key = "[species.race_key][r_skin][g_skin][b_skin][r_hair][g_hair][b_hair]"
var/icon_key = "[species.get_race_key(src)][r_skin][g_skin][b_skin][r_hair][g_hair][b_hair]"
var/icon/tail_icon = tail_icon_cache[icon_key]
if(!tail_icon)
//generate a new one
tail_icon = new/icon(icon = (species.tail_animation? species.tail_animation : 'icons/effects/species.dmi'))
var/species_tail_anim = species.get_tail_animation(src)
if(!species_tail_anim) species_tail_anim = 'icons/effects/species.dmi'
tail_icon = new/icon(species_tail_anim)
tail_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD)
// The following will not work with animated tails.
if(species.tail_hair)
var/icon/hair_icon = icon('icons/effects/species.dmi', "[species.tail]_[species.tail_hair]")
var/use_species_tail = species.get_tail_hair(src)
if(use_species_tail)
var/icon/hair_icon = icon('icons/effects/species.dmi', "[species.get_tail(src)]_[use_species_tail]")
hair_icon.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
tail_icon.Blend(hair_icon, ICON_OVERLAY)
tail_icon_cache[icon_key] = tail_icon
@@ -991,7 +1026,7 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/proc/set_tail_state(var/t_state)
var/image/tail_overlay = overlays_standing[TAIL_LAYER]
if(tail_overlay && species.tail_animation)
if(tail_overlay && species.get_tail_animation(src))
tail_overlay.icon_state = t_state
return tail_overlay
return null
@@ -999,7 +1034,7 @@ var/global/list/damage_icon_parts = list()
//Not really once, since BYOND can't do that.
//Update this if the ability to flick() images or make looping animation start at the first frame is ever added.
/mob/living/carbon/human/proc/animate_tail_once(var/update_icons=1)
var/t_state = "[species.tail]_once"
var/t_state = "[species.get_tail(src)]_once"
var/image/tail_overlay = overlays_standing[TAIL_LAYER]
if(tail_overlay && tail_overlay.icon_state == t_state)
@@ -1016,29 +1051,28 @@ var/global/list/damage_icon_parts = list()
update_icons()
/mob/living/carbon/human/proc/animate_tail_start(var/update_icons=1)
set_tail_state("[species.tail]_slow[rand(0,9)]")
set_tail_state("[species.get_tail(src)]_slow[rand(0,9)]")
if(update_icons)
update_icons()
/mob/living/carbon/human/proc/animate_tail_fast(var/update_icons=1)
set_tail_state("[species.tail]_loop[rand(0,9)]")
set_tail_state("[species.get_tail(src)]_loop[rand(0,9)]")
if(update_icons)
update_icons()
/mob/living/carbon/human/proc/animate_tail_reset(var/update_icons=1)
if(stat != DEAD)
set_tail_state("[species.tail]_idle[rand(0,9)]")
set_tail_state("[species.get_tail(src)]_idle[rand(0,9)]")
else
set_tail_state("[species.tail]_static")
set_tail_state("[species.get_tail(src)]_static")
if(update_icons)
update_icons()
/mob/living/carbon/human/proc/animate_tail_stop(var/update_icons=1)
set_tail_state("[species.tail]_static")
set_tail_state("[species.get_tail(src)]_static")
if(update_icons)
update_icons()
@@ -1,161 +0,0 @@
//Lallander was here
/mob/living/carbon/human/whisper(message as text)
var/alt_name = ""
if(say_disabled) //This is here to try to identify lag problems
usr << "\red Speech is currently admin-disabled."
return
message = sanitize(message)
log_whisper("[src.name]/[src.key] : [message]")
if (src.client)
if (src.client.prefs.muted & MUTE_IC)
src << "\red You cannot whisper (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (src.stat == 2)
return src.say_dead(message)
if (src.stat)
return
if(name != GetVoice())
alt_name = "(as [get_id_name("Unknown")])"
//parse the language code and consume it
var/datum/language/speaking = parse_language(message)
if (speaking)
message = copytext(message,2+length(speaking.key))
whisper_say(message, speaking, alt_name)
//This is used by both the whisper verb and human/say() to handle whispering
/mob/living/carbon/human/proc/whisper_say(var/message, var/datum/language/speaking = null, var/alt_name="", var/verb="whispers")
if (is_muzzled())
src << "<span class='danger'>You're muzzled and cannot speak!</span>"
return
var/message_range = 1
var/eavesdropping_range = 2
var/watching_range = 5
var/italics = 1
var/not_heard //the message displayed to people who could not hear the whispering
if (speaking)
if (speaking.whisper_verb)
verb = speaking.whisper_verb
not_heard = "[verb] something"
else
var/adverb = pick("quietly", "softly")
verb = "[speaking.speech_verb] [adverb]"
not_heard = "[speaking.speech_verb] something [adverb]"
else
not_heard = "[verb] something" //TODO get rid of the null language and just prevent speech if language is null
message = capitalize(trim(message))
if(speech_problem_flag)
var/list/handle_r = handle_speech_problems(message)
message = handle_r[1]
verb = handle_r[2]
if(verb == "yells loudly")
verb = "slurs emphatically"
else
var/adverb = pick("quietly", "softly")
verb = "[verb] [adverb]"
speech_problem_flag = handle_r[3]
if(!message || message=="")
return
//looks like this only appears in whisper. Should it be elsewhere as well? Maybe handle_speech_problems?
var/voice_sub
if(istype(back,/obj/item/weapon/rig))
var/obj/item/weapon/rig/rig = back
// todo: fix this shit
if(rig.speech && rig.speech.voice_holder && rig.speech.voice_holder.active && rig.speech.voice_holder.voice)
voice_sub = rig.speech.voice_holder.voice
else
for(var/obj/item/gear in list(wear_mask,wear_suit,head))
if(!gear)
continue
var/obj/item/voice_changer/changer = locate() in gear
if(changer && changer.active && changer.voice)
voice_sub = changer.voice
if(voice_sub == "Unknown")
if(copytext(message, 1, 2) != "*")
var/list/temp_message = text2list(message, " ")
var/list/pick_list = list()
for(var/i = 1, i <= temp_message.len, i++)
pick_list += i
for(var/i=1, i <= abs(temp_message.len/3), i++)
var/H = pick(pick_list)
if(findtext(temp_message[H], "*") || findtext(temp_message[H], ";") || findtext(temp_message[H], ":")) continue
temp_message[H] = ninjaspeak(temp_message[H])
pick_list -= H
message = list2text(temp_message, " ")
message = replacetext(message, "o", "¤")
message = replacetext(message, "p", "þ")
message = replacetext(message, "l", "£")
message = replacetext(message, "s", "§")
message = replacetext(message, "u", "µ")
message = replacetext(message, "b", "ß")
var/list/listening = hearers(message_range, src)
listening |= src
//ghosts
for (var/mob/M in dead_mob_list) //does this include players who joined as observers as well?
if (!(M.client))
continue
if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS))
listening |= M
//Pass whispers on to anything inside the immediate listeners.
for(var/mob/L in listening)
for(var/mob/C in L.contents)
if(istype(C,/mob/living))
listening += C
//pass on the message to objects that can hear us.
for (var/obj/O in view(message_range, src))
spawn (0)
if (O)
O.hear_talk(src, message, verb, speaking)
var/list/eavesdropping = hearers(eavesdropping_range, src)
eavesdropping -= src
eavesdropping -= listening
var/list/watching = hearers(watching_range, src)
watching -= src
watching -= listening
watching -= eavesdropping
//now mobs
var/speech_bubble_test = say_test(message)
var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]")
spawn(30) qdel(speech_bubble)
for(var/mob/M in listening)
M << speech_bubble
M.hear_say(message, verb, speaking, alt_name, italics, src)
if (eavesdropping.len)
var/new_message = stars(message) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
for(var/mob/M in eavesdropping)
M << speech_bubble
M.hear_say(new_message, verb, speaking, alt_name, italics, src)
if (watching.len)
var/rendered = "<span class='game say'><span class='name'>[src.name]</span> [not_heard].</span>"
for (var/mob/M in watching)
M.show_message(rendered, 2)
@@ -18,8 +18,6 @@
if (client.prefs.muted & MUTE_IC)
src << "\red You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (stat)
return
if(!(message))
@@ -244,8 +244,8 @@
processing_objects.Add(src)
process()
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
var/mob/observer/dead/ghost
for(var/mob/observer/dead/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
@@ -256,8 +256,8 @@
icon_state = "golem"
attack_hand(mob/living/user as mob)
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
var/mob/observer/dead/ghost
for(var/mob/observer/dead/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
@@ -273,7 +273,7 @@
proc/announce_to_ghosts()
for(var/mob/dead/observer/G in player_list)
for(var/mob/observer/dead/G in player_list)
if(G.client)
var/area/A = get_area(src)
if(A)
@@ -106,14 +106,11 @@
else
if (src.paralysis || src.stunned || src.weakened || (status_flags && FAKEDEATH)) //Stunned etc.
if (src.stunned > 0)
AdjustStunned(-1)
src.stat = 0
if (src.weakened > 0)
AdjustWeakened(-1)
src.lying = 0
src.stat = 0
if (src.paralysis > 0)
AdjustParalysis(-1)
src.blinded = 0
src.lying = 0
src.stat = 0
@@ -220,7 +217,7 @@
if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men
var/mob/living/carbon/human/H = L
if(H.species.name == "Slime")
if(H.species.name == "Promethean")
continue
if(!L.canmove) // Only one slime can latch on at a time.
@@ -31,7 +31,7 @@
speech_buffer.Add(lowertext(html_decode(message)))
..()
/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
if (speaker in Friends)
speech_buffer = list()
speech_buffer.Add(speaker)
+11 -9
View File
@@ -1,4 +1,3 @@
/mob/living/carbon/process_resist()
//drop && roll
@@ -17,14 +16,17 @@
"<span class='notice'>You extinguish yourself.</span>"
)
ExtinguishMob()
return
return TRUE
..()
if(..())
return TRUE
if(handcuffed)
spawn() escape_handcuffs()
else if(legcuffed)
spawn() escape_legcuffs()
else
..()
/mob/living/carbon/proc/escape_handcuffs()
//if(!(last_special <= world.time)) return
@@ -57,8 +59,8 @@
"<span class='warning'>You attempt to remove \the [HC]. (This will take around [displaytime] minutes and you need to stand still)</span>"
)
if(do_after(src, breakouttime))
if(!handcuffed)
if(do_after(src, breakouttime, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
if(!handcuffed || buckled)
return
visible_message(
"<span class='danger'>\The [src] manages to remove \the [handcuffed]!</span>",
@@ -91,7 +93,7 @@
"<span class='warning'>You attempt to remove \the [HC]. (This will take around [displaytime] minutes and you need to stand still)</span>"
)
if(do_after(src, breakouttime))
if(do_after(src, breakouttime, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
if(!legcuffed || buckled)
return
visible_message(
@@ -113,7 +115,7 @@
"<span class='warning'>You attempt to break your [handcuffed.name]. (This will take around 5 seconds and you need to stand still)</span>"
)
if(do_after(src, 50))
if(do_after(src, 5 SECONDS, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
if(!handcuffed || buckled)
return
@@ -134,7 +136,7 @@
src << "<span class='warning'>You attempt to break your legcuffs. (This will take around 5 seconds and you need to stand still)</span>"
visible_message("<span class='danger'>[src] is trying to break the legcuffs!</span>")
if(do_after(src, 50))
if(do_after(src, 5 SECONDS, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
if(!legcuffed || buckled)
return
@@ -166,7 +168,7 @@
"<span class='warning'>You attempt to unbuckle yourself. (This will take around 2 minutes and you need to stand still)</span>"
)
if(do_after(usr, 1200))
if(do_after(usr, 2 MINUTES, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY)))
if(!buckled)
return
visible_message("<span class='danger'>[usr] manages to unbuckle themself!</span>",
+3 -1
View File
@@ -23,8 +23,10 @@
if(istype(src,/mob/living/carbon/human))
var/mob/living/carbon/human/M = src
for(var/obj/item/organ/external/organ in M.organs)
if(organ && (organ.is_broken() || organ.open))
if(organ.is_broken() || organ.open)
src.traumatic_shock += 30
else if(organ.is_dislocated())
src.traumatic_shock += 15
if(src.traumatic_shock < 0)
src.traumatic_shock = 0
+3
View File
@@ -0,0 +1,3 @@
/mob/living/death()
clear_fullscreens()
. = ..()
+172
View File
@@ -0,0 +1,172 @@
/mob/living
var/hand = null
var/obj/item/l_hand = null
var/obj/item/r_hand = null
var/obj/item/weapon/back = null//Human/Monkey
var/obj/item/weapon/tank/internal = null//Human/Monkey
var/obj/item/clothing/mask/wear_mask = null//Carbon
/mob/living/equip_to_storage(obj/item/newitem)
// Try put it in their backpack
if(istype(src.back,/obj/item/weapon/storage))
var/obj/item/weapon/storage/backpack = src.back
if(backpack.can_be_inserted(newitem, 1))
newitem.forceMove(src.back)
return 1
// Try to place it in any item that can store stuff, on the mob.
for(var/obj/item/weapon/storage/S in src.contents)
if (S.can_be_inserted(newitem, 1))
newitem.forceMove(S)
return 1
return 0
//Returns the thing in our active hand
/mob/living/get_active_hand()
if(hand) return l_hand
else return r_hand
//Returns the thing in our inactive hand
/mob/living/get_inactive_hand()
if(hand) return r_hand
else return l_hand
//Drops the item in our active hand. TODO: rename this to drop_active_hand or something
/mob/living/drop_item(var/atom/Target)
if(hand) return drop_l_hand(Target)
else return drop_r_hand(Target)
//Drops the item in our left hand
/mob/living/drop_l_hand(var/atom/Target)
return drop_from_inventory(l_hand, Target)
//Drops the item in our right hand
/mob/living/drop_r_hand(var/atom/Target)
return drop_from_inventory(r_hand, Target)
/mob/living/proc/hands_are_full()
return (r_hand && l_hand)
/mob/living/proc/item_is_in_hands(var/obj/item/I)
return (I == r_hand || I == l_hand)
/mob/living/proc/update_held_icons()
if(l_hand)
l_hand.update_held_icon()
if(r_hand)
r_hand.update_held_icon()
/mob/living/proc/get_type_in_hands(var/T)
if(istype(l_hand, T))
return l_hand
if(istype(r_hand, T))
return r_hand
return null
/mob/living/proc/get_left_hand()
return l_hand
/mob/living/proc/get_right_hand()
return r_hand
/mob/living/u_equip(obj/W as obj)
if (W == r_hand)
r_hand = null
update_inv_r_hand(0)
else if (W == l_hand)
l_hand = null
update_inv_l_hand(0)
else if (W == back)
back = null
update_inv_back(0)
else if (W == wear_mask)
wear_mask = null
update_inv_wear_mask(0)
return
/mob/living/get_equipped_item(var/slot)
switch(slot)
if(slot_l_hand) return l_hand
if(slot_r_hand) return r_hand
if(slot_back) return back
if(slot_wear_mask) return wear_mask
return null
/mob/living/show_inv(mob/user as mob)
user.set_machine(src)
var/dat = {"
<B><HR><FONT size=3>[name]</FONT></B>
<BR><HR>
<BR><B>Head(Mask):</B> <A href='?src=\ref[src];item=mask'>[(wear_mask ? wear_mask : "Nothing")]</A>
<BR><B>Left Hand:</B> <A href='?src=\ref[src];item=l_hand'>[(l_hand ? l_hand : "Nothing")]</A>
<BR><B>Right Hand:</B> <A href='?src=\ref[src];item=r_hand'>[(r_hand ? r_hand : "Nothing")]</A>
<BR><B>Back:</B> <A href='?src=\ref[src];item=back'>[(back ? back : "Nothing")]</A> [((istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/weapon/tank) && !( internal )) ? text(" <A href='?src=\ref[];item=internal'>Set Internal</A>", src) : "")]
<BR>[(internal ? text("<A href='?src=\ref[src];item=internal'>Remove Internal</A>") : "")]
<BR><A href='?src=\ref[src];item=pockets'>Empty Pockets</A>
<BR><A href='?src=\ref[user];refresh=1'>Refresh</A>
<BR><A href='?src=\ref[user];mach_close=mob[name]'>Close</A>
<BR>"}
user << browse(dat, text("window=mob[];size=325x500", name))
onclose(user, "mob[name]")
return
/mob/living/ret_grab(obj/effect/list_container/mobl/L as obj, flag)
if ((!( istype(l_hand, /obj/item/weapon/grab) ) && !( istype(r_hand, /obj/item/weapon/grab) )))
if (!( L ))
return null
else
return L.container
else
if (!( L ))
L = new /obj/effect/list_container/mobl( null )
L.container += src
L.master = src
if (istype(l_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = l_hand
if (!( L.container.Find(G.affecting) ))
L.container += G.affecting
if (G.affecting)
G.affecting.ret_grab(L, 1)
if (istype(r_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = r_hand
if (!( L.container.Find(G.affecting) ))
L.container += G.affecting
if (G.affecting)
G.affecting.ret_grab(L, 1)
if (!( flag ))
if (L.master == src)
var/list/temp = list( )
temp += L.container
//L = null
qdel(L)
return temp
else
return L.container
return
/mob/living/mode()
set name = "Activate Held Object"
set category = "Object"
set src = usr
if(istype(loc,/obj/mecha)) return
if(hand)
var/obj/item/W = l_hand
if (W)
W.attack_self(src)
update_inv_l_hand()
else
var/obj/item/W = r_hand
if (W)
W.attack_self(src)
update_inv_r_hand()
return
/mob/living/abiotic(var/full_body = 0)
if(full_body && ((src.l_hand && !( src.l_hand.abstract )) || (src.r_hand && !( src.r_hand.abstract )) || (src.back || src.wear_mask)))
return 1
if((src.l_hand && !( src.l_hand.abstract )) || (src.r_hand && !( src.r_hand.abstract )))
return 1
return 0
+45 -10
View File
@@ -47,14 +47,13 @@
if(handle_regular_status_updates()) // Status & health update, are we dead or alive etc.
handle_disabilities() // eye, ear, brain damages
handle_status_effects() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
handle_statuses() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
handle_actions()
update_canmove()
if(client)
handle_regular_hud_updates()
handle_regular_hud_updates()
/mob/living/proc/handle_breathing()
return
@@ -94,23 +93,59 @@
stat = CONSCIOUS
return 1
//this updates all special effects: stunned, sleeping, weakened, druggy, stuttering, etc..
/mob/living/proc/handle_status_effects()
if(paralysis)
paralysis = max(paralysis-1,0)
/mob/living/proc/handle_statuses()
handle_stunned()
handle_weakened()
handle_paralysed()
handle_stuttering()
handle_silent()
handle_drugged()
handle_slurring()
/mob/living/proc/handle_stunned()
if(stunned)
stunned = max(stunned-1,0)
AdjustStunned(-1)
if(!stunned)
update_icons()
return stunned
/mob/living/proc/handle_weakened()
if(weakened)
weakened = max(weakened-1,0)
if(!weakened)
update_icons()
return weakened
/mob/living/proc/handle_stuttering()
if(stuttering)
stuttering = max(stuttering-1, 0)
return stuttering
/mob/living/proc/handle_silent()
if(silent)
silent = max(silent-1, 0)
return silent
/mob/living/proc/handle_drugged()
if(druggy)
druggy = max(druggy-1, 0)
return druggy
/mob/living/proc/handle_slurring()
if(slurring)
slurring = max(slurring-1, 0)
return slurring
/mob/living/proc/handle_paralysed()
if(paralysis)
AdjustParalysis(-1)
if(!paralysis)
update_icons()
return paralysis
/mob/living/proc/handle_disabilities()
//Eyes
if(disabilities & BLIND || stat) //blindness from disability or unconsciousness doesn't get better on its own
if(sdisabilities & BLIND || stat) //blindness from disability or unconsciousness doesn't get better on its own
eye_blind = max(eye_blind, 1)
else if(eye_blind) //blindness, heals slowly over time
eye_blind = max(eye_blind-1,0)
@@ -118,7 +153,7 @@
eye_blurry = max(eye_blurry-1, 0)
//Ears
if(disabilities & DEAF) //disabled-deaf, doesn't get better on its own
if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own
setEarDamage(-1, max(ear_deaf, 1))
else
// deafness heals slowly over time, unless ear_damage is over 100
+104 -64
View File
@@ -125,10 +125,11 @@ default behaviour is:
..()
if (!istype(AM, /atom/movable) || AM.anchored)
if(confused && prob(50) && m_intent=="run")
Paralyse(1)
Weaken(2)
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='warning'>[src] [pick("ran", "slammed")] into \the [AM]!</span>")
src.take_organ_damage(5)
src.apply_damage(5, BRUTE)
src << ("<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
return
if (!now_pushing)
now_pushing = 1
@@ -453,6 +454,7 @@ default behaviour is:
BITSET(hud_updateflag, LIFE_HUD)
failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
reload_fullscreen()
return
@@ -510,52 +512,38 @@ default behaviour is:
if ((get_dist(src, pulling) > 1 || diag))
if (isliving(pulling))
var/mob/living/M = pulling
var/ok = 1
if (locate(/obj/item/weapon/grab, M.grabbed_by))
if (prob(75))
var/obj/item/weapon/grab/G = pick(M.grabbed_by)
if (istype(G, /obj/item/weapon/grab))
for(var/mob/O in viewers(M, null))
O.show_message(text("\red [] has been pulled from []'s grip by []", G.affecting, G.assailant, src), 1)
//G = null
qdel(G)
else
ok = 0
if (locate(/obj/item/weapon/grab, M.grabbed_by.len))
ok = 0
if (ok)
var/atom/movable/t = M.pulling
M.stop_pulling()
var/atom/movable/t = M.pulling
M.stop_pulling()
if(!istype(M.loc, /turf/space))
var/area/A = get_area(M)
if(A.has_gravity)
//this is the gay blood on floor shit -- Added back -- Skie
if (M.lying && (prob(M.getBruteLoss() / 6)))
if(!istype(M.loc, /turf/space))
var/area/A = get_area(M)
if(A.has_gravity)
//this is the gay blood on floor shit -- Added back -- Skie
if (M.lying && (prob(M.getBruteLoss() / 6)))
var/turf/location = M.loc
if (istype(location, /turf/simulated))
location.add_blood(M)
//pull damage with injured people
if(prob(25))
M.adjustBruteLoss(1)
visible_message("<span class='danger'>\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!</span>")
if(M.pull_damage())
if(prob(25))
M.adjustBruteLoss(2)
visible_message("<span class='danger'>\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!</span>")
var/turf/location = M.loc
if (istype(location, /turf/simulated))
location.add_blood(M)
//pull damage with injured people
if(prob(25))
M.adjustBruteLoss(1)
visible_message("<span class='danger'>\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!</span>")
if(M.pull_damage())
if(prob(25))
M.adjustBruteLoss(2)
visible_message("<span class='danger'>\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!</span>")
var/turf/location = M.loc
if (istype(location, /turf/simulated))
location.add_blood(M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/blood_volume = round(H.vessel.get_reagent_amount("blood"))
if(blood_volume > 0)
H.vessel.remove_reagent("blood", 1)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/blood_volume = round(H.vessel.get_reagent_amount("blood"))
if(blood_volume > 0)
H.vessel.remove_reagent("blood", 1)
step(pulling, get_dir(pulling.loc, T))
if(t)
M.start_pulling(t)
step(pulling, get_dir(pulling.loc, T))
if(t)
M.start_pulling(t)
else
if (pulling)
if (istype(pulling, /obj/structure/window))
@@ -580,7 +568,7 @@ default behaviour is:
set name = "Resist"
set category = "IC"
if(!stat && canClick())
if(!incapacitated(INCAPACITATION_KNOCKOUT) && canClick())
setClickCooldown(20)
resist_grab()
if(!weakened)
@@ -595,11 +583,13 @@ default behaviour is:
//unbuckling yourself
if(buckled)
spawn() escape_buckle()
return TRUE
//Breaking out of a locker?
if( src.loc && (istype(src.loc, /obj/structure/closet)) )
var/obj/structure/closet/C = loc
spawn() C.mob_breakout(src)
return TRUE
/mob/living/proc/escape_inventory(obj/item/weapon/holder/H)
if(H != src.loc) return
@@ -633,24 +623,9 @@ default behaviour is:
/mob/living/proc/resist_grab()
var/resisting = 0
for(var/obj/O in requests)
requests.Remove(O)
qdel(O)
resisting++
for(var/obj/item/weapon/grab/G in grabbed_by)
resisting++
switch(G.state)
if(GRAB_PASSIVE)
qdel(G)
if(GRAB_AGGRESSIVE)
if(prob(60)) //same chance of breaking the grab as disarm
visible_message("<span class='warning'>[src] has broken free of [G.assailant]'s grip!</span>")
qdel(G)
if(GRAB_NECK)
//If the you move when grabbing someone then it's easier for them to break free. Same if the affected mob is immune to stun.
if (((world.time - G.assailant.l_move_time < 30 || !stunned) && prob(15)) || prob(3))
visible_message("<span class='warning'>[src] has broken free of [G.assailant]'s headlock!</span>")
qdel(G)
G.handle_resist()
if(resisting)
visible_message("<span class='danger'>[src] resists!</span>")
@@ -662,13 +637,22 @@ default behaviour is:
src << "<span class='notice'>You are now [resting ? "resting" : "getting up"]</span>"
/mob/living/proc/is_allowed_vent_crawl_item(var/obj/item/carried_item)
return isnull(get_inventory_slot(carried_item))
return (get_inventory_slot(carried_item) == 0)
/mob/living/simple_animal/spiderbot/is_allowed_vent_crawl_item(var/obj/item/carried_item)
if(carried_item == held_item)
return 0
return ..()
//called when the mob receives a bright flash
/mob/living/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash)
if(override_blindness_check || !(disabilities & BLIND))
overlay_fullscreen("flash", type)
spawn(25)
if(src)
clear_fullscreen("flash", 25)
return 1
/mob/living/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null, var/ignore_items = 0) // -- TLE -- Merged by Carn
if(stat)
src << "You must be conscious to do this!"
@@ -676,7 +660,6 @@ default behaviour is:
if(lying)
src << "You can't vent crawl while you're stunned!"
return
var/special_fail_msg = cannot_use_vents()
if(special_fail_msg)
src << "<span class='warning'>[special_fail_msg]</span>"
@@ -730,10 +713,12 @@ default behaviour is:
return
if(!ignore_items)
var/list/badItems = list()
for(var/obj/item/carried_item in contents)//If the monkey got on objects.
if(is_allowed_vent_crawl_item(carried_item))
continue
src << "<span class='warning'>You can't be carrying items or have items equipped when vent crawling!</span>"
if(!is_allowed_vent_crawl_item(carried_item))
badItems += carried_item.name
if(badItems.len)
src << "<span class='warning'>Your [english_list(badItems)] prevent[badItems.len == 1 ? "s" : ""] you from ventcrawling.</span>"
return
if(isslime(src))
@@ -865,3 +850,58 @@ default behaviour is:
sleep(350)
lastpuke = 0
/mob/living/update_canmove()
if(!resting && cannot_stand() && can_stand_overridden())
lying = 0
canmove = 1
else
if(istype(buckled, /obj/vehicle))
var/obj/vehicle/V = buckled
if(is_physically_disabled())
lying = 0
canmove = 1
pixel_y = V.mob_offset_y - 5
else
if(buckled.buckle_lying != -1) lying = buckled.buckle_lying
canmove = 1
pixel_y = V.mob_offset_y
else if(buckled)
anchored = 1
canmove = 0
if(istype(buckled))
if(buckled.buckle_lying != -1)
lying = buckled.buckle_lying
if(buckled.buckle_movable)
anchored = 0
canmove = 1
else if(captured)
anchored = 1
canmove = 0
lying = 0
else
lying = incapacitated(INCAPACITATION_KNOCKDOWN)
canmove = !incapacitated(INCAPACITATION_DISABLED)
if(lying)
density = 0
if(l_hand) unEquip(l_hand)
if(r_hand) unEquip(r_hand)
else
density = initial(density)
for(var/obj/item/weapon/grab/G in grabbed_by)
if(G.state >= GRAB_AGGRESSIVE)
canmove = 0
break
//Temporarily moved here from the various life() procs
//I'm fixing stuff incrementally so this will likely find a better home.
//It just makes sense for now. ~Carn
if( update_icon ) //forces a full overlay update
update_icon = 0
regenerate_icons()
else if( lying != lying_prev )
update_icons()
return canmove
+36 -51
View File
@@ -144,6 +144,42 @@
O.emp_act(severity)
..()
/mob/living/proc/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone)
return target_zone
//Called when the mob is hit with an item in combat. Returns the blocked result
/mob/living/proc/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
visible_message("<span class='danger'>[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] with [I.name] by [user]!</span>")
var/blocked = run_armor_check(hit_zone, "melee")
standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone)
if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too
var/turf/simulated/location = get_turf(src)
if(istype(location)) location.add_blood_floor(src)
return blocked
//returns 0 if the effects failed to apply for some reason, 1 otherwise.
/mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone)
if(!effective_force || blocked >= 100)
return 0
//Hulk modifier
if(HULK in user.mutations)
effective_force *= 2
//Apply weapon damage
var/weapon_sharp = is_sharp(I)
var/weapon_edge = has_edge(I)
if(prob(max(getarmor(hit_zone, "melee") - I.armor_penetration, 0))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones
weapon_sharp = 0
weapon_edge = 0
apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I)
return 1
//this proc handles being hit by a thrown atom
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
if(istype(AM,/obj/))
@@ -370,54 +406,3 @@
hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1)
//hud_used.SetButtonCoords(hud_used.hide_actions_toggle,button_number+1)
client.screen += hud_used.hide_actions_toggle
//If simple_animals are ever moved under carbon, then this can probably be moved to carbon as well
/mob/living/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user)
// Knifing
if(!W.edge || !W.force || W.damtype != BRUTE) return //unsuitable weapon
user.visible_message("<span class='danger'>\The [user] begins to slit [src]'s throat with \the [W]!</span>")
user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly
if(!do_after(user, 20))
return
if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab
return
var/damage_mod = 1
//presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well
var/obj/item/clothing/head/helmet = get_equipped_item(slot_head)
if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.item_flags & STOPPRESSUREDAMAGE))
//we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off.
damage_mod = 1.0 - (helmet.armor["melee"]/100)
var/total_damage = 0
for(var/i in 1 to 3)
var/damage = min(W.force*1.5, 20)*damage_mod
apply_damage(damage, W.damtype, BP_HEAD, 0, sharp=W.sharp, edge=W.edge)
total_damage += damage
var/oxyloss = total_damage
if(total_damage >= 40) //threshold to make someone pass out
oxyloss = 60 // Brain lacks oxygen immediately, pass out
adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss
if(total_damage)
if(oxyloss >= 40)
user.visible_message("<span class='danger'>\The [user] slit [src]'s throat open with \the [W]!</span>")
else
user.visible_message("<span class='danger'>\The [user] cut [src]'s neck with \the [W]!</span>")
if(W.hitsound)
playsound(loc, W.hitsound, 50, 1, -1)
G.last_action = world.time
flick(G.hud.icon_state, G.hud)
user.attack_log += "\[[time_stamp()]\]<font color='red'> Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])</font>"
src.attack_log += "\[[time_stamp()]\]<font color='orange'> Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])</font>"
msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" )
return
+113 -57
View File
@@ -82,27 +82,31 @@ proc/get_radio_key_from_channel(var/channel)
/mob/living/proc/get_default_language()
return default_language
/mob/living/proc/handle_speech_problems(var/message, var/verb)
var/list/returns[3]
var/speech_problem_flag = 0
//Takes a list of the form list(message, verb, whispering) and modifies it as needed
//Returns 1 if a speech problem was applied, 0 otherwise
/mob/living/proc/handle_speech_problems(var/list/message_data)
var/message = message_data[1]
var/verb = message_data[2]
var/whispering = message_data[3]
. = 0
if((HULK in mutations) && health >= 25 && length(message))
message = "[uppertext(message)]!!!"
verb = pick("yells","roars","hollers")
speech_problem_flag = 1
whispering = 0
. = 1
if(slurring)
message = slur(message)
verb = pick("slobbers","slurs")
speech_problem_flag = 1
. = 1
if(stuttering)
message = stutter(message)
verb = pick("stammers","stutters")
speech_problem_flag = 1
. = 1
returns[1] = message
returns[2] = verb
returns[3] = speech_problem_flag
return returns
message_data[1] = message
message_data[2] = verb
message_data[3] = whispering
/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
if(message_mode == "intercom")
@@ -124,33 +128,42 @@ proc/get_radio_key_from_channel(var/channel)
return "asks"
return verb
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="")
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering = 0)
//If you're muted for IC chat
if(client)
if(client.prefs.muted & MUTE_IC)
src << "\red You cannot speak in IC (Muted)."
if((client.prefs.muted & MUTE_IC) || say_disabled)
src << "<span class='warning'>You cannot speak in IC (Muted).</span>"
return
//Redirect to say_dead if talker is dead
if(stat)
if(stat == 2)
if(stat == DEAD)
return say_dead(message)
return
//Parse the mode
var/message_mode = parse_message_mode(message, "headset")
//Maybe they are using say/whisper to do a quick emote, so do those
switch(copytext(message,1,2))
if("*") return emote(copytext(message,2))
if("^") return custom_emote(1, copytext(message,2))
//parse the radio code and consume it
//Parse the radio code and consume it
if (message_mode)
if (message_mode == "headset")
message = copytext(message,2) //it would be really nice if the parse procs could do this for us.
else if (message_mode == "whisper")
whispering = 1
message_mode = null
message = copytext(message,3)
else
message = copytext(message,3)
//Clean up any remaining space on the left
message = trim_left(message)
//parse the language code and consume it
//Parse the language code and consume it
if(!speaking)
speaking = parse_language(message)
if(speaking)
@@ -158,42 +171,72 @@ proc/get_radio_key_from_channel(var/channel)
else
speaking = get_default_language()
// This is broadcast to all mobs with the language,
// irrespective of distance or anything else.
//HIVEMIND languages always send to all people with that language
if(speaking && (speaking.flags & HIVEMIND))
speaking.broadcast(src,trim(message))
return 1
verb = say_quote(message, speaking)
//Self explanatory.
if(is_muzzled())
src << "<span class='danger'>You're muzzled and cannot speak!</span>"
return
//Clean up any remaining junk on the left like spaces.
message = trim_left(message)
//Autohiss handles auto-rolling tajaran R's and unathi S's/Z's
message = handle_autohiss(message, speaking)
//Whisper vars
var/w_scramble_range = 5 //The range at which you get ***as*th**wi****
var/w_adverb //An adverb prepended to the verb in whispers
var/w_not_heard //The message for people in watching range
//Handle language-specific verbs and adverb setup if necessary
if(!whispering) //Just doing normal 'say' (for now, may change below)
verb = say_quote(message, speaking)
else if(whispering && speaking.whisper_verb) //Language has defined whisper verb
verb = speaking.whisper_verb
w_not_heard = "[verb] something"
else //Whispering but language has no whisper verb, use say verb
w_adverb = pick("quietly", "softly")
verb = speaking.speech_verb
w_not_heard = "[speaking.speech_verb] something [w_adverb]"
//For speech disorders (hulk, slurring, stuttering)
if(!(speaking && (speaking.flags & NO_STUTTER)))
message = handle_autohiss(message, speaking)
var/list/message_data = list(message, verb, whispering)
if(handle_speech_problems(message_data))
message = message_data[1]
whispering = message_data[3]
var/list/handle_s = handle_speech_problems(message, verb)
message = handle_s[1]
verb = handle_s[2]
if(verb != message_data[2]) //They changed our verb
if(whispering)
w_adverb = pick("quietly", "softly")
verb = message_data[2]
//Whisper may have adverbs, add those if one was set
if(w_adverb) verb = "[verb] [w_adverb]"
//If something nulled or emptied the message, forget it
if(!message || message == "")
return 0
//Radio message handling
var/list/obj/item/used_radios = new
if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name))
if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whispering))
return 1
//For languages with actual speech sounds
var/list/handle_v = handle_speech_sound()
var/sound/speech_sound = handle_v[1]
var/sound_vol = handle_v[2]
var/italics = 0
//Default range and italics, may be overridden past here
var/message_range = world.view
var/italics = 0
//speaking into radios
//Speaking into radios
if(used_radios.len)
italics = 1
message_range = 1
@@ -208,9 +251,13 @@ proc/get_radio_key_from_channel(var/channel)
if (speech_sound)
sound_vol *= 0.5
var/turf/T = get_turf(src)
//Set vars if we're still whispering by this point
if(whispering)
italics = 1
message_range = 1
sound_vol *= 0.5
//handle nonverbal and sign languages here
//Handle nonverbal and sign languages here
if (speaking)
if (speaking.flags & NONVERBAL)
if (prob(30))
@@ -219,55 +266,64 @@ proc/get_radio_key_from_channel(var/channel)
if (speaking.flags & SIGNLANG)
return say_signlang(message, pick(speaking.signlang_verb), speaking)
//These will contain the main receivers of the message
var/list/listening = list()
var/list/listening_obj = list()
//Atmosphere calculations (speaker's side only, for now)
var/turf/T = get_turf(src)
if(T)
//make sure the air can transmit speech - speaker's side
//Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = (environment)? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
//Air is nearing minimum levels, make text italics as a hint, and muffle sound
if (pressure < ONE_ATMOSPHERE*0.4)
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
sound_vol *= 0.5
var/list/hear = get_mobs_or_objects_in_view(message_range,src)
var/list/hearturfs = list()
for(var/I in hear)
if(ismob(I))
var/mob/M = I
listening += M
hearturfs += M.locs[1]
else if(isobj(I))
var/obj/O = I
hearturfs += O.locs[1]
listening_obj |= O
for(var/mob/M in player_list)
if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS))
listening |= M
continue
if(M.loc && M.locs[1] in hearturfs)
listening |= M
//Obtain the mobs and objects in the message range
var/list/results = get_mobs_and_objs_in_view_fast(T, world.view)
listening = results["mobs"]
listening_obj = results["objs"]
else
return 1 //If we're in nullspace, then forget it.
//The 'post-say' static speech bubble
var/speech_bubble_test = say_test(message)
var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]")
spawn(30) qdel(speech_bubble)
//Main 'say' and 'whisper' message delivery
for(var/mob/M in listening)
M << speech_bubble
M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes
if(M && src) //If we still exist, when the spawn processes
var/dst = get_dist(get_turf(M),get_turf(src))
if(dst <= message_range || M.stat == DEAD) //Inside normal message range, or dead with ears (handled in the view proc)
M << speech_bubble
M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
if(whispering) //Don't even bother with these unless whispering
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
M << speech_bubble
M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol*0.2)
if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range
M.show_message("<span class='game say'><span class='name'>[src.name]</span> [w_not_heard].</span>", 2)
//Object message delivery
for(var/obj/O in listening_obj)
spawn(0)
if(O) //It's possible that it could be deleted in the meantime.
O.hear_talk(src, message, verb, speaking)
if(O && src) //If we still exist, when the spawn processes
var/dst = get_dist(get_turf(O),get_turf(src))
if(dst <= message_range)
O.hear_talk(src, message, verb, speaking)
log_say("[name]/[key] : [message]")
//Log the message to file
log_say("[name]/[key][whispering ? " (W)" : ""]: [message]")
return 1
/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/datum/language/language)
+6 -4
View File
@@ -20,7 +20,7 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/toggle_hidden_verbs,
)
var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.com/1172/
var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.com/1172/,
/mob/living/silicon/ai/proc/ai_announcement,
/mob/living/silicon/ai/proc/ai_call_shuttle,
/mob/living/silicon/ai/proc/ai_camera_track,
@@ -52,7 +52,7 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
density = 1
status_flags = CANSTUN|CANPARALYSE|CANPUSH
shouldnt_see = list(/obj/effect/rune)
var/list/network = list("Northern Star")
var/list/network = list(station_short)
var/obj/machinery/camera/camera = null
var/list/connected_robots = list()
var/aiRestorePowerRoutine = 0
@@ -151,11 +151,13 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
add_language("Galactic Common", 1)
add_language("Sol Common", 0)
add_language("Sinta'unathi", 0)
add_language("Siik'maas", 0)
add_language("Siik'tajr", 0)
add_language("Skrellian", 0)
add_language("Tradeband", 1)
add_language("Gutter", 0)
add_language("Encoded Audio Language", 1)
add_language("Schechi", 0)
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
@@ -232,11 +234,11 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
/mob/living/silicon/ai/proc/setup_icon()
var/file = file2text("config/custom_sprites.txt")
var/lines = text2list(file, "\n")
var/lines = splittext(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = text2list(line, ":")
var/list/Entry = splittext(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
@@ -39,6 +39,6 @@
/mob/proc/showLaws(var/mob/living/silicon/S)
return
/mob/dead/observer/showLaws(var/mob/living/silicon/S)
/mob/observer/dead/showLaws(var/mob/living/silicon/S)
if(antagHUD || is_admin(src))
S.laws.show_laws(src)
+6 -8
View File
@@ -56,18 +56,18 @@
if (aiRestorePowerRoutine==2)
src << "Alert cancelled. Power has been restored without our assistance."
aiRestorePowerRoutine = 0
src.blind.layer = 0
clear_fullscreen("blind")
updateicon()
return
else if (aiRestorePowerRoutine==3)
src << "Alert cancelled. Power has been restored."
aiRestorePowerRoutine = 0
src.blind.layer = 0
clear_fullscreen("blind")
updateicon()
return
else if (APU_power)
aiRestorePowerRoutine = 0
src.blind.layer = 0
clear_fullscreen("blind")
updateicon()
return
else
@@ -79,9 +79,7 @@
//Blind the AI
updateicon()
src.blind.screen_loc = ui_entire_screen
if (src.blind.layer!=18)
src.blind.layer = 18
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
src.sight = src.sight&~SEE_TURFS
src.sight = src.sight&~SEE_MOBS
src.sight = src.sight&~SEE_OBJS
@@ -99,7 +97,7 @@
if (!istype(T, /turf/space))
src << "Alert cancelled. Power has been restored without our assistance."
aiRestorePowerRoutine = 0
src.blind.layer = 0
clear_fullscreen("blind")
return
src << "Fault confirmed: missing external power. Shutting down main control system to save power."
sleep(20)
@@ -129,7 +127,7 @@
if (!istype(T, /turf/space))
src << "Alert cancelled. Power has been restored without our assistance."
aiRestorePowerRoutine = 0
src.blind.layer = 0 //This, too, is a fix to issue 603
clear_fullscreen("blind") //This, too, is a fix to issue 603
return
switch(PRP)
if (1) src << "APC located. Optimizing route to APC to avoid needless power waste."
@@ -2,19 +2,6 @@
..()
for(var/obj/effect/rune/rune in rune_list)
client.images += rune.blood_image
regenerate_icons()
flash = new /obj/screen()
flash.icon_state = "blank"
flash.name = "flash"
flash.screen_loc = ui_entire_screen
flash.layer = 17
blind = new /obj/screen()
blind.icon_state = "black"
blind.name = " "
blind.screen_loc = ui_entire_screen
blind.layer = 0
client.screen.Add( blind, flash )
if(stat != DEAD)
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 1
@@ -7,6 +7,9 @@
pass_flags = 1
mob_size = MOB_SMALL
can_pull_size = 2
can_pull_mobs = MOB_PULL_SMALLER
idcard_type = /obj/item/weapon/card/id
var/idaccessible = 0
@@ -233,7 +233,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates
for(var/datum/paiCandidate/c in paiController.pai_candidates)
if(c.ready)
var/found = 0
for(var/mob/dead/observer/o in player_list)
for(var/mob/observer/dead/o in player_list)
if(o.key == c.key && o.MayRespawn())
found = 1
if(found)
@@ -346,7 +346,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates
/datum/paiController/proc/requestRecruits(var/mob/user)
inquirer = user
for(var/mob/dead/observer/O in player_list)
for(var/mob/observer/dead/O in player_list)
if(!O.MayRespawn())
continue
if(jobban_isbanned(O, "pAI"))
@@ -121,11 +121,11 @@
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
data_core.get_manifest_json()
data_core.get_manifest_list()
var/data[0]
// This is dumb, but NanoUI breaks if it has no data to send
data["manifest"] = list("__json_cache" = ManifestJSON)
data["manifest"] = PDA_Manifest
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
@@ -75,7 +75,7 @@
var/organ_found
if(H.internal_organs.len)
for(var/obj/item/organ/external/E in H.organs)
if(!(E.status & ORGAN_ROBOT))
if(!(E.robotic >= ORGAN_ROBOT))
continue
organ_found = 1
user << "[E.name]: <font color='red'>[E.brute_dam]</font> <font color='#FFA500'>[E.burn_dam]</font>"
@@ -86,7 +86,7 @@
organ_found = null
if(H.internal_organs.len)
for(var/obj/item/organ/O in H.internal_organs)
if(!(O.status & ORGAN_ROBOT))
if(!(O.robotic >= ORGAN_ROBOT))
continue
organ_found = 1
user << "[O.name]: <font color='red'>[O.damage]</font>"
@@ -75,7 +75,7 @@
/datum/robot_component/armour
name = "armour plating"
external_type = /obj/item/robot_parts/robot_component/armour
max_damage = 60
max_damage = 90
// ACTUATOR
@@ -6,7 +6,7 @@ var/list/robot_custom_icons
/hook/startup/proc/load_robot_custom_sprites()
var/config_file = file2text("config/custom_sprites.txt")
var/list/lines = text2list(config_file, "\n")
var/list/lines = splittext(config_file, "\n")
robot_custom_icons = list()
for(var/line in lines)
@@ -240,7 +240,7 @@ var/list/mob_hat_cache = list()
//Drones killed by damage will gib.
/mob/living/silicon/robot/drone/handle_regular_status_updates()
var/turf/T = get_turf(src)
if((!T || health <= -35 || (master_fabricator && T.z != master_fabricator.z)) && src.stat != DEAD)
if(!T || health <= -35 )
timeofdeath = world.time
death() //Possibly redundant, having trouble making death() cooperate.
gib()
@@ -278,7 +278,7 @@ var/list/mob_hat_cache = list()
//Reboot procs.
/mob/living/silicon/robot/drone/proc/request_player()
for(var/mob/dead/observer/O in player_list)
for(var/mob/observer/dead/O in player_list)
if(jobban_isbanned(O, "Cyborg"))
continue
if(O.client)
@@ -11,8 +11,6 @@
//Has a list of items that it can hold.
var/list/can_hold = list(
/obj/item/weapon/cell,
/obj/item/weapon/firealarm_electronics,
/obj/item/weapon/airalarm_electronics,
/obj/item/weapon/airlock_electronics,
/obj/item/weapon/tracker_electronics,
/obj/item/weapon/module/power_control,
@@ -63,9 +61,9 @@
/obj/item/device/mmi,
/obj/item/robot_parts,
/obj/item/borg/upgrade,
/obj/item/device/flash, //to build borgs
/obj/item/organ/internal/brain, //to insert into MMIs.
/obj/item/stack/cable_coil, //again, for borg building
/obj/item/device/flash, //to build borgs,
/obj/item/organ/internal/brain, //to insert into MMIs,
/obj/item/weapon/disk,
/obj/item/weapon/circuitboard,
/obj/item/slime_extract,
/obj/item/weapon/reagent_containers/glass,
@@ -85,6 +83,35 @@
/obj/item/weapon/grown
)
/obj/item/weapon/gripper/no_use/organ
name = "organ gripper"
icon_state = "gripper-flesh"
desc = "A specialized grasping tool used to preserve and manipulate organic material."
can_hold = list(
/obj/item/organ
)
/obj/item/weapon/gripper/no_use/organ/robotics
name = "external organ gripper"
icon_state = "gripper-flesh"
desc = "A specialized grasping tool used in robotics work."
can_hold = list(
/obj/item/organ/external,
/obj/item/organ/internal/cell
)
/obj/item/weapon/gripper/no_use/mech
name = "exosuit gripper"
icon_state = "gripper-mech"
desc = "A large, heavy-duty grasping tool used in construction of mechs."
can_hold = list(
/obj/item/mecha_parts/part,
/obj/item/mecha_parts/mecha_equipment
)
/obj/item/weapon/gripper/no_use //Used when you want to hold and put items in other things, but not able to 'use' the item
/obj/item/weapon/gripper/no_use/attack_self(mob/user as mob)
@@ -15,7 +15,7 @@
idle_power_usage = 20
active_power_usage = 5000
var/fabricator_tag = "Northern Star Upper Level"
var/fabricator_tag = station_short+" Upper Level"
var/drone_progress = 0
var/produce_drones = 1
var/time_last_drone = 500
@@ -26,7 +26,7 @@
/obj/machinery/drone_fabricator/derelict
name = "construction drone fabricator"
fabricator_tag = "Northern Star Depths"
fabricator_tag = station_short+" Depths"
drone_type = /mob/living/silicon/robot/drone/construction
/obj/machinery/drone_fabricator/New()
@@ -59,7 +59,7 @@
/obj/machinery/drone_fabricator/examine(mob/user)
..(user)
if(produce_drones && drone_progress >= 100 && istype(user,/mob/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
if(produce_drones && drone_progress >= 100 && istype(user,/mob/observer/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
user << "<BR><B>A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone.</B>"
/obj/machinery/drone_fabricator/proc/create_drone(var/client/player)
@@ -70,7 +70,7 @@
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
return
if(!player || !istype(player.mob,/mob/dead))
if(!player || !istype(player.mob,/mob/observer/dead))
return
announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
@@ -85,7 +85,7 @@
drone_progress = 0
/mob/dead/verb/join_as_drone()
/mob/observer/dead/verb/join_as_drone()
set category = "Ghost"
set name = "Join As Drone"
@@ -4,12 +4,10 @@
if(client.prefs.muted & MUTE_IC)
src << "You cannot send IC messages (muted)."
return 0
if (src.client.handle_spam_prevention(message,MUTE_IC))
return 0
message = sanitize(message)
if (stat == 2)
if (stat == DEAD)
return say_dead(message)
if(copytext(message,1,2) == "*")
@@ -34,7 +32,7 @@
for (var/mob/M in player_list)
if (istype(M, /mob/new_player))
continue
else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
if(M.client) M << "<b>[src]</b> transmits, \"[message]\""
return 1
return ..(message, 0)
@@ -14,8 +14,6 @@
if(client.prefs.muted & MUTE_IC)
src << "You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (stat)
return
if(!(message))
+13 -21
View File
@@ -275,29 +275,21 @@
// if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]"
// if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]"
client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired)
if ((src.blind && src.stat != 2))
if(src.blinded)
src.blind.layer = 18
if(stat != 2)
if(blinded)
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else
src.blind.layer = 0
if (src.disabilities & NEARSIGHTED)
src.client.screen += global_hud.vimpaired
clear_fullscreen("blind")
set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
if (src.eye_blurry)
src.client.screen += global_hud.blurry
if (src.druggy)
src.client.screen += global_hud.druggy
if (src.stat != 2)
if (src.machine)
if (src.machine.check_eye(src) < 0)
src.reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
if (src.machine)
if (src.machine.check_eye(src) < 0)
src.reset_view(null)
else
if(client && !client.adminobs)
reset_view(null)
return 1
@@ -28,10 +28,9 @@
user << "You activate the analyzer's microlaser, analyzing \the [loaded_item] and breaking it down."
flick("portable_analyzer_scan", src)
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
var/list/temp_tech = ConvertReqString2List(loaded_item.origin_tech)
for(var/T in temp_tech)
files.UpdateTech(T, temp_tech[T])
user << "\The [loaded_item] had level [temp_tech[T]] in [T]."
for(var/T in loaded_item.origin_tech)
files.UpdateTech(T, loaded_item.origin_tech[T])
user << "\The [loaded_item] had level [loaded_item.origin_tech[T]] in [CallTechName(T)]."
loaded_item = null
for(var/obj/I in contents)
for(var/mob/M in I.contents)
@@ -20,9 +20,10 @@ var/global/list/robot_modules = list(
w_class = 100.0
item_state = "electronic"
flags = CONDUCT
var/hide_on_manifest = 0
var/channels = list()
var/networks = list()
var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK_TAJR = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0)
var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK_TAJR = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0, LANGUAGE_SCHECHI = 0)
var/sprites = list()
var/can_be_pushed = 1
var/no_slip = 0
@@ -186,7 +187,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/medical/surgeon/New()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/device/healthanalyzer(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo(src)
src.modules += new /obj/item/weapon/scalpel(src)
src.modules += new /obj/item/weapon/hemostat(src)
src.modules += new /obj/item/weapon/retractor(src)
@@ -196,6 +197,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/bonesetter(src)
src.modules += new /obj/item/weapon/circular_saw(src)
src.modules += new /obj/item/weapon/surgicaldrill(src)
src.modules += new /obj/item/weapon/gripper/no_use/organ(src)
src.modules += new /obj/item/weapon/extinguisher/mini(src)
src.emag = new /obj/item/weapon/reagent_containers/spray(src)
src.emag.reagents.add_reagent("pacid", 250)
@@ -240,10 +242,11 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/device/healthanalyzer(src)
src.modules += new /obj/item/device/reagent_scanner/adv(src)
src.modules += new /obj/item/roller_holder(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo/crisis(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo(src)
src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src)
src.modules += new /obj/item/weapon/reagent_containers/syringe(src)
src.modules += new /obj/item/weapon/gripper/no_use/organ(src)
src.modules += new /obj/item/weapon/extinguisher/mini(src)
src.emag = new /obj/item/weapon/reagent_containers/spray(src)
src.emag.reagents.add_reagent("pacid", 250)
@@ -311,6 +314,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/screwdriver(src)
src.modules += new /obj/item/weapon/wrench(src)
src.modules += new /obj/item/weapon/crowbar(src)
src.modules += new /obj/item/weapon/weldingtool/largetank(src)
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
src.modules += new /obj/item/device/pipe_painter(src)
src.modules += new /obj/item/device/floor_painter(src)
@@ -331,6 +335,10 @@ var/global/list/robot_modules = list(
R.synths = list(metal)
src.modules += R
var/obj/item/stack/tile/floor/cyborg/F = new /obj/item/stack/tile/floor/cyborg(src)
F.synths = list(metal)
src.modules += F
var/obj/item/stack/material/cyborg/plasteel/S = new (src)
S.synths = list(plasteel)
src.modules += S
@@ -357,6 +365,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/gripper(src)
src.modules += new /obj/item/device/lightreplacer(src)
src.modules += new /obj/item/device/pipe_painter(src)
src.modules += new /obj/item/device/floor_painter(src)
src.emag = new /obj/item/borg/stun(src)
var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000)
@@ -422,6 +431,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/melee/baton/robot(src)
src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src)
src.modules += new /obj/item/taperoll/police(src)
src.modules += new /obj/item/weapon/reagent_containers/spray/pepper(src)
src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src)
..()
@@ -478,11 +488,12 @@ var/global/list/robot_modules = list(
LANGUAGE_SOL_COMMON = 1,
LANGUAGE_UNATHI = 1,
LANGUAGE_SIIK_MAAS = 1,
LANGUAGE_SIIK_TAJR = 0,
LANGUAGE_SIIK_TAJR = 1,
LANGUAGE_SKRELLIAN = 1,
LANGUAGE_ROOTSPEAK = 1,
LANGUAGE_TRADEBAND = 1,
LANGUAGE_GUTTER = 1
LANGUAGE_GUTTER = 1,
LANGUAGE_SCHECHI = 1
)
/obj/item/weapon/robot_module/clerical/butler
@@ -504,6 +515,8 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/device/analyzer/plant_analyzer(src)
src.modules += new /obj/item/weapon/storage/bag/plants(src)
src.modules += new /obj/item/weapon/robot_harvester(src)
src.modules += new /obj/item/weapon/material/knife(src)
src.modules += new /obj/item/weapon/material/kitchen/rollingpin(src)
var/obj/item/weapon/rsf/M = new /obj/item/weapon/rsf(src)
M.stored_matter = 30
@@ -543,8 +556,10 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/form_printer(src)
src.modules += new /obj/item/weapon/gripper/paperwork(src)
src.modules += new /obj/item/weapon/hand_labeler(src)
src.emag = new /obj/item/weapon/stamp/denied(src)
..()
src.modules += new /obj/item/weapon/stamp(src)
src.modules += new /obj/item/weapon/stamp/denied(src)
src.emag = new /obj/item/weapon/stamp/chameleon(src)
src.emag = new /obj/item/weapon/pen/chameleon(src)
/obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules
@@ -591,12 +606,17 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/weapon/portable_destructive_analyzer(src)
src.modules += new /obj/item/weapon/gripper/research(src)
src.modules += new /obj/item/weapon/gripper/no_use/organ/robotics(src)
src.modules += new /obj/item/weapon/gripper/no_use/mech(src)
src.modules += new /obj/item/weapon/gripper/no_use/loader(src)
src.modules += new /obj/item/device/robotanalyzer(src)
src.modules += new /obj/item/weapon/card/robot(src)
src.modules += new /obj/item/weapon/wrench(src)
src.modules += new /obj/item/weapon/weldingtool/largetank(src)
src.modules += new /obj/item/weapon/screwdriver(src)
src.modules += new /obj/item/weapon/wrench(src)
src.modules += new /obj/item/weapon/crowbar(src)
src.modules += new /obj/item/weapon/wirecutters(src)
src.modules += new /obj/item/device/multitool(src)
src.modules += new /obj/item/weapon/scalpel(src)
src.modules += new /obj/item/weapon/circular_saw(src)
src.modules += new /obj/item/weapon/extinguisher/mini(src)
@@ -606,6 +626,8 @@ var/global/list/robot_modules = list(
var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000)
synths += nanite
var/datum/matter_synth/wire = new /datum/matter_synth/wire() //Added to allow repairs, would rather add cable now than be asked to add it later,
synths += wire //Cable code, taken from engiborg,
var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src)
N.uses_charge = 1
@@ -613,17 +635,25 @@ var/global/list/robot_modules = list(
N.synths = list(nanite)
src.modules += N
var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) //Cable code, taken from engiborg,
C.synths = list(wire)
src.modules += C
..()
/obj/item/weapon/robot_module/syndicate
name = "illegal robot module"
hide_on_manifest = 1
languages = list(
LANGUAGE_SOL_COMMON = 1,
LANGUAGE_TRADEBAND = 1,
LANGUAGE_UNATHI = 0,
LANGUAGE_SIIK_MAAS = 0,
LANGUAGE_SIIK_TAJR = 0,
LANGUAGE_SKRELLIAN = 0,
LANGUAGE_GUTTER = 1
LANGUAGE_ROOTSPEAK = 0,
LANGUAGE_GUTTER = 1,
LANGUAGE_SCHECHI = 0
)
sprites = list(
"Dread" = "securityrobot",
@@ -651,6 +681,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/security/combat
name = "combat robot module"
hide_on_manifest = 1
sprites = list("Combat Android" = "droid-combat")
/obj/item/weapon/robot_module/combat/New()
@@ -665,6 +696,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/drone
name = "drone module"
hide_on_manifest = 1
no_slip = 1
networks = list(NETWORK_ENGINEERING)
@@ -747,6 +779,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/drone/construction
name = "construction drone module"
hide_on_manifest = 1
channels = list("Engineering" = 1)
languages = list()
+2 -2
View File
@@ -1,5 +1,5 @@
/mob/living/silicon/say(var/message, var/sanitize = 1)
return ..(sanitize ? sanitize(message) : message)
/mob/living/silicon/say(var/message, var/sanitize = 1, var/whispering = 0)
return ..((sanitize ? sanitize(message) : message), whispering = whispering)
/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
log_say("[key_name(src)] : [message]")
+7 -6
View File
@@ -40,7 +40,7 @@
/mob/living/silicon/Destroy()
silicon_mob_list -= src
for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
AH.unregister(src)
AH.unregister_alarm(src)
..()
/mob/living/silicon/proc/init_id()
@@ -67,7 +67,7 @@
if(2)
src.take_organ_damage(0,10,emp=1)
confused = (min(confused + 2, 30))
flick("noise", src.flash)
flash_eyes(affect_silicon = 1)
src << "<span class='danger'><B>*BZZZT*</B></span>"
src << "<span class='danger'>Warning: Electromagnetic pulse detected.</span>"
..()
@@ -132,9 +132,6 @@
updatehealth()
return 1*/
/mob/living/silicon/attack_throat()
return
/proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai)
if(!istype(bot) || !istype(ai))
return 0
@@ -267,7 +264,7 @@
/mob/living/silicon/ex_act(severity)
if(!blinded)
flick("flash", flash)
flash_eyes()
switch(severity)
if(1.0)
@@ -364,3 +361,7 @@
..()
if(cameraFollow)
cameraFollow = null
/mob/living/silicon/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash)
if(affect_silicon)
return ..()
+1 -1
View File
@@ -39,7 +39,7 @@
return
for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
AH.register(src, /mob/living/silicon/proc/receive_alarm)
AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm)
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
/********************
@@ -173,7 +173,7 @@
//Procs for grabbing players.
/mob/living/simple_animal/borer/proc/request_player()
for(var/mob/dead/observer/O in player_list)
for(var/mob/observer/dead/O in player_list)
if(jobban_isbanned(O, "Borer"))
continue
if(O.client)
@@ -9,8 +9,6 @@
if(client.prefs.muted & MUTE_IC)
src << "\red You cannot speak in IC (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if(istype(src.loc,/mob/living/simple_animal/borer))
@@ -28,7 +26,7 @@
for (var/mob/M in player_list)
if (istype(M, /mob/new_player))
continue
else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
M << "The captive mind of [src] whispers, \"[message]\""
/mob/living/captive_brain/emote(var/message)
@@ -16,8 +16,6 @@
if(client.prefs.muted & MUTE_IC)
src << "\red You cannot speak in IC (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
@@ -38,5 +36,5 @@
for (var/mob/M in player_list)
if (istype(M, /mob/new_player))
continue
else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
M << "[src.truename] whispers to [host], \"[message]\""
@@ -57,7 +57,7 @@
handle_movement_target()
if(prob(2)) //spooky
var/mob/dead/observer/spook = locate() in range(src,5)
var/mob/observer/dead/spook = locate() in range(src,5)
if(spook)
var/turf/T = spook.loc
var/list/visible = list()
@@ -61,7 +61,7 @@
if(!B.brainmob.key)
var/ghost_can_reenter = 0
if(B.brainmob.mind)
for(var/mob/dead/observer/G in player_list)
for(var/mob/observer/dead/G in player_list)
if(G.can_reenter_corpse && G.mind == B.brainmob.mind)
ghost_can_reenter = 1
break
@@ -130,7 +130,7 @@
return 0
else
attacked_with_item(O, user)
O.attack(src, user, user.zone_sel.selecting)
/mob/living/simple_animal/spiderbot/emag_act(var/remaining_charges, var/mob/user)
if (emagged)
@@ -57,16 +57,16 @@
switch(stance)
if(HOSTILE_STANCE_TIRED)
if(STANCE_TIRED)
stop_automated_movement = 1
stance_step++
if(stance_step >= 10) //rests for 10 ticks
if(target_mob && target_mob in ListTargets(10))
stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
stance = STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
else
stance = HOSTILE_STANCE_IDLE
stance = STANCE_IDLE
if(HOSTILE_STANCE_ALERT)
if(STANCE_ALERT)
stop_automated_movement = 1
var/found_mob = 0
if(target_mob && target_mob in ListTargets(10))
@@ -84,14 +84,14 @@
stance_step--
if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode
stance = HOSTILE_STANCE_IDLE
stance = STANCE_IDLE
if(stance_step >= 7) //If we have been staring at a mob for 7 ticks,
stance = HOSTILE_STANCE_ATTACK
stance = STANCE_ATTACK
if(HOSTILE_STANCE_ATTACKING)
if(STANCE_ATTACKING)
if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest
custom_emote(1, "is worn out and needs to rest." )
stance = HOSTILE_STANCE_TIRED
stance = STANCE_TIRED
stance_step = 0
walk(src, 0) //This stops the bear's walking
return
@@ -99,15 +99,15 @@
/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
stance = HOSTILE_STANCE_ALERT
if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING)
stance = STANCE_ALERT
stance_step = 6
target_mob = user
..()
/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob)
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
stance = HOSTILE_STANCE_ALERT
if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING)
stance = STANCE_ALERT
stance_step = 6
target_mob = M
..()
@@ -119,7 +119,7 @@
. = ..()
if(.)
custom_emote(1,"stares alertly at [.]")
stance = HOSTILE_STANCE_ALERT
stance = STANCE_ALERT
/mob/living/simple_animal/hostile/bear/LoseTarget()
..(5)
@@ -6,15 +6,16 @@
icon_state = "otherthing"
icon_living = "otherthing"
icon_dead = "otherthing-dead"
health = 40
maxHealth = 40
health = 40
harm_intent_damage = 8
melee_damage_lower = 5
melee_damage_upper = 5
attacktext = "chomped"
attack_sound = 'sound/weapons/bite.ogg'
faction = "creature"
speed = 8
harm_intent_damage = 10
/mob/living/simple_animal/hostile/creature/cult
faction = "cult"
@@ -37,3 +38,35 @@
/mob/living/simple_animal/hostile/creature/cult/Life()
..()
check_horde()
/mob/living/simple_animal/hostile/creature/strong
maxHealth = 160
health = 160
harm_intent_damage = 5
melee_damage_lower = 8
melee_damage_upper = 25
/mob/living/simple_animal/hostile/creature/strong/cult
faction = "cult"
min_oxy = 0
max_oxy = 0
min_tox = 0
max_tox = 0
min_co2 = 0
max_co2 = 0
min_n2 = 0
max_n2 = 0
minbodytemp = 0
supernatural = 1
/mob/living/simple_animal/hostile/creature/cult/cultify()
return
/mob/living/simple_animal/hostile/creature/cult/Life()
..()
check_horde()
@@ -58,3 +58,26 @@
/mob/living/simple_animal/hostile/faithless/cult/Life()
..()
check_horde()
/mob/living/simple_animal/hostile/faithless/strong
maxHealth = 100
health = 100
harm_intent_damage = 5
melee_damage_lower = 7
melee_damage_upper = 20
/mob/living/simple_animal/hostile/faithless/strong/cult
faction = "cult"
supernatural = 1
/mob/living/simple_animal/hostile/faithless/cult/cultify()
return
/mob/living/simple_animal/hostile/faithless/cult/Life()
..()
check_horde()
@@ -19,7 +19,7 @@
meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "pokes"
response_harm = "punches"
stop_automated_movement_when_pulled = 0
maxHealth = 200
health = 200
@@ -83,14 +83,14 @@
var/mob/living/carbon/human/H = target
if(prob(poison_per_bite))
var/obj/item/organ/external/O = pick(H.organs)
if(!(O.status & ORGAN_ROBOT))
if(!(O.robotic >= ORGAN_ROBOT))
var/eggs = PoolOrNew(/obj/effect/spider/eggcluster/, list(O, src))
O.implants += eggs
/mob/living/simple_animal/hostile/giant_spider/Life()
..()
if(!stat)
if(stance == HOSTILE_STANCE_IDLE)
if(stance == STANCE_IDLE)
//1% chance to skitter madly away
if(!busy && prob(1))
/*var/list/move_targets = list()
@@ -113,7 +113,7 @@
/mob/living/simple_animal/hostile/giant_spider/nurse/Life()
..()
if(!stat)
if(stance == HOSTILE_STANCE_IDLE)
if(stance == STANCE_IDLE)
var/list/can_see = view(src, 10)
//30% chance to stop wandering and do something
if(!busy && prob(30))
@@ -213,4 +213,4 @@
#undef SPINNING_WEB
#undef LAYING_EGGS
#undef MOVING_TO_TARGET
#undef SPINNING_COCOON
#undef SPINNING_COCOON
@@ -1,234 +1,8 @@
/mob/living/simple_animal/hostile
faction = "hostile"
var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior
var/mob/living/target_mob
var/attack_same = 0
var/ranged = 0
var/rapid = 0
var/projectiletype
var/projectilesound
var/casingtype
var/move_to_delay = 4 //delay for the automated movement.
var/list/friends = list()
var/break_stuff_probability = 10
break_stuff_probability = 10
stop_automated_movement_when_pulled = 0
var/destroy_surroundings = 1
destroy_surroundings = 1
a_intent = I_HURT
var/shuttletarget = null
var/enroute = 0
/mob/living/simple_animal/hostile/proc/FindTarget()
var/atom/T = null
stop_automated_movement = 0
for(var/atom/A in ListTargets(10))
if(A == src)
continue
var/atom/F = Found(A)
if(F)
T = F
break
if(isliving(A))
var/mob/living/L = A
if(L.faction == src.faction && !attack_same)
continue
else if(L in friends)
continue
else
if(!L.stat)
stance = HOSTILE_STANCE_ATTACK
T = L
break
else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
var/obj/mecha/M = A
if (M.occupant)
stance = HOSTILE_STANCE_ATTACK
T = M
break
return T
/mob/living/simple_animal/hostile/proc/Found(var/atom/A)
return
/mob/living/simple_animal/hostile/proc/MoveToTarget()
stop_automated_movement = 1
if(!target_mob || SA_attackable(target_mob))
stance = HOSTILE_STANCE_IDLE
if(target_mob in ListTargets(10))
if(ranged)
if(get_dist(src, target_mob) <= 6)
OpenFire(target_mob)
else
walk_to(src, target_mob, 1, move_to_delay)
else
stance = HOSTILE_STANCE_ATTACKING
walk_to(src, target_mob, 1, move_to_delay)
/mob/living/simple_animal/hostile/proc/AttackTarget()
stop_automated_movement = 1
if(!target_mob || SA_attackable(target_mob))
LoseTarget()
return 0
if(!(target_mob in ListTargets(10)))
LostTarget()
return 0
if(get_dist(src, target_mob) <= 1) //Attacking
AttackingTarget()
return 1
/mob/living/simple_animal/hostile/proc/AttackingTarget()
if(!Adjacent(target_mob))
return
if(isliving(target_mob))
var/mob/living/L = target_mob
L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return L
if(istype(target_mob,/obj/mecha))
var/obj/mecha/M = target_mob
M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return M
/mob/living/simple_animal/hostile/proc/LoseTarget()
stance = HOSTILE_STANCE_IDLE
target_mob = null
walk(src, 0)
/mob/living/simple_animal/hostile/proc/LostTarget()
stance = HOSTILE_STANCE_IDLE
walk(src, 0)
/mob/living/simple_animal/hostile/proc/ListTargets(var/dist = 7)
var/list/L = hearers(src, dist)
for (var/obj/mecha/M in mechas_list)
if (M.z == src.z && get_dist(src, M) <= dist)
L += M
return L
/mob/living/simple_animal/hostile/death()
..()
walk(src, 0)
/mob/living/simple_animal/hostile/Life()
. = ..()
if(!.)
walk(src, 0)
return 0
if(client)
return 0
if(!stat && !ai_inactive)
switch(stance)
if(HOSTILE_STANCE_IDLE)
target_mob = FindTarget()
if(HOSTILE_STANCE_ATTACK)
if(destroy_surroundings)
DestroySurroundings()
MoveToTarget()
if(HOSTILE_STANCE_ATTACKING)
if(destroy_surroundings)
DestroySurroundings()
AttackTarget()
/mob/living/simple_animal/hostile/proc/OpenFire(target_mob)
var/target = target_mob
visible_message("\red <b>[src]</b> fires at [target]!", 1)
var/tturf = get_turf(target)
if(rapid)
spawn(1)
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
spawn(4)
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
spawn(6)
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
else
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype
stance = HOSTILE_STANCE_IDLE
target_mob = null
return
/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
if(target == start)
return
var/obj/item/projectile/A = new projectiletype(user:loc)
playsound(user, projectilesound, 100, 1)
if(!A) return
if (!istype(target, /turf))
qdel(A)
return
A.launch(target)
return
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
if(prob(break_stuff_probability))
for(var/dir in cardinal) // North, South, East, West
for(var/obj/structure/window/obstacle in get_step(src, dir))
if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
/mob/living/simple_animal/hostile/proc/check_horde()
return 0
if(emergency_shuttle.shuttle.location)
if(!enroute && !target_mob) //The shuttle docked, all monsters rush for the escape hallway
if(!shuttletarget && escape_list.len) //Make sure we didn't already assign it a target, and that there are targets to pick
shuttletarget = pick(escape_list) //Pick a shuttle target
enroute = 1
stop_automated_movement = 1
spawn()
if(!src.stat)
horde()
if(get_dist(src, shuttletarget) <= 2) //The monster reached the escape hallway
enroute = 0
stop_automated_movement = 0
/mob/living/simple_animal/hostile/proc/horde()
var/turf/T = get_step_to(src, shuttletarget)
for(var/atom/A in T)
if(istype(A,/obj/machinery/door/airlock))
var/obj/machinery/door/airlock/D = A
D.open(1)
else if(istype(A,/obj/structure/simple_door))
var/obj/structure/simple_door/D = A
if(D.density)
D.Open()
else if(istype(A,/obj/structure/cult/pylon))
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille))
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
Move(T)
FindTarget()
if(!target_mob || enroute)
spawn(10)
if(!src.stat)
horde()
hostile = 1
@@ -5,14 +5,14 @@
if(isliving(A))
var/mob/living/L = A
if(!L.stat)
stance = HOSTILE_STANCE_ATTACK
stance = STANCE_ATTACK
return L
else
enemies -= L
else if(istype(A, /obj/mecha))
var/obj/mecha/M = A
if(M.occupant)
stance = HOSTILE_STANCE_ATTACK
stance = STANCE_ATTACK
return A
/mob/living/simple_animal/hostile/retaliate/ListTargets()
@@ -42,7 +42,7 @@
ranged = 1
projectiletype = /obj/item/projectile/bullet
projectilesound = 'sound/weapons/Gunshot.ogg'
casingtype = /obj/item/ammo_casing/a357
casingtype = /obj/item/ammo_casing/spent
/mob/living/simple_animal/hostile/russian/death()
@@ -107,7 +107,7 @@
rapid = 1
icon_state = "syndicateranged"
icon_living = "syndicateranged"
casingtype = /obj/item/ammo_casing/a10mm
casingtype = /obj/item/ammo_casing/spent
projectilesound = 'sound/weapons/Gunshot_light.ogg'
projectiletype = /obj/item/projectile/bullet/pistol/medium
@@ -71,7 +71,7 @@
//Parrots will generally sit on their pertch unless something catches their eye.
//These vars store their preffered perch and if they dont have one, what they can use as a perch
var/obj/parrot_perch = null
var/obj/desired_perches = list(/obj/structure/computerframe, /obj/structure/displaycase, \
var/obj/desired_perches = list(/obj/structure/frame, /obj/structure/displaycase, \
/obj/structure/filingcabinet, /obj/machinery/teleport, \
/obj/machinery/computer, /obj/machinery/clonepod, \
/obj/machinery/dna_scannernew, /obj/machinery/telecomms, \
@@ -727,7 +727,7 @@
/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0)
/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0)
if(prob(50))
parrot_hear("[pick(available_channels)] [message]")
..(message,verb,language,part_a,part_b,speaker,hard_to_hear)
@@ -66,8 +66,33 @@
var/supernatural = 0
var/purge = 0
//AI stuff
var/ai_inactive = 0
//Pulling hostile mob vars down
var/stance = STANCE_IDLE //Used to determine behavior
var/mob/living/target_mob
var/attack_same = 0
var/ranged = 0
var/rapid = 0
var/projectiletype
var/projectilesound
var/casingtype
var/move_to_delay = 4 //delay for the automated movement.
var/list/friends = list()
var/break_stuff_probability = 0
var/destroy_surroundings = 0
var/shuttletarget = null
var/enroute = 0
var/ai_inactive = 0 // Set to 1 to turn off most AI actions in Life()
var/list/resistances = list(
HALLOSS = 0,
BRUTE = 1,
BURN = 1,
TOX = 1,
OXY = 0,
CLONE = 0
)
var/hostile = 0
/mob/living/simple_animal/New()
..()
@@ -75,7 +100,8 @@
/mob/living/simple_animal/Login()
if(src && src.client)
src.client.screen = null
src.client.screen = list()
src.client.screen += src.client.void
..()
/mob/living/simple_animal/updatehealth()
@@ -92,6 +118,8 @@
living_mob_list += src
stat = CONSCIOUS
density = 1
else
walk(src, 0)
return 0
@@ -108,19 +136,19 @@
handle_supernatural()
//Movement
if(!client && !ai_inactive && !stop_automated_movement && wander && !anchored)
if(!client && !stop_automated_movement && wander && !anchored && !ai_inactive)
if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
turns_since_move++
if(turns_since_move >= turns_per_move)
if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled
/var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
moving_to = pick(cardinal)
dir = moving_to //How about we turn them the direction they are moving, yay.
Move(get_step(src,moving_to))
turns_since_move = 0
//Speaking
if(!client && !ai_inactive && speak_chance)
if(!client && speak_chance)
if(rand(0,200) < speak_chance)
if(speak && speak.len)
if((emote_hear && emote_hear.len) || (emote_see && emote_see.len))
@@ -206,6 +234,23 @@
if(!atmos_suitable)
adjustBruteLoss(unsuitable_atoms_damage)
//Hostility
if(!stat && !client && hostile && !ai_inactive)
switch(stance)
if(STANCE_IDLE)
target_mob = FindTarget()
if(STANCE_ATTACK)
if(destroy_surroundings)
DestroySurroundings()
MoveToTarget()
if(STANCE_ATTACKING)
if(destroy_surroundings)
DestroySurroundings()
AttackTarget()
return 1
/mob/living/simple_animal/proc/handle_supernatural()
@@ -289,28 +334,28 @@
if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch))
harvest(user)
else
attacked_with_item(O, user)
if(!O.force)
visible_message("<span class='notice'>[user] gently taps [src] with \the [O].</span>")
else
O.attack(src, user, user.zone_sel.selecting)
//TODO: refactor mob attackby(), attacked_by(), and friends.
/mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(!O.force)
visible_message("<span class='notice'>[user] gently taps [src] with \the [O].</span>")
return
if(O.force > resistance)
var/damage = O.force
if (O.damtype == HALLOSS)
damage = 0
if(supernatural && istype(O,/obj/item/weapon/nullrod))
damage *= 2
purge = 3
adjustBruteLoss(damage)
else
usr << "<span class='danger'>This weapon is ineffective, it does no damage.</span>"
/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone)
visible_message("<span class='danger'>\The [src] has been attacked with \the [O] by [user].</span>")
user.do_attack_animation(src)
if(O.force <= resistance)
user << "<span class='danger'>This weapon is ineffective, it does no damage.</span>"
return 2
var/damage = O.force
if (O.damtype == HALLOSS)
damage = 0
if(supernatural && istype(O,/obj/item/weapon/nullrod))
damage *= 2
purge = 3
adjustBruteLoss(damage)
return 0
/mob/living/simple_animal/movement_delay()
var/tally = 0 //Incase I need to add stuff other than "speed" later
@@ -336,7 +381,7 @@
/mob/living/simple_animal/ex_act(severity)
if(!blinded)
flick("flash", flash)
flash_eyes()
switch (severity)
if (1.0)
adjustBruteLoss(500)
@@ -404,3 +449,191 @@
return
/mob/living/simple_animal/ExtinguishMob()
return
//Hostile procs moved down
/mob/living/simple_animal/proc/FindTarget()
var/atom/T = null
stop_automated_movement = 0
for(var/atom/A in ListTargets(10))
if(A == src)
continue
var/atom/F = Found(A)
if(F)
T = F
break
if(isliving(A))
var/mob/living/L = A
if(L.faction == src.faction && !attack_same)
continue
else if(L in friends)
continue
else
if(!L.stat)
stance = STANCE_ATTACK
T = L
break
else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
var/obj/mecha/M = A
if (M.occupant)
stance = STANCE_ATTACK
T = M
break
return T
/mob/living/simple_animal/proc/Found(var/atom/A)
return
/mob/living/simple_animal/proc/MoveToTarget()
stop_automated_movement = 1
if(!target_mob || SA_attackable(target_mob))
stance = STANCE_IDLE
if(target_mob in ListTargets(10))
if(ranged)
if(get_dist(src, target_mob) <= 6)
OpenFire(target_mob)
else
walk_to(src, target_mob, 1, move_to_delay)
else
stance = STANCE_ATTACKING
walk_to(src, target_mob, 1, move_to_delay)
/mob/living/simple_animal/proc/AttackTarget()
stop_automated_movement = 1
if(!target_mob || SA_attackable(target_mob))
LoseTarget()
return 0
if(!(target_mob in ListTargets(10)))
LostTarget()
return 0
if(get_dist(src, target_mob) <= 1) //Attacking
AttackingTarget()
return 1
/mob/living/simple_animal/proc/AttackingTarget()
if(!Adjacent(target_mob))
return
if(isliving(target_mob))
var/mob/living/L = target_mob
L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return L
if(istype(target_mob,/obj/mecha))
var/obj/mecha/M = target_mob
M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return M
/mob/living/simple_animal/proc/LoseTarget()
stance = STANCE_IDLE
target_mob = null
walk(src, 0)
/mob/living/simple_animal/proc/LostTarget()
stance = STANCE_IDLE
walk(src, 0)
/mob/living/simple_animal/proc/ListTargets(var/dist = 7)
var/list/L = hearers(src, dist)
for (var/obj/mecha/M in mechas_list)
if (M.z == src.z && get_dist(src, M) <= dist)
L += M
return L
/mob/living/simple_animal/proc/OpenFire(target_mob)
var/target = target_mob
visible_message("\red <b>[src]</b> fires at [target]!", 1)
var/tturf = get_turf(target)
if(rapid)
spawn(1)
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
spawn(4)
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
spawn(6)
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
else
Shoot(tturf, src.loc, src)
if(casingtype)
new casingtype
stance = STANCE_IDLE
target_mob = null
return
/mob/living/simple_animal/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
if(target == start)
return
var/obj/item/projectile/A = new projectiletype(user:loc)
playsound(user, projectilesound, 100, 1)
if(!A) return
if (!istype(target, /turf))
qdel(A)
return
A.launch(target)
return
/mob/living/simple_animal/proc/DestroySurroundings()
if(prob(break_stuff_probability))
for(var/dir in cardinal) // North, South, East, West
for(var/obj/structure/window/obstacle in get_step(src, dir))
if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
/mob/living/simple_animal/proc/check_horde()
return 0
if(emergency_shuttle.shuttle.location)
if(!enroute && !target_mob) //The shuttle docked, all monsters rush for the escape hallway
if(!shuttletarget && escape_list.len) //Make sure we didn't already assign it a target, and that there are targets to pick
shuttletarget = pick(escape_list) //Pick a shuttle target
enroute = 1
stop_automated_movement = 1
spawn()
if(!src.stat)
horde()
if(get_dist(src, shuttletarget) <= 2) //The monster reached the escape hallway
enroute = 0
stop_automated_movement = 0
/mob/living/simple_animal/proc/horde()
var/turf/T = get_step_to(src, shuttletarget)
for(var/atom/A in T)
if(istype(A,/obj/machinery/door/airlock))
var/obj/machinery/door/airlock/D = A
D.open(1)
else if(istype(A,/obj/structure/simple_door))
var/obj/structure/simple_door/D = A
if(D.density)
D.Open()
else if(istype(A,/obj/structure/cult/pylon))
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille))
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper))
Move(T)
FindTarget()
if(!target_mob || enroute)
spawn(10)
if(!src.stat)
horde()
+10 -9
View File
@@ -33,7 +33,7 @@
var/datum/preferences/p = speaker.client.prefs
name = p.real_name
real_name = name
gender = p.gender
gender = p.identifying_gender
for(var/language in p.alternate_languages)
add_language(language)
@@ -42,12 +42,9 @@
// Parameters: None
// Description: Adds a static overlay to the client's screen.
/mob/living/voice/Login()
var/obj/screen/static_effect = new() //Since what the player sees is essentially a video feed, from a vast distance away, the view isn't going to be perfect.
static_effect.screen_loc = ui_entire_screen
static_effect.icon = 'icons/effects/static.dmi'
static_effect.icon_state = "1 light"
static_effect.mouse_opacity = 0 //So the static doesn't get in the way of clicking.
client.screen.Add(static_effect)
..()
client.screen |= global_hud.whitense
client.screen |= global_hud.darkMask
// Proc: Destroy()
// Parameters: None
@@ -110,7 +107,7 @@
// Proc: say()
// Parameters: 4 (generic say() arguments)
// Description: Adds a speech bubble to the communicator device, then calls ..() to do the real work.
/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="")
/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering=0)
//Speech bubbles.
if(comm)
var/speech_bubble_test = say_test(message)
@@ -122,4 +119,8 @@
M << speech_bubble
src << speech_bubble
..(message, speaking, verb, alt_name) //mob/living/say() can do the actual talking.
..(message, speaking, verb, alt_name, whispering) //mob/living/say() can do the actual talking.
/mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
if(!comm) return
..(m_type,message,comm.video_range)