mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-07-19 12:13:38 +01:00
Merges AI Branch into Master
This commit is contained in:
+13
-13
@@ -280,21 +280,21 @@
|
||||
if("larva") M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob )
|
||||
if("nymph") M.change_mob_type( /mob/living/carbon/alien/diona , null, null, delmob )
|
||||
if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"])
|
||||
if("slime") M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob )
|
||||
if("slime") M.change_mob_type( /mob/living/simple_mob/slime/xenobio , null, null, delmob )
|
||||
if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob )
|
||||
if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob )
|
||||
if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob )
|
||||
if("runtime") M.change_mob_type( /mob/living/simple_animal/cat/fluff/Runtime , null, null, delmob )
|
||||
if("corgi") M.change_mob_type( /mob/living/simple_animal/corgi , null, null, delmob )
|
||||
if("ian") M.change_mob_type( /mob/living/simple_animal/corgi/Ian , null, null, delmob )
|
||||
if("crab") M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob )
|
||||
if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob )
|
||||
if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob )
|
||||
if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob )
|
||||
if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/construct/armoured , null, null, delmob )
|
||||
if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob )
|
||||
if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob )
|
||||
if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
|
||||
if("cat") M.change_mob_type( /mob/living/simple_mob/animal/passive/cat , null, null, delmob )
|
||||
if("runtime") M.change_mob_type( /mob/living/simple_mob/animal/passive/cat/runtime , null, null, delmob )
|
||||
if("corgi") M.change_mob_type( /mob/living/simple_mob/animal/passive/dog/corgi , null, null, delmob )
|
||||
if("ian") M.change_mob_type( /mob/living/simple_mob/animal/passive/dog/corgi/Ian , null, null, delmob )
|
||||
if("crab") M.change_mob_type( /mob/living/simple_mob/animal/passive/crab , null, null, delmob )
|
||||
if("coffee") M.change_mob_type( /mob/living/simple_mob/animal/passive/crab/Coffee , null, null, delmob )
|
||||
if("parrot") M.change_mob_type( /mob/living/simple_mob/animal/passive/bird/parrot , null, null, delmob )
|
||||
if("polyparrot") M.change_mob_type( /mob/living/simple_mob/animal/passive/bird/parrot/poly , null, null, delmob )
|
||||
if("constructarmoured") M.change_mob_type( /mob/living/simple_mob/construct/juggernaut , null, null, delmob )
|
||||
if("constructbuilder") M.change_mob_type( /mob/living/simple_mob/construct/artificer , null, null, delmob )
|
||||
if("constructwraith") M.change_mob_type( /mob/living/simple_mob/construct/wraith , null, null, delmob )
|
||||
if("shade") M.change_mob_type( /mob/living/simple_mob/construct/shade , null, null, delmob )
|
||||
|
||||
|
||||
/////////////////////////////////////new ban stuff
|
||||
|
||||
@@ -127,6 +127,18 @@
|
||||
usr << "<span class='notice'>Right Mouse Button on turf/obj/mob = Reset glowing</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on buildmode button = Change glow properties</span>"
|
||||
usr << "<span class='notice'>***********************************************************</span>"
|
||||
if(9) // Control mobs with ai_holders.
|
||||
usr << "<span class='notice'>***********************************************************</span>"
|
||||
usr << "<span class='notice'>Left Mouse Button on AI mob = Select/Deselect mob</span>"
|
||||
usr << "<span class='notice'>Left Mouse Button + alt on AI mob = Toggle hostility on mob</span>"
|
||||
usr << "<span class='notice'>Left Mouse Button + ctrl on AI mob = Reset target/following/movement</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on enemy mob = Command selected mobs to attack mob</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on allied mob = Command selected mobs to follow mob</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button + shift on any mob = Command selected mobs to follow mob regardless of faction</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button on tile = Command selected mobs to move to tile (will cancel if enemies are seen)</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button + shift on tile = Command selected mobs to reposition to tile (will not be inturrupted by enemies)</span>"
|
||||
usr << "<span class='notice'>Right Mouse Button + alt on obj/turfs = Command selected mobs to attack obj/turf</span>"
|
||||
usr << "<span class='notice'>***********************************************************</span>"
|
||||
return 1
|
||||
|
||||
/obj/effect/bmode/buildquit
|
||||
@@ -146,6 +158,7 @@
|
||||
var/obj/effect/bmode/buildmode/buildmode = null
|
||||
var/obj/effect/bmode/buildquit/buildquit = null
|
||||
var/atom/movable/throw_atom = null
|
||||
var/list/selected_mobs = list()
|
||||
|
||||
/obj/effect/bmode/buildholder/Destroy()
|
||||
qdel(builddir)
|
||||
@@ -157,9 +170,21 @@
|
||||
qdel(buildquit)
|
||||
buildquit = null
|
||||
throw_atom = null
|
||||
for(var/mob/living/unit in selected_mobs)
|
||||
deselect_AI_mob(cl, unit)
|
||||
selected_mobs.Cut()
|
||||
cl = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/bmode/buildholder/proc/select_AI_mob(client/C, mob/living/unit)
|
||||
selected_mobs += unit
|
||||
C.images += unit.selected_image
|
||||
|
||||
/obj/effect/bmode/buildholder/proc/deselect_AI_mob(client/C, mob/living/unit)
|
||||
selected_mobs -= unit
|
||||
C.images -= unit.selected_image
|
||||
|
||||
|
||||
/obj/effect/bmode/buildmode
|
||||
icon_state = "buildmode1"
|
||||
screen_loc = "NORTH,WEST+2"
|
||||
@@ -210,6 +235,9 @@
|
||||
master.cl.buildmode = 8
|
||||
src.icon_state = "buildmode8"
|
||||
if(8)
|
||||
master.cl.buildmode = 9
|
||||
src.icon_state = "buildmode9"
|
||||
if(9)
|
||||
master.cl.buildmode = 1
|
||||
src.icon_state = "buildmode1"
|
||||
|
||||
@@ -416,6 +444,86 @@
|
||||
if(pa.Find("right"))
|
||||
if(object)
|
||||
object.set_light(0, 0, "#FFFFFF")
|
||||
if(9) // AI control
|
||||
if(pa.Find("left"))
|
||||
if(isliving(object))
|
||||
var/mob/living/L = object
|
||||
// Reset processes.
|
||||
if(pa.Find("ctrl"))
|
||||
if(!isnull(L.get_AI_stance())) // Null means there's no AI datum or it has one but is player controlled w/o autopilot on.
|
||||
var/datum/ai_holder/AI = L.ai_holder
|
||||
AI.forget_everything()
|
||||
to_chat(user, span("notice", "\The [L]'s AI has forgotten its target/movement destination/leader."))
|
||||
else
|
||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||
return
|
||||
|
||||
// Toggle hostility
|
||||
if(pa.Find("alt"))
|
||||
if(!isnull(L.get_AI_stance()))
|
||||
var/datum/ai_holder/AI = L.ai_holder
|
||||
AI.hostile = !AI.hostile
|
||||
to_chat(user, span("notice", "\The [L] is now [AI.hostile ? "hostile" : "passive"]."))
|
||||
else
|
||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||
return
|
||||
|
||||
// Select/Deselect
|
||||
if(!isnull(L.get_AI_stance()))
|
||||
if(L in holder.selected_mobs)
|
||||
holder.deselect_AI_mob(user.client, L)
|
||||
to_chat(user, span("notice", "Deselected \the [L]."))
|
||||
else
|
||||
holder.select_AI_mob(user.client, L)
|
||||
to_chat(user, span("notice", "Selected \the [L]."))
|
||||
else
|
||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||
|
||||
if(pa.Find("right"))
|
||||
if(istype(object, /atom)) // Force attack.
|
||||
var/atom/A = object
|
||||
|
||||
if(pa.Find("alt"))
|
||||
var/i = 0
|
||||
for(var/mob/living/unit in holder.selected_mobs)
|
||||
var/datum/ai_holder/AI = unit.ai_holder
|
||||
AI.give_target(A)
|
||||
i++
|
||||
to_chat(user, span("notice", "Commanded [i] mob\s to attack \the [A]."))
|
||||
return
|
||||
|
||||
if(isliving(object)) // Follow or attack.
|
||||
var/mob/living/L = object
|
||||
var/i = 0 // Attacking mobs.
|
||||
var/j = 0 // Following mobs.
|
||||
for(var/mob/living/unit in holder.selected_mobs)
|
||||
var/datum/ai_holder/AI = unit.ai_holder
|
||||
if(L.IIsAlly(unit) || !AI.hostile || pa.Find("shift"))
|
||||
AI.set_follow(L)
|
||||
j++
|
||||
else
|
||||
AI.give_target(L)
|
||||
i++
|
||||
var/message = "Commanded "
|
||||
if(i)
|
||||
message += "[i] mob\s to attack \the [L]"
|
||||
if(j)
|
||||
message += ", and "
|
||||
else
|
||||
message += "."
|
||||
if(j)
|
||||
message += "[j] mob\s to follow \the [L]."
|
||||
to_chat(user, span("notice", message))
|
||||
|
||||
if(isturf(object)) // Move or reposition.
|
||||
var/turf/T = object
|
||||
var/i = 0
|
||||
for(var/mob/living/unit in holder.selected_mobs)
|
||||
var/datum/ai_holder/AI = unit.ai_holder
|
||||
AI.give_destination(T, 1, pa.Find("shift")) // If shift is held, the mobs will not stop moving to attack a visible enemy.
|
||||
i++
|
||||
to_chat(user, span("notice", "Commanded [i] mob\s to move to \the [T]."))
|
||||
|
||||
|
||||
/obj/effect/bmode/buildmode/proc/get_path_from_partial_text(default_path)
|
||||
var/desired_path = input("Enter full or partial typepath.","Typepath","[default_path]")
|
||||
|
||||
@@ -1,115 +1,99 @@
|
||||
/client/proc/admin_lightning_strike()
|
||||
set name = "Lightning Strike"
|
||||
set desc = "Causes lightning to strike on your tile. This will hurt things on or nearby it severely."
|
||||
set category = "Fun"
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/result = alert(src, "Really strike your tile with lightning?", "Confirm Badmin" , "No", "Yes (Cosmetic)", "Yes (Real)")
|
||||
|
||||
if(result == "No")
|
||||
return
|
||||
var/fake_lightning = result == "Yes (Cosmetic)"
|
||||
|
||||
lightning_strike(get_turf(usr), fake_lightning)
|
||||
log_and_message_admins("[key_name(src)] has caused [fake_lightning ? "cosmetic":"harmful"] lightning to strike at their position ([src.mob.x], [src.mob.y], [src.mob.z]). \
|
||||
(<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[src.mob.x];Y=[src.mob.y];Z=[src.mob.z]'>JMP</a>)")
|
||||
|
||||
#define LIGHTNING_REDIRECT_RANGE 28 // How far in tiles certain things draw lightning from.
|
||||
#define LIGHTNING_ZAP_RANGE 3 // How far the tesla effect zaps, as well as the bad effects from a direct strike.
|
||||
#define LIGHTNING_POWER 20000 // How much 'zap' is in a strike, used for tesla_zap().
|
||||
|
||||
// The real lightning proc.
|
||||
// This is global until I can figure out a better place for it.
|
||||
// T is the turf that is being struck. If cosmetic is true, the lightning won't actually hurt anything.
|
||||
/proc/lightning_strike(turf/T, cosmetic = FALSE)
|
||||
// First, visuals.
|
||||
|
||||
// Do a lightning flash for the whole planet, if the turf belongs to a planet.
|
||||
var/datum/planet/P = null
|
||||
P = SSplanets.z_to_planet[T.z]
|
||||
if(P)
|
||||
var/datum/weather_holder/holder = P.weather_holder
|
||||
flick("lightning_flash", holder.special_visuals)
|
||||
|
||||
// Before we do the other visuals, we need to see if something is going to hijack our intended target.
|
||||
var/obj/machinery/power/grounding_rod/ground = null // Most of the bad effects of lightning will get negated if a grounding rod is nearby.
|
||||
var/obj/machinery/power/tesla_coil/coil = null // However a tesla coil has higher priority and the strike will bounce.
|
||||
|
||||
for(var/obj/machinery/power/thing in range(LIGHTNING_REDIRECT_RANGE, T))
|
||||
if(istype(thing, /obj/machinery/power/tesla_coil))
|
||||
var/turf/simulated/coil_turf = get_turf(thing)
|
||||
if(istype(coil_turf) && thing.anchored && coil_turf.outdoors)
|
||||
coil = thing
|
||||
break
|
||||
|
||||
if(istype(thing, /obj/machinery/power/grounding_rod))
|
||||
var/turf/simulated/rod_turf = get_turf(thing)
|
||||
if(istype(rod_turf) && thing.anchored && rod_turf.outdoors)
|
||||
ground = thing
|
||||
|
||||
if(coil) // Coil gets highest priority.
|
||||
T = coil.loc
|
||||
else if(ground)
|
||||
T = ground.loc
|
||||
|
||||
// Now make the lightning strike sprite. It will fade and delete itself in a second.
|
||||
new /obj/effect/temporary_effect/lightning_strike(T)
|
||||
|
||||
// For those close up.
|
||||
playsound(T, 'sound/effects/lightningbolt.ogg', 100, 1)
|
||||
|
||||
// And for those far away. If the strike happens on a planet, everyone on the planet will hear it.
|
||||
// Otherwise only those on the current z-level will hear it.
|
||||
var/sound = get_sfx("thunder")
|
||||
for(var/mob/M in player_list)
|
||||
if((P && M.z in P.expected_z_levels) || M.z == T.z)
|
||||
M.playsound_local(get_turf(M), soundin = sound, vol = 70, vary = FALSE, is_global = TRUE)
|
||||
|
||||
if(cosmetic) // Everything beyond here involves potentially damaging things. If we don't want to do that, stop now.
|
||||
return
|
||||
|
||||
if(ground) // All is well.
|
||||
ground.tesla_act(LIGHTNING_POWER, FALSE)
|
||||
return
|
||||
|
||||
else if(coil) // Otherwise lets bounce off the tesla coil.
|
||||
coil.tesla_act(LIGHTNING_POWER, TRUE)
|
||||
|
||||
else // Striking the turf directly.
|
||||
tesla_zap(T, zap_range = LIGHTNING_ZAP_RANGE, power = LIGHTNING_POWER, explosive = FALSE, stun_mobs = TRUE)
|
||||
|
||||
// Some extra effects.
|
||||
// Some apply to those within zap range, others if they were a bit farther away.
|
||||
for(var/mob/living/L in view(5, T))
|
||||
if(get_dist(L, T) <= LIGHTNING_ZAP_RANGE) // They probably got zapped.
|
||||
// The actual damage/electrocution is handled by tesla_zap().
|
||||
L.Paralyse(5)
|
||||
L.stuttering += 20
|
||||
L.make_jittery(20)
|
||||
L.emp_act(1)
|
||||
to_chat(L, span("critical", "You've been struck by lightning!"))
|
||||
|
||||
// If a non-player simplemob was struck, inflict huge damage.
|
||||
// If the damage is fatal, the SA is turned to ash.
|
||||
if(istype(L, /mob/living/simple_animal) && !L.key)
|
||||
var/mob/living/simple_animal/SA = L
|
||||
SA.adjustFireLoss(200)
|
||||
SA.updatehealth()
|
||||
if(SA.health <= 0) // Might be best to check/give simple_mobs siemens when this gets ported to new mobs.
|
||||
SA.visible_message(span("critical", "\The [SA] disintegrates into ash!"))
|
||||
SA.ash()
|
||||
continue // No point deafening something that wont exist.
|
||||
|
||||
// Deafen them.
|
||||
if(L.get_ear_protection() < 2)
|
||||
L.AdjustSleeping(-100)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.ear_deaf += 10
|
||||
to_chat(L, span("danger", "Lightning struck nearby, and the thunderclap is deafening!"))
|
||||
|
||||
#undef GROUNDING_ROD_RANGE
|
||||
#undef LIGHTNING_ZAP_RANGE
|
||||
#undef LIGHTNING_POWER
|
||||
/client/proc/admin_lightning_strike()
|
||||
set name = "Lightning Strike"
|
||||
set desc = "Causes lightning to strike on your tile. This will hurt things on or nearby it severely."
|
||||
set category = "Fun"
|
||||
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/result = alert(src, "Really strike your tile with lightning?", "Confirm Badmin" , "No", "Yes (Cosmetic)", "Yes (Real)")
|
||||
|
||||
if(result == "No")
|
||||
return
|
||||
var/fake_lightning = result == "Yes (Cosmetic)"
|
||||
|
||||
lightning_strike(get_turf(usr), fake_lightning)
|
||||
log_and_message_admins("[key_name(src)] has caused [fake_lightning ? "cosmetic":"harmful"] lightning to strike at their position ([src.mob.x], [src.mob.y], [src.mob.z]). \
|
||||
(<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[src.mob.x];Y=[src.mob.y];Z=[src.mob.z]'>JMP</a>)")
|
||||
|
||||
#define LIGHTNING_REDIRECT_RANGE 28 // How far in tiles certain things draw lightning from.
|
||||
#define LIGHTNING_ZAP_RANGE 3 // How far the tesla effect zaps, as well as the bad effects from a direct strike.
|
||||
#define LIGHTNING_POWER 20000 // How much 'zap' is in a strike, used for tesla_zap().
|
||||
|
||||
// The real lightning proc.
|
||||
// This is global until I can figure out a better place for it.
|
||||
// T is the turf that is being struck. If cosmetic is true, the lightning won't actually hurt anything.
|
||||
/proc/lightning_strike(turf/T, cosmetic = FALSE)
|
||||
// First, visuals.
|
||||
|
||||
// Do a lightning flash for the whole planet, if the turf belongs to a planet.
|
||||
var/datum/planet/P = null
|
||||
P = SSplanets.z_to_planet[T.z]
|
||||
if(P)
|
||||
var/datum/weather_holder/holder = P.weather_holder
|
||||
flick("lightning_flash", holder.special_visuals)
|
||||
|
||||
// Before we do the other visuals, we need to see if something is going to hijack our intended target.
|
||||
var/obj/machinery/power/grounding_rod/ground = null // Most of the bad effects of lightning will get negated if a grounding rod is nearby.
|
||||
var/obj/machinery/power/tesla_coil/coil = null // However a tesla coil has higher priority and the strike will bounce.
|
||||
|
||||
for(var/obj/machinery/power/thing in range(LIGHTNING_REDIRECT_RANGE, T))
|
||||
if(istype(thing, /obj/machinery/power/tesla_coil))
|
||||
var/turf/simulated/coil_turf = get_turf(thing)
|
||||
if(istype(coil_turf) && thing.anchored && coil_turf.outdoors)
|
||||
coil = thing
|
||||
break
|
||||
|
||||
if(istype(thing, /obj/machinery/power/grounding_rod))
|
||||
var/turf/simulated/rod_turf = get_turf(thing)
|
||||
if(istype(rod_turf) && thing.anchored && rod_turf.outdoors)
|
||||
ground = thing
|
||||
|
||||
if(coil) // Coil gets highest priority.
|
||||
T = coil.loc
|
||||
else if(ground)
|
||||
T = ground.loc
|
||||
|
||||
// Now make the lightning strike sprite. It will fade and delete itself in a second.
|
||||
new /obj/effect/temporary_effect/lightning_strike(T)
|
||||
|
||||
// For those close up.
|
||||
playsound(T, 'sound/effects/lightningbolt.ogg', 100, 1)
|
||||
|
||||
// And for those far away. If the strike happens on a planet, everyone on the planet will hear it.
|
||||
// Otherwise only those on the current z-level will hear it.
|
||||
var/sound = get_sfx("thunder")
|
||||
for(var/mob/M in player_list)
|
||||
if((P && M.z in P.expected_z_levels) || M.z == T.z)
|
||||
M.playsound_local(get_turf(M), soundin = sound, vol = 70, vary = FALSE, is_global = TRUE)
|
||||
|
||||
if(cosmetic) // Everything beyond here involves potentially damaging things. If we don't want to do that, stop now.
|
||||
return
|
||||
|
||||
if(ground) // All is well.
|
||||
ground.tesla_act(LIGHTNING_POWER, FALSE)
|
||||
return
|
||||
|
||||
else if(coil) // Otherwise lets bounce off the tesla coil.
|
||||
coil.tesla_act(LIGHTNING_POWER, TRUE)
|
||||
|
||||
else // Striking the turf directly.
|
||||
tesla_zap(T, zap_range = LIGHTNING_ZAP_RANGE, power = LIGHTNING_POWER, explosive = FALSE, stun_mobs = TRUE)
|
||||
|
||||
// Some extra effects.
|
||||
// Some apply to those within zap range, others if they were a bit farther away.
|
||||
for(var/mob/living/L in view(5, T))
|
||||
if(get_dist(L, T) <= LIGHTNING_ZAP_RANGE) // They probably got zapped.
|
||||
L.lightning_act()
|
||||
|
||||
// Deafen them.
|
||||
if(L.get_ear_protection() < 2)
|
||||
L.AdjustSleeping(-100)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.ear_deaf += 10
|
||||
to_chat(L, span("danger", "Lightning struck nearby, and the thunderclap is deafening!"))
|
||||
|
||||
#undef GROUNDING_ROD_RANGE
|
||||
#undef LIGHTNING_ZAP_RANGE
|
||||
#undef LIGHTNING_POWER
|
||||
|
||||
Reference in New Issue
Block a user