Lleill Species - Part 2 (#16127)

* [WIP] Lleill Species - Part 2

This PR is primarily to bring the lleill species to a point where players could reasonably request to play as them, having some semblance.

* Major update

Includes breathing changes to the Lleill, Two new glamour items to spawn (a flavoured nudity permit and a gasmask that supplies infinite air for outdoor gimmicks), 2 new tails, 2 new ears and a bunch of fixes.

* Added alchemy ability
This commit is contained in:
SatinIsle
2024-07-28 06:14:47 +10:00
committed by GitHub
parent 6e9278ca01
commit bc87e5204a
15 changed files with 354 additions and 18 deletions
@@ -161,3 +161,5 @@
// Custom Species Name
var/custom_species
var/block_hud
+16 -1
View File
@@ -537,6 +537,11 @@
suiciding--
return 0
if(wear_mask && (wear_mask.item_flags & INFINITE_AIR))
failed_last_breath = 0
adjustOxyLoss(-5)
return
if(does_not_breathe)
failed_last_breath = 0
adjustOxyLoss(-5)
@@ -1972,6 +1977,8 @@
holder.icon_state = "-100" // X_X
else
holder.icon_state = RoundHealth((health-config.health_threshold_crit)/(getMaxHealth()-config.health_threshold_crit)*100)
if(block_hud)
holder.icon_state = "hudblank"
apply_hud(HEALTH_HUD, holder)
if (BITTEST(hud_updateflag, LIFE_HUD))
@@ -1982,6 +1989,8 @@
holder.icon_state = "huddead"
else
holder.icon_state = "hudhealthy"
if(block_hud)
holder.icon_state = "hudblank"
apply_hud(LIFE_HUD, holder)
if (BITTEST(hud_updateflag, STATUS_HUD))
@@ -2013,6 +2022,9 @@
holder2.icon_state = "hudill"
else
holder2.icon_state = "hudhealthy"
if(block_hud)
holder.icon_state = "hudblank"
holder2.icon_state = "hudblank"
apply_hud(STATUS_HUD, holder)
apply_hud(STATUS_HUD_OOC, holder2)
@@ -2028,6 +2040,8 @@
else
holder.icon_state = "hudunknown"
if(block_hud)
holder.icon_state = "hudblank"
apply_hud(ID_HUD, holder)
if (BITTEST(hud_updateflag, WANTED_HUD))
@@ -2054,7 +2068,8 @@
else if((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "Released"))
holder.icon_state = "hudreleased"
break
if(block_hud)
holder.icon_state = "hudblank"
apply_hud(WANTED_HUD, holder)
if ( BITTEST(hud_updateflag, IMPLOYAL_HUD) \
@@ -21,6 +21,8 @@
var/image/other_status = hud_list[STATUS_HUD]
var/image/status_r = grab_hud(STATUS_R_HUD)
status_r.icon_state = other_status.icon_state
if(block_hud)
status_r.icon_state = "hudblank"
apply_hud(STATUS_R_HUD, status_r)
//Our custom health bar HUD
@@ -28,6 +30,8 @@
var/image/other_health = hud_list[HEALTH_HUD]
var/image/health_us = grab_hud(HEALTH_VR_HUD)
health_us.icon_state = other_health.icon_state
if(block_hud)
health_us.icon_state = "hudblank"
apply_hud(HEALTH_VR_HUD, health_us)
//Backup implant hud status
@@ -46,7 +50,8 @@
holder.icon_state = "hud_backup_nobody"
else
holder.icon_state = "hud_backup_norm"
if(block_hud)
holder.icon_state = "hudblank"
apply_hud(BACKUP_HUD, holder)
//VOREStation Antag Hud
@@ -56,6 +61,8 @@
vantag.icon_state = vantag_pref
else
vantag.icon_state = "hudblank"
if(block_hud)
vantag.icon_state = "hudblank"
apply_hud(VANTAG_HUD, vantag)
//Our call for the NIF to do whatever
@@ -33,6 +33,11 @@
//Specific abilities
var/lleill_energy = 200
var/lleill_energy_max = 200
var/ring_cooldown = 0
darksight = 10 //Can see in dark
burn_mod = 0.25 //Very resistant to fire
@@ -43,6 +48,8 @@
warning_high_pressure = 300
hazard_high_pressure = 10000 //Can be killed by pressure but you're going to need a hell of a lot
minimum_breath_pressure = 0 //Doesn't gasp and lungs shouldn't pop
cold_level_1 = -1 //Safe in space
cold_level_2 = -1
cold_level_3 = -1
@@ -81,7 +88,9 @@
/mob/living/proc/set_size,
/mob/living/carbon/human/proc/lleill_invisibility,
/mob/living/carbon/human/proc/lleill_transmute,
/mob/living/carbon/human/proc/lleill_rings)
/mob/living/carbon/human/proc/lleill_rings,
/mob/living/carbon/human/proc/lleill_contact,
/mob/living/carbon/human/proc/lleill_alchemy)
//organs, going with just the basics for now
@@ -9,19 +9,35 @@
verbpath = /mob/living/carbon/human/proc/lleill_invisibility
/mob/living/carbon/human/proc/lleill_invisibility()
set name = "Invisibility"
set name = "Invisibility (75)"
set desc = "Change your appearance to match your surroundings, becoming completely invisible to the naked eye."
set category = "Abilities"
var/energy_cost = 75
var/datum/species/lleill/LL = species
if(!istype(LL))
to_chat(src, "<span class='warning'>Only a lleill can use that!</span>")
return
if(stat)
to_chat(src, "<span class='warning'>You can't go invisible when weakened like this.</span>")
return
if(!cloaked)
if(LL.lleill_energy < energy_cost)
to_chat(src, "<span class='warning'>You do not have enough energy to do that!</span>")
return
cloak()
block_hud = 1
hud_updateflag = 1
to_chat(src, "<span class='warning'>Your fur shimmers and shifts around you, hiding you from the naked eye.</span>")
LL.lleill_energy -= energy_cost
else
uncloak()
block_hud = 0
hud_updateflag = 1
to_chat(src, "<span class='warning'>The brustling of your fur settles down and you become visible once again.</span>")
/mob/living/carbon/human/proc/lleill_select_shape()
@@ -81,20 +97,34 @@
regenerate_icons()
/mob/living/carbon/human/proc/lleill_transmute()
set name = "Transmute Object"
set name = "Transmute Object (50)"
set desc = "Convert an object into a piece of glamour."
set category = "Abilities"
var/list/transmute_list = list(
/obj/item/weapon/potion_material/glamour_transparent,
/obj/item/weapon/potion_material/glamour_shrinking,
/obj/item/weapon/potion_material/glamour_twinkling,
/obj/item/weapon/potion_material/glamour_shard,
/obj/item/capture_crystal/glamour,
/obj/item/glamour_face,
/obj/item/device/universal_translator/glamour
"Transparent Glamour" = /obj/item/weapon/potion_material/glamour_transparent,
"Shrinking Glamour" = /obj/item/weapon/potion_material/glamour_shrinking,
"Twinkling Glamour" = /obj/item/weapon/potion_material/glamour_twinkling,
"Glamour Shard" = /obj/item/weapon/potion_material/glamour_shard,
"Glamour Cell" = /obj/item/capture_crystal/glamour,
"Face of Glamour" = /obj/item/glamour_face,
"Speaking Glamour" = /obj/item/device/universal_translator/glamour,
"Glamour Bubble" = /obj/item/clothing/mask/gas/glamour,
"Pocket of Glamour" = /obj/item/clothing/under/permit/glamour
)
var/energy_cost = 50
var/datum/species/lleill/LL = species
if(!istype(LL))
to_chat(src, "<span class='warning'>Only a lleill can use that!</span>")
return
if(LL.lleill_energy < energy_cost)
to_chat(src, "<span class='warning'>You do not have enough energy to do that!</span>")
return
if(stat)
to_chat(src, "<span class='warning'>You can't go do that when weakened like this.</span>")
return
@@ -104,7 +134,13 @@
to_chat(src, "<span class='warning'>You have no item in your active hand.</span>")
return
var/obj/item/transmute_product = tgui_input_list(src, "Choose an glamour to transmute the item into:", "Transmutation", transmute_list)
var/choice = tgui_input_list(src, "Choose a glamour to transmute the item into:", "Transmutation", transmute_list)
if(!choice)
return
var/obj/item/transmute_product = transmute_list[choice]
if(!get_active_hand(I))
to_chat(src, "<span class='warning'>The item is no longer in your hands.</span>")
return
@@ -113,36 +149,54 @@
if(!do_after(usr, 10 SECONDS, I, exclusive = TASK_USER_EXCLUSIVE))
visible_message("<b>\The [src]</b> leaves \the [I] in its original form.")
return 0
visible_message("<b>\The [src]</b> transmutes \the [I] into a \the [transmute_product.name].")
visible_message("<b>\The [src]</b> transmutes \the [I] into \the [transmute_product.name].")
drop_item(I)
qdel(I)
var/spawnloc = get_turf(usr)
var/obj/item/N = new transmute_product(spawnloc)
put_in_active_hand(N)
LL.lleill_energy -= energy_cost
/mob/living/carbon/human/proc/lleill_rings()
set name = "Place/Use Rings"
set desc = "Place or teleport to a glamour ring."
set category = "Abilities"
var/energy_cost_multi = src.teleporters.len
var/energy_cost_spawn = (25 * energy_cost_multi)
var/energy_cost_tele = 50
var/datum/species/lleill/LL = species
if(!istype(LL))
to_chat(src, "<span class='warning'>Only a lleill can use that!</span>")
return
if(stat)
to_chat(src, "<span class='warning'>You can't go do that when weakened like this.</span>")
return
if(buckled)
to_chat(src,"<span class='warning'>You can't do that when restrained.</span>")
var/r_action = tgui_alert(src, "What would you like to do with your rings?", "Actions", list("Spawn New Ring", "Teleport to Ring", "Cancel"))
var/r_action = tgui_alert(src, "What would you like to do with your rings? You currently have [LL.lleill_energy] energy remaining.", "Actions", list("Spawn New Ring ([energy_cost_spawn])", "Teleport to Ring ([energy_cost_tele])", "Cancel"))
if(r_action == "Cancel")
return
if(r_action == "Spawn New Ring")
if(findtext(r_action,"Spawn New Ring"))
if(LL.lleill_energy < energy_cost_spawn)
to_chat(src, "<span class='warning'>You do not have enough energy to do that!</span>")
return
if(!do_after(src, 10 SECONDS, src, exclusive = TASK_USER_EXCLUSIVE))
src.visible_message("<b>\The [src]</b> begins to form white rings on the ground.")
return 0
to_chat(src, "<span class='warning'>You place a new glamour ring at your feet.</span>")
var/spawnloc = get_turf(src)
var/obj/structure/glamour_ring/R = new(spawnloc)
R.connected_mob = src
src.teleporters |= R
if(r_action == "Teleport to Ring")
LL.lleill_energy -= energy_cost_spawn
if(findtext(r_action,"Teleport to Ring"))
if(LL.lleill_energy < energy_cost_tele)
to_chat(src, "<span class='warning'>You do not have enough energy to do that!</span>")
return
if(!src.teleporters.len)
to_chat(src, "<span class='warning'>You need to place rings to teleport to them.</span>")
return
@@ -160,6 +214,7 @@
var/S = get_turf(R)
src.forceMove(S)
LL.lleill_energy -= energy_cost_tele
spk.start()
playsound(S, 'sound/effects/phasein.ogg', 25, 1)
@@ -177,3 +232,139 @@
M.forceMove(vore_selected)
to_chat(M,"<span class='vwarning'>In a bright flash of white light, you suddenly find yourself trapped in \the [src]'s [vore_selected.name]!</span>")
/mob/living/carbon/human/proc/lleill_contact()
set name = "Energy Transfer"
set desc = "Take the energy of another creature by making physical contact with them, the other party must consent. This will make them feel drained."
set category = "Abilities"
if(!ishuman(src))
return //If you're not a human you don't have permission to do this.
var/datum/species/lleill/LL = species
var/list/contact_options = list(
"Kiss (lips)",
"Kiss (neck)",
"Bite (neck)",
"Bite (wrist)",
"Hold Hand",
"Embrace",
"Boop (nose)",
"Stroke (hair)",
"Custom"
)
if(!istype(LL))
to_chat(src, "<span class='warning'>Only a lleill can use that!</span>")
return
if(stat)
to_chat(src, "<span class='warning'>You can't go do that when weakened like this.</span>")
return
var/list/targets = list()
for(var/mob/living/carbon/human/M in mob_list)
if(M.z != src.z || get_dist(src,M) > 1)
continue
if(src == M)
continue
targets |= M
if(!targets)
to_chat(src, "<span class='warning'>There is nobody next to you.</span>")
return
var/mob/living/carbon/human/chosen_target = tgui_input_list(src, "Who do you wish to take energy from?", "Make contact", targets)
if(!chosen_target)
return
var/contact_type = tgui_input_list(src, "How do you wish to make contact with \the [chosen_target]?", "Contact type", contact_options)
if(!contact_type)
return
var/custom_text
if(contact_type == "Custom")
custom_text = tgui_input_text(src, "Write a description of how you make contact with \the [chosen_target], from a third person perspective.", "Custom contact")
var/accepted = tgui_alert(chosen_target, "Do you accept the [contact_type] physical contact from \the [src]?", "Actions", list("Yes", "No"))
if(get_dist(src,chosen_target) > 1)
to_chat(src, "<span class='warning'>You need to be standing next to [chosen_target].</span>")
return
if(accepted == "No")
to_chat(src, "<span class='warning'>\The [chosen_target] refuses the contact.</span>")
return
if(accepted == "Yes")
if(contact_type == "Kiss (lips)")
src.visible_message("<b>\The [src]</b> presses their lips up against [chosen_target]'s own.")
if(contact_type == "Kiss (neck)")
src.visible_message("<b>\The [src]</b> presses their lips up against [chosen_target]'s neck.")
if(contact_type == "Bite (neck)")
src.visible_message("<b>\The [src]</b> bites down on [chosen_target]'s neck.")
if(contact_type == "Bite (wrist)")
src.visible_message("<b>\The [src]</b> bites down on [chosen_target]'s wrist.")
if(contact_type == "Hold Hand")
src.visible_message("<b>\The [src]</b> takes [chosen_target]'s hand into their own.")
if(contact_type == "Embrace")
src.visible_message("<b>\The [src]</b> embraces [chosen_target].")
if(contact_type == "Stroke (hair)")
src.visible_message("<b>\The [src]</b> runs their hand through [chosen_target]'s hair.")
if(contact_type == "Boop (nose)")
src.visible_message("<b>\The [src]</b> boops [chosen_target] on the nose.")
if(contact_type == "Custom")
src.visible_message("[custom_text]")
if(!do_after(src, 10 SECONDS, chosen_target, exclusive = TASK_USER_EXCLUSIVE))
return
else
src.visible_message("<b>\The [src]</b> and \the [chosen_target] break contact before energy has been transferred.")
src.visible_message("<b>\The [src]</b> and \the [chosen_target] complete their contact.")
LL.lleill_energy = LL.lleill_energy_max
nutrition += (chosen_target.nutrition / 2)
to_chat(src, "<span class='warning'>You feel revitalised.</span>")
chosen_target.tiredness += 70
chosen_target.nutrition = max((chosen_target.nutrition / 2),75)
chosen_target.remove_blood(40) //removes enough blood to make them feel a bit woozy, mostly just for flavour
chosen_target.eye_blurry += 20
to_chat(chosen_target, "<span class='warning'>You feel considerably weakened for the moment.</span>")
/mob/living/carbon/human/proc/lleill_alchemy()
set name = "Alchemy (25)"
set desc = "Convert a potion material into a potion without the use of a base or alembic."
set category = "Abilities"
var/energy_cost = 25
var/datum/species/lleill/LL = species
if(!istype(LL))
to_chat(src, "<span class='warning'>Only a lleill can use that!</span>")
return
if(LL.lleill_energy < energy_cost)
to_chat(src, "<span class='warning'>You do not have enough energy to do that!</span>")
return
if(stat)
to_chat(src, "<span class='warning'>You can't go do that when weakened like this.</span>")
return
var/obj/item/weapon/potion_material/I = get_active_hand()
if(!I)
to_chat(src, "<span class='warning'>You have no item in your active hand.</span>")
return
if(!istype(I))
to_chat(src, "<span class='warning'>\The [I] is not a potion material.</span>")
return
var/obj/item/weapon/reagent_containers/glass/bottle/potion/transmute_product = I.product_potion
if(!get_active_hand(I))
to_chat(src, "<span class='warning'>The item is no longer in your hands.</span>")
return
else
visible_message("<b>\The [src]</b> begins to change the form of \the [I].")
if(!do_after(usr, 10 SECONDS, I, exclusive = TASK_USER_EXCLUSIVE))
visible_message("<b>\The [src]</b> leaves \the [I] in its original form.")
return 0
visible_message("<b>\The [src]</b> transmutes \the [I] into \the [transmute_product.name].")
drop_item(I)
qdel(I)
var/spawnloc = get_turf(usr)
var/obj/item/N = new transmute_product(spawnloc)
put_in_active_hand(N)
LL.lleill_energy -= energy_cost
@@ -139,6 +139,8 @@
return
var/mob/living/carbon/human/chosen_target = tgui_input_list(user, "Which target do you wish to create a homunculus of?", "homunculus", targets)
if(!chosen_target)
return
var/spawnloc = get_turf(user)
var/mob/living/simple_mob/homunculus/H = new(spawnloc)
@@ -175,6 +177,43 @@
icon = 'icons/obj/glamour.dmi'
icon_state = "translator"
/obj/item/device/universal_translator/glamour/hear_talk(mob/M, list/message_pieces, verb)
if(!listening || !istype(M))
return
//Show the "I heard something" animation.
if(mult_icons)
flick("[initial(icon_state)]2",src)
//Handheld or pocket only.
if(!isliving(loc))
return
var/mob/living/L = loc
if(visual && ((L.sdisabilities & BLIND) || L.eye_blind))
return
if(audio && ((L.sdisabilities & DEAF) || L.ear_deaf))
return
// Using two for loops kinda sucks, but I think it's more efficient
// to shortcut past string building if we're just going to discard the string
// anyways.
if(user_understands(M, L, message_pieces))
return
var/new_message = ""
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking.flags & NONVERBAL)
continue
new_message += (S.message + " ")
if(!L.say_understands(null, langset))
new_message = langset.scramble(new_message)
to_chat(L, "<span class='filter_say'><i><b>[src]</b> translates, </i>\"<span class='[langset.colour]'>[new_message]</span>\"</span>")
//Teleporter ring
/obj/structure/glamour_ring
@@ -194,5 +233,58 @@
area_name = A.name
name = "[area_name] glamour ring"
/obj/structure/glamour_ring/attack_hand(mob/living/M as mob)
var/mob/living/carbon/human/L = connected_mob
var/datum/species/lleill/LL = L.species
var/m_action
if(M == L)
m_action= tgui_alert(M, "Do you want to destroy the ring, or restore energy?", "Destroy ring", list("Yes", "No", "Restore Energy"))
else
m_action= tgui_alert(M, "Do you want to destroy the ring, the owner of it may be aware that you have done this?", "Destroy ring", list("Yes", "No"))
if(m_action == "No")
return
if(m_action == "Yes")
to_chat(M, "<span class='warning'>You begin to break the lines of the glamour ring.</span>")
if(!do_after(M, 10 SECONDS, src, exclusive = TASK_USER_EXCLUSIVE))
to_chat(M, "<span class='warning'>You leave the glamour ring alone.</span>")
return
to_chat(M, "<span class='warning'>You have destroyed \the [src].</span>")
src.visible_message("<b>\The [M]</b> has broken apart \the [src].")
if(M != connected_mob && connected_mob)
to_chat(connected_mob, "<span class='warning'>\The [src] has been destroyed by \the [M].</span>")
if(istype(LL))
L.teleporters -= src
qdel(src)
if(m_action == "Restore Energy")
if(LL.ring_cooldown + 10 MINUTES > world.time)
to_chat(M, "<span class='warning'>You must wait a while before drawing energy from the glamour again.</span>")
return
if(!do_after(M, 10 SECONDS, src, exclusive = TASK_USER_EXCLUSIVE))
to_chat(M, "<span class='warning'>You stop drawing energy.</span>")
return
LL.lleill_energy = min((LL.lleill_energy + 75),LL.lleill_energy_max)
//Glamour Helm
/obj/item/clothing/mask/gas/glamour
desc = "A bubble-like helmet of glamour that can protect your face from the atmosphere, or lack thereof, outside."
name = "glamour bubble"
icon = 'icons/obj/glamour.dmi'
icon_state = "bubble"
item_flags = BLOCK_GAS_SMOKE_EFFECT | AIRTIGHT | ALLOW_SURVIVALFOOD | INFINITE_AIR
//Glamour Pockets
/obj/item/clothing/under/permit/glamour
name = "pocket of glamour"
desc = "A small crystal of glamour that is capable of storing small items inside of it."
icon = 'icons/obj/glamour.dmi'
icon_state = "pocket"
//Glamour Floor
//Glamour Wall
@@ -40,6 +40,15 @@
extra_overlay = "lleill-antlers"
species_allowed = list(SPECIES_LLEILL)
/datum/sprite_accessory/ears/lleill/curled
name = "Lleill Ears Curled, colorable"
icon_state = "lleill2"
extra_overlay = "lleill2-antlers"
/datum/sprite_accessory/ears/lleill/tall
name = "Lleill Ears Tall, colorable"
icon_state = "lleill3"
extra_overlay = "lleill3-antlers"
// Ears avaliable to anyone
@@ -1067,3 +1067,13 @@
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "tail_marking"
/datum/sprite_accessory/tail/lleill/large
name = "Lleill tail, Large"
icon_state = "tail2"
extra_overlay = "tail2_marking"
/datum/sprite_accessory/tail/lleill/small
name = "Lleill tail, Small"
icon_state = "tail3"
extra_overlay = "tail3_marking"