mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-20 10:37:45 +01:00
Why do we have a robot that literally does the entire job. Basically people leave it and it becomes a lag generator forever. Removes farmbot harvesting and removal of dead plants, plus adds an idle timer for 150 process cycles without a target causing it to turn itself off. So basically it will tend the plants and keep them alive, but you need to come harvest them sometimes.
405 lines
12 KiB
Plaintext
405 lines
12 KiB
Plaintext
#define FARMBOT_COLLECT 1
|
|
#define FARMBOT_WATER 2
|
|
#define FARMBOT_UPROOT 3
|
|
#define FARMBOT_NUTRIMENT 4
|
|
|
|
/mob/living/bot/farmbot
|
|
name = "Farmbot"
|
|
desc = "The botanist's best friend."
|
|
icon = 'icons/obj/aibots.dmi'
|
|
icon_state = "farmbot0"
|
|
health = 50
|
|
maxHealth = 50
|
|
req_one_access = list(access_robotics, access_hydroponics)
|
|
|
|
var/action = "" // Used to update icon
|
|
var/waters_trays = 1
|
|
var/refills_water = 1
|
|
var/uproots_weeds = 1
|
|
var/replaces_nutriment = 0
|
|
var/collects_produce = 0
|
|
var/removes_dead = 0
|
|
var/times_idle = 0 //VOREStation Add
|
|
var/obj/structure/reagent_dispensers/watertank/tank
|
|
|
|
|
|
/mob/living/bot/farmbot/New(var/newloc, var/newTank)
|
|
..(newloc)
|
|
if(!newTank)
|
|
newTank = new /obj/structure/reagent_dispensers/watertank(src)
|
|
tank = newTank
|
|
tank.forceMove(src)
|
|
|
|
|
|
/mob/living/bot/farmbot/attack_hand(var/mob/user as mob)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
var/dat = ""
|
|
dat += "<TT><B>Automatic Hyrdoponic Assisting Unit v1.0</B></TT><BR><BR>"
|
|
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
|
|
dat += "Water Tank: "
|
|
if (tank)
|
|
dat += "[tank.reagents.total_volume]/[tank.reagents.maximum_volume]"
|
|
else
|
|
dat += "Error: Watertank not found"
|
|
dat += "<br>Behaviour controls are [locked ? "locked" : "unlocked"]<hr>"
|
|
if(!locked)
|
|
dat += "<TT>Watering controls:<br>"
|
|
dat += "Water plants : <A href='?src=\ref[src];water=1'>[waters_trays ? "Yes" : "No"]</A><BR>"
|
|
dat += "Refill watertank : <A href='?src=\ref[src];refill=1'>[refills_water ? "Yes" : "No"]</A><BR>"
|
|
dat += "<br>Weeding controls:<br>"
|
|
dat += "Weed plants: <A href='?src=\ref[src];weed=1'>[uproots_weeds ? "Yes" : "No"]</A><BR>"
|
|
dat += "<br>Nutriment controls:<br>"
|
|
dat += "Replace fertilizer: <A href='?src=\ref[src];replacenutri=1'>[replaces_nutriment ? "Yes" : "No"]</A><BR>"
|
|
/* VOREStation Removal - No whole-job lag-bot automation.
|
|
dat += "<br>Plant controls:<br>"
|
|
dat += "Collect produce: <A href='?src=\ref[src];collect=1'>[collects_produce ? "Yes" : "No"]</A><BR>"
|
|
dat += "Remove dead plants: <A href='?src=\ref[src];removedead=1'>[removes_dead ? "Yes" : "No"]</A><BR>"
|
|
*/
|
|
dat += "</TT>"
|
|
|
|
user << browse("<HEAD><TITLE>Farmbot v1.0 controls</TITLE></HEAD>[dat]", "window=autofarm")
|
|
onclose(user, "autofarm")
|
|
return
|
|
|
|
/mob/living/bot/farmbot/emag_act(var/remaining_charges, var/mob/user)
|
|
. = ..()
|
|
if(!emagged)
|
|
if(user)
|
|
user << "<span class='notice'>You short out [src]'s plant identifier circuits.</span>"
|
|
spawn(rand(30, 50))
|
|
visible_message("<span class='warning'>[src] buzzes oddly.</span>")
|
|
emagged = 1
|
|
return 1
|
|
|
|
/mob/living/bot/farmbot/Topic(href, href_list)
|
|
if(..())
|
|
return
|
|
usr.machine = src
|
|
add_fingerprint(usr)
|
|
if((href_list["power"]) && (access_scanner.allowed(usr)))
|
|
if(on)
|
|
turn_off()
|
|
else
|
|
turn_on()
|
|
|
|
if(locked)
|
|
return
|
|
|
|
if(href_list["water"])
|
|
waters_trays = !waters_trays
|
|
else if(href_list["refill"])
|
|
refills_water = !refills_water
|
|
else if(href_list["weed"])
|
|
uproots_weeds = !uproots_weeds
|
|
else if(href_list["replacenutri"])
|
|
replaces_nutriment = !replaces_nutriment
|
|
else if(href_list["collect"])
|
|
collects_produce = !collects_produce
|
|
else if(href_list["removedead"])
|
|
removes_dead = !removes_dead
|
|
|
|
attack_hand(usr)
|
|
return
|
|
|
|
/mob/living/bot/farmbot/update_icons()
|
|
if(on && action)
|
|
icon_state = "farmbot_[action]"
|
|
else
|
|
icon_state = "farmbot[on]"
|
|
|
|
|
|
/mob/living/bot/farmbot/handleRegular()
|
|
if(emagged && prob(1))
|
|
flick("farmbot_broke", src)
|
|
|
|
|
|
|
|
/mob/living/bot/farmbot/handleAdjacentTarget()
|
|
UnarmedAttack(target)
|
|
|
|
/mob/living/bot/farmbot/lookForTargets()
|
|
if(emagged)
|
|
for(var/mob/living/carbon/human/H in view(7, src))
|
|
target = H
|
|
times_idle = 0 //VOREStation Add - Idle shutoff time
|
|
return
|
|
else
|
|
for(var/obj/machinery/portable_atmospherics/hydroponics/tray in view(7, src))
|
|
if(confirmTarget(tray))
|
|
target = tray
|
|
times_idle = 0 //VOREStation Add - Idle shutoff time
|
|
return
|
|
if(!target && refills_water && tank && tank.reagents.total_volume < tank.reagents.maximum_volume)
|
|
for(var/obj/structure/sink/source in view(7, src))
|
|
target = source
|
|
times_idle = 0 //VOREStation Add - Idle shutoff time
|
|
return
|
|
if(++times_idle == 150) turn_off() //VOREStation Add - Idle shutoff time
|
|
/mob/living/bot/farmbot/calcTargetPath() // We need to land NEXT to the tray, because the tray itself is impassable
|
|
for(var/trayDir in list(NORTH, SOUTH, EAST, WEST))
|
|
target_path = AStar(get_turf(loc), get_step(get_turf(target), trayDir), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard)
|
|
if(target_path)
|
|
break
|
|
if(!target_path)
|
|
ignore_list |= target
|
|
target = null
|
|
target_path = list()
|
|
return
|
|
|
|
/mob/living/bot/farmbot/stepToTarget() // Same reason
|
|
var/turf/T = get_turf(target)
|
|
if(!target_path.len || !T.Adjacent(target_path[target_path.len]))
|
|
calcTargetPath()
|
|
makeStep(target_path)
|
|
return
|
|
|
|
/mob/living/bot/farmbot/UnarmedAttack(var/atom/A, var/proximity)
|
|
if(!..())
|
|
return
|
|
|
|
if(busy)
|
|
return
|
|
|
|
if(istype(A, /obj/machinery/portable_atmospherics/hydroponics))
|
|
var/obj/machinery/portable_atmospherics/hydroponics/T = A
|
|
|
|
var/t = confirmTarget(T)
|
|
switch(t)
|
|
if(0)
|
|
return
|
|
if(FARMBOT_COLLECT)
|
|
action = "water" // Needs a better one
|
|
update_icons()
|
|
visible_message("<span class='notice'>[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].</span>")
|
|
|
|
busy = 1
|
|
if(do_after(src, 30, A))
|
|
visible_message("<span class='notice'>[src] [T.dead? "removes the plant from" : "harvests"] \the [A].</span>")
|
|
T.attack_hand(src)
|
|
if(FARMBOT_WATER)
|
|
action = "water"
|
|
update_icons()
|
|
visible_message("<span class='notice'>[src] starts watering \the [A].</span>")
|
|
|
|
busy = 1
|
|
if(do_after(src, 30, A))
|
|
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
|
|
visible_message("<span class='notice'>[src] waters \the [A].</span>")
|
|
tank.reagents.trans_to(T, 100 - T.waterlevel)
|
|
if(FARMBOT_UPROOT)
|
|
action = "hoe"
|
|
update_icons()
|
|
visible_message("<span class='notice'>[src] starts uprooting the weeds in \the [A].</span>")
|
|
|
|
busy = 1
|
|
if(do_after(src, 30))
|
|
visible_message("<span class='notice'>[src] uproots the weeds in \the [A].</span>")
|
|
T.weedlevel = 0
|
|
if(FARMBOT_NUTRIMENT)
|
|
action = "fertile"
|
|
update_icons()
|
|
visible_message("<span class='notice'>[src] starts fertilizing \the [A].</span>")
|
|
|
|
busy = 1
|
|
if(do_after(src, 30, A))
|
|
|
|
visible_message("<span class='notice'>[src] fertilizes \the [A].</span>")
|
|
T.reagents.add_reagent("ammonia", 10)
|
|
|
|
busy = 0
|
|
action = ""
|
|
update_icons()
|
|
T.update_icon()
|
|
else if(istype(A, /obj/structure/sink))
|
|
if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume)
|
|
return
|
|
action = "water"
|
|
update_icons()
|
|
visible_message("<span class='notice'>[src] starts refilling its tank from \the [A].</span>")
|
|
|
|
busy = 1
|
|
while(do_after(src, 10) && tank.reagents.total_volume < tank.reagents.maximum_volume)
|
|
tank.reagents.add_reagent("water", 10)
|
|
if(prob(5))
|
|
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
|
|
|
|
busy = 0
|
|
action = ""
|
|
update_icons()
|
|
visible_message("<span class='notice'>[src] finishes refilling its tank.</span>")
|
|
else if(emagged && ishuman(A))
|
|
var/action = pick("weed", "water")
|
|
|
|
busy = 1
|
|
spawn(50) // Some delay
|
|
|
|
busy = 0
|
|
switch(action)
|
|
if("weed")
|
|
flick("farmbot_hoe", src)
|
|
do_attack_animation(A)
|
|
if(prob(50))
|
|
visible_message("<span class='danger'>[src] swings wildly at [A] with a minihoe, missing completely!</span>")
|
|
return
|
|
var/t = pick("slashed", "sliced", "cut", "clawed")
|
|
A.attack_generic(src, 5, t)
|
|
if("water")
|
|
flick("farmbot_water", src)
|
|
|
|
visible_message("<span class='danger'>[src] splashes [A] with water!</span>")
|
|
tank.reagents.splash(A, 100)
|
|
|
|
/mob/living/bot/farmbot/explode()
|
|
visible_message("<span class='danger'>[src] blows apart!</span>")
|
|
var/turf/Tsec = get_turf(src)
|
|
|
|
new /obj/item/weapon/material/minihoe(Tsec)
|
|
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
|
|
new /obj/item/device/assembly/prox_sensor(Tsec)
|
|
new /obj/item/device/analyzer/plant_analyzer(Tsec)
|
|
|
|
if(tank)
|
|
tank.loc = Tsec
|
|
|
|
if(prob(50))
|
|
new /obj/item/robot_parts/l_arm(Tsec)
|
|
|
|
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
|
s.set_up(3, 1, src)
|
|
s.start()
|
|
qdel(src)
|
|
return
|
|
|
|
|
|
/mob/living/bot/farmbot/confirmTarget(var/atom/targ)
|
|
if(!..())
|
|
return 0
|
|
|
|
if(emagged && ishuman(targ))
|
|
if(targ in view(world.view, src))
|
|
return 1
|
|
return 0
|
|
|
|
if(istype(targ, /obj/structure/sink))
|
|
if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume)
|
|
return 0
|
|
return 1
|
|
|
|
var/obj/machinery/portable_atmospherics/hydroponics/tray = targ
|
|
if(!istype(tray))
|
|
return 0
|
|
|
|
if(tray.closed_system || !tray.seed)
|
|
return 0
|
|
|
|
if(tray.dead && removes_dead || tray.harvest && collects_produce)
|
|
return FARMBOT_COLLECT
|
|
|
|
else if(refills_water && tray.waterlevel < 40 && !tray.reagents.has_reagent("water"))
|
|
return FARMBOT_WATER
|
|
|
|
else if(uproots_weeds && tray.weedlevel > 3)
|
|
return FARMBOT_UPROOT
|
|
|
|
else if(replaces_nutriment && tray.nutrilevel < 1 && tray.reagents.total_volume < 1)
|
|
return FARMBOT_NUTRIMENT
|
|
|
|
return 0
|
|
|
|
// Assembly
|
|
|
|
/obj/item/weapon/farmbot_arm_assembly
|
|
name = "water tank/robot arm assembly"
|
|
desc = "A water tank with a robot arm permanently grafted to it."
|
|
icon = 'icons/obj/aibots.dmi'
|
|
icon_state = "water_arm"
|
|
var/build_step = 0
|
|
var/created_name = "Farmbot"
|
|
var/obj/tank
|
|
w_class = ITEMSIZE_NORMAL
|
|
|
|
|
|
/obj/item/weapon/farmbot_arm_assembly/New(var/newloc, var/theTank)
|
|
..(newloc)
|
|
if(!theTank) // If an admin spawned it, it won't have a watertank it, so lets make one for em!
|
|
tank = new /obj/structure/reagent_dispensers/watertank(src)
|
|
else
|
|
tank = theTank
|
|
tank.forceMove(src)
|
|
|
|
/obj/structure/reagent_dispensers/watertank/attackby(var/obj/item/robot_parts/S, mob/user as mob)
|
|
if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
|
|
..()
|
|
return
|
|
|
|
|
|
user << "You add the robot arm to [src]."
|
|
|
|
user.drop_from_inventory(S)
|
|
qdel(S)
|
|
|
|
new /obj/item/weapon/farmbot_arm_assembly(loc, src)
|
|
|
|
/obj/structure/reagent_dispensers/watertank/attackby(var/obj/item/organ/external/S, mob/user as mob)
|
|
if ((!istype(S, /obj/item/organ/external/arm)) || (!S.robotic == ORGAN_ROBOT))
|
|
..()
|
|
return
|
|
|
|
user << "You add the robot arm to [src]."
|
|
|
|
user.drop_from_inventory(S)
|
|
qdel(S)
|
|
|
|
new /obj/item/weapon/farmbot_arm_assembly(loc, src)
|
|
|
|
/obj/item/weapon/farmbot_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
..()
|
|
if((istype(W, /obj/item/device/analyzer/plant_analyzer)) && (build_step == 0))
|
|
build_step++
|
|
user << "You add the plant analyzer to [src]."
|
|
name = "farmbot assembly"
|
|
|
|
user.remove_from_mob(W)
|
|
qdel(W)
|
|
|
|
else if((istype(W, /obj/item/weapon/reagent_containers/glass/bucket)) && (build_step == 1))
|
|
build_step++
|
|
user << "You add a bucket to [src]."
|
|
name = "farmbot assembly with bucket"
|
|
|
|
user.remove_from_mob(W)
|
|
qdel(W)
|
|
|
|
else if((istype(W, /obj/item/weapon/material/minihoe)) && (build_step == 2))
|
|
build_step++
|
|
user << "You add a minihoe to [src]."
|
|
name = "farmbot assembly with bucket and minihoe"
|
|
|
|
user.remove_from_mob(W)
|
|
qdel(W)
|
|
|
|
else if((isprox(W)) && (build_step == 3))
|
|
build_step++
|
|
user << "You complete the Farmbot! Beep boop."
|
|
|
|
var/mob/living/bot/farmbot/S = new /mob/living/bot/farmbot(get_turf(src), tank)
|
|
S.name = created_name
|
|
|
|
user.remove_from_mob(W)
|
|
qdel(W)
|
|
qdel(src)
|
|
|
|
else if(istype(W, /obj/item/weapon/pen))
|
|
var/t = input(user, "Enter new robot name", name, created_name) as text
|
|
t = sanitize(t, MAX_NAME_LEN)
|
|
if(!t)
|
|
return
|
|
if(!in_range(src, usr) && loc != usr)
|
|
return
|
|
|
|
created_name = t
|
|
|
|
/obj/item/weapon/farmbot_arm_assembly/attack_hand(mob/user as mob)
|
|
return //it's a converted watertank, no you cannot pick it up and put it in your backpack |