Merge conflict begone

This commit is contained in:
LemonInTheDark
2020-07-12 17:37:14 -07:00
186 changed files with 4969 additions and 3766 deletions
+4
View File
@@ -102,6 +102,10 @@
step_towards(M,src)
for(var/obj/O in range(0,src))
if(!O.anchored)
if(isturf(O.loc))
var/turf/T = O.loc
if(T.intact && HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
continue
var/mob/living/target = locate() in view(4,src)
if(target && !target.stat)
O.throw_at(target, 5, 10)
+1 -1
View File
@@ -164,7 +164,7 @@
return
to_chat(user, "<span class='notice'>The poster falls down!</span>")
D.roll_and_drop(temp_loc)
D.roll_and_drop(get_turf(user))
// Various possible posters follow
@@ -141,6 +141,10 @@
for(var/obj/O in range(0,src))
if(O.type == src.type)
continue
if(isturf(O.loc))
var/turf/T = O.loc
if(T.intact && HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
continue
if(lifetime % reagent_divisor)
reagents.expose(O, VAPOR, fraction)
var/hit = 0
@@ -232,6 +232,8 @@
for(var/atom/movable/AM in T)
if(AM.type == src.type)
continue
if(T.intact && HAS_TRAIT(AM, TRAIT_T_RAY_VISIBLE))
continue
reagents.expose(AM, TOUCH, fraction)
reagents.expose(T, TOUCH, fraction)
+2 -5
View File
@@ -45,11 +45,6 @@
. = ..()
. += "This is a [generation]\th generation [name]!"
/obj/structure/glowshroom/Destroy()
if(myseed)
QDEL_NULL(myseed)
return ..()
/**
* Creates a new glowshroom structure.
*
@@ -142,6 +137,8 @@
continue
Decay(TRUE, 2) // Decay before spawning new mushrooms to reduce their endurance
if(QDELETED(src)) //Decay can end us
return
var/obj/structure/glowshroom/child = new type(newLoc, myseed, TRUE, TRUE)
child.generation = generation + 1
shrooms_planted++
-2
View File
@@ -154,8 +154,6 @@
return FALSE
if(!force && (!ismecha(M) && !istype(M, /obj/projectile) && M.anchored && !allow_anchored))
return
if(ismegafauna(M))
message_admins("[M] has used a portal at [ADMIN_VERBOSEJMP(src)] made by [usr].")
var/no_effect = FALSE
if(last_effect == world.time)
no_effect = TRUE
-7
View File
@@ -45,10 +45,6 @@
w_class = WEIGHT_CLASS_SMALL
item_flags = NO_MAT_REDEMPTION
/obj/item/bodybag/bluespace/Initialize()
. = ..()
RegisterSignal(src, COMSIG_ATOM_CANREACH, .proc/CanReachReact)
/obj/item/bodybag/bluespace/examine(mob/user)
. = ..()
if(contents.len)
@@ -62,9 +58,6 @@
to_chat(A, "<span class='notice'>You suddenly feel the space around you torn apart! You're free!</span>")
return ..()
/obj/item/bodybag/bluespace/proc/CanReachReact(atom/movable/source, list/next)
return COMPONENT_BLOCK_REACH
/obj/item/bodybag/bluespace/deploy_bodybag(mob/user, atom/location)
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
for(var/atom/movable/A in contents)
@@ -15,7 +15,7 @@
var/energy = 10
var/max_energy = 10
var/effectchance = 30
var/recharging = 0
var/recharging = FALSE
var/recharge_locked = FALSE
var/obj/item/stock_parts/micro_laser/diode //used for upgrading!
@@ -178,7 +178,7 @@
energy -= 1
if(energy <= max_energy)
if(!recharging)
recharging = 1
recharging = TRUE
START_PROCESSING(SSobj, src)
if(energy <= 0)
to_chat(user, "<span class='warning'>[src]'s battery is overused, it needs time to recharge!</span>")
@@ -188,10 +188,13 @@
icon_state = "pointer"
/obj/item/laser_pointer/process()
if(!diode)
recharging = FALSE
return PROCESS_KILL
if(prob(20 + diode.rating*20 - recharge_locked*2)) //t1 is 20, 2 40
energy += 1
if(energy >= max_energy)
energy = max_energy
recharging = 0
recharging = FALSE
recharge_locked = FALSE
..()
return ..()
@@ -3,6 +3,7 @@
desc = "A portable device that dispenses and mixes chemicals. Requires a vortex anomaly core. All necessary reagents need to be supplied with beakers. A label indicates that a screwdriver is required to open it for refills. This device can be worn on a belt. The letters 'S&T' are imprinted on the side."
icon = 'icons/obj/chemical.dmi'
icon_state = "portablechemicalmixer_open"
worn_icon_state = "portable_chem_mixer"
w_class = WEIGHT_CLASS_HUGE
slot_flags = ITEM_SLOT_BELT
equip_sound = 'sound/items/equip/toolbelt_equip.ogg'
+1 -2
View File
@@ -67,8 +67,7 @@ GENE SCANNER
return
var/list/t_ray_images = list()
for(var/obj/O in orange(distance, viewer) )
if(O.invisibility == INVISIBILITY_MAXIMUM || HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
if(HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
var/image/I = new(loc = get_turf(O))
var/mutable_appearance/MA = new(O)
MA.alpha = 128
+1 -1
View File
@@ -61,7 +61,7 @@
msg = "You hear something crackle in your ears for a moment before a voice speaks. \"Please stand by for a message from Central Command. Message as follows: <span class='bold'>Item request received. Your package is inbound, please stand back from the landing site.</span> Message ends.\""
to_chat(M, msg)
new /obj/effect/dp_target(get_turf(src), pod)
new /obj/effect/pod_landingzone(get_turf(src), pod)
/obj/item/choice_beacon/hero
name = "heroic beacon"
+11
View File
@@ -275,6 +275,17 @@
qdel(I)
//BubbleWrap END
/obj/item/stack/vv_edit_var(vname, vval)
if(vname == NAMEOF(src, amount))
add(clamp(vval, 1-amount, max_amount - amount)) //there must always be one.
return TRUE
else if(vname == NAMEOF(src, max_amount))
max_amount = max(vval, 1)
add((max_amount < amount) ? (max_amount - amount) : 0) //update icon, weight, ect
return TRUE
return ..()
/obj/item/stack/proc/building_checks(datum/stack_recipe/R, multiplier)
if (get_amount() < R.req_amount*multiplier)
if (R.req_amount*multiplier>1)
+7
View File
@@ -102,6 +102,7 @@
desc = "This little bugger can be used to store and transport ores."
icon = 'icons/obj/mining.dmi'
icon_state = "satchel"
worn_icon_state = "satchel"
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKETS
w_class = WEIGHT_CLASS_NORMAL
component_type = /datum/component/storage/concrete/stack
@@ -188,6 +189,7 @@
name = "plant bag"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "plantbag"
worn_icon_state = "plantbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/plants/ComponentInitialize()
@@ -230,6 +232,7 @@
desc = "A patented Nanotrasen storage system designed for any kind of mineral sheet."
icon = 'icons/obj/mining.dmi'
icon_state = "sheetsnatcher"
worn_icon_state = "satchel"
var/capacity = 300; //the number of sheets it can carry.
component_type = /datum/component/storage/concrete/stack
@@ -271,6 +274,7 @@
desc = "A bag for books."
icon = 'icons/obj/library.dmi'
icon_state = "bookbag"
worn_icon_state = "bookbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/books/ComponentInitialize()
@@ -361,6 +365,7 @@
name = "chemistry bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "bag"
worn_icon_state = "chembag"
desc = "A bag for storing pills, patches, and bottles."
resistance_flags = FLAMMABLE
@@ -389,6 +394,7 @@
name = "bio bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "biobag"
worn_icon_state = "biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
resistance_flags = FLAMMABLE
@@ -420,6 +426,7 @@
name = "construction bag"
icon = 'icons/obj/tools.dmi'
icon_state = "construction_bag"
worn_icon_state = "construction_bag"
desc = "A bag for storing small construction components."
resistance_flags = FLAMMABLE
+632
View File
@@ -0,0 +1,632 @@
/**
* Mech prizes + MECHA COMBAT!!
*/
/// Mech battle special attack types.
#define SPECIAL_ATTACK_HEAL 1
#define SPECIAL_ATTACK_DAMAGE 2
#define SPECIAL_ATTACK_UTILITY 3
#define SPECIAL_ATTACK_OTHER 4
/// Max length of a mech battle
#define MAX_BATTLE_LENGTH 50
/obj/item/toy/prize
icon = 'icons/obj/toy.dmi'
icon_state = "ripleytoy"
verb_say = "beeps"
verb_ask = "beeps"
verb_exclaim = "beeps"
verb_yell = "beeps"
w_class = WEIGHT_CLASS_SMALL
/// Timer when it'll be off cooldown
var/timer = 0
/// Cooldown between play sessions
var/cooldown = 1.5 SECONDS
/// Cooldown multiplier after a battle (by default: battle cooldowns are 30 seconds)
var/cooldown_multiplier = 20
/// If it makes noise when played with
var/quiet = FALSE
/// TRUE = Offering battle to someone || FALSE = Not offering battle
var/wants_to_battle = FALSE
/// TRUE = in combat currently || FALSE = Not in combat
var/in_combat = FALSE
/// The mech's health in battle
var/combat_health = 0
/// The mech's max combat health
var/max_combat_health = 0
/// TRUE = the special attack is charged || FALSE = not charged
var/special_attack_charged = FALSE
/// What type of special attack they use - SPECIAL_ATTACK_DAMAGE, SPECIAL_ATTACK_HEAL, SPECIAL_ATTACK_UTILITY, SPECIAL_ATTACK_OTHER
var/special_attack_type = 0
/// What message their special move gets on examining
var/special_attack_type_message = ""
/// The battlecry when using the special attack
var/special_attack_cry = "*flip"
/// Current cooldown of their special attack
var/special_attack_cooldown = 0
/// This mech's win count in combat
var/wins = 0
/// ...And their loss count in combat
var/losses = 0
/obj/item/toy/prize/Initialize()
. = ..()
desc = "Mini-Mecha action figure! Collect them all! Attack your friends or another mech with one to initiate epic mech combat! [desc]."
combat_health = max_combat_health
switch(special_attack_type)
if(SPECIAL_ATTACK_DAMAGE)
special_attack_type_message = "an aggressive move, which deals bonus damage."
if(SPECIAL_ATTACK_HEAL)
special_attack_type_message = "a defensive move, which grants bonus healing."
if(SPECIAL_ATTACK_UTILITY)
special_attack_type_message = "a utility move, which heals the user and damages the opponent."
if(SPECIAL_ATTACK_OTHER)
special_attack_type_message = "a special move, which [special_attack_type_message]"
else
special_attack_type_message = "a mystery move, even I don't know."
/**
* this proc combines "sleep" while also checking for if the battle should continue
*
* this goes through some of the checks - the toys need to be next to each other to fight!
* if it's player vs themself: They need to be able to "control" both mechs (either must be adjacent or using TK)
* if it's player vs player: Both players need to be able to "control" their mechs (either must be adjacent or using TK)
* if it's player vs mech (suicide): the mech needs to be in range of the player
* if all the checks are TRUE, it does the sleeps, and returns TRUE. Otherwise, it returns FALSE.
* Arguments:
* * delay - the amount of time the sleep at the end of the check will sleep for
* * attacker - the attacking toy in the battle.
* * attacker_controller - the controller of the attacking toy. there should ALWAYS be an attacker_controller
* * opponent - (optional) the defender controller in the battle, for PvP
*/
/obj/item/toy/prize/proc/combat_sleep(var/delay, obj/item/toy/prize/attacker, mob/living/carbon/attacker_controller, mob/living/carbon/opponent)
if(!attacker_controller)
return FALSE
if(!attacker) //if there's no attacker, then attacker_controller IS the attacker
if(!in_range(src, attacker_controller))
attacker_controller.visible_message("<span class='suicide'>[attacker_controller] is running from [src]! The coward!</span>")
return FALSE
else // if there's an attacker, we can procede as normal
if(!in_range(src, attacker)) //and the two toys aren't next to each other, the battle ends
attacker_controller.visible_message("<span class='notice'> [attacker] and [src] separate, ending the battle. </span>", \
"<span class='notice'> [attacker] and [src] separate, ending the battle. </span>")
return FALSE
//dead men tell no tales, incapacitated men fight no fights
if(attacker_controller.incapacitated())
return FALSE
//if the attacker_controller isn't next to the attacking toy (and doesn't have telekinesis), the battle ends
if(!in_range(attacker, attacker_controller) && !(attacker_controller.dna.check_mutation(TK)))
attacker_controller.visible_message("<span class='notice'> [attacker_controller.name] seperates from [attacker], ending the battle.</span>", \
"<span class='notice'> You separate from [attacker], ending the battle. </span>")
return FALSE
//if it's PVP and the opponent is not next to the defending(src) toy (and doesn't have telekinesis), the battle ends
if(opponent)
if(opponent.incapacitated())
return FALSE
if(!in_range(src, opponent) && !(opponent.dna.check_mutation(TK)))
opponent.visible_message("<span class='notice'> [opponent.name] seperates from [src], ending the battle.</span>", \
"<span class='notice'> You separate from [src], ending the battle. </span>")
return FALSE
//if it's not PVP and the attacker_controller isn't next to the defending toy (and doesn't have telekinesis), the battle ends
else
if (!in_range(src, attacker_controller) && !(attacker_controller.dna.check_mutation(TK)))
attacker_controller.visible_message("<span class='notice'> [attacker_controller.name] seperates from [src] and [attacker], ending the battle.</span>", \
"<span class='notice'> You separate [attacker] and [src], ending the battle. </span>")
return FALSE
//if all that is good, then we can sleep peacefully
sleep(delay)
return TRUE
//all credit to skasi for toy mech fun ideas
/obj/item/toy/prize/attack_self(mob/user)
if(timer < world.time)
to_chat(user, "<span class='notice'>You play with [src].</span>")
timer = world.time + cooldown
if(!quiet)
playsound(user, 'sound/mecha/mechstep.ogg', 20, TRUE)
else
. = ..()
/obj/item/toy/prize/attack_hand(mob/user)
. = ..()
if(.)
return
if(loc == user)
attack_self(user)
/**
* If you attack a mech with a mech, initiate combat between them
*/
/obj/item/toy/prize/attackby(obj/item/user_toy, mob/living/user)
if(istype(user_toy, /obj/item/toy/prize))
var/obj/item/toy/prize/P = user_toy
if(check_battle_start(user, P))
mecha_brawl(P, user)
..()
/**
* Attack is called from the user's toy, aimed at target(another human), checking for target's toy.
*/
/obj/item/toy/prize/attack(mob/living/carbon/human/target, mob/living/carbon/human/user)
if(target == user)
to_chat(user, "<span class='notice'>Target another toy mech if you want to start a battle with yourself.</span>")
return
else if(user.a_intent != INTENT_HARM)
if(wants_to_battle) //prevent spamming someone with offers
to_chat(user, "<span class='notice'>You already are offering battle to someone!</span>")
return
if(!check_battle_start(user)) //if the user's mech isn't ready, don't bother checking
return
for(var/obj/item/I in target.held_items)
if(istype(I, /obj/item/toy/prize)) //if you attack someone with a mech who's also holding a mech, offer to battle them
var/obj/item/toy/prize/P = I
if(!P.check_battle_start(target, null, user)) //check if the attacker mech is ready
break
//slap them with the metaphorical white glove
if(P.wants_to_battle) //if the target mech wants to battle, initiate the battle from their POV
mecha_brawl(P, target, user) //P = defender's mech / SRC = attacker's mech / target = defender / user = attacker
P.wants_to_battle = FALSE
return
//extend the offer of battle to the other mech
to_chat(user, "<span class='notice'>You offer battle to [target.name]!</span>")
to_chat(target, "<span class='notice'><b>[user.name] wants to battle with [user.p_their()] [name]!</b> <i>Attack them with a toy mech to initiate combat.</i></span>")
wants_to_battle = TRUE
addtimer(CALLBACK(src, .proc/withdraw_offer, user), 6 SECONDS)
return
..()
/**
* Overrides attack_tk - Sorry, you have to be face to face to initiate a battle, it's good sportsmanship
*/
/obj/item/toy/prize/attack_tk(mob/user)
if(timer < world.time)
to_chat(user, "<span class='notice'>You telekinetically play with [src].</span>")
timer = world.time + cooldown
if(!quiet)
playsound(user, 'sound/mecha/mechstep.ogg', 20, TRUE)
/**
* Resets the request for battle.
*
* For use in a timer, this proc resets the wants_to_battle variable after a short period.
* Arguments:
* * user - the user wanting to do battle
*/
/obj/item/toy/prize/proc/withdraw_offer(mob/living/carbon/user)
if(wants_to_battle)
wants_to_battle = FALSE
to_chat(user, "<span class='notice'>You get the feeling they don't want to battle.</span>")
/**
* Starts a battle, toy mech vs player. Player... doesn't win.
*/
/obj/item/toy/prize/suicide_act(mob/living/carbon/user)
if(in_combat)
to_chat(user, "<span class='notice'>[src] is in battle, let it finish first.</span>")
return
user.visible_message("<span class='suicide'>[user] begins a fight [user.p_they()] can't win with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
in_combat = TRUE
sleep(1.5 SECONDS)
for(var/i in 1 to 4)
switch(i)
if(1, 3)
SpinAnimation(5, 0)
playsound(src, 'sound/mecha/mechstep.ogg', 30, TRUE)
user.adjustBruteLoss(25)
user.adjustStaminaLoss(50)
if(2)
user.SpinAnimation(5, 0)
playsound(user, 'sound/weapons/smash.ogg', 20, TRUE)
combat_health-- //we scratched it!
if(4)
say(special_attack_cry + "!!")
user.adjustStaminaLoss(25)
if(!combat_sleep(1 SECONDS, null, user))
say("PATHETIC.")
combat_health = max_combat_health
in_combat = FALSE
return SHAME
sleep(0.5 SECONDS)
user.adjustBruteLoss(450)
in_combat = FALSE
say("AN EASY WIN. MY POWER INCREASES.") // steal a soul, become swole
add_atom_colour(rgb(255, 115, 115), ADMIN_COLOUR_PRIORITY)
max_combat_health = round(max_combat_health*1.5 + 0.1)
combat_health = max_combat_health
wins++
return BRUTELOSS
/obj/item/toy/prize/examine()
. = ..()
. += "<span class='notice'>This toy's special attack is [special_attack_cry], [special_attack_type_message] </span>"
if(in_combat)
. += "<span class='notice'>This toy has a maximum health of [max_combat_health]. Currently, it's [combat_health].</span>"
. += "<span class='notice'>Its special move light is [special_attack_cooldown? "flashing red." : "green and is ready!"]</span>"
else
. += "<span class='notice'>This toy has a maximum health of [max_combat_health].</span>"
if(wins || losses)
. += "<span class='notice'>This toy has [wins] wins, and [losses] losses.</span>"
/**
* Override the say proc if they're mute
*/
/obj/item/toy/prize/say()
if(!quiet)
. = ..()
/**
* The 'master' proc of the mech battle. Processes the entire battle's events and makes sure it start and finishes correctly.
*
* src is the defending toy, and the battle proc is called on it to begin the battle.
* After going through a few checks at the beginning to ensure the battle can start properly, the battle begins a loop that lasts
* until either toy has no more health. During this loop, it also ensures the mechs stay in combat range of each other.
* It will then randomly decide attacks for each toy, occasionally making one or the other use their special attack.
* When either mech has no more health, the loop ends, and it displays the victor and the loser while updating their stats and resetting them.
* Arguments:
* * attacker - the attacking toy, the toy in the attacker_controller's hands
* * attacker_controller - the user, the one who is holding the toys / controlling the fight
* * opponent - optional arg used in Mech PvP battles: the other person who is taking part in the fight (controls src)
*/
/obj/item/toy/prize/proc/mecha_brawl(obj/item/toy/prize/attacker, mob/living/carbon/attacker_controller, mob/living/carbon/opponent)
//A GOOD DAY FOR A SWELL BATTLE!
attacker_controller.visible_message("<span class='danger'> [attacker_controller.name] collides [attacker] with [src]! Looks like they're preparing for a brawl! </span>", \
"<span class='danger'> You collide [attacker] into [src], sparking a fierce battle! </span>", \
"<span class='hear'> You hear hard plastic smacking into hard plastic.</span>", COMBAT_MESSAGE_RANGE)
/// Who's in control of the defender (src)?
var/mob/living/carbon/src_controller = (opponent)? opponent : attacker_controller
/// How long has the battle been going?
var/battle_length = 0
in_combat = TRUE
attacker.in_combat = TRUE
//1.5 second cooldown * 20 = 30 second cooldown after a fight
timer = world.time + cooldown*cooldown_multiplier
attacker.timer = world.time + attacker.cooldown*attacker.cooldown_multiplier
sleep(1 SECONDS)
//--THE BATTLE BEGINS--
while(combat_health > 0 && attacker.combat_health > 0 && battle_length < MAX_BATTLE_LENGTH)
if(!combat_sleep(0.5 SECONDS, attacker, attacker_controller, opponent)) //combat_sleep checks everything we need to have checked for combat to continue
break
//before we do anything - deal with charged attacks
if(special_attack_charged)
src_controller.visible_message("<span class='danger'> [src] unleashes its special attack!! </span>", \
"<span class='danger'> You unleash [src]'s special attack! </span>")
special_attack_move(attacker)
else if(attacker.special_attack_charged)
attacker_controller.visible_message("<span class='danger'> [attacker] unleashes its special attack!! </span>", \
"<span class='danger'> You unleash [attacker]'s special attack! </span>")
attacker.special_attack_move(src)
else
//process the cooldowns
if(special_attack_cooldown > 0)
special_attack_cooldown--
if(attacker.special_attack_cooldown > 0)
attacker.special_attack_cooldown--
//combat commences
switch(rand(1,8))
if(1 to 3) //attacker wins
if(attacker.special_attack_cooldown == 0 && attacker.combat_health <= round(attacker.max_combat_health/3)) //if health is less than 1/3 and special off CD, use it
attacker.special_attack_charged = TRUE
attacker_controller.visible_message("<span class='danger'> [attacker] begins charging its special attack!! </span>", \
"<span class='danger'> You begin charging [attacker]'s special attack! </span>")
else //just attack
attacker.SpinAnimation(5, 0)
playsound(attacker, 'sound/mecha/mechstep.ogg', 30, TRUE)
combat_health--
attacker_controller.visible_message("<span class='danger'> [attacker] devastates [src]! </span>", \
"<span class='danger'> You ram [attacker] into [src]! </span>", \
"<span class='hear'> You hear hard plastic smacking hard plastic.</span>", COMBAT_MESSAGE_RANGE)
if(prob(5))
combat_health--
playsound(src, 'sound/effects/meteorimpact.ogg', 20, TRUE)
attacker_controller.visible_message("<span class='boldwarning'> ...and lands a CRIPPLING BLOW! </span>", \
"<span class='boldwarning'> ...and you land a CRIPPLING blow on [src]! </span>", null, COMBAT_MESSAGE_RANGE)
if(4) //both lose
attacker.SpinAnimation(5, 0)
SpinAnimation(5, 0)
combat_health--
attacker.combat_health--
do_sparks(2, FALSE, src)
do_sparks(2, FALSE, attacker)
if(prob(50))
attacker_controller.visible_message("<span class='danger'> [attacker] and [src] clash dramatically, causing sparks to fly! </span>", \
"<span class='danger'> [attacker] and [src] clash dramatically, causing sparks to fly! </span>", \
"<span class='hear'> You hear hard plastic rubbing against hard plastic.</span>", COMBAT_MESSAGE_RANGE)
else
src_controller.visible_message("<span class='danger'> [src] and [attacker] clash dramatically, causing sparks to fly! </span>", \
"<span class='danger'> [src] and [attacker] clash dramatically, causing sparks to fly! </span>", \
"<span class='hear'> You hear hard plastic rubbing against hard plastic.</span>", COMBAT_MESSAGE_RANGE)
if(5) //both win
playsound(attacker, 'sound/weapons/parry.ogg', 20, TRUE)
if(prob(50))
attacker_controller.visible_message("<span class='danger'> [src]'s attack deflects off of [attacker]. </span>", \
"<span class='danger'> [src]'s attack deflects off of [attacker]. </span>", \
"<span class='hear'> You hear hard plastic bouncing off hard plastic.</span>", COMBAT_MESSAGE_RANGE)
else
src_controller.visible_message("<span class='danger'> [attacker]'s attack deflects off of [src]. </span>", \
"<span class='danger'> [attacker]'s attack deflects off of [src]. </span>", \
"<span class='hear'> You hear hard plastic bouncing off hard plastic.</span>", COMBAT_MESSAGE_RANGE)
if(6 to 8) //defender wins
if(special_attack_cooldown == 0 && combat_health <= round(max_combat_health/3)) //if health is less than 1/3 and special off CD, use it
special_attack_charged = TRUE
src_controller.visible_message("<span class='danger'> [src] begins charging its special attack!! </span>", \
"<span class='danger'> You begin charging [src]'s special attack! </span>")
else //just attack
SpinAnimation(5, 0)
playsound(src, 'sound/mecha/mechstep.ogg', 30, TRUE)
attacker.combat_health--
src_controller.visible_message("<span class='danger'> [src] smashes [attacker]! </span>", \
"<span class='danger'> You smash [src] into [attacker]! </span>", \
"<span class='hear'> You hear hard plastic smashing hard plastic.</span>", COMBAT_MESSAGE_RANGE)
if(prob(5))
attacker.combat_health--
playsound(attacker, 'sound/effects/meteorimpact.ogg', 20, TRUE)
src_controller.visible_message("<span class='boldwarning'> ...and lands a CRIPPLING BLOW! </span>", \
"<span class='boldwarning'> ...and you land a CRIPPLING blow on [attacker]! </span>", null, COMBAT_MESSAGE_RANGE)
else
attacker_controller.visible_message("<span class='notice'> [src] and [attacker] stand around awkwardly.</span>", \
"<span class='notice'> You don't know what to do next.</span>")
battle_length++
sleep(0.5 SECONDS)
/// Lines chosen for the winning mech
var/list/winlines = list("YOU'RE NOTHING BUT SCRAP!", "I'LL YIELD TO NONE!", "GLORY IS MINE!", "AN EASY FIGHT.", "YOU SHOULD HAVE NEVER FACED ME.", "ROCKED AND SOCKED.")
if(attacker.combat_health <= 0 && combat_health <= 0) //both lose
playsound(src, 'sound/machines/warning-buzzer.ogg', 20, TRUE)
attacker_controller.visible_message("<span class='boldnotice'> MUTUALLY ASSURED DESTRUCTION!! [src] and [attacker] both end up destroyed!</span>", \
"<span class='boldnotice'> Both [src] and [attacker] are destroyed!</span>")
else if(attacker.combat_health <= 0) //src wins
wins++
attacker.losses++
playsound(attacker, 'sound/effects/light_flicker.ogg', 20, TRUE)
attacker_controller.visible_message("<span class='notice'> [attacker] falls apart!</span>", \
"<span class='notice'> [attacker] falls apart!</span>", null, COMBAT_MESSAGE_RANGE)
say("[pick(winlines)]")
src_controller.visible_message("<span class='notice'> [src] destroys [attacker] and walks away victorious!</span>", \
"<span class='notice'> You raise up [src] victoriously over [attacker]!</span>")
else if (combat_health <= 0) //attacker wins
attacker.wins++
losses++
playsound(src, 'sound/effects/light_flicker.ogg', 20, TRUE)
src_controller.visible_message("<span class='notice'> [src] collapses!</span>", \
"<span class='notice'> [src] collapses!</span>", null, COMBAT_MESSAGE_RANGE)
attacker.say("[pick(winlines)]")
attacker_controller.visible_message("<span class='notice'> [attacker] demolishes [src] and walks away victorious!</span>", \
"<span class='notice'> You raise up [attacker] proudly over [src]</span>!")
else //both win?
say("NEXT TIME.")
//don't want to make this a one sided conversation
quiet? attacker.say("I WENT EASY ON YOU.") : attacker.say("OF COURSE.")
in_combat = FALSE
attacker.in_combat = FALSE
combat_health = max_combat_health
attacker.combat_health = attacker.max_combat_health
return
/**
* This proc checks if a battle can be initiated between src and attacker.
*
* Both SRC and attacker (if attacker is included) timers are checked if they're on cooldown, and
* both SRC and attacker (if attacker is included) are checked if they are in combat already.
* If any of the above are true, the proc returns FALSE and sends a message to user (and target, if included) otherwise, it returns TRUE
* Arguments:
* * user: the user who is initiating the battle
* * attacker: optional arg for checking two mechs at once
* * target: optional arg used in Mech PvP battles (if used, attacker is target's toy)
*/
/obj/item/toy/prize/proc/check_battle_start(mob/living/carbon/user, obj/item/toy/prize/attacker, mob/living/carbon/target)
if(attacker && attacker.in_combat)
to_chat(user, "<span class='notice'>[target?target.p_their() : "Your" ] [attacker.name] is in combat.</span>")
target?.to_chat(target, "<span class='notice'>Your [attacker.name] is in combat.</span>")
return FALSE
if(in_combat)
to_chat(user, "<span class='notice'>Your [name] is in combat.</span>")
target?.to_chat(target, "<span class='notice'>[target.p_their()] [name] is in combat.</span>")
return FALSE
if(attacker && attacker.timer > world.time)
to_chat(user, "<span class='notice'>[target?target.p_their() : "Your" ] [attacker.name] isn't ready for battle.</span>")
target?.to_chat(target, "<span class='notice'>Your [attacker.name] isn't ready for battle.</span>")
return FALSE
if(timer > world.time)
to_chat(user, "<span class='notice'>Your [name] isn't ready for battle.</span>")
target?.to_chat(target, "<span class='notice'>[target.p_their()] [name] isn't ready for battle.</span>")
return FALSE
return TRUE
/**
* Processes any special attack moves that happen in the battle (called in the mechaBattle proc).
*
* Makes the toy shout their special attack cry and updates its cooldown. Then, does the special attack.
* Arguments:
* * victim - the toy being hit by the special move
*/
/obj/item/toy/prize/proc/special_attack_move(obj/item/toy/prize/victim)
say(special_attack_cry + "!!")
special_attack_charged = FALSE
special_attack_cooldown = 3
switch(special_attack_type)
if(SPECIAL_ATTACK_DAMAGE) //+2 damage
victim.combat_health-=2
playsound(src, 'sound/weapons/marauder.ogg', 20, TRUE)
if(SPECIAL_ATTACK_HEAL) //+2 healing
combat_health+=2
playsound(src, 'sound/mecha/mech_shield_raise.ogg', 20, TRUE)
if(SPECIAL_ATTACK_UTILITY) //+1 heal, +1 damage
victim.combat_health--
combat_health++
playsound(src, 'sound/mecha/mechmove01.ogg', 30, TRUE)
if(SPECIAL_ATTACK_OTHER) //other
super_special_attack(victim)
else
say("I FORGOT MY SPECIAL ATTACK...")
/**
* Base proc for 'other' special attack moves.
*
* This one is only for inheritance, each mech with an 'other' type move has their procs below.
* Arguments:
* * victim - the toy being hit by the super special move (doesn't necessarily need to be used)
*/
/obj/item/toy/prize/proc/super_special_attack(obj/item/toy/prize/victim)
visible_message("<span class='notice'> [src] does a cool flip.</span>")
/obj/item/toy/prize/ripley
name = "toy Ripley"
desc = "1/13"
max_combat_health = 4 //200 integrity
special_attack_type = SPECIAL_ATTACK_DAMAGE
special_attack_cry = "GIGA DRILL BREAK"
/obj/item/toy/prize/fireripley //rip
name = "toy Firefighting Ripley"
desc = "2/13"
icon_state = "fireripleytoy"
max_combat_health = 5 //250 integrity?
special_attack_type = SPECIAL_ATTACK_UTILITY
special_attack_cry = "FIRE SHIELD"
/obj/item/toy/prize/deathripley
name = "toy Deathsquad Ripley"
desc = "3/13"
icon_state = "deathripleytoy"
max_combat_health = 5 //250 integrity
special_attack_type = SPECIAL_ATTACK_OTHER
special_attack_type_message = "instantly destroys the opposing mech if its health is less than this mech's health."
special_attack_cry = "KILLER CLAMP"
/obj/item/toy/prize/deathripley/super_special_attack(obj/item/toy/prize/victim)
playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 20, TRUE)
if(victim.combat_health < combat_health) //Instantly kills the other mech if it's health is below our's.
say("EXECUTE!!")
victim.combat_health = 0
else //Otherwise, just deal one damage.
victim.combat_health--
/obj/item/toy/prize/gygax
name = "toy Gygax"
desc = "4/13"
icon_state = "gygaxtoy"
max_combat_health = 5 //250 integrity
special_attack_type = SPECIAL_ATTACK_UTILITY
special_attack_cry = "SUPER SERVOS"
/obj/item/toy/prize/durand
name = "toy Durand"
desc = "5/13"
icon_state = "durandtoy"
max_combat_health = 6 //400 integrity
special_attack_type = SPECIAL_ATTACK_HEAL
special_attack_cry = "SHIELD OF PROTECTION"
/obj/item/toy/prize/honk
name = "toy H.O.N.K."
desc = "6/13"
icon_state = "honktoy"
max_combat_health = 4 //140 integrity
special_attack_type = SPECIAL_ATTACK_OTHER
special_attack_type_message = "puts the opposing mech's special move on cooldown and heals this mech."
special_attack_cry = "MEGA HORN"
/obj/item/toy/prize/honk/super_special_attack(obj/item/toy/prize/victim)
playsound(src, 'sound/machines/honkbot_evil_laugh.ogg', 20, TRUE)
victim.special_attack_cooldown += 3 //Adds cooldown to the other mech and gives a minor self heal
combat_health++
/obj/item/toy/prize/marauder
name = "toy Marauder"
desc = "7/13"
icon_state = "maraudertoy"
max_combat_health = 7 //500 integrity
special_attack_type = SPECIAL_ATTACK_DAMAGE
special_attack_cry = "BEAM BLAST"
/obj/item/toy/prize/seraph
name = "toy Seraph"
desc = "8/13"
icon_state = "seraphtoy"
max_combat_health = 8 //550 integrity
special_attack_type = SPECIAL_ATTACK_DAMAGE
special_attack_cry = "ROCKET BARRAGE"
/obj/item/toy/prize/mauler
name = "toy Mauler"
desc = "9/13"
icon_state = "maulertoy"
max_combat_health = 7 //500 integrity
special_attack_type = SPECIAL_ATTACK_DAMAGE
special_attack_cry = "BULLET STORM"
/obj/item/toy/prize/odysseus
name = "toy Odysseus"
desc = "10/13"
icon_state = "odysseustoy"
max_combat_health = 4 //120 integrity
special_attack_type = SPECIAL_ATTACK_HEAL
special_attack_cry = "MECHA BEAM"
/obj/item/toy/prize/phazon
name = "toy Phazon"
desc = "11/13"
icon_state = "phazontoy"
max_combat_health = 6 //200 integrity
special_attack_type = SPECIAL_ATTACK_UTILITY
special_attack_cry = "NO-CLIP"
/obj/item/toy/prize/reticence
name = "toy Reticence"
desc = "12/13"
icon_state = "reticencetoy"
quiet = TRUE
max_combat_health = 4 //100 integrity
special_attack_type = SPECIAL_ATTACK_OTHER
special_attack_type_message = "has a lower cooldown than normal special moves, increases the opponent's cooldown, and deals damage."
special_attack_cry = "*wave"
/obj/item/toy/prize/reticence/super_special_attack(obj/item/toy/prize/victim)
special_attack_cooldown-- //Has a lower cooldown...
victim.special_attack_cooldown++ //and increases the opponent's cooldown by 1...
victim.combat_health-- //and some free damage.
/obj/item/toy/prize/clarke
name = "toy Clarke"
desc = "13/13"
icon_state = "clarketoy"
max_combat_health = 4 //200 integrity
special_attack_type = SPECIAL_ATTACK_UTILITY
special_attack_cry = "ROLL OUT"
#undef SPECIAL_ATTACK_HEAL
#undef SPECIAL_ATTACK_DAMAGE
#undef SPECIAL_ATTACK_UTILITY
#undef SPECIAL_ATTACK_OTHER
#undef MAX_BATTLE_LENGTH
-96
View File
@@ -7,7 +7,6 @@
* Toy swords
* Crayons
* Snap pops
* Mech prizes
* AI core prizes
* Toy codex gigas
* Skeleton toys
@@ -26,7 +25,6 @@
* Broken Radio
*/
/obj/item/toy
throwforce = 0
throw_speed = 3
@@ -519,100 +517,6 @@
new /obj/item/toy/snappop/phoenix(get_turf(src))
qdel(src)
/*
* Mech prizes
*/
/obj/item/toy/prize
icon = 'icons/obj/toy.dmi'
icon_state = "ripleytoy"
var/timer = 0
var/cooldown = 30
var/quiet = 0
w_class = WEIGHT_CLASS_SMALL
//all credit to skasi for toy mech fun ideas
/obj/item/toy/prize/attack_self(mob/user)
if(timer < world.time)
to_chat(user, "<span class='notice'>You play with [src].</span>")
timer = world.time + cooldown
if(!quiet)
playsound(user, 'sound/mecha/mechstep.ogg', 20, TRUE)
else
. = ..()
/obj/item/toy/prize/attack_hand(mob/user)
. = ..()
if(.)
return
if(loc == user)
attack_self(user)
/obj/item/toy/prize/ripley
name = "toy Ripley"
desc = "Mini-Mecha action figure! Collect them all! 1/13."
/obj/item/toy/prize/fireripley
name = "toy firefighting Ripley"
desc = "Mini-Mecha action figure! Collect them all! 2/13."
icon_state = "fireripleytoy"
/obj/item/toy/prize/deathripley
name = "toy deathsquad Ripley"
desc = "Mini-Mecha action figure! Collect them all! 3/13."
icon_state = "deathripleytoy"
/obj/item/toy/prize/gygax
name = "toy Gygax"
desc = "Mini-Mecha action figure! Collect them all! 4/13."
icon_state = "gygaxtoy"
/obj/item/toy/prize/durand
name = "toy Durand"
desc = "Mini-Mecha action figure! Collect them all! 5/13."
icon_state = "durandtoy"
/obj/item/toy/prize/honk
name = "toy H.O.N.K."
desc = "Mini-Mecha action figure! Collect them all! 6/13."
icon_state = "honktoy"
/obj/item/toy/prize/marauder
name = "toy Marauder"
desc = "Mini-Mecha action figure! Collect them all! 7/13."
icon_state = "maraudertoy"
/obj/item/toy/prize/seraph
name = "toy Seraph"
desc = "Mini-Mecha action figure! Collect them all! 8/13."
icon_state = "seraphtoy"
/obj/item/toy/prize/mauler
name = "toy Mauler"
desc = "Mini-Mecha action figure! Collect them all! 9/13."
icon_state = "maulertoy"
/obj/item/toy/prize/odysseus
name = "toy Odysseus"
desc = "Mini-Mecha action figure! Collect them all! 10/13."
icon_state = "odysseustoy"
/obj/item/toy/prize/phazon
name = "toy Phazon"
desc = "Mini-Mecha action figure! Collect them all! 11/13."
icon_state = "phazontoy"
/obj/item/toy/prize/reticence
name = "toy Reticence"
desc = "Mini-Mecha action figure! Collect them all! 12/13."
icon_state = "reticencetoy"
quiet = 1
/obj/item/toy/prize/clarke
name = "toy Clarke"
desc = "Mini-Mecha action figure! Collect them all! 13/13."
icon_state = "clarketoy"
/obj/item/toy/talking
name = "talking action figure"
desc = "A generic action figure modeled after nothing in particular."
+8
View File
@@ -91,6 +91,10 @@
return TRUE
/obj/blob_act(obj/structure/blob/B)
if(isturf(loc))
var/turf/T = loc
if(T.intact && HAS_TRAIT(src, TRAIT_T_RAY_VISIBLE))
return
take_damage(400, BRUTE, "melee", 0, get_dir(src, B))
/obj/proc/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0) //used by attack_alien, attack_animal, and attack_slime
@@ -198,6 +202,10 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
///Called when the obj is exposed to fire.
/obj/fire_act(exposed_temperature, exposed_volume)
if(isturf(loc))
var/turf/T = loc
if(T.intact && HAS_TRAIT(src, TRAIT_T_RAY_VISIBLE))
return
if(exposed_temperature && !(resistance_flags & FIRE_PROOF))
take_damage(clamp(0.02 * exposed_temperature, 0, 20), BURN, "fire", 0)
if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE) && !(resistance_flags & FIRE_PROOF))
@@ -46,11 +46,6 @@
update_icon()
PopulateContents()
RegisterSignal(src, COMSIG_ATOM_CANREACH, .proc/canreach_react)
/obj/structure/closet/proc/canreach_react(datum/source, list/next)
return COMPONENT_BLOCK_REACH //closed block, open have nothing inside.
//USE THIS TO FILL IT, NOT INITIALIZE OR NEW
/obj/structure/closet/proc/PopulateContents()
return
@@ -61,6 +56,8 @@
/obj/structure/closet/update_icon()
. = ..()
if (istype(src, /obj/structure/closet/supplypod))
return
if(!opened)
layer = OBJ_LAYER
else
@@ -337,8 +334,11 @@
var/mob/living/L = O
if(!issilicon(L))
L.Paralyze(40)
O.forceMove(T)
close()
if(istype(src, /obj/structure/closet/supplypod/extractionpod))
O.forceMove(src)
else
O.forceMove(T)
close()
else
O.forceMove(T)
return 1
+5 -5
View File
@@ -1,22 +1,22 @@
/obj/structure/sacrificealtar
name = "sacrificial altar"
desc = "An altar designed to perform blood sacrifice for a deity."
desc = "An altar designed to perform blood sacrifice for a deity. Alt-click it to sacrifice a buckled creature."
icon = 'icons/obj/hand_of_god_structures.dmi'
icon_state = "sacrificealtar"
anchored = TRUE
density = FALSE
can_buckle = 1
/obj/structure/sacrificealtar/attack_hand(mob/living/user)
. = ..()
if(.)
/obj/structure/sacrificealtar/AltClick(mob/living/user)
..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
return
if(!has_buckled_mobs())
return
var/mob/living/L = locate() in buckled_mobs
if(!L)
return
to_chat(user, "<span class='notice'>You attempt to sacrifice [L] by invoking the sacrificial ritual.</span>")
to_chat(user, "<span class='notice'>Invoking the sacred ritual, you sacrifice [L].</span>")
L.gib()
message_admins("[ADMIN_LOOKUPFLW(user)] has sacrificed [key_name_admin(L)] on the sacrificial altar at [AREACOORD(src)].")
+37 -11
View File
@@ -13,15 +13,46 @@
icon_state = "headpike-bone"
bonespear = TRUE
/obj/structure/headpike/Initialize(mapload)
. = ..()
if(mapload)
CheckParts()
/obj/structure/headpike/CheckParts(list/parts_list)
..()
victim = locate(/obj/item/bodypart/head) in parts_list
name = "[victim.name] on a spear"
if(!victim) //likely a mapspawned one
victim = new(src)
victim.real_name = random_unique_name(prob(50))
name = "[victim.real_name] on a spear"
update_icon()
if(bonespear)
spear = locate(/obj/item/spear/bonespear) in parts_list
else
spear = locate(/obj/item/spear) in parts_list
spear = locate(bonespear ? /obj/item/spear/bonespear : /obj/item/spear) in parts_list
if(!spear)
spear = bonespear ? new/obj/item/spear/bonespear(src) : new/obj/item/spear(src)
/obj/structure/headpike/Destroy()
QDEL_NULL(victim)
QDEL_NULL(spear)
return ..()
/obj/structure/headpike/handle_atom_del(atom/A)
if(A == victim)
victim = null
if(A == spear)
spear = null
deconstruct(TRUE)
return ..()
/obj/structure/headpike/deconstruct(disassembled)
if(!disassembled)
return ..()
if(victim)
victim.forceMove(drop_location())
victim = null
if(spear)
spear.forceMove(drop_location())
spear = null
return ..()
/obj/structure/headpike/Initialize()
. = ..()
@@ -41,9 +72,4 @@
if(.)
return
to_chat(user, "<span class='notice'>You take down [src].</span>")
if(victim)
victim.forceMove(drop_location())
victim = null
spear.forceMove(drop_location())
spear = null
qdel(src)
deconstruct(TRUE)
+1
View File
@@ -7,6 +7,7 @@
anchored = TRUE
var/obj/structure/ladder/down //the ladder below this one
var/obj/structure/ladder/up //the ladder above this one
obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN
/obj/structure/ladder/Initialize(mapload, obj/structure/ladder/up, obj/structure/ladder/down)
..()
+3 -2
View File
@@ -17,6 +17,7 @@
/obj/structure/falsewall)
smooth = SMOOTH_MORE
// flags = CONDUCT_1
obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN
/obj/structure/lattice/examine(mob/user)
. = ..()
@@ -77,7 +78,7 @@
number_of_mats = 2
smooth = SMOOTH_TRUE
canSmoothWith = null
obj_flags = CAN_BE_HIT | BLOCK_Z_FALL
obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN | BLOCK_Z_IN_UP
/obj/structure/lattice/catwalk/deconstruction_hints(mob/user)
return "<span class='notice'>The supporting rods look like they could be <b>cut</b>.</span>"
@@ -103,7 +104,7 @@
color = "#5286b9ff"
smooth = SMOOTH_TRUE
canSmoothWith = null
obj_flags = CAN_BE_HIT | BLOCK_Z_FALL
obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN | BLOCK_Z_IN_UP
resistance_flags = FIRE_PROOF | LAVA_PROOF
/obj/structure/lattice/lava/deconstruction_hints(mob/user)
+6 -5
View File
@@ -67,20 +67,21 @@
return TRUE
/obj/structure/railing/CanPass(atom/movable/mover, turf/target)
..()
. = ..()
if(get_dir(loc, target) & dir)
var/checking = UNSTOPPABLE | FLYING | FLOATING
return !density || mover.movement_type & checking
var/checking = FLYING | FLOATING
return . || mover.movement_type & checking
return TRUE
/obj/structure/railing/corner/CanPass()
..()
return TRUE
/obj/structure/railing/CheckExit(atom/movable/O, turf/target)
/obj/structure/railing/CheckExit(atom/movable/mover, turf/target)
..()
if(get_dir(loc, target) & dir)
return FALSE
var/checking = UNSTOPPABLE | FLYING | FLOATING
return !density || mover.movement_type & checking || mover.move_force >= MOVE_FORCE_EXTREMELY_STRONG
return TRUE
/obj/structure/railing/corner/CheckExit()