game: add bleed
This commit is contained in:
		| @@ -3,7 +3,7 @@ | ||||
| name="Linux" | ||||
| platform="Linux" | ||||
| runnable=true | ||||
| advanced_options=false | ||||
| advanced_options=true | ||||
| dedicated_server=false | ||||
| custom_features="" | ||||
| export_filter="all_resources" | ||||
|   | ||||
							
								
								
									
										7
									
								
								scenes/enemies/effects/enemy_effect_base.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								scenes/enemies/effects/enemy_effect_base.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| class_name EnemyEffectBase | ||||
| extends Resource | ||||
|  | ||||
| var enemy: EnemyBase | ||||
|  | ||||
| func apply(enemy: EnemyBase) -> void: | ||||
| 	push_error("%s does not implement apply" % self) | ||||
							
								
								
									
										1
									
								
								scenes/enemies/effects/enemy_effect_base.gd.uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								scenes/enemies/effects/enemy_effect_base.gd.uid
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| uid://dg3yshxb4vdiu | ||||
							
								
								
									
										29
									
								
								scenes/enemies/effects/enemy_effect_bleed.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								scenes/enemies/effects/enemy_effect_bleed.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| class_name EnemyEffectBleed | ||||
| extends EnemyEffectBase | ||||
|  | ||||
| var damage: float | ||||
| var duration: float | ||||
| var tick_rate: float = 1.0 | ||||
|  | ||||
| var _timer: Timer | ||||
| var _remaining_ticks: int = 5 | ||||
| var _enemy: EnemyBase | ||||
|  | ||||
| const PUDDLE = preload("res://scenes/puddle.tscn") | ||||
|  | ||||
| func _init(enemy: EnemyBase, damage: float, duration: float): | ||||
| 	_timer = Timer.new() | ||||
|  | ||||
| func apply(enemy: EnemyBase) -> void: | ||||
| 	enemy.effects.append(self) | ||||
| 	while _remaining_ticks > 0: | ||||
| 		_remaining_ticks -= 1 | ||||
| 		var tree = enemy.get_tree() | ||||
| 		await enemy.get_tree().create_timer(1.0, false, true, false).timeout | ||||
| 		var p = PUDDLE.instantiate() | ||||
| 		enemy.get_parent().add_child(p) | ||||
| 		p.global_position = enemy.global_position | ||||
| 	enemy.effects.erase(self) | ||||
|  | ||||
| static func _is_bleeding(enemy: EnemyBase) -> bool: | ||||
| 	return false | ||||
							
								
								
									
										1
									
								
								scenes/enemies/effects/enemy_effect_bleed.gd.uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								scenes/enemies/effects/enemy_effect_bleed.gd.uid
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| uid://b2ptwltm211t3 | ||||
| @@ -17,7 +17,9 @@ var modifiers: Array[EnemyMod] = [] | ||||
| @onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D | ||||
| @onready var shape_cast_2d: ShapeCast2D = $ShapeCast2D | ||||
| @onready var sprite_2d: Sprite2D = $Sprite2D | ||||
| @onready var label: Label = $Label | ||||
| @onready var label: Label = $HBoxContainer/Label | ||||
| @onready var effect_container: HBoxContainer = $HBoxContainer/EffectContainer | ||||
|  | ||||
|  | ||||
| var player: Player | ||||
| var enemy_name: String | ||||
| @@ -26,9 +28,11 @@ var god_mode: bool = false | ||||
| var is_dead: bool = false | ||||
| var health: float | ||||
|  | ||||
| var effects: Array[EnemyEffectBase] | ||||
|  | ||||
| var _path_update_timer: float = 0.0 | ||||
| var _compute_cache: KeyedCache = KeyedCache.new() | ||||
|  | ||||
| var _effects_visible = [] | ||||
|  | ||||
| func _ready() -> void: | ||||
| 	enemy_name = _gen_name() | ||||
| @@ -63,6 +67,15 @@ func _find_player(): | ||||
| func _gen_name() -> String: | ||||
| 	return "Unnamed enemy" | ||||
|  | ||||
| func _process(delta: float) -> void: | ||||
| 	for effect in effects: | ||||
| 		if effect in _effects_visible: | ||||
| 			continue | ||||
| 		var effect_sprite = Sprite2D.new() | ||||
| 		effect_sprite.texture = preload("res://assets/sprites/small_bleed_icon.png") | ||||
| 		effect_container.add_child(effect_sprite) | ||||
| 		_effects_visible.append(effect) | ||||
| 		 | ||||
|  | ||||
| func _physics_process(delta: float) -> void: | ||||
| 	if not target: | ||||
|   | ||||
| @@ -90,20 +90,25 @@ wait_time = 0.5 | ||||
| shape = SubResource("CircleShape2D_pkqou") | ||||
| max_results = 2 | ||||
|  | ||||
| [node name="Label" type="Label" parent="."] | ||||
| anchors_preset = 7 | ||||
| [node name="HBoxContainer" type="HBoxContainer" parent="."] | ||||
| anchors_preset = 8 | ||||
| anchor_left = 0.5 | ||||
| anchor_top = 1.0 | ||||
| anchor_top = 0.5 | ||||
| anchor_right = 0.5 | ||||
| anchor_bottom = 1.0 | ||||
| offset_left = -85.5 | ||||
| offset_top = 5.0 | ||||
| offset_right = 85.5 | ||||
| offset_bottom = 28.0 | ||||
| anchor_bottom = 0.5 | ||||
| offset_left = -53.0 | ||||
| offset_right = 53.0 | ||||
| offset_bottom = 40.0 | ||||
| grow_horizontal = 2 | ||||
| grow_vertical = 0 | ||||
| grow_vertical = 2 | ||||
|  | ||||
| [node name="EffectContainer" type="HBoxContainer" parent="HBoxContainer"] | ||||
| layout_mode = 2 | ||||
| size_flags_vertical = 4 | ||||
|  | ||||
| [node name="Label" type="Label" parent="HBoxContainer"] | ||||
| layout_mode = 2 | ||||
| theme_override_font_sizes/font_size = 9 | ||||
| text = "Unnamed the Adjective" | ||||
| horizontal_alignment = 1 | ||||
|  | ||||
| [connection signal="animation_finished" from="AnimationPlayer" to="." method="_on_animation_player_animation_finished"] | ||||
|   | ||||
| @@ -115,4 +115,3 @@ func _on_set_spawn_rate(val: float): | ||||
| 	timer.stop() | ||||
| 	timer.wait_time = 1.0 / val | ||||
| 	timer.start() | ||||
| 	print_debug("spawn_rate: %s" % timer.wait_time) | ||||
|   | ||||
| @@ -29,11 +29,7 @@ func _ready() -> void: | ||||
| 	if not weapon: | ||||
| 		weapon = WEAPON_SWORD.instantiate() | ||||
| 		add_child(weapon) | ||||
| 		var mod = WeaponModBase.new() | ||||
| 		mod.mod_property = "attack_damage" | ||||
| 		mod.mod_value = 10.0 | ||||
| 		mod.mod_type = WeaponModBase.ModType.ADDITIVE | ||||
| 		weapon.add_mod(mod) | ||||
|  | ||||
|  | ||||
|  | ||||
| func _physics_process(delta: float) -> void: | ||||
|   | ||||
							
								
								
									
										21
									
								
								scenes/puddle.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								scenes/puddle.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| class_name Puddle | ||||
| extends Node2D | ||||
|  | ||||
| @export var color: Color = Color.CRIMSON | ||||
| @onready var base: Sprite2D = $Base | ||||
|  | ||||
| func _ready() -> void: | ||||
| 	var player: Player = get_tree().get_first_node_in_group(GlobalConst.GROUP_PLAYER) | ||||
| 	var shader = preload("res://assets/shaders/base_color_tint.gdshader") | ||||
| 	var shader_material: ShaderMaterial | ||||
| 	shader_material = ShaderMaterial.new() | ||||
| 	shader_material.set_shader_parameter("base_color", color) | ||||
| 	shader_material.shader = shader | ||||
| 	base.material = shader_material | ||||
| 	match randi() % 4: | ||||
| 		1: | ||||
| 			rotation_degrees = 90 | ||||
| 		2: | ||||
| 			rotation_degrees = 180 | ||||
| 		3: | ||||
| 			rotation_degrees = -90 | ||||
							
								
								
									
										1
									
								
								scenes/puddle.gd.uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								scenes/puddle.gd.uid
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| uid://cds5aqq2mqmpe | ||||
							
								
								
									
										34
									
								
								scenes/puddle.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								scenes/puddle.tscn
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| [gd_scene load_steps=8 format=3 uid="uid://dcka1mmlgeoj7"] | ||||
|  | ||||
| [ext_resource type="Shader" uid="uid://cf48pgfl308o3" path="res://assets/shaders/base_color_tint.gdshader" id="1_qlq6d"] | ||||
| [ext_resource type="Script" uid="uid://cds5aqq2mqmpe" path="res://scenes/puddle.gd" id="1_s8xbh"] | ||||
| [ext_resource type="Texture2D" uid="uid://c5t4it4if0s6g" path="res://assets/sprites/puddle_1.png" id="2_s8xbh"] | ||||
|  | ||||
| [sub_resource type="ShaderMaterial" id="ShaderMaterial_i64cl"] | ||||
| shader = ExtResource("1_qlq6d") | ||||
| shader_parameter/base_color = Color(1, 0.2, 0.2, 1) | ||||
|  | ||||
| [sub_resource type="AtlasTexture" id="AtlasTexture_h42jt"] | ||||
| atlas = ExtResource("2_s8xbh") | ||||
| region = Rect2(0, 0, 16, 13) | ||||
|  | ||||
| [sub_resource type="AtlasTexture" id="AtlasTexture_16dvh"] | ||||
| atlas = ExtResource("2_s8xbh") | ||||
| region = Rect2(32, 0, 16, 13) | ||||
|  | ||||
| [sub_resource type="AtlasTexture" id="AtlasTexture_5nuq4"] | ||||
| atlas = ExtResource("2_s8xbh") | ||||
| region = Rect2(16, 0, 16, 13) | ||||
|  | ||||
| [node name="Puddle" type="Node2D"] | ||||
| script = ExtResource("1_s8xbh") | ||||
|  | ||||
| [node name="Base" type="Sprite2D" parent="."] | ||||
| material = SubResource("ShaderMaterial_i64cl") | ||||
| texture = SubResource("AtlasTexture_h42jt") | ||||
|  | ||||
| [node name="Highlights" type="Sprite2D" parent="."] | ||||
| texture = SubResource("AtlasTexture_16dvh") | ||||
|  | ||||
| [node name="Shading" type="Sprite2D" parent="."] | ||||
| texture = SubResource("AtlasTexture_5nuq4") | ||||
| @@ -4,6 +4,8 @@ extends Node2D | ||||
| enum WeaponTag { | ||||
| 	CAN_RETURN, | ||||
| 	CAN_BLEED, | ||||
| 	CAN_CHAIN, | ||||
| 	CAN_FORK, | ||||
| } | ||||
|  | ||||
| @export var attack_cd: float | ||||
| @@ -12,11 +14,19 @@ enum WeaponTag { | ||||
| @export var attack_duration: float | ||||
| @export var attack_range: float | ||||
| @export var attack_crit_chance: float = 0.05 | ||||
| @export var return_chance: float = 0.0 | ||||
| @export var bleed_chance: float = 0.0 | ||||
| @export var bleed_duration: float = 5.0 | ||||
| @export var chain_chance: float = 0.0 | ||||
| @export var tags: Array[String] = [] | ||||
| @export var modifiers: Array[WeaponModBase] = [] | ||||
|  | ||||
| @onready var active_cd_timer: Timer = $ActiveCDTimer | ||||
|  | ||||
| var _player: Player | ||||
|  | ||||
| func _ready() -> void: | ||||
| 	_player = get_tree().get_first_node_in_group(GlobalConst.GROUP_PLAYER) | ||||
|  | ||||
| func _on_attack_cd_timer_timeout() -> void: | ||||
| 	do_attack() | ||||
| @@ -76,3 +86,19 @@ func has_property(key: String) -> bool: | ||||
| 		if prop.name == key: | ||||
| 			return true | ||||
| 	return false | ||||
|  | ||||
| func did_crit() -> bool: | ||||
| 	var weapon_crit = get_calculated("attack_crit_chance") | ||||
| 	var player_crit = _player.player_stats.get_final("crit_chance", _player.modifiers) | ||||
|  | ||||
| 	return randf() >= 1 - weapon_crit + player_crit | ||||
|  | ||||
| func did_bleed() -> bool: | ||||
| 	return randf() >= 1 - bleed_chance | ||||
|  | ||||
| func base_damage() -> Array[Variant]: | ||||
| 	var damage = get_calculated("attack_damage") | ||||
| 	var is_crit := did_crit() | ||||
| 	if is_crit: | ||||
| 		damage *= _player.player_stats.get_final("crit_multiplier", _player.modifiers) | ||||
| 	return [damage, is_crit] | ||||
|   | ||||
| @@ -8,13 +8,14 @@ const WEAPON_SWORD_PROJECTILE = preload("res://scenes/weapons/weapon_sword_proje | ||||
|  | ||||
| signal projectile_hit(projectile: WeaponSwordProjectile, enemy: EnemyBase) | ||||
|  | ||||
| var _player: Player | ||||
|  | ||||
|  | ||||
|  | ||||
| func _ready() -> void: | ||||
| 	bleed_chance = 0.2 | ||||
| 	targeting_range_shape.shape.radius = attack_range | ||||
| 	projectile_hit.connect(_on_projectile_hit) | ||||
| 	_player = get_tree().get_first_node_in_group(GlobalConst.GROUP_PLAYER) | ||||
| 	super._ready() | ||||
|  | ||||
|  | ||||
| func do_attack() -> void: | ||||
| @@ -44,13 +45,13 @@ func _do_active() -> void: | ||||
|  | ||||
|  | ||||
| func deal_damage(enemy: EnemyBase, damage_mult: float): | ||||
| 	var weapon_crit = get_calculated("attack_crit_chance") | ||||
| 	var player_crit = _player.player_stats.get_final("crit_chance", _player.modifiers) | ||||
| 	var damage = get_calculated("attack_damage") | ||||
| 	var is_crit = randf() >= 1 - weapon_crit + player_crit | ||||
| 	if is_crit: | ||||
| 		damage *= _player.player_stats.get_final("crit_multiplier", _player.modifiers) | ||||
| 	enemy.take_damage(damage * damage_mult, is_crit) | ||||
| 	var damage_and_crit = base_damage() | ||||
| 	# TODO: Fix crit value | ||||
| 	enemy.take_damage(damage_and_crit[0], damage_and_crit[1]) | ||||
| 	 | ||||
| 	if did_bleed(): | ||||
| 		var bleed = EnemyEffectBleed.new(enemy, damage_and_crit[0], bleed_duration) | ||||
| 		bleed.apply(enemy) | ||||
|  | ||||
|  | ||||
| func _on_projectile_hit(projectile: WeaponSwordProjectile, enemy: EnemyBase, damage_mult: float): | ||||
|   | ||||
| @@ -5,6 +5,7 @@ extends Node2D | ||||
| @export var range: float = 200.0 | ||||
| @export var target: Node2D | ||||
| @export var damage_mult: float = 1.0 | ||||
| @export var bleed_chance: float = 0.2 | ||||
| @export var on_hit_sig: Signal | ||||
|  | ||||
| var _direction: Vector2 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user