Compare commits

...

4 Commits

16 changed files with 280 additions and 21 deletions

View File

@@ -24,7 +24,7 @@ const GROUP_XP_ORB = "xp_orb"
const GROUP_PICKUP = "pickup" const GROUP_PICKUP = "pickup"
const GROUP_PROJ_MANAGER = "proj_manager" const GROUP_PROJ_MANAGER = "proj_manager"
enum ModRarity { LEGENDARY, EPIC, RARE, NORMAL } enum Rarity { LEGENDARY, EPIC, RARE, NORMAL }
const placeholder_tex = preload("res://assets/sprites/64x64_placeholder.tres") const placeholder_tex = preload("res://assets/sprites/64x64_placeholder.tres")
@@ -32,7 +32,7 @@ var MOD_CHOICES = [
{ {
"internal_name": "flat_health_small", "internal_name": "flat_health_small",
"name": "+10 Health", "name": "+10 Health",
"rarity": ModRarity.NORMAL, "rarity": Rarity.NORMAL,
"tex": placeholder_tex, "tex": placeholder_tex,
"description": "Adds 10 flat health.", "description": "Adds 10 flat health.",
"weight": 100, "weight": 100,
@@ -43,7 +43,7 @@ var MOD_CHOICES = [
{ {
"internal_name": "flat_health_med", "internal_name": "flat_health_med",
"name": "+25 Health", "name": "+25 Health",
"rarity": ModRarity.RARE, "rarity": Rarity.RARE,
"tex": placeholder_tex, "tex": placeholder_tex,
"description": "Adds 25 flat health.", "description": "Adds 25 flat health.",
"weight": 50, "weight": 50,
@@ -54,7 +54,7 @@ var MOD_CHOICES = [
{ {
"internal_name": "flat_health_large", "internal_name": "flat_health_large",
"name": "+50 Health", "name": "+50 Health",
"rarity": ModRarity.EPIC, "rarity": Rarity.EPIC,
"tex": placeholder_tex, "tex": placeholder_tex,
"description": "Adds 50 flat health.", "description": "Adds 50 flat health.",
"weight": 10, "weight": 10,
@@ -65,7 +65,7 @@ var MOD_CHOICES = [
{ {
"internal_name": "flat_crit_small", "internal_name": "flat_crit_small",
"name": "2.5% More Critical Chance", "name": "2.5% More Critical Chance",
"rarity": ModRarity.RARE, "rarity": Rarity.RARE,
"tex": placeholder_tex, "tex": placeholder_tex,
"description": "Gives 2.5% more base critical hit chance", "description": "Gives 2.5% more base critical hit chance",
"weight": 50, "weight": 50,
@@ -76,7 +76,7 @@ var MOD_CHOICES = [
{ {
"internal_name": "flat_crit_large", "internal_name": "flat_crit_large",
"name": "5% More Critical Chance", "name": "5% More Critical Chance",
"rarity": ModRarity.EPIC, "rarity": Rarity.EPIC,
"tex": placeholder_tex, "tex": placeholder_tex,
"description": "Gives 5% more base critical hit chance", "description": "Gives 5% more base critical hit chance",
"weight": 10, "weight": 10,
@@ -87,6 +87,17 @@ var MOD_CHOICES = [
] ]
func rarity_to_color(rarity: Rarity) -> Color:
match rarity:
Rarity.RARE:
return Color.YELLOW
Rarity.EPIC:
return Color.BLUE_VIOLET
Rarity.LEGENDARY:
return Color.DARK_ORANGE
return Color.WHITE
func _draw_random_choice(fortune: float = 1.0) -> Dictionary: func _draw_random_choice(fortune: float = 1.0) -> Dictionary:
var total_weight: int = 0 var total_weight: int = 0
for choice in MOD_CHOICES: for choice in MOD_CHOICES:

View File

@@ -9,9 +9,9 @@ extends CharacterBody2D
@onready var contact_damage_cd: Timer = $ContactDamageCD @onready var contact_damage_cd: Timer = $ContactDamageCD
@onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var animation_player: AnimationPlayer = $AnimationPlayer
var move_speed: float var move_speed: float = default_move_speed
var health: float var health: float = default_max_health
var max_health: float var max_health: float = default_max_health
var god_mode: bool = false var god_mode: bool = false
var is_dead: bool = false var is_dead: bool = false

View File

@@ -7,6 +7,8 @@ extends CharacterBody2D
@export var target_distance: float = 6.0 @export var target_distance: float = 6.0
@export var path_update_interval: float = 1.5 @export var path_update_interval: float = 1.5
@export var xp_dropped: float = 5.0 @export var xp_dropped: float = 5.0
@export var enemy_rarity: GlobalConst.Rarity = GlobalConst.Rarity.NORMAL
var modifiers: Array[EnemyMod] = []
@onready var target_cast: RayCast2D = $TargetCast @onready var target_cast: RayCast2D = $TargetCast
@onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var animation_player: AnimationPlayer = $AnimationPlayer
@@ -15,6 +17,7 @@ extends CharacterBody2D
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D @onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
@onready var shape_cast_2d: ShapeCast2D = $ShapeCast2D @onready var shape_cast_2d: ShapeCast2D = $ShapeCast2D
@onready var sprite_2d: Sprite2D = $Sprite2D @onready var sprite_2d: Sprite2D = $Sprite2D
@onready var label: Label = $Label
var player: Player var player: Player
var enemy_name: String var enemy_name: String
@@ -27,8 +30,23 @@ var _path_update_timer: float = 0.0
func _ready() -> void: func _ready() -> void:
health = max_health
enemy_name = _gen_name() enemy_name = _gen_name()
match enemy_rarity:
GlobalConst.Rarity.NORMAL:
label.visible = false
GlobalConst.Rarity.RARE:
var mods = EnemyModPool.get_random_mods(2)
label.visible = true
modifiers = mods
GlobalConst.Rarity.EPIC:
var mods = EnemyModPool.get_random_mods(4)
label.visible = true
modifiers = mods
if modifiers.size() > 0:
enemy_name += " the %s" % modifiers.pick_random().adjective
label.add_theme_color_override("font_color", GlobalConst.rarity_to_color(enemy_rarity))
label.text = enemy_name
health = get_calculated("max_health")
shape_cast_2d.shape.radius = collision_shape_2d.shape.radius shape_cast_2d.shape.radius = collision_shape_2d.shape.radius
shape_cast_2d.enabled = false shape_cast_2d.enabled = false
sprite_2d.material = sprite_2d.material.duplicate() sprite_2d.material = sprite_2d.material.duplicate()
@@ -79,7 +97,7 @@ func _do_simple_movement():
var direction = global_position.direction_to(target.global_position) var direction = global_position.direction_to(target.global_position)
var distance = global_position.distance_to(target.global_position) var distance = global_position.distance_to(target.global_position)
if distance > 4: if distance > 4:
velocity = direction * move_speed velocity = direction * get_calculated("move_speed")
move_and_slide() move_and_slide()
@@ -97,7 +115,7 @@ func _do_nav_agent_movement():
if shape_cast_2d.is_colliding(): if shape_cast_2d.is_colliding():
direction = direction.bounce(shape_cast_2d.get_collision_normal(0)).normalized() direction = direction.bounce(shape_cast_2d.get_collision_normal(0)).normalized()
velocity = direction * move_speed velocity = direction * get_calculated("move_speed")
move_and_slide() move_and_slide()
@@ -147,7 +165,7 @@ func die():
func drop_xp_orb() -> void: func drop_xp_orb() -> void:
var orb: XPOrb = preload("res://scenes/xp_orb.tscn").instantiate() var orb: XPOrb = preload("res://scenes/xp_orb.tscn").instantiate()
orb.value = xp_dropped orb.value = xp_dropped * (1 + (modifiers.size() * 3))
orb.position = position orb.position = position
get_parent().call_deferred("add_child", orb) get_parent().call_deferred("add_child", orb)
@@ -155,3 +173,21 @@ func drop_xp_orb() -> void:
func _on_animation_player_animation_finished(anim_name: StringName) -> void: func _on_animation_player_animation_finished(anim_name: StringName) -> void:
if is_dead: if is_dead:
queue_free() queue_free()
func get_calculated(key: String) -> Variant:
# set max move speed to players move speed
if key == "move_speed":
return clampf(
EnemyMod.get_calculated(self, key),
0,
player.player_stats.get_final("move_speed", player.modifiers)
)
return EnemyMod.get_calculated(self, key)
func has_property(key: String) -> bool:
for prop in get_property_list():
if prop.name == key:
return true
return false

View File

@@ -90,4 +90,20 @@ wait_time = 0.5
shape = SubResource("CircleShape2D_pkqou") shape = SubResource("CircleShape2D_pkqou")
max_results = 2 max_results = 2
[node name="Label" type="Label" parent="."]
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -85.5
offset_top = 5.0
offset_right = 85.5
offset_bottom = 28.0
grow_horizontal = 2
grow_vertical = 0
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"] [connection signal="animation_finished" from="AnimationPlayer" to="." method="_on_animation_player_animation_finished"]

View File

@@ -1 +1,32 @@
extends EnemyBase extends EnemyBase
const NAME_PREFIXES: Array[String] = [
"Chi",
"Sque",
"Flit",
"Bat",
"Kla",
]
const NAME_ROOTS: Array[String] = [
"ter",
"tch",
"reek",
"p",
"nap",
]
const NAME_SUFFIXES: Array[String] = [
"y",
"a",
"et",
"ik",
"in",
]
func _gen_name() -> String:
return (
"%s%s%s"
% [NAME_PREFIXES.pick_random(), NAME_ROOTS.pick_random(), NAME_SUFFIXES.pick_random()]
)

View File

@@ -0,0 +1,34 @@
class_name EnemyMod
extends Resource
enum ModType { ADDITIVE, MULTIPLICATIVE, ABSOLUTE, BOOL }
@export var mod_name: String
@export var mod_property: String
@export var mod_value: float
@export var mod_value_bool: bool = false
@export var mod_type: ModType = ModType.MULTIPLICATIVE
var adjective: String
static func get_calculated(enemy: EnemyBase, key: String) -> Variant:
assert(
enemy.has_property(key),
"tried to calculate property '%s' where base value does not exist on %s" % [key, enemy]
)
var base_value = enemy.get(key)
var add = 0.0
var mul = 1.0
for mod in enemy.modifiers:
if mod.mod_property == key:
match mod.mod_type:
ModType.ADDITIVE:
add += mod.mod_value
ModType.MULTIPLICATIVE:
mul *= mod.mod_value
ModType.ABSOLUTE:
return mod.mod_value
ModType.BOOL:
return mod.mod_value_bool
return (base_value + add) * mul

View File

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

View File

@@ -0,0 +1,58 @@
class_name EnemyModPool
extends Resource
const MAX_HEALTH_MOD: Dictionary = {
"mod_name": "Extra health",
"mod_property": "max_health",
"mod_value": 1.0,
"mod_value_bool": false,
"mod_type": EnemyMod.ModType.MULTIPLICATIVE,
"mod_adjectives":
[
"Sturdy",
"Bulky",
"Ironclad",
"Unyielding",
"Stonehide",
"Thicc",
"Chunky",
"Pudgy",
"Chonky",
"Double-stuffed"
],
}
const MOD_POOL = [
{
"mod_name": "Extra movement speed",
"mod_property": "move_speed",
"mod_value": 1.25,
"mod_value_bool": false,
"mod_type": EnemyMod.ModType.MULTIPLICATIVE,
"mod_adjectives": ["Swift", "Nimble", "Fleet", "Spry", "Skittering", "Zoomy", "Zippy"]
}
]
static func get_random_mods(count: int) -> Array[EnemyMod]:
var mods: Array[EnemyMod] = []
# always include extra health mod
var hp_mod = _dict_to_mod(MAX_HEALTH_MOD)
hp_mod.mod_value *= 5 * count
mods.append(hp_mod)
for i in count:
var mod_data = MOD_POOL.pick_random()
var mod = _dict_to_mod(mod_data)
mods.append(mod)
return mods
static func _dict_to_mod(d: Dictionary) -> EnemyMod:
var mod: EnemyMod = EnemyMod.new()
mod.mod_name = d["mod_name"]
mod.mod_property = d["mod_property"]
mod.mod_value = d["mod_value"]
mod.mod_value_bool = d["mod_value_bool"]
mod.mod_type = d["mod_type"]
mod.adjective = d["mod_adjectives"].pick_random()
return mod

View File

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

View File

@@ -1 +1,29 @@
extends EnemyBase extends EnemyBase
const NAME_PREFIXES: Array[String] = [
"Sk",
"Sn",
"Gr",
"R",
"Kr",
"V",
"Vr",
]
const NAME_ROOTS: Array[String] = [
"itch",
"abble",
"itter",
"usk",
"arp",
"uzzle",
]
const NAME_SUFFIXES: Array[String] = ["y", "er", "o", "ok", "in"]
func _gen_name() -> String:
return (
"%s%s%s"
% [NAME_PREFIXES.pick_random(), NAME_ROOTS.pick_random(), NAME_SUFFIXES.pick_random()]
)

View File

@@ -8,6 +8,37 @@ extends EnemyBase
var shader = preload("res://assets/shaders/base_color_tint.gdshader") var shader = preload("res://assets/shaders/base_color_tint.gdshader")
var shader_material: ShaderMaterial var shader_material: ShaderMaterial
const NAME_PREFIXES: Array[String] = [
"Gl",
"Sl",
"Bl",
"Pl",
"Dr",
"Go",
"Glo",
"Blo",
]
const NAME_ROOTS: Array[String] = [
"op",
"ub",
"ooz",
"ump",
"ibble",
"ug",
"urp",
"lop",
]
const NAME_SUFFIXES: Array[String] = [
"y",
"o",
"let",
"kin",
"ish",
"oo",
]
func _ready() -> void: func _ready() -> void:
shader_material = ShaderMaterial.new() shader_material = ShaderMaterial.new()
@@ -15,7 +46,15 @@ func _ready() -> void:
set_color(color) set_color(color)
shader_material.shader = shader shader_material.shader = shader
base_sprite.material = shader_material base_sprite.material = shader_material
super._ready()
func set_color(new_color: Color) -> void: func set_color(new_color: Color) -> void:
shader_material.set_shader_parameter("base_color", new_color) shader_material.set_shader_parameter("base_color", new_color)
func _gen_name() -> String:
return (
"%s%s%s"
% [NAME_PREFIXES.pick_random(), NAME_ROOTS.pick_random(), NAME_SUFFIXES.pick_random()]
)

View File

@@ -31,10 +31,10 @@ color = Color(0.498039, 1, 0, 1)
material = SubResource("ShaderMaterial_daihb") material = SubResource("ShaderMaterial_daihb")
texture = SubResource("AtlasTexture_2yvgl") texture = SubResource("AtlasTexture_2yvgl")
[node name="Highlights" type="Sprite2D" parent="Sprite" index="1"] [node name="Shading" type="Sprite2D" parent="Sprite" index="1"]
texture = SubResource("AtlasTexture_daihb") texture = SubResource("AtlasTexture_daihb")
[node name="Shading" type="Sprite2D" parent="Sprite" index="2"] [node name="Highlights" type="Sprite2D" parent="Sprite" index="2"]
texture = SubResource("AtlasTexture_wu20c") texture = SubResource("AtlasTexture_wu20c")
[node name="Sprite2D" parent="." index="1"] [node name="Sprite2D" parent="." index="1"]

View File

@@ -37,6 +37,10 @@ func _on_timer_timeout() -> void:
var new_enemy = next_enemy.instantiate() var new_enemy = next_enemy.instantiate()
new_enemy.position = _get_spawn_pos() new_enemy.position = _get_spawn_pos()
new_enemy.target = target new_enemy.target = target
if randf() < 0.1:
new_enemy.enemy_rarity = GlobalConst.Rarity.RARE
if randf() < 0.1:
new_enemy.enemy_rarity = GlobalConst.Rarity.EPIC
if is_instance_of(new_enemy, EnemySlimeSmall): if is_instance_of(new_enemy, EnemySlimeSmall):
var slime_color: Color = SLIME_COLOR_VARIATIONS.pick_random() var slime_color: Color = SLIME_COLOR_VARIATIONS.pick_random()
new_enemy.color = slime_color new_enemy.color = slime_color

View File

@@ -13,13 +13,13 @@ signal lvlup_picked(mod: PlayerStatsModifier)
func _ready() -> void: func _ready() -> void:
match mod.rarity: match mod.rarity:
GlobalConst.ModRarity.NORMAL: GlobalConst.Rarity.NORMAL:
upgrade_name.add_theme_color_override("font_color", Color.WHITE) upgrade_name.add_theme_color_override("font_color", Color.WHITE)
GlobalConst.ModRarity.RARE: GlobalConst.Rarity.RARE:
upgrade_name.add_theme_color_override("font_color", Color.DODGER_BLUE) upgrade_name.add_theme_color_override("font_color", Color.DODGER_BLUE)
GlobalConst.ModRarity.EPIC: GlobalConst.Rarity.EPIC:
upgrade_name.add_theme_color_override("font_color", Color.DARK_ORCHID) upgrade_name.add_theme_color_override("font_color", Color.DARK_ORCHID)
GlobalConst.ModRarity.LEGENDARY: GlobalConst.Rarity.LEGENDARY:
upgrade_name.add_theme_color_override("font_color", Color.DARK_ORANGE) upgrade_name.add_theme_color_override("font_color", Color.DARK_ORANGE)
upgrade_name.text = mod.title upgrade_name.text = mod.title

View File

@@ -16,7 +16,7 @@ func pickup() -> void:
mod.title = "Magnet" mod.title = "Magnet"
mod.tex = GlobalConst.placeholder_tex mod.tex = GlobalConst.placeholder_tex
mod.internal_name = "magnet" mod.internal_name = "magnet"
mod.rarity = GlobalConst.ModRarity.RARE mod.rarity = GlobalConst.Rarity.RARE
mod.stat_name = "pickup_radius" mod.stat_name = "pickup_radius"
mod.value = 5000.0 mod.value = 5000.0
mod.type = PlayerStatsModifier.ModifierType.ABSOLUTE mod.type = PlayerStatsModifier.ModifierType.ABSOLUTE

View File

@@ -8,6 +8,6 @@ var value: Variant
var type: ModifierType = ModifierType.ADDITIVE var type: ModifierType = ModifierType.ADDITIVE
var internal_name: String var internal_name: String
var title: String var title: String
var rarity: GlobalConst.ModRarity var rarity: GlobalConst.Rarity
var tex: Texture2D var tex: Texture2D
var description: String var description: String