mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
Merge pull request #6733 from VOREStation/pol-aitweaks
Readd some AI features and improve AI buildmode
This commit is contained in:
@@ -130,6 +130,8 @@ What is the naming convention for planes or layers?
|
|||||||
|
|
||||||
#define PLANE_ADMIN2 33 //Purely for shenanigans (above lighting)
|
#define PLANE_ADMIN2 33 //Purely for shenanigans (above lighting)
|
||||||
|
|
||||||
|
#define PLANE_BUILDMODE 39 //Things that only show up when you have buildmode on
|
||||||
|
|
||||||
//Fullscreen overlays under inventory
|
//Fullscreen overlays under inventory
|
||||||
#define PLANE_FULLSCREEN 90 //Blindness, mesons, druggy, etc
|
#define PLANE_FULLSCREEN 90 //Blindness, mesons, druggy, etc
|
||||||
#define OBFUSCATION_LAYER 5 //Where images covering the view for eyes are put
|
#define OBFUSCATION_LAYER 5 //Where images covering the view for eyes are put
|
||||||
|
|||||||
@@ -394,7 +394,9 @@
|
|||||||
#define VIS_OBJS 20
|
#define VIS_OBJS 20
|
||||||
#define VIS_MOBS 21
|
#define VIS_MOBS 21
|
||||||
|
|
||||||
#define VIS_COUNT 21 //Must be highest number from above.
|
#define VIS_BUILDMODE 22
|
||||||
|
|
||||||
|
#define VIS_COUNT 22 //Must be highest number from above.
|
||||||
|
|
||||||
//Some mob icon layering defines
|
//Some mob icon layering defines
|
||||||
#define BODY_LAYER -100
|
#define BODY_LAYER -100
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ var/list/station_departments = list("Command", "Medical", "Engineering", "Scienc
|
|||||||
//Icons for in-game HUD glasses. Why don't we just share these a little bit?
|
//Icons for in-game HUD glasses. Why don't we just share these a little bit?
|
||||||
var/static/icon/ingame_hud = icon('icons/mob/hud.dmi')
|
var/static/icon/ingame_hud = icon('icons/mob/hud.dmi')
|
||||||
var/static/icon/ingame_hud_med = icon('icons/mob/hud_med.dmi')
|
var/static/icon/ingame_hud_med = icon('icons/mob/hud_med.dmi')
|
||||||
|
var/static/icon/buildmode_hud = icon('icons/misc/buildmode.dmi')
|
||||||
|
|
||||||
//Keyed list for caching icons so you don't need to make them for records, IDs, etc all separately.
|
//Keyed list for caching icons so you don't need to make them for records, IDs, etc all separately.
|
||||||
//Could be useful for AI impersonation or something at some point?
|
//Could be useful for AI impersonation or something at some point?
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
#define BUILDMODE_BASIC 1
|
||||||
|
#define BUILDMODE_ADVANCED 2
|
||||||
|
#define BUILDMODE_EDIT 3
|
||||||
|
#define BUILDMODE_THROW 4
|
||||||
|
#define BUILDMODE_ROOM 5
|
||||||
|
#define BUILDMODE_LADDER 6
|
||||||
|
#define BUILDMODE_CONTENTS 7
|
||||||
|
#define BUILDMODE_LIGHTS 8
|
||||||
|
#define BUILDMODE_AI 9
|
||||||
|
|
||||||
|
#define LAST_BUILDMODE 9
|
||||||
|
|
||||||
/proc/togglebuildmode(mob/M as mob in player_list)
|
/proc/togglebuildmode(mob/M as mob in player_list)
|
||||||
set name = "Toggle Build Mode"
|
set name = "Toggle Build Mode"
|
||||||
set category = "Special Verbs"
|
set category = "Special Verbs"
|
||||||
@@ -6,6 +18,7 @@
|
|||||||
log_admin("[key_name(usr)] has left build mode.")
|
log_admin("[key_name(usr)] has left build mode.")
|
||||||
M.client.buildmode = 0
|
M.client.buildmode = 0
|
||||||
M.client.show_popup_menus = 1
|
M.client.show_popup_menus = 1
|
||||||
|
M.plane_holder.set_vis(VIS_BUILDMODE, FALSE)
|
||||||
for(var/obj/effect/bmode/buildholder/H)
|
for(var/obj/effect/bmode/buildholder/H)
|
||||||
if(H.cl == M.client)
|
if(H.cl == M.client)
|
||||||
qdel(H)
|
qdel(H)
|
||||||
@@ -13,6 +26,7 @@
|
|||||||
log_admin("[key_name(usr)] has entered build mode.")
|
log_admin("[key_name(usr)] has entered build mode.")
|
||||||
M.client.buildmode = 1
|
M.client.buildmode = 1
|
||||||
M.client.show_popup_menus = 0
|
M.client.show_popup_menus = 0
|
||||||
|
M.plane_holder.set_vis(VIS_BUILDMODE, TRUE)
|
||||||
|
|
||||||
var/obj/effect/bmode/buildholder/H = new/obj/effect/bmode/buildholder()
|
var/obj/effect/bmode/buildholder/H = new/obj/effect/bmode/buildholder()
|
||||||
var/obj/effect/bmode/builddir/A = new/obj/effect/bmode/builddir(H)
|
var/obj/effect/bmode/builddir/A = new/obj/effect/bmode/builddir(H)
|
||||||
@@ -72,7 +86,8 @@
|
|||||||
screen_loc = "NORTH,WEST+1"
|
screen_loc = "NORTH,WEST+1"
|
||||||
Click()
|
Click()
|
||||||
switch(master.cl.buildmode)
|
switch(master.cl.buildmode)
|
||||||
if(1) // Basic Build
|
|
||||||
|
if(BUILDMODE_BASIC)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button = Construct / Upgrade</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button = Construct / Upgrade</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button = Deconstruct / Delete / Downgrade</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button = Deconstruct / Delete / Downgrade</span>")
|
||||||
@@ -82,7 +97,8 @@
|
|||||||
to_chat(usr, "<span class='notice'>Use the button in the upper left corner to</span>")
|
to_chat(usr, "<span class='notice'>Use the button in the upper left corner to</span>")
|
||||||
to_chat(usr, "<span class='notice'>change the direction of built objects.</span>")
|
to_chat(usr, "<span class='notice'>change the direction of built objects.</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(2) // Adv. Build
|
|
||||||
|
if(BUILDMODE_ADVANCED)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Set object type</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Set object type</span>")
|
||||||
to_chat(usr, "<span class='notice'>Middle Mouse Button on buildmode button= On/Off object type saying</span>")
|
to_chat(usr, "<span class='notice'>Middle Mouse Button on buildmode button= On/Off object type saying</span>")
|
||||||
@@ -94,44 +110,56 @@
|
|||||||
to_chat(usr, "<span class='notice'>Use the button in the upper left corner to</span>")
|
to_chat(usr, "<span class='notice'>Use the button in the upper left corner to</span>")
|
||||||
to_chat(usr, "<span class='notice'>change the direction of built objects.</span>")
|
to_chat(usr, "<span class='notice'>change the direction of built objects.</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(3) // Edit
|
|
||||||
|
if(BUILDMODE_EDIT)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Select var(type) & value</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Select var(type) & value</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Set var(type) & value</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Set var(type) & value</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Reset var's value</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Reset var's value</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(4) // Throw
|
|
||||||
|
if(BUILDMODE_THROW)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Select</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Select</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Throw</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Throw</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(5) // Room Build
|
|
||||||
|
if(BUILDMODE_ROOM)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on turf = Select as point A</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on turf = Select as point A</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on turf = Select as point B</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on turf = Select as point B</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Change floor/wall type</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Change floor/wall type</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(6) // Make Ladders
|
|
||||||
|
if(BUILDMODE_LADDER)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on turf = Set as upper ladder loc</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on turf = Set as upper ladder loc</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on turf = Set as lower ladder loc</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on turf = Set as lower ladder loc</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(7) // Move Into Contents
|
|
||||||
|
if(BUILDMODE_CONTENTS)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Select</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Select</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Move into selection</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Move into selection</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(8) // Make Lights
|
|
||||||
|
if(BUILDMODE_LIGHTS)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Make it glow</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on turf/obj/mob = Make it glow</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Reset glowing</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on turf/obj/mob = Reset glowing</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Change glow properties</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on buildmode button = Change glow properties</span>")
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
if(9) // Control mobs with ai_holders.
|
|
||||||
|
if(BUILDMODE_AI)
|
||||||
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
to_chat(usr, "<span class='notice'>***********************************************************</span>")
|
||||||
|
to_chat(usr, "<span class='notice'>Left Mouse Button drag box = Select only mobs in box</span>")
|
||||||
|
to_chat(usr, "<span class='notice'>Left Mouse Button drag box + shift = Select additional mobs in area</span>")
|
||||||
|
to_chat(usr, "<span class='notice'>Left Mouse Button on non-mob = Deselect all mobs</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button on AI mob = Select/Deselect mob</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button on AI mob = Select/Deselect mob</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button + alt on AI mob = Toggle hostility on mob</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button + alt on AI mob = Toggle hostility on mob</span>")
|
||||||
to_chat(usr, "<span class='notice'>Left Mouse Button + ctrl on AI mob = Reset target/following/movement</span>")
|
to_chat(usr, "<span class='notice'>Left Mouse Button + shift on AI mob = Toggle AI (also resets)</span>")
|
||||||
|
to_chat(usr, "<span class='notice'>Left Mouse Button + ctrl on AI mob = Copy mob faction</span>")
|
||||||
|
to_chat(usr, "<span class='notice'>Right Mouse Button + ctrl on any mob = Paste mob faction copied with Left Mouse Button + shift</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on enemy mob = Command selected mobs to attack mob</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on enemy mob = Command selected mobs to attack mob</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button on allied mob = Command selected mobs to follow mob</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button on allied mob = Command selected mobs to follow mob</span>")
|
||||||
to_chat(usr, "<span class='notice'>Right Mouse Button + shift on any mob = Command selected mobs to follow mob regardless of faction</span>")
|
to_chat(usr, "<span class='notice'>Right Mouse Button + shift on any mob = Command selected mobs to follow mob regardless of faction</span>")
|
||||||
@@ -159,6 +187,7 @@
|
|||||||
var/obj/effect/bmode/buildquit/buildquit = null
|
var/obj/effect/bmode/buildquit/buildquit = null
|
||||||
var/atom/movable/throw_atom = null
|
var/atom/movable/throw_atom = null
|
||||||
var/list/selected_mobs = list()
|
var/list/selected_mobs = list()
|
||||||
|
var/copied_faction = null
|
||||||
|
|
||||||
/obj/effect/bmode/buildholder/Destroy()
|
/obj/effect/bmode/buildholder/Destroy()
|
||||||
qdel(builddir)
|
qdel(builddir)
|
||||||
@@ -184,7 +213,6 @@
|
|||||||
selected_mobs -= unit
|
selected_mobs -= unit
|
||||||
C.images -= unit.selected_image
|
C.images -= unit.selected_image
|
||||||
|
|
||||||
|
|
||||||
/obj/effect/bmode/buildmode
|
/obj/effect/bmode/buildmode
|
||||||
icon_state = "buildmode1"
|
icon_state = "buildmode1"
|
||||||
screen_loc = "NORTH,WEST+2"
|
screen_loc = "NORTH,WEST+2"
|
||||||
@@ -207,48 +235,25 @@
|
|||||||
|
|
||||||
if(pa.Find("middle"))
|
if(pa.Find("middle"))
|
||||||
switch(master.cl.buildmode)
|
switch(master.cl.buildmode)
|
||||||
if(2)
|
if(BUILDMODE_ADVANCED)
|
||||||
objsay=!objsay
|
objsay=!objsay
|
||||||
|
|
||||||
|
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
switch(master.cl.buildmode)
|
if(master.cl.buildmode == LAST_BUILDMODE)
|
||||||
if(1)
|
master.cl.buildmode = 1
|
||||||
master.cl.buildmode = 2
|
else
|
||||||
src.icon_state = "buildmode2"
|
master.cl.buildmode++
|
||||||
if(2)
|
src.icon_state = "buildmode[master.cl.buildmode]"
|
||||||
master.cl.buildmode = 3
|
|
||||||
src.icon_state = "buildmode3"
|
|
||||||
if(3)
|
|
||||||
master.cl.buildmode = 4
|
|
||||||
src.icon_state = "buildmode4"
|
|
||||||
if(4)
|
|
||||||
master.cl.buildmode = 5
|
|
||||||
src.icon_state = "buildmode5"
|
|
||||||
if(5)
|
|
||||||
master.cl.buildmode = 6
|
|
||||||
src.icon_state = "buildmode6"
|
|
||||||
if(6)
|
|
||||||
master.cl.buildmode = 7
|
|
||||||
src.icon_state = "buildmode7"
|
|
||||||
if(7)
|
|
||||||
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"
|
|
||||||
|
|
||||||
else if(pa.Find("right"))
|
else if(pa.Find("right"))
|
||||||
switch(master.cl.buildmode)
|
switch(master.cl.buildmode)
|
||||||
if(1) // Basic Build
|
if(BUILDMODE_BASIC)
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
if(2) // Adv. Build
|
if(BUILDMODE_ADVANCED)
|
||||||
objholder = get_path_from_partial_text(/obj/structure/closet)
|
objholder = get_path_from_partial_text(/obj/structure/closet)
|
||||||
|
|
||||||
if(3) // Edit
|
if(BUILDMODE_EDIT)
|
||||||
var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine")
|
var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine")
|
||||||
|
|
||||||
master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name")
|
master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name")
|
||||||
@@ -267,14 +272,16 @@
|
|||||||
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world
|
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world
|
||||||
if("turf-reference")
|
if("turf-reference")
|
||||||
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world
|
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world
|
||||||
if(5) // Room build
|
|
||||||
|
if(BUILDMODE_ROOM)
|
||||||
var/choice = alert("Would you like to change the floor or wall holders?","Room Builder", "Floor", "Wall")
|
var/choice = alert("Would you like to change the floor or wall holders?","Room Builder", "Floor", "Wall")
|
||||||
switch(choice)
|
switch(choice)
|
||||||
if("Floor")
|
if("Floor")
|
||||||
floor_holder = get_path_from_partial_text(/turf/simulated/floor/plating)
|
floor_holder = get_path_from_partial_text(/turf/simulated/floor/plating)
|
||||||
if("Wall")
|
if("Wall")
|
||||||
wall_holder = get_path_from_partial_text(/turf/simulated/wall)
|
wall_holder = get_path_from_partial_text(/turf/simulated/wall)
|
||||||
if(8) // Lights
|
|
||||||
|
if(BUILDMODE_LIGHTS)
|
||||||
var/choice = alert("Change the new light range, power, or color?", "Light Maker", "Range", "Power", "Color")
|
var/choice = alert("Change the new light range, power, or color?", "Light Maker", "Range", "Power", "Color")
|
||||||
switch(choice)
|
switch(choice)
|
||||||
if("Range")
|
if("Range")
|
||||||
@@ -301,7 +308,7 @@
|
|||||||
var/list/pa = params2list(params)
|
var/list/pa = params2list(params)
|
||||||
|
|
||||||
switch(buildmode)
|
switch(buildmode)
|
||||||
if(1) // Basic Build
|
if(BUILDMODE_BASIC)
|
||||||
if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") )
|
if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") )
|
||||||
if(istype(object,/turf/space))
|
if(istype(object,/turf/space))
|
||||||
var/turf/T = object
|
var/turf/T = object
|
||||||
@@ -350,7 +357,8 @@
|
|||||||
if(NORTHWEST)
|
if(NORTHWEST)
|
||||||
var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
|
var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
|
||||||
WIN.set_dir(NORTHWEST)
|
WIN.set_dir(NORTHWEST)
|
||||||
if(2) // Adv. Build
|
|
||||||
|
if(BUILDMODE_ADVANCED)
|
||||||
if(pa.Find("left") && !pa.Find("ctrl"))
|
if(pa.Find("left") && !pa.Find("ctrl"))
|
||||||
if(ispath(holder.buildmode.objholder,/turf))
|
if(ispath(holder.buildmode.objholder,/turf))
|
||||||
var/turf/T = get_turf(object)
|
var/turf/T = get_turf(object)
|
||||||
@@ -369,8 +377,7 @@
|
|||||||
if(holder.buildmode.objsay)
|
if(holder.buildmode.objsay)
|
||||||
to_chat(usr, "[object.type]")
|
to_chat(usr, "[object.type]")
|
||||||
|
|
||||||
|
if(BUILDMODE_EDIT)
|
||||||
if(3) // Edit
|
|
||||||
if(pa.Find("left")) //I cant believe this shit actually compiles.
|
if(pa.Find("left")) //I cant believe this shit actually compiles.
|
||||||
if(object.vars.Find(holder.buildmode.varholder))
|
if(object.vars.Find(holder.buildmode.varholder))
|
||||||
log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]")
|
log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]")
|
||||||
@@ -384,7 +391,7 @@
|
|||||||
else
|
else
|
||||||
to_chat(user, "<span class='danger'>[initial(object.name)] does not have a var called '[holder.buildmode.varholder]'</span>")
|
to_chat(user, "<span class='danger'>[initial(object.name)] does not have a var called '[holder.buildmode.varholder]'</span>")
|
||||||
|
|
||||||
if(4) // Throw
|
if(BUILDMODE_THROW)
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
if(istype(object, /atom/movable))
|
if(istype(object, /atom/movable))
|
||||||
holder.throw_atom = object
|
holder.throw_atom = object
|
||||||
@@ -392,7 +399,8 @@
|
|||||||
if(holder.throw_atom)
|
if(holder.throw_atom)
|
||||||
holder.throw_atom.throw_at(object, 10, 1)
|
holder.throw_atom.throw_at(object, 10, 1)
|
||||||
log_admin("[key_name(usr)] threw [holder.throw_atom] at [object]")
|
log_admin("[key_name(usr)] threw [holder.throw_atom] at [object]")
|
||||||
if(5) // Room build
|
|
||||||
|
if(BUILDMODE_ROOM)
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
holder.buildmode.coordA = get_turf(object)
|
holder.buildmode.coordA = get_turf(object)
|
||||||
to_chat(user, "<span class='notice'>Defined [object] ([object.type]) as point A.</span>")
|
to_chat(user, "<span class='notice'>Defined [object] ([object.type]) as point A.</span>")
|
||||||
@@ -411,7 +419,8 @@
|
|||||||
)
|
)
|
||||||
holder.buildmode.coordA = null
|
holder.buildmode.coordA = null
|
||||||
holder.buildmode.coordB = null
|
holder.buildmode.coordB = null
|
||||||
if(6) // Ladders
|
|
||||||
|
if(BUILDMODE_LADDER)
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
holder.buildmode.coordA = get_turf(object)
|
holder.buildmode.coordA = get_turf(object)
|
||||||
to_chat(user, "<span class='notice'>Defined [object] ([object.type]) as upper ladder location.</span>")
|
to_chat(user, "<span class='notice'>Defined [object] ([object.type]) as upper ladder location.</span>")
|
||||||
@@ -430,7 +439,8 @@
|
|||||||
B.update_icon()
|
B.update_icon()
|
||||||
holder.buildmode.coordA = null
|
holder.buildmode.coordA = null
|
||||||
holder.buildmode.coordB = null
|
holder.buildmode.coordB = null
|
||||||
if(7) // Move into contents
|
|
||||||
|
if(BUILDMODE_CONTENTS)
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
if(istype(object, /atom))
|
if(istype(object, /atom))
|
||||||
holder.throw_atom = object
|
holder.throw_atom = object
|
||||||
@@ -438,23 +448,32 @@
|
|||||||
if(holder.throw_atom && istype(object, /atom/movable))
|
if(holder.throw_atom && istype(object, /atom/movable))
|
||||||
object.forceMove(holder.throw_atom)
|
object.forceMove(holder.throw_atom)
|
||||||
log_admin("[key_name(usr)] moved [object] into [holder.throw_atom].")
|
log_admin("[key_name(usr)] moved [object] into [holder.throw_atom].")
|
||||||
if(8) // Lights
|
|
||||||
|
if(BUILDMODE_LIGHTS)
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
if(object)
|
if(object)
|
||||||
object.set_light(holder.buildmode.new_light_range, holder.buildmode.new_light_intensity, holder.buildmode.new_light_color)
|
object.set_light(holder.buildmode.new_light_range, holder.buildmode.new_light_intensity, holder.buildmode.new_light_color)
|
||||||
if(pa.Find("right"))
|
if(pa.Find("right"))
|
||||||
if(object)
|
if(object)
|
||||||
object.set_light(0, 0, "#FFFFFF")
|
object.set_light(0, 0, "#FFFFFF")
|
||||||
if(9) // AI control
|
|
||||||
|
if(BUILDMODE_AI)
|
||||||
if(pa.Find("left"))
|
if(pa.Find("left"))
|
||||||
if(isliving(object))
|
if(isliving(object))
|
||||||
var/mob/living/L = object
|
var/mob/living/L = object
|
||||||
// Reset processes.
|
|
||||||
if(pa.Find("ctrl"))
|
// Pause/unpause AI
|
||||||
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.
|
if(pa.Find("shift"))
|
||||||
|
var/stance = L.get_AI_stance()
|
||||||
|
if(!isnull(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
|
var/datum/ai_holder/AI = L.ai_holder
|
||||||
AI.forget_everything()
|
if(stance == STANCE_SLEEP)
|
||||||
to_chat(user, span("notice", "\The [L]'s AI has forgotten its target/movement destination/leader."))
|
AI.go_wake()
|
||||||
|
to_chat(user, span("notice", "\The [L]'s AI has been enabled."))
|
||||||
|
else
|
||||||
|
AI.go_sleep()
|
||||||
|
to_chat(user, span("notice", "\The [L]'s AI has been disabled."))
|
||||||
|
return
|
||||||
else
|
else
|
||||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||||
return
|
return
|
||||||
@@ -469,6 +488,12 @@
|
|||||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// Copy faction
|
||||||
|
if(pa.Find("ctrl"))
|
||||||
|
holder.copied_faction = L.faction
|
||||||
|
to_chat(user, span("notice", "Copied faction '[holder.copied_faction]'."))
|
||||||
|
return
|
||||||
|
|
||||||
// Select/Deselect
|
// Select/Deselect
|
||||||
if(!isnull(L.get_AI_stance()))
|
if(!isnull(L.get_AI_stance()))
|
||||||
if(L in holder.selected_mobs)
|
if(L in holder.selected_mobs)
|
||||||
@@ -477,10 +502,27 @@
|
|||||||
else
|
else
|
||||||
holder.select_AI_mob(user.client, L)
|
holder.select_AI_mob(user.client, L)
|
||||||
to_chat(user, span("notice", "Selected \the [L]."))
|
to_chat(user, span("notice", "Selected \the [L]."))
|
||||||
|
return
|
||||||
else
|
else
|
||||||
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
to_chat(user, span("warning", "\The [L] is not AI controlled."))
|
||||||
|
return
|
||||||
|
else //Not living
|
||||||
|
for(var/mob/living/unit in holder.selected_mobs)
|
||||||
|
holder.deselect_AI_mob(user.client, unit)
|
||||||
|
|
||||||
|
|
||||||
if(pa.Find("right"))
|
if(pa.Find("right"))
|
||||||
|
// Paste faction
|
||||||
|
if(pa.Find("ctrl") && isliving(object))
|
||||||
|
if(!holder.copied_faction)
|
||||||
|
to_chat(user, span("warning", "LMB+Shift a mob to copy their faction before pasting."))
|
||||||
|
return
|
||||||
|
else
|
||||||
|
var/mob/living/L = object
|
||||||
|
L.faction = holder.copied_faction
|
||||||
|
to_chat(user, span("notice", "Pasted faction '[holder.copied_faction]'."))
|
||||||
|
return
|
||||||
|
|
||||||
if(istype(object, /atom)) // Force attack.
|
if(istype(object, /atom)) // Force attack.
|
||||||
var/atom/A = object
|
var/atom/A = object
|
||||||
|
|
||||||
@@ -491,6 +533,9 @@
|
|||||||
AI.give_target(A)
|
AI.give_target(A)
|
||||||
i++
|
i++
|
||||||
to_chat(user, span("notice", "Commanded [i] mob\s to attack \the [A]."))
|
to_chat(user, span("notice", "Commanded [i] mob\s to attack \the [A]."))
|
||||||
|
var/image/orderimage = image(buildmode_hud,A,"ai_targetorder")
|
||||||
|
orderimage.plane = PLANE_BUILDMODE
|
||||||
|
flick_overlay(orderimage, list(user.client), 8, TRUE)
|
||||||
return
|
return
|
||||||
|
|
||||||
if(isliving(object)) // Follow or attack.
|
if(isliving(object)) // Follow or attack.
|
||||||
@@ -515,16 +560,67 @@
|
|||||||
if(j)
|
if(j)
|
||||||
message += "[j] mob\s to follow \the [L]."
|
message += "[j] mob\s to follow \the [L]."
|
||||||
to_chat(user, span("notice", message))
|
to_chat(user, span("notice", message))
|
||||||
|
var/image/orderimage = image(buildmode_hud,L,"ai_targetorder")
|
||||||
|
orderimage.plane = PLANE_BUILDMODE
|
||||||
|
flick_overlay(orderimage, list(user.client), 8, TRUE)
|
||||||
|
return
|
||||||
|
|
||||||
if(isturf(object)) // Move or reposition.
|
if(isturf(object)) // Move or reposition.
|
||||||
var/turf/T = object
|
var/turf/T = object
|
||||||
var/i = 0
|
var/forced = 0
|
||||||
|
var/told = 0
|
||||||
for(var/mob/living/unit in holder.selected_mobs)
|
for(var/mob/living/unit in holder.selected_mobs)
|
||||||
var/datum/ai_holder/AI = unit.ai_holder
|
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.
|
if(unit.get_AI_stance() == STANCE_SLEEP)
|
||||||
i++
|
unit.forceMove(T)
|
||||||
to_chat(user, span("notice", "Commanded [i] mob\s to move to \the [T]."))
|
forced++
|
||||||
|
else
|
||||||
|
AI.give_destination(T, 1, pa.Find("shift")) // If shift is held, the mobs will not stop moving to attack a visible enemy.
|
||||||
|
told++
|
||||||
|
to_chat(user, span("notice", "Commanded [told] mob\s to move to \the [T], and manually placed [forced] of them."))
|
||||||
|
var/image/orderimage = image(buildmode_hud,T,"ai_turforder")
|
||||||
|
orderimage.plane = PLANE_BUILDMODE
|
||||||
|
flick_overlay(orderimage, list(user.client), 8, TRUE)
|
||||||
|
return
|
||||||
|
|
||||||
|
/proc/build_drag(var/client/user, buildmode, var/atom/fromatom, var/atom/toatom, var/atom/fromloc, var/atom/toloc, var/fromcontrol, var/tocontrol, params)
|
||||||
|
var/obj/effect/bmode/buildholder/holder = null
|
||||||
|
for(var/obj/effect/bmode/buildholder/H)
|
||||||
|
if(H.cl == user)
|
||||||
|
holder = H
|
||||||
|
break
|
||||||
|
if(!holder) return
|
||||||
|
var/list/pa = params2list(params)
|
||||||
|
|
||||||
|
switch(buildmode)
|
||||||
|
if(BUILDMODE_AI)
|
||||||
|
|
||||||
|
//Holding shift prevents the deselection of existing
|
||||||
|
if(!pa.Find("shift"))
|
||||||
|
for(var/mob/living/unit in holder.selected_mobs)
|
||||||
|
holder.deselect_AI_mob(user, unit)
|
||||||
|
|
||||||
|
var/turf/c1 = get_turf(fromatom)
|
||||||
|
var/turf/c2 = get_turf(toatom)
|
||||||
|
if(!c1 || !c2)
|
||||||
|
return //Dragged outside window or something
|
||||||
|
|
||||||
|
var/low_x = min(c1.x,c2.x)
|
||||||
|
var/low_y = min(c1.y,c2.y)
|
||||||
|
var/hi_x = max(c1.x,c2.x)
|
||||||
|
var/hi_y = max(c1.y,c2.y)
|
||||||
|
var/z = c1.z //Eh
|
||||||
|
|
||||||
|
var/i = 0
|
||||||
|
for(var/mob/living/L in living_mob_list)
|
||||||
|
if(L.z != z || L.client)
|
||||||
|
continue
|
||||||
|
if(L.x >= low_x && L.x <= hi_x && L.y >= low_y && L.y <= hi_y)
|
||||||
|
holder.select_AI_mob(user, L)
|
||||||
|
i++
|
||||||
|
|
||||||
|
to_chat(user, span("notice", "Band-selected [i] mobs."))
|
||||||
|
return
|
||||||
|
|
||||||
/obj/effect/bmode/buildmode/proc/get_path_from_partial_text(default_path)
|
/obj/effect/bmode/buildmode/proc/get_path_from_partial_text(default_path)
|
||||||
var/desired_path = input("Enter full or partial typepath.","Typepath","[default_path]")
|
var/desired_path = input("Enter full or partial typepath.","Typepath","[default_path]")
|
||||||
@@ -596,4 +692,15 @@
|
|||||||
if(isturf(floor_type))
|
if(isturf(floor_type))
|
||||||
T.ChangeTurf(floor_type)
|
T.ChangeTurf(floor_type)
|
||||||
else
|
else
|
||||||
new floor_type(T)
|
new floor_type(T)
|
||||||
|
|
||||||
|
#undef BUILDMODE_BASIC
|
||||||
|
#undef BUILDMODE_ADVANCED
|
||||||
|
#undef BUILDMODE_EDIT
|
||||||
|
#undef BUILDMODE_THROW
|
||||||
|
#undef BUILDMODE_ROOM
|
||||||
|
#undef BUILDMODE_LADDER
|
||||||
|
#undef BUILDMODE_CONTENTS
|
||||||
|
#undef BUILDMODE_LIGHTS
|
||||||
|
#undef BUILDMODE_AI
|
||||||
|
#undef LAST_BUILDMODE
|
||||||
@@ -150,3 +150,40 @@
|
|||||||
// Simple mobs that retaliate and support others in their faction who get attacked.
|
// Simple mobs that retaliate and support others in their faction who get attacked.
|
||||||
/datum/ai_holder/simple_mob/retaliate/cooperative
|
/datum/ai_holder/simple_mob/retaliate/cooperative
|
||||||
cooperative = TRUE
|
cooperative = TRUE
|
||||||
|
|
||||||
|
// With all the bells and whistles
|
||||||
|
/datum/ai_holder/simple_mob/humanoid
|
||||||
|
intelligence_level = AI_SMART //Purportedly
|
||||||
|
retaliate = TRUE //If attacked, attack back
|
||||||
|
threaten = TRUE //Verbal threats
|
||||||
|
firing_lanes = TRUE //Avoid shooting allies
|
||||||
|
conserve_ammo = TRUE //Don't shoot when it can't hit target
|
||||||
|
can_breakthrough = TRUE //Can break through doors
|
||||||
|
violent_breakthrough = FALSE //Won't try to break through walls (humans can, but usually don't)
|
||||||
|
speak_chance = 2 //Babble chance
|
||||||
|
cooperative = TRUE //Assist each other
|
||||||
|
wander = TRUE //Wander around
|
||||||
|
returns_home = TRUE //But not too far
|
||||||
|
use_astar = TRUE //Path smartly
|
||||||
|
home_low_priority = TRUE //Following/helping is more important
|
||||||
|
|
||||||
|
// The hostile subtype is implied to be trained combatants who use ""tactics""
|
||||||
|
/datum/ai_holder/simple_mob/humanoid/hostile
|
||||||
|
var/run_if_this_close = 4 // If anything gets within this range, it'll try to move away.
|
||||||
|
hostile = TRUE //Attack!
|
||||||
|
|
||||||
|
// Juke
|
||||||
|
/datum/ai_holder/simple_mob/humanoid/hostile/post_melee_attack(atom/A)
|
||||||
|
holder.IMove(get_step(holder, pick(alldirs)))
|
||||||
|
holder.face_atom(A)
|
||||||
|
|
||||||
|
/datum/ai_holder/simple_mob/humanoid/hostile/post_ranged_attack(atom/A)
|
||||||
|
//Pick a random turf to step into
|
||||||
|
var/turf/T = get_step(holder, pick(alldirs))
|
||||||
|
if(check_trajectory(A, T)) // Can we even hit them from there?
|
||||||
|
holder.IMove(T)
|
||||||
|
holder.face_atom(A)
|
||||||
|
|
||||||
|
if(get_dist(holder, A) < run_if_this_close)
|
||||||
|
holder.IMove(get_step_away(holder, A))
|
||||||
|
holder.face_atom(A)
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
if(rabid)
|
if(rabid)
|
||||||
return
|
return
|
||||||
var/justified = my_slime.is_justified_to_discipline() // This will also consider the AI-side of that proc.
|
var/justified = my_slime.is_justified_to_discipline() // This will also consider the AI-side of that proc.
|
||||||
lost_target() // Stop attacking.
|
remove_target() // Stop attacking.
|
||||||
|
|
||||||
if(justified)
|
if(justified)
|
||||||
obedience++
|
obedience++
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
|
|
||||||
// Called when using a pacification agent (or it's Kendrick being initalized).
|
// Called when using a pacification agent (or it's Kendrick being initalized).
|
||||||
/datum/ai_holder/simple_mob/xenobio_slime/proc/pacify()
|
/datum/ai_holder/simple_mob/xenobio_slime/proc/pacify()
|
||||||
lost_target() // So it stops trying to kill them.
|
remove_target() // So it stops trying to kill them.
|
||||||
rabid = FALSE
|
rabid = FALSE
|
||||||
hostile = FALSE
|
hostile = FALSE
|
||||||
retaliate = FALSE
|
retaliate = FALSE
|
||||||
@@ -247,7 +247,7 @@
|
|||||||
else
|
else
|
||||||
delayed_say("Fine...", speaker)
|
delayed_say("Fine...", speaker)
|
||||||
adjust_discipline(1, TRUE) // This must come before losing the target or it will be unjustified.
|
adjust_discipline(1, TRUE) // This must come before losing the target or it will be unjustified.
|
||||||
lost_target()
|
remove_target()
|
||||||
|
|
||||||
|
|
||||||
if(leader) // We're being asked to stop following someone.
|
if(leader) // We're being asked to stop following someone.
|
||||||
|
|||||||
@@ -46,8 +46,25 @@
|
|||||||
home_turf = null
|
home_turf = null
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
|
/datum/ai_holder/proc/update_stance_hud()
|
||||||
|
var/image/stanceimage = holder.grab_hud(LIFE_HUD)
|
||||||
|
stanceimage.icon_state = "ais_[stance]"
|
||||||
|
holder.apply_hud(LIFE_HUD, stanceimage)
|
||||||
|
|
||||||
|
/datum/ai_holder/proc/update_paused_hud()
|
||||||
|
var/image/sleepingimage = holder.grab_hud(STATUS_HUD)
|
||||||
|
var/asleep = 0
|
||||||
|
if(busy)
|
||||||
|
asleep = 2
|
||||||
|
else if (stance == STANCE_SLEEP)
|
||||||
|
asleep = 1
|
||||||
|
sleepingimage.icon_state = "ai_[asleep]"
|
||||||
|
holder.apply_hud(STATUS_HUD, sleepingimage)
|
||||||
|
|
||||||
// Now for the actual AI stuff.
|
// Now for the actual AI stuff.
|
||||||
|
/datum/ai_holder/proc/set_busy(var/value = 0)
|
||||||
|
busy = value
|
||||||
|
update_paused_hud()
|
||||||
|
|
||||||
// Makes this ai holder not get processed.
|
// Makes this ai holder not get processed.
|
||||||
// Called automatically when the host mob is killed.
|
// Called automatically when the host mob is killed.
|
||||||
@@ -58,6 +75,7 @@
|
|||||||
forget_everything() // If we ever wake up, its really unlikely that our current memory will be of use.
|
forget_everything() // If we ever wake up, its really unlikely that our current memory will be of use.
|
||||||
set_stance(STANCE_SLEEP)
|
set_stance(STANCE_SLEEP)
|
||||||
SSai.processing -= src
|
SSai.processing -= src
|
||||||
|
update_paused_hud()
|
||||||
|
|
||||||
// Reverses the above proc.
|
// Reverses the above proc.
|
||||||
// Revived mobs will wake their AI if they have one.
|
// Revived mobs will wake their AI if they have one.
|
||||||
@@ -68,6 +86,7 @@
|
|||||||
return
|
return
|
||||||
set_stance(STANCE_IDLE)
|
set_stance(STANCE_IDLE)
|
||||||
SSai.processing += src
|
SSai.processing += src
|
||||||
|
update_paused_hud()
|
||||||
|
|
||||||
/datum/ai_holder/proc/should_wake()
|
/datum/ai_holder/proc/should_wake()
|
||||||
if(holder.client && !autopilot)
|
if(holder.client && !autopilot)
|
||||||
@@ -80,9 +99,7 @@
|
|||||||
/datum/ai_holder/proc/forget_everything()
|
/datum/ai_holder/proc/forget_everything()
|
||||||
// Some of these might be redundant, but hopefully this prevents future bugs if that changes.
|
// Some of these might be redundant, but hopefully this prevents future bugs if that changes.
|
||||||
lose_follow()
|
lose_follow()
|
||||||
lose_target()
|
remove_target()
|
||||||
lose_target_position()
|
|
||||||
give_up_movement()
|
|
||||||
|
|
||||||
// 'Tactical' processes such as moving a step, meleeing an enemy, firing a projectile, and other fairly cheap actions that need to happen quickly.
|
// 'Tactical' processes such as moving a step, meleeing an enemy, firing a projectile, and other fairly cheap actions that need to happen quickly.
|
||||||
/datum/ai_holder/proc/handle_tactics()
|
/datum/ai_holder/proc/handle_tactics()
|
||||||
@@ -103,39 +120,13 @@
|
|||||||
|
|
||||||
/datum/ai_holder/proc/handle_special_strategical()
|
/datum/ai_holder/proc/handle_special_strategical()
|
||||||
|
|
||||||
/*
|
|
||||||
//AI Actions
|
|
||||||
if(!ai_inactive)
|
|
||||||
//Stanceyness
|
|
||||||
handle_stance()
|
|
||||||
|
|
||||||
//Movement
|
|
||||||
if(!stop_automated_movement && wander && !anchored) //Allowed to move?
|
|
||||||
handle_wander_movement()
|
|
||||||
|
|
||||||
//Speaking
|
|
||||||
if(speak_chance && stance == STANCE_IDLE) // Allowed to chatter?
|
|
||||||
handle_idle_speaking()
|
|
||||||
|
|
||||||
//Resisting out buckles
|
|
||||||
if(stance != STANCE_IDLE && incapacitated(INCAPACITATION_BUCKLED_PARTIALLY))
|
|
||||||
handle_resist()
|
|
||||||
|
|
||||||
//Resisting out of closets
|
|
||||||
if(istype(loc,/obj/structure/closet))
|
|
||||||
var/obj/structure/closet/C = loc
|
|
||||||
if(C.welded)
|
|
||||||
resist()
|
|
||||||
else
|
|
||||||
C.open()
|
|
||||||
*/
|
|
||||||
|
|
||||||
// For setting the stance WITHOUT processing it
|
// For setting the stance WITHOUT processing it
|
||||||
/datum/ai_holder/proc/set_stance(var/new_stance)
|
/datum/ai_holder/proc/set_stance(var/new_stance)
|
||||||
ai_log("set_stance() : Setting stance from [stance] to [new_stance].", AI_LOG_INFO)
|
ai_log("set_stance() : Setting stance from [stance] to [new_stance].", AI_LOG_INFO)
|
||||||
stance = new_stance
|
stance = new_stance
|
||||||
if(stance_coloring) // For debugging or really weird mobs.
|
if(stance_coloring) // For debugging or really weird mobs.
|
||||||
stance_color()
|
stance_color()
|
||||||
|
update_stance_hud()
|
||||||
|
|
||||||
// This is called every half a second.
|
// This is called every half a second.
|
||||||
/datum/ai_holder/proc/handle_stance_tactical()
|
/datum/ai_holder/proc/handle_stance_tactical()
|
||||||
@@ -207,7 +198,8 @@
|
|||||||
|
|
||||||
if(STANCE_REPOSITION) // This is the same as above but doesn't stop if an enemy is visible since its an 'in-combat' move order.
|
if(STANCE_REPOSITION) // This is the same as above but doesn't stop if an enemy is visible since its an 'in-combat' move order.
|
||||||
ai_log("handle_stance_tactical() : STANCE_REPOSITION, going to walk_to_destination().", AI_LOG_TRACE)
|
ai_log("handle_stance_tactical() : STANCE_REPOSITION, going to walk_to_destination().", AI_LOG_TRACE)
|
||||||
walk_to_destination()
|
if(!target && !find_target())
|
||||||
|
walk_to_destination()
|
||||||
|
|
||||||
if(STANCE_FOLLOW)
|
if(STANCE_FOLLOW)
|
||||||
ai_log("handle_stance_tactical() : STANCE_FOLLOW, going to walk_to_leader().", AI_LOG_TRACE)
|
ai_log("handle_stance_tactical() : STANCE_FOLLOW, going to walk_to_leader().", AI_LOG_TRACE)
|
||||||
@@ -233,12 +225,18 @@
|
|||||||
ai_log("++++++++++ Slow Process Beginning ++++++++++", AI_LOG_TRACE)
|
ai_log("++++++++++ Slow Process Beginning ++++++++++", AI_LOG_TRACE)
|
||||||
ai_log("handle_stance_strategical() : Called.", AI_LOG_TRACE)
|
ai_log("handle_stance_strategical() : Called.", AI_LOG_TRACE)
|
||||||
|
|
||||||
|
ai_log("handle_stance_strategical() : LTT=[lose_target_time]", AI_LOG_TRACE)
|
||||||
|
if(lose_target_time && (lose_target_time + lose_target_timeout < world.time)) // We were tracking an enemy but they are gone.
|
||||||
|
ai_log("handle_stance_strategical() : Giving up a chase.", AI_LOG_DEBUG)
|
||||||
|
remove_target()
|
||||||
|
|
||||||
|
if(stance in STANCES_COMBAT)
|
||||||
|
request_help() // Call our allies.
|
||||||
|
|
||||||
switch(stance)
|
switch(stance)
|
||||||
if(STANCE_IDLE)
|
if(STANCE_IDLE)
|
||||||
|
|
||||||
if(speak_chance) // In the long loop since otherwise it wont shut up.
|
if(speak_chance) // In the long loop since otherwise it wont shut up.
|
||||||
handle_idle_speaking()
|
handle_idle_speaking()
|
||||||
|
|
||||||
if(hostile)
|
if(hostile)
|
||||||
ai_log("handle_stance_strategical() : STANCE_IDLE, going to find_target().", AI_LOG_TRACE)
|
ai_log("handle_stance_strategical() : STANCE_IDLE, going to find_target().", AI_LOG_TRACE)
|
||||||
find_target()
|
find_target()
|
||||||
@@ -246,6 +244,7 @@
|
|||||||
if(target)
|
if(target)
|
||||||
ai_log("handle_stance_strategical() : STANCE_APPROACH, going to calculate_path([target]).", AI_LOG_TRACE)
|
ai_log("handle_stance_strategical() : STANCE_APPROACH, going to calculate_path([target]).", AI_LOG_TRACE)
|
||||||
calculate_path(target)
|
calculate_path(target)
|
||||||
|
walk_to_target()
|
||||||
if(STANCE_MOVE)
|
if(STANCE_MOVE)
|
||||||
if(hostile && find_target()) // This will switch its stance.
|
if(hostile && find_target()) // This will switch its stance.
|
||||||
ai_log("handle_stance_strategical() : STANCE_MOVE, found target and was inturrupted.", AI_LOG_TRACE)
|
ai_log("handle_stance_strategical() : STANCE_MOVE, found target and was inturrupted.", AI_LOG_TRACE)
|
||||||
@@ -255,6 +254,7 @@
|
|||||||
else if(leader)
|
else if(leader)
|
||||||
ai_log("handle_stance_strategical() : STANCE_FOLLOW, going to calculate_path([leader]).", AI_LOG_TRACE)
|
ai_log("handle_stance_strategical() : STANCE_FOLLOW, going to calculate_path([leader]).", AI_LOG_TRACE)
|
||||||
calculate_path(leader)
|
calculate_path(leader)
|
||||||
|
walk_to_leader()
|
||||||
|
|
||||||
ai_log("handle_stance_strategical() : Exiting.", AI_LOG_TRACE)
|
ai_log("handle_stance_strategical() : Exiting.", AI_LOG_TRACE)
|
||||||
ai_log("++++++++++ Slow Process Ending ++++++++++", AI_LOG_TRACE)
|
ai_log("++++++++++ Slow Process Ending ++++++++++", AI_LOG_TRACE)
|
||||||
@@ -263,7 +263,7 @@
|
|||||||
// Helper proc to turn AI 'busy' mode on or off without having to check if there is an AI, to simplify writing code.
|
// Helper proc to turn AI 'busy' mode on or off without having to check if there is an AI, to simplify writing code.
|
||||||
/mob/living/proc/set_AI_busy(value)
|
/mob/living/proc/set_AI_busy(value)
|
||||||
if(ai_holder)
|
if(ai_holder)
|
||||||
ai_holder.busy = value
|
ai_holder.set_busy(value)
|
||||||
|
|
||||||
/mob/living/proc/is_AI_busy()
|
/mob/living/proc/is_AI_busy()
|
||||||
if(!ai_holder)
|
if(!ai_holder)
|
||||||
|
|||||||
@@ -9,47 +9,23 @@
|
|||||||
var/violent_breakthrough = TRUE // If false, the AI is not allowed to destroy things like windows or other structures in the way. Requires above var to be true.
|
var/violent_breakthrough = TRUE // If false, the AI is not allowed to destroy things like windows or other structures in the way. Requires above var to be true.
|
||||||
|
|
||||||
var/stand_ground = FALSE // If true, the AI won't try to get closer to an enemy if out of range.
|
var/stand_ground = FALSE // If true, the AI won't try to get closer to an enemy if out of range.
|
||||||
|
|
||||||
|
|
||||||
// This does the actual attacking.
|
// This does the actual attacking.
|
||||||
/datum/ai_holder/proc/engage_target()
|
/datum/ai_holder/proc/engage_target()
|
||||||
ai_log("engage_target() : Entering.", AI_LOG_DEBUG)
|
ai_log("engage_target() : Entering.", AI_LOG_DEBUG)
|
||||||
|
|
||||||
// Can we still see them?
|
// Can we still see them?
|
||||||
// if(!target || !can_attack(target) || (!(target in list_targets())) )
|
|
||||||
if(!target || !can_attack(target))
|
if(!target || !can_attack(target))
|
||||||
ai_log("engage_target() : Lost sight of target.", AI_LOG_TRACE)
|
ai_log("engage_target() : Lost sight of target.", AI_LOG_TRACE)
|
||||||
lose_target() // We lost them.
|
if(lose_target()) // We lost them (returns TRUE if we found something else to do)
|
||||||
|
ai_log("engage_target() : Pursuing other options (last seen, or a new target).", AI_LOG_TRACE)
|
||||||
if(!find_target()) // If we can't get a new one, then wait for a bit and then time out.
|
|
||||||
set_stance(STANCE_IDLE)
|
|
||||||
lost_target()
|
|
||||||
ai_log("engage_target() : No more targets. Exiting.", AI_LOG_DEBUG)
|
|
||||||
return
|
return
|
||||||
// if(lose_target_time + lose_target_timeout < world.time)
|
|
||||||
// ai_log("engage_target() : Unseen enemy timed out.", AI_LOG_TRACE)
|
|
||||||
// set_stance(STANCE_IDLE) // It must've been the wind.
|
|
||||||
// lost_target()
|
|
||||||
// ai_log("engage_target() : Exiting.", AI_LOG_DEBUG)
|
|
||||||
// return
|
|
||||||
|
|
||||||
// // But maybe we do one last ditch effort.
|
|
||||||
// if(!target_last_seen_turf || intelligence_level < AI_SMART)
|
|
||||||
// ai_log("engage_target() : No last known position or is too dumb to fight unseen enemies.", AI_LOG_TRACE)
|
|
||||||
// set_stance(STANCE_IDLE)
|
|
||||||
// else
|
|
||||||
// ai_log("engage_target() : Fighting unseen enemy.", AI_LOG_TRACE)
|
|
||||||
// engage_unseen_enemy()
|
|
||||||
else
|
|
||||||
ai_log("engage_target() : Got new target ([target]).", AI_LOG_TRACE)
|
|
||||||
|
|
||||||
var/distance = get_dist(holder, target)
|
var/distance = get_dist(holder, target)
|
||||||
ai_log("engage_target() : Distance to target ([target]) is [distance].", AI_LOG_TRACE)
|
ai_log("engage_target() : Distance to target ([target]) is [distance].", AI_LOG_TRACE)
|
||||||
holder.face_atom(target)
|
holder.face_atom(target)
|
||||||
last_conflict_time = world.time
|
last_conflict_time = world.time
|
||||||
|
|
||||||
request_help() // Call our allies.
|
|
||||||
|
|
||||||
// Do a 'special' attack, if one is allowed.
|
// Do a 'special' attack, if one is allowed.
|
||||||
// if(prob(special_attack_prob) && (distance >= special_attack_min_range) && (distance <= special_attack_max_range))
|
// if(prob(special_attack_prob) && (distance >= special_attack_min_range) && (distance <= special_attack_max_range))
|
||||||
if(holder.ICheckSpecialAttack(target))
|
if(holder.ICheckSpecialAttack(target))
|
||||||
@@ -198,12 +174,8 @@
|
|||||||
// Make sure we can still chase/attack them.
|
// Make sure we can still chase/attack them.
|
||||||
if(!target || !can_attack(target))
|
if(!target || !can_attack(target))
|
||||||
ai_log("walk_to_target() : Lost target.", AI_LOG_INFO)
|
ai_log("walk_to_target() : Lost target.", AI_LOG_INFO)
|
||||||
if(!find_target())
|
lose_target()
|
||||||
lost_target()
|
return
|
||||||
ai_log("walk_to_target() : Exiting.", AI_LOG_DEBUG)
|
|
||||||
return
|
|
||||||
else
|
|
||||||
ai_log("walk_to_target() : Found new target ([target]).", AI_LOG_INFO)
|
|
||||||
|
|
||||||
// Find out where we're going.
|
// Find out where we're going.
|
||||||
var/get_to = closest_distance(target)
|
var/get_to = closest_distance(target)
|
||||||
@@ -220,7 +192,6 @@
|
|||||||
ai_log("walk_to_target() : Exiting.", AI_LOG_DEBUG)
|
ai_log("walk_to_target() : Exiting.", AI_LOG_DEBUG)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
// Otherwise keep walking.
|
// Otherwise keep walking.
|
||||||
if(!stand_ground)
|
if(!stand_ground)
|
||||||
walk_path(target, get_to)
|
walk_path(target, get_to)
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
|
|
||||||
// Used when a target is out of sight or invisible.
|
// Used when a target is out of sight or invisible.
|
||||||
/datum/ai_holder/proc/engage_unseen_enemy()
|
/datum/ai_holder/proc/engage_unseen_enemy()
|
||||||
|
ai_log("engage_unseen_enemy() : Entering.", AI_LOG_TRACE)
|
||||||
// Lets do some last things before giving up.
|
// Lets do some last things before giving up.
|
||||||
if(!ranged)
|
if(conserve_ammo || !holder.ICheckRangedAttack(target_last_seen_turf))
|
||||||
if(get_dist(holder, target_last_seen_turf > 1)) // We last saw them over there.
|
if(get_dist(holder, target_last_seen_turf) > 1) // We last saw them over there.
|
||||||
// Go to where you last saw the enemy.
|
// Go to where you last saw the enemy.
|
||||||
give_destination(target_last_seen_turf, 1, TRUE) // This will set it to STANCE_REPOSITION.
|
give_destination(target_last_seen_turf, 1, TRUE) // Sets stance as well
|
||||||
else // We last saw them next to us, so do a blind attack on that tile.
|
else if(lose_target_time == world.time) // We last saw them next to us, so do a blind attack on that tile.
|
||||||
melee_on_tile(target_last_seen_turf)
|
melee_on_tile(target_last_seen_turf)
|
||||||
|
else
|
||||||
else if(!conserve_ammo)
|
find_target()
|
||||||
|
else
|
||||||
shoot_near_turf(target_last_seen_turf)
|
shoot_near_turf(target_last_seen_turf)
|
||||||
|
|
||||||
// This shoots semi-randomly near a specific turf.
|
// This shoots semi-randomly near a specific turf.
|
||||||
/datum/ai_holder/proc/shoot_near_turf(turf/targeted_turf)
|
/datum/ai_holder/proc/shoot_near_turf(turf/targeted_turf)
|
||||||
if(!ranged)
|
|
||||||
return // Can't shoot.
|
|
||||||
if(get_dist(holder, targeted_turf) > max_range(targeted_turf))
|
if(get_dist(holder, targeted_turf) > max_range(targeted_turf))
|
||||||
return // Too far to shoot.
|
return // Too far to shoot.
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
// Attempts to attack something on a specific tile.
|
// Attempts to attack something on a specific tile.
|
||||||
// TODO: Put on mob/living?
|
// TODO: Put on mob/living?
|
||||||
/datum/ai_holder/proc/melee_on_tile(turf/T)
|
/datum/ai_holder/proc/melee_on_tile(turf/T)
|
||||||
|
ai_log("melee_on_tile() : Entering.", AI_LOG_TRACE)
|
||||||
var/mob/living/L = locate() in T
|
var/mob/living/L = locate() in T
|
||||||
if(!L)
|
if(!L)
|
||||||
T.visible_message("\The [holder] attacks nothing around \the [T].")
|
T.visible_message("\The [holder] attacks nothing around \the [T].")
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
/datum/ai_holder/proc/should_threaten()
|
/datum/ai_holder/proc/should_threaten()
|
||||||
if(!threaten)
|
if(!threaten)
|
||||||
return FALSE // We don't negotiate.
|
return FALSE // We don't negotiate.
|
||||||
if(target in attackers)
|
if(check_attacker(target))
|
||||||
return FALSE // They (or someone like them) attacked us before, escalate immediately.
|
return FALSE // They (or someone like them) attacked us before, escalate immediately.
|
||||||
if(!will_threaten(target))
|
if(!will_threaten(target))
|
||||||
return FALSE // Pointless to threaten an animal, a mindless drone, or an object.
|
return FALSE // Pointless to threaten an animal, a mindless drone, or an object.
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
|
|
||||||
ai_log("request_help() : Exiting.", AI_LOG_DEBUG)
|
ai_log("request_help() : Exiting.", AI_LOG_DEBUG)
|
||||||
|
|
||||||
// What allies receive when someone else is calling for help.
|
// What allies receive when someone else is calling for help.1
|
||||||
/datum/ai_holder/proc/help_requested(mob/living/friend)
|
/datum/ai_holder/proc/help_requested(mob/living/friend)
|
||||||
ai_log("help_requested() : Entering.", AI_LOG_DEBUG)
|
ai_log("help_requested() : Entering.", AI_LOG_DEBUG)
|
||||||
if(stance == STANCE_SLEEP)
|
if(stance == STANCE_SLEEP)
|
||||||
@@ -92,24 +92,26 @@
|
|||||||
if(!holder.IIsAlly(friend)) // Extra sanity.
|
if(!holder.IIsAlly(friend)) // Extra sanity.
|
||||||
ai_log("help_requested() : Help requested by [friend] but we hate them.", AI_LOG_INFO)
|
ai_log("help_requested() : Help requested by [friend] but we hate them.", AI_LOG_INFO)
|
||||||
return
|
return
|
||||||
if(friend.ai_holder && friend.ai_holder.target && !can_attack(friend.ai_holder.target))
|
var/their_target = friend?.ai_holder?.target
|
||||||
ai_log("help_requested() : Help requested by [friend] but we don't want to fight their target.", AI_LOG_INFO)
|
if(their_target) // They have a target and aren't just shouting for no reason
|
||||||
return
|
if(!can_attack(their_target, vision_required = FALSE))
|
||||||
if(get_dist(holder, friend) <= follow_distance)
|
ai_log("help_requested() : Help requested by [friend] but we don't want to fight their target.", AI_LOG_INFO)
|
||||||
ai_log("help_requested() : Help requested by [friend] but we're already here.", AI_LOG_INFO)
|
return
|
||||||
return
|
if(get_dist(holder, friend) <= follow_distance)
|
||||||
if(get_dist(holder, friend) <= vision_range) // Within our sight.
|
ai_log("help_requested() : Help requested by [friend] but we're already here.", AI_LOG_INFO)
|
||||||
ai_log("help_requested() : Help requested by [friend], and within target sharing range.", AI_LOG_INFO)
|
return
|
||||||
if(friend.ai_holder) // AI calling for help.
|
if(get_dist(holder, friend) <= vision_range) // Within our sight.
|
||||||
if(friend.ai_holder.target && can_attack(friend.ai_holder.target)) // Friend wants us to attack their target.
|
ai_log("help_requested() : Help requested by [friend], and within target sharing range.", AI_LOG_INFO)
|
||||||
last_conflict_time = world.time // So we attack immediately and not threaten.
|
last_conflict_time = world.time // So we attack immediately and not threaten.
|
||||||
give_target(friend.ai_holder.target) // This will set us to the appropiate stance.
|
give_target(their_target, urgent = TRUE) // This will set us to the appropiate stance.
|
||||||
ai_log("help_requested() : Given target [target] by [friend]. Exiting", AI_LOG_DEBUG)
|
ai_log("help_requested() : Given target [target] by [friend]. Exiting", AI_LOG_DEBUG)
|
||||||
return
|
return
|
||||||
|
|
||||||
// Otherwise they're outside our sight, lack a target, or aren't AI controlled, but within call range.
|
// Otherwise they're outside our sight, lack a target, or aren't AI controlled, but within call range.
|
||||||
// So assuming we're AI controlled, we'll go to them and see whats wrong.
|
// So assuming we're AI controlled, we'll go to them and see whats wrong.
|
||||||
ai_log("help_requested() : Help requested by [friend], going to go to friend.", AI_LOG_INFO)
|
ai_log("help_requested() : Help requested by [friend], going to go to friend.", AI_LOG_INFO)
|
||||||
|
if(their_target)
|
||||||
|
add_attacker(their_target) // We won't wait and 'warn' them while they're stabbing our ally
|
||||||
set_follow(friend, 10 SECONDS)
|
set_follow(friend, 10 SECONDS)
|
||||||
ai_log("help_requested() : Exiting.", AI_LOG_DEBUG)
|
ai_log("help_requested() : Exiting.", AI_LOG_DEBUG)
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
// Step 1, find out what we can see.
|
// Step 1, find out what we can see.
|
||||||
/datum/ai_holder/proc/list_targets()
|
/datum/ai_holder/proc/list_targets()
|
||||||
. = hearers(vision_range, holder) - holder // Remove ourselves to prevent suicidal decisions. ~ SRC is the ai_holder.
|
. = hearers(vision_range, holder) - holder // Remove ourselves to prevent suicidal decisions. ~ SRC is the ai_holder.
|
||||||
|
. -= dview_mob // Not the dview mob either, nerd.
|
||||||
|
|
||||||
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha))
|
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha))
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
|
|
||||||
// Step 2, filter down possible targets to things we actually care about.
|
// Step 2, filter down possible targets to things we actually care about.
|
||||||
/datum/ai_holder/proc/find_target(var/list/possible_targets, var/has_targets_list = FALSE)
|
/datum/ai_holder/proc/find_target(var/list/possible_targets, var/has_targets_list = FALSE)
|
||||||
|
ai_log("find_target() : Entered.", AI_LOG_TRACE)
|
||||||
if(!hostile) // So retaliating mobs only attack the thing that hit it.
|
if(!hostile) // So retaliating mobs only attack the thing that hit it.
|
||||||
return null
|
return null
|
||||||
. = list()
|
. = list()
|
||||||
@@ -70,13 +72,17 @@
|
|||||||
return chosen_target
|
return chosen_target
|
||||||
|
|
||||||
// Step 4, give us our selected target.
|
// Step 4, give us our selected target.
|
||||||
/datum/ai_holder/proc/give_target(new_target)
|
/datum/ai_holder/proc/give_target(new_target, urgent = FALSE)
|
||||||
|
ai_log("give_target() : Given '[new_target]', urgent=[urgent].", AI_LOG_TRACE)
|
||||||
target = new_target
|
target = new_target
|
||||||
|
|
||||||
if(target != null)
|
if(target != null)
|
||||||
if(should_threaten())
|
lose_target_time = 0
|
||||||
|
track_target_position()
|
||||||
|
if(should_threaten() && !urgent)
|
||||||
set_stance(STANCE_ALERT)
|
set_stance(STANCE_ALERT)
|
||||||
else
|
else
|
||||||
set_stance(STANCE_APPROACH)
|
set_stance(STANCE_FIGHT)
|
||||||
last_target_time = world.time
|
last_target_time = world.time
|
||||||
return TRUE
|
return TRUE
|
||||||
|
|
||||||
@@ -109,8 +115,8 @@
|
|||||||
sorted_targets += A
|
sorted_targets += A
|
||||||
return sorted_targets
|
return sorted_targets
|
||||||
|
|
||||||
/datum/ai_holder/proc/can_attack(atom/movable/the_target)
|
/datum/ai_holder/proc/can_attack(atom/movable/the_target, vision_required = TRUE)
|
||||||
if(!can_see_target(the_target))
|
if(!can_see_target(the_target) && vision_required)
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
if(istype(the_target, /mob/zshadow))
|
if(istype(the_target, /mob/zshadow))
|
||||||
@@ -157,21 +163,38 @@
|
|||||||
/datum/ai_holder/proc/found(atom/movable/the_target)
|
/datum/ai_holder/proc/found(atom/movable/the_target)
|
||||||
return FALSE
|
return FALSE
|
||||||
|
|
||||||
//We can't see the target, go look or attack where they were last seen.
|
// 'Soft' loss of target. They may still exist, we still have some info about them maybe.
|
||||||
/datum/ai_holder/proc/lose_target()
|
/datum/ai_holder/proc/lose_target()
|
||||||
|
ai_log("lose_target() : Entering.", AI_LOG_TRACE)
|
||||||
if(target)
|
if(target)
|
||||||
|
ai_log("lose_target() : Had a target, setting to null and LTT.", AI_LOG_DEBUG)
|
||||||
target = null
|
target = null
|
||||||
lose_target_time = world.time
|
lose_target_time = world.time
|
||||||
|
|
||||||
give_up_movement()
|
give_up_movement()
|
||||||
|
|
||||||
|
if(target_last_seen_turf && intelligence_level >= AI_SMART)
|
||||||
|
ai_log("lose_target() : Going into 'engage unseen enemy' mode.", AI_LOG_INFO)
|
||||||
|
engage_unseen_enemy()
|
||||||
|
return TRUE //We're still working on it
|
||||||
|
else
|
||||||
|
ai_log("lose_target() : Can't chase target, so giving up.", AI_LOG_INFO)
|
||||||
|
remove_target()
|
||||||
|
return find_target() //Returns if we found anything else to do
|
||||||
|
|
||||||
//Target is no longer valid (?)
|
return FALSE //Nothing new to do
|
||||||
/datum/ai_holder/proc/lost_target()
|
|
||||||
set_stance(STANCE_IDLE)
|
// 'Hard' loss of target. Clean things up and return to idle.
|
||||||
|
/datum/ai_holder/proc/remove_target()
|
||||||
|
ai_log("remove_target() : Entering.", AI_LOG_TRACE)
|
||||||
|
if(target)
|
||||||
|
target = null
|
||||||
|
|
||||||
|
lose_target_time = 0
|
||||||
|
give_up_movement()
|
||||||
lose_target_position()
|
lose_target_position()
|
||||||
lose_target()
|
set_stance(STANCE_IDLE)
|
||||||
|
|
||||||
// Check if target is visible to us.
|
// Check if target is visible to us.
|
||||||
/datum/ai_holder/proc/can_see_target(atom/movable/the_target, view_range = vision_range)
|
/datum/ai_holder/proc/can_see_target(atom/movable/the_target, view_range = vision_range)
|
||||||
ai_log("can_see_target() : Entering.", AI_LOG_TRACE)
|
ai_log("can_see_target() : Entering.", AI_LOG_TRACE)
|
||||||
@@ -235,7 +258,7 @@
|
|||||||
ai_log("react_to_attack() : Was attacked by [attacker], but we already have a target.", AI_LOG_TRACE)
|
ai_log("react_to_attack() : Was attacked by [attacker], but we already have a target.", AI_LOG_TRACE)
|
||||||
on_attacked(attacker) // So we attack immediately and not threaten.
|
on_attacked(attacker) // So we attack immediately and not threaten.
|
||||||
return FALSE
|
return FALSE
|
||||||
else if(attacker in attackers && world.time > last_target_time + 3 SECONDS) // Otherwise, let 'er rip
|
else if(check_attacker(attacker) && world.time > last_target_time + 3 SECONDS) // Otherwise, let 'er rip
|
||||||
ai_log("react_to_attack() : Was attacked by [attacker]. Can retaliate, waited 3 seconds.", AI_LOG_INFO)
|
ai_log("react_to_attack() : Was attacked by [attacker]. Can retaliate, waited 3 seconds.", AI_LOG_INFO)
|
||||||
on_attacked(attacker) // So we attack immediately and not threaten.
|
on_attacked(attacker) // So we attack immediately and not threaten.
|
||||||
return give_target(attacker) // Also handles setting the appropiate stance.
|
return give_target(attacker) // Also handles setting the appropiate stance.
|
||||||
@@ -246,16 +269,25 @@
|
|||||||
|
|
||||||
ai_log("react_to_attack() : Was attacked by [attacker].", AI_LOG_INFO)
|
ai_log("react_to_attack() : Was attacked by [attacker].", AI_LOG_INFO)
|
||||||
on_attacked(attacker) // So we attack immediately and not threaten.
|
on_attacked(attacker) // So we attack immediately and not threaten.
|
||||||
return give_target(attacker) // Also handles setting the appropiate stance.
|
return give_target(attacker, urgent = TRUE) // Also handles setting the appropiate stance.
|
||||||
|
|
||||||
// Sets a few vars so mobs that threaten will react faster to an attacker or someone who attacked them before.
|
// Sets a few vars so mobs that threaten will react faster to an attacker or someone who attacked them before.
|
||||||
/datum/ai_holder/proc/on_attacked(atom/movable/AM)
|
/datum/ai_holder/proc/on_attacked(atom/movable/AM)
|
||||||
if(isliving(AM))
|
last_conflict_time = world.time
|
||||||
var/mob/living/L = AM
|
add_attacker(AM)
|
||||||
if(!(L.name in attackers))
|
|
||||||
attackers |= L.name
|
|
||||||
last_conflict_time = world.time
|
|
||||||
|
|
||||||
|
// Checks to see if an atom attacked us lately
|
||||||
|
/datum/ai_holder/proc/check_attacker(var/atom/movable/A)
|
||||||
|
return (A in attackers)
|
||||||
|
|
||||||
|
// We were attacked by this thing recently
|
||||||
|
/datum/ai_holder/proc/add_attacker(var/atom/movable/A)
|
||||||
|
attackers |= A.name
|
||||||
|
|
||||||
|
// Forgive this attacker
|
||||||
|
/datum/ai_holder/proc/remove_attacker(var/atom/movable/A)
|
||||||
|
attackers -= A.name
|
||||||
|
|
||||||
// Causes targeting to prefer targeting the taunter if possible.
|
// Causes targeting to prefer targeting the taunter if possible.
|
||||||
// This generally occurs if more than one option is within striking distance, including the taunter.
|
// This generally occurs if more than one option is within striking distance, including the taunter.
|
||||||
// Otherwise the default filter will prefer the closest target.
|
// Otherwise the default filter will prefer the closest target.
|
||||||
|
|||||||
@@ -340,6 +340,14 @@
|
|||||||
if(inactivity > duration) return inactivity
|
if(inactivity > duration) return inactivity
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
//Called when the client performs a drag-and-drop operation.
|
||||||
|
/client/MouseDrop(start_object,end_object,start_location,end_location,start_control,end_control,params)
|
||||||
|
if(buildmode && start_control == "mapwindow.map" && start_control == end_control)
|
||||||
|
build_drag(src,buildmode,start_object,end_object,start_location,end_location,start_control,end_control,params)
|
||||||
|
else
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
|
||||||
// Byond seemingly calls stat, each tick.
|
// Byond seemingly calls stat, each tick.
|
||||||
// Calling things each tick can get expensive real quick.
|
// Calling things each tick can get expensive real quick.
|
||||||
// So we slow this down a little.
|
// So we slow this down a little.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
dsma.blend_mode = BLEND_ADD
|
dsma.blend_mode = BLEND_ADD
|
||||||
dsoverlay.appearance = dsma
|
dsoverlay.appearance = dsma
|
||||||
|
|
||||||
selected_image = image(icon = 'icons/mob/screen1.dmi', loc = src, icon_state = "centermarker")
|
selected_image = image(icon = buildmode_hud, loc = src, icon_state = "ai_sel")
|
||||||
|
|
||||||
/mob/living/Destroy()
|
/mob/living/Destroy()
|
||||||
dsoverlay.loc = null //I'll take my coat with me
|
dsoverlay.loc = null //I'll take my coat with me
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
mob_swap_flags = ~HEAVY
|
mob_swap_flags = ~HEAVY
|
||||||
mob_push_flags = ~HEAVY
|
mob_push_flags = ~HEAVY
|
||||||
|
|
||||||
|
has_huds = TRUE // We do show AI status huds for buildmode players
|
||||||
|
|
||||||
var/tt_desc = null //Tooltip description
|
var/tt_desc = null //Tooltip description
|
||||||
|
|
||||||
//Settings for played mobs
|
//Settings for played mobs
|
||||||
@@ -295,4 +297,9 @@
|
|||||||
return mob_class & MOB_CLASS_HUMANOID|MOB_CLASS_ANIMAL|MOB_CLASS_SLIME // Update this if needed.
|
return mob_class & MOB_CLASS_HUMANOID|MOB_CLASS_ANIMAL|MOB_CLASS_SLIME // Update this if needed.
|
||||||
|
|
||||||
/mob/living/simple_mob/get_nametag_desc(mob/user)
|
/mob/living/simple_mob/get_nametag_desc(mob/user)
|
||||||
return "<i>[tt_desc]</i>"
|
return "<i>[tt_desc]</i>"
|
||||||
|
|
||||||
|
/mob/living/simple_mob/make_hud_overlays()
|
||||||
|
hud_list[STATUS_HUD] = gen_hud_image(buildmode_hud, src, "ai_0", plane = PLANE_BUILDMODE)
|
||||||
|
hud_list[LIFE_HUD] = gen_hud_image(buildmode_hud, src, "ais_1", plane = PLANE_BUILDMODE)
|
||||||
|
add_overlay(hud_list)
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
plane_masters[VIS_MESONS] = new /obj/screen/plane_master{plane = PLANE_MESONS} //Meson-specific things like open ceilings.
|
plane_masters[VIS_MESONS] = new /obj/screen/plane_master{plane = PLANE_MESONS} //Meson-specific things like open ceilings.
|
||||||
|
|
||||||
|
plane_masters[VIS_BUILDMODE] = new /obj/screen/plane_master{plane = PLANE_BUILDMODE} //Things that only show up while in build mode
|
||||||
|
|
||||||
// Real tangible stuff planes
|
// Real tangible stuff planes
|
||||||
plane_masters[VIS_TURFS] = new /obj/screen/plane_master/main{plane = TURF_PLANE}
|
plane_masters[VIS_TURFS] = new /obj/screen/plane_master/main{plane = TURF_PLANE}
|
||||||
plane_masters[VIS_OBJS] = new /obj/screen/plane_master/main{plane = OBJ_PLANE}
|
plane_masters[VIS_OBJS] = new /obj/screen/plane_master/main{plane = OBJ_PLANE}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
to_chat(user, "<span class='notice'>You feed \the [SM] the agent, calming it.</span>")
|
to_chat(user, "<span class='notice'>You feed \the [SM] the agent, calming it.</span>")
|
||||||
|
|
||||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||||
AI.lost_target() // So hostile things stop attacking people even if not hostile anymore.
|
AI.remove_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||||
var/newname = copytext(sanitize(input(user, "Would you like to give \the [M] a name?", "Name your new pet", M.name) as null|text),1,MAX_NAME_LEN)
|
var/newname = copytext(sanitize(input(user, "Would you like to give \the [M] a name?", "Name your new pet", M.name) as null|text),1,MAX_NAME_LEN)
|
||||||
|
|
||||||
if(newname)
|
if(newname)
|
||||||
@@ -202,7 +202,7 @@
|
|||||||
to_chat(user, "<span class='notice'>You feed \the [M] the agent. It will now try to murder things that want to murder you instead.</span>")
|
to_chat(user, "<span class='notice'>You feed \the [M] the agent. It will now try to murder things that want to murder you instead.</span>")
|
||||||
to_chat(M, "<span class='notice'>\The [user] feeds you \the [src], and feel that the others will regard you as an outsider now.</span>")
|
to_chat(M, "<span class='notice'>\The [user] feeds you \the [src], and feel that the others will regard you as an outsider now.</span>")
|
||||||
M.faction = user.faction
|
M.faction = user.faction
|
||||||
AI.lost_target() // So hostile things stop attacking people even if not hostile anymore.
|
AI.remove_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||||
qdel(src)
|
qdel(src)
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
to_chat(user, "<span class='notice'>You feed \the [M] the agent. It will now be your best friend.</span>")
|
to_chat(user, "<span class='notice'>You feed \the [M] the agent. It will now be your best friend.</span>")
|
||||||
to_chat(M, "<span class='notice'>\The [user] feeds you \the [src], and feel that \the [user] wants to be best friends with you.</span>")
|
to_chat(M, "<span class='notice'>\The [user] feeds you \the [src], and feel that \the [user] wants to be best friends with you.</span>")
|
||||||
M.friends.Add(user)
|
M.friends.Add(user)
|
||||||
AI.lost_target() // So hostile things stop attacking people even if not hostile anymore.
|
AI.remove_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||||
qdel(src)
|
qdel(src)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.1 KiB |
@@ -1551,6 +1551,7 @@
|
|||||||
#include "code\modules\ai\_defines.dm"
|
#include "code\modules\ai\_defines.dm"
|
||||||
#include "code\modules\ai\ai_holder.dm"
|
#include "code\modules\ai\ai_holder.dm"
|
||||||
#include "code\modules\ai\ai_holder_combat.dm"
|
#include "code\modules\ai\ai_holder_combat.dm"
|
||||||
|
#include "code\modules\ai\ai_holder_combat_unseen.dm"
|
||||||
#include "code\modules\ai\ai_holder_communication.dm"
|
#include "code\modules\ai\ai_holder_communication.dm"
|
||||||
#include "code\modules\ai\ai_holder_cooperation.dm"
|
#include "code\modules\ai\ai_holder_cooperation.dm"
|
||||||
#include "code\modules\ai\ai_holder_debug.dm"
|
#include "code\modules\ai\ai_holder_debug.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user