Skip to content

Commit

Permalink
Xenothumbs Minor Event Button Comeback (#6034)
Browse files Browse the repository at this point in the history
# About the pull request
Working version that is TMable for april fools. 


Revived and fixed up
https://gitlab.com/cmdevs/colonial-warfare/-/merge_requests/1915/diffs#9ec310cca070259d82839a4a70e89dd858ded438_958_958

#2997

Additions from  Vanagandr's original MR
- xenos can use health items on marines
- vendors are usable now, all checks are simply skipped so introducing
xenos with thumbs to snowflake vendors is a horrible idea (as if
enabling this in the first place wasn't bad enough) [needs further
testing]
- xenos can drive
- M2C usable


I think this is pretty much done, it's already exceeding the scope of
the original and we're just making xenos human past this point

Original description
> TL;DR: https://streamable.com/rlvs86
> 
> Mainly this allows xenos to pick up items. They can then use most of
them.
> 
> Ex. a xeno can't flip a plasteel cade open - but if she has a toolbelt
and time to work, she can unwrench it.
> 
> They can fumble about but a lot of QoL and objects (middleclick
container open, click-dragging containers, tables, etc.) were never
designed to be interacted with by xenos so item interactions are a bit
clunky.
> 
> They can't strip clothing and gear from people.
> 
> They *can* strip and attach attachments but can't aim down scopes.
> 
> They *can* FF.
> 
> They *can't* use MGs.
> 
> IFF works, roughly, not picking up on specific hives but allowing them
to shoot past other xenos and hit humans.
> 
> They pass spec checks and can clumsily handle medic gear.
> 
> needless to say this is all colossally imbalanced and has potential
for fuckery limited only by the xeno's imagination and whether the thing
they're messing with makes an explicit ishuman() check. Or is a
structure. They can't hand-interact with structures, so they can shove
shells into a mortar but can't change its coords.
> 
> Cosmetically, gun inhands don't line up with xenos. Tweaked it a bit
to center it horizontally but lining inhands up with hands for every
xeno and xenonid sprite is a bit more hassle than seems worthwhile ATM.
> 
<!-- Remove this text and explain what the purpose of your PR is.

Mention if you have tested your changes. If you changed a map, make sure
you used the mapmerge tool.
If this is an Issue Correction, you can type "Fixes Issue #169420" to
link the PR to the corresponding Issue number #169420.

Remember: something that is self-evident to you might not be to others.
Explain your rationale fully, even if you feel it goes without saying.
-->

# Explain why it's good for the game
TM funny
# Testing Photographs and Procedure
<details>
<summary>Screenshots & Videos</summary>

Put screenshots and videos here with an empty line between the
screenshots and the `<details>` tags.

</details>


# Changelog
:cl:  Vanagandr, totalepicness
add: Added a button to event panel to give xenomorphs opposable thumbs
and firearms permits, to individuals, to hives, or to all xenos
everywhere. They're clumsy, though, and have issues with fine
manipulation sometimes. Remember that warriors cannot throw objects and
make for poor grenadiers.
add: Xenos with opposable thumbs can use buckles, drive vehicles, use
machine guns and vendors without care for access or skills
/:cl:

---------

Co-authored-by: Epicness <[email protected]>
Co-authored-by: harry <[email protected]>
  • Loading branch information
3 people authored Apr 6, 2024
1 parent 8b217b4 commit b190bea
Show file tree
Hide file tree
Showing 20 changed files with 199 additions and 82 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@
// HIVE TRAITS
/// If the Hive is a Xenonid Hive
#define TRAIT_XENONID "t_xenonid"
/// If the hive or xeno can use objects.
#define TRAIT_OPPOSABLE_THUMBS "t_thumbs"
/// If the Hive delays round end (this is overridden for some hives). Does not occur naturally. Must be applied in events.
#define TRAIT_NO_HIVE_DELAY "t_no_hive_delay"
/// If the Hive uses it's colors on the mobs. Does not occur naturally, excepting the Mutated hive.
Expand Down
8 changes: 4 additions & 4 deletions code/controllers/subsystem/minimap.dm
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ SUBSYSTEM_DEF(minimaps)
data["canDraw"] = FALSE
data["canViewTacmap"] = TRUE
data["canViewCanvas"] = FALSE
data["isXeno"] = FALSE
data["isxeno"] = FALSE

return data

Expand All @@ -781,7 +781,7 @@ SUBSYSTEM_DEF(minimaps)
var/is_xeno = istype(xeno)
var/faction = is_xeno ? xeno.hivenumber : user.faction

data["isXeno"] = is_xeno
data["isxeno"] = is_xeno
data["canViewTacmap"] = is_xeno
data["canViewCanvas"] = faction == FACTION_MARINE || faction == XENO_HIVE_NORMAL

Expand All @@ -799,7 +799,7 @@ SUBSYSTEM_DEF(minimaps)
data["canDraw"] = FALSE
data["canViewTacmap"] = FALSE
data["canViewCanvas"] = TRUE
data["isXeno"] = FALSE
data["isxeno"] = FALSE

return data

Expand All @@ -811,7 +811,7 @@ SUBSYSTEM_DEF(minimaps)
data["canDraw"] = FALSE
data["canViewTacmap"] = FALSE
data["canViewCanvas"] = TRUE
data["isXeno"] = TRUE
data["isxeno"] = TRUE

return data

Expand Down
2 changes: 2 additions & 0 deletions code/datums/action.dm
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@
var/mob/living/carbon/human/human = owner
if(human.body_position == STANDING_UP)
return TRUE
if((HAS_TRAIT(owner, TRAIT_OPPOSABLE_THUMBS)) && !owner.is_mob_incapacitated())
return TRUE

/datum/action/item_action/update_button_icon()
button.overlays.Cut()
Expand Down
4 changes: 4 additions & 0 deletions code/game/machinery/machinery.dm
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ Class Procs:
return TRUE
if(user.is_mob_incapacitated())
return TRUE
if(!(istype(user, /mob/living/carbon/human) || isRemoteControlling(user) || istype(user, /mob/living/carbon/xenomorph)))
if(!HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS))
to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!"))
return TRUE
if(!is_valid_user(user))
to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!"))
return TRUE
Expand Down
60 changes: 39 additions & 21 deletions code/game/machinery/vending/cm_vending.dm
Original file line number Diff line number Diff line change
Expand Up @@ -373,41 +373,49 @@ GLOBAL_LIST_EMPTY(vending_products)

//------------INTERACTION PROCS---------------

/obj/structure/machinery/cm_vending/attack_alien(mob/living/carbon/xenomorph/M)
/obj/structure/machinery/cm_vending/attack_alien(mob/living/carbon/xenomorph/user)
if(stat & TIPPED_OVER || indestructible)
to_chat(M, SPAN_WARNING("There's no reason to bother with that old piece of trash."))
to_chat(user, SPAN_WARNING("There's no reason to bother with that old piece of trash."))
return XENO_NO_DELAY_ACTION

if(M.a_intent == INTENT_HARM && !unslashable)
M.animation_attack_on(src)
if(prob(M.melee_damage_lower))
if(user.a_intent == INTENT_HARM && !unslashable)
user.animation_attack_on(src)
if(prob(user.melee_damage_lower))
playsound(loc, 'sound/effects/metalhit.ogg', 25, 1)
M.visible_message(SPAN_DANGER("[M] smashes [src] beyond recognition!"), \
user.visible_message(SPAN_DANGER("[user] smashes [src] beyond recognition!"), \
SPAN_DANGER("You enter a frenzy and smash [src] apart!"), null, 5, CHAT_TYPE_XENO_COMBAT)
malfunction()
tip_over()
else
M.visible_message(SPAN_DANGER("[M] slashes [src]!"), \
user.visible_message(SPAN_DANGER("[user] slashes [src]!"), \
SPAN_DANGER("You slash [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT)
playsound(loc, 'sound/effects/metalhit.ogg', 25, 1)
return XENO_ATTACK_ACTION

if(M.action_busy)
if(user.action_busy)
return XENO_NO_DELAY_ACTION

M.visible_message(SPAN_WARNING("[M] begins to lean against [src]."), \
if(user.a_intent == INTENT_HELP && user.IsAdvancedToolUser())
user.set_interaction(src)
tgui_interact(user)
if(!hacked)
to_chat(user, SPAN_WARNING("You slash open [src]'s front panel, revealing the items within."))
var/datum/effect_system/spark_spread/spark_system = new
spark_system.set_up(5, 5, get_turf(src))
hacked = TRUE
return XENO_ATTACK_ACTION
user.visible_message(SPAN_WARNING("[user] begins to lean against [src]."), \
SPAN_WARNING("You begin to lean against [src]."), null, 5, CHAT_TYPE_XENO_COMBAT)
var/shove_time = 80
if(M.mob_size >= MOB_SIZE_BIG)
if(user.mob_size >= MOB_SIZE_BIG)
shove_time = 30
if(istype(M,/mob/living/carbon/xenomorph/crusher))
if(istype(user,/mob/living/carbon/xenomorph/crusher))
shove_time = 15

xeno_attack_delay(M) //Adds delay here and returns nothing because otherwise it'd cause lag *after* finishing the shove.
xeno_attack_delay(user) //Adds delay here and returns nothing because otherwise it'd cause lag *after* finishing the shove.

if(do_after(M, shove_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE))
M.animation_attack_on(src)
M.visible_message(SPAN_DANGER("[M] knocks [src] down!"), \
if(do_after(user, shove_time, INTERRUPT_ALL, BUSY_ICON_HOSTILE))
user.animation_attack_on(src)
user.visible_message(SPAN_DANGER("[user] knocks [src] down!"), \
SPAN_DANGER("You knock [src] down!"), null, 5, CHAT_TYPE_XENO_COMBAT)
tip_over()
return XENO_NO_DELAY_ACTION
Expand Down Expand Up @@ -508,7 +516,12 @@ GLOBAL_LIST_EMPTY(vending_products)
if(.)
return

var/mob/living/carbon/human/user = usr
var/mob/living/carbon/human/human_user
var/mob/living/carbon/user = ui.user

if(ishuman(user))
human_user = usr

switch (action)
if ("vend")
if(stat & IN_USE)
Expand All @@ -528,8 +541,11 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(usr, SPAN_WARNING("The floor is too cluttered, make some space."))
vend_fail()
return FALSE

if((!user.assigned_squad && squad_tag) || (!user.assigned_squad?.omni_squad_vendor && (squad_tag && user.assigned_squad.name != squad_tag)))
if(HAS_TRAIT(user,TRAIT_OPPOSABLE_THUMBS)) // the big monster 7 ft with thumbs does not care for squads
vendor_successful_vend(itemspec, usr)
add_fingerprint(usr)
return TRUE
if((!human_user.assigned_squad && squad_tag) || (!human_user.assigned_squad?.omni_squad_vendor && (squad_tag && human_user.assigned_squad.name != squad_tag)))
to_chat(user, SPAN_WARNING("This machine isn't for your squad."))
vend_fail()
return FALSE
Expand All @@ -554,7 +570,7 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(user, SPAN_WARNING("That set is already taken."))
vend_fail()
return FALSE
var/obj/item/card/id/ID = user.wear_id
var/obj/item/card/id/ID = human_user.wear_id
if(!istype(ID) || !ID.check_biometrics(user))
to_chat(user, SPAN_WARNING("You must be wearing your [SPAN_INFO("dog tags")] to select a specialization!"))
return FALSE
Expand Down Expand Up @@ -584,7 +600,7 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(user, SPAN_WARNING("<b>Something bad occurred with [src], tell a Dev.</b>"))
vend_fail()
return FALSE
ID.set_assignment((user.assigned_squad ? (user.assigned_squad.name + " ") : "") + JOB_SQUAD_SPECIALIST + " ([specialist_assignment])")
ID.set_assignment((human_user.assigned_squad ? (human_user.assigned_squad.name + " ") : "") + JOB_SQUAD_SPECIALIST + " ([specialist_assignment])")
GLOB.data_core.manifest_modify(user.real_name, WEAKREF(user), ID.assignment)
GLOB.available_specialist_sets -= p_name
else if(vendor_role.Find(JOB_SYNTH))
Expand Down Expand Up @@ -777,6 +793,8 @@ GLOBAL_LIST_EMPTY(vending_products)
return listed_products

/obj/structure/machinery/cm_vending/proc/can_access_to_vend(mob/user, display = TRUE, ignore_hack = FALSE)
if(HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS)) // We're just going to skip the mess of access checks assuming xenos with thumbs are human and just allow them to access because it's funny
return TRUE
if(!hacked || ignore_hack)
if(!allowed(user))
if(display)
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/explosives/grenades/grenade.dm
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
to_chat(user, SPAN_WARNING("You don't have the dexterity to do this!"))
return FALSE

if(harmful && !user.allow_gun_usage)
if(harmful && ishuman(user) && !user.allow_gun_usage)
to_chat(user, SPAN_WARNING("Your programming prevents you from using this!"))
return FALSE

Expand Down
14 changes: 7 additions & 7 deletions code/game/objects/objs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@
if (!ismob(M) || (get_dist(src, user) > 1) || user.is_mob_restrained() || user.stat || buckled_mob || M.buckled || !isturf(user.loc))
return

if (isxeno(user))
if (isxeno(user) && !HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS))
to_chat(user, SPAN_WARNING("You don't have the dexterity to do that, try a nest."))
return
if (iszombie(user))
Expand All @@ -300,12 +300,12 @@
if(M.loc != src.loc)
return
. = buckle_mob(M)
if (M.mob_size <= MOB_SIZE_XENO && M.stat == DEAD && istype(src, /obj/structure/bed/roller))
do_buckle(M, user)
return
if (M.mob_size > MOB_SIZE_HUMAN)
to_chat(user, SPAN_WARNING("[M] is too big to buckle in."))
return
if (M.mob_size <= MOB_SIZE_XENO)
if ((M.stat == DEAD && istype(src, /obj/structure/bed/roller) || HAS_TRAIT(M, TRAIT_OPPOSABLE_THUMBS)))
do_buckle(M, user)
else if ((M.mob_size > MOB_SIZE_HUMAN))
to_chat(user, SPAN_WARNING("[M] is too big to buckle in."))
return
do_buckle(M, user)

// the actual buckling proc
Expand Down
1 change: 1 addition & 0 deletions code/modules/admin/tabs/event_tab.dm
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@
<A href='?src=\ref[src];[HrefToken()];events=nuke'>Spawn a nuke</A><BR>
<A href='?src=\ref[src];[HrefToken()];events=pmcguns'>Toggle PMC gun restrictions</A><BR>
<A href='?src=\ref[src];[HrefToken()];events=monkify'>Turn everyone into monkies</A><BR>
<A href='?src=\ref[src];[HrefToken()];events=xenothumbs'>Give or take opposable thumbs and gun permits from xenos</A><BR>
<BR>
"}

Expand Down
57 changes: 57 additions & 0 deletions code/modules/admin/topic/topic_events.dm
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,63 @@
message_admins("[key_name_admin(usr)] added [amount] research credits.")
GLOB.chemical_data.update_credits(amount)

if("xenothumbs")
var/grant = alert(usr, "Do you wish to grant or revoke Xenomorph firearms permits?", "Give or Take", "Grant", "Revoke", "Cancel")
if(grant == "Cancel")
return

var/list/mob/living/carbon/xenomorph/permit_recipients = list()
var/list/datum/hive_status/permit_hives = list()
switch(alert(usr, "Do you wish to do this for one Xeno or an entire hive?", "Recipients", "Xeno", "Hive", "All Xenos"))
if("Xeno")
permit_recipients += tgui_input_list(usr, "Select recipient Xenomorph:", "Armed Xenomorph", GLOB.living_xeno_list)
if(isnull(permit_recipients[1])) //Cancel button.
return
if("Hive")
permit_hives += GLOB.hive_datum[tgui_input_list(usr, "Select recipient hive:", "Armed Hive", GLOB.hive_datum)]
if(isnull(permit_hives[1])) //Cancel button.
return
permit_recipients = permit_hives[1].totalXenos.Copy()
if("All Xenos")
permit_recipients = GLOB.living_xeno_list.Copy()
for(var/H in GLOB.hive_datum)
permit_hives += GLOB.hive_datum[H]

var/list/handled_xenos = list()

for(var/mob/living/carbon/xenomorph/xeno as anything in permit_recipients)
if(QDELETED(xeno) || xeno.stat == DEAD) //Xenos might die before the admin picks them.
to_chat(usr, SPAN_HIGHDANGER("[xeno] died before her firearms permit could be issued!"))
continue
if(HAS_TRAIT(xeno, TRAIT_OPPOSABLE_THUMBS))
if(grant == "Revoke")
REMOVE_TRAIT(xeno, TRAIT_OPPOSABLE_THUMBS, TRAIT_SOURCE_HIVE)
to_chat(xeno, SPAN_XENOANNOUNCE("You forget how thumbs work. You feel a terrible sense of loss."))
handled_xenos += xeno
else if(grant == "Grant")
ADD_TRAIT(xeno, TRAIT_OPPOSABLE_THUMBS, TRAIT_SOURCE_HIVE)
to_chat(xeno, SPAN_XENOANNOUNCE("You suddenly comprehend the magic of opposable thumbs along with surprising kinesthetic intelligence. You could do... <b><i>so much</b></i> with this knowledge."))
handled_xenos += xeno

for(var/datum/hive_status/permit_hive as anything in permit_hives)
//Give or remove the trait from newly-born xenos in this hive.
if(grant == "Grant")
LAZYADD(permit_hive.hive_inherant_traits, TRAIT_OPPOSABLE_THUMBS)
else
LAZYREMOVE(permit_hive.hive_inherant_traits, TRAIT_OPPOSABLE_THUMBS)

if(!length(handled_xenos) && !length(permit_hives))
return

if(grant == "Grant")
message_admins("[usr] granted 2nd Amendment rights to [length(handled_xenos) > 1 ? "[length(handled_xenos)] xenos" : "[length(handled_xenos) == 1 ? "[handled_xenos[1]]" : "no xenos"]"]\
[length(permit_hives) > 1 ? " in all hives, and to any new xenos. Quite possibly we will all regret this." : "[length(permit_hives) == 1 ? " in [permit_hives[1]], and to any new xenos in that hive." : "."]"]")
else
message_admins("[usr] revoked 2nd Amendment rights from [length(handled_xenos) > 1 ? "[length(handled_xenos)] xenos" : "[length(handled_xenos) == 1 ? "[handled_xenos[1]]" : "no xenos"]"]\
[length(permit_hives) > 1 ? " in all hives, and from any new xenos." : "[length(permit_hives) == 1 ? " in [permit_hives[1]], and from any new xenos in that hive." : "."]"]")



/datum/admins/proc/create_humans_list(href_list)
if(SSticker?.current_state < GAME_STATE_PLAYING)
alert("Please wait until the game has started before spawning humans")
Expand Down
13 changes: 6 additions & 7 deletions code/modules/cm_marines/m2c.dm
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
icon_state = icon_name

/obj/item/device/m2c_gun/proc/check_can_setup(mob/user, turf/rotate_check, turf/open/OT, list/ACR)
if(!ishuman(user))
if(!ishuman(user) && !HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS))
return FALSE
if(broken_gun)
to_chat(user, SPAN_WARNING("You can't set up \the [src], it's completely broken!"))
Expand Down Expand Up @@ -148,7 +148,7 @@
HMG.try_mount_gun(user)

/obj/item/device/m2c_gun/attackby(obj/item/O as obj, mob/user as mob)
if(!ishuman(user))
if(!ishuman(user) && !HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS))
return

if(!iswelder(O) || user.action_busy)
Expand Down Expand Up @@ -330,7 +330,7 @@
update_icon()

/obj/structure/machinery/m56d_hmg/auto/attackby(obj/item/O as obj, mob/user as mob)
if(!ishuman(user))
if(!ishuman(user) && !HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS))
return
// RELOADING
if(istype(O, /obj/item/ammo_magazine/m2c))
Expand Down Expand Up @@ -456,13 +456,12 @@
// DISASSEMBLY

/obj/structure/machinery/m56d_hmg/auto/MouseDrop(over_object, src_location, over_location)
if(!ishuman(usr))
return
var/mob/living/carbon/human/user = usr
var/mob/living/carbon/user = usr
// If the user is unconscious or dead.
if(user.stat)
return

if(!ishuman(user) && !HAS_TRAIT(user, TRAIT_OPPOSABLE_THUMBS))
return
if(over_object == user && in_range(src, user))
if((rounds > 0) && (user.a_intent & (INTENT_GRAB)))
playsound(src.loc, 'sound/items/m56dauto_load.ogg', 75, 1)
Expand Down
Loading

0 comments on commit b190bea

Please sign in to comment.