diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 8aab6175..8acc1d8f 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -185,6 +185,12 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
//We will round to this value in damage calculations.
#define DAMAGE_PRECISION 0.1
+//bullet_act() return values
+#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
+#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
+
//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25)
#define TOTAL_MASS_TINY_ITEM 1.25
#define TOTAL_MASS_SMALL_ITEM 2.5
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index 9ffd40b1..a2222fa2 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -461,3 +461,56 @@
//NC.mergeConnectedNetworksOnTurf()
last_piece = NC
return 1
+
+//Dunno where else to put this so shrug
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade
+ name = "Ripley MK-II Conversion Kit"
+ desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I mecha, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied."
+ icon_state = "ripleyupgrade"
+
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/mecha/working/ripley/M)
+ if(M.type != /obj/mecha/working/ripley)
+ to_chat(loc, "This conversion kit can only be applied to APLU MK-I models.")
+ return FALSE
+ if(M.cargo.len)
+ to_chat(loc, "[M]'s cargo hold must be empty before this conversion kit can be applied.")
+ return FALSE
+ if(!M.maint_access) //non-removable upgrade, so lets make sure the pilot or owner has their say.
+ to_chat(loc, "[M] must have maintenance protocols active in order to allow this conversion kit.")
+ return FALSE
+ if(M.occupant) //We're actualy making a new mech and swapping things over, it might get weird if players are involved
+ to_chat(loc, "[M] must be unoccupied before this conversion kit can be applied.")
+ return FALSE
+ if(!M.cell) //Turns out things break if the cell is missing
+ to_chat(loc, "The conversion process requires a cell installed.")
+ return FALSE
+ return TRUE
+
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/mecha/M)
+ var/obj/mecha/working/ripley/mkii/N = new /obj/mecha/working/ripley/mkii(get_turf(M),1)
+ if(!N)
+ return
+ QDEL_NULL(N.cell)
+ if (M.cell)
+ N.cell = M.cell
+ M.cell.forceMove(N)
+ M.cell = null
+ N.step_energy_drain = M.step_energy_drain //For the scanning module
+ N.armor = N.armor.setRating(energy = M.armor["energy"]) //for the capacitor
+ for(var/obj/item/mecha_parts/E in M.contents)
+// if(istype(E, /obj/item/mecha_parts/concealed_weapon_bay)) //why is the bay not just a variable change who did this
+// E.forceMove(N)
+ for(var/obj/item/mecha_parts/mecha_equipment/E in M.equipment) //Move the equipment over...
+ E.detach()
+ E.attach(N)
+ M.equipment -= E
+ N.dna_lock = M.dna_lock
+ N.maint_access = M.maint_access
+ N.strafe = M.strafe
+ N.obj_integrity = M.obj_integrity //This is not a repair tool
+ if (M.name != "\improper APLU MK-I \"Ripley\"")
+ N.name = M.name
+ M.wreckage = 0
+ qdel(M)
+ playsound(get_turf(N),'sound/items/ratchet.ogg',50,1)
+ return
\ No newline at end of file
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 2d182516..b357e96d 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -69,6 +69,12 @@
var/melee_cooldown = 10
var/melee_can_hit = 1
+ var/silicon_pilot = FALSE //set to true if an AI or MMI is piloting.
+
+ var/enter_delay = 40 //Time taken to enter the mech
+ var/enclosed = TRUE //Set to false for open-cockpit mechs
+ var/silicon_icon_state = null //if the mech has a different icon when piloted by an AI or MMI
+
//Action datums
var/datum/action/innate/mecha/mech_eject/eject_action = new
var/datum/action/innate/mecha/mech_toggle_internals/internals_action = new
@@ -116,7 +122,8 @@
icon_state += "-open"
add_radio()
add_cabin()
- add_airtank()
+ if (enclosed)
+ add_airtank()
spark_system.set_up(2, 0, src)
spark_system.attach(src)
smoke_system.set_up(3, src)
@@ -133,6 +140,11 @@
diag_hud_set_mechcell()
diag_hud_set_mechstat()
+/obj/mecha/update_icon()
+ if (silicon_pilot && silicon_icon_state)
+ icon_state = silicon_icon_state
+ . = ..()
+
/obj/mecha/get_cell()
return cell
@@ -273,6 +285,11 @@
to_chat(user, "It's equipped with:")
for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
to_chat(user, "[icon2html(ME, user)] \A [ME].")
+ if(!enclosed)
+ if(silicon_pilot)
+ to_chat(user, "[src] appears to be piloting itself...")
+ else if(occupant && occupant != user) //!silicon_pilot implied
+ to_chat(user, "You can see [occupant] inside.")
//processing internal damage, temperature, air regulation, alert updates, lights power use.
/obj/mecha/process()
@@ -392,13 +409,19 @@
diag_hud_set_mechcell()
diag_hud_set_mechstat()
+/obj/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech
+ if (occupant && !enclosed && !silicon_pilot)
+ if (occupant.fire_stacks < 5)
+ occupant.fire_stacks += 1
+ occupant.IgniteMob()
+
/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits.
return
/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
if(speaker == occupant)
- if(radio.broadcasting)
+ if(radio?.broadcasting)
radio.talk_into(speaker, text, , spans, message_language)
//flick speech bubble
var/list/speech_bubble_recipients = list()
@@ -474,7 +497,7 @@
. = ..()
if(.)
events.fireEvent("onMove",get_turf(src))
- if (internal_tank.disconnect()) // Something moved us and broke connection
+ if (internal_tank?.disconnect()) // Something moved us and broke connection
occupant_message("Air port connection teared off!")
log_message("Lost connection to gas port.")
@@ -500,7 +523,7 @@
user.forceMove(get_turf(src))
to_chat(user, "You climb out from [src].")
return 0
- if(internal_tank.connected_port)
+ if(internal_tank?.connected_port)
if(world.time - last_message > 20)
occupant_message("Unable to move while connected to the air system port!")
last_message = world.time
@@ -688,6 +711,7 @@
AI.disconnect_shell()
RemoveActions(AI, TRUE)
occupant = null
+ silicon_pilot = FALSE
AI.forceMove(card)
card.AI = AI
AI.controlled_mech = null
@@ -729,7 +753,9 @@
AI.ai_restore_power()
AI.forceMove(src)
occupant = AI
+ silicon_pilot = TRUE
icon_state = initial(icon_state)
+ update_icon()
playsound(src, 'sound/machines/windowdoor.ogg', 50, 1)
if(!internal_damage)
SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50))
@@ -832,7 +858,7 @@
visible_message("[user] starts to climb into [name].")
- if(do_after(user, 40, target = src))
+ if(do_after(user, enter_delay, target = src))
if(obj_integrity <= 0)
to_chat(user, "You cannot get in the [name], it has been destroyed!")
else if(occupant)
@@ -905,6 +931,7 @@
var/mob/living/brainmob = mmi_as_oc.brainmob
mmi_as_oc.mecha = src
occupant = brainmob
+ silicon_pilot = TRUE
brainmob.forceMove(src) //should allow relaymove
brainmob.reset_perspective(src)
brainmob.remote_control = src
@@ -946,6 +973,7 @@
RemoveActions(occupant)
occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced.
occupant = null
+ silicon_pilot = FALSE
return
else
if(!AI.linked_core)
@@ -963,6 +991,7 @@
return
var/mob/living/L = occupant
occupant = null //we need it null when forceMove calls Exited().
+ silicon_pilot = FALSE
if(mob_container.forceMove(newloc))//ejecting mob container
log_message("[mob_container] moved out.")
L << browse(null, "window=exosuit")
diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm
index 7b00e208..307e8d1b 100644
--- a/code/game/mecha/mecha_actions.dm
+++ b/code/game/mecha/mecha_actions.dm
@@ -3,7 +3,8 @@
/obj/mecha/proc/GrantActions(mob/living/user, human_occupant = 0)
if(human_occupant)
eject_action.Grant(user, src)
- internals_action.Grant(user, src)
+ if(enclosed)
+ internals_action.Grant(user, src)
cycle_action.Grant(user, src)
lights_action.Grant(user, src)
stats_action.Grant(user, src)
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 5b7becb5..0c87ca84 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -171,36 +171,29 @@
list(
"key" = TOOL_WRENCH,
"back_key" = TOOL_CROWBAR,
- "desc" = "Internal armor is installed."
+ "desc" = "Outer plating is installed."
),
//17
list(
"key" = TOOL_WELDER,
"back_key" = TOOL_WRENCH,
- "desc" = "Internal armor is wrenched."
+ "desc" = "Outer Plating is wrenched."
),
//18
list(
- "key" = /obj/item/stack/sheet/plasteel,
- "amount" = 5,
+ "key" = /obj/item/stack/rods,
+ "amount" = 10,
"back_key" = TOOL_WELDER,
- "desc" = "Internal armor is welded."
+ "desc" = "Outer Plating is welded."
),
//19
- list(
- "key" = TOOL_WRENCH,
- "back_key" = TOOL_CROWBAR,
- "desc" = "External armor is installed."
- ),
-
- //20
list(
"key" = TOOL_WELDER,
- "back_key" = TOOL_WRENCH,
- "desc" = "External armor is wrenched."
+ "back_key" = TOOL_WIRECUTTER,
+ "desc" = "Cockpit wire screen is installed."
),
)
diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm
index 0188419f..37395dd4 100644
--- a/code/game/mecha/mecha_control_console.dm
+++ b/code/game/mecha/mecha_control_console.dm
@@ -76,7 +76,7 @@
var/answer = {"Name: [M.name]
Integrity: [M.obj_integrity/M.max_integrity*100]%
Cell charge: [isnull(cell_charge)?"Not found":"[M.cell.percent()]%"]
-Airtank: [M.return_pressure()]kPa
+Airtank: [M.internal_tank?"[round(M.return_pressure(), 0.01)]":"Not Equipped"] kPa
Pilot: [M.occupant||"None"]
Location: [get_area(M)||"Unknown"]
Active equipment: [M.selected||"None"] "}
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index b7d59c6a..74981f35 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -114,6 +114,9 @@
/obj/mecha/bullet_act(obj/item/projectile/Proj) //wrapper
+ if (!enclosed && occupant && !silicon_pilot) //allows bullets to hit the pilot of open-canopy mechs
+ occupant.bullet_act(Proj) //If the sides are open, the occupant can be hit
+ return BULLET_ACT_HIT
log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).", color="red")
. = ..()
diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm
index 0bab48da..f087c67f 100644
--- a/code/game/mecha/mecha_topic.dm
+++ b/code/game/mecha/mecha_topic.dm
@@ -71,19 +71,24 @@
/obj/mecha/proc/get_stats_part()
var/integrity = obj_integrity/max_integrity*100
var/cell_charge = get_charge()
- var/datum/gas_mixture/int_tank_air = internal_tank.return_air()
- var/tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
- var/tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
- var/cabin_pressure = round(return_pressure(),0.01)
+ var/datum/gas_mixture/int_tank_air = 0
+ var/tank_pressure = 0
+ var/tank_temperature = 0
+ var/cabin_pressure = 0
+ if (internal_tank)
+ int_tank_air = internal_tank.return_air()
+ tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
+ tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
+ cabin_pressure = round(return_pressure(),0.01)
. = {"[report_internal_damage()]
[integrity<30?"DAMAGE LEVEL CRITICAL
":null]
Integrity: [integrity]%
Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
- Air source: [use_internal_tank?"Internal Airtank":"Environment"]
- Airtank pressure: [tank_pressure]kPa
- Airtank temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
- Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
+ Air source: [internal_tank?"[use_internal_tank?"Internal Airtank":"Environment"]":"Environment"]
+ Airtank pressure: [internal_tank?"[tank_pressure]kPa":"N/A"]
+ Airtank temperature: [internal_tank?"[tank_temperature]°K|[tank_temperature - T0C]°C":"N/A"]
+ Cabin pressure: [internal_tank?"[cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa":"N/A"]
+ Cabin temperature: [internal_tank?"[return_temperature()]°K|[return_temperature() - T0C]°C":"N/A"]
[dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":""]
[thrusters_action.owner ? "Thrusters: [thrusters_active ? "Enabled" : "Disabled"]
" : ""]
[defense_action.owner ? "Defence Mode: [defence_mode ? "Enabled" : "Disabled"]
" : ""]
@@ -100,14 +105,14 @@