mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-27 22:17:32 +01:00
Merge pull request #11358 from Couls/diagonal-movement
[Ready for Testmerge] Implement Diagonal Movement
This commit is contained in:
@@ -185,3 +185,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
|
||||
else
|
||||
send2irc(source, "[msg] - All admins AFK ([admin_number_afk]/[admin_number_total]) or skipped ([admin_number_ignored]/[admin_number_total])")
|
||||
return admin_number_present
|
||||
|
||||
/client/proc/get_adminhelp()
|
||||
var/msg = input(src, "Please describe your problem concisely and an admin will help as soon as they're able.", "Adminhelp contents") as text|null
|
||||
adminhelp(msg)
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/get_admin_say()
|
||||
var/msg = input(src, null, "asay \"text\"") as text|null
|
||||
cmd_admin_say(msg)
|
||||
|
||||
/client/proc/cmd_mentor_say(msg as text)
|
||||
set category = "Admin"
|
||||
set name = "Msay"
|
||||
|
||||
@@ -43,3 +43,7 @@
|
||||
say_dead_direct("<span class='name'>[prefix]</span> says, <span class='message'>\"[msg]\"</span>")
|
||||
|
||||
feedback_add_details("admin_verb","D") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/get_dead_say()
|
||||
var/msg = input(src, null, "dsay \"text\"") as text
|
||||
dsay(msg)
|
||||
@@ -116,7 +116,7 @@
|
||||
a_right.holder_movement()
|
||||
|
||||
/obj/item/assembly_holder/Move()
|
||||
..()
|
||||
. = ..()
|
||||
process_movement()
|
||||
return
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
/obj/item/assembly/infra/Move()
|
||||
var/t = dir
|
||||
..()
|
||||
. = ..()
|
||||
dir = t
|
||||
qdel(first)
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/client
|
||||
//////////////////////
|
||||
//BLACK MAGIC THINGS//
|
||||
//////////////////////
|
||||
parent_type = /datum
|
||||
////////////////
|
||||
//ADMIN THINGS//
|
||||
////////////////
|
||||
@@ -24,7 +28,7 @@
|
||||
|
||||
var/adminhelped = 0
|
||||
|
||||
var/gc_destroyed //Time when this object was destroyed.
|
||||
// var/gc_destroyed //Time when this object was destroyed. [Inherits from datum]
|
||||
|
||||
#ifdef TESTING
|
||||
var/running_find_references
|
||||
@@ -89,5 +93,5 @@
|
||||
// If set to true, this client can interact with atoms such as buttons and doors on top of regular machinery interaction
|
||||
var/advanced_admin_interaction = FALSE
|
||||
|
||||
// Has the client been varedited by an admin?
|
||||
var/var_edited = FALSE
|
||||
// Has the client been varedited by an admin? [Inherits from datum now]
|
||||
// var/var_edited = FALSE
|
||||
|
||||
@@ -297,14 +297,14 @@
|
||||
return null
|
||||
if(byond_build < config.minimum_client_build)
|
||||
alert(src, "You are using a byond build which is not supported by this server. Please use a build version of atleast [config.minimum_client_build].", "Incorrect build", "OK")
|
||||
del(src)
|
||||
qdel(src)
|
||||
return
|
||||
if(byond_version < SUGGESTED_CLIENT_VERSION) // Update is suggested, but not required.
|
||||
to_chat(src,"<span class='userdanger'>Your BYOND client (v: [byond_version]) is out of date. This can cause glitches. We highly suggest you download the latest client from http://www.byond.com/ before playing. </span>")
|
||||
|
||||
if(IsGuestKey(key))
|
||||
alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK")
|
||||
del(src)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
// Change the way they should download resources.
|
||||
@@ -317,7 +317,6 @@
|
||||
|
||||
GLOB.clients += src
|
||||
GLOB.directory[ckey] = src
|
||||
|
||||
//Admin Authorisation
|
||||
// Automatically makes localhost connection an admin
|
||||
if(!config.disable_localhost_admin)
|
||||
@@ -365,11 +364,14 @@
|
||||
|
||||
. = ..() //calls mob.Login()
|
||||
|
||||
|
||||
if(ckey in clientmessages)
|
||||
for(var/message in clientmessages[ckey])
|
||||
to_chat(src, message)
|
||||
clientmessages.Remove(ckey)
|
||||
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
|
||||
donator_check()
|
||||
check_ip_intel()
|
||||
@@ -404,8 +406,7 @@
|
||||
|
||||
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
|
||||
to_chat(src, "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>")
|
||||
|
||||
|
||||
|
||||
//This is down here because of the browse() calls in tooltip/New()
|
||||
if(!tooltips)
|
||||
tooltips = new /datum/tooltip(src)
|
||||
@@ -664,7 +665,7 @@
|
||||
sleep(10) // Since browse is non-instant, and kinda async
|
||||
|
||||
to_chat(src, "<pre class=\"system system\">you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point</pre>")
|
||||
del(src)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
else
|
||||
if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey])
|
||||
@@ -675,7 +676,7 @@
|
||||
tokens[ckey] = cid_check_reconnect()
|
||||
|
||||
sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command.
|
||||
del(src)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
// We DO have their cached CID handy - compare it, now
|
||||
if(oldcid != computer_id)
|
||||
@@ -693,7 +694,7 @@
|
||||
|
||||
log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])")
|
||||
|
||||
del(src)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
else
|
||||
// don't shoot, I'm innocent
|
||||
@@ -795,18 +796,15 @@
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "mainwindow.hotkey_toggle", "background-color=#40628a;text-color=#FFFFFF")
|
||||
///// UI ELEMENTS /////
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow", "background-color=#272727")
|
||||
winset(src, "mainwindow.mainvsplit", "background-color=#272727")
|
||||
winset(src, "mainwindow.tooltip", "background-color=#272727")
|
||||
/* Outputwindow */
|
||||
winset(src, "outputwindow.outputwindow", "background-color=#272727")
|
||||
winset(src, "outputwindow.browseroutput", "background-color=#272727")
|
||||
/* Rpane */
|
||||
winset(src, "rpane", "background-color=#272727")
|
||||
winset(src, "rpane.rpane", "background-color=#272727")
|
||||
winset(src, "rpane.rpanewindow", "background-color=#272727")
|
||||
/* Browserwindow */
|
||||
winset(src, "browserwindow", "background-color=#272727")
|
||||
@@ -830,18 +828,15 @@
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow.saybutton", "background-color=none;text-color=#000000")
|
||||
winset(src, "mainwindow.mebutton", "background-color=none;text-color=#000000")
|
||||
winset(src, "mainwindow.hotkey_toggle", "background-color=none;text-color=#000000")
|
||||
///// UI ELEMENTS /////
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow", "background-color=none")
|
||||
winset(src, "mainwindow.mainvsplit", "background-color=none")
|
||||
winset(src, "mainwindow.tooltip", "background-color=none")
|
||||
/* Outputwindow */
|
||||
winset(src, "outputwindow.outputwindow", "background-color=none")
|
||||
winset(src, "outputwindow.browseroutput", "background-color=none")
|
||||
/* Rpane */
|
||||
winset(src, "rpane", "background-color=none")
|
||||
winset(src, "rpane.rpane", "background-color=none")
|
||||
winset(src, "rpane.rpanewindow", "background-color=none")
|
||||
/* Browserwindow */
|
||||
winset(src, "browserwindow", "background-color=none")
|
||||
|
||||
@@ -241,7 +241,31 @@
|
||||
to_chat(usr, "<span class='notice'>You have enabled text popup limiting.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You have disabled text popup limiting.")
|
||||
return
|
||||
|
||||
/client/verb/numpad_target()
|
||||
set name = "Toggle Numpad targetting"
|
||||
set category = "Preferences"
|
||||
set desc = "This button will allow you to enable or disable Numpad Targetting"
|
||||
prefs.toggles ^= NUMPAD_TARGET
|
||||
prefs.save_preferences(src)
|
||||
if (prefs.toggles & NUMPAD_TARGET)
|
||||
to_chat(usr, "<span class='notice'>You have enabled Numpad Targetting.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You have disabled Numpad Targetting.")
|
||||
return
|
||||
|
||||
/client/verb/azerty_toggle()
|
||||
set name = "Toggle QWERTY/AZERTY"
|
||||
set category = "Preferences"
|
||||
set desc = "This button will switch you between QWERTY and AZERTY control sets"
|
||||
prefs.toggles ^= AZERTY
|
||||
prefs.save_preferences(src)
|
||||
if (prefs.toggles & AZERTY)
|
||||
to_chat(usr, "<span class='notice'>You are now in AZERTY mode.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You are now in QWERTY mode.")
|
||||
return
|
||||
/client/verb/toggle_ghost_pda()
|
||||
set name = "Show/Hide GhostPDA"
|
||||
set category = "Preferences"
|
||||
@@ -249,4 +273,4 @@
|
||||
prefs.toggles ^= CHAT_GHOSTPDA
|
||||
to_chat(src, "As a ghost, you will now [(prefs.toggles & CHAT_GHOSTPDA) ? "see all PDA messages" : "no longer see PDA messages"].")
|
||||
prefs.save_preferences(src)
|
||||
feedback_add_details("admin_verb","TGP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
feedback_add_details("admin_verb","TGP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/datum/admins/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("F3")
|
||||
user.get_admin_say()
|
||||
return
|
||||
if("F5")
|
||||
user.admin_ghost()
|
||||
return
|
||||
if("F6")
|
||||
player_panel_new()
|
||||
return
|
||||
if("F7")
|
||||
user.togglebuildmodeself()
|
||||
return
|
||||
if("F8")
|
||||
if(user.keys_held["Ctrl"])
|
||||
user.stealth()
|
||||
else
|
||||
user.invisimin()
|
||||
return
|
||||
if("F10")
|
||||
user.get_dead_say()
|
||||
return
|
||||
..()
|
||||
@@ -0,0 +1,21 @@
|
||||
// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
|
||||
// Only way to do that is to tie the behavior into the focus's keyLoop().
|
||||
|
||||
/atom/movable/keyLoop(client/user)
|
||||
if(!user.keys_held["Ctrl"])
|
||||
var/movement_dir = NONE
|
||||
var/list/movement = SSinput.movement_keys
|
||||
if(user.prefs.toggles & AZERTY)
|
||||
movement = SSinput.alt_movement_keys
|
||||
for(var/_key in user.keys_held)
|
||||
movement_dir = movement_dir | movement[_key]
|
||||
if(user.next_move_dir_add)
|
||||
movement_dir |= user.next_move_dir_add
|
||||
if(user.next_move_dir_sub)
|
||||
movement_dir &= ~user.next_move_dir_sub
|
||||
// Sanity checks in case you hold left and right and up to make sure you only go up
|
||||
if((movement_dir & NORTH) && (movement_dir & SOUTH))
|
||||
movement_dir &= ~(NORTH|SOUTH)
|
||||
if((movement_dir & EAST) && (movement_dir & WEST))
|
||||
movement_dir &= ~(EAST|WEST)
|
||||
user.Move(get_step(src, movement_dir), movement_dir)
|
||||
@@ -0,0 +1,18 @@
|
||||
/mob/living/carbon/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("R", "Southwest") // Southwest is End
|
||||
toggle_throw_mode()
|
||||
return
|
||||
if("1")
|
||||
a_intent_change("help")
|
||||
return
|
||||
if("2")
|
||||
a_intent_change("disarm")
|
||||
return
|
||||
if("3")
|
||||
a_intent_change("grab")
|
||||
return
|
||||
if("4")
|
||||
a_intent_change("harm")
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,53 @@
|
||||
// Clients aren't datums so we have to define these procs indpendently.
|
||||
// These verbs are called for all key press and release events
|
||||
/client/verb/keyDown(_key as text)
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
keys_held[_key] = world.time
|
||||
var/movement = SSinput.movement_keys[_key]
|
||||
if (prefs.toggles & AZERTY) movement = SSinput.alt_movement_keys[_key]
|
||||
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
|
||||
next_move_dir_add |= movement
|
||||
|
||||
// Client-level keybindings are ones anyone should be able to do at any time
|
||||
// Things like taking screenshots, hitting tab, and adminhelps.
|
||||
|
||||
switch(_key)
|
||||
if("F1")
|
||||
if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used?
|
||||
winset(src, null, "command=.options")
|
||||
else
|
||||
get_adminhelp()
|
||||
return
|
||||
if("F2") // Screenshot. Hold shift to choose a name and location to save in
|
||||
winset(src, null, "command=.screenshot [!keys_held["shift"] ? "auto" : ""]")
|
||||
return
|
||||
if("F12") // Toggles minimal HUD
|
||||
mob.button_pressed_F12()
|
||||
return
|
||||
|
||||
if(holder)
|
||||
holder.key_down(_key, src)
|
||||
if(mob.focus)
|
||||
mob.focus.key_down(_key, src)
|
||||
|
||||
/client/verb/keyUp(_key as text)
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
keys_held -= _key
|
||||
var/movement = SSinput.movement_keys[_key]
|
||||
if (prefs.toggles & AZERTY) movement = SSinput.alt_movement_keys[_key]
|
||||
if(!(next_move_dir_add & movement))
|
||||
next_move_dir_sub |= movement
|
||||
|
||||
if(holder)
|
||||
holder.key_up(_key, src)
|
||||
if(mob.focus)
|
||||
mob.focus.key_up(_key, src)
|
||||
|
||||
// Called every game tick
|
||||
/client/keyLoop()
|
||||
if(holder)
|
||||
holder.keyLoop(src)
|
||||
if(mob.focus)
|
||||
mob.focus.keyLoop(src)
|
||||
@@ -0,0 +1,80 @@
|
||||
/mob/living/carbon/human/key_down(_key, client/user)
|
||||
if(_key == "H")
|
||||
var/obj/item/clothing/accessory/holster/H = null
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/S = w_uniform
|
||||
if(S.accessories.len)
|
||||
H = locate() in S.accessories
|
||||
if (!H)
|
||||
return
|
||||
if(!H.holstered)
|
||||
if(!istype(get_active_hand(), /obj/item/gun))
|
||||
to_chat(usr, "<span class='warning'>You need your gun equiped to holster it.</span>")
|
||||
return
|
||||
var/obj/item/gun/W = get_active_hand()
|
||||
H.holster(W, usr)
|
||||
else
|
||||
H.unholster(usr)
|
||||
if(client.keys_held["Shift"])
|
||||
switch(_key)
|
||||
if("E") // Put held thing in belt or take out most recent thing from belt
|
||||
quick_equip() // Implementing the storage component is going to take way too long
|
||||
// var/obj/item/thing = get_active_hand()
|
||||
// var/obj/item/equipped_belt = get_item_by_slot(slot_belt)
|
||||
// if(!equipped_belt) // We also let you equip a belt like this
|
||||
// if(!thing)
|
||||
// to_chat(user, "<span class='notice'>You have no belt to take something out of.</span>")
|
||||
// return
|
||||
// if(equip_to_slot_if_possible(thing, slot_belt))
|
||||
// update_inv_r_hand()
|
||||
// update_inv_l_hand()
|
||||
// return
|
||||
// if(!SEND_SIGNAL(equipped_belt, COMSIG_CONTAINS_STORAGE)) // not a storage item
|
||||
// if(!thing)
|
||||
// equipped_belt.attack_hand(src)
|
||||
// else
|
||||
// to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
// return
|
||||
// if(thing) // put thing in belt
|
||||
// if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
|
||||
// to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
// return
|
||||
// if(!equipped_belt.contents.len) // nothing to take out
|
||||
// to_chat(user, "<span class='notice'>There's nothing in your belt to take out.</span>")
|
||||
// return
|
||||
// var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
|
||||
// if(!stored || stored.on_found(src))
|
||||
// return
|
||||
// stored.attack_hand(src) // take out thing from belt
|
||||
// return
|
||||
|
||||
/* if("B") // Put held thing in backpack or take out most recent thing from backpack
|
||||
var/obj/item/thing = get_active_hand()
|
||||
var/obj/item/equipped_back = get_item_by_slot(slot_back)
|
||||
if(!equipped_back) // We also let you equip a backpack like this
|
||||
if(!thing)
|
||||
to_chat(user, "<span class='notice'>You have no backpack to take something out of.</span>")
|
||||
return
|
||||
if(equip_to_slot_if_possible(thing, slot_back))
|
||||
update_inv_r_hand()
|
||||
update_inv_l_hand()
|
||||
return
|
||||
if(!SEND_SIGNAL(equipped_back, COMSIG_CONTAINS_STORAGE)) // not a storage item
|
||||
if(!thing)
|
||||
equipped_back.attack_hand(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
return
|
||||
if(thing) // put thing in backpack
|
||||
if(!SEND_SIGNAL(equipped_back, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
|
||||
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
return
|
||||
if(!equipped_back.contents.len) // nothing to take out
|
||||
to_chat(user, "<span class='notice'>There's nothing in your backpack to take out.</span>")
|
||||
return
|
||||
var/obj/item/stored = equipped_back.contents[equipped_back.contents.len]
|
||||
if(!stored || stored.on_found(src))
|
||||
return
|
||||
stored.attack_hand(src) // take out thing from backpack
|
||||
return */
|
||||
return ..()
|
||||
@@ -0,0 +1,7 @@
|
||||
/mob/living/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("B")
|
||||
resist()
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -0,0 +1,132 @@
|
||||
// Technically the client argument is unncessary here since that SHOULD be src.client but let's not assume things
|
||||
// All it takes is one badmin setting their focus to someone else's client to mess things up
|
||||
// Or we can have NPC's send actual keypresses and detect that by seeing no client
|
||||
|
||||
/mob/key_down(_key, client/user)
|
||||
if(user.prefs.toggles & AZERTY)
|
||||
switch(_key)
|
||||
if("Delete")
|
||||
if(!pulling)
|
||||
to_chat(src, "<span class='notice'>You are not pulling anything.</span>")
|
||||
else
|
||||
stop_pulling()
|
||||
return
|
||||
if("Insert", "G")
|
||||
a_intent_change(INTENT_HOTKEY_RIGHT)
|
||||
return
|
||||
if("F")
|
||||
a_intent_change(INTENT_HOTKEY_LEFT)
|
||||
return
|
||||
if("X", "Northeast") // Northeast is Page-up
|
||||
swap_hand()
|
||||
return
|
||||
if("Y", "W", "Southeast") // Southeast is Page-down
|
||||
mode() // attack_self(). No idea who came up with "mode()"
|
||||
return
|
||||
if("A", "Northwest") // Northwest is Home
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You have nothing to drop in your hand!</span>")
|
||||
else
|
||||
drop_item(I)
|
||||
return
|
||||
if("E")
|
||||
quick_equip()
|
||||
return
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
else
|
||||
switch(_key)
|
||||
if("Delete")
|
||||
if(!pulling)
|
||||
to_chat(src, "<span class='notice'>You are not pulling anything.</span>")
|
||||
else
|
||||
stop_pulling()
|
||||
return
|
||||
if("Insert", "G")
|
||||
a_intent_change(INTENT_HOTKEY_RIGHT)
|
||||
return
|
||||
if("F")
|
||||
a_intent_change(INTENT_HOTKEY_LEFT)
|
||||
return
|
||||
if("X", "Northeast") // Northeast is Page-up
|
||||
swap_hand()
|
||||
return
|
||||
if("Y", "Z", "Southeast") // Southeast is Page-down
|
||||
mode() // attack_self(). No idea who came up with "mode()"
|
||||
return
|
||||
if("Q", "Northwest") // Northwest is Home
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You have nothing to drop in your hand!</span>")
|
||||
else
|
||||
drop_item(I)
|
||||
return
|
||||
if("E")
|
||||
quick_equip()
|
||||
return
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
//Bodypart selections
|
||||
if(client.prefs.toggles & NUMPAD_TARGET)
|
||||
switch(_key)
|
||||
if("Numpad8")
|
||||
user.body_toggle_head()
|
||||
return
|
||||
if("Numpad4")
|
||||
user.body_r_arm()
|
||||
return
|
||||
if("Numpad5")
|
||||
user.body_chest()
|
||||
return
|
||||
if("Numpad6")
|
||||
user.body_l_arm()
|
||||
return
|
||||
if("Numpad1")
|
||||
user.body_r_leg()
|
||||
return
|
||||
if("Numpad2")
|
||||
user.body_groin()
|
||||
return
|
||||
if("Numpad3")
|
||||
user.body_l_leg()
|
||||
return
|
||||
|
||||
if(client.keys_held["Ctrl"] && client.prefs.toggles & AZERTY)
|
||||
switch(SSinput.alt_movement_keys[_key])
|
||||
if(NORTH)
|
||||
northface()
|
||||
return
|
||||
if(SOUTH)
|
||||
southface()
|
||||
return
|
||||
if(WEST)
|
||||
westface()
|
||||
return
|
||||
if(EAST)
|
||||
eastface()
|
||||
return
|
||||
else if(client.keys_held["Ctrl"])
|
||||
switch(SSinput.movement_keys[_key])
|
||||
if(NORTH)
|
||||
northface()
|
||||
return
|
||||
if(SOUTH)
|
||||
southface()
|
||||
return
|
||||
if(WEST)
|
||||
westface()
|
||||
return
|
||||
if(EAST)
|
||||
eastface()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/key_up(_key, client/user)
|
||||
switch(_key)
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,12 @@
|
||||
/mob/living/silicon/robot/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("1", "2", "3")
|
||||
toggle_module(text2num(_key))
|
||||
return
|
||||
if("4")
|
||||
a_intent_change(INTENT_HOTKEY_LEFT)
|
||||
return
|
||||
if("Q")
|
||||
uneq_active()
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,8 @@
|
||||
/mob
|
||||
var/datum/focus //What receives our keyboard inputs. src by default
|
||||
|
||||
/mob/proc/set_focus(datum/new_focus)
|
||||
if(focus == new_focus)
|
||||
return
|
||||
focus = new_focus
|
||||
reset_perspective(focus) //Maybe this should be done manually? You figure it out, reader
|
||||
@@ -0,0 +1,42 @@
|
||||
# In-code keypress handling system
|
||||
|
||||
This whole system is heavily based off of forum_account's keyboard library.
|
||||
Thanks to forum_account for saving the day, the library can be found
|
||||
[here](https://secure.byond.com/developer/Forum_account/Keyboard)!
|
||||
|
||||
.dmf macros have some very serious shortcomings. For example, they do not allow reusing parts
|
||||
of one macro in another, so giving cyborgs their own shortcuts to swap active module couldn't
|
||||
inherit the movement that all mobs should have anyways. The webclient only supports one macro,
|
||||
so having more than one was problematic. Additionally each keybind has to call an actual
|
||||
verb, which meant a lot of hidden verbs that just call one other proc. Also our existing
|
||||
macro was really bad and tied unrelated behavior into `Northeast()`, `Southeast()`, `Northwest()`,
|
||||
and `Southwest()`.
|
||||
|
||||
The basic premise of this system is to not screw with .dmf macro setup at all and handle
|
||||
pressing those keys in the code instead. We have every key call `client.keyDown()`
|
||||
or `client.keyUp()` with the pressed key as an argument. Certain keys get processed
|
||||
directly by the client because they should be doable at any time, then we call
|
||||
`keyDown()` or `keyUp()` on the client's holder and the client's mob's focus.
|
||||
By default `mob.focus` is the mob itself, but you can set it to any datum to give control of a
|
||||
client's keypresses to another object. This would be a good way to handle a menu or driving
|
||||
a mech. You can also set it to null to disregard input from a certain user.
|
||||
|
||||
Movement is handled by having each client call `client.keyLoop()` every game tick.
|
||||
As above, this calls holder and `focus.keyLoop()`. `atom/movable/keyLoop()` handles movement
|
||||
Try to keep the calculations in this proc light. It runs every tick for every client after all!
|
||||
|
||||
You can also tell which keys are being held down now. Each client a list of keys pressed called
|
||||
`keys_held`. Each entry is a key as a text string associated with the world.time when it was
|
||||
pressed.
|
||||
|
||||
No client-set keybindings at this time, but it shouldn't be too hard if someone wants.
|
||||
|
||||
Notes about certain keys:
|
||||
|
||||
* `Tab` has client-sided behavior but acts normally
|
||||
* `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away.
|
||||
* `\` needs to be escaped in the dmf so any usage is `\\`
|
||||
|
||||
You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up
|
||||
events. They happen outside of a byond tick and have no meaning there. Key looping
|
||||
works correctly since it's part of a subsystem, not direct input.
|
||||
@@ -0,0 +1,46 @@
|
||||
/client
|
||||
var/list/keys_held = list() // A list of any keys held currently
|
||||
// These next two vars are to apply movement for keypresses and releases made while move delayed.
|
||||
// Because discarding that input makes the game less responsive.
|
||||
var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done
|
||||
var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done
|
||||
|
||||
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
|
||||
|
||||
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
|
||||
return
|
||||
/datum/proc/key_up(key, client/user) // Called when a key is released
|
||||
return
|
||||
/datum/proc/keyLoop(client/user) // Called once every frame
|
||||
set waitfor = FALSE
|
||||
return
|
||||
|
||||
// removes all the existing macros
|
||||
/client/proc/erase_all_macros()
|
||||
var/list/macro_sets = params2list(winget(src, null, "macros"))
|
||||
var/erase_output = ""
|
||||
for(var/i in 1 to macro_sets.len)
|
||||
var/setname = macro_sets[i]
|
||||
var/list/macro_set = params2list(winget(src, "[setname].*", "command")) // The third arg doesnt matter here as we're just removing them all
|
||||
for(var/k in 1 to macro_set.len)
|
||||
var/list/split_name = splittext(macro_set[k], ".")
|
||||
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
|
||||
erase_output = "[erase_output];[macro_name].parent=null"
|
||||
winset(src, null, erase_output)
|
||||
|
||||
/client/proc/set_macros()
|
||||
set waitfor = FALSE
|
||||
|
||||
erase_all_macros()
|
||||
|
||||
var/list/macro_sets = SSinput.macro_sets
|
||||
for(var/i in 1 to macro_sets.len)
|
||||
var/setname = macro_sets[i]
|
||||
if(setname != "default")
|
||||
winclone(src, "default", setname)
|
||||
var/list/macro_set = macro_sets[setname]
|
||||
for(var/k in 1 to macro_set.len)
|
||||
var/key = macro_set[k]
|
||||
var/command = macro_set[key]
|
||||
winset(src, "[setname]-\ref[key]", "parent=[setname];name=[key];command=[command]")
|
||||
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
|
||||
@@ -1,44 +1,44 @@
|
||||
/****************Explorer's Suit and Mask****************/
|
||||
/obj/item/clothing/suit/hooded/explorer
|
||||
name = "explorer suit"
|
||||
desc = "An armoured suit for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
|
||||
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
|
||||
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
hoodtype = /obj/item/clothing/head/hooded/explorer
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
|
||||
resistance_flags = FIRE_PROOF
|
||||
hide_tail_by_species = list("Vox" , "Vulpkanin" , "Unathi" , "Tajaran")
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/suit.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/suit.dmi',
|
||||
"Tajaran" = 'icons/mob/species/tajaran/suit.dmi',
|
||||
"Unathi" = 'icons/mob/species/unathi/suit.dmi',
|
||||
"Vulpkanin" = 'icons/mob/species/vulpkanin/suit.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/head/hooded/explorer
|
||||
name = "explorer hood"
|
||||
desc = "An armoured hood for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = HEAD
|
||||
flags = BLOCKHAIR | NODROP
|
||||
flags_cover = HEADCOVERSEYES
|
||||
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/head.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/head.dmi',
|
||||
"Grey" = 'icons/mob/species/grey/head.dmi',
|
||||
"Skrell" = 'icons/mob/species/skrell/head.dmi'
|
||||
/****************Explorer's Suit and Mask****************/
|
||||
/obj/item/clothing/suit/hooded/explorer
|
||||
name = "explorer suit"
|
||||
desc = "An armoured suit for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
|
||||
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
|
||||
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
hoodtype = /obj/item/clothing/head/hooded/explorer
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
|
||||
resistance_flags = FIRE_PROOF
|
||||
hide_tail_by_species = list("Vox" , "Vulpkanin" , "Unathi" , "Tajaran")
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/suit.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/suit.dmi',
|
||||
"Tajaran" = 'icons/mob/species/tajaran/suit.dmi',
|
||||
"Unathi" = 'icons/mob/species/unathi/suit.dmi',
|
||||
"Vulpkanin" = 'icons/mob/species/vulpkanin/suit.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/head/hooded/explorer
|
||||
name = "explorer hood"
|
||||
desc = "An armoured hood for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = HEAD
|
||||
flags = BLOCKHAIR | NODROP
|
||||
flags_cover = HEADCOVERSEYES
|
||||
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/head.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/head.dmi',
|
||||
"Grey" = 'icons/mob/species/grey/head.dmi',
|
||||
"Skrell" = 'icons/mob/species/skrell/head.dmi'
|
||||
)
|
||||
@@ -6,6 +6,14 @@
|
||||
if(hand) return l_hand
|
||||
else return r_hand
|
||||
|
||||
/mob/verb/quick_equip()
|
||||
set name = "quick-equip"
|
||||
set hidden = 1
|
||||
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
I.equip_to_best_slot(src)
|
||||
|
||||
/mob/proc/is_in_active_hand(obj/item/I)
|
||||
var/obj/item/item_to_test = get_active_hand()
|
||||
|
||||
@@ -254,3 +262,4 @@
|
||||
if(slot_r_hand)
|
||||
return r_hand
|
||||
return null
|
||||
|
||||
|
||||
@@ -975,6 +975,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
|
||||
to_chat(src, "<span class='notice'>You [slipVerb]ped on [description]!</span>")
|
||||
playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3)
|
||||
// Something something don't run with scissors
|
||||
moving_diagonally = 0 //If this was part of diagonal move slipping will stop it.
|
||||
Stun(stun)
|
||||
Weaken(weaken)
|
||||
return 1
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
/mob/living/carbon/human/verb/quick_equip()
|
||||
set name = "quick-equip"
|
||||
set hidden = 1
|
||||
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
I.equip_to_best_slot(src)
|
||||
|
||||
/mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1)
|
||||
for(var/slot in slots)
|
||||
if(equip_to_slot_if_possible(W, slots[slot], del_on_fail = 0))
|
||||
|
||||
@@ -528,7 +528,7 @@
|
||||
return
|
||||
|
||||
var/pull_dir = get_dir(src, pulling)
|
||||
if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) // puller and pullee more than one tile away or in diagonal position
|
||||
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))) // puller and pullee more than one tile away or in diagonal position
|
||||
if(isliving(pulling))
|
||||
var/mob/living/M = pulling
|
||||
if(M.lying && !M.buckled && (prob(M.getBruteLoss() * 200 / M.maxHealth)))
|
||||
|
||||
@@ -2,6 +2,3 @@
|
||||
..()
|
||||
regenerate_icons()
|
||||
show_laws(0)
|
||||
|
||||
var/datum/hotkey_mode/cyborg/C = new(src)
|
||||
C.set_winset_values()
|
||||
|
||||
@@ -1,265 +1,265 @@
|
||||
#define MINER_DASH_RANGE 4
|
||||
|
||||
/*
|
||||
|
||||
BLOOD-DRUNK MINER
|
||||
|
||||
Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive.
|
||||
|
||||
The blood-drunk miner's attacks are as follows
|
||||
- If not in KA range, it will rapidly dash at its target
|
||||
- If in KA range, it will fire its kinetic accelerator
|
||||
- If in melee range, will rapidly attack, akin to an actual player
|
||||
- After any of these attacks, may transform its cleaving saw:
|
||||
Untransformed, it attacks very rapidly for smaller amounts of damage
|
||||
Transformed, it attacks at normal speed for higher damage and cleaves enemies hit
|
||||
|
||||
When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
|
||||
|
||||
Difficulty: Medium
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
|
||||
name = "blood-drunk miner"
|
||||
desc = "A miner destined to wander forever, engaged in an endless hunt."
|
||||
health = 900
|
||||
maxHealth = 900
|
||||
icon_state = "miner"
|
||||
icon_living = "miner"
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
light_color = "#E4C7C5"
|
||||
speak_emote = list("roars")
|
||||
speed = 1
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
ranged = 1
|
||||
ranged_cooldown_time = 16
|
||||
pixel_x = -16
|
||||
loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator)
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/melee/energy/cleaving_saw/miner/miner_saw
|
||||
var/time_until_next_transform = 0
|
||||
var/dashing = FALSE
|
||||
var/dash_cooldown = 15
|
||||
var/guidance = FALSE
|
||||
deathmessage = "falls to the ground, decaying into glowing particles."
|
||||
death_sound = "bodyfall"
|
||||
|
||||
/obj/item/gps/internal/miner
|
||||
icon_state = null
|
||||
gpstag = "Resonant Signal"
|
||||
desc = "The sweet blood, oh, it sings to me."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
|
||||
force = 6
|
||||
force_on = 10
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
target.add_stun_absorption("miner", 10, INFINITY)
|
||||
..()
|
||||
target.stun_absorption -= "miner"
|
||||
|
||||
/obj/item/projectile/kinetic/miner
|
||||
damage = 20
|
||||
speed = 0.9
|
||||
icon_state = "ka_tracer"
|
||||
range = MINER_DASH_RANGE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
miner_saw = new(src)
|
||||
internal_gps = new/obj/item/gps/internal/miner(src)
|
||||
|
||||
// Add a zone selection UI; otherwise the mob can't melee attack properly.
|
||||
zone_sel = new /obj/screen/zone_sel()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
|
||||
if(health > 0)
|
||||
return
|
||||
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
|
||||
if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
|
||||
if(dash())
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return
|
||||
face_atom(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
visible_message("<span class='danger'>[src] butchers [L]!</span>",
|
||||
"<span class='userdanger'>You butcher [L], restoring your health!</span>")
|
||||
if(!is_station_level(z) || client) //NPC monsters won't heal while on station
|
||||
if(guidance)
|
||||
adjustHealth(-L.maxHealth)
|
||||
else
|
||||
adjustHealth(-(L.maxHealth * 0.5))
|
||||
L.gib()
|
||||
return TRUE
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(!used_item && !isturf(A))
|
||||
used_item = miner_saw
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/GiveTarget(new_target)
|
||||
var/targets_the_same = (new_target == target)
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
wander = TRUE
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
|
||||
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
visible_message("<span class='danger'>[src] fires the proto-kinetic accelerator!</span>")
|
||||
face_atom(target)
|
||||
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
|
||||
if(world.time < dash_cooldown)
|
||||
return
|
||||
var/list/accessable_turfs = list()
|
||||
var/self_dist_to_target = 0
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(!QDELETED(dash_target))
|
||||
self_dist_to_target += get_dist(dash_target, own_turf)
|
||||
for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
|
||||
var/turf_dist_to_target = 0
|
||||
if(!QDELETED(dash_target))
|
||||
turf_dist_to_target += get_dist(dash_target, O)
|
||||
if(get_dist(src, O) >= MINER_DASH_RANGE && turf_dist_to_target <= self_dist_to_target && !islava(O) && !ischasm(O))
|
||||
var/valid = TRUE
|
||||
for(var/turf/T in getline(own_turf, O))
|
||||
if(is_blocked_turf(T, TRUE))
|
||||
valid = FALSE
|
||||
continue
|
||||
if(valid)
|
||||
accessable_turfs[O] = turf_dist_to_target
|
||||
var/turf/target_turf
|
||||
if(!QDELETED(dash_target))
|
||||
var/closest_dist = MINER_DASH_RANGE
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] < closest_dist)
|
||||
closest_dist = accessable_turfs[t]
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] != closest_dist)
|
||||
accessable_turfs -= t
|
||||
if(!LAZYLEN(accessable_turfs))
|
||||
return
|
||||
dash_cooldown = world.time + initial(dash_cooldown)
|
||||
target_turf = pick(accessable_turfs)
|
||||
var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
|
||||
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
|
||||
animate(D, alpha = 0, time = 5)
|
||||
forceMove(step_back_turf)
|
||||
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
dashing = TRUE
|
||||
alpha = 0
|
||||
animate(src, alpha = 255, time = 5)
|
||||
sleep(2)
|
||||
D.forceMove(step_forward_turf)
|
||||
forceMove(target_turf)
|
||||
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
sleep(1)
|
||||
dashing = FALSE
|
||||
shoot_ka()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
|
||||
if(time_until_next_transform <= world.time)
|
||||
miner_saw.transform_cooldown = 0
|
||||
miner_saw.transform_weapon(src, TRUE)
|
||||
icon_state = "miner[miner_saw.active ? "_transformed":""]"
|
||||
icon_living = "miner[miner_saw.active ? "_transformed":""]"
|
||||
time_until_next_transform = world.time + rand(50, 100)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death
|
||||
icon_state = "miner_death"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/Initialize(mapload, set_dir)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fade_out)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/proc/fade_out()
|
||||
var/matrix/M = new
|
||||
M.Turn(pick(90, 270))
|
||||
var/final_dir = dir
|
||||
if(dir & (EAST|WEST)) //Facing east or west
|
||||
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
|
||||
|
||||
animate(src, transform = M, pixel_y = -6, dir = final_dir, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
sleep(5)
|
||||
animate(src, color = list("#A7A19E", "#A7A19E", "#A7A19E", list(0, 0, 0)), time = 10, easing = EASE_IN, flags = ANIMATION_PARALLEL)
|
||||
sleep(4)
|
||||
animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
#define MINER_DASH_RANGE 4
|
||||
|
||||
/*
|
||||
|
||||
BLOOD-DRUNK MINER
|
||||
|
||||
Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive.
|
||||
|
||||
The blood-drunk miner's attacks are as follows
|
||||
- If not in KA range, it will rapidly dash at its target
|
||||
- If in KA range, it will fire its kinetic accelerator
|
||||
- If in melee range, will rapidly attack, akin to an actual player
|
||||
- After any of these attacks, may transform its cleaving saw:
|
||||
Untransformed, it attacks very rapidly for smaller amounts of damage
|
||||
Transformed, it attacks at normal speed for higher damage and cleaves enemies hit
|
||||
|
||||
When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
|
||||
|
||||
Difficulty: Medium
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
|
||||
name = "blood-drunk miner"
|
||||
desc = "A miner destined to wander forever, engaged in an endless hunt."
|
||||
health = 900
|
||||
maxHealth = 900
|
||||
icon_state = "miner"
|
||||
icon_living = "miner"
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
light_color = "#E4C7C5"
|
||||
speak_emote = list("roars")
|
||||
speed = 1
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
ranged = 1
|
||||
ranged_cooldown_time = 16
|
||||
pixel_x = -16
|
||||
loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator)
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/melee/energy/cleaving_saw/miner/miner_saw
|
||||
var/time_until_next_transform = 0
|
||||
var/dashing = FALSE
|
||||
var/dash_cooldown = 15
|
||||
var/guidance = FALSE
|
||||
deathmessage = "falls to the ground, decaying into glowing particles."
|
||||
death_sound = "bodyfall"
|
||||
|
||||
/obj/item/gps/internal/miner
|
||||
icon_state = null
|
||||
gpstag = "Resonant Signal"
|
||||
desc = "The sweet blood, oh, it sings to me."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
|
||||
force = 6
|
||||
force_on = 10
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
target.add_stun_absorption("miner", 10, INFINITY)
|
||||
..()
|
||||
target.stun_absorption -= "miner"
|
||||
|
||||
/obj/item/projectile/kinetic/miner
|
||||
damage = 20
|
||||
speed = 0.9
|
||||
icon_state = "ka_tracer"
|
||||
range = MINER_DASH_RANGE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
miner_saw = new(src)
|
||||
internal_gps = new/obj/item/gps/internal/miner(src)
|
||||
|
||||
// Add a zone selection UI; otherwise the mob can't melee attack properly.
|
||||
zone_sel = new /obj/screen/zone_sel()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
|
||||
if(health > 0)
|
||||
return
|
||||
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
|
||||
if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
|
||||
if(dash())
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return
|
||||
face_atom(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
visible_message("<span class='danger'>[src] butchers [L]!</span>",
|
||||
"<span class='userdanger'>You butcher [L], restoring your health!</span>")
|
||||
if(!is_station_level(z) || client) //NPC monsters won't heal while on station
|
||||
if(guidance)
|
||||
adjustHealth(-L.maxHealth)
|
||||
else
|
||||
adjustHealth(-(L.maxHealth * 0.5))
|
||||
L.gib()
|
||||
return TRUE
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(!used_item && !isturf(A))
|
||||
used_item = miner_saw
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/GiveTarget(new_target)
|
||||
var/targets_the_same = (new_target == target)
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
wander = TRUE
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
|
||||
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
visible_message("<span class='danger'>[src] fires the proto-kinetic accelerator!</span>")
|
||||
face_atom(target)
|
||||
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
|
||||
if(world.time < dash_cooldown)
|
||||
return
|
||||
var/list/accessable_turfs = list()
|
||||
var/self_dist_to_target = 0
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(!QDELETED(dash_target))
|
||||
self_dist_to_target += get_dist(dash_target, own_turf)
|
||||
for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
|
||||
var/turf_dist_to_target = 0
|
||||
if(!QDELETED(dash_target))
|
||||
turf_dist_to_target += get_dist(dash_target, O)
|
||||
if(get_dist(src, O) >= MINER_DASH_RANGE && turf_dist_to_target <= self_dist_to_target && !islava(O) && !ischasm(O))
|
||||
var/valid = TRUE
|
||||
for(var/turf/T in getline(own_turf, O))
|
||||
if(is_blocked_turf(T, TRUE))
|
||||
valid = FALSE
|
||||
continue
|
||||
if(valid)
|
||||
accessable_turfs[O] = turf_dist_to_target
|
||||
var/turf/target_turf
|
||||
if(!QDELETED(dash_target))
|
||||
var/closest_dist = MINER_DASH_RANGE
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] < closest_dist)
|
||||
closest_dist = accessable_turfs[t]
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] != closest_dist)
|
||||
accessable_turfs -= t
|
||||
if(!LAZYLEN(accessable_turfs))
|
||||
return
|
||||
dash_cooldown = world.time + initial(dash_cooldown)
|
||||
target_turf = pick(accessable_turfs)
|
||||
var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
|
||||
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
|
||||
animate(D, alpha = 0, time = 5)
|
||||
forceMove(step_back_turf)
|
||||
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
dashing = TRUE
|
||||
alpha = 0
|
||||
animate(src, alpha = 255, time = 5)
|
||||
sleep(2)
|
||||
D.forceMove(step_forward_turf)
|
||||
forceMove(target_turf)
|
||||
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
sleep(1)
|
||||
dashing = FALSE
|
||||
shoot_ka()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
|
||||
if(time_until_next_transform <= world.time)
|
||||
miner_saw.transform_cooldown = 0
|
||||
miner_saw.transform_weapon(src, TRUE)
|
||||
icon_state = "miner[miner_saw.active ? "_transformed":""]"
|
||||
icon_living = "miner[miner_saw.active ? "_transformed":""]"
|
||||
time_until_next_transform = world.time + rand(50, 100)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death
|
||||
icon_state = "miner_death"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/Initialize(mapload, set_dir)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fade_out)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/proc/fade_out()
|
||||
var/matrix/M = new
|
||||
M.Turn(pick(90, 270))
|
||||
var/final_dir = dir
|
||||
if(dir & (EAST|WEST)) //Facing east or west
|
||||
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
|
||||
|
||||
animate(src, transform = M, pixel_y = -6, dir = final_dir, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
sleep(5)
|
||||
animate(src, color = list("#A7A19E", "#A7A19E", "#A7A19E", list(0, 0, 0)), time = 10, easing = EASE_IN, flags = ANIMATION_PARALLEL)
|
||||
sleep(4)
|
||||
animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
#undef MINER_DASH_RANGE
|
||||
@@ -2,6 +2,7 @@
|
||||
GLOB.mob_list -= src
|
||||
GLOB.dead_mob_list -= src
|
||||
GLOB.living_mob_list -= src
|
||||
focus = null
|
||||
QDEL_NULL(hud_used)
|
||||
if(mind && mind.current == src)
|
||||
spellremove(src)
|
||||
@@ -30,6 +31,7 @@
|
||||
GLOB.dead_mob_list += src
|
||||
else
|
||||
GLOB.living_mob_list += src
|
||||
set_focus(src)
|
||||
prepare_huds()
|
||||
..()
|
||||
|
||||
@@ -50,7 +52,6 @@
|
||||
/mob/proc/GetAltName()
|
||||
return ""
|
||||
|
||||
|
||||
/mob/proc/Cell()
|
||||
set category = "Admin"
|
||||
set hidden = 1
|
||||
@@ -173,6 +174,7 @@
|
||||
return 0
|
||||
|
||||
/mob/proc/Life(seconds, times_fired)
|
||||
set waitfor = FALSE
|
||||
if(forced_look)
|
||||
if(!isnum(forced_look))
|
||||
var/atom/A = locateUID(forced_look)
|
||||
|
||||
@@ -399,9 +399,6 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM)
|
||||
set name = "Rest"
|
||||
set category = "IC"
|
||||
|
||||
if(world.time < client.move_delay)
|
||||
return
|
||||
|
||||
if(!resting)
|
||||
client.move_delay = world.time + 20
|
||||
to_chat(src, "<span class='notice'>You are now resting.</span>")
|
||||
|
||||
+145
-105
@@ -15,102 +15,6 @@
|
||||
return 1
|
||||
return (!mover.density || !density || lying)
|
||||
|
||||
//The byond version of these verbs wait for the next tick before acting.
|
||||
// instant verbs however can run mid tick or even during the time between ticks.
|
||||
#define DO_MOVE(this_dir) var/final_dir = turn(this_dir, -dir2angle(dir)); Move(get_step(mob, final_dir), final_dir);
|
||||
|
||||
/client/verb/moveup()
|
||||
set name = ".moveup"
|
||||
set instant = 1
|
||||
DO_MOVE(NORTH)
|
||||
|
||||
/client/verb/movedown()
|
||||
set name = ".movedown"
|
||||
set instant = 1
|
||||
DO_MOVE(SOUTH)
|
||||
|
||||
/client/verb/moveright()
|
||||
set name = ".moveright"
|
||||
set instant = 1
|
||||
DO_MOVE(EAST)
|
||||
|
||||
/client/verb/moveleft()
|
||||
set name = ".moveleft"
|
||||
set instant = 1
|
||||
DO_MOVE(WEST)
|
||||
|
||||
#undef DO_MOVE
|
||||
|
||||
/client/Northeast()
|
||||
swap_hand()
|
||||
return
|
||||
|
||||
|
||||
/client/Southeast()
|
||||
attack_self()
|
||||
return
|
||||
|
||||
|
||||
/client/Southwest()
|
||||
if(iscarbon(usr))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.toggle_throw_mode()
|
||||
else if(isrobot(usr))
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
var/module = R.get_selected_module()
|
||||
if(!module)
|
||||
to_chat(usr, "<span class='warning'>You have no module selected.</span>")
|
||||
return
|
||||
R.cycle_modules()
|
||||
R.uneq_numbered(module)
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>This mob type cannot throw items.</span>")
|
||||
return
|
||||
|
||||
|
||||
/client/Northwest()
|
||||
if(iscarbon(usr))
|
||||
var/mob/living/carbon/C = usr
|
||||
if(!C.get_active_hand())
|
||||
to_chat(usr, "<span class='warning'>You have nothing to drop in your hand.</span>")
|
||||
return
|
||||
drop_item()
|
||||
else if(isrobot(usr))
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
if(!R.get_selected_module())
|
||||
to_chat(usr, "<span class='warning'>You have no module selected.</span>")
|
||||
return
|
||||
R.deselect_module(R.get_selected_module())
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>This mob type cannot drop items.</span>")
|
||||
return
|
||||
|
||||
//This gets called when you press the delete button.
|
||||
/client/verb/delete_key_pressed()
|
||||
set hidden = 1
|
||||
|
||||
if(!usr.pulling)
|
||||
to_chat(usr, "<span class='notice'>You are not pulling anything.</span>")
|
||||
return
|
||||
usr.stop_pulling()
|
||||
|
||||
/client/verb/swap_hand()
|
||||
set hidden = 1
|
||||
if(istype(mob, /mob/living/carbon))
|
||||
mob:swap_hand()
|
||||
if(istype(mob,/mob/living/silicon/robot))
|
||||
var/mob/living/silicon/robot/R = mob
|
||||
R.cycle_modules()
|
||||
return
|
||||
|
||||
|
||||
|
||||
/client/verb/attack_self()
|
||||
set hidden = 1
|
||||
if(mob)
|
||||
mob.mode()
|
||||
return
|
||||
|
||||
|
||||
/client/verb/toggle_throw_mode()
|
||||
set hidden = 1
|
||||
@@ -128,7 +32,7 @@
|
||||
return
|
||||
|
||||
|
||||
/client/Center()
|
||||
/* /client/Center()
|
||||
/* No 3D movement in 2D spessman game. dir 16 is Z Up
|
||||
if(isobj(mob.loc))
|
||||
var/obj/O = mob.loc
|
||||
@@ -136,7 +40,7 @@
|
||||
return O.relaymove(mob, 16)
|
||||
*/
|
||||
return
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/client/proc/Move_object(direct)
|
||||
@@ -155,11 +59,17 @@
|
||||
/client/Move(n, direct)
|
||||
if(world.time < move_delay)
|
||||
return
|
||||
else
|
||||
next_move_dir_add = 0
|
||||
next_move_dir_sub = 0
|
||||
var/old_move_delay = move_delay
|
||||
move_delay = world.time + world.tick_lag //this is here because Move() can now be called multiple times per tick
|
||||
if(!mob || !mob.loc)
|
||||
return 0
|
||||
|
||||
if(!n || !direct) // why did we never check this before?
|
||||
return FALSE
|
||||
|
||||
if(mob.notransform)
|
||||
return 0 //This is sota the goto stop mobs from moving var
|
||||
|
||||
@@ -226,9 +136,9 @@
|
||||
moving = 1
|
||||
var/delay = mob.movement_delay()
|
||||
if(old_move_delay + (delay * MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time)
|
||||
move_delay = old_move_delay + delay
|
||||
move_delay = old_move_delay
|
||||
else
|
||||
move_delay = delay + world.time
|
||||
move_delay = world.time
|
||||
mob.last_movement = world.time
|
||||
|
||||
if(locate(/obj/item/grab, mob))
|
||||
@@ -264,19 +174,29 @@
|
||||
return
|
||||
|
||||
else if(mob.confused)
|
||||
step(mob, pick(cardinal))
|
||||
else
|
||||
. = ..()
|
||||
var/newdir = 0
|
||||
if(mob.confused > 40)
|
||||
newdir = pick(alldirs)
|
||||
else if(prob(mob.confused * 1.5))
|
||||
newdir = angle2dir(dir2angle(direct) + pick(90, -90))
|
||||
else if(prob(mob.confused * 3))
|
||||
newdir = angle2dir(dir2angle(direct) + pick(45, -45))
|
||||
if(newdir)
|
||||
direct = newdir
|
||||
n = get_step(mob, direct)
|
||||
|
||||
. = ..()
|
||||
mob.setDir(direct)
|
||||
|
||||
for(var/obj/item/grab/G in mob)
|
||||
if(G.state == GRAB_NECK)
|
||||
mob.setDir(reverse_dir[direct])
|
||||
mob.setDir(angle2dir((dir2angle(direct) + 202.5) % 365))
|
||||
G.adjust_position()
|
||||
for(var/obj/item/grab/G in mob.grabbed_by)
|
||||
G.adjust_position()
|
||||
|
||||
if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully
|
||||
delay = mob.movement_delay() * 2
|
||||
move_delay += delay
|
||||
moving = 0
|
||||
if(mob && .)
|
||||
if(mob.throwing)
|
||||
@@ -461,3 +381,123 @@
|
||||
|
||||
/mob/proc/update_gravity()
|
||||
return
|
||||
/client/proc/check_has_body_select()
|
||||
return mob && mob.hud_used && mob.zone_sel && istype(mob.zone_sel, /obj/screen/zone_sel)
|
||||
|
||||
/client/verb/body_toggle_head()
|
||||
set name = "body-toggle-head"
|
||||
set hidden = 1
|
||||
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/next_in_line
|
||||
switch(mob.zone_sel.selecting)
|
||||
if(BODY_ZONE_HEAD)
|
||||
next_in_line = BODY_ZONE_PRECISE_EYES
|
||||
if(BODY_ZONE_PRECISE_EYES)
|
||||
next_in_line = BODY_ZONE_PRECISE_MOUTH
|
||||
else
|
||||
next_in_line = BODY_ZONE_HEAD
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(next_in_line, mob)
|
||||
|
||||
/client/verb/body_r_arm()
|
||||
set name = "body-r-arm"
|
||||
set hidden = 1
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/next_in_line
|
||||
if(mob.zone_sel.selecting == BODY_ZONE_R_ARM)
|
||||
next_in_line = BODY_ZONE_PRECISE_R_HAND
|
||||
else
|
||||
next_in_line = BODY_ZONE_R_ARM
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(next_in_line, mob)
|
||||
|
||||
/client/verb/body_chest()
|
||||
set name = "body-chest"
|
||||
set hidden = 1
|
||||
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(BODY_ZONE_CHEST, mob)
|
||||
|
||||
/client/verb/body_l_arm()
|
||||
set name = "body-l-arm"
|
||||
set hidden = 1
|
||||
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/next_in_line
|
||||
if(mob.zone_sel.selecting == BODY_ZONE_L_ARM)
|
||||
next_in_line = BODY_ZONE_PRECISE_L_HAND
|
||||
else
|
||||
next_in_line = BODY_ZONE_L_ARM
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(next_in_line, mob)
|
||||
|
||||
/client/verb/body_r_leg()
|
||||
set name = "body-r-leg"
|
||||
set hidden = 1
|
||||
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/next_in_line
|
||||
if(mob.zone_sel.selecting == BODY_ZONE_R_LEG)
|
||||
next_in_line = BODY_ZONE_PRECISE_R_FOOT
|
||||
else
|
||||
next_in_line = BODY_ZONE_R_LEG
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(next_in_line, mob)
|
||||
|
||||
/client/verb/body_groin()
|
||||
set name = "body-groin"
|
||||
set hidden = 1
|
||||
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(BODY_ZONE_PRECISE_GROIN, mob)
|
||||
|
||||
/client/verb/body_l_leg()
|
||||
set name = "body-l-leg"
|
||||
set hidden = 1
|
||||
|
||||
if(!check_has_body_select())
|
||||
return
|
||||
|
||||
var/next_in_line
|
||||
if(mob.zone_sel.selecting == BODY_ZONE_L_LEG)
|
||||
next_in_line = BODY_ZONE_PRECISE_L_FOOT
|
||||
else
|
||||
next_in_line = BODY_ZONE_L_LEG
|
||||
|
||||
var/obj/screen/zone_sel/selector = mob.zone_sel
|
||||
selector.set_selected_zone(next_in_line, mob)
|
||||
|
||||
/client/verb/toggle_walk_run()
|
||||
set name = "toggle-walk-run"
|
||||
set hidden = TRUE
|
||||
set instant = TRUE
|
||||
if(mob)
|
||||
mob.toggle_move_intent(usr)
|
||||
|
||||
/mob/proc/toggle_move_intent(mob/user)
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
m_intent = MOVE_INTENT_WALK
|
||||
else
|
||||
m_intent = MOVE_INTENT_RUN
|
||||
if(hud_used && hud_used.static_inventory)
|
||||
for(var/obj/screen/mov_intent/selector in hud_used.static_inventory)
|
||||
selector.update_icon(src)
|
||||
|
||||
@@ -46,7 +46,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
|
||||
|
||||
// You aren't allowed to move.
|
||||
/obj/machinery/gravity_generator/Move()
|
||||
..()
|
||||
. = ..()
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/gravity_generator/proc/set_broken()
|
||||
|
||||
@@ -144,7 +144,7 @@ So, hopefully this is helpful if any more icons are to be added/changed/wonderin
|
||||
|
||||
|
||||
/obj/structure/particle_accelerator/Move()
|
||||
..()
|
||||
. = ..()
|
||||
if(master && master.active)
|
||||
master.toggle_power()
|
||||
investigate_log("was moved whilst active; it <font color='red'>powered down</font>.","singulo")
|
||||
|
||||
@@ -1037,7 +1037,7 @@ obj/spacepod/proc/add_equipment(mob/user, var/obj/item/spacepod_equipment/SPE, v
|
||||
return stop()
|
||||
|
||||
/obj/spacepod/relaymove(mob/user, direction)
|
||||
if(usr != src.pilot)
|
||||
if(user != src.pilot)
|
||||
return
|
||||
handlerelaymove(user, direction)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user