|
25 | 25 | var/proj_trail_icon_state = "trail" |
26 | 26 | /// Any extant trail effects. |
27 | 27 | var/list/proj_trails |
| 28 | + /// An effect to spawn when a non-hitscan projectile collides with a target. |
| 29 | + var/impact_effect_type |
| 30 | + /// A sound to play when striking a non-mob (hitsound is used for mobs) |
| 31 | + var/hitsound_non_mob |
28 | 32 |
|
29 | 33 | var/bumped = 0 //Prevents it from hitting more than one guy at once |
30 | 34 | var/def_zone = "" //Aiming at |
|
73 | 77 |
|
74 | 78 | var/fire_sound |
75 | 79 | var/fire_sound_vol = 50 |
76 | | - var/miss_sounds |
77 | | - var/ricochet_sounds |
78 | | - var/list/impact_sounds //for different categories, IMPACT_MEAT etc |
| 80 | + var/fire_sound_vol_silenced = 10 |
79 | 81 | var/shrapnel_type = /obj/item/shard/shrapnel |
80 | 82 |
|
81 | 83 | var/vacuum_traversal = 1 //Determines if the projectile can exist in vacuum, if false, the projectile will be deleted if it enters vacuum. |
|
131 | 133 |
|
132 | 134 | //called when the projectile stops flying because it collided with something |
133 | 135 | /obj/item/projectile/proc/on_impact(var/atom/A) |
| 136 | + |
| 137 | + impact_sounds(A) |
| 138 | + impact_visuals(A) |
| 139 | + |
134 | 140 | if(damage && atom_damage_type == BURN) |
135 | 141 | var/turf/T = get_turf(A) |
136 | 142 | if(T) |
|
208 | 214 |
|
209 | 215 | //Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying. |
210 | 216 | /obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/special_miss_modifier=0) |
| 217 | + SHOULD_CALL_PARENT(TRUE) |
211 | 218 | if(!istype(target_mob)) |
212 | 219 | return |
213 | 220 |
|
|
234 | 241 | if(result == PROJECTILE_FORCE_MISS) |
235 | 242 | if(!silenced) |
236 | 243 | target_mob.visible_message("<span class='notice'>\The [src] misses [target_mob] narrowly!</span>") |
| 244 | + var/list/miss_sounds = get_miss_sounds() |
237 | 245 | if(LAZYLEN(miss_sounds)) |
238 | 246 | playsound(target_mob.loc, pick(miss_sounds), 60, 1) |
239 | 247 | return FALSE |
240 | 248 |
|
241 | 249 | //hit messages |
242 | 250 | if(silenced) |
243 | | - to_chat(target_mob, "<span class='danger'>You've been hit in the [parse_zone(def_zone)] by \the [src]!</span>") |
| 251 | + to_chat(target_mob, SPAN_DANGER("You've been hit in the [parse_zone(def_zone)] by \the [src]!")) |
| 252 | + if(hitsound) |
| 253 | + var/impact_volume = get_impact_volume_by_damage() |
| 254 | + if(impact_volume) |
| 255 | + playsound(target_mob, hitsound, impact_volume, 1, -1) |
244 | 256 | else |
245 | 257 | target_mob.visible_message("<span class='danger'>\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!</span>")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter |
246 | 258 |
|
|
672 | 684 |
|
673 | 685 | /obj/item/projectile/proc/update_effect(var/obj/effect/projectile/effect) |
674 | 686 | return |
| 687 | + |
| 688 | +/obj/item/projectile/proc/get_projectile_damage(mob/living/target) |
| 689 | + return damage |
| 690 | + |
| 691 | + |
| 692 | +// Makes a brief effect sprite appear when the projectile hits something solid. |
| 693 | +/obj/item/projectile/proc/impact_visuals(atom/A, hit_x, hit_y) |
| 694 | + // Hitscan things have their own impact sprite. |
| 695 | + if(!impact_effect_type || hitscan) |
| 696 | + return |
| 697 | + if(isnull(hit_x) && isnull(hit_y)) |
| 698 | + if(trajectory) |
| 699 | + // Effect goes where the projectile 'stopped'. |
| 700 | + hit_x = A.pixel_x + trajectory.return_px() |
| 701 | + hit_y = A.pixel_y + trajectory.return_py() |
| 702 | + else if(A == original) |
| 703 | + // Otherwise it goes where the person who fired clicked. |
| 704 | + hit_x = A.pixel_x + p_x - 16 |
| 705 | + hit_y = A.pixel_y + p_y - 16 |
| 706 | + else |
| 707 | + // Otherwise it'll be random. |
| 708 | + hit_x = A.pixel_x + rand(-8, 8) |
| 709 | + hit_y = A.pixel_y + rand(-8, 8) |
| 710 | + new impact_effect_type(get_turf(A), src, hit_x, hit_y) |
| 711 | + |
| 712 | +/obj/item/projectile/proc/get_impact_volume_by_damage() |
| 713 | + if(damage || agony) |
| 714 | + var/value_to_use = damage > agony ? damage : agony |
| 715 | + // Multiply projectile damage by 1.2, then CLAMP the value between 30 and 100. |
| 716 | + // This was 0.67 but in practice it made all projectiles that did 45 or less damage play at 30, |
| 717 | + // which is hard to hear over the gunshots, and is rather rare for a projectile to do that much. |
| 718 | + return clamp((value_to_use) * 1.2, 30, 100) |
| 719 | + return 50 //if the projectile doesn't do damage or agony, play its hitsound at 50% volume. |
| 720 | + |
| 721 | +/obj/item/projectile/proc/impact_sounds(atom/A) |
| 722 | + |
| 723 | + var/play_volume = clamp(get_impact_volume_by_damage() + 20, 0, 100) |
| 724 | + if(play_volume <= 0) |
| 725 | + return |
| 726 | + if(silenced) |
| 727 | + play_volume = min(play_volume, 5) |
| 728 | + |
| 729 | + var/play_sound |
| 730 | + if(ismob(A)) // Mob sounds are handled in attack_mob(). |
| 731 | + play_sound = hitsound |
| 732 | + else |
| 733 | + play_sound = hitsound_non_mob |
| 734 | + if(!play_sound) |
| 735 | + return |
| 736 | + playsound(A, play_sound, play_volume, 1, -1) |
| 737 | + |
| 738 | +/obj/item/projectile/proc/get_miss_sounds() |
| 739 | + return |
| 740 | + |
| 741 | +/obj/item/projectile/proc/get_ricochet_sounds() |
| 742 | + return |
| 743 | + |
| 744 | +/obj/item/projectile/proc/get_impact_sounds() |
| 745 | + return |
0 commit comments