You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

193 lines
7.3 KiB

  1. /**
  2. * This is the proc that handles the order of an item_attack.
  3. *
  4. * The order of procs called is:
  5. * * [/atom/proc/tool_act] on the target. If it returns TRUE, the chain will be stopped.
  6. * * [/obj/item/proc/pre_attack] on src. If this returns TRUE, the chain will be stopped.
  7. * * [/atom/proc/attackby] on the target. If it returns TRUE, the chain will be stopped.
  8. * * [/obj/item/proc/afterattack]. The return value does not matter.
  9. */
  10. /obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
  11. SSdemo.mark_dirty(src)
  12. if(isturf(target))
  13. SSdemo.mark_turf(target)
  14. else
  15. SSdemo.mark_dirty(target)
  16. if(tool_behaviour && target.tool_act(user, src, tool_behaviour))
  17. return
  18. if(pre_attack(target, user, params))
  19. return
  20. if(target.attackby(src,user, params))
  21. return
  22. if(QDELETED(src) || QDELETED(target))
  23. attack_qdeleted(target, user, TRUE, params)
  24. return
  25. afterattack(target, user, TRUE, params)
  26. /// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
  27. /obj/item/proc/attack_self(mob/user)
  28. if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) & COMPONENT_NO_INTERACT)
  29. return
  30. interact(user)
  31. /**
  32. * Called on the item before it hits something
  33. *
  34. * Arguments:
  35. * * atom/A - The atom about to be hit
  36. * * mob/living/user - The mob doing the htting
  37. * * params - click params such as alt/shift etc
  38. *
  39. * See: [/obj/item/proc/melee_attack_chain]
  40. */
  41. /obj/item/proc/pre_attack(atom/A, mob/living/user, params) //do stuff before attackby!
  42. if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_NO_ATTACK)
  43. return TRUE
  44. return FALSE //return TRUE to avoid calling attackby after this proc does stuff
  45. /**
  46. * Called on an object being hit by an item
  47. *
  48. * Arguments:
  49. * * obj/item/W - The item hitting this atom
  50. * * mob/user - The wielder of this item
  51. * * params - click params such as alt/shift etc
  52. *
  53. * See: [/obj/item/proc/melee_attack_chain]
  54. */
  55. /atom/proc/attackby(obj/item/W, mob/user, params)
  56. if(SEND_SIGNAL(src, COMSIG_PARENT_ATTACKBY, W, user, params) & COMPONENT_NO_AFTERATTACK)
  57. return TRUE
  58. return FALSE
  59. /obj/attackby(obj/item/I, mob/living/user, params)
  60. return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_obj(src, user))
  61. /mob/living/attackby(obj/item/I, mob/living/user, params)
  62. if(..())
  63. return TRUE
  64. user.changeNext_move(CLICK_CD_MELEE)
  65. return I.attack(src, user)
  66. /**
  67. * Called from [/mob/living/attackby]
  68. *
  69. * Arguments:
  70. * * mob/living/M - The mob being hit by this item
  71. * * mob/living/user - The mob hitting with this item
  72. */
  73. /obj/item/proc/attack(mob/living/M, mob/living/user)
  74. if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
  75. return
  76. SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
  77. if(item_flags & NOBLUDGEON)
  78. return
  79. if(force && HAS_TRAIT(user, TRAIT_PACIFISM))
  80. to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
  81. return
  82. if(!force)
  83. playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), TRUE, -1)
  84. else if(hitsound)
  85. playsound(loc, hitsound, get_clamped_volume(), TRUE, -1)
  86. M.lastattacker = user.real_name
  87. M.lastattackerckey = user.ckey
  88. if(force && M == user && user.client)
  89. user.client.give_award(/datum/award/achievement/misc/selfouch, user)
  90. user.do_attack_animation(M)
  91. M.attacked_by(src, user)
  92. log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
  93. add_fingerprint(user)
  94. /// The equivalent of the standard version of [/obj/item/proc/attack] but for object targets.
  95. /obj/item/proc/attack_obj(obj/O, mob/living/user)
  96. if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
  97. return
  98. if(item_flags & NOBLUDGEON)
  99. return
  100. user.changeNext_move(CLICK_CD_MELEE)
  101. user.do_attack_animation(O)
  102. O.attacked_by(src, user)
  103. /// Called from [/obj/item/proc/attack_obj] and [/obj/item/proc/attack] if the attack succeeds
  104. /atom/movable/proc/attacked_by()
  105. return
  106. /obj/attacked_by(obj/item/I, mob/living/user)
  107. if(I.force)
  108. user.visible_message("<span class='danger'>[user] hits [src] with [I]!</span>", \
  109. "<span class='danger'>You hit [src] with [I]!</span>", null, COMBAT_MESSAGE_RANGE)
  110. //only witnesses close by and the victim see a hit message.
  111. log_combat(user, src, "attacked", I)
  112. take_damage(I.force, I.damtype, "melee", 1)
  113. /mob/living/attacked_by(obj/item/I, mob/living/user)
  114. send_item_attack_message(I, user)
  115. if(I.force)
  116. apply_damage(I.force, I.damtype)
  117. if(I.damtype == BRUTE)
  118. if(prob(33))
  119. I.add_mob_blood(src)
  120. var/turf/location = get_turf(src)
  121. add_splatter_floor(location)
  122. if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
  123. user.add_mob_blood(src)
  124. return TRUE //successful attack
  125. /mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
  126. if(I.force < force_threshold || I.damtype == STAMINA)
  127. playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), TRUE, -1)
  128. else
  129. return ..()
  130. /**
  131. * Last proc in the [/obj/item/proc/melee_attack_chain]
  132. *
  133. * Arguments:
  134. * * atom/target - The thing that was hit
  135. * * mob/user - The mob doing the hitting
  136. * * proximity_flag - is 1 if this afterattack was called on something adjacent, in your square, or on your person.
  137. * * click_parameters - is the params string from byond [/atom/proc/Click] code, see that documentation.
  138. */
  139. /obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
  140. SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
  141. SEND_SIGNAL(user, COMSIG_MOB_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
  142. /// Called if the target gets deleted by our attack
  143. /obj/item/proc/attack_qdeleted(atom/target, mob/user, proximity_flag, click_parameters)
  144. SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters)
  145. SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters)
  146. /obj/item/proc/get_clamped_volume()
  147. if(w_class)
  148. if(force)
  149. return clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
  150. else
  151. return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
  152. /mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
  153. var/message_verb = "attacked"
  154. if(I.attack_verb && I.attack_verb.len)
  155. message_verb = "[pick(I.attack_verb)]"
  156. else if(!I.force)
  157. return
  158. var/message_hit_area = ""
  159. if(hit_area)
  160. message_hit_area = " in the [hit_area]"
  161. var/attack_message = "[src] is [message_verb][message_hit_area] with [I]!"
  162. var/attack_message_local = "You're [message_verb][message_hit_area] with [I]!"
  163. if(user in viewers(src, null))
  164. attack_message = "[user] [message_verb] [src][message_hit_area] with [I]!"
  165. attack_message_local = "[user] [message_verb] you[message_hit_area] with [I]!"
  166. if(user == src)
  167. attack_message_local = "You [message_verb] yourself[message_hit_area] with [I]"
  168. visible_message("<span class='danger'>[attack_message]</span>",\
  169. "<span class='userdanger'>[attack_message_local]</span>", null, COMBAT_MESSAGE_RANGE)
  170. return 1