From a07b7a5ce3a8740e2fdf602ffa7c8c2d6db4f92d Mon Sep 17 00:00:00 2001 From: mwerezak Date: Tue, 15 Jul 2014 01:14:04 -0400 Subject: [PATCH] Thrown items can be targeted, has miss chance... ...based on distance, similar to projectiles. Conflicts: code/defines/obj.dm code/game/machinery/kitchen/smartfridge.dm code/game/machinery/vending.dm code/game/mecha/equipment/weapons/weapons.dm code/modules/games/cards.dm code/modules/mob/living/carbon/carbon.dm code/modules/mob/living/living_defense.dm --- code/_onclick/telekinesis.dm | 2 +- code/defines/obj.dm | 4 +- code/game/atoms_movable.dm | 8 +- code/game/machinery/bots/farmbot.dm | 2 +- code/game/machinery/kitchen/gibber.dm | 2 +- code/game/machinery/kitchen/smartfridge.dm | 2 - code/game/machinery/vending.dm | 2 +- code/game/mecha/equipment/tools/tools.dm | 2 +- code/game/mecha/equipment/weapons/weapons.dm | 10 +- .../objects/items/weapons/extinguisher.dm | 9 +- .../structures/stool_bed_chair_nest/chairs.dm | 2 +- .../stool_bed_chair_nest/wheelchair.dm | 7 +- code/modules/games/cards.dm | 222 ++++++++++++++++++ code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 2 +- code/modules/mob/living/living_defense.dm | 20 +- code/modules/projectiles/guns/alien.dm | 2 +- .../projectiles/guns/projectile/bow.dm | 2 +- .../projectiles/guns/projectile/pneumatic.dm | 2 +- .../projectiles/guns/projectile/rocket.dm | 2 +- code/modules/reagents/grenade_launcher.dm | 2 +- 21 files changed, 275 insertions(+), 33 deletions(-) create mode 100644 code/modules/games/cards.dm diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index 78f99228a9f..0eadbff6696 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -141,7 +141,7 @@ var/const/tk_maxrange = 15 else apply_focus_overlay() - focus.throw_at(target, 10, 1) + focus.throw_at(target, 10, 1, user) last_throw = world.time return diff --git a/code/defines/obj.dm b/code/defines/obj.dm index 2eae6a301af..7ad6c7ff6f6 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -387,9 +387,7 @@ var/global/list/PDA_Manifest = list() throw_speed = 1 throw_range = 20 flags = FPRINT | TABLEPASS | CONDUCT -// afterattack(atom/target as mob|obj|turf|area, mob/user as mob) -// user.drop_item() -// src.throw_at(target, throw_range, throw_speed) + /obj/effect/stop var/victim = null diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 8d89ad23f8e..e3607665395 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -7,6 +7,8 @@ var/l_move_time = 1 var/m_flag = 1 var/throwing = 0 + var/thrower + var/turf/throw_source = null var/throw_speed = 2 var/throw_range = 7 var/moved_recently = 0 @@ -83,11 +85,13 @@ if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement src.throw_impact(A,speed) -/atom/movable/proc/throw_at(atom/target, range, speed) +/atom/movable/proc/throw_at(atom/target, range, speed, thrower) if(!target || !src) return 0 //use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target src.throwing = 1 + src.thrower = thrower + src.throw_source = get_turf(src) //store the origin turf if(usr) if(M_HULK in usr.mutations) @@ -176,6 +180,8 @@ //done throwing, either because it hit something or it finished moving if(isobj(src)) src.throw_impact(get_turf(src),speed) src.throwing = 0 + src.thrower = null + src.throw_source = null //Overlays diff --git a/code/game/machinery/bots/farmbot.dm b/code/game/machinery/bots/farmbot.dm index d7a8e163141..f2981c70fe1 100644 --- a/code/game/machinery/bots/farmbot.dm +++ b/code/game/machinery/bots/farmbot.dm @@ -396,7 +396,7 @@ if ( emagged ) // Warning, hungry humans detected: throw fertilizer at them spawn(0) fert.loc = src.loc - fert.throw_at(target, 16, 3) + fert.throw_at(target, 16, 3, src) src.visible_message("\red [src] launches [fert.name] at [target.name]!") flick("farmbot_broke", src) spawn (FARMBOT_EMAG_DELAY) diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm index 6be3782dc72..8d020c5c268 100644 --- a/code/game/machinery/kitchen/gibber.dm +++ b/code/game/machinery/kitchen/gibber.dm @@ -172,7 +172,7 @@ var/obj/item/meatslab = allmeat[i] var/turf/Tx = locate(src.x - i, src.y, src.z) meatslab.loc = src.loc - meatslab.throw_at(Tx,i,3) + meatslab.throw_at(Tx,i,3,src) if (!Tx.density) new /obj/effect/decal/cleanable/blood/gibs(Tx,i) src.operating = 0 diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 123eeee2ee5..e51b11aafa4 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -203,5 +203,3 @@ - - diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 3ba71a125d8..97019615ad8 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -545,7 +545,7 @@ if (!throw_item) return 0 spawn(0) - throw_item.throw_at(target, 16, shoot_speed) + throw_item.throw_at(target, 16, 3, src) src.visible_message("\red [src] launches [throw_item.name] at [target.name]!") return 1 diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index e1fbd1803d6..42406003a5e 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -475,7 +475,7 @@ return else if(target!=locked) if(locked in view(chassis)) - locked.throw_at(target, 14, 1.5) + locked.throw_at(target, 14, 1.5, chassis) locked = null send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) set_ready_state(0) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 0adfc28c47e..3605c493246 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -312,7 +312,7 @@ var/obj/item/missile/M = new projectile(chassis.loc) M.primed = 1 playsound(chassis, fire_sound, 50, 1) - M.throw_at(target, missile_range, missile_speed) + M.throw_at(target, missile_range, missile_speed, chassis) projectiles-- log_message("Fired from [src.name], targeting [target].") do_after_cooldown() @@ -349,7 +349,7 @@ set_ready_state(0) var/obj/item/weapon/grenade/flashbang/F = new projectile(chassis.loc) playsound(chassis, fire_sound, 50, 1) - F.throw_at(target, missile_range, missile_speed) + F.throw_at(target, missile_range, missile_speed, chassis) projectiles-- log_message("Fired from [src.name], targeting [target].") spawn(det_time) @@ -391,7 +391,7 @@ set_ready_state(0) var/obj/item/weapon/bananapeel/B = new projectile(chassis.loc) playsound(chassis, fire_sound, 60, 1) - B.throw_at(target, missile_range, missile_speed) + B.throw_at(target, missile_range, missile_speed, chassis) projectiles-- log_message("Bananed from [src.name], targeting [target]. HONK!") do_after_cooldown() @@ -422,8 +422,8 @@ var/obj/item/device/assembly/mousetrap/M = new projectile(chassis.loc) M.secured = 1 playsound(chassis, fire_sound, 60, 1) - M.throw_at(target, missile_range, missile_speed) + M.throw_at(target, missile_range, missile_speed, chassis) projectiles-- log_message("Launched a mouse-trap from [src.name], targeting [target]. HONK!") do_after_cooldown() - return + return diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index 76d5b30acaa..37eb1384e9e 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -151,16 +151,19 @@ C = usr.buckled var/obj/B = usr.buckled var/movementdirection = turn(direction,180) - if(C) C.propelled = 1 - B.Move(get_step(usr,movementdirection), movementdirection) - sleep(1) + if(C) C.propelled = 4 B.Move(get_step(usr,movementdirection), movementdirection) sleep(1) B.Move(get_step(usr,movementdirection), movementdirection) + if(C) C.propelled = 3 + sleep(1) + B.Move(get_step(usr,movementdirection), movementdirection) sleep(1) B.Move(get_step(usr,movementdirection), movementdirection) + if(C) C.propelled = 2 sleep(2) B.Move(get_step(usr,movementdirection), movementdirection) + if(C) C.propelled = 1 sleep(2) B.Move(get_step(usr,movementdirection), movementdirection) if(C) C.propelled = 0 diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 932319d5940..17ac70a7aa9 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -136,7 +136,7 @@ if(propelled) var/mob/living/occupant = buckled_mob unbuckle() - occupant.throw_at(A, 3, 2) + occupant.throw_at(A, 3, propelled) occupant.apply_effect(6, STUN, 0) occupant.apply_effect(6, WEAKEN, 0) occupant.apply_effect(6, STUTTER, 0) diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index 605fc427e6b..118016cceeb 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -136,7 +136,12 @@ if(propelled || (pulling && (pulling.a_intent == "harm"))) var/mob/living/occupant = buckled_mob unbuckle() - occupant.throw_at(A, 3, 2) + + if (pulling && (pulling.a_intent == "hurt")) + occupant.throw_at(A, 3, 3, pulling) + else if (propelled) + occupant.throw_at(A, 3, propelled) + occupant.apply_effect(6, STUN, 0) occupant.apply_effect(6, WEAKEN, 0) occupant.apply_effect(6, STUTTER, 0) diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm new file mode 100644 index 00000000000..60adf1e7046 --- /dev/null +++ b/code/modules/games/cards.dm @@ -0,0 +1,222 @@ +/datum/playingcard + var/name = "playing card" + var/card_icon = "card_back" + +/obj/item/weapon/deck + name = "deck of cards" + desc = "A simple deck of playing cards." + icon = 'icons/obj/playing_cards.dmi' + icon_state = "deck" + w_class = 2 + + var/list/cards = list() + +/obj/item/weapon/deck/New() + ..() + + var/datum/playingcard/P + for(var/suit in list("spades","clubs","diamonds","hearts")) + + var/colour + if(suit == "spades" || suit == "clubs") + colour = "black_" + else + colour = "red_" + + for(var/number in list("ace","two","three","four","five","six","seven","eight","nine","ten")) + P = new() + P.name = "[number] of [suit]" + P.card_icon = "[colour]num" + cards += P + + for(var/number in list("jack","queen","king")) + P = new() + P.name = "[number] of [suit]" + P.card_icon = "[colour]col" + cards += P + + + for(var/i = 0,i<2,i++) + P = new() + P.name = "joker" + P.card_icon = "joker" + cards += P + +/obj/item/weapon/deck/attackby(obj/O as obj, mob/user as mob) + if(istype(O,/obj/item/weapon/hand)) + var/obj/item/weapon/hand/H = O + for(var/datum/playingcard/P in H.cards) + cards += P + del(O) + user << "You place your cards on the bottom of the deck." + return + ..() + +/obj/item/weapon/deck/verb/draw_card() + + set category = "Object" + set name = "Draw" + set desc = "Draw a card from a deck." + set src in oview(1) + + if(usr.stat || !Adjacent(usr)) return + + if(!istype(usr,/mob/living/carbon)) + return + + var/mob/living/carbon/user = usr + + if(!cards.len) + usr << "There are no cards in the deck." + return + + var/obj/item/weapon/hand/H + if(user.l_hand && istype(user.l_hand,/obj/item/weapon/hand)) + H = user.l_hand + else if(user.r_hand && istype(user.r_hand,/obj/item/weapon/hand)) + H = user.r_hand + else + H = new(get_turf(src)) + user.put_in_hands(H) + + if(!H || !user) return + + var/datum/playingcard/P = cards[1] + H.cards += P + cards -= P + H.update_icon() + user.visible_message("\The [user] draws a card.") + user << "It's the [P]." + +/obj/item/weapon/deck/verb/deal_card() + + set category = "Object" + set name = "Deal" + set desc = "Deal a card from a deck." + + if(usr.stat || !Adjacent(usr)) return + + if(!cards.len) + usr << "There are no cards in the deck." + return + + var/list/players = list() + for(var/mob/living/player in orange(3)) + if(!player.stat) + players += player + players -= usr + + var/mob/living/M = input("Who do you wish to deal a card?") as null|anything in players + if(!usr || !src || !M) return + + var/obj/item/weapon/hand/H = new(get_turf(src)) + + H.cards += cards[1] + cards -= cards[1] + H.concealed = 1 + H.update_icon() + usr.visible_message("\The [usr] deals a card to \the [M].") + H.throw_at(get_step(M,M.dir),10,1,H) + +/obj/item/weapon/hand/attackby(obj/O as obj, mob/user as mob) + if(istype(O,/obj/item/weapon/hand)) + var/obj/item/weapon/hand/H = O + for(var/datum/playingcard/P in H.cards) + cards += P + del(O) + user.put_in_hands(src) + update_icon() + return + ..() + +/obj/item/weapon/deck/attack_self(var/mob/user as mob) + + var/list/newcards = list() + while(cards.len) + var/datum/playingcard/P = pick(cards) + newcards += P + cards -= P + cards = newcards + user.visible_message("\The [user] shuffles [src].") + +/obj/item/weapon/hand + name = "hand of cards" + desc = "Some playing cards." + icon = 'icons/obj/playing_cards.dmi' + icon_state = "empty" + w_class = 1 + + var/concealed = 0 + var/list/cards = list() + +/obj/item/weapon/hand/verb/discard() + + set category = "Object" + set name = "Discard" + set desc = "Place a card from your hand in front of you." + + var/list/to_discard = list() + for(var/datum/playingcard/P in cards) + to_discard[P.name] = P + var/discarding = input("Which card do you wish to put down?") as null|anything in to_discard + + if(!discarding || !to_discard[discarding] || !usr || !src) return + + var/datum/playingcard/card = to_discard[discarding] + del(to_discard) + + var/obj/item/weapon/hand/H = new(src.loc) + H.cards += card + cards -= card + H.concealed = 0 + H.update_icon() + usr.visible_message("\The [usr] plays \the [discarding].") + H.loc = get_step(usr,usr.dir) + + if(!cards.len) + del(src) + +/obj/item/weapon/hand/attack_self(var/mob/user as mob) + concealed = !concealed + update_icon() + user.visible_message("\The [user] [concealed ? "conceals" : "reveals"] their hand.") + +/obj/item/weapon/hand/examine() + ..() + if((!concealed || src.loc == usr) && cards.len) + usr << "It contains: " + for(var/datum/playingcard/P in cards) + usr << "The [P.name]." + +/obj/item/weapon/hand/update_icon() + + if(!cards.len) + del(src) + return + else if(cards.len > 1) + name = "hand of cards" + desc = "Some playing cards." + else + name = "a playing card" + desc = "A playing card." + + overlays.Cut() + + + if(cards.len == 1) + var/datum/playingcard/P = cards[1] + var/image/I = new(src.icon, (concealed ? "card_back" : "[P.card_icon]") ) + I.pixel_x += (-5+rand(10)) + I.pixel_y += (-5+rand(10)) + overlays += I + return + + var/origin = -12 + var/offset = Floor(32/cards.len) + + var/i = 0 + for(var/datum/playingcard/P in cards) + var/image/I = new(src.icon, (concealed ? "card_back" : "[P.card_icon]") ) + I.pixel_x = origin+(offset*i) + overlays += I + i++ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index eb47e5da66d..4d1542ad704 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -416,7 +416,7 @@ */ - item.throw_at(target, item.throw_range, item.throw_speed) + item.throw_at(target, item.throw_range, item.throw_speed, src) /mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) ..() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d49ea30b668..a43201a2a22 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1548,7 +1548,7 @@ status_flags |= LEAPING src.visible_message("\The [src] leaps at [T]!") - src.throw_at(get_step(get_turf(T),get_turf(src)), 5, 1) + src.throw_at(get_step(get_turf(T),get_turf(src)), 5, 1, src) playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) sleep(5) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 422d622da6f..388045c8b6d 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -72,7 +72,6 @@ /mob/living/hitby(atom/movable/AM as mob|obj,var/speed = 5)//Standardization and logging -Sieve if(istype(AM,/obj/)) var/obj/O = AM - var/zone = ran_zone("chest",75)//Hits a random part of the body, geared towards the chest var/dtype = BRUTE if(istype(O,/obj/item/weapon)) var/obj/item/weapon/W = O @@ -84,14 +83,25 @@ var/throw_damage = O.throwforce*(speed/5) + var/zone + if (istype(O.thrower, /mob/living)) + var/mob/living/L = O.thrower + zone = check_zone(L.zone_sel.selecting) + else + zone = ran_zone("chest",75) //Hits a random part of the body, geared towards the chest + //def_zone = get_zone_with_miss_chance(zone, src, 15*AM.throwing_dist_travelled) - zone = get_zone_with_miss_chance(zone, src) //TODO: store the location of the thrower and adjust miss chance with distance + if (O.throw_source) + var/distance = get_dist(O.throw_source, loc) + zone = get_zone_with_miss_chance(zone, src, min(15*(distance-2), 0)) + else + zone = get_zone_with_miss_chance(zone, src, 15) if(!zone) - visible_message("\blue \The [AM] misses [src] narrowly!") + visible_message("\blue \The [O] misses [src] narrowly!") return - AM.throwing = 0 //it hit, so stop moving + O.throwing = 0 //it hit, so stop moving if (istype(src, /mob/living/carbon/human)) var/mob/living/carbon/human/H = src @@ -148,7 +158,7 @@ //This is called when the mob is thrown into a dense turf /mob/living/proc/turf_collision(var/turf/T, var/speed) - src.take_organ_damage(speed*4) + src.take_organ_damage(speed*5) /mob/living/proc/near_wall(var/direction,var/distance=1) var/turf/T = get_step(get_turf(src),direction) diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm index 0fba816ab06..0acbdc5ffae 100644 --- a/code/modules/projectiles/guns/alien.dm +++ b/code/modules/projectiles/guns/alien.dm @@ -110,7 +110,7 @@ user.visible_message("\red [user] fires [src]!", "\red You fire [src]!") spike.loc = get_turf(src) - spike.throw_at(target,10,fire_force) + spike.throw_at(target,10,fire_force,user) spike = null update_icon() diff --git a/code/modules/projectiles/guns/projectile/bow.dm b/code/modules/projectiles/guns/projectile/bow.dm index 23b055b806b..bb9f6fda179 100644 --- a/code/modules/projectiles/guns/projectile/bow.dm +++ b/code/modules/projectiles/guns/projectile/bow.dm @@ -199,7 +199,7 @@ var/obj/item/weapon/arrow/A = arrow A.loc = get_turf(user) - A.throw_at(target,10,tension*release_speed) + A.throw_at(target,10,tension*release_speed,user) arrow = null tension = 0 icon_state = "crossbow" diff --git a/code/modules/projectiles/guns/projectile/pneumatic.dm b/code/modules/projectiles/guns/projectile/pneumatic.dm index 007a45b0a41..64033bf1840 100644 --- a/code/modules/projectiles/guns/projectile/pneumatic.dm +++ b/code/modules/projectiles/guns/projectile/pneumatic.dm @@ -131,7 +131,7 @@ user.visible_message("[user] fires [src] and launches [object] at [target]!","You fire [src] and launch [object] at [target]!") src.remove_from_storage(object,user.loc) - object.throw_at(target,10,speed) + object.throw_at(target,10,speed,user) var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100) var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount) diff --git a/code/modules/projectiles/guns/projectile/rocket.dm b/code/modules/projectiles/guns/projectile/rocket.dm index e25a6ae3a9c..5f939e59073 100644 --- a/code/modules/projectiles/guns/projectile/rocket.dm +++ b/code/modules/projectiles/guns/projectile/rocket.dm @@ -42,7 +42,7 @@ var/obj/item/missile/M = new projectile(user.loc) playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) M.primed = 1 - M.throw_at(target, missile_range, missile_speed) + M.throw_at(target, missile_range, missile_speed,user) message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]).") log_game("[key_name_admin(user)] used a rocket launcher ([src.name]).") rockets -= I diff --git a/code/modules/reagents/grenade_launcher.dm b/code/modules/reagents/grenade_launcher.dm index d5f1ca734df..43fe7311938 100644 --- a/code/modules/reagents/grenade_launcher.dm +++ b/code/modules/reagents/grenade_launcher.dm @@ -56,7 +56,7 @@ var/obj/item/weapon/grenade/chem_grenade/F = grenades[1] //Now with less copypasta! grenades -= F F.loc = user.loc - F.throw_at(target, 30, 2) + F.throw_at(target, 30, 2, user) message_admins("[key_name_admin(user)] fired a grenade ([F.name]) from a grenade launcher ([src.name]).") log_game("[key_name_admin(user)] used a grenade ([src.name]).") F.active = 1