Many changes

Handle it
This commit is contained in:
Dan Baker 2025-05-04 09:30:14 +01:00
parent bf09402bc5
commit 214e0aa5e0
366 changed files with 24353 additions and 2096 deletions

View file

@ -0,0 +1,63 @@
class_name Ability extends Node2D
@export var cooldown: float = 5.0
@export var effect_duration: float = 3.0
var modifiers: Array = []
var can_activate: bool = true
var cooldown_timer: Timer
var effect_timer: Timer
var is_active: bool = false
func _ready():
cooldown_timer = Timer.new()
add_child(cooldown_timer)
cooldown_timer.one_shot = true
cooldown_timer.connect("timeout", _on_cooldown_timeout)
effect_timer = Timer.new()
add_child(effect_timer)
effect_timer.one_shot = true
effect_timer.connect("timeout", _on_effect_timeout)
func activate():
if !can_activate:
return
# Apply ability effects
_start_ability()
# Apply modifiers to the ability
for modifier in modifiers:
modifier.modify_ability(self)
is_active = true
can_activate = false
effect_timer.start(effect_duration)
func add_modifier(modifier: Modifier):
modifiers.append(modifier)
modifier.on_equip(self)
func remove_modifier(modifier_id: String):
for i in range(modifiers.size()):
if modifiers[i].id == modifier_id:
modifiers[i].on_unequip(self)
modifiers.remove_at(i)
break
# Override in child classes
func _start_ability():
pass
# Override in child classes
func _end_ability():
pass
func _on_effect_timeout():
is_active = false
_end_ability()
cooldown_timer.start(cooldown)
func _on_cooldown_timeout():
can_activate = true

View file

@ -0,0 +1 @@
uid://hhd27rd8ii8j

View file

@ -0,0 +1,23 @@
class_name IceFieldAbility extends Ability
@export var field_radius: float = 150.0
@export var damage_per_second: float = 5.0
@export var slow_amount: float = 0.5
var field_instance: Node2D
func _init():
cooldown = 10.0
effect_duration = 6.0
func _start_ability():
field_instance = preload("scenes/ice_field.tscn").instantiate()
field_instance.global_position = global_position
field_instance.radius = field_radius
field_instance.damage = damage_per_second
field_instance.slow = slow_amount
get_tree().root.add_child(field_instance)
func _end_ability():
if is_instance_valid(field_instance):
field_instance.queue_free()

View file

@ -0,0 +1 @@
uid://cs28213tcth26

View file

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://btymtl71y0hx7"]
[sub_resource type="ImageTexture" id="ImageTexture_6kos1"]
[node name="IceField" type="Node2D"]
[node name="Sprite2D" type="Sprite2D" parent="."]
texture = SubResource("ImageTexture_6kos1")

View file

@ -0,0 +1,13 @@
class_name FireRateAdditive extends Modifier
@export var fire_rate_bonus: float = 1.0 # +1 shot per second
func _init():
id = "fire_rate_additive"
display_name = "Rapid Fire"
description = "Increases fire rate by %0.1f shots per second" % fire_rate_bonus
modifier_type = ModifierType.ADDITIVE
func apply_stats_modification(final_stats: Dictionary, base_stats: Dictionary) -> void:
if final_stats.has("fire_rate"):
final_stats.fire_rate += fire_rate_bonus

View file

@ -0,0 +1 @@
uid://cqamoc42g8sam

View file

@ -0,0 +1,13 @@
class_name FireRateMultiplicative extends Modifier
@export var fire_rate_multiplier: float = 1.2 # 20% faster firing
func _init():
id = "fire_rate_multiplicative"
display_name = "Frenzy"
description = "Increases fire rate by %d%%" % ((fire_rate_multiplier - 1.0) * 100)
modifier_type = ModifierType.MULTIPLICATIVE
func apply_stats_modification(final_stats: Dictionary, base_stats: Dictionary) -> void:
if final_stats.has("fire_rate"):
final_stats.fire_rate *= fire_rate_multiplier

View file

@ -0,0 +1 @@
uid://bbqp2rhogkicu

View file

@ -0,0 +1,31 @@
class_name Modifier extends Resource
enum ModifierType {
ADDITIVE, # Simply adds values (e.g., +5 damage)
MULTIPLICATIVE, # Multiplies by a percentage (e.g., 20% more damage)
OVERRIDE, # Completely replaces the value
CONDITIONAL # Applies under certain conditions
}
@export var id: String
@export var display_name: String
@export var description: String
@export var icon: Texture
@export var rarity: int
@export var modifier_type: ModifierType = ModifierType.ADDITIVE
@export var priority: int = 0 # Higher priority modifiers apply first
# Called when the modifier is added to a weapon or ability
func on_equip(_owner) -> void:
pass
# Called when the modifier is removed
func on_unequip(_owner) -> void:
pass
# Override in child classes for specific modification logic
func modify_projectile(_projectile) -> void:
pass
func modify_ability(_ability) -> void:
pass

View file

@ -0,0 +1 @@
uid://c2vpdeqk0vvrg

View file

@ -0,0 +1,18 @@
class_name PiercingModifier extends Modifier
@export var pierce_count: int = 2
func _init():
id = "piercing"
display_name = "Piercing Shot"
description = "Projectiles pass through %d enemies" % pierce_count
func modify_projectile(projectile):
projectile.pierce_count = pierce_count
projectile.connect("on_hit", _on_projectile_hit)
func _on_projectile_hit(projectile, _target):
projectile.pierce_count -= 1
if projectile.pierce_count <= 0:
projectile.pierce_count = 0
projectile.set_piercing(false)

View file

@ -0,0 +1 @@
uid://b60nonvh7ml2o

View file

@ -0,0 +1,25 @@
class_name ProjectileSizeAdditive extends Modifier
@export var size_increase: float = 0.5 # +50% bigger
func _init():
id = "size_additive"
display_name = "Enlarged Projectiles"
description = "Increases projectile size by %d%%" % (size_increase * 100)
modifier_type = ModifierType.ADDITIVE
func apply_stats_modification(final_stats: Dictionary, base_stats: Dictionary) -> void:
if final_stats.has("projectile_size"):
final_stats.projectile_size += size_increase
func modify_projectile(projectile) -> void:
# This will be called when the projectile is created
# Scale is often handled in the recalculate_stats method, but we can also add visual effects here
projectile.connect("on_spawned", _on_projectile_spawned)
func _on_projectile_spawned(projectile):
# Add a trail effect for larger projectiles
if projectile.scale.x > 1.2:
pass
#var trail = preload("res://scenes/projectile_trail.tscn").instantiate()
#projectile.add_child(trail)

View file

@ -0,0 +1 @@
uid://hsl3es4bcvqf

View file

@ -0,0 +1,14 @@
class_name ProjectileSizeMultiplicative extends Modifier
@export var size_multiplier: float = 1.5 # 50% bigger
func _init():
id = "size_multiplicative"
display_name = "Giant Projectiles"
description = "Multiplies projectile size by %0.1fx" % size_multiplier
modifier_type = ModifierType.MULTIPLICATIVE
priority = 10 # Higher priority than the additive version
func apply_stats_modification(final_stats: Dictionary, base_stats: Dictionary) -> void:
if final_stats.has("projectile_size"):
final_stats.projectile_size *= size_multiplier

View file

@ -0,0 +1 @@
uid://bvfir8srnaraa

558
player/player.tscn Normal file
View file

@ -0,0 +1,558 @@
[gd_scene load_steps=82 format=3 uid="uid://bo5aw2cad3akl"]
[ext_resource type="Script" uid="uid://bq038uo4cm6nv" path="res://player/scripts/player.gd" id="1_oul6g"]
[ext_resource type="Texture2D" uid="uid://dqgq2c1h6yk3k" path="res://assets/sprites/characters/pink/Pink_Monster_Attack1_4.png" id="2_yllr7"]
[ext_resource type="Texture2D" uid="uid://dinwwco5v2km5" path="res://assets/sprites/characters/pink/Pink_Monster_Attack2_6.png" id="3_kb6p2"]
[ext_resource type="Texture2D" uid="uid://bx6nst3hqsww0" path="res://assets/sprites/characters/pink/Pink_Monster_Climb_4.png" id="4_wodsf"]
[ext_resource type="Texture2D" uid="uid://0muqa26ngic7" path="res://assets/sprites/characters/pink/Pink_Monster_Death_8.png" id="5_32hag"]
[ext_resource type="Texture2D" uid="uid://nyfqe1b4k8sx" path="res://assets/sprites/characters/pink/Pink_Monster_Hurt_4.png" id="6_tqiix"]
[ext_resource type="Texture2D" uid="uid://b6ihjsu8qhm2x" path="res://assets/sprites/characters/pink/Pink_Monster_Idle_4.png" id="7_e7oew"]
[ext_resource type="Texture2D" uid="uid://hnw46ye6vusn" path="res://assets/sprites/characters/pink/Pink_Monster_Jump_8.png" id="8_c35mf"]
[ext_resource type="Texture2D" uid="uid://dun0f0rkhaew5" path="res://assets/sprites/characters/pink/Pink_Monster_Push_6.png" id="9_65viv"]
[ext_resource type="Texture2D" uid="uid://cx2x6p0dnnm6y" path="res://assets/sprites/characters/pink/Pink_Monster_Run_6.png" id="10_x7c3f"]
[ext_resource type="Texture2D" uid="uid://538sc3bsdell" path="res://assets/sprites/characters/pink/Pink_Monster_Throw_4.png" id="11_bjvpn"]
[ext_resource type="Texture2D" uid="uid://efnfh4mf0ia2" path="res://assets/sprites/characters/pink/Pink_Monster_Walk_6.png" id="12_s7qer"]
[ext_resource type="Texture2D" uid="uid://cyfq0x0h2qeof" path="res://assets/sprites/characters/pink/Pink_Monster_Walk+Attack_6.png" id="13_g4c7l"]
[sub_resource type="CircleShape2D" id="CircleShape2D_rkbax"]
[sub_resource type="AtlasTexture" id="AtlasTexture_knn7v"]
atlas = ExtResource("2_yllr7")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_7pqkx"]
atlas = ExtResource("2_yllr7")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_uw77l"]
atlas = ExtResource("2_yllr7")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_rptt4"]
atlas = ExtResource("2_yllr7")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_r7pn3"]
atlas = ExtResource("3_kb6p2")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_b8hi5"]
atlas = ExtResource("3_kb6p2")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_2uvqg"]
atlas = ExtResource("3_kb6p2")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_1s1yo"]
atlas = ExtResource("3_kb6p2")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_5ejfk"]
atlas = ExtResource("3_kb6p2")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_jd2rm"]
atlas = ExtResource("3_kb6p2")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_q28gw"]
atlas = ExtResource("4_wodsf")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_ge24q"]
atlas = ExtResource("4_wodsf")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_pnw6m"]
atlas = ExtResource("4_wodsf")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_1so5t"]
atlas = ExtResource("4_wodsf")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_55jnj"]
atlas = ExtResource("5_32hag")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_dx5ib"]
atlas = ExtResource("5_32hag")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_a2xo5"]
atlas = ExtResource("5_32hag")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_art4l"]
atlas = ExtResource("5_32hag")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_fjxoa"]
atlas = ExtResource("5_32hag")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_gswnw"]
atlas = ExtResource("5_32hag")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_xcnuv"]
atlas = ExtResource("5_32hag")
region = Rect2(192, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_j55il"]
atlas = ExtResource("5_32hag")
region = Rect2(224, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_hjies"]
atlas = ExtResource("6_tqiix")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_mmwog"]
atlas = ExtResource("6_tqiix")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_8pxes"]
atlas = ExtResource("6_tqiix")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_fmu53"]
atlas = ExtResource("6_tqiix")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_w7j2h"]
atlas = ExtResource("7_e7oew")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_n0b8q"]
atlas = ExtResource("7_e7oew")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_jfgyi"]
atlas = ExtResource("7_e7oew")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_237xx"]
atlas = ExtResource("7_e7oew")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_wpyo2"]
atlas = ExtResource("8_c35mf")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_7crtr"]
atlas = ExtResource("8_c35mf")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_vgvch"]
atlas = ExtResource("8_c35mf")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_a1u5o"]
atlas = ExtResource("8_c35mf")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_3dxkp"]
atlas = ExtResource("8_c35mf")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_6wior"]
atlas = ExtResource("8_c35mf")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_p5tca"]
atlas = ExtResource("8_c35mf")
region = Rect2(192, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_jbx34"]
atlas = ExtResource("8_c35mf")
region = Rect2(224, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_s3g0c"]
atlas = ExtResource("9_65viv")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_35wys"]
atlas = ExtResource("9_65viv")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_pjwc4"]
atlas = ExtResource("9_65viv")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_or4qq"]
atlas = ExtResource("9_65viv")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_hggc2"]
atlas = ExtResource("9_65viv")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_b2j0d"]
atlas = ExtResource("9_65viv")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_7l6ig"]
atlas = ExtResource("10_x7c3f")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_j3r50"]
atlas = ExtResource("10_x7c3f")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_utr5e"]
atlas = ExtResource("10_x7c3f")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_kewli"]
atlas = ExtResource("10_x7c3f")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_do7qw"]
atlas = ExtResource("10_x7c3f")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_2h6tc"]
atlas = ExtResource("10_x7c3f")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_8rogd"]
atlas = ExtResource("11_bjvpn")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_48p26"]
atlas = ExtResource("11_bjvpn")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_anp34"]
atlas = ExtResource("11_bjvpn")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_jdjat"]
atlas = ExtResource("11_bjvpn")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_j420s"]
atlas = ExtResource("12_s7qer")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_kcq4v"]
atlas = ExtResource("12_s7qer")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_qavcc"]
atlas = ExtResource("12_s7qer")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_bd26m"]
atlas = ExtResource("12_s7qer")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_lufic"]
atlas = ExtResource("12_s7qer")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_nxclr"]
atlas = ExtResource("12_s7qer")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_onxu2"]
atlas = ExtResource("13_g4c7l")
region = Rect2(0, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_gci7n"]
atlas = ExtResource("13_g4c7l")
region = Rect2(32, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_tcwf7"]
atlas = ExtResource("13_g4c7l")
region = Rect2(64, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_20bc7"]
atlas = ExtResource("13_g4c7l")
region = Rect2(96, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_jfgxe"]
atlas = ExtResource("13_g4c7l")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_yg0n1"]
atlas = ExtResource("13_g4c7l")
region = Rect2(160, 0, 32, 32)
[sub_resource type="SpriteFrames" id="SpriteFrames_qjt2w"]
animations = [{
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_knn7v")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_7pqkx")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_uw77l")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_rptt4")
}],
"loop": true,
"name": &"attack_1",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_r7pn3")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_b8hi5")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_2uvqg")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_1s1yo")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_5ejfk")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_jd2rm")
}],
"loop": true,
"name": &"attack_2",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_q28gw")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ge24q")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_pnw6m")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1so5t")
}],
"loop": true,
"name": &"climb",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_55jnj")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_dx5ib")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_a2xo5")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_art4l")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_fjxoa")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_gswnw")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_xcnuv")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_j55il")
}],
"loop": true,
"name": &"death",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_hjies")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_mmwog")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_8pxes")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_fmu53")
}],
"loop": true,
"name": &"hurt",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_w7j2h")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_n0b8q")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_jfgyi")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_237xx")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_wpyo2")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_7crtr")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_vgvch")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_a1u5o")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_3dxkp")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_6wior")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_p5tca")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_jbx34")
}],
"loop": true,
"name": &"jump",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_s3g0c")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_35wys")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_pjwc4")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_or4qq")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_hggc2")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_b2j0d")
}],
"loop": true,
"name": &"push",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_7l6ig")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_j3r50")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_utr5e")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_kewli")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_do7qw")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_2h6tc")
}],
"loop": true,
"name": &"run",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_8rogd")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_48p26")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_anp34")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_jdjat")
}],
"loop": true,
"name": &"throw",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_j420s")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_kcq4v")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_qavcc")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_bd26m")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_lufic")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_nxclr")
}],
"loop": true,
"name": &"walk",
"speed": 5.0
}, {
"frames": [{
"duration": 0.5,
"texture": SubResource("AtlasTexture_onxu2")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_gci7n")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_tcwf7")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_20bc7")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_jfgxe")
}, {
"duration": 0.5,
"texture": SubResource("AtlasTexture_yg0n1")
}],
"loop": true,
"name": &"walk_attack",
"speed": 5.0
}]
[node name="Player" type="CharacterBody2D"]
collision_mask = 14
script = ExtResource("1_oul6g")
[node name="PlayerCollision" type="CollisionShape2D" parent="."]
position = Vector2(0, 7)
shape = SubResource("CircleShape2D_rkbax")
[node name="PlayerSprite" type="AnimatedSprite2D" parent="."]
sprite_frames = SubResource("SpriteFrames_qjt2w")
animation = &"attack_2"
frame_progress = 0.752485
[node name="Camera2D" type="Camera2D" parent="."]
zoom = Vector2(2, 2)

View file

@ -0,0 +1,84 @@
class_name ModifierManager extends Node
signal modifier_added(modifier)
signal modifier_removed(modifier)
signal stats_updated()
# Stores all active modifiers
var modifiers: Array[Modifier] = []
# Base stats (before modifiers)
var base_stats: Dictionary = {}
# Final calculated stats
var final_stats: Dictionary = {}
func _init(initial_base_stats: Dictionary = {}):
base_stats = initial_base_stats.duplicate()
final_stats = initial_base_stats.duplicate()
func add_modifier(modifier: Modifier) -> void:
modifiers.append(modifier)
modifier.on_equip(get_parent())
emit_signal("modifier_added", modifier)
recalculate_stats()
func remove_modifier(modifier_id: String) -> void:
for i in range(modifiers.size()):
if modifiers[i].id == modifier_id:
var modifier = modifiers[i]
modifier.on_unequip(get_parent())
modifiers.remove_at(i)
emit_signal("modifier_removed", modifier)
recalculate_stats()
break
func recalculate_stats() -> void:
# Reset stats to base values
final_stats = base_stats.duplicate()
# Sort modifiers by priority
modifiers.sort_custom(func(a, b): return a.priority > b.priority)
# First pass: Apply OVERRIDE modifiers (highest priority first)
for modifier in modifiers:
if modifier.modifier_type == Modifier.ModifierType.OVERRIDE:
_apply_modifier_stats(modifier)
# Second pass: Apply ADDITIVE modifiers
for modifier in modifiers:
if modifier.modifier_type == Modifier.ModifierType.ADDITIVE:
_apply_modifier_stats(modifier)
# Third pass: Apply MULTIPLICATIVE modifiers
for modifier in modifiers:
if modifier.modifier_type == Modifier.ModifierType.MULTIPLICATIVE:
_apply_modifier_stats(modifier)
# Last pass: Apply CONDITIONAL modifiers
for modifier in modifiers:
if modifier.modifier_type == Modifier.ModifierType.CONDITIONAL:
_apply_modifier_stats(modifier)
# Apply caps and floors to stats
_apply_stat_limits()
emit_signal("stats_updated")
func _apply_modifier_stats(modifier: Modifier) -> void:
if modifier.has_method("apply_stats_modification"):
modifier.apply_stats_modification(final_stats, base_stats)
func _apply_stat_limits() -> void:
# Example: Cap fire rate
if final_stats.has("fire_rate"):
final_stats.fire_rate = min(final_stats.fire_rate, 20.0) # Max 20 shots per second
final_stats.fire_rate = max(final_stats.fire_rate, 0.5) # Min 0.5 shots per second
# Example: Cap projectile size
if final_stats.has("projectile_size"):
final_stats.projectile_size = min(final_stats.projectile_size, 5.0) # Max 5x normal size
final_stats.projectile_size = max(final_stats.projectile_size, 0.2) # Min 0.2x normal size
func get_stat(stat_name: String, default_value = 0):
return final_stats.get(stat_name, default_value)

View file

@ -0,0 +1 @@
uid://cvklefr50qhfb

View file

@ -0,0 +1 @@
uid://bw6kcdfiq3ugv

47
player/scripts/player.gd Normal file
View file

@ -0,0 +1,47 @@
extends CharacterBody2D
@export var speed = 200
@export var weapon: RangedWeapon
@export var special_ability: Ability
@export var movement: PlayerMovement
# Last direction for idle state
var last_direction = Vector2.DOWN
@onready var animated_sprite = $PlayerSprite
func _ready():
weapon = RangedWeapon.new()
Log.pr("Weapon", weapon)
# Initialize the movement resource with references
if movement:
movement.player = self
movement.animated_sprite = animated_sprite
movement.last_direction = Vector2.DOWN # Default direction
else:
# Create a new resource instance if none was assigned in the editor
movement = PlayerMovement.new()
movement.player = self
movement.animated_sprite = animated_sprite
Log.pr("Adding projectile size additive modifier")
weapon.add_modifier(ProjectileSizeAdditive.new())
Log.pr(weapon.stats.get_stat("projectile_size")) # Size is now 1.0 + 0.5 = 1.5
# Size is now 1.0 + 0.5 = 1.5
# Add the multiplicative size modifier (1.5x multiplier)
Log.pr("Adding projectile size multiplicative modifier")
weapon.add_modifier(ProjectileSizeMultiplicative.new())
Log.pr(weapon.stats.get_stat("projectile_size"))
# Size is now 1.5 * 1.5 = 2.25
# Add another additive size modifier (+0.7 or 70% increase)
Log.pr("Adding another projectile size additive modifier", 0.7)
var another_size_mod = ProjectileSizeAdditive.new()
another_size_mod.size_increase = 0.7
weapon.add_modifier(another_size_mod)
Log.pr(weapon.stats.get_stat("projectile_size"))
func _physics_process(delta):
movement.process(delta)

View file

@ -0,0 +1 @@
uid://bq038uo4cm6nv

View file

@ -0,0 +1,48 @@
# PlayerMovement.gd
extends Resource
class_name PlayerMovement
var player: CharacterBody2D
var animated_sprite: AnimatedSprite2D
var speed: float = 300.0
var last_direction: Vector2 = Vector2.ZERO
func process(_delta):
# Get input direction
var direction = Vector2.ZERO
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_down"):
direction.y += 1
if Input.is_action_pressed("move_up"):
direction.y -= 1
# Normalize the direction
if direction.length() > 0:
direction = direction.normalized()
last_direction = direction
# Set velocity
player.velocity = direction * speed
# Move the character
player.move_and_slide()
# Update animation
update_animation(direction)
func update_animation(direction):
var anim_name = "idle" # Default animation
if direction == Vector2.ZERO:
# Character is idle
anim_name = "idle"
else:
# Character is moving
anim_name = "walk"
if animated_sprite.animation != anim_name:
animated_sprite.play(anim_name)

View file

@ -0,0 +1 @@
uid://b3wtxr3udscoa

View file

@ -0,0 +1,85 @@
class_name RangedWeapon extends Node2D
signal projectile_spawned(projectile)
@export var projectile_scene: PackedScene
# Base stats - will be modified by modifiers
var base_stats = {
"damage": 10.0,
"fire_rate": 2.0, # Shots per second
"projectile_speed": 500.0,
"projectile_size": 1.0,
"projectile_lifetime": 5.0,
"max_pierce": 0
}
# Components
var stats: ModifierManager
var can_fire: bool = true
var fire_timer: Timer
func _init() -> void:
stats = ModifierManager.new(base_stats)
Log.pr(stats)
add_child(stats)
func _ready():
# Connect to stats updated signal
stats.connect("stats_updated", _on_stats_updated)
# Setup fire timer
fire_timer = Timer.new()
add_child(fire_timer)
fire_timer.one_shot = true
fire_timer.connect("timeout", _on_fire_timer_timeout)
# Initial update
_on_stats_updated()
func fire(direction: Vector2):
if !can_fire:
return
_spawn_projectile(global_position, direction)
can_fire = false
fire_timer.start(1.0 / stats.get_stat("fire_rate"))
func _spawn_projectile(spawn_position: Vector2, spawn_direction: Vector2):
var projectile = projectile_scene.instantiate()
projectile.global_position = spawn_position
projectile.direction = spawn_direction
# Apply stats to projectile
projectile.speed = stats.get_stat("projectile_speed")
projectile.damage = stats.get_stat("damage")
projectile.lifetime = stats.get_stat("projectile_lifetime")
projectile.pierce_count = stats.get_stat("max_pierce")
projectile.source_weapon = self
# Apply size (scale)
var size = stats.get_stat("projectile_size")
projectile.scale = Vector2(size, size)
# Allow modifiers to directly modify the projectile
for modifier in stats.modifiers:
modifier.modify_projectile(projectile)
get_tree().root.add_child(projectile)
projectile.emit_signal("on_spawned", projectile)
emit_signal("projectile_spawned", projectile)
func add_modifier(modifier: Modifier):
stats.add_modifier(modifier)
func remove_modifier(modifier_id: String):
stats.remove_modifier(modifier_id)
func _on_stats_updated():
# Update any visual components based on new stats
# For example, if weapon appearance changes based on damage/fire rate
pass
func _on_fire_timer_timeout():
can_fire = true

View file

@ -0,0 +1 @@
uid://dcenqdci4hjes