mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 20:16:55 +01:00
Ports tg simple_animal bots
This commit is contained in:
@@ -135,7 +135,7 @@
|
||||
dat += "<a href='?src=\ref[src];screen=1'>Back</a>"
|
||||
dat += "<br><b>Medical Robots:</b>"
|
||||
var/bdat = null
|
||||
for(var/obj/machinery/bot/medbot/M in world)
|
||||
for(var/mob/living/simple_animal/bot/medbot/M in world)
|
||||
|
||||
if(M.z != computer.z) continue //only find medibots on the same z-level as the computer
|
||||
var/turf/bl = get_turf(M)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
/datum/table_recipe/ed209
|
||||
name = "ED209"
|
||||
result = /obj/machinery/bot/ed209
|
||||
result = /mob/living/simple_animal/bot/ed209
|
||||
reqs = list(/obj/item/robot_parts/robot_suit = 1,
|
||||
/obj/item/clothing/head/helmet = 1,
|
||||
/obj/item/clothing/suit/armor/vest = 1,
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
/datum/table_recipe/secbot
|
||||
name = "Secbot"
|
||||
result = /obj/machinery/bot/secbot
|
||||
result = /mob/living/simple_animal/bot/secbot
|
||||
reqs = list(/obj/item/device/assembly/signaler = 1,
|
||||
/obj/item/clothing/head/helmet = 1,
|
||||
/obj/item/weapon/melee/baton = 1,
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
/datum/table_recipe/cleanbot
|
||||
name = "Cleanbot"
|
||||
result = /obj/machinery/bot/cleanbot
|
||||
result = /mob/living/simple_animal/bot/cleanbot
|
||||
reqs = list(/obj/item/weapon/reagent_containers/glass/bucket = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 1,
|
||||
/obj/item/robot_parts/r_arm = 1)
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
/datum/table_recipe/floorbot
|
||||
name = "Floorbot"
|
||||
result = /obj/machinery/bot/floorbot
|
||||
result = /mob/living/simple_animal/bot/floorbot
|
||||
reqs = list(/obj/item/weapon/storage/toolbox/mechanical = 1,
|
||||
/obj/item/stack/tile/plasteel = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 1,
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
/datum/table_recipe/medbot
|
||||
name = "Medbot"
|
||||
result = /obj/machinery/bot/medbot
|
||||
result = /mob/living/simple_animal/bot/medbot
|
||||
reqs = list(/obj/item/device/healthanalyzer = 1,
|
||||
/obj/item/weapon/storage/firstaid = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 1,
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
M << "<br>"
|
||||
|
||||
if(botEmagChance)
|
||||
for(var/obj/machinery/bot/bot in machines)
|
||||
for(var/mob/living/simple_animal/bot/bot in machines)
|
||||
if(prob(botEmagChance))
|
||||
bot.Emag()
|
||||
bot.emag_act()
|
||||
|
||||
/proc/generate_ion_law(ionMessage)
|
||||
if(ionMessage)
|
||||
|
||||
@@ -693,14 +693,7 @@
|
||||
mouse_opacity = 1
|
||||
faction = list("neutral")
|
||||
a_intent = I_HARM
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
wander = 0
|
||||
idle_vision_range = 5
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
message = stars(message)
|
||||
|
||||
var/speaker_name = "unknown"
|
||||
if(speaker)
|
||||
if(speaker)
|
||||
speaker_name = speaker.name
|
||||
|
||||
if(vname)
|
||||
@@ -160,7 +160,7 @@
|
||||
else
|
||||
track = "[speaker_name] ([jobname])"
|
||||
else
|
||||
if(istype(follow_target, /obj/machinery/bot))
|
||||
if(istype(follow_target, /mob/living/simple_animal/bot))
|
||||
track = "<a href='byond://?src=\ref[src];trackbot=\ref[follow_target]'>[speaker_name] ([jobname])</a>"
|
||||
else
|
||||
track = "<a href='byond://?src=\ref[src];track=\ref[speaker]'>[speaker_name] ([jobname])</a>"
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
usr.hud_used.nightvisionicon.icon_state = "nightvision0"
|
||||
|
||||
|
||||
/mob/living/carbon/alien/assess_threat(var/obj/machinery/bot/secbot/judgebot, var/lasercolor)
|
||||
/mob/living/carbon/alien/assess_threat(var/mob/living/simple_animal/bot/secbot/judgebot, var/lasercolor)
|
||||
if(judgebot.emagged == 2)
|
||||
return 10 //Everyone is a criminal!
|
||||
var/threatcount = 0
|
||||
|
||||
@@ -636,8 +636,8 @@
|
||||
// called when something steps onto a human
|
||||
// this handles mulebots and vehicles
|
||||
/mob/living/carbon/human/Crossed(var/atom/movable/AM)
|
||||
if(istype(AM, /obj/machinery/bot/mulebot))
|
||||
var/obj/machinery/bot/mulebot/MB = AM
|
||||
if(istype(AM, /mob/living/simple_animal/bot/mulebot))
|
||||
var/mob/living/simple_animal/bot/mulebot/MB = AM
|
||||
MB.RunOver(src)
|
||||
|
||||
if(istype(AM, /obj/vehicle))
|
||||
@@ -1753,7 +1753,7 @@
|
||||
if(M.stat == 2)
|
||||
M.gib()
|
||||
|
||||
/mob/living/carbon/human/assess_threat(var/obj/machinery/bot/secbot/judgebot, var/lasercolor)
|
||||
/mob/living/carbon/human/assess_threat(var/mob/living/simple_animal/bot/secbot/judgebot, var/lasercolor)
|
||||
if(judgebot.emagged == 2)
|
||||
return 10 //Everyone is a criminal!
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ var/list/ai_verbs_default = list(
|
||||
anchored = 1 // -- TLE
|
||||
density = 1
|
||||
status_flags = CANSTUN|CANPARALYSE|CANPUSH
|
||||
can_strip = 0
|
||||
var/list/network = list("SS13","Telecomms","Research Outpost","Mining Outpost")
|
||||
var/obj/machinery/camera/current = null
|
||||
var/list/connected_robots = list()
|
||||
@@ -80,7 +81,7 @@ var/list/ai_verbs_default = list(
|
||||
var/can_shunt = 1
|
||||
var/last_announcement = ""
|
||||
var/datum/announcement/priority/announcement
|
||||
var/obj/machinery/bot/Bot
|
||||
var/mob/living/simple_animal/bot/Bot
|
||||
var/turf/waypoint //Holds the turf of the currently selected waypoint.
|
||||
var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
|
||||
|
||||
@@ -513,7 +514,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if (href_list["trackbot"])
|
||||
var/obj/machinery/bot/target = locate(href_list["trackbot"]) in aibots
|
||||
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in simple_animal_list
|
||||
if(target)
|
||||
ai_actual_track(target)
|
||||
else
|
||||
@@ -521,7 +522,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if (href_list["callbot"]) //Command a bot to move to a selected location.
|
||||
Bot = locate(href_list["callbot"]) in aibots
|
||||
Bot = locate(href_list["callbot"]) in simple_animal_list
|
||||
if(!Bot || Bot.remote_disabled || src.control_disabled)
|
||||
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
|
||||
waypoint_mode = 1
|
||||
@@ -529,7 +530,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if (href_list["interface"]) //Remotely connect to a bot!
|
||||
Bot = locate(href_list["interface"]) in aibots
|
||||
Bot = locate(href_list["interface"]) in simple_animal_list
|
||||
if(!Bot || Bot.remote_disabled || src.control_disabled)
|
||||
return
|
||||
Bot.attack_ai(src)
|
||||
@@ -643,10 +644,10 @@ var/list/ai_verbs_default = list(
|
||||
d += "<A HREF=?src=\ref[src];botrefresh=\ref[Bot]>Query network status</A><br>"
|
||||
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='20%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
|
||||
|
||||
for (Bot in aibots)
|
||||
for (var/mob/living/simple_animal/bot/Bot in simple_animal_list)
|
||||
if((Bot.z in ai_allowed_Zlevel) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected!
|
||||
bot_area = get_area(Bot)
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name] ([Bot.bot_type_name])</td>"
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name] ([Bot.model])</td>"
|
||||
//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
|
||||
d += "<td width='20%'>[Bot.on ? "[Bot.mode ? "<span class='average'>[ Bot.mode_name[Bot.mode] ]</span>": "<span class='good'>Idle</span>"]" : "<span class='bad'>Inactive</span>"]</td>"
|
||||
d += "<td width='30%'>[bot_area.name]</td>"
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
var/obj/machinery/portable_atmospherics/hydroponics/my_hydrotray
|
||||
|
||||
// Allow final solutions.
|
||||
min_oxy = 5
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 1
|
||||
min_co2 = 0
|
||||
max_co2 = 5
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 360
|
||||
|
||||
@@ -37,145 +29,143 @@
|
||||
parent.owned_bee_swarms.Remove(src)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bee/Life()
|
||||
..()
|
||||
/mob/living/simple_animal/bee/process_ai()
|
||||
//if we're strong enough, sting some people
|
||||
var/mob/living/carbon/human/M = target_mob
|
||||
var/sting_prob = 100 // Bees will always try to sting.
|
||||
if(M in view(src,1)) // Can I see my target?
|
||||
if(prob(max(feral * 10, 0))) // Am I mad enough to want to sting? And yes, when I initially appear, I AM mad enough
|
||||
var/obj/item/clothing/worn_suit = M.wear_suit
|
||||
var/obj/item/clothing/worn_helmet = M.head
|
||||
if(worn_suit) // Are you wearing clothes?
|
||||
sting_prob -= min(worn_suit.armor["bio"],70) // Is it sealed? I can't get to 70% of your body.
|
||||
if(worn_helmet)
|
||||
sting_prob -= min(worn_helmet.armor["bio"],30) // Is your helmet sealed? I can't get to 30% of your body.
|
||||
if( prob(sting_prob) && (M.stat == CONSCIOUS || (M.stat == UNCONSCIOUS && prob(25))) ) // Try to sting! If you're not moving, think about stinging.
|
||||
M.apply_damage(min(strength,2)+mut, BRUTE, sharp=1) // Stinging. The more mutated I am, the harder I sting.
|
||||
M.apply_damage((round(feral/10,1)*(max((round(strength/20,1)),1)))+toxic, TOX) // Bee venom based on how angry I am and how many there are of me!
|
||||
M << "\red You have been stung!"
|
||||
|
||||
if(stat == CONSCIOUS)
|
||||
//if we're strong enough, sting some people
|
||||
var/mob/living/carbon/human/M = target_mob
|
||||
var/sting_prob = 100 // Bees will always try to sting.
|
||||
if(M in view(src,1)) // Can I see my target?
|
||||
if(prob(max(feral * 10, 0))) // Am I mad enough to want to sting? And yes, when I initially appear, I AM mad enough
|
||||
var/obj/item/clothing/worn_suit = M.wear_suit
|
||||
var/obj/item/clothing/worn_helmet = M.head
|
||||
if(worn_suit) // Are you wearing clothes?
|
||||
sting_prob -= min(worn_suit.armor["bio"],70) // Is it sealed? I can't get to 70% of your body.
|
||||
if(worn_helmet)
|
||||
sting_prob -= min(worn_helmet.armor["bio"],30) // Is your helmet sealed? I can't get to 30% of your body.
|
||||
if( prob(sting_prob) && (M.stat == CONSCIOUS || (M.stat == UNCONSCIOUS && prob(25))) ) // Try to sting! If you're not moving, think about stinging.
|
||||
M.apply_damage(min(strength,2)+mut, BRUTE, sharp=1) // Stinging. The more mutated I am, the harder I sting.
|
||||
M.apply_damage((round(feral/10,1)*(max((round(strength/20,1)),1)))+toxic, TOX) // Bee venom based on how angry I am and how many there are of me!
|
||||
M << "\red You have been stung!"
|
||||
M.flash_pain()
|
||||
//if we're chasing someone, get a little bit angry
|
||||
if(target_mob && prob(10))
|
||||
feral++
|
||||
M.flash_pain()
|
||||
|
||||
//if we're chasing someone, get a little bit angry
|
||||
if(target_mob && prob(10))
|
||||
feral++
|
||||
|
||||
//calm down a little bit
|
||||
if(feral > 0)
|
||||
if(prob(feral * 10))
|
||||
feral -= 1
|
||||
else
|
||||
//if feral is less than 0, we're becalmed by smoke or steam
|
||||
if(feral < 0)
|
||||
feral += 1
|
||||
|
||||
if(target_mob)
|
||||
target_mob = null
|
||||
target_turf = null
|
||||
if(strength > 5)
|
||||
//calm down and spread out a little
|
||||
var/mob/living/simple_animal/bee/B = new(get_turf(pick(orange(src,1))))
|
||||
B.strength = rand(1,5)
|
||||
src.strength -= B.strength
|
||||
if(src.strength <= 5)
|
||||
src.icon_living = "bees[src.strength]"
|
||||
B.icon_living = "bees[B.strength]"
|
||||
if(src.parent)
|
||||
B.parent = src.parent
|
||||
src.parent.owned_bee_swarms.Add(B)
|
||||
|
||||
//make some noise
|
||||
if(prob(0.5))
|
||||
src.visible_message("\blue [pick("Buzzzz.","Hmmmmm.","Bzzz.")]")
|
||||
|
||||
//smoke, water and steam calms us down
|
||||
var/calming = 0
|
||||
var/list/calmers = list(/obj/effect/effect/chem_smoke, \
|
||||
/obj/effect/effect/water, \
|
||||
/obj/effect/effect/foam, \
|
||||
/obj/effect/effect/steam, \
|
||||
/obj/effect/mist)
|
||||
|
||||
for(var/obj/effect/check_effect in src.loc)
|
||||
if(check_effect.type in calmers)
|
||||
calming = 1
|
||||
break
|
||||
|
||||
if(calming)
|
||||
if(feral > 0)
|
||||
src.visible_message("\blue The bees calm down!")
|
||||
feral = -10
|
||||
target_mob = null
|
||||
target_turf = null
|
||||
wander = 1
|
||||
|
||||
for(var/mob/living/simple_animal/bee/B in src.loc)
|
||||
if(B == src)
|
||||
continue
|
||||
|
||||
if(feral > 0)
|
||||
src.strength += B.strength
|
||||
qdel(B)
|
||||
src.icon_living = "bees[src.strength]"
|
||||
if(strength > 5)
|
||||
icon_living = "bees_swarm"
|
||||
else if(prob(10))
|
||||
//make the other swarm of bees stronger, then move away
|
||||
var/total_bees = B.strength + src.strength
|
||||
if(total_bees < 10)
|
||||
B.strength = min(5, total_bees)
|
||||
src.strength = total_bees - B.strength
|
||||
|
||||
B.icon_living = "bees[B.strength]"
|
||||
if(src.strength <= 0)
|
||||
qdel(src)
|
||||
return
|
||||
src.icon_living = "bees[B.strength]"
|
||||
var/turf/simulated/floor/T = get_turf(get_step(src, pick(1,2,4,8)))
|
||||
density = 1
|
||||
if(T.Enter(src, get_turf(src)))
|
||||
src.loc = T
|
||||
density = 0
|
||||
break
|
||||
//calm down a little bit
|
||||
if(feral > 0)
|
||||
if(prob(feral * 10))
|
||||
feral -= 1
|
||||
else
|
||||
//if feral is less than 0, we're becalmed by smoke or steam
|
||||
if(feral < 0)
|
||||
feral += 1
|
||||
|
||||
if(target_mob)
|
||||
if(target_mob in view(src,7))
|
||||
target_turf = get_turf(target_mob)
|
||||
wander = 0
|
||||
target_mob = null
|
||||
target_turf = null
|
||||
if(strength > 5)
|
||||
//calm down and spread out a little
|
||||
var/mob/living/simple_animal/bee/B = new(get_turf(pick(orange(src,1))))
|
||||
B.strength = rand(1,5)
|
||||
src.strength -= B.strength
|
||||
if(src.strength <= 5)
|
||||
src.icon_living = "bees[src.strength]"
|
||||
B.icon_living = "bees[B.strength]"
|
||||
if(src.parent)
|
||||
B.parent = src.parent
|
||||
src.parent.owned_bee_swarms.Add(B)
|
||||
|
||||
else // My target's gone! But I might still be pissed! You there. You look like a good stinging target!
|
||||
for(var/mob/living/carbon/G in view(src,7))
|
||||
target_mob = G
|
||||
break
|
||||
//make some noise
|
||||
if(prob(0.5))
|
||||
src.visible_message("\blue [pick("Buzzzz.","Hmmmmm.","Bzzz.")]")
|
||||
|
||||
if(target_turf)
|
||||
if (!(DirBlocked(get_step(src, get_dir(src,target_turf)),get_dir(src,target_turf)))) // Check for windows and doors!
|
||||
Move(get_step(src, get_dir(src,target_turf)))
|
||||
if (prob(0.1))
|
||||
src.visible_message("\blue The bees swarm after [target_mob]!")
|
||||
if(src.loc == target_turf)
|
||||
target_turf = null
|
||||
wander = 1
|
||||
else
|
||||
//find some flowers, harvest
|
||||
//angry bee swarms don't hang around
|
||||
if(feral > 0)
|
||||
turns_per_move = rand(1,3)
|
||||
else if(feral < 0)
|
||||
turns_since_move = 0
|
||||
else if(!my_hydrotray || my_hydrotray.loc != src.loc || my_hydrotray.dead || !my_hydrotray.seed)
|
||||
var/obj/machinery/portable_atmospherics/hydroponics/my_hydrotray = locate() in src.loc
|
||||
if(my_hydrotray)
|
||||
if(!my_hydrotray.dead && my_hydrotray.seed)
|
||||
turns_per_move = rand(20,50)
|
||||
else
|
||||
my_hydrotray = null
|
||||
//smoke, water and steam calms us down
|
||||
var/calming = 0
|
||||
var/list/calmers = list(/obj/effect/effect/chem_smoke, \
|
||||
/obj/effect/effect/water, \
|
||||
/obj/effect/effect/foam, \
|
||||
/obj/effect/effect/steam, \
|
||||
/obj/effect/mist)
|
||||
|
||||
pixel_x = rand(-12,12)
|
||||
pixel_y = rand(-12,12)
|
||||
for(var/obj/effect/check_effect in src.loc)
|
||||
if(check_effect.type in calmers)
|
||||
calming = 1
|
||||
break
|
||||
|
||||
if(calming)
|
||||
if(feral > 0)
|
||||
src.visible_message("\blue The bees calm down!")
|
||||
feral = -10
|
||||
target_mob = null
|
||||
target_turf = null
|
||||
wander = 1
|
||||
|
||||
for(var/mob/living/simple_animal/bee/B in src.loc)
|
||||
if(B == src)
|
||||
continue
|
||||
|
||||
if(feral > 0)
|
||||
src.strength += B.strength
|
||||
qdel(B)
|
||||
src.icon_living = "bees[src.strength]"
|
||||
if(strength > 5)
|
||||
icon_living = "bees_swarm"
|
||||
else if(prob(10))
|
||||
//make the other swarm of bees stronger, then move away
|
||||
var/total_bees = B.strength + src.strength
|
||||
if(total_bees < 10)
|
||||
B.strength = min(5, total_bees)
|
||||
src.strength = total_bees - B.strength
|
||||
|
||||
B.icon_living = "bees[B.strength]"
|
||||
if(src.strength <= 0)
|
||||
qdel(src)
|
||||
return
|
||||
src.icon_living = "bees[B.strength]"
|
||||
var/turf/simulated/floor/T = get_turf(get_step(src, pick(1,2,4,8)))
|
||||
density = 1
|
||||
if(T.Enter(src, get_turf(src)))
|
||||
src.loc = T
|
||||
density = 0
|
||||
break
|
||||
|
||||
if(target_mob)
|
||||
if(target_mob in view(src,7))
|
||||
target_turf = get_turf(target_mob)
|
||||
wander = 0
|
||||
|
||||
else // My target's gone! But I might still be pissed! You there. You look like a good stinging target!
|
||||
for(var/mob/living/carbon/G in view(src,7))
|
||||
target_mob = G
|
||||
break
|
||||
|
||||
if(target_turf)
|
||||
if (!(DirBlocked(get_step(src, get_dir(src,target_turf)),get_dir(src,target_turf)))) // Check for windows and doors!
|
||||
Move(get_step(src, get_dir(src,target_turf)))
|
||||
if (prob(0.1))
|
||||
src.visible_message("\blue The bees swarm after [target_mob]!")
|
||||
if(src.loc == target_turf)
|
||||
target_turf = null
|
||||
wander = 1
|
||||
else
|
||||
//find some flowers, harvest
|
||||
//angry bee swarms don't hang around
|
||||
if(feral > 0)
|
||||
turns_per_move = rand(1,3)
|
||||
else if(feral < 0)
|
||||
turns_since_move = 0
|
||||
else if(!my_hydrotray || my_hydrotray.loc != src.loc || my_hydrotray.dead || !my_hydrotray.seed)
|
||||
var/obj/machinery/portable_atmospherics/hydroponics/my_hydrotray = locate() in src.loc
|
||||
if(my_hydrotray)
|
||||
if(!my_hydrotray.dead && my_hydrotray.seed)
|
||||
turns_per_move = rand(20,50)
|
||||
else
|
||||
my_hydrotray = null
|
||||
|
||||
pixel_x = rand(-12,12)
|
||||
pixel_y = rand(-12,12)
|
||||
|
||||
/mob/living/simple_animal/bee/handle_state_icons()
|
||||
if(!parent && prob(10))
|
||||
strength -= 1
|
||||
if(strength <= 0)
|
||||
@@ -187,3 +177,5 @@
|
||||
/*icon_living = "[strength]"
|
||||
if(strength > 5)
|
||||
icon_living = "unknown"*/
|
||||
|
||||
..()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,227 @@
|
||||
//Cleanbot
|
||||
/mob/living/simple_animal/bot/cleanbot
|
||||
name = "\improper Cleanbot"
|
||||
desc = "A little cleaning robot, he looks so excited!"
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "cleanbot0"
|
||||
density = 0
|
||||
anchored = 0
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
radio_channel = "Service" //Service
|
||||
bot_filter = RADIO_CLEANBOT
|
||||
bot_type = CLEAN_BOT
|
||||
model = "Cleanbot"
|
||||
bot_purpose = "seek out messes and clean them"
|
||||
bot_core_type = /obj/machinery/bot_core/cleanbot
|
||||
window_id = "autoclean"
|
||||
window_name = "Automatic Station Cleaner v1.1"
|
||||
pass_flags = PASSMOB
|
||||
|
||||
var/blood = 1
|
||||
var/list/target_types = list()
|
||||
var/obj/effect/decal/cleanable/target
|
||||
var/max_targets = 50 //Maximum number of targets a cleanbot can ignore.
|
||||
var/oldloc = null
|
||||
var/closest_dist
|
||||
var/closest_loc
|
||||
var/failed_steps
|
||||
var/next_dest
|
||||
var/next_dest_loc
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/New()
|
||||
..()
|
||||
get_targets()
|
||||
icon_state = "cleanbot[on]"
|
||||
|
||||
var/datum/job/janitor/J = new/datum/job/janitor
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/turn_on()
|
||||
..()
|
||||
icon_state = "cleanbot[on]"
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/turn_off()
|
||||
..()
|
||||
icon_state = "cleanbot[on]"
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/bot_reset()
|
||||
..()
|
||||
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
|
||||
target = null
|
||||
oldloc = null
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/set_custom_texts()
|
||||
text_hack = "You corrupt [name]'s cleaning software."
|
||||
text_dehack = "[name]'s software has been reset!"
|
||||
text_dehack_fail = "[name] does not seem to respond to your repair code!"
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
|
||||
if(bot_core.allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>You [ locked ? "lock" : "unlock"] \the [src] behaviour controls.</span>"
|
||||
else
|
||||
if(emagged)
|
||||
user << "<span class='warning'>ERROR</span>"
|
||||
if(open)
|
||||
user << "<span class='warning'>Please close the access panel before locking it.</span>"
|
||||
else
|
||||
user << "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'>[src] buzzes and beeps.</span>"
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/process_scan(obj/effect/decal/cleanable/D)
|
||||
for(var/T in target_types)
|
||||
if(istype(D, T))
|
||||
return D
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
if(mode == BOT_CLEANING)
|
||||
return
|
||||
|
||||
if(emagged == 2) //Emag functions
|
||||
if(istype(loc,/turf/simulated))
|
||||
if(prob(10)) //Wets floors randomly
|
||||
var/turf/simulated/T = loc
|
||||
T.MakeSlippery()
|
||||
|
||||
if(prob(5)) //Spawns foam!
|
||||
visible_message("<span class='danger'>[src] whirs and bubbles violently, before releasing a plume of froth!</span>")
|
||||
new /obj/effect/effect/foam(loc)
|
||||
|
||||
else if(prob(5))
|
||||
audible_message("[src] makes an excited beeping booping sound!")
|
||||
|
||||
if(!target) //Search for cleanables it can see.
|
||||
target = scan(/obj/effect/decal/cleanable/)
|
||||
|
||||
if(!target && auto_patrol) //Search for cleanables it can see.
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
if(target)
|
||||
if(!path || path.len == 0) //No path, need a new one
|
||||
//Try to produce a path to the target, and ignore airlocks to which it has access.
|
||||
path = get_path_to(src, target.loc, /turf/proc/Distance_cardinal, 0, 30, id=access_card)
|
||||
if(!bot_move(target))
|
||||
add_to_ignore(target)
|
||||
target = null
|
||||
path = list()
|
||||
return
|
||||
mode = BOT_MOVING
|
||||
else if(!bot_move(target))
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
|
||||
if(target && loc == target.loc)
|
||||
clean(target)
|
||||
path = list()
|
||||
target = null
|
||||
|
||||
oldloc = loc
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/get_targets()
|
||||
target_types = new/list()
|
||||
|
||||
target_types += /obj/effect/decal/cleanable/blood/oil
|
||||
target_types += /obj/effect/decal/cleanable/vomit
|
||||
target_types += /obj/effect/decal/cleanable/poop
|
||||
target_types += /obj/effect/decal/cleanable/blood/gibs/robot
|
||||
target_types += /obj/effect/decal/cleanable/crayon
|
||||
target_types += /obj/effect/decal/cleanable/liquid_fuel
|
||||
target_types += /obj/effect/decal/cleanable/molten_item
|
||||
target_types += /obj/effect/decal/cleanable/tomato_smudge
|
||||
target_types += /obj/effect/decal/cleanable/egg_smudge
|
||||
target_types += /obj/effect/decal/cleanable/pie_smudge
|
||||
target_types += /obj/effect/decal/cleanable/flour
|
||||
target_types += /obj/effect/decal/cleanable/ash
|
||||
target_types += /obj/effect/decal/cleanable/greenglow
|
||||
target_types += /obj/effect/decal/cleanable/dirt
|
||||
target_types += /obj/effect/decal/cleanable/mucus
|
||||
|
||||
if(blood)
|
||||
target_types += /obj/effect/decal/cleanable/blood/xeno/
|
||||
target_types += /obj/effect/decal/cleanable/blood/gibs/xeno
|
||||
target_types += /obj/effect/decal/cleanable/blood/
|
||||
target_types += /obj/effect/decal/cleanable/blood/gibs/
|
||||
target_types += /obj/effect/decal/cleanable/blood/tracks
|
||||
target_types += /obj/effect/decal/cleanable/dirt
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/clean(obj/effect/decal/cleanable/target)
|
||||
anchored = 1
|
||||
icon_state = "cleanbot-c"
|
||||
visible_message("<span class='notice'>[src] begins to clean up [target]</span>")
|
||||
mode = BOT_CLEANING
|
||||
spawn(50)
|
||||
if(mode == BOT_CLEANING)
|
||||
qdel(target)
|
||||
anchored = 0
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
icon_state = "cleanbot[on]"
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/explode()
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
|
||||
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/robot_parts/l_arm(Tsec)
|
||||
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/cleanbot
|
||||
req_one_access = list(access_janitor, access_robotics)
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += text({"
|
||||
<TT><B>Cleaner v1.1 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
text("<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>"))
|
||||
if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user))
|
||||
dat += text({"<BR>Cleans Blood: []<BR>"}, text("<A href='?src=\ref[src];operation=blood'>[blood ? "Yes" : "No"]</A>"))
|
||||
dat += text({"<BR>Patrol station: []<BR>"}, text("<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A>"))
|
||||
return dat
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
switch(href_list["operation"])
|
||||
if("blood")
|
||||
blood =!blood
|
||||
get_targets()
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
|
||||
if(istype(A,/obj/effect/decal/cleanable))
|
||||
clean(A)
|
||||
else
|
||||
..()
|
||||
@@ -0,0 +1,480 @@
|
||||
//Bot Construction
|
||||
|
||||
//Cleanbot assembly
|
||||
/obj/item/weapon/bucket_sensor
|
||||
desc = "It's a bucket. With a sensor attached."
|
||||
name = "proxy bucket"
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "bucket_proxy"
|
||||
force = 3
|
||||
throwforce = 5
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = 3
|
||||
var/created_name = "Cleanbot"
|
||||
|
||||
/obj/item/weapon/bucket_sensor/attackby(obj/item/W, mob/user as mob, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
qdel(W)
|
||||
var/turf/T = get_turf(loc)
|
||||
var/mob/living/simple_animal/bot/cleanbot/A = new /mob/living/simple_animal/bot/cleanbot(T)
|
||||
A.name = created_name
|
||||
user << "<span class='notice'>You add the robot arm to the bucket and sensor assembly. Beep boop!</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
else if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
|
||||
//Edbot Assembly
|
||||
|
||||
/obj/item/weapon/ed209_assembly
|
||||
name = "\improper ED-209 assembly"
|
||||
desc = "Some sort of bizarre assembly."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "ed209_frame"
|
||||
item_state = "ed209_frame"
|
||||
var/build_step = 0
|
||||
var/created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess
|
||||
var/lasercolor = ""
|
||||
|
||||
/obj/item/weapon/ed209_assembly/attackby(obj/item/weapon/W, mob/user, params)
|
||||
..()
|
||||
|
||||
if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
return
|
||||
|
||||
switch(build_step)
|
||||
if(0,1)
|
||||
if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the robot leg to [src].</span>"
|
||||
name = "legs/frame assembly"
|
||||
if(build_step == 1)
|
||||
item_state = "ed209_leg"
|
||||
icon_state = "ed209_leg"
|
||||
else
|
||||
item_state = "ed209_legs"
|
||||
icon_state = "ed209_legs"
|
||||
|
||||
if(2)
|
||||
var/newcolor = ""
|
||||
if(istype(W, /obj/item/clothing/suit/redtag))
|
||||
newcolor = "r"
|
||||
else if(istype(W, /obj/item/clothing/suit/bluetag))
|
||||
newcolor = "b"
|
||||
if(newcolor || istype(W, /obj/item/clothing/suit/armor/vest))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
lasercolor = newcolor
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the armor to [src].</span>"
|
||||
name = "vest/legs/frame assembly"
|
||||
item_state = "[lasercolor]ed209_shell"
|
||||
icon_state = "[lasercolor]ed209_shell"
|
||||
|
||||
if(3)
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.remove_fuel(0,user))
|
||||
build_step++
|
||||
name = "shielded frame assembly"
|
||||
user << "<span class='notice'>You weld the vest to [src].</span>"
|
||||
if(4)
|
||||
switch(lasercolor)
|
||||
if("b")
|
||||
if(!istype(W, /obj/item/clothing/head/helmet/bluetaghelm))
|
||||
return
|
||||
|
||||
if("r")
|
||||
if(!istype(W, /obj/item/clothing/head/helmet/redtaghelm))
|
||||
return
|
||||
|
||||
if("")
|
||||
if(!istype(W, /obj/item/clothing/head/helmet))
|
||||
return
|
||||
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the helmet to [src].</span>"
|
||||
name = "covered and shielded frame assembly"
|
||||
item_state = "[lasercolor]ed209_hat"
|
||||
icon_state = "[lasercolor]ed209_hat"
|
||||
|
||||
if(5)
|
||||
if(isprox(W))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the prox sensor to [src].</span>"
|
||||
name = "covered, shielded and sensored frame assembly"
|
||||
item_state = "[lasercolor]ed209_prox"
|
||||
icon_state = "[lasercolor]ed209_prox"
|
||||
|
||||
if(6)
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
if(coil.get_amount() < 1)
|
||||
user << "<span class='warning'>You need one length of cable to wire the ED-209!</span>"
|
||||
return
|
||||
user << "<span class='notice'>You start to wire [src]...</span>"
|
||||
if(do_after(user, 40, target = src))
|
||||
if(coil.get_amount() >= 1 && build_step == 6)
|
||||
coil.use(1)
|
||||
build_step = 7
|
||||
user << "<span class='notice'>You wire the ED-209 assembly.</span>"
|
||||
name = "wired ED-209 assembly"
|
||||
|
||||
if(7)
|
||||
var/newname = ""
|
||||
switch(lasercolor)
|
||||
if("b")
|
||||
if(!istype(W, /obj/item/weapon/gun/energy/laser/bluetag))
|
||||
return
|
||||
newname = "bluetag ED-209 assembly"
|
||||
if("r")
|
||||
if(!istype(W, /obj/item/weapon/gun/energy/laser/redtag))
|
||||
return
|
||||
newname = "redtag ED-209 assembly"
|
||||
if("")
|
||||
if(!istype(W, /obj/item/weapon/gun/energy/advtaser))
|
||||
return
|
||||
newname = "taser ED-209 assembly"
|
||||
else
|
||||
return
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
name = newname
|
||||
build_step++
|
||||
user << "<span class='notice'>You add [W] to [src].</span>"
|
||||
item_state = "[lasercolor]ed209_taser"
|
||||
icon_state = "[lasercolor]ed209_taser"
|
||||
qdel(W)
|
||||
|
||||
if(8)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
|
||||
user << "<span class='notice'>You start attaching the gun to the frame...</span>"
|
||||
if(do_after(user, 40, target = src))
|
||||
build_step++
|
||||
name = "armed [name]"
|
||||
user << "<span class='notice'>Taser gun attached.</span>"
|
||||
|
||||
if(9)
|
||||
if(istype(W, /obj/item/weapon/stock_parts/cell))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
build_step++
|
||||
user << "<span class='notice'>You complete the ED-209.</span>"
|
||||
var/turf/T = get_turf(src)
|
||||
new /mob/living/simple_animal/bot/ed209(T,created_name,lasercolor)
|
||||
qdel(W)
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
//Floorbot assemblies
|
||||
/obj/item/weapon/toolbox_tiles
|
||||
desc = "It's a toolbox with tiles sticking out the top"
|
||||
name = "tiles and toolbox"
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "toolbox_tiles"
|
||||
force = 3
|
||||
throwforce = 10
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = 3
|
||||
var/created_name = "Floorbot"
|
||||
|
||||
/obj/item/weapon/toolbox_tiles_sensor
|
||||
desc = "It's a toolbox with tiles sticking out the top and a sensor attached"
|
||||
name = "tiles, toolbox and sensor arrangement"
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "toolbox_tiles_sensor"
|
||||
force = 3
|
||||
throwforce = 10
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = 3
|
||||
var/created_name = "Floorbot"
|
||||
|
||||
/obj/item/weapon/storage/toolbox/mechanical/attackby(obj/item/stack/tile/plasteel/T, mob/user, params)
|
||||
if(!istype(T, /obj/item/stack/tile/plasteel))
|
||||
..()
|
||||
return
|
||||
if(contents.len >= 1)
|
||||
user << "<span class='warning'>They won't fit in, as there is already stuff inside.</span>"
|
||||
return
|
||||
if(T.use(10))
|
||||
if(user.s_active)
|
||||
user.s_active.close(user)
|
||||
var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles
|
||||
user.put_in_hands(B)
|
||||
user << "<span class='notice'>You add the tiles into the empty toolbox. They protrude from the top.</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='warning'>You need 10 floor tiles to start building a floorbot.</span>"
|
||||
return
|
||||
|
||||
/obj/item/weapon/toolbox_tiles/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(isprox(W))
|
||||
qdel(W)
|
||||
var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor()
|
||||
B.created_name = created_name
|
||||
user.put_in_hands(B)
|
||||
user << "<span class='notice'>You add the sensor to the toolbox and tiles.</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
else if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
|
||||
created_name = t
|
||||
|
||||
/obj/item/weapon/toolbox_tiles_sensor/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
|
||||
qdel(W)
|
||||
var/turf/T = get_turf(user.loc)
|
||||
var/mob/living/simple_animal/bot/floorbot/A = new /mob/living/simple_animal/bot/floorbot(T)
|
||||
A.name = created_name
|
||||
user << "<span class='notice'>You add the robot arm to the odd looking toolbox assembly. Boop beep!</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
else if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
|
||||
created_name = t
|
||||
|
||||
//Medbot Assembly
|
||||
/obj/item/weapon/firstaid_arm_assembly
|
||||
name = "incomplete medibot assembly."
|
||||
desc = "A first aid kit with a robot arm permanently grafted to it."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "firstaid_arm"
|
||||
var/build_step = 0
|
||||
var/created_name = "Medibot" //To preserve the name if it's a unique medbot I guess
|
||||
var/skin = null //Same as medbot, set to tox or ointment for the respective kits.
|
||||
w_class = 3
|
||||
var/treatment_brute = "salglu_solution"
|
||||
var/treatment_oxy = "salbutamol"
|
||||
var/treatment_fire = "salglu_solution"
|
||||
var/treatment_tox = "charcoal"
|
||||
var/treatment_virus = "spaceacillin"
|
||||
req_one_access = list(access_medical, access_robotics)
|
||||
|
||||
/obj/item/weapon/firstaid_arm_assembly/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(skin)
|
||||
overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]")
|
||||
|
||||
/obj/item/weapon/storage/firstaid/attackby(obj/item/robot_parts/S, mob/user, params)
|
||||
|
||||
if((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
|
||||
..()
|
||||
return
|
||||
|
||||
//Making a medibot!
|
||||
if(contents.len >= 1)
|
||||
user << "<span class='warning'>You need to empty [src] out first!</span>"
|
||||
return
|
||||
|
||||
var/obj/item/weapon/firstaid_arm_assembly/A = new /obj/item/weapon/firstaid_arm_assembly
|
||||
if(istype(src,/obj/item/weapon/storage/firstaid/fire))
|
||||
A.skin = "ointment"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/toxin))
|
||||
A.skin = "tox"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/o2))
|
||||
A.skin = "o2"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/brute))
|
||||
A.skin = "brute"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/adv))
|
||||
A.skin = "adv"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/tactical))
|
||||
A.skin = "bezerk"
|
||||
else if(istype(src,/obj/item/weapon/storage/firstaid/aquatic_kit))
|
||||
A.skin = "fish"
|
||||
|
||||
A.req_one_access = req_one_access
|
||||
A.treatment_oxy = treatment_oxy
|
||||
A.treatment_brute = treatment_brute
|
||||
A.treatment_fire = treatment_fire
|
||||
A.treatment_tox = treatment_tox
|
||||
A.treatment_virus = treatment_virus
|
||||
|
||||
qdel(S)
|
||||
user.put_in_hands(A)
|
||||
user << "<span class='notice'>You add the robot arm to the first aid kit.</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
else
|
||||
switch(build_step)
|
||||
if(0)
|
||||
if(istype(W, /obj/item/device/healthanalyzer))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the health sensor to [src].</span>"
|
||||
name = "First aid/robot arm/health analyzer assembly"
|
||||
overlays += image('icons/obj/aibots.dmi', "na_scanner")
|
||||
|
||||
if(1)
|
||||
if(isprox(W))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
qdel(W)
|
||||
build_step++
|
||||
user << "<span class='notice'>You complete the Medibot. Beep boop!</span>"
|
||||
var/turf/T = get_turf(src)
|
||||
var/mob/living/simple_animal/bot/medbot/S = new /mob/living/simple_animal/bot/medbot(T)
|
||||
S.skin = skin
|
||||
S.name = created_name
|
||||
S.bot_core.req_one_access = req_one_access
|
||||
S.treatment_oxy = treatment_oxy
|
||||
S.treatment_brute = treatment_brute
|
||||
S.treatment_fire = treatment_fire
|
||||
S.treatment_tox = treatment_tox
|
||||
S.treatment_virus = treatment_virus
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
//Secbot Assembly
|
||||
/obj/item/weapon/secbot_assembly
|
||||
name = "incomplete securitron assembly"
|
||||
desc = "Some sort of bizarre assembly made from a proximity sensor, helmet, and signaler."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "helmet_signaler"
|
||||
item_state = "helmet"
|
||||
var/build_step = 0
|
||||
var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
|
||||
|
||||
/obj/item/clothing/head/helmet/attackby(obj/item/device/assembly/signaler/S, mob/user, params)
|
||||
..()
|
||||
if(!issignaler(S))
|
||||
..()
|
||||
return
|
||||
|
||||
if(!S.secured)
|
||||
qdel(S)
|
||||
var/obj/item/weapon/secbot_assembly/A = new /obj/item/weapon/secbot_assembly
|
||||
user.put_in_hands(A)
|
||||
user << "<span class='notice'>You add the signaler to the helmet.</span>"
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/weapon/secbot_assembly/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/weapon/weldingtool))
|
||||
if(!build_step)
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(WT.remove_fuel(0, user))
|
||||
build_step++
|
||||
overlays += "hs_hole"
|
||||
user << "<span class='notice'>You weld a hole in [src]!</span>"
|
||||
else if(build_step == 1)
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(WT.remove_fuel(0, user))
|
||||
build_step--
|
||||
overlays -= "hs_hole"
|
||||
user << "<span class='notice'>You weld the hole in [src] shut!</span>"
|
||||
|
||||
else if(isprox(I) && (build_step == 1))
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the prox sensor to [src]!</span>"
|
||||
overlays += "hs_eye"
|
||||
name = "helmet/signaler/prox sensor assembly"
|
||||
qdel(I)
|
||||
|
||||
else if(((istype(I, /obj/item/robot_parts/l_arm)) || (istype(I, /obj/item/robot_parts/r_arm))) && (build_step == 2))
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
build_step++
|
||||
user << "<span class='notice'>You add the robot arm to [src]!</span>"
|
||||
name = "helmet/signaler/prox sensor/robot arm assembly"
|
||||
overlays += "hs_arm"
|
||||
qdel(I)
|
||||
|
||||
else if((istype(I, /obj/item/weapon/melee/baton)) && (build_step >= 3))
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
build_step++
|
||||
user << "<span class='notice'>You complete the Securitron! Beep boop.</span>"
|
||||
var/mob/living/simple_animal/bot/secbot/S = new /mob/living/simple_animal/bot/secbot
|
||||
S.forceMove(get_turf(src))
|
||||
S.name = created_name
|
||||
qdel(I)
|
||||
qdel(src)
|
||||
|
||||
else if(istype(I, /obj/item/weapon/pen))
|
||||
var/t = stripped_input(user, "Enter new robot name", name, created_name,MAX_NAME_LEN)
|
||||
if(!t)
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
|
||||
else if(istype(I, /obj/item/weapon/screwdriver))
|
||||
if(!build_step)
|
||||
new /obj/item/device/assembly/signaler(get_turf(src))
|
||||
new /obj/item/clothing/head/helmet(get_turf(src))
|
||||
user << "<span class='notice'>You disconnect the signaler from the helmet.</span>"
|
||||
qdel(src)
|
||||
|
||||
else if(build_step == 2)
|
||||
overlays -= "hs_eye"
|
||||
new /obj/item/device/assembly/prox_sensor(get_turf(src))
|
||||
user << "<span class='notice'>You detach the proximity sensor from [src].</span>"
|
||||
build_step--
|
||||
|
||||
else if(build_step == 3)
|
||||
overlays -= "hs_arm"
|
||||
new /obj/item/robot_parts/l_arm(get_turf(src))
|
||||
user << "<span class='notice'>You remove the robot arm from [src].</span>"
|
||||
build_step--
|
||||
@@ -0,0 +1,569 @@
|
||||
/mob/living/simple_animal/bot/ed209
|
||||
name = "\improper ED-209 Security Robot"
|
||||
desc = "A security robot. He looks less than thrilled."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "ed2090"
|
||||
density = 1
|
||||
anchored = 0
|
||||
health = 100
|
||||
maxHealth = 100
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
|
||||
environment_smash = 2 //Walls can't stop THE LAW
|
||||
|
||||
radio_channel = "Security"
|
||||
bot_type = SEC_BOT
|
||||
bot_filter = RADIO_SECBOT
|
||||
model = "ED-209"
|
||||
bot_purpose = "seek out criminals, handcuff them, and report their location to security"
|
||||
bot_core = /obj/machinery/bot_core/secbot
|
||||
window_id = "autoed209"
|
||||
window_name = "Automatic Security Unit v2.6"
|
||||
|
||||
var/lastfired = 0
|
||||
var/shot_delay = 3 //.3 seconds between shots
|
||||
var/lasercolor = ""
|
||||
var/disabled = 0//A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag
|
||||
|
||||
|
||||
var/mob/living/carbon/target
|
||||
var/oldtarget_name
|
||||
var/threatlevel = 0
|
||||
var/target_lastloc //Loc of target when arrested.
|
||||
var/last_found //There's a delay
|
||||
var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds?
|
||||
var/idcheck = 1 //If true, arrest people with no IDs
|
||||
var/weaponscheck = 1 //If true, arrest people for weapons if they don't have access
|
||||
var/check_records = 1 //Does it check security records?
|
||||
var/arrest_type = 0 //If true, don't handcuff
|
||||
var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type
|
||||
var/shoot_sound = 'sound/weapons/Taser.ogg'
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/New(loc,created_name,created_lasercolor)
|
||||
..()
|
||||
if(created_name)
|
||||
name = created_name
|
||||
if(created_lasercolor)
|
||||
lasercolor = created_lasercolor
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
set_weapon() //giving it the right projectile and firing sound.
|
||||
spawn(3)
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
if(lasercolor)
|
||||
shot_delay = 6//Longer shot delay because JESUS CHRIST
|
||||
check_records = 0//Don't actively target people set to arrest
|
||||
arrest_type = 1//Don't even try to cuff
|
||||
bot_core.req_access = list(access_maint_tunnels, access_theatre)
|
||||
arrest_type = 1
|
||||
if((lasercolor == "b") && (name == "\improper ED-209 Security Robot"))//Picks a name if there isn't already a custome one
|
||||
name = pick("BLUE BALLER","SANIC","BLUE KILLDEATH MURDERBOT")
|
||||
if((lasercolor == "r") && (name == "\improper ED-209 Security Robot"))
|
||||
name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT")
|
||||
|
||||
//SECHUD
|
||||
var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
secsensor.add_hud_to(src)
|
||||
permanent_huds |= secsensor
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/turn_on()
|
||||
. = ..()
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
mode = BOT_IDLE
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/turn_off()
|
||||
..()
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
anchored = 0
|
||||
walk_to(src,0)
|
||||
last_found = world.time
|
||||
set_weapon()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/set_custom_texts()
|
||||
text_hack = "You disable [name]'s combat inhibitor."
|
||||
text_dehack = "You restore [name]'s combat inhibitor."
|
||||
text_dehack_fail = "[name] ignores your attempts to restrict him!"
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += text({"
|
||||
<TT><B>Security Unit v2.6 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]<BR>"},
|
||||
|
||||
"<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>" )
|
||||
|
||||
if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user))
|
||||
if(!lasercolor)
|
||||
dat += text({"<BR>
|
||||
Arrest Unidentifiable Persons: []<BR>
|
||||
Arrest for Unauthorized Weapons: []<BR>
|
||||
Arrest for Warrant: []<BR>
|
||||
<BR>
|
||||
Operating Mode: []<BR>
|
||||
Report Arrests[]<BR>
|
||||
Auto Patrol[]"},
|
||||
|
||||
"<A href='?src=\ref[src];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
|
||||
"<A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
|
||||
|
||||
return dat
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/Topic(href, href_list)
|
||||
if(lasercolor && (istype(usr,/mob/living/carbon/human)))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
if((lasercolor == "b") && (istype(H.wear_suit, /obj/item/clothing/suit/redtag)))//Opposing team cannot operate it
|
||||
return
|
||||
else if((lasercolor == "r") && (istype(H.wear_suit, /obj/item/clothing/suit/bluetag)))
|
||||
return
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("idcheck")
|
||||
idcheck = !idcheck
|
||||
update_controls()
|
||||
if("weaponscheck")
|
||||
weaponscheck = !weaponscheck
|
||||
update_controls()
|
||||
if("ignorerec")
|
||||
check_records = !check_records
|
||||
update_controls()
|
||||
if("switchmode")
|
||||
arrest_type = !arrest_type
|
||||
update_controls()
|
||||
if("declarearrests")
|
||||
declare_arrests = !declare_arrests
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/retaliate(mob/living/carbon/human/H)
|
||||
threatlevel = H.assess_threat(src)
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
target = H
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == "harm")
|
||||
retaliate(H)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/attackby(obj/item/weapon/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
|
||||
return
|
||||
if(!istype(W, /obj/item/weapon/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina.
|
||||
retaliate(user)
|
||||
if(lasercolor)//To make up for the fact that lasertag bots don't hunt
|
||||
shootAt(user)
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='warning'>You short out [src]'s target assessment circuits.</span>"
|
||||
oldtarget_name = user.name
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = 0
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
set_weapon()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/bullet_act(obj/item/projectile/Proj)
|
||||
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
|
||||
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
|
||||
if(!Proj.nodamage && Proj.damage < src.health)
|
||||
retaliate(Proj.firer)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
if(disabled)
|
||||
return
|
||||
|
||||
var/list/targets = list()
|
||||
for(var/mob/living/carbon/C in view(7, src)) //Let's find us a target
|
||||
var/threatlevel = 0
|
||||
if((C.stat) || (C.lying))
|
||||
continue
|
||||
threatlevel = C.assess_threat(src, lasercolor)
|
||||
//speak(C.real_name + text(": threat: []", threatlevel))
|
||||
if(threatlevel < 4)
|
||||
continue
|
||||
|
||||
var/dst = get_dist(src, C)
|
||||
if(dst <= 1 || dst > 7)
|
||||
continue
|
||||
|
||||
targets += C
|
||||
if(targets.len>0)
|
||||
var/mob/living/carbon/t = pick(targets)
|
||||
if((t.stat!=2) && (t.lying != 1) && (!t.handcuffed)) //we don't shoot people who are dead, cuffed or lying down.
|
||||
shootAt(t)
|
||||
switch(mode)
|
||||
|
||||
if(BOT_IDLE) // idle
|
||||
walk_to(src,0)
|
||||
if(!lasercolor) //lasertag bots don't want to arrest anyone
|
||||
look_for_perp() // see if any criminals are in range
|
||||
if(!mode && auto_patrol) // still idle, and set to patrol
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(BOT_HUNT) // hunting for perp
|
||||
// if can't reach perp for long enough, go idle
|
||||
if(frustration >= 8)
|
||||
walk_to(src,0)
|
||||
back_to_idle()
|
||||
|
||||
if(target) // make sure target exists
|
||||
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
|
||||
stun_attack(target)
|
||||
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 1
|
||||
target_lastloc = target.loc
|
||||
return
|
||||
|
||||
else // not next to perp
|
||||
var/turf/olddist = get_dist(src, target)
|
||||
walk_to(src, target,1,4)
|
||||
if((get_dist(src, target)) >= (olddist))
|
||||
frustration++
|
||||
else
|
||||
frustration = 0
|
||||
else
|
||||
back_to_idle()
|
||||
|
||||
if(BOT_PREP_ARREST) // preparing to arrest target
|
||||
|
||||
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if(!Adjacent(target) || !isturf(target.loc) || target.weakened < 2)
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
cuff(target)
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(BOT_ARREST)
|
||||
if(!target)
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
|
||||
back_to_hunt()
|
||||
return
|
||||
else
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 0
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_perp()
|
||||
start_patrol()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/back_to_idle()
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
spawn(0)
|
||||
handle_automated_action() //ensure bot quickly responds
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/back_to_hunt()
|
||||
anchored = 0
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
handle_automated_action() //ensure bot quickly responds
|
||||
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/look_for_perp()
|
||||
if(disabled)
|
||||
return
|
||||
anchored = 0
|
||||
threatlevel = 0
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
|
||||
if((C.stat) || (C.handcuffed))
|
||||
continue
|
||||
|
||||
if((C.name == oldtarget_name) && (world.time < last_found + 100))
|
||||
continue
|
||||
|
||||
threatlevel = C.assess_threat(src, lasercolor)
|
||||
|
||||
if(!threatlevel)
|
||||
continue
|
||||
|
||||
else if(threatlevel >= 4)
|
||||
target = C
|
||||
oldtarget_name = C.name
|
||||
speak("Level [threatlevel] infraction alert!")
|
||||
playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/EDPlaceholder.ogg'), 50, 0)
|
||||
visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
handle_automated_action() // ensure bot quickly responds to a perp
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/check_for_weapons(var/obj/item/slot_item)
|
||||
if(slot_item && slot_item.needs_permit)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/explode()
|
||||
walk_to(src,0)
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/ed209_assembly/Sa = new /obj/item/weapon/ed209_assembly(Tsec)
|
||||
Sa.build_step = 1
|
||||
Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole")
|
||||
Sa.created_name = name
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
|
||||
if(!lasercolor)
|
||||
var/obj/item/weapon/gun/energy/advtaser/G = new /obj/item/weapon/gun/energy/advtaser(Tsec)
|
||||
G.power_supply.charge = 0
|
||||
G.update_icon()
|
||||
else if(lasercolor == "b")
|
||||
var/obj/item/weapon/gun/energy/laser/bluetag/G = new /obj/item/weapon/gun/energy/laser/bluetag(Tsec)
|
||||
G.power_supply.charge = 0
|
||||
G.update_icon()
|
||||
else if(lasercolor == "r")
|
||||
var/obj/item/weapon/gun/energy/laser/redtag/G = new /obj/item/weapon/gun/energy/laser/redtag(Tsec)
|
||||
G.power_supply.charge = 0
|
||||
G.update_icon()
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/robot_parts/l_leg(Tsec)
|
||||
if(prob(25))
|
||||
new /obj/item/robot_parts/r_leg(Tsec)
|
||||
if(prob(25))//50% chance for a helmet OR vest
|
||||
if(prob(50))
|
||||
new /obj/item/clothing/head/helmet(Tsec)
|
||||
else
|
||||
if(!lasercolor)
|
||||
new /obj/item/clothing/suit/armor/vest(Tsec)
|
||||
if(lasercolor == "b")
|
||||
new /obj/item/clothing/suit/bluetag(Tsec)
|
||||
if(lasercolor == "r")
|
||||
new /obj/item/clothing/suit/redtag(Tsec)
|
||||
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/blood/oil(loc)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound
|
||||
shoot_sound = 'sound/weapons/laser.ogg'
|
||||
if(emagged == 2)
|
||||
if(lasercolor)
|
||||
projectile = /obj/item/projectile/lasertag
|
||||
else
|
||||
projectile = /obj/item/projectile/beam
|
||||
else
|
||||
if(!lasercolor)
|
||||
shoot_sound = 'sound/weapons/Taser.ogg'
|
||||
projectile = /obj/item/projectile/energy/electrode
|
||||
else if(lasercolor == "b")
|
||||
projectile = /obj/item/projectile/lasertag/blue
|
||||
else if(lasercolor == "r")
|
||||
projectile = /obj/item/projectile/lasertag/red
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/shootAt(mob/target)
|
||||
if(lastfired && world.time - lastfired < shot_delay)
|
||||
return
|
||||
lastfired = world.time
|
||||
var/turf/T = loc
|
||||
var/atom/U = (istype(target, /atom/movable) ? target.loc : target)
|
||||
if((!( U ) || !( T )))
|
||||
return
|
||||
while(!(istype(U, /turf)))
|
||||
U = U.loc
|
||||
if(!(istype(T, /turf)))
|
||||
return
|
||||
|
||||
if(!projectile)
|
||||
return
|
||||
|
||||
if(!(istype(U, /turf)))
|
||||
return
|
||||
var/obj/item/projectile/A = new projectile(loc)
|
||||
playsound(loc, shoot_sound, 50, 1)
|
||||
A.current = U
|
||||
A.yo = U.y - T.y
|
||||
A.xo = U.x - T.x
|
||||
spawn(0)
|
||||
A.process()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/attack_alien(mob/living/carbon/alien/user)
|
||||
..()
|
||||
if(!isalien(target))
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/emp_act(severity)
|
||||
|
||||
if(severity==2 && prob(70))
|
||||
..(severity-1)
|
||||
else
|
||||
var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( loc )
|
||||
pulse2.icon = 'icons/effects/effects.dmi'
|
||||
pulse2.icon_state = "empdisable"
|
||||
pulse2.name = "emp sparks"
|
||||
pulse2.anchored = 1
|
||||
pulse2.dir = pick(cardinal)
|
||||
spawn(10)
|
||||
qdel(pulse2)
|
||||
var/list/mob/living/carbon/targets = new
|
||||
for(var/mob/living/carbon/C in view(12,src))
|
||||
if(C.stat==2)
|
||||
continue
|
||||
targets += C
|
||||
if(targets.len)
|
||||
if(prob(50))
|
||||
var/mob/toshoot = pick(targets)
|
||||
if(toshoot)
|
||||
targets-=toshoot
|
||||
if(prob(50) && emagged < 2)
|
||||
emagged = 2
|
||||
set_weapon()
|
||||
shootAt(toshoot)
|
||||
emagged = 0
|
||||
set_weapon()
|
||||
else
|
||||
shootAt(toshoot)
|
||||
else if(prob(50))
|
||||
if(targets.len)
|
||||
var/mob/toarrest = pick(targets)
|
||||
if(toarrest)
|
||||
target = toarrest
|
||||
mode = BOT_HUNT
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/bullet_act(obj/item/projectile/Proj)
|
||||
if(!disabled)
|
||||
var/lasertag_check = 0
|
||||
if((lasercolor == "b"))
|
||||
if(istype(Proj, /obj/item/projectile/lasertag/red))
|
||||
lasertag_check++
|
||||
else if((lasercolor == "r"))
|
||||
if(istype(Proj, /obj/item/projectile/lasertag/blue))
|
||||
lasertag_check++
|
||||
if(lasertag_check)
|
||||
icon_state = "[lasercolor]ed2090"
|
||||
disabled = 1
|
||||
target = null
|
||||
spawn(100)
|
||||
disabled = 0
|
||||
icon_state = "[lasercolor]ed2091"
|
||||
return 1
|
||||
else
|
||||
..(Proj)
|
||||
else
|
||||
..(Proj)
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/bluetag
|
||||
lasercolor = "b"
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/redtag
|
||||
lasercolor = "r"
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A)
|
||||
if(!on)
|
||||
return
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/C = A
|
||||
if(!C.stunned || arrest_type)
|
||||
stun_attack(A)
|
||||
else if(C.canBeHandcuffed() && !C.handcuffed)
|
||||
cuff(A)
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/RangedAttack(atom/A)
|
||||
if(!on)
|
||||
return
|
||||
shootAt(A)
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
icon_state = "[lasercolor]ed209-c"
|
||||
spawn(2)
|
||||
icon_state = "[lasercolor]ed209[on]"
|
||||
var/threat = 5
|
||||
if(istype(C, /mob/living/carbon/human))
|
||||
C.stuttering = 5
|
||||
C.Stun(5)
|
||||
C.Weaken(5)
|
||||
var/mob/living/carbon/human/H = C
|
||||
threat = H.assess_threat(src)
|
||||
else
|
||||
C.Weaken(5)
|
||||
C.stuttering = 5
|
||||
C.Stun(5)
|
||||
add_logs(src,C,"stunned")
|
||||
if(declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
|
||||
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
|
||||
"<span class='userdanger'>[src] has stunned you!</span>")
|
||||
|
||||
/mob/living/simple_animal/bot/ed209/proc/cuff(mob/living/carbon/C)
|
||||
mode = BOT_ARREST
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
|
||||
|
||||
spawn(60)
|
||||
if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
|
||||
C.update_inv_handcuffed(1)
|
||||
back_to_idle()
|
||||
@@ -0,0 +1,119 @@
|
||||
/mob/living/simple_animal/bot/emote(var/act, var/m_type=1, var/message = null)
|
||||
var/param = null
|
||||
if (findtext(act, "-", 1, null))
|
||||
var/t1 = findtext(act, "-", 1, null)
|
||||
param = copytext(act, t1 + 1, length(act) + 1)
|
||||
act = copytext(act, 1, t1)
|
||||
|
||||
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
|
||||
act = copytext(act,1,length(act))
|
||||
|
||||
//Emote Cooldown System (it's so simple!)
|
||||
// proc/handle_emote_CD() located in [code\modules\mob\emote.dm]
|
||||
var/on_CD = 0
|
||||
switch(act)
|
||||
//Cooldown-inducing emotes
|
||||
if("scream", "screams")
|
||||
on_CD = handle_emote_CD(50) //longer cooldown
|
||||
if("ping","buzz","beep","yes","no") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT.
|
||||
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
|
||||
//Everything else, including typos of the above emotes
|
||||
else
|
||||
on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown
|
||||
|
||||
if(on_CD == 1) // Check if we need to suppress the emote attempt.
|
||||
return // Suppress emote, you're still cooling off.
|
||||
//--FalseIncarnate
|
||||
|
||||
switch(act)
|
||||
if("ping")
|
||||
var/M = null
|
||||
if(param)
|
||||
for (var/mob/A in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if (param)
|
||||
message = "<B>[src]</B> pings at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> pings."
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("buzz")
|
||||
var/M = null
|
||||
if(param)
|
||||
for (var/mob/A in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if (param)
|
||||
message = "<B>[src]</B> buzzes at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> buzzes."
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("beep")
|
||||
var/M = null
|
||||
if(param)
|
||||
for (var/mob/A in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if (param)
|
||||
message = "<B>[src]</B> beeps at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> beeps."
|
||||
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("yes")
|
||||
var/M = null
|
||||
if(param)
|
||||
for (var/mob/A in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if (param)
|
||||
message = "<B>[src]</B> emits an affirmative blip at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> emits an affirmative blip."
|
||||
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("no")
|
||||
var/M = null
|
||||
if(param)
|
||||
for (var/mob/A in view(null, null))
|
||||
if (param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(!M)
|
||||
param = null
|
||||
|
||||
if (param)
|
||||
message = "<B>[src]</B> emits a negative blip at [param]."
|
||||
else
|
||||
message = "<B>[src]</B> emits a negative blip."
|
||||
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
|
||||
m_type = 2
|
||||
|
||||
if("scream", "screams")
|
||||
message = "<B>[src]</B> screams!"
|
||||
playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0)
|
||||
m_type = 2
|
||||
|
||||
..(act, m_type, message)
|
||||
@@ -0,0 +1,425 @@
|
||||
//Floorbot
|
||||
/mob/living/simple_animal/bot/floorbot
|
||||
name = "\improper Floorbot"
|
||||
desc = "A little floor repairing robot, he looks so excited!"
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "floorbot0"
|
||||
density = 0
|
||||
anchored = 0
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
|
||||
radio_channel = "Engineering"
|
||||
bot_type = FLOOR_BOT
|
||||
bot_filter = RADIO_FLOORBOT
|
||||
model = "Floorbot"
|
||||
bot_purpose = "seek out damaged or missing floor tiles, and repair or replace them as necessary"
|
||||
bot_core = /obj/machinery/bot_core/floorbot
|
||||
window_id = "autofloor"
|
||||
window_name = "Automatic Station Floor Repairer v1.1"
|
||||
|
||||
var/process_type //Determines what to do when process_scan() recieves a target. See process_scan() for details.
|
||||
var/targetdirection
|
||||
var/amount = 10
|
||||
var/replacetiles = 0
|
||||
var/eattiles = 0
|
||||
var/maketiles = 0
|
||||
var/fixfloors = 0
|
||||
var/autotile = 0
|
||||
var/nag_on_empty = 1
|
||||
var/nagged = 0 //Prevents the Floorbot nagging more than once per refill.
|
||||
var/max_targets = 50
|
||||
var/turf/target
|
||||
var/oldloc = null
|
||||
|
||||
#define HULL_BREACH 1
|
||||
#define BRIDGE_MODE 2
|
||||
#define FIX_TILE 3
|
||||
#define AUTO_TILE 4
|
||||
#define REPLACE_TILE 5
|
||||
#define TILE_EMAG 6
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/New()
|
||||
..()
|
||||
update_icon()
|
||||
var/datum/job/engineer/J = new/datum/job/engineer
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldloc = null
|
||||
ignore_list = list()
|
||||
nagged = 0
|
||||
anchored = 0
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/set_custom_texts()
|
||||
text_hack = "You corrupt [name]'s construction protocols."
|
||||
text_dehack = "You detect errors in [name] and reset his programming."
|
||||
text_dehack_fail = "[name] is not responding to reset commands!"
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += "<TT><B>Floor Repairer Controls v1.1</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel panel is [open ? "opened" : "closed"]<BR>"
|
||||
dat += "Tiles left: [amount]<BR>"
|
||||
dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]<BR>"
|
||||
if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user))
|
||||
dat += "Add tiles to new hull plating: <A href='?src=\ref[src];operation=autotile'>[autotile ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Replace floor tiles: <A href='?src=\ref[src];operation=replace'>[replacetiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Finds tiles: <A href='?src=\ref[src];operation=tiles'>[eattiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Make pieces of metal into tiles when empty: <A href='?src=\ref[src];operation=make'>[maketiles ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Transmit notice when empty: <A href='?src=\ref[src];operation=emptynag'>[nag_on_empty ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Repair damaged tiles and platings: <A href='?src=\ref[src];operation=fix'>[fixfloors ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Traction Magnets: <A href='?src=\ref[src];operation=anchor'>[anchored ? "Engaged" : "Disengaged"]</A><BR>"
|
||||
dat += "Patrol Station: <A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A><BR>"
|
||||
var/bmode
|
||||
if(targetdirection)
|
||||
bmode = dir2text(targetdirection)
|
||||
else
|
||||
bmode = "disabled"
|
||||
dat += "Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
|
||||
|
||||
return dat
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/attackby(obj/item/W , mob/user, params)
|
||||
if(istype(W, /obj/item/stack/tile/plasteel))
|
||||
var/obj/item/stack/tile/plasteel/T = W
|
||||
if(amount >= 50)
|
||||
return
|
||||
var/loaded = min(50-amount, T.amount)
|
||||
T.use(loaded)
|
||||
amount += loaded
|
||||
if(loaded > 0)
|
||||
user << "<span class='notice'>You load [loaded] tiles into the floorbot. He now contains [amount] tiles.</span>"
|
||||
nagged = 0
|
||||
update_icon()
|
||||
else
|
||||
user << "<span class='warning'>You need at least one floor tile to put into [src]!</span>"
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'>[src] buzzes and beeps.</span>"
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("replace")
|
||||
replacetiles = !replacetiles
|
||||
if("tiles")
|
||||
eattiles = !eattiles
|
||||
if("make")
|
||||
maketiles = !maketiles
|
||||
if("fix")
|
||||
fixfloors = !fixfloors
|
||||
if("autotile")
|
||||
autotile = !autotile
|
||||
if("emptynag")
|
||||
nag_on_empty = !nag_on_empty
|
||||
if("anchor")
|
||||
anchored = !anchored
|
||||
|
||||
if("bridgemode")
|
||||
var/setdir = input("Select construction direction:") as null|anything in list("north","east","south","west","disable")
|
||||
switch(setdir)
|
||||
if("north")
|
||||
targetdirection = 1
|
||||
if("south")
|
||||
targetdirection = 2
|
||||
if("east")
|
||||
targetdirection = 4
|
||||
if("west")
|
||||
targetdirection = 8
|
||||
if("disable")
|
||||
targetdirection = null
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
if(mode == BOT_REPAIRING)
|
||||
return
|
||||
|
||||
if(amount <= 0 && !target) //Out of tiles! We must refill!
|
||||
if(eattiles) //Configured to find and consume floortiles!
|
||||
target = scan(/obj/item/stack/tile/plasteel)
|
||||
process_type = null
|
||||
|
||||
if(!target && maketiles) //We did not manage to find any floor tiles! Scan for metal stacks and make our own!
|
||||
target = scan(/obj/item/stack/sheet/metal)
|
||||
process_type = null
|
||||
return
|
||||
else
|
||||
if(nag_on_empty) //Floorbot is empty and cannot acquire more tiles, nag the engineers for more!
|
||||
nag()
|
||||
|
||||
if(prob(5))
|
||||
audible_message("[src] makes an excited booping beeping sound!")
|
||||
|
||||
//Normal scanning procedure. We have tiles loaded, are not emagged.
|
||||
if(!target && emagged < 2 && amount > 0)
|
||||
if(targetdirection != null) //The bot is in bridge mode.
|
||||
//Try to find a space tile immediately in our selected direction.
|
||||
var/turf/T = get_step(src, targetdirection)
|
||||
if(istype(T, /turf/space))
|
||||
target = T
|
||||
|
||||
else //Find a space tile farther way!
|
||||
target = scan(/turf/space)
|
||||
process_type = BRIDGE_MODE
|
||||
|
||||
if(!target)
|
||||
process_type = HULL_BREACH //Ensures the floorbot does not try to "fix" space areas or shuttle docking zones.
|
||||
target = scan(/turf/space)
|
||||
|
||||
if(!target && replacetiles) //Finds a floor without a tile and gives it one.
|
||||
process_type = REPLACE_TILE //The target must be the floor and not a tile. The floor must not already have a floortile.
|
||||
target = scan(/turf/simulated/floor)
|
||||
|
||||
if(!target && fixfloors) //Repairs damaged floors and tiles.
|
||||
process_type = FIX_TILE
|
||||
target = scan(/turf/simulated/floor)
|
||||
|
||||
if(!target && emagged == 2) //We are emagged! Time to rip up the floors!
|
||||
process_type = TILE_EMAG
|
||||
target = scan(/turf/simulated/floor)
|
||||
|
||||
|
||||
if(!target)
|
||||
|
||||
if(auto_patrol)
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
if(target)
|
||||
if(path.len == 0)
|
||||
if(!istype(target, /turf/))
|
||||
var/turf/TL = get_turf(target)
|
||||
path = get_path_to(src, TL, /turf/proc/Distance_cardinal, 0, 30, id=access_card,simulated_only = 0)
|
||||
else
|
||||
path = get_path_to(src, target, /turf/proc/Distance_cardinal, 0, 30, id=access_card,simulated_only = 0)
|
||||
|
||||
if(!bot_move(target))
|
||||
add_to_ignore(target)
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
else if( !bot_move(target) )
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
|
||||
if(loc == target || loc == target.loc)
|
||||
if(istype(target, /obj/item/stack/tile/plasteel))
|
||||
eattile(target)
|
||||
else if(istype(target, /obj/item/stack/sheet/metal))
|
||||
maketile(target)
|
||||
else if(istype(target, /turf/) && emagged < 2)
|
||||
repair(target)
|
||||
else if(emagged == 2 && istype(target,/turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = target
|
||||
anchored = 1
|
||||
mode = BOT_REPAIRING
|
||||
if(prob(90))
|
||||
F.break_tile_to_plating()
|
||||
else
|
||||
F.ReplaceWithLattice()
|
||||
audible_message("<span class='danger'>[src] makes an excited booping sound.</span>")
|
||||
spawn(50)
|
||||
amount ++
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
path = list()
|
||||
return
|
||||
|
||||
oldloc = loc
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us!
|
||||
if(!nagged)
|
||||
speak("Requesting refill at <b>[get_area(src)]</b>!", radio_channel)
|
||||
nagged = 1
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/proc/is_hull_breach(turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas.
|
||||
var/area/t_area = get_area(t)
|
||||
if(t_area && (t_area.name == "Space" || findtext(t_area.name, "huttle")))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
//Floorbots, having several functions, need sort out special conditions here.
|
||||
/mob/living/simple_animal/bot/floorbot/process_scan(scan_target)
|
||||
var/result
|
||||
var/turf/simulated/floor/F
|
||||
switch(process_type)
|
||||
if(HULL_BREACH) //The most common job, patching breaches in the station's hull.
|
||||
if(is_hull_breach(scan_target)) //Ensure that the targeted space turf is actually part of the station, and not random space.
|
||||
result = scan_target
|
||||
anchored = 1 //Prevent the floorbot being blown off-course while trying to reach a hull breach.
|
||||
if(BRIDGE_MODE) //Only space turfs in our chosen direction are considered.
|
||||
if(get_dir(src, scan_target) == targetdirection)
|
||||
result = scan_target
|
||||
anchored = 1
|
||||
if(REPLACE_TILE)
|
||||
F = scan_target
|
||||
if(istype(F, /turf/simulated/floor/plating)) //The floor must not already have a tile.
|
||||
result = F
|
||||
if(FIX_TILE) //Selects only damaged floors.
|
||||
F = scan_target
|
||||
if(istype(F) && (F.broken || F.burnt))
|
||||
result = F
|
||||
if(TILE_EMAG) //Emag mode! Rip up the floor and cause breaches to space!
|
||||
F = scan_target
|
||||
if(!istype(F, /turf/simulated/floor/plating))
|
||||
result = F
|
||||
else //If no special processing is needed, simply return the result.
|
||||
result = scan_target
|
||||
return result
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/proc/repair(turf/target_turf)
|
||||
|
||||
if(istype(target_turf, /turf/space/))
|
||||
//Must be a hull breach or in bridge mode to continue.
|
||||
if(!is_hull_breach(target_turf) && !targetdirection)
|
||||
target = null
|
||||
return
|
||||
else if(!istype(target_turf, /turf/simulated/floor))
|
||||
return
|
||||
if(amount <= 0)
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
return
|
||||
anchored = 1
|
||||
icon_state = "floorbot-c"
|
||||
if(istype(target_turf, /turf/space/)) //If we are fixing an area not part of pure space, it is
|
||||
visible_message("<span class='notice'>[targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] </span>")
|
||||
mode = BOT_REPAIRING
|
||||
spawn(50)
|
||||
if(mode == BOT_REPAIRING)
|
||||
if(autotile) //Build the floor and include a tile.
|
||||
target_turf.ChangeTurf(/turf/simulated/floor/plasteel)
|
||||
else //Build a hull plating without a floor tile.
|
||||
target_turf.ChangeTurf(/turf/simulated/floor/plating)
|
||||
mode = BOT_IDLE
|
||||
amount -= 1
|
||||
update_icon()
|
||||
anchored = 0
|
||||
target = null
|
||||
else
|
||||
var/turf/simulated/floor/F = target_turf
|
||||
mode = BOT_REPAIRING
|
||||
visible_message("<span class='notice'>[src] begins repairing the floor.</span>")
|
||||
spawn(50)
|
||||
if(mode == BOT_REPAIRING)
|
||||
F.broken = 0
|
||||
F.burnt = 0
|
||||
F.ChangeTurf(/turf/simulated/floor/plasteel)
|
||||
mode = BOT_IDLE
|
||||
amount -= 1
|
||||
update_icon()
|
||||
anchored = 0
|
||||
target = null
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/proc/eattile(obj/item/stack/tile/plasteel/T)
|
||||
if(!istype(T, /obj/item/stack/tile/plasteel))
|
||||
return
|
||||
visible_message("<span class='notice'>[src] begins to collect tiles.</span>")
|
||||
mode = BOT_REPAIRING
|
||||
spawn(20)
|
||||
if(isnull(T))
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
if(amount + T.amount > 50)
|
||||
var/i = 50 - amount
|
||||
amount += i
|
||||
T.amount -= i
|
||||
else
|
||||
amount += T.amount
|
||||
qdel(T)
|
||||
update_icon()
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/proc/maketile(obj/item/stack/sheet/metal/M)
|
||||
if(!istype(M, /obj/item/stack/sheet/metal))
|
||||
return
|
||||
visible_message("<span class='notice'>[src] begins to create tiles.</span>")
|
||||
mode = BOT_REPAIRING
|
||||
spawn(20)
|
||||
if(isnull(M))
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
return
|
||||
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
|
||||
T.amount = 4
|
||||
T.forceMove(M.loc)
|
||||
if(M.amount > 1)
|
||||
M.amount--
|
||||
else
|
||||
qdel(M)
|
||||
target = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/update_icon()
|
||||
if(amount > 0)
|
||||
icon_state = "floorbot[on]"
|
||||
else
|
||||
icon_state = "floorbot[on]e"
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/explode()
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
|
||||
N.contents = list()
|
||||
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/robot_parts/l_arm(Tsec)
|
||||
|
||||
while(amount)//Dumps the tiles into the appropriate sized stacks
|
||||
if(amount >= 16)
|
||||
var/obj/item/stack/tile/plasteel/T = new (Tsec)
|
||||
T.amount = 16
|
||||
amount -= 16
|
||||
else
|
||||
var/obj/item/stack/tile/plasteel/T = new (Tsec)
|
||||
T.amount = amount
|
||||
amount = 0
|
||||
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/floorbot
|
||||
req_one_access = list(access_construction, access_robotics)
|
||||
|
||||
/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A)
|
||||
if(isturf(A))
|
||||
repair(A)
|
||||
else if(istype(A,/obj/item/stack/tile/plasteel))
|
||||
eattile(A)
|
||||
else if(istype(A,/obj/item/stack/sheet/metal))
|
||||
maketile(A)
|
||||
else
|
||||
..()
|
||||
@@ -0,0 +1,563 @@
|
||||
//Medbot
|
||||
/mob/living/simple_animal/bot/medbot
|
||||
name = "\improper Medibot"
|
||||
desc = "A little medical robot. He looks somewhat underwhelmed."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "medibot0"
|
||||
density = 0
|
||||
anchored = 0
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
pass_flags = PASSMOB
|
||||
|
||||
radio_channel = "Medical"
|
||||
|
||||
bot_type = MED_BOT
|
||||
bot_filter = RADIO_MEDBOT
|
||||
model = "Medibot"
|
||||
bot_purpose = "seek out hurt crewmembers and ensure that they are healed"
|
||||
bot_core_type = /obj/machinery/bot_core/medbot
|
||||
window_id = "automed"
|
||||
window_name = "Automatic Medical Unit v1.1"
|
||||
|
||||
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
|
||||
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
|
||||
var/mob/living/carbon/patient = null
|
||||
var/mob/living/carbon/oldpatient = null
|
||||
var/oldloc = null
|
||||
var/last_found = 0
|
||||
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
|
||||
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.
|
||||
var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
|
||||
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
|
||||
var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
|
||||
//Setting which reagents to use to treat what by default. By id.
|
||||
var/treatment_brute = "salglu_solution"
|
||||
var/treatment_oxy = "salbutamol"
|
||||
var/treatment_fire = "salglu_solution"
|
||||
var/treatment_tox = "charcoal"
|
||||
var/treatment_virus = "spaceacillin"
|
||||
var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
|
||||
var/shut_up = 0 //self explanatory :)
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/tox
|
||||
skin = "tox"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/o2
|
||||
skin = "o2"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/brute
|
||||
skin = "brute"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/fire
|
||||
skin = "ointment"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/adv
|
||||
skin = "adv"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/fish
|
||||
skin = "fish"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/mysterious
|
||||
name = "\improper Mysterious Medibot"
|
||||
desc = "International Medibot of mystery."
|
||||
skin = "bezerk"
|
||||
treatment_oxy = "perfluorodecalin"
|
||||
treatment_brute = "styptic_powder"
|
||||
treatment_fire = "silver_sulfadiazine"
|
||||
treatment_tox = "charcoal"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/syndicate
|
||||
name = "Suspicious Medibot"
|
||||
desc = "You'd better have insurance!"
|
||||
skin = "bezerk"
|
||||
treatment_oxy = "perfluorodecalin"
|
||||
treatment_brute = "styptic_powder"
|
||||
treatment_fire = "silver_sulfadiazine"
|
||||
treatment_tox = "charcoal"
|
||||
bot_core_type = /obj/machinery/bot_core/medbot/syndicate
|
||||
control_freq = BOT_FREQ + 1000 // make it not show up on lists
|
||||
radio_channel = "Syndicate"
|
||||
radio_config = list("Common" = 1, "Medical" = 1, "Syndicate" = 1)
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/syndicate/New()
|
||||
..()
|
||||
Radio.syndie = 1
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/update_icon()
|
||||
if(!on)
|
||||
icon_state = "medibot0"
|
||||
return
|
||||
if(mode == BOT_HEALING)
|
||||
icon_state = "medibots[stationary_mode]"
|
||||
return
|
||||
else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
|
||||
icon_state = "medibot2"
|
||||
else
|
||||
icon_state = "medibot1"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/New()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
spawn(4)
|
||||
if(skin)
|
||||
overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
|
||||
|
||||
var/datum/job/doctor/J = new/datum/job/doctor
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
var/datum/atom_hud/medsensor = huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
medsensor.add_hud_to(src)
|
||||
permanent_huds |= medsensor
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/bot_reset()
|
||||
..()
|
||||
patient = null
|
||||
oldpatient = null
|
||||
oldloc = null
|
||||
last_found = world.time
|
||||
declare_cooldown = 0
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
|
||||
path = list()
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/set_custom_texts()
|
||||
text_hack = "You corrupt [name]'s reagent processor circuits."
|
||||
text_dehack = "You reset [name]'s reagent processor circuits."
|
||||
text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += "<TT><B>Medical Unit Controls v1.1</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel panel is [open ? "opened" : "closed"]<BR>"
|
||||
dat += "Beaker: "
|
||||
if(reagent_glass)
|
||||
dat += "<A href='?src=\ref[src];eject=1'>Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]</a>"
|
||||
else
|
||||
dat += "None Loaded"
|
||||
dat += "<br>Behaviour controls are [locked ? "locked" : "unlocked"]<hr>"
|
||||
if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user))
|
||||
dat += "<TT>Healing Threshold: "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=-10'>--</a> "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=-5'>-</a> "
|
||||
dat += "[heal_threshold] "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=5'>+</a> "
|
||||
dat += "<a href='?src=\ref[src];adj_threshold=10'>++</a>"
|
||||
dat += "</TT><br>"
|
||||
|
||||
dat += "<TT>Injection Level: "
|
||||
dat += "<a href='?src=\ref[src];adj_inject=-5'>-</a> "
|
||||
dat += "[injection_amount] "
|
||||
dat += "<a href='?src=\ref[src];adj_inject=5'>+</a> "
|
||||
dat += "</TT><br>"
|
||||
|
||||
dat += "Reagent Source: "
|
||||
dat += "<a href='?src=\ref[src];use_beaker=1'>[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]</a><br>"
|
||||
|
||||
dat += "Treat Viral Infections: <a href='?src=\ref[src];virus=1'>[treat_virus ? "Yes" : "No"]</a><br>"
|
||||
dat += "The speaker switch is [shut_up ? "off" : "on"]. <a href='?src=\ref[src];togglevoice=[1]'>Toggle</a><br>"
|
||||
dat += "Critical Patient Alerts: <a href='?src=\ref[src];critalerts=1'>[declare_crit ? "Yes" : "No"]</a><br>"
|
||||
dat += "Patrol Station: <a href='?src=\ref[src];operation=patrol'>[auto_patrol ? "Yes" : "No"]</a><br>"
|
||||
dat += "Stationary Mode: <a href='?src=\ref[src];stationary=1'>[stationary_mode ? "Yes" : "No"]</a><br>"
|
||||
|
||||
return dat
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["adj_threshold"])
|
||||
var/adjust_num = text2num(href_list["adj_threshold"])
|
||||
heal_threshold += adjust_num
|
||||
if(heal_threshold < 5)
|
||||
heal_threshold = 5
|
||||
if(heal_threshold > 75)
|
||||
heal_threshold = 75
|
||||
|
||||
else if(href_list["adj_inject"])
|
||||
var/adjust_num = text2num(href_list["adj_inject"])
|
||||
injection_amount += adjust_num
|
||||
if(injection_amount < 5)
|
||||
injection_amount = 5
|
||||
if(injection_amount > 15)
|
||||
injection_amount = 15
|
||||
|
||||
else if(href_list["use_beaker"])
|
||||
use_beaker = !use_beaker
|
||||
|
||||
else if(href_list["eject"] && (!isnull(reagent_glass)))
|
||||
reagent_glass.forceMove(get_turf(src))
|
||||
reagent_glass = null
|
||||
|
||||
else if(href_list["togglevoice"])
|
||||
shut_up = !shut_up
|
||||
|
||||
else if(href_list["critalerts"])
|
||||
declare_crit = !declare_crit
|
||||
|
||||
else if(href_list["stationary"])
|
||||
stationary_mode = !stationary_mode
|
||||
path = list()
|
||||
update_icon()
|
||||
|
||||
else if(href_list["virus"])
|
||||
treat_virus = !treat_virus
|
||||
|
||||
update_controls()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
|
||||
if(istype(W, /obj/item/weapon/reagent_containers/glass))
|
||||
if(locked)
|
||||
user << "<span class='warning'>You cannot insert a beaker because the panel is locked!</span>"
|
||||
return
|
||||
if(!isnull(reagent_glass))
|
||||
user << "<span class='warning'>There is already a beaker loaded!</span>"
|
||||
return
|
||||
if(!user.drop_item())
|
||||
return
|
||||
|
||||
W.forceMove(src)
|
||||
reagent_glass = W
|
||||
user << "<span class='notice'>You insert [W].</span>"
|
||||
show_controls(user)
|
||||
return
|
||||
|
||||
else
|
||||
var/current_health = health
|
||||
..()
|
||||
if(health < current_health) //if medbot took some damage
|
||||
step_to(src, (get_step_away(src,user)))
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
declare_crit = 0
|
||||
if(user)
|
||||
user << "<span class='notice'>You short out [src]'s reagent synthesis circuits.</span>"
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
flick("medibot_spark", src)
|
||||
if(user)
|
||||
oldpatient = user
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/process_scan(mob/living/carbon/human/H)
|
||||
if(H.stat == 2)
|
||||
return
|
||||
|
||||
if((H == oldpatient) && (world.time < last_found + 200))
|
||||
return
|
||||
|
||||
if(assess_patient(H))
|
||||
last_found = world.time
|
||||
if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
|
||||
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!")
|
||||
speak(message)
|
||||
last_newpatient_speak = world.time
|
||||
return H
|
||||
else
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
if(mode == BOT_HEALING)
|
||||
return
|
||||
|
||||
if(stunned)
|
||||
icon_state = "medibota"
|
||||
stunned--
|
||||
|
||||
oldpatient = patient
|
||||
patient = null
|
||||
mode = BOT_IDLE
|
||||
|
||||
if(stunned <= 0)
|
||||
update_icon()
|
||||
stunned = 0
|
||||
return
|
||||
|
||||
if(frustration > 8)
|
||||
oldpatient = patient
|
||||
soft_reset()
|
||||
|
||||
if(!patient)
|
||||
if(!shut_up && 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!")
|
||||
speak(message)
|
||||
var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
|
||||
patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
|
||||
oldpatient = patient
|
||||
|
||||
if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
|
||||
if(mode != BOT_HEALING)
|
||||
mode = BOT_HEALING
|
||||
update_icon()
|
||||
frustration = 0
|
||||
medicate_patient(patient)
|
||||
return
|
||||
|
||||
//Patient has moved away from us!
|
||||
else if(patient && path.len && (get_dist(patient,path[path.len]) > 2))
|
||||
path = list()
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
|
||||
else if(stationary_mode && patient) //Since we cannot move in this mode, ignore the patient and wait for another.
|
||||
soft_reset()
|
||||
return
|
||||
|
||||
if(patient && path.len == 0 && (get_dist(src,patient) > 1))
|
||||
path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,id=access_card)
|
||||
mode = BOT_MOVING
|
||||
if(!path.len) //try to get closer if you can't reach the patient directly
|
||||
path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,1,id=access_card)
|
||||
if(!path.len) //Do not chase a patient we cannot reach.
|
||||
soft_reset()
|
||||
|
||||
if(path.len > 0 && patient)
|
||||
if(!bot_move(path[path.len]))
|
||||
oldpatient = patient
|
||||
soft_reset()
|
||||
return
|
||||
|
||||
if(path.len > 8 && patient)
|
||||
frustration++
|
||||
|
||||
if(auto_patrol && !stationary_mode && !patient)
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
|
||||
if(mode == BOT_PATROL)
|
||||
bot_patrol()
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/assess_patient(mob/living/carbon/C)
|
||||
//Time to see if they need medical help!
|
||||
if(C.stat == 2)
|
||||
return 0 //welp too late for them!
|
||||
|
||||
if(C.suiciding)
|
||||
return 0 //Kevorkian school of robotic medical assistants.
|
||||
|
||||
if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
|
||||
return 1
|
||||
|
||||
if((skin == "bezerk") && (!("syndicate" in C.faction)))
|
||||
return 0
|
||||
|
||||
if(declare_crit && C.health <= 0) //Critical condition! Call for help!
|
||||
declare(C)
|
||||
|
||||
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
|
||||
if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
return 1
|
||||
|
||||
//They're injured enough for it!
|
||||
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
|
||||
return 1 //If they're already medicated don't bother!
|
||||
|
||||
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
|
||||
return 1
|
||||
|
||||
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
|
||||
return 1
|
||||
|
||||
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_tox)))
|
||||
return 1
|
||||
|
||||
if(treat_virus && C.virus2.len && !C.reagents.has_reagent(treatment_virus))
|
||||
for (var/ID in C.virus2)
|
||||
if (ID in virusDB) // If the virus is known, the medbot is aware of it
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A)
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/C = A
|
||||
patient = C
|
||||
mode = BOT_HEALING
|
||||
update_icon()
|
||||
medicate_patient(C)
|
||||
update_icon()
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in view())
|
||||
..()
|
||||
if(!is_blind(src))
|
||||
chemscan(src, A)
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/medicate_patient(mob/living/carbon/C)
|
||||
if(!on)
|
||||
return
|
||||
|
||||
if(!istype(C))
|
||||
oldpatient = patient
|
||||
soft_reset()
|
||||
return
|
||||
|
||||
if(C.stat == 2)
|
||||
var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.")
|
||||
speak(death_message)
|
||||
oldpatient = patient
|
||||
soft_reset()
|
||||
return
|
||||
|
||||
var/reagent_id = null
|
||||
|
||||
if(emagged == 2) //Emagged! Time to poison everybody.
|
||||
reagent_id = "pancuronium"
|
||||
|
||||
else
|
||||
if(treat_virus)
|
||||
var/virus = 0
|
||||
if(C.virus2.len)
|
||||
for (var/ID in C.virus2)
|
||||
if (ID in virusDB) // If the virus is known, the medbot is aware of it and will try to cure it
|
||||
virus = 1
|
||||
|
||||
if (!reagent_id && (virus))
|
||||
if(!C.reagents.has_reagent(treatment_virus))
|
||||
reagent_id = treatment_virus
|
||||
|
||||
if(!reagent_id && (C.getBruteLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(treatment_brute))
|
||||
reagent_id = treatment_brute
|
||||
|
||||
if(!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
|
||||
if(!C.reagents.has_reagent(treatment_oxy))
|
||||
reagent_id = treatment_oxy
|
||||
|
||||
if(!reagent_id && (C.getFireLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(treatment_fire))
|
||||
reagent_id = treatment_fire
|
||||
|
||||
if(!reagent_id && (C.getToxLoss() >= heal_threshold))
|
||||
if(!C.reagents.has_reagent(treatment_tox))
|
||||
reagent_id = treatment_tox
|
||||
|
||||
//If the patient is injured but doesn't have our special reagent in them then we should give it to them first
|
||||
if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
|
||||
if(!C.reagents.has_reagent(R.id))
|
||||
reagent_id = "internal_beaker"
|
||||
break
|
||||
|
||||
if(!reagent_id) //If they don't need any of that they're probably cured!
|
||||
var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!")
|
||||
speak(message)
|
||||
bot_reset()
|
||||
return
|
||||
else
|
||||
if(!emagged && check_overdose(patient,reagent_id,injection_amount))
|
||||
soft_reset()
|
||||
return
|
||||
C.visible_message("<span class='danger'>[src] is trying to inject [patient]!</span>", \
|
||||
"<span class='userdanger'>[src] is trying to inject you!</span>")
|
||||
|
||||
spawn(30)//replace with do mob
|
||||
if((get_dist(src, patient) <= 1) && on && assess_patient(patient))
|
||||
if(reagent_id == "internal_beaker")
|
||||
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
|
||||
var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
|
||||
reagent_glass.reagents.reaction(patient, 2, fraction)
|
||||
reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead.
|
||||
else
|
||||
patient.reagents.add_reagent(reagent_id,injection_amount)
|
||||
C.visible_message("<span class='danger'>[src] injects [patient] with its syringe!</span>", \
|
||||
"<span class='userdanger'>[src] injects you with its syringe!</span>")
|
||||
else
|
||||
visible_message("[src] retracts its syringe.")
|
||||
update_icon()
|
||||
soft_reset()
|
||||
return
|
||||
|
||||
reagent_id = null
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount)
|
||||
var/datum/reagent/R = chemical_reagents_list[reagent_id]
|
||||
if(!R.overdose_threshold)
|
||||
return 0
|
||||
var/current_volume = patient.reagents.get_reagent_amount(reagent_id)
|
||||
if(current_volume + injection_amount > R.overdose_threshold)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/bullet_act(obj/item/projectile/Proj)
|
||||
if(Proj.flag == "taser")
|
||||
stunned = min(stunned+10,20)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/explode()
|
||||
on = 0
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
switch(skin)
|
||||
if("ointment")
|
||||
new /obj/item/weapon/storage/firstaid/fire/empty(Tsec)
|
||||
if("tox")
|
||||
new /obj/item/weapon/storage/firstaid/toxin/empty(Tsec)
|
||||
if("o2")
|
||||
new /obj/item/weapon/storage/firstaid/o2/empty(Tsec)
|
||||
if("brute")
|
||||
new /obj/item/weapon/storage/firstaid/brute/empty(Tsec)
|
||||
if("adv")
|
||||
new /obj/item/weapon/storage/firstaid/adv/empty(Tsec)
|
||||
if("bezerk")
|
||||
new /obj/item/weapon/storage/firstaid/tactical/empty(Tsec)
|
||||
if("fish")
|
||||
new /obj/item/weapon/storage/firstaid/aquatic_kit(Tsec)
|
||||
else
|
||||
new /obj/item/weapon/storage/firstaid(Tsec)
|
||||
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
|
||||
new /obj/item/device/healthanalyzer(Tsec)
|
||||
|
||||
if(reagent_glass)
|
||||
reagent_glass.forceMove(Tsec)
|
||||
reagent_glass = null
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/robot_parts/l_arm(Tsec)
|
||||
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/medbot/proc/declare(crit_patient)
|
||||
if(declare_cooldown)
|
||||
return
|
||||
if((skin == "bezerk"))
|
||||
return
|
||||
var/area/location = get_area(src)
|
||||
speak("Medical emergency! [crit_patient ? "<b>[crit_patient]</b>" : "A patient"] is in critical condition at [location]!", radio_channel)
|
||||
declare_cooldown = 1
|
||||
spawn(200) //Twenty seconds
|
||||
declare_cooldown = 0
|
||||
|
||||
/obj/machinery/bot_core/medbot
|
||||
req_one_access = list(access_medical, access_robotics)
|
||||
|
||||
/obj/machinery/bot_core/medbot/syndicate
|
||||
req_one_access = list(access_syndicate)
|
||||
@@ -0,0 +1,869 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
|
||||
|
||||
// Mulebot - carries crates around for Quartermaster
|
||||
// Navigates via floor navbeacons
|
||||
// Remote Controlled from QM's PDA
|
||||
|
||||
#define SIGH 0
|
||||
#define ANNOYED 1
|
||||
#define DELIGHT 2
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot
|
||||
name = "\improper MULEbot"
|
||||
desc = "A Multiple Utility Load Effector bot."
|
||||
icon_state = "mulebot0"
|
||||
density = 1
|
||||
anchored = 1
|
||||
animate_movement=1
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
a_intent = "harm" //No swapping
|
||||
buckle_lying = 0
|
||||
|
||||
radio_channel = "Supply"
|
||||
|
||||
bot_type = MULE_BOT
|
||||
bot_filter = RADIO_MULEBOT
|
||||
model = "MULE"
|
||||
bot_purpose = "deliver crates and other packages between departments, as requested"
|
||||
bot_core_type = /obj/machinery/bot_core/mulebot
|
||||
|
||||
suffix = ""
|
||||
|
||||
var/global/mulebot_count = 0
|
||||
var/atom/movable/load = null
|
||||
var/mob/living/passenger = null
|
||||
var/turf/target // this is turf to navigate to (location of beacon)
|
||||
var/loaddir = 0 // this the direction to unload onto/load from
|
||||
var/home_destination = "" // tag of home beacon
|
||||
|
||||
var/reached_target = 1 //true if already reached the target
|
||||
|
||||
var/auto_return = 1 // true if auto return to home beacon after unload
|
||||
var/auto_pickup = 1 // true if auto-pickup at beacon
|
||||
var/report_delivery = 1 // true if bot will announce an arrival to a location.
|
||||
|
||||
var/obj/item/weapon/stock_parts/cell/cell
|
||||
var/datum/wires/mulebot/wires = null
|
||||
var/bloodiness = 0
|
||||
var/currentBloodColor = "#A10808"
|
||||
var/currentDNA = null
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/New()
|
||||
..()
|
||||
wires = new /datum/wires/mulebot(src)
|
||||
var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
|
||||
access_card.access = J.get_access()
|
||||
prev_access = access_card.access
|
||||
cell = new(src)
|
||||
cell.charge = 2000
|
||||
cell.maxcharge = 2000
|
||||
|
||||
mulebot_count++
|
||||
set_suffix(suffix ? suffix : "#[mulebot_count]")
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Destroy()
|
||||
unload(0)
|
||||
if(wires)
|
||||
qdel(wires)
|
||||
wires = null
|
||||
if(cell)
|
||||
qdel(cell)
|
||||
cell = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/set_suffix(suffix)
|
||||
src.suffix = suffix
|
||||
if(paicard)
|
||||
bot_name = "\improper MULEbot ([suffix])"
|
||||
else
|
||||
name = "\improper MULEbot ([suffix])"
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bot_reset()
|
||||
..()
|
||||
reached_target = 0
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/screwdriver))
|
||||
..()
|
||||
if(open)
|
||||
on = FALSE
|
||||
update_controls()
|
||||
else if(istype(I,/obj/item/weapon/stock_parts/cell) && open && !cell)
|
||||
if(!user.drop_item())
|
||||
return
|
||||
var/obj/item/weapon/stock_parts/cell/C = I
|
||||
C.forceMove(src)
|
||||
cell = C
|
||||
visible_message("[user] inserts a cell into [src].",
|
||||
"<span class='notice'>You insert the new cell into [src].</span>")
|
||||
update_controls()
|
||||
else if(istype(I, /obj/item/weapon/crowbar) && open && cell)
|
||||
cell.add_fingerprint(usr)
|
||||
cell.forceMove(loc)
|
||||
cell = null
|
||||
visible_message("[user] crowbars out the power cell from [src].",
|
||||
"<span class='notice'>You pry the powercell out of [src].</span>")
|
||||
update_controls()
|
||||
else if (istype(I, /obj/item/weapon/wrench))
|
||||
if (health < maxHealth)
|
||||
adjustBruteLoss(-25)
|
||||
updatehealth()
|
||||
user.visible_message(
|
||||
"<span class='notice'>[user] repairs [src]!</span>",
|
||||
"<span class='notice'>You repair [src]!</span>"
|
||||
)
|
||||
else
|
||||
user << "<span class='notice'>[src] does not need a repair!</span>"
|
||||
else if((istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters)) && open)
|
||||
return attack_hand(user)
|
||||
else if(load && ismob(load)) // chance to knock off rider
|
||||
if(prob(1 + I.force * 2))
|
||||
unload(0)
|
||||
user.visible_message("<span class='danger'>[user] knocks [load] off [src] with \the [I]!</span>",
|
||||
"<span class='danger'>You knock [load] off [src] with \the [I]!</span>")
|
||||
else
|
||||
user << "<span class='warning'>You hit [src] with \the [I] but to no effect!</span>"
|
||||
..()
|
||||
else
|
||||
..()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/emag_act(mob/user)
|
||||
if(emagged < 1)
|
||||
emagged = 1
|
||||
if(!open)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>You [locked ? "lock" : "unlock"] the [src]'s controls!</span>"
|
||||
flick("mulebot-emagged", src)
|
||||
playsound(loc, 'sound/effects/sparks1.ogg', 100, 0)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/update_icon()
|
||||
if(open)
|
||||
icon_state="mulebot-hatch"
|
||||
else
|
||||
icon_state = "mulebot[!wires.MobAvoid()]"
|
||||
overlays.Cut()
|
||||
if(load && !ismob(load))//buckling handles the mob offsets
|
||||
load.pixel_y = initial(load.pixel_y) + 9
|
||||
if(load.layer < layer)
|
||||
load.layer = layer + 0.1
|
||||
overlays += load
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/ex_act(severity)
|
||||
unload(0)
|
||||
switch(severity)
|
||||
if(1)
|
||||
qdel(src)
|
||||
if(2)
|
||||
for(var/i = 1; i < 3; i++)
|
||||
wires.RandomCut()
|
||||
if(3)
|
||||
wires.RandomCut()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
|
||||
if(..())
|
||||
if(prob(50) && !isnull(load))
|
||||
unload(0)
|
||||
if(prob(25))
|
||||
visible_message("<span class='danger'>Something shorts out inside [src]!</span>")
|
||||
wires.RandomCut()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Topic(href, list/href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
switch(href_list["op"])
|
||||
if("lock")
|
||||
toggle_lock(usr)
|
||||
if("power")
|
||||
if(on)
|
||||
turn_off()
|
||||
else if(cell && !open)
|
||||
if(!turn_on())
|
||||
usr << "<span class='warning'>You can't switch on [src]!</span>"
|
||||
return
|
||||
else
|
||||
return
|
||||
visible_message("[usr] switches [on ? "on" : "off"] [src].")
|
||||
if("cellremove")
|
||||
if(open && cell && !usr.get_active_hand())
|
||||
cell.updateicon()
|
||||
usr.put_in_active_hand(cell)
|
||||
cell.add_fingerprint(usr)
|
||||
cell = null
|
||||
|
||||
usr.visible_message("<span class='notice'>[usr] removes the power cell from [src].</span>", "<span class='notice'>You remove the power cell from [src].</span>")
|
||||
if("cellinsert")
|
||||
if(open && !cell)
|
||||
var/obj/item/weapon/stock_parts/cell/C = usr.get_active_hand()
|
||||
if(istype(C))
|
||||
usr.drop_item()
|
||||
cell = C
|
||||
C.forceMove(src)
|
||||
C.add_fingerprint(usr)
|
||||
|
||||
usr.visible_message("<span class='notice'>[usr] inserts a power cell into [src].</span>", "<span class='notice'>You insert the power cell into [src].</span>")
|
||||
if("stop")
|
||||
if(mode >= BOT_DELIVER)
|
||||
bot_reset()
|
||||
if("go")
|
||||
if(mode == BOT_IDLE)
|
||||
start()
|
||||
if("home")
|
||||
if(mode == BOT_IDLE || mode == BOT_DELIVER)
|
||||
start_home()
|
||||
if("destination")
|
||||
var/new_dest = input(usr, "Enter Destination:", name, destination) as null|anything in deliverybeacontags
|
||||
if(new_dest)
|
||||
set_destination(new_dest)
|
||||
if("setid")
|
||||
var/new_id = stripped_input(usr, "Enter ID:", name, suffix, MAX_NAME_LEN)
|
||||
if(new_id)
|
||||
set_suffix(new_id)
|
||||
if("sethome")
|
||||
var/new_home = input(usr, "Enter Home:", name, home_destination) as null|anything in deliverybeacontags
|
||||
if(new_home)
|
||||
home_destination = new_home
|
||||
if("unload")
|
||||
if(load && mode != BOT_HUNT)
|
||||
if(loc == target)
|
||||
unload(loaddir)
|
||||
else
|
||||
unload(0)
|
||||
if("autoret")
|
||||
auto_return = !auto_return
|
||||
if("autopick")
|
||||
auto_pickup = !auto_pickup
|
||||
if("report")
|
||||
report_delivery = !report_delivery
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/toggle_lock(var/mob/user)
|
||||
if(bot_core.allowed(user))
|
||||
locked = !locked
|
||||
update_controls()
|
||||
return 1
|
||||
else
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
return 0
|
||||
|
||||
// TODO: remove this; PDAs currently depend on it
|
||||
/mob/living/simple_animal/bot/mulebot/get_controls(mob/user)
|
||||
var/ai = issilicon(user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += "<h3>Multiple Utility Load Effector Mk. V</h3>"
|
||||
dat += "<b>ID:</b> [suffix]<BR>"
|
||||
dat += "<b>Power:</b> [on ? "On" : "Off"]<BR>"
|
||||
|
||||
if(!open)
|
||||
dat += "<h3>Status</h3>"
|
||||
dat += "<div class='statusDisplay'>"
|
||||
switch(mode)
|
||||
if(BOT_IDLE)
|
||||
dat += "<span class='good'>Ready</span>"
|
||||
if(BOT_DELIVER)
|
||||
dat += "<span class='good'>[mode_name[BOT_DELIVER]]</span>"
|
||||
if(BOT_GO_HOME)
|
||||
dat += "<span class='good'>[mode_name[BOT_GO_HOME]]</span>"
|
||||
if(BOT_BLOCKED)
|
||||
dat += "<span class='average'>[mode_name[BOT_BLOCKED]]</span>"
|
||||
if(BOT_NAV,BOT_WAIT_FOR_NAV)
|
||||
dat += "<span class='average'>[mode_name[BOT_NAV]]</span>"
|
||||
if(BOT_NO_ROUTE)
|
||||
dat += "<span class='bad'>[mode_name[BOT_NO_ROUTE]]</span>"
|
||||
dat += "</div>"
|
||||
|
||||
dat += "<b>Current Load:</b> [load ? load.name : "<i>none</i>"]<BR>"
|
||||
dat += "<b>Destination:</b> [!destination ? "<i>none</i>" : destination]<BR>"
|
||||
dat += "<b>Power level:</b> [cell ? cell.percent() : 0]%"
|
||||
|
||||
if(locked && !ai && !check_rights(R_ADMIN, 0, user))
|
||||
dat += " <br /><div class='notice'>Controls are locked</div><A href='?src=\ref[src];op=unlock'>Unlock Controls</A>"
|
||||
else
|
||||
dat += " <br /><div class='notice'>Controls are unlocked</div><A href='?src=\ref[src];op=lock'>Lock Controls</A><BR><BR>"
|
||||
|
||||
dat += "<A href='?src=\ref[src];op=power'>Toggle Power</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=stop'>Stop</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=go'>Proceed</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=home'>Return to Home</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=destination'>Set Destination</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=setid'>Set Bot ID</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=sethome'>Set Home</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];op=autoret'>Toggle Auto Return Home</A> ([auto_return ? "On":"Off"])<BR>"
|
||||
dat += "<A href='?src=\ref[src];op=autopick'>Toggle Auto Pickup Crate</A> ([auto_pickup ? "On":"Off"])<BR>"
|
||||
dat += "<A href='?src=\ref[src];op=report'>Toggle Delivery Reporting</A> ([report_delivery ? "On" : "Off"])<BR>"
|
||||
if(load)
|
||||
dat += "<A href='?src=\ref[src];op=unload'>Unload Now</A><BR>"
|
||||
dat += "<div class='notice'>The maintenance hatch is closed.</div>"
|
||||
else
|
||||
if(!ai)
|
||||
dat += "<div class='notice'>The maintenance hatch is open.</div><BR>"
|
||||
dat += "<b>Power cell:</b> "
|
||||
if(cell)
|
||||
dat += "<A href='?src=\ref[src];op=cellremove'>Installed</A><BR>"
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];op=cellinsert'>Removed</A><BR>"
|
||||
|
||||
dat += wires.GetInteractWindow()
|
||||
else
|
||||
dat += "<div class='notice'>The bot is in maintenance mode and cannot be controlled.</div><BR>"
|
||||
|
||||
return dat
|
||||
|
||||
|
||||
// returns true if the bot has power
|
||||
/mob/living/simple_animal/bot/mulebot/proc/has_power()
|
||||
return !open && cell && cell.charge > 0 && wires.HasPower()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
|
||||
switch(type)
|
||||
if(SIGH)
|
||||
audible_message("[src] makes a sighing buzz.", "<span class='emote'>You hear an electronic buzzing sound.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
if(ANNOYED)
|
||||
audible_message("[src] makes an annoyed buzzing sound.", "<span class='emote'>You hear an electronic buzzing sound.</span>")
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
if(DELIGHT)
|
||||
audible_message("[src] makes a delighted ping!", "<span class='emote'>You hear a ping.</span>")
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
||||
|
||||
|
||||
// mousedrop a crate to load the bot
|
||||
// can load anything if hacked
|
||||
/mob/living/simple_animal/bot/mulebot/MouseDrop_T(atom/movable/AM, mob/user)
|
||||
|
||||
if(user.incapacitated() || user.lying || get_dist(user, src) > 1)
|
||||
return
|
||||
|
||||
if(!istype(AM))
|
||||
return
|
||||
|
||||
load(AM)
|
||||
|
||||
// called to load a crate
|
||||
/mob/living/simple_animal/bot/mulebot/proc/load(atom/movable/AM)
|
||||
if(!on || load || AM.anchored || get_dist(src, AM) > 1)
|
||||
return
|
||||
|
||||
|
||||
//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(AM, /obj/item) && !istype(AM, /obj/machinery) && !istype(AM, /obj/structure) && !ismob(AM))
|
||||
return
|
||||
if(!isturf(AM.loc)) //To prevent the loading from stuff from someone's inventory or screen icons.
|
||||
return
|
||||
|
||||
var/obj/structure/closet/crate/CRATE
|
||||
if(istype(AM,/obj/structure/closet/crate))
|
||||
CRATE = AM
|
||||
else
|
||||
if(wires.LoadCheck())
|
||||
buzz(SIGH)
|
||||
return // if not hacked, only allow crates to be loaded
|
||||
|
||||
if(CRATE) // if it's a crate, close before loading
|
||||
CRATE.close()
|
||||
|
||||
if(isobj(AM))
|
||||
var/obj/O = AM
|
||||
if(O.buckled_mob || (locate(/mob) in AM)) //can't load non crates objects with mobs buckled to it or inside it.
|
||||
buzz(SIGH)
|
||||
return
|
||||
|
||||
if(isliving(AM))
|
||||
if(!load_mob(AM))
|
||||
return
|
||||
else
|
||||
AM.forceMove(src)
|
||||
|
||||
load = AM
|
||||
mode = BOT_IDLE
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/load_mob(mob/living/M)
|
||||
can_buckle = TRUE
|
||||
if(buckle_mob(M))
|
||||
passenger = M
|
||||
load = M
|
||||
can_buckle = FALSE
|
||||
if(M.client)
|
||||
M.client.perspective = EYE_PERSPECTIVE
|
||||
M.client.eye = src
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/post_buckle_mob(mob/living/M)
|
||||
if(M == buckled_mob) //post buckling
|
||||
M.pixel_y = initial(M.pixel_y) + 9
|
||||
if(M.layer < layer)
|
||||
M.layer = layer + 0.1
|
||||
|
||||
else //post unbuckling
|
||||
load = null
|
||||
M.layer = initial(M.layer)
|
||||
M.pixel_y = initial(M.pixel_y)
|
||||
|
||||
// called to unload the bot
|
||||
// argument is optional direction to unload
|
||||
// if zero, unload at bot's location
|
||||
/mob/living/simple_animal/bot/mulebot/proc/unload(dirn)
|
||||
if(!load)
|
||||
return
|
||||
|
||||
mode = BOT_IDLE
|
||||
|
||||
overlays.Cut()
|
||||
|
||||
if(ismob(load))
|
||||
var/mob/M = load
|
||||
if(M.client)
|
||||
M.client.perspective = MOB_PERSPECTIVE
|
||||
M.client.eye = M
|
||||
unbuckle_mob()
|
||||
|
||||
if(load)
|
||||
load.forceMove(loc)
|
||||
load.pixel_y = initial(load.pixel_y)
|
||||
load.layer = initial(load.layer)
|
||||
if(dirn)
|
||||
var/turf/T = loc
|
||||
var/turf/newT = get_step(T,dirn)
|
||||
if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally
|
||||
step(load, dirn)
|
||||
load = null
|
||||
|
||||
// in case non-load items end up in contents, dump every else too
|
||||
// this seems to happen sometimes due to race conditions
|
||||
// with items dropping as mobs are loaded
|
||||
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM == cell || AM == access_card || AM == Radio || AM == bot_core || AM == paicard)
|
||||
continue
|
||||
|
||||
AM.forceMove(loc)
|
||||
AM.layer = initial(AM.layer)
|
||||
AM.pixel_y = initial(AM.pixel_y)
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
if(M.client)
|
||||
M.client.perspective = MOB_PERSPECTIVE
|
||||
M.client.eye = M
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/call_bot()
|
||||
..()
|
||||
var/area/dest_area
|
||||
if(path && path.len)
|
||||
target = ai_waypoint //Target is the end point of the path, the waypoint set by the AI.
|
||||
dest_area = get_area(target)
|
||||
destination = format_text(dest_area.name)
|
||||
pathset = 1 //Indicates the AI's custom path is initialized.
|
||||
start()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/handle_automated_action()
|
||||
diag_hud_set_botmode()
|
||||
|
||||
if(!has_power())
|
||||
on = 0
|
||||
return
|
||||
if(on)
|
||||
var/speed = (wires.Motor1() ? 1 : 0) + (wires.Motor2() ? 2 : 0)
|
||||
//world << "speed: [speed]"
|
||||
var/num_steps = 0
|
||||
switch(speed)
|
||||
if(0)
|
||||
// do nothing
|
||||
if(1)
|
||||
num_steps = 10
|
||||
if(2)
|
||||
num_steps = 5
|
||||
if(3)
|
||||
num_steps = 3
|
||||
|
||||
if(num_steps)
|
||||
process_bot()
|
||||
num_steps--
|
||||
if(mode != BOT_IDLE)
|
||||
spawn(0)
|
||||
for(var/i=num_steps,i>0,i--)
|
||||
sleep(2)
|
||||
process_bot()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/proc/process_bot()
|
||||
if(!on)
|
||||
return
|
||||
update_icon()
|
||||
|
||||
switch(mode)
|
||||
if(BOT_IDLE) // idle
|
||||
return
|
||||
|
||||
if(BOT_DELIVER, BOT_GO_HOME, BOT_BLOCKED) // navigating to deliver,home, or blocked
|
||||
if(loc == target) // reached target
|
||||
at_target()
|
||||
return
|
||||
|
||||
else if(path.len > 0 && target) // valid path
|
||||
var/turf/next = path[1]
|
||||
reached_target = 0
|
||||
if(next == loc)
|
||||
path -= next
|
||||
return
|
||||
if(istype(next, /turf/simulated))
|
||||
//world << "at ([x],[y]) moving to ([next.x],[next.y])"
|
||||
|
||||
var/oldloc = loc
|
||||
var/moved = step_towards(src, next) // attempt to move
|
||||
if(cell) cell.use(1)
|
||||
if(moved && oldloc!=loc) // successful move
|
||||
//world << "Successful move."
|
||||
blockcount = 0
|
||||
path -= loc
|
||||
|
||||
if(destination == home_destination)
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
mode = BOT_DELIVER
|
||||
|
||||
else // failed to move
|
||||
|
||||
//world << "Unable to move."
|
||||
blockcount++
|
||||
mode = BOT_BLOCKED
|
||||
if(blockcount == 3)
|
||||
buzz(ANNOYED)
|
||||
|
||||
if(blockcount > 10) // attempt 10 times before recomputing
|
||||
// find new path excluding blocked turf
|
||||
buzz(SIGH)
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
blockcount = 0
|
||||
spawn(20)
|
||||
calc_path(avoid=next)
|
||||
if(path.len > 0)
|
||||
buzz(DELIGHT)
|
||||
mode = BOT_BLOCKED
|
||||
return
|
||||
return
|
||||
else
|
||||
buzz(ANNOYED)
|
||||
//world << "Bad turf."
|
||||
mode = BOT_NAV
|
||||
return
|
||||
else
|
||||
//world << "No path."
|
||||
mode = BOT_NAV
|
||||
return
|
||||
|
||||
if(BOT_NAV) // calculate new path
|
||||
//world << "Calc new path."
|
||||
mode = BOT_WAIT_FOR_NAV
|
||||
spawn(0)
|
||||
calc_path()
|
||||
|
||||
if(path.len > 0)
|
||||
blockcount = 0
|
||||
mode = BOT_BLOCKED
|
||||
buzz(DELIGHT)
|
||||
|
||||
else
|
||||
buzz(SIGH)
|
||||
|
||||
mode = BOT_NO_ROUTE
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/Move(turf/simulated/next)
|
||||
var/turf/simulated/last = loc
|
||||
|
||||
if(istype(last) && bloodiness)
|
||||
last.AddTracks(/obj/effect/decal/cleanable/blood/tracks/wheels, currentDNA, 0, get_dir(last, next), currentBloodColor)
|
||||
|
||||
. = ..()
|
||||
|
||||
if(. && istype(next) && bloodiness)
|
||||
next.AddTracks(/obj/effect/decal/cleanable/blood/tracks/wheels, currentDNA, get_dir(last, next), 0, currentBloodColor)
|
||||
bloodiness--
|
||||
|
||||
// calculates a path to the current destination
|
||||
// given an optional turf to avoid
|
||||
/mob/living/simple_animal/bot/mulebot/calc_path(turf/avoid = null)
|
||||
check_bot_access()
|
||||
path = get_path_to(src, target, /turf/proc/Distance_cardinal, 0, 250, id=access_card, exclude=avoid)
|
||||
|
||||
// sets the current destination
|
||||
// signals all beacons matching the delivery code
|
||||
// beacons will return a signal giving their locations
|
||||
/mob/living/simple_animal/bot/mulebot/proc/set_destination(new_dest)
|
||||
new_destination = new_dest
|
||||
get_nav()
|
||||
|
||||
// starts bot moving to current destination
|
||||
/mob/living/simple_animal/bot/mulebot/proc/start()
|
||||
if(!on)
|
||||
return
|
||||
if(destination == home_destination)
|
||||
mode = BOT_GO_HOME
|
||||
else
|
||||
mode = BOT_DELIVER
|
||||
update_icon()
|
||||
get_nav()
|
||||
|
||||
// starts bot moving to home
|
||||
// sends a beacon query to find
|
||||
/mob/living/simple_animal/bot/mulebot/proc/start_home()
|
||||
if(!on)
|
||||
return
|
||||
spawn(0)
|
||||
set_destination(home_destination)
|
||||
mode = BOT_BLOCKED
|
||||
update_icon()
|
||||
|
||||
// called when bot reaches current target
|
||||
/mob/living/simple_animal/bot/mulebot/proc/at_target()
|
||||
if(!reached_target)
|
||||
radio_channel = "Supply" //Supply channel
|
||||
audible_message("[src] makes a chiming sound!", "<span class='emote'>You hear a chime.</span>")
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
|
||||
reached_target = 1
|
||||
|
||||
if(pathset) //The AI called us here, so notify it of our arrival.
|
||||
loaddir = dir //The MULE will attempt to load a crate in whatever direction the MULE is "facing".
|
||||
if(calling_ai)
|
||||
calling_ai << "<span class='notice'>\icon[src] [src] wirelessly plays a chiming sound!</span>"
|
||||
playsound(calling_ai, 'sound/machines/chime.ogg',40, 0)
|
||||
calling_ai = null
|
||||
radio_channel = "AI Private" //Report on AI Private instead if the AI is controlling us.
|
||||
|
||||
if(load) // if loaded, unload at target
|
||||
if(report_delivery)
|
||||
speak("Destination <b>[destination]</b> reached. Unloading [load].", radio_channel)
|
||||
if(istype(load, /obj/structure/closet/crate))
|
||||
var/obj/structure/closet/crate/C = load
|
||||
C.notifyRecipient(destination)
|
||||
unload(loaddir)
|
||||
else
|
||||
// not loaded
|
||||
if(auto_pickup) // find a crate
|
||||
var/atom/movable/AM
|
||||
if(wires.LoadCheck()) // if hacked, load first unanchored thing we find
|
||||
for(var/atom/movable/A in get_step(loc, loaddir))
|
||||
if(!A.anchored)
|
||||
AM = A
|
||||
break
|
||||
else // otherwise, look for crates only
|
||||
AM = locate(/obj/structure/closet/crate) in get_step(loc,loaddir)
|
||||
if(AM && AM.Adjacent(src))
|
||||
load(AM)
|
||||
if(report_delivery)
|
||||
speak("Now loading [load] at <b>[get_area(src)]</b>.", radio_channel)
|
||||
// whatever happened, check to see if we return home
|
||||
|
||||
if(auto_return && home_destination && destination != home_destination)
|
||||
// auto return set and not at home already
|
||||
start_home()
|
||||
mode = BOT_BLOCKED
|
||||
else
|
||||
bot_reset() // otherwise go idle
|
||||
|
||||
return
|
||||
|
||||
// called when bot bumps into anything
|
||||
/mob/living/simple_animal/bot/mulebot/Bump(atom/obs)
|
||||
if(!wires.MobAvoid()) // usually just bumps, but if avoidance disabled knock over mobs
|
||||
var/mob/M = obs
|
||||
if(ismob(M))
|
||||
if(istype(M,/mob/living/silicon/robot))
|
||||
visible_message("<span class='danger'>[src] bumps into [M]!</span>")
|
||||
else
|
||||
add_logs(src, M, "knocked down")
|
||||
visible_message("<span class='danger'>[src] knocks over [M]!</span>")
|
||||
M.stop_pulling()
|
||||
M.Stun(8)
|
||||
M.Weaken(5)
|
||||
return ..()
|
||||
|
||||
// called from mob/living/carbon/human/Crossed()
|
||||
// when mulebot is in the same loc
|
||||
/mob/living/simple_animal/bot/mulebot/proc/RunOver(mob/living/carbon/human/H)
|
||||
add_logs(src, H, "run over", null, "(DAMTYPE: [uppertext(BRUTE)])")
|
||||
H.visible_message("<span class='danger'>[src] drives over [H]!</span>", \
|
||||
"<span class='userdanger'>[src] drives over you!<span>")
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
var/damage = rand(5,15)
|
||||
H.apply_damage(2*damage, BRUTE, "head", run_armor_check("head", "melee"))
|
||||
H.apply_damage(2*damage, BRUTE, "chest", run_armor_check("chest", "melee"))
|
||||
H.apply_damage(0.5*damage, BRUTE, "l_leg", run_armor_check("l_leg", "melee"))
|
||||
H.apply_damage(0.5*damage, BRUTE, "r_leg", run_armor_check("r_leg", "melee"))
|
||||
H.apply_damage(0.5*damage, BRUTE, "l_arm", run_armor_check("l_arm", "melee"))
|
||||
H.apply_damage(0.5*damage, BRUTE, "r_arm", run_armor_check("r_arm", "melee"))
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/B = new(loc)
|
||||
B.blood_DNA = list()
|
||||
B.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type
|
||||
currentDNA = B.blood_DNA
|
||||
|
||||
bloodiness += 4
|
||||
|
||||
currentBloodColor = "#A10808"
|
||||
if(istype(H))
|
||||
var/datum/reagent/blood/bld = H.get_blood(H.vessel)
|
||||
if(bld.data["blood_colour"])
|
||||
currentBloodColor = bld.data["blood_colour"]
|
||||
return
|
||||
B.basecolor = currentBloodColor
|
||||
B.update_icon()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/bot_control_message(command, mob/user, user_turf)
|
||||
switch(command)
|
||||
if("start")
|
||||
if(load)
|
||||
src << "<span class='warning big'>DELIVER [load] TO [destination]</span>"
|
||||
else
|
||||
src << "<span class='warning big'>PICK UP DELIVERY AT [destination]</span>"
|
||||
if("unload")
|
||||
if(load)
|
||||
src << "<span class='warning big'>UNLOAD</span>"
|
||||
else
|
||||
src << "<span class='warning big'>LOAD</span>"
|
||||
if("autoret", "autopick", "target")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/receive_signal(datum/signal/signal)
|
||||
if(!wires.RemoteRX() || ..())
|
||||
return 1
|
||||
|
||||
var/recv = signal.data["command"]
|
||||
|
||||
// process control input
|
||||
switch(recv)
|
||||
if("start")
|
||||
start()
|
||||
|
||||
if("target")
|
||||
set_destination(signal.data["destination"])
|
||||
|
||||
if("unload")
|
||||
if(client)
|
||||
return 1
|
||||
if(loc == target)
|
||||
unload(loaddir)
|
||||
else
|
||||
unload(0)
|
||||
|
||||
if("home")
|
||||
start_home()
|
||||
|
||||
if("autoret")
|
||||
auto_return = text2num(signal.data["value"])
|
||||
|
||||
if("autopick")
|
||||
auto_pickup = text2num(signal.data["value"])
|
||||
|
||||
else
|
||||
return 0
|
||||
return 1
|
||||
|
||||
// send a radio signal with multiple data key/values
|
||||
/mob/living/simple_animal/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
|
||||
if(!wires.RemoteTX())
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
// signals bot status etc. to controller
|
||||
/mob/living/simple_animal/bot/mulebot/send_status()
|
||||
var/list/kv = list(
|
||||
"type" = MULE_BOT,
|
||||
"name" = suffix,
|
||||
"loca" = get_area(src),
|
||||
"mode" = mode,
|
||||
"powr" = (cell ? cell.percent() : 0),
|
||||
"dest" = destination,
|
||||
"home" = home_destination,
|
||||
"load" = load,
|
||||
"retn" = auto_return,
|
||||
"pick" = auto_pickup,
|
||||
)
|
||||
post_signal_multiple(control_freq, kv)
|
||||
|
||||
// player on mulebot attempted to move
|
||||
/mob/living/simple_animal/bot/mulebot/relaymove(mob/user)
|
||||
if(user.incapacitated())
|
||||
return
|
||||
if(load == user)
|
||||
unload(0)
|
||||
|
||||
|
||||
//Update navigation data. Called when commanded to deliver, return home, or a route update is needed...
|
||||
/mob/living/simple_animal/bot/mulebot/proc/get_nav()
|
||||
if(!on || !wires.BeaconRX())
|
||||
return
|
||||
|
||||
for(var/obj/machinery/navbeacon/NB in deliverybeacons)
|
||||
if(NB.location == new_destination) // if the beacon location matches the set destination
|
||||
destination = new_destination // the we will navigate there
|
||||
target = NB.loc
|
||||
var/direction = NB.dir // this will be the load/unload dir
|
||||
loaddir = direction
|
||||
update_icon()
|
||||
calc_path()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/emp_act(severity)
|
||||
if(cell)
|
||||
cell.emp_act(severity)
|
||||
if(load)
|
||||
load.emp_act(severity)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/explode()
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
new /obj/item/stack/rods(Tsec)
|
||||
new /obj/item/stack/rods(Tsec)
|
||||
new /obj/item/stack/cable_coil/cut(Tsec)
|
||||
if(cell)
|
||||
cell.forceMove(Tsec)
|
||||
cell.update_icon()
|
||||
cell = null
|
||||
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/blood/oil(loc)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/remove_air(amount) //To prevent riders suffocating
|
||||
if(loc)
|
||||
return loc.remove_air(amount)
|
||||
else
|
||||
return null
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/resist()
|
||||
..()
|
||||
if(load)
|
||||
unload()
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/UnarmedAttack(atom/A)
|
||||
if(isturf(A) && isturf(loc) && loc.Adjacent(A) && load)
|
||||
unload(get_dir(loc, A))
|
||||
else
|
||||
..()
|
||||
|
||||
#undef SIGH
|
||||
#undef ANNOYED
|
||||
#undef DELIGHT
|
||||
|
||||
/obj/machinery/bot_core/mulebot
|
||||
req_access = list(access_cargo)
|
||||
@@ -0,0 +1,462 @@
|
||||
/mob/living/simple_animal/bot/secbot
|
||||
name = "\improper Securitron"
|
||||
desc = "A little security robot. He looks less than thrilled."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "secbot0"
|
||||
density = 0
|
||||
anchored = 0
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
pass_flags = PASSMOB
|
||||
|
||||
radio_channel = "Security" //Security channel
|
||||
bot_type = SEC_BOT
|
||||
bot_filter = RADIO_SECBOT
|
||||
model = "Securitron"
|
||||
bot_purpose = "seek out criminals, handcuff them, and report their location to security"
|
||||
bot_core_type = /obj/machinery/bot_core/secbot
|
||||
window_id = "autosec"
|
||||
window_name = "Automatic Security Unit v1.6"
|
||||
|
||||
var/base_icon = "secbot"
|
||||
var/mob/living/carbon/target
|
||||
var/oldtarget_name
|
||||
var/threatlevel = 0
|
||||
var/target_lastloc //Loc of target when arrested.
|
||||
var/last_found //There's a delay
|
||||
var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
|
||||
var/idcheck = 0 //If true, arrest people with no IDs
|
||||
var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
|
||||
var/check_records = 1 //Does it check security records?
|
||||
var/arrest_type = 0 //If true, don't handcuff
|
||||
var/harmbaton = 0 //If true, beat instead of stun
|
||||
var/flashing_lights = 0 //If true, flash lights
|
||||
var/prev_flashing_lights = 0
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky
|
||||
name = "Officer Beep O'sky"
|
||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||
idcheck = 0
|
||||
weaponscheck = 0
|
||||
auto_patrol = 1
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/beepsky/explode()
|
||||
var/turf/Tsec = get_turf(src)
|
||||
new /obj/item/weapon/stock_parts/cell/potato(Tsec)
|
||||
var/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/S = new(Tsec)
|
||||
S.reagents.add_reagent("whiskey", 15)
|
||||
S.on_reagent_change()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/pingsky
|
||||
name = "Officer Pingsky"
|
||||
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
|
||||
radio_channel = "AI Private"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/ofitser
|
||||
name = "Prison Ofitser"
|
||||
desc = "It's Prison Ofitser! Powered by the tears and sweat of prisoners."
|
||||
idcheck = 0
|
||||
weaponscheck = 1
|
||||
auto_patrol = 1
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/buzzsky
|
||||
name = "Officer Buzzsky"
|
||||
desc = "It's Officer Buzzsky! Rusted and falling apart, he seems less than thrilled with the crew for leaving him in his current state."
|
||||
base_icon = "rustbot"
|
||||
icon_state = "rustbot0"
|
||||
declare_arrests = 0
|
||||
arrest_type = 1
|
||||
harmbaton = 1
|
||||
emagged = 2
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/New()
|
||||
..()
|
||||
icon_state = "[base_icon][on]"
|
||||
spawn(3)
|
||||
var/datum/job/detective/J = new/datum/job/detective
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
//SECHUD
|
||||
var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
secsensor.add_hud_to(src)
|
||||
permanent_huds |= secsensor
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/turn_on()
|
||||
..()
|
||||
icon_state = "[base_icon][on]"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/turn_off()
|
||||
..()
|
||||
icon_state = "[base_icon][on]"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
anchored = 0
|
||||
walk_to(src,0)
|
||||
last_found = world.time
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/set_custom_texts()
|
||||
|
||||
text_hack = "You overload [name]'s target identification system."
|
||||
text_dehack = "You reboot [name] and restore the target identification."
|
||||
text_dehack_fail = "[name] refuses to accept your authority!"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
dat += showpai(user)
|
||||
dat += text({"
|
||||
<TT><B>Securitron v1.6 controls</B></TT><BR><BR>
|
||||
Status: []<BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"},
|
||||
|
||||
"<A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A>" )
|
||||
|
||||
if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user))
|
||||
dat += text({"<BR>
|
||||
Arrest Unidentifiable Persons: []<BR>
|
||||
Arrest for Unauthorized Weapons: []<BR>
|
||||
Arrest for Warrant: []<BR>
|
||||
Operating Mode: []<BR>
|
||||
Report Arrests[]<BR>
|
||||
Auto Patrol: []"},
|
||||
|
||||
"<A href='?src=\ref[src];operation=idcheck'>[idcheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=weaponscheck'>[weaponscheck ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=ignorerec'>[check_records ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A>",
|
||||
"<A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A>",
|
||||
"<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
|
||||
|
||||
return dat
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
switch(href_list["operation"])
|
||||
if("idcheck")
|
||||
idcheck = !idcheck
|
||||
update_controls()
|
||||
if("weaponscheck")
|
||||
weaponscheck = !weaponscheck
|
||||
update_controls()
|
||||
if("ignorerec")
|
||||
check_records = !check_records
|
||||
update_controls()
|
||||
if("switchmode")
|
||||
arrest_type = !arrest_type
|
||||
update_controls()
|
||||
if("declarearrests")
|
||||
declare_arrests = !declare_arrests
|
||||
update_controls()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
|
||||
threatlevel = H.assess_threat(src)
|
||||
threatlevel += 6
|
||||
if(threatlevel >= 4)
|
||||
target = H
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == "harm")
|
||||
retaliate(H)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
|
||||
return
|
||||
if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
|
||||
retaliate(user)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
|
||||
..()
|
||||
if(emagged == 2)
|
||||
if(user)
|
||||
user << "<span class='danger'>You short out [src]'s target assessment circuits.</span>"
|
||||
oldtarget_name = user.name
|
||||
audible_message("<span class='danger'>[src] buzzes oddly!</span>")
|
||||
declare_arrests = 0
|
||||
icon_state = "[base_icon][on]"
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
|
||||
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
|
||||
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
|
||||
if(!Proj.nodamage && Proj.damage < src.health)
|
||||
retaliate(Proj.firer)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
|
||||
if(!on)
|
||||
return
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/C = A
|
||||
if(!C.stunned || arrest_type)
|
||||
stun_attack(A)
|
||||
else if(C.canBeHandcuffed() && !C.handcuffed)
|
||||
cuff(A)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/I = AM
|
||||
if(I.throwforce < src.health && I.thrower && (istype(I.thrower, /mob/living/carbon/human)))
|
||||
var/mob/living/carbon/human/H = I.thrower
|
||||
retaliate(H)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
|
||||
mode = BOT_ARREST
|
||||
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
|
||||
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
|
||||
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
|
||||
spawn(60)
|
||||
if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
|
||||
return
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
|
||||
C.update_inv_handcuffed(1)
|
||||
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
|
||||
back_to_idle()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
if(harmbaton)
|
||||
playsound(loc, 'sound/weapons/genhit1.ogg', 50, 1, -1)
|
||||
icon_state = "[base_icon]-c"
|
||||
spawn(2)
|
||||
icon_state = "[base_icon][on]"
|
||||
var/threat = 5
|
||||
if(istype(C, /mob/living/carbon/human))
|
||||
C.stuttering = 5
|
||||
if(harmbaton) // Bots with harmbaton enabled become shitcurity. - Dave
|
||||
C.apply_damage(10, BRUTE)
|
||||
C.Stun(5)
|
||||
C.Weaken(5)
|
||||
var/mob/living/carbon/human/H = C
|
||||
threat = H.assess_threat(src)
|
||||
else
|
||||
C.Weaken(5)
|
||||
C.stuttering = 5
|
||||
C.Stun(5)
|
||||
add_logs(src,C,"stunned")
|
||||
if(declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
|
||||
C.visible_message("<span class='danger'>[src] has [harmbaton ? "beaten" : "stunned"] [C]!</span>",\
|
||||
"<span class='userdanger'>[src] has [harmbaton ? "beaten" : "stunned"] you!</span>")
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Life()
|
||||
. = ..()
|
||||
if(flashing_lights)
|
||||
switch(light_color)
|
||||
if(LIGHT_COLOR_PURE_RED)
|
||||
light_color = LIGHT_COLOR_PURE_BLUE
|
||||
if(LIGHT_COLOR_PURE_BLUE)
|
||||
light_color = LIGHT_COLOR_PURE_RED
|
||||
update_light()
|
||||
else if(prev_flashing_lights)
|
||||
light_color = LIGHT_COLOR_PURE_RED
|
||||
update_light()
|
||||
|
||||
prev_flashing_lights = flashing_lights
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/verb/toggle_flashing_lights()
|
||||
set name = "Toggle Flashing Lights"
|
||||
set category = "Object"
|
||||
set src = usr
|
||||
|
||||
flashing_lights = !flashing_lights
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
flashing_lights = mode == BOT_HUNT
|
||||
|
||||
switch(mode)
|
||||
if(BOT_IDLE) // idle
|
||||
walk_to(src,0)
|
||||
look_for_perp() // see if any criminals are in range
|
||||
if(!mode && auto_patrol) // still idle, and set to patrol
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(BOT_HUNT) // hunting for perp
|
||||
// if can't reach perp for long enough, go idle
|
||||
if(frustration >= 8)
|
||||
walk_to(src,0)
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(target) // make sure target exists
|
||||
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
|
||||
stun_attack(target)
|
||||
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 1
|
||||
target_lastloc = target.loc
|
||||
return
|
||||
|
||||
else // not next to perp
|
||||
var/turf/olddist = get_dist(src, target)
|
||||
walk_to(src, target,1,4)
|
||||
if((get_dist(src, target)) >= (olddist))
|
||||
frustration++
|
||||
else
|
||||
frustration = 0
|
||||
else
|
||||
back_to_idle()
|
||||
|
||||
if(BOT_PREP_ARREST) // preparing to arrest target
|
||||
// see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
|
||||
if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
|
||||
back_to_hunt()
|
||||
return
|
||||
|
||||
if(iscarbon(target) && target.canBeHandcuffed())
|
||||
if(!arrest_type)
|
||||
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
|
||||
cuff(target)
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
else
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(BOT_ARREST)
|
||||
if(!target)
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
return
|
||||
|
||||
if(target.handcuffed) //no target or target cuffed? back to idle.
|
||||
back_to_idle()
|
||||
return
|
||||
|
||||
if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
|
||||
back_to_hunt()
|
||||
return
|
||||
else //Try arresting again if the target escapes.
|
||||
mode = BOT_PREP_ARREST
|
||||
anchored = 0
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_perp()
|
||||
start_patrol()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_perp()
|
||||
bot_patrol()
|
||||
|
||||
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
|
||||
anchored = 0
|
||||
mode = BOT_IDLE
|
||||
target = null
|
||||
last_found = world.time
|
||||
frustration = 0
|
||||
spawn(0)
|
||||
handle_automated_action() //ensure bot quickly responds
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
|
||||
anchored = 0
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
handle_automated_action() //ensure bot quickly responds
|
||||
// look for a criminal in view of the bot
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
|
||||
anchored = 0
|
||||
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
|
||||
if((C.stat) || (C.handcuffed))
|
||||
continue
|
||||
|
||||
if((C.name == oldtarget_name) && (world.time < last_found + 100))
|
||||
continue
|
||||
|
||||
threatlevel = C.assess_threat(src)
|
||||
|
||||
if(!threatlevel)
|
||||
continue
|
||||
|
||||
else if(threatlevel >= 4)
|
||||
target = C
|
||||
oldtarget_name = C.name
|
||||
speak("Level [threatlevel] infraction alert!")
|
||||
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
|
||||
visible_message("<b>[src]</b> points at [C.name]!")
|
||||
mode = BOT_HUNT
|
||||
spawn(0)
|
||||
handle_automated_action() // ensure bot quickly responds to a perp
|
||||
break
|
||||
else
|
||||
continue
|
||||
/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
|
||||
if(slot_item && slot_item.needs_permit)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/explode()
|
||||
|
||||
walk_to(src,0)
|
||||
visible_message("<span class='userdanger'>[src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
|
||||
Sa.build_step = 1
|
||||
Sa.overlays += "hs_hole"
|
||||
Sa.created_name = name
|
||||
new /obj/item/device/assembly/prox_sensor(Tsec)
|
||||
new /obj/item/weapon/melee/baton(Tsec)
|
||||
|
||||
if(prob(50))
|
||||
new /obj/item/robot_parts/l_arm(Tsec)
|
||||
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
new /obj/effect/decal/cleanable/blood/oil(loc)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
|
||||
..()
|
||||
if(!isalien(target))
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
|
||||
if(ismob(AM) && target)
|
||||
var/mob/living/carbon/C = AM
|
||||
if(!istype(C) || !C || in_range(src, target))
|
||||
return
|
||||
C.visible_message("<span class='warning'>[pick( \
|
||||
"[C] dives out of [src]'s way!", \
|
||||
"[C] stumbles over [src]!", \
|
||||
"[C] jumps out of [src]'s path!", \
|
||||
"[C] trips over [src] and falls!", \
|
||||
"[C] topples over [src]!", \
|
||||
"[C] leaps out of [src]'s way!")]</span>")
|
||||
C.Weaken(2)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/bot_core/secbot
|
||||
req_access = list(access_security)
|
||||
@@ -14,14 +14,7 @@
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
faction = list("cult")
|
||||
flying = 1
|
||||
@@ -110,7 +103,7 @@
|
||||
|
||||
/mob/living/simple_animal/construct/armoured/Life()
|
||||
weakened = 0
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P)
|
||||
if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam))
|
||||
|
||||
@@ -399,11 +399,11 @@
|
||||
response_disarm = "bops"
|
||||
response_harm = "kicks"
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/Life()
|
||||
/mob/living/simple_animal/pet/corgi/Ian/process_ai()
|
||||
..()
|
||||
|
||||
//Feeding, chasing food, FOOOOODDDD
|
||||
if(!stat && !resting && !buckled && (ckey == null))
|
||||
if(!resting && !buckled)
|
||||
turns_since_scan++
|
||||
if(turns_since_scan > 5)
|
||||
turns_since_scan = 0
|
||||
@@ -450,10 +450,9 @@
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("dances around.","chases its tail!"))
|
||||
spawn(0)
|
||||
if (ckey == null)
|
||||
for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
|
||||
dir = i
|
||||
sleep(1)
|
||||
for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
|
||||
dir = i
|
||||
sleep(1)
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meat/corgi
|
||||
name = "Corgi meat"
|
||||
@@ -563,20 +562,18 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Lisa/Life()
|
||||
/mob/living/simple_animal/pet/corgi/Lisa/process_ai()
|
||||
..()
|
||||
|
||||
make_babies()
|
||||
|
||||
if(!stat && !resting && !buckled)
|
||||
if(!resting && !buckled)
|
||||
if(prob(1))
|
||||
if (ckey == null)
|
||||
custom_emote(1, pick("dances around.","chases her tail."))
|
||||
spawn(0)
|
||||
for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
|
||||
dir = i
|
||||
sleep(1)
|
||||
|
||||
custom_emote(1, pick("dances around.","chases her tail."))
|
||||
spawn(0)
|
||||
for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
|
||||
dir = i
|
||||
sleep(1)
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
|
||||
var/mouse_color //brown, gray and white, leave blank for random
|
||||
layer = MOB_LAYER
|
||||
min_oxy = 16 //Require atleast 16kPA oxygen
|
||||
atmos_requirements = list("min_oxy" = 16, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 223 //Below -50 Degrees Celcius
|
||||
maxbodytemp = 323 //Above 50 Degrees Celcius
|
||||
universal_speak = 0
|
||||
@@ -41,14 +41,7 @@
|
||||
|
||||
/mob/living/simple_animal/mouse/Life()
|
||||
. = ..()
|
||||
|
||||
if(!ckey && stat == CONSCIOUS && prob(0.5))
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "mouse_[mouse_color]_sleep"
|
||||
wander = 0
|
||||
speak_chance = 0
|
||||
//snuffles
|
||||
else if(stat == UNCONSCIOUS)
|
||||
if(stat == UNCONSCIOUS)
|
||||
if(ckey || prob(1))
|
||||
stat = CONSCIOUS
|
||||
icon_state = "mouse_[mouse_color]"
|
||||
@@ -56,6 +49,15 @@
|
||||
else if(prob(5))
|
||||
emote("snuffles")
|
||||
|
||||
/mob/living/simple_animal/mouse/process_ai()
|
||||
..()
|
||||
|
||||
if(prob(0.5))
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "mouse_[mouse_color]_sleep"
|
||||
wander = 0
|
||||
speak_chance = 0
|
||||
|
||||
/mob/living/simple_animal/mouse/New()
|
||||
..()
|
||||
if(!mouse_color)
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
response_harm = "kicks"
|
||||
see_in_dark = 5
|
||||
|
||||
/mob/living/simple_animal/pet/pug/Life()
|
||||
/mob/living/simple_animal/pet/pug/process_ai()
|
||||
..()
|
||||
|
||||
if(!stat && !resting && !buckled)
|
||||
if(!resting && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("chases its tail."))
|
||||
spawn(0)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/mob/living/simple_animal/spiderbot
|
||||
|
||||
min_oxy = 0
|
||||
max_tox = 0
|
||||
max_co2 = 0
|
||||
atmos_requirements = list("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
|
||||
maxbodytemp = 500
|
||||
|
||||
|
||||
@@ -21,14 +21,7 @@
|
||||
speak_emote = list("hisses")
|
||||
a_intent = I_HARM
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
var/dead = 0
|
||||
unsuitable_atmos_damage = 15
|
||||
faction = list("alien")
|
||||
@@ -50,14 +43,16 @@
|
||||
var/plant_cooldown = 30
|
||||
var/plants_off = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/drone/Life()
|
||||
..()
|
||||
if(!stat)
|
||||
plant_cooldown--
|
||||
if(stance==HOSTILE_STANCE_IDLE)
|
||||
if(!plants_off && prob(10) && plant_cooldown<=0)
|
||||
plant_cooldown = initial(plant_cooldown)
|
||||
SpreadPlants()
|
||||
/mob/living/simple_animal/hostile/alien/drone/process_ai()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
plant_cooldown--
|
||||
if(stance==HOSTILE_STANCE_IDLE)
|
||||
if(!plants_off && prob(10) && plant_cooldown<=0)
|
||||
plant_cooldown = initial(plant_cooldown)
|
||||
SpreadPlants()
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/sentinel
|
||||
name = "alien sentinel"
|
||||
@@ -95,18 +90,18 @@
|
||||
var/egg_cooldown = 30
|
||||
var/plant_cooldown = 30
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/queen/Life()
|
||||
/mob/living/simple_animal/hostile/alien/queen/process_ai()
|
||||
..()
|
||||
if(!stat)
|
||||
egg_cooldown--
|
||||
plant_cooldown--
|
||||
if(stance==HOSTILE_STANCE_IDLE)
|
||||
if(!plants_off && prob(10) && plant_cooldown<=0)
|
||||
plant_cooldown = initial(plant_cooldown)
|
||||
SpreadPlants()
|
||||
if(!sterile && prob(10) && egg_cooldown<=0)
|
||||
egg_cooldown = initial(egg_cooldown)
|
||||
LayEggs()
|
||||
|
||||
egg_cooldown--
|
||||
plant_cooldown--
|
||||
if(stance==HOSTILE_STANCE_IDLE)
|
||||
if(!plants_off && prob(10) && plant_cooldown<=0)
|
||||
plant_cooldown = initial(plant_cooldown)
|
||||
SpreadPlants()
|
||||
if(!sterile && prob(10) && egg_cooldown<=0)
|
||||
egg_cooldown = initial(egg_cooldown)
|
||||
LayEggs()
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/proc/SpreadPlants()
|
||||
if(!isturf(loc) || istype(loc, /turf/space))
|
||||
|
||||
@@ -23,15 +23,7 @@
|
||||
attacktext = "bites"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
|
||||
//Space carp aren't affected by atmos.
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
// break_stuff_probability = 2
|
||||
|
||||
@@ -27,14 +27,7 @@
|
||||
attack_sound = 'sound/weapons/genhit3.ogg'
|
||||
|
||||
//Space bears aren't affected by atmos.
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
var/stance_step = 0
|
||||
|
||||
@@ -56,12 +49,11 @@
|
||||
else
|
||||
icon_state = "bearfloor"
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/Life()
|
||||
/mob/living/simple_animal/hostile/bear/process_ai()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
|
||||
switch(stance)
|
||||
|
||||
if(HOSTILE_STANCE_TIRED)
|
||||
|
||||
@@ -26,14 +26,7 @@
|
||||
speak_emote = list("gnashes")
|
||||
|
||||
//Space carp aren't affected by atmos.
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
maxbodytemp = 1500
|
||||
|
||||
|
||||
@@ -20,14 +20,7 @@
|
||||
attack_sound = 'sound/hallucinations/growl1.ogg'
|
||||
speak_emote = list("growls")
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
speed = 4
|
||||
|
||||
|
||||
@@ -18,14 +18,7 @@
|
||||
projectilesound = 'sound/weapons/Gunshot.ogg'
|
||||
projectiletype = /obj/item/projectile/hivebotbullet
|
||||
faction = list("hivebot")
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
speak_emote = list("states")
|
||||
|
||||
@@ -79,37 +72,36 @@
|
||||
warpbots()
|
||||
|
||||
|
||||
New()
|
||||
..()
|
||||
var/datum/effect/system/harmless_smoke_spread/smoke = new /datum/effect/system/harmless_smoke_spread()
|
||||
smoke.set_up(5, 0, src.loc)
|
||||
smoke.start()
|
||||
visible_message("\red <B>The [src] warps in!</B>")
|
||||
playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
|
||||
/mob/living/simple_animal/hostile/hivebot/tele/New()
|
||||
..()
|
||||
var/datum/effect/system/harmless_smoke_spread/smoke = new /datum/effect/system/harmless_smoke_spread()
|
||||
smoke.set_up(5, 0, src.loc)
|
||||
smoke.start()
|
||||
visible_message("\red <B>The [src] warps in!</B>")
|
||||
playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
|
||||
|
||||
warpbots()
|
||||
icon_state = "def_radar"
|
||||
visible_message("\red The [src] turns on!")
|
||||
while(bot_amt > 0)
|
||||
bot_amt--
|
||||
switch(bot_type)
|
||||
if("norm")
|
||||
var/mob/living/simple_animal/hostile/hivebot/H = new /mob/living/simple_animal/hostile/hivebot(get_turf(src))
|
||||
H.faction = faction
|
||||
if("range")
|
||||
var/mob/living/simple_animal/hostile/hivebot/range/R = new /mob/living/simple_animal/hostile/hivebot/range(get_turf(src))
|
||||
R.faction = faction
|
||||
if("rapid")
|
||||
var/mob/living/simple_animal/hostile/hivebot/rapid/F = new /mob/living/simple_animal/hostile/hivebot/rapid(get_turf(src))
|
||||
F.faction = faction
|
||||
spawn(100)
|
||||
qdel(src)
|
||||
/mob/living/simple_animal/hostile/hivebot/tele/warpbots()
|
||||
icon_state = "def_radar"
|
||||
visible_message("\red The [src] turns on!")
|
||||
while(bot_amt > 0)
|
||||
bot_amt--
|
||||
switch(bot_type)
|
||||
if("norm")
|
||||
var/mob/living/simple_animal/hostile/hivebot/H = new /mob/living/simple_animal/hostile/hivebot(get_turf(src))
|
||||
H.faction = faction
|
||||
if("range")
|
||||
var/mob/living/simple_animal/hostile/hivebot/range/R = new /mob/living/simple_animal/hostile/hivebot/range(get_turf(src))
|
||||
R.faction = faction
|
||||
if("rapid")
|
||||
var/mob/living/simple_animal/hostile/hivebot/rapid/F = new /mob/living/simple_animal/hostile/hivebot/rapid(get_turf(src))
|
||||
F.faction = faction
|
||||
spawn(100)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/tele/process_ai()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
|
||||
Life()
|
||||
..()
|
||||
if(stat == 0)
|
||||
if(prob(2))//Might be a bit low, will mess with it likely
|
||||
warpbots()
|
||||
|
||||
if(prob(2))//Might be a bit low, will mess with it likely
|
||||
warpbots()
|
||||
@@ -32,33 +32,34 @@
|
||||
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_SLEEP (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
|
||||
|
||||
/mob/living/simple_animal/hostile/Life()
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
walk(src, 0)
|
||||
return 0
|
||||
if(ranged)
|
||||
ranged_cooldown--
|
||||
if(client)
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/process_ai()
|
||||
..()
|
||||
if(!AICanContinue())
|
||||
return 0
|
||||
if(!stat)
|
||||
switch(stance)
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
var/new_target = FindTarget()
|
||||
GiveTarget(new_target)
|
||||
switch(stance)
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
var/new_target = FindTarget()
|
||||
GiveTarget(new_target)
|
||||
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
MoveToTarget()
|
||||
DestroySurroundings()
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
MoveToTarget()
|
||||
DestroySurroundings()
|
||||
|
||||
if(HOSTILE_STANCE_ATTACKING)
|
||||
AttackTarget()
|
||||
DestroySurroundings()
|
||||
if(HOSTILE_STANCE_ATTACKING)
|
||||
AttackTarget()
|
||||
DestroySurroundings()
|
||||
|
||||
if(AIShouldSleep())
|
||||
AIStatus = AI_SLEEP
|
||||
if(AIShouldSleep())
|
||||
AIStatus = AI_SLEEP
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
|
||||
|
||||
@@ -23,14 +23,7 @@
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
speak_emote = list("creaks")
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
faction = list("mimic")
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/
|
||||
vision_range = 2
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 15
|
||||
faction = list("mining")
|
||||
environment_smash = 2
|
||||
@@ -387,7 +380,7 @@
|
||||
anchored = 1 //Stays anchored until death as to be unpullable
|
||||
var/pre_attack = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/process_ai()
|
||||
..()
|
||||
handle_preattack()
|
||||
|
||||
|
||||
@@ -19,14 +19,7 @@
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
|
||||
min_oxy = 5
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 1
|
||||
min_co2 = 0
|
||||
max_co2 = 5
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 15
|
||||
speak_emote = list("yarrs")
|
||||
var/corpse = /obj/effect/landmark/mobcorpse/pirate
|
||||
|
||||
@@ -22,14 +22,7 @@
|
||||
flying = 1
|
||||
|
||||
//Spaceborn beings don't get hurt by space
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/bees/Process_Spacemove(var/check_drift = 0)
|
||||
|
||||
@@ -23,15 +23,6 @@
|
||||
attacktext = "attacks"
|
||||
attack_sound = 'sound/items/bikehorn.ogg'
|
||||
environment_smash = 0
|
||||
|
||||
min_oxy = 5
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 1
|
||||
min_co2 = 0
|
||||
max_co2 = 5
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
minbodytemp = 270
|
||||
maxbodytemp = 370
|
||||
heat_damage_per_tick = 15 //amount of damage applied if animal's body temperature is higher than maxbodytemp
|
||||
|
||||
@@ -35,14 +35,7 @@
|
||||
var/exploding = 0
|
||||
|
||||
//Drones aren't affected by atmos.
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
var/has_loot = 1
|
||||
|
||||
@@ -17,7 +17,4 @@
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
|
||||
min_oxy = 5
|
||||
max_tox = 2
|
||||
max_co2 = 5
|
||||
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 2, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
|
||||
@@ -41,14 +41,7 @@
|
||||
attacktext = "grips"
|
||||
attack_sound = 'sound/hallucinations/growl1.ogg'
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
faction = list("undead") // did I mention ghost
|
||||
@@ -93,14 +86,7 @@
|
||||
attacktext = "claws"
|
||||
attack_sound = 'sound/hallucinations/growl1.ogg'
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
faction = list("undead")
|
||||
@@ -131,14 +117,7 @@
|
||||
attacktext = "claws"
|
||||
attack_sound = 'sound/hallucinations/growl1.ogg'
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
faction = list("undead")
|
||||
|
||||
@@ -21,14 +21,6 @@
|
||||
a_intent = I_HARM
|
||||
var/corpse = /obj/effect/landmark/mobcorpse/russian
|
||||
var/weapon1 = /obj/item/weapon/kitchen/knife
|
||||
min_oxy = 5
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 1
|
||||
min_co2 = 0
|
||||
max_co2 = 5
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
unsuitable_atmos_damage = 15
|
||||
faction = list("russian")
|
||||
status_flags = CANPUSH
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 350
|
||||
min_oxy = 0
|
||||
max_co2 = 0
|
||||
max_tox = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
|
||||
a_intent = I_HARM //so they don't get pushed around
|
||||
|
||||
|
||||
@@ -23,14 +23,7 @@
|
||||
attacktext = "claws"
|
||||
attack_sound = 'sound/hallucinations/growl1.ogg'
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
faction = list("statue")
|
||||
@@ -76,12 +69,12 @@
|
||||
icon_state = "angel"
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/statue/Life()
|
||||
if(..())
|
||||
if(!ckey)
|
||||
spawn() //for saftey
|
||||
checkTargets()
|
||||
. = 1
|
||||
/mob/living/simple_animal/hostile/statue/process_ai()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
spawn() //for saftey
|
||||
checkTargets()
|
||||
|
||||
/mob/living/simple_animal/hostile/statue/proc/checkTargets()
|
||||
if(target)
|
||||
@@ -195,6 +188,9 @@
|
||||
. = ..()
|
||||
return . - creator
|
||||
|
||||
/mob/living/simple_animal/hostile/statue/sentience_act()
|
||||
faction -= "neutral"
|
||||
|
||||
// Statue powers
|
||||
|
||||
// Flicker lights
|
||||
|
||||
@@ -22,14 +22,6 @@
|
||||
var/corpse = /obj/effect/landmark/mobcorpse/syndicatesoldier
|
||||
var/weapon1
|
||||
var/weapon2
|
||||
min_oxy = 5
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 1
|
||||
min_co2 = 0
|
||||
max_co2 = 5
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
unsuitable_atmos_damage = 15
|
||||
faction = list("syndicate")
|
||||
status_flags = CANPUSH
|
||||
@@ -85,14 +77,7 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/space
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
icon_state = "syndicatemeleespace"
|
||||
icon_living = "syndicatemeleespace"
|
||||
@@ -120,14 +105,7 @@
|
||||
icon_state = "syndicaterangedpsace"
|
||||
icon_living = "syndicaterangedpsace"
|
||||
name = "Syndicate Commando"
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
|
||||
speed = 1
|
||||
@@ -151,14 +129,7 @@
|
||||
attacktext = "cuts"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
faction = list("syndicate")
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
flying = 1
|
||||
|
||||
|
||||
@@ -24,15 +24,7 @@
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
speak_emote = list("pines")
|
||||
|
||||
//Space carp aren't affected by atmos.
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
faction = list("hostile", "winter")
|
||||
|
||||
@@ -14,14 +14,7 @@
|
||||
icon_living = "placeholder"
|
||||
icon_dead = "placeholder"
|
||||
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
atmos_requirements = list("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
|
||||
|
||||
melee_damage_lower = 3
|
||||
|
||||
@@ -53,12 +53,12 @@
|
||||
universal_speak = 1
|
||||
|
||||
var/parrot_state = PARROT_WANDER //Hunt for a perch when created
|
||||
var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick.
|
||||
var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in process_ai() being run every single tick.
|
||||
var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down
|
||||
var/parrot_dam_zone = list("chest", "head", "l_arm", "l_leg", "r_arm", "r_leg") //For humans, select a bodypart to attack
|
||||
|
||||
var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower.
|
||||
var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed.
|
||||
var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every process_ai() and at 0 the parrot will return to regular speed.
|
||||
|
||||
var/list/speech_buffer = list()
|
||||
var/list/available_channels = list()
|
||||
@@ -273,14 +273,13 @@
|
||||
|
||||
//Sprite and AI update for when a parrot gets pulled
|
||||
if(pulledby && stat == CONSCIOUS)
|
||||
icon_state = "parrot_fly"
|
||||
if(!client)
|
||||
parrot_state = PARROT_WANDER
|
||||
icon_state = "parrot_fly"
|
||||
|
||||
/mob/living/simple_animal/parrot/process_ai()
|
||||
if(pulledby)
|
||||
parrot_state = PARROT_WANDER
|
||||
return
|
||||
|
||||
if(client || stat)
|
||||
return //Lets not force players or dead/incap parrots to move
|
||||
|
||||
|
||||
if(!isturf(src.loc) || !canmove || buckled)
|
||||
return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove)
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
attacktext = "sends rainbows of power to"
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 4000
|
||||
min_oxy = 0
|
||||
max_co2 = 0
|
||||
max_tox = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
speed = 0
|
||||
stop_automated_movement = 0
|
||||
status_flags = 0
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
attacktext = "drains the life from"
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 4000
|
||||
min_oxy = 0
|
||||
max_co2 = 0
|
||||
max_tox = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
speed = -1
|
||||
stop_automated_movement = 1
|
||||
status_flags = 0
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
var/oxygen_alert = 0
|
||||
var/toxins_alert = 0
|
||||
var/fire_alert = 0
|
||||
var/healable = 1
|
||||
|
||||
var/list/speak = list()
|
||||
var/speak_chance = 0
|
||||
@@ -43,14 +44,7 @@
|
||||
var/cold_damage_per_tick = 2 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
|
||||
|
||||
//Atmos effect - Yes, you can make creatures that require plasma or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage
|
||||
var/min_oxy = 5
|
||||
var/max_oxy = 0 //Leaving something at 0 means it's off - has no maximum
|
||||
var/min_tox = 0
|
||||
var/max_tox = 1
|
||||
var/min_co2 = 0
|
||||
var/max_co2 = 5
|
||||
var/min_n2 = 0
|
||||
var/max_n2 = 0
|
||||
var/list/atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) //Leaving something at 0 means it's off - has no maximum
|
||||
var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above
|
||||
|
||||
|
||||
@@ -58,7 +52,7 @@
|
||||
var/melee_damage_lower = 0
|
||||
var/melee_damage_upper = 0
|
||||
var/melee_damage_type = BRUTE //Damage type of a simple mob's melee attack, should it do damage.
|
||||
var/list/ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 0, CLONE = 0, STAMINA = 1, OXY = 0) //Set 0 to receive that damage type, 1 to ignore
|
||||
var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) // 1 for full damage , 0 for none , -1 for 1:1 heal from that source
|
||||
var/attacktext = "attacks"
|
||||
var/attack_sound = null
|
||||
var/friendly = "nuzzles" //If the mob does no damage with it's attack
|
||||
@@ -76,10 +70,12 @@
|
||||
var/simplespecies //Sorry, no spider+corgi buttbabies.
|
||||
|
||||
var/master_commander = null //holding var for determining who own/controls a sentient simple animal (for sentience potions).
|
||||
var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions
|
||||
|
||||
|
||||
/mob/living/simple_animal/New()
|
||||
..()
|
||||
simple_animal_list += src
|
||||
verbs -= /mob/verb/observe
|
||||
if(!can_hide)
|
||||
verbs -= /mob/living/simple_animal/verb/hide
|
||||
@@ -92,6 +88,7 @@
|
||||
if(collar)
|
||||
collar.forceMove(loc)
|
||||
collar = null
|
||||
simple_animal_list -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/Login()
|
||||
@@ -130,16 +127,14 @@
|
||||
if(0) healths.icon_state = "health7"
|
||||
|
||||
/mob/living/simple_animal/Life()
|
||||
|
||||
if(..())
|
||||
if(!ckey)
|
||||
handle_automated_movement()
|
||||
handle_automated_action()
|
||||
handle_automated_speech()
|
||||
. = 1
|
||||
|
||||
. = ..()
|
||||
handle_state_icons()
|
||||
|
||||
/mob/living/simple_animal/proc/process_ai()
|
||||
handle_automated_movement()
|
||||
handle_automated_action()
|
||||
handle_automated_speech()
|
||||
|
||||
/mob/living/simple_animal/proc/handle_state_icons()
|
||||
if(resting && icon_resting && stat != DEAD)
|
||||
icon_state = icon_resting
|
||||
@@ -218,32 +213,32 @@
|
||||
var/n2 = environment.nitrogen
|
||||
var/co2 = environment.carbon_dioxide
|
||||
|
||||
if(min_oxy && oxy < min_oxy)
|
||||
if(atmos_requirements["min_oxy"] && oxy < atmos_requirements["min_oxy"])
|
||||
atmos_suitable = 0
|
||||
oxygen_alert = 1
|
||||
else if(max_oxy && oxy > max_oxy)
|
||||
else if(atmos_requirements["max_oxy"] && oxy > atmos_requirements["max_oxy"])
|
||||
atmos_suitable = 0
|
||||
oxygen_alert = 1
|
||||
else
|
||||
oxygen_alert = 0
|
||||
|
||||
if(min_tox && tox < min_tox)
|
||||
if(atmos_requirements["min_tox"] && tox < atmos_requirements["min_tox"])
|
||||
atmos_suitable = 0
|
||||
toxins_alert = 1
|
||||
else if(max_tox && tox > max_tox)
|
||||
else if(atmos_requirements["max_tox"] && tox > atmos_requirements["max_tox"])
|
||||
atmos_suitable = 0
|
||||
toxins_alert = 1
|
||||
else
|
||||
toxins_alert = 0
|
||||
|
||||
if(min_n2 && n2 < min_n2)
|
||||
if(atmos_requirements["min_n2"] && n2 < atmos_requirements["min_n2"])
|
||||
atmos_suitable = 0
|
||||
else if(max_n2 && n2 > max_n2)
|
||||
else if(atmos_requirements["max_n2"] && n2 > atmos_requirements["max_n2"])
|
||||
atmos_suitable = 0
|
||||
|
||||
if(min_co2 && co2 < min_co2)
|
||||
if(atmos_requirements["min_co2"] && co2 < atmos_requirements["min_co2"])
|
||||
atmos_suitable = 0
|
||||
else if(max_co2 && co2 > max_co2)
|
||||
else if(atmos_requirements["max_co2"] && co2 > atmos_requirements["max_co2"])
|
||||
atmos_suitable = 0
|
||||
|
||||
if(!atmos_suitable)
|
||||
@@ -414,7 +409,7 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/attackby(var/obj/item/O as obj, var/mob/living/user as mob) //Marker -Agouri
|
||||
if(istype(O, /obj/item/stack/medical))
|
||||
if(istype(O, /obj/item/stack/medical) && healable)
|
||||
if(stat != DEAD)
|
||||
var/obj/item/stack/medical/MED = O
|
||||
if(health < maxHealth)
|
||||
@@ -510,21 +505,29 @@
|
||||
if(3.0)
|
||||
adjustBruteLoss(30)
|
||||
|
||||
/mob/living/simple_animal/adjustBruteLoss(damage)
|
||||
if(!ignored_damage_types[BRUTE])
|
||||
..()
|
||||
/mob/living/simple_animal/adjustBruteLoss(amount)
|
||||
if(damage_coeff[BRUTE])
|
||||
return ..(amount * damage_coeff[BRUTE])
|
||||
|
||||
/mob/living/simple_animal/adjustFireLoss(damage)
|
||||
if(!ignored_damage_types[BURN])
|
||||
..(damage)
|
||||
/mob/living/simple_animal/adjustFireLoss(amount)
|
||||
if(damage_coeff[BURN])
|
||||
return ..(amount * damage_coeff[BURN])
|
||||
|
||||
/mob/living/simple_animal/adjustToxLoss(damage)
|
||||
if(!ignored_damage_types[TOX])
|
||||
..(damage)
|
||||
/mob/living/simple_animal/adjustOxyLoss(amount)
|
||||
if(damage_coeff[OXY])
|
||||
return ..(amount * damage_coeff[OXY])
|
||||
|
||||
/mob/living/simple_animal/adjustCloneLoss(damage)
|
||||
if(!ignored_damage_types[CLONE])
|
||||
..(damage)
|
||||
/mob/living/simple_animal/adjustToxLoss(amount)
|
||||
if(damage_coeff[TOX])
|
||||
return ..(amount * damage_coeff[TOX])
|
||||
|
||||
/mob/living/simple_animal/adjustCloneLoss(amount)
|
||||
if(damage_coeff[CLONE])
|
||||
return ..(amount * damage_coeff[CLONE])
|
||||
|
||||
/mob/living/simple_animal/adjustStaminaLoss(amount)
|
||||
if(damage_coeff[STAMINA])
|
||||
return ..(amount*damage_coeff[STAMINA])
|
||||
|
||||
/mob/living/simple_animal/proc/CanAttack(var/atom/the_target)
|
||||
if(see_invisible < the_target.invisibility)
|
||||
@@ -544,11 +547,10 @@
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE)
|
||||
if(damage <= force_threshold || ignored_damage_types[damagetype])
|
||||
if(damage <= force_threshold || !damage_coeff[damagetype])
|
||||
visible_message("<span class='warning'>[src] looks unharmed from the damage.</span>")
|
||||
else
|
||||
adjustBruteLoss(damage)
|
||||
updatehealth()
|
||||
apply_damage(damage, damagetype)
|
||||
|
||||
|
||||
/mob/living/simple_animal/update_fire()
|
||||
@@ -699,4 +701,7 @@
|
||||
/mob/living/simple_animal/get_access()
|
||||
. = ..()
|
||||
if(collar)
|
||||
. |= collar.GetAccess()
|
||||
. |= collar.GetAccess()
|
||||
|
||||
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
|
||||
return
|
||||
+1
-11
@@ -749,16 +749,6 @@ var/list/slot_equipment_priority = list( \
|
||||
namecounts[name] = 1
|
||||
creatures[name] = O
|
||||
|
||||
if(istype(O, /obj/machinery/bot))
|
||||
var/name = "BOT: [O.name]"
|
||||
if (names.Find(name))
|
||||
namecounts[name]++
|
||||
name = "[name] ([namecounts[name]])"
|
||||
else
|
||||
names.Add(name)
|
||||
namecounts[name] = 1
|
||||
creatures[name] = O
|
||||
|
||||
|
||||
for(var/mob/M in sortAtom(mob_list))
|
||||
var/name = M.name
|
||||
@@ -861,9 +851,9 @@ var/list/slot_equipment_priority = list( \
|
||||
..()
|
||||
if(M != usr) return
|
||||
if(M.small) return // Stops pAI drones and small mobs (borers, parrots, crabs) from stripping people. --DZD
|
||||
if(!M.can_strip) return
|
||||
if(usr == src) return
|
||||
if(!Adjacent(usr)) return
|
||||
if(istype(M,/mob/living/silicon/ai)) return
|
||||
show_inv(usr)
|
||||
|
||||
//this and stop_pulling really ought to be /mob/living procs
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
var/lastpuke = 0
|
||||
var/unacidable = 0
|
||||
var/small = 0
|
||||
var/can_strip = 1
|
||||
var/list/pinned = list() //List of things pinning this creature to walls (see living_defense.dm)
|
||||
var/list/embedded = list() //Embedded items, since simple mobs don't have organs.
|
||||
var/list/languages = list() // For speaking/listening.
|
||||
|
||||
@@ -94,6 +94,11 @@ proc/isembryo(A)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/isbot(A)
|
||||
if(istype(A, /mob/living/simple_animal/bot))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/isclown(A)
|
||||
if(istype(A, /mob/living/simple_animal/hostile/retaliate/clown))
|
||||
return 1
|
||||
|
||||
@@ -96,4 +96,10 @@
|
||||
if(. != STATUS_CLOSE)
|
||||
. = min(., shared_living_nano_distance(src_object))
|
||||
if(!IsAdvancedToolUser())
|
||||
. = STATUS_CLOSE
|
||||
|
||||
/mob/living/simple_animal/bot/default_can_use_topic(var/src_object)
|
||||
. = shared_nano_interaction(src_object)
|
||||
if(. != STATUS_CLOSE)
|
||||
if(!(src_object in contents))
|
||||
. = STATUS_CLOSE
|
||||
@@ -187,7 +187,7 @@ nanoui is used to open and update nano browser uis
|
||||
"showMap" = show_map,
|
||||
"mapZLevel" = map_z_level,
|
||||
"user" = list(
|
||||
"name" = user.name,
|
||||
"name" = sanitize(user.name),
|
||||
"fancy" = user.client.prefs.nanoui_fancy
|
||||
),
|
||||
"window" = list(
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
/datum/data/pda/app/power/update_ui(mob/user as mob, list/data)
|
||||
update = PDA_APP_UPDATE_SLOW
|
||||
|
||||
|
||||
if (powmonitor && !isnull(powmonitor.powernet))
|
||||
data["records"] = list(
|
||||
"powerconnected" = 1,
|
||||
@@ -226,7 +226,7 @@
|
||||
beepskyData["botstatus"] = list("loca" = null, "mode" = -1)
|
||||
var/botsCount=0
|
||||
if(SC.botlist && SC.botlist.len)
|
||||
for(var/obj/machinery/bot/B in SC.botlist)
|
||||
for(var/mob/living/simple_animal/bot/B in SC.botlist)
|
||||
botsCount++
|
||||
if(B.loc)
|
||||
botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
|
||||
@@ -276,7 +276,7 @@
|
||||
|
||||
|
||||
var/mulebotsCount=0
|
||||
for(var/obj/machinery/bot/B in QC.botlist)
|
||||
for(var/mob/living/simple_animal/bot/B in QC.botlist)
|
||||
mulebotsCount++
|
||||
if(B.loc)
|
||||
mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
|
||||
@@ -392,7 +392,7 @@
|
||||
BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
|
||||
|
||||
var/CbotData[0]
|
||||
for(var/obj/machinery/bot/cleanbot/B in aibots)
|
||||
for(var/mob/living/simple_animal/bot/cleanbot/B in simple_animal_list)
|
||||
var/turf/bl = get_turf(B)
|
||||
if(bl)
|
||||
if(bl.z != cl.z)
|
||||
|
||||
+27
-92
@@ -5,7 +5,7 @@
|
||||
icon_state = "power_mod"
|
||||
var/obj/item/device/pda/hostpda = null
|
||||
var/list/botlist = null // list of bots
|
||||
var/obj/machinery/bot/active // the active bot; if null, show bot list
|
||||
var/mob/living/simple_animal/bot/active // the active bot; if null, show bot list
|
||||
var/list/botstatus // the status signal sent by the bot
|
||||
var/bot_type //The type of bot it is.
|
||||
var/bot_filter //Determines which radio filter to use.
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
/obj/item/radio/integrated/New()
|
||||
..()
|
||||
if (istype(loc.loc, /obj/item/device/pda))
|
||||
if(istype(loc.loc, /obj/item/device/pda))
|
||||
hostpda = loc.loc
|
||||
if (bot_filter)
|
||||
if(bot_filter)
|
||||
spawn(5)
|
||||
add_to_radio(bot_filter)
|
||||
|
||||
@@ -51,31 +51,22 @@
|
||||
frequency.post_signal(src, signal, filter = s_filter)
|
||||
|
||||
/obj/item/radio/integrated/receive_signal(datum/signal/signal)
|
||||
/*var/obj/item/device/pda/P = src.loc
|
||||
|
||||
|
||||
world << "recvd:[P] : [signal.source]"
|
||||
for(var/d in signal.data)
|
||||
world << "- [d] = [signal.data[d]]"
|
||||
*/
|
||||
|
||||
if (signal.data["type"] == bot_type)
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
if(!(signal.source in botlist))
|
||||
botlist += signal.source
|
||||
var/obj/machinery/bot_core/core = signal.source
|
||||
|
||||
if(active == signal.source)
|
||||
if(istype(core) && !(core.owner in botlist))
|
||||
botlist += core.owner
|
||||
|
||||
if(active == core.owner)
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
|
||||
/obj/item/radio/integrated/Topic(href, href_list)
|
||||
..()
|
||||
var/obj/item/device/pda/PDA = src.hostpda
|
||||
|
||||
switch(href_list["op"])
|
||||
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
spawn(0)
|
||||
@@ -89,14 +80,14 @@
|
||||
if("botlist")
|
||||
active = null
|
||||
|
||||
if("stop", "go")
|
||||
if("stop", "go", "home")
|
||||
spawn(0)
|
||||
post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
if("summon")
|
||||
spawn(0)
|
||||
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(hostpda), "useraccess", hostpda.GetAccess(), "user", usr, s_filter = bot_filter)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
|
||||
|
||||
/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots.
|
||||
@@ -121,101 +112,45 @@
|
||||
bot_type = CLEAN_BOT
|
||||
|
||||
/obj/item/radio/integrated/mule
|
||||
//var/list/botlist = null // list of bots
|
||||
//var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
|
||||
//var/list/botstatus // the status signal sent by the bot
|
||||
var/list/beacons
|
||||
|
||||
var/beacon_freq = 1400
|
||||
control_freq = 1447
|
||||
|
||||
// create a new QM cartridge, and register to receive bot control & beacon message
|
||||
/obj/item/radio/integrated/mule/New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
|
||||
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
|
||||
spawn(10)
|
||||
post_signal(beacon_freq, "findbeacon", "delivery", s_filter = RADIO_NAVBEACONS)
|
||||
|
||||
/obj/item/radio/integrated/mule/Destroy()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src,beacon_freq)
|
||||
return ..()
|
||||
|
||||
// receive radio signals
|
||||
// can detect bot status signals
|
||||
// and beacon locations
|
||||
// create/populate lists as they are recvd
|
||||
|
||||
/obj/item/radio/integrated/mule/receive_signal(datum/signal/signal)
|
||||
if(signal.data["type"] == MULE_BOT)
|
||||
if(!botlist)
|
||||
botlist = new()
|
||||
|
||||
if(!(signal.source in botlist))
|
||||
botlist += signal.source
|
||||
|
||||
if(active == signal.source)
|
||||
var/list/b = signal.data
|
||||
botstatus = b.Copy()
|
||||
|
||||
else if(signal.data["beacon"])
|
||||
if(!beacons)
|
||||
beacons = new()
|
||||
|
||||
beacons[signal.data["beacon"] ] = signal.source
|
||||
bot_filter = RADIO_MULEBOT
|
||||
bot_type = MULE_BOT
|
||||
|
||||
/obj/item/radio/integrated/mule/Topic(href, href_list)
|
||||
//..()
|
||||
//var/obj/item/device/pda/PDA = src.hostpda
|
||||
var/cmd = "command"
|
||||
if(active)
|
||||
cmd = "command [active.suffix]"
|
||||
|
||||
..()
|
||||
switch(href_list["op"])
|
||||
if("control")
|
||||
active = locate(href_list["bot"])
|
||||
|
||||
if("scanbots") // find all bots
|
||||
botlist = null
|
||||
|
||||
if("botlist")
|
||||
active = null
|
||||
if("start")
|
||||
spawn(0)
|
||||
post_signal(control_freq, "command", "start", "active", active, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("unload")
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, "command", "unload", "active", active, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("setdest")
|
||||
if(beacons)
|
||||
var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons
|
||||
if(deliverybeacons)
|
||||
var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in deliverybeacontags
|
||||
if(dest)
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, "command", "target", "active", active, "destination", dest, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("retoff")
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
|
||||
post_signal(control_freq, "command", "autoret", "active", active, "value", 0, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("reton")
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, "command", "autoret", "active", active, "value", 1, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("pickoff")
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, "command", "autopick", "active", active, "value", 0, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("pickon")
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT)
|
||||
|
||||
if("stop", "go", "home")
|
||||
spawn(0)
|
||||
post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, "command", "autopick", "active", active, "value", 1, s_filter = RADIO_MULEBOT)
|
||||
|
||||
spawn(10)
|
||||
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
|
||||
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_MULEBOT)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
/obj/machinery/atmospherics/unary/cryo_cell,
|
||||
/obj/machinery/dna_scannernew,
|
||||
/obj/item/weapon/grenade/chem_grenade,
|
||||
/obj/machinery/bot/medbot,
|
||||
/mob/living/simple_animal/bot/medbot,
|
||||
/obj/item/weapon/storage/secure/safe,
|
||||
/obj/machinery/iv_drip,
|
||||
/obj/machinery/disease2/incubator,
|
||||
|
||||
@@ -780,7 +780,8 @@
|
||||
var/list/mobs_can_pass = list(
|
||||
/mob/living/carbon/slime,
|
||||
/mob/living/simple_animal/mouse,
|
||||
/mob/living/silicon/robot/drone
|
||||
/mob/living/silicon/robot/drone,
|
||||
/mob/living/simple_animal/bot/mulebot
|
||||
)
|
||||
|
||||
/obj/structure/plasticflaps/CanPass(atom/A, turf/T)
|
||||
@@ -814,6 +815,18 @@
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/plasticflaps/CanAStarPass(ID, to_dir, caller)
|
||||
if(istype(caller, /mob/living))
|
||||
for(var/mob_type in mobs_can_pass)
|
||||
if(istype(caller, mob_type))
|
||||
return 1
|
||||
|
||||
var/mob/living/M = caller
|
||||
if(!M.ventcrawler && !M.small)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/structure/plasticflaps/ex_act(severity)
|
||||
switch(severity)
|
||||
if (1)
|
||||
|
||||
Reference in New Issue
Block a user