Reworked weapons and projectiles

This commit is contained in:
2025-12-20 18:35:27 +03:00
parent 2ecc53416a
commit 8227e8bcf3
312 changed files with 2466 additions and 1376 deletions
+274
View File
@@ -0,0 +1,274 @@
class_name AreaGenerator
extends Node
const STAGE_COUNT = 9
const EXTRA_PASSAGE_CHANCE = 33
const PASSAGE_TYPES = {
"1 1 0": PassageData.PassageType.ZeroGrad,
"1 2 0": PassageData.PassageType.Minus26Grad,
"1 2 -1": PassageData.PassageType.Plus26Grad,
"1 3 0": PassageData.PassageType.Plus45Grad,
"1 3 -1": PassageData.PassageType.ZeroGrad,
"1 3 -2": PassageData.PassageType.Minus45Grad,
"2 1 1": PassageData.PassageType.Minus26Grad,
"2 1 0": PassageData.PassageType.Plus26Grad,
"2 2 1": PassageData.PassageType.Minus45Grad,
"2 2 0": PassageData.PassageType.ZeroGrad,
"2 2 -1": PassageData.PassageType.Plus45Grad,
"2 3 0": PassageData.PassageType.Minus26Grad,
"2 3 -1": PassageData.PassageType.Plus26Grad,
"3 1 2": PassageData.PassageType.Minus45Grad,
"3 1 1": PassageData.PassageType.ZeroGrad,
"3 1 0": PassageData.PassageType.Plus45Grad,
"3 2 1": PassageData.PassageType.Minus26Grad,
"3 2 0": PassageData.PassageType.Plus26Grad,
"3 3 1": PassageData.PassageType.Minus45Grad,
"3 3 0": PassageData.PassageType.ZeroGrad,
"3 3 -1": PassageData.PassageType.Plus45Grad,
}
var local_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var stage_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var passage_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var passage_chance_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var passage_direction_rng : RandomNumberGenerator = RandomNumberGenerator.new()
@onready var stage_generator : StageGenerator = $StageGenerator
@onready var passage_generator : PassageGenerator = $PassageGenerator
func generate(seed_value: int) -> AreaData:
local_seed_rng.seed = seed_value
stage_seed_rng.seed = local_seed_rng.randi()
passage_seed_rng.seed = local_seed_rng.randi()
passage_chance_rng.seed = local_seed_rng.randi()
passage_direction_rng.seed = local_seed_rng.randi()
var data : AreaData = AreaData.new()
data.seed_value = seed_value
_fill_stages(data)
_fill_passages(data)
return data
func _fill_stages(data : AreaData) -> void:
for i in range(STAGE_COUNT):
var stage_type := _get_stage_type(i)
var seed_value := stage_seed_rng.randi()
var stage := stage_generator.generate(seed_value, stage_type)
data.stages.append(stage)
_update_neighbors(data)
func _get_stage_type(stage_index: int) -> StageGenerator.StageType:
match stage_index:
0:
return StageGenerator.StageType.Start
STAGE_COUNT - 1:
return StageGenerator.StageType.Boss
_:
return StageGenerator.StageType.Inner
func _fill_passages(data : AreaData) -> void:
for i in range(data.stages.size() - 1):
var first_stage := data.stages[i]
var second_stage := data.stages[i + 1]
_fill_passages_for_pair(data, first_stage, second_stage)
func _fill_passages_for_pair(
data : AreaData,
first_stage: StageData,
second_stage: StageData
) -> void:
var first_size := first_stage.sectors.size()
var second_size := second_stage.sectors.size()
if first_size < second_size:
_fill_passages_for_unequal_pair(
data, first_stage.sectors, second_stage.sectors, _connect_sectors
)
elif first_size > second_size:
_fill_passages_for_unequal_pair(
data, second_stage.sectors, first_stage.sectors, _connect_sectors_flipped
)
else:
_fill_passages_for_equal_pair(data, first_stage.sectors, second_stage.sectors)
func _fill_passages_for_equal_pair(
data : AreaData,
first_sectors: Array[SectorData],
second_sectors: Array[SectorData]
) -> void:
var size := first_sectors.size()
for i in range(size):
_connect_sectors(data, first_sectors, i, second_sectors, i)
for i in range(size - 1):
if _extra_passage_needed():
var is_passage_fliped := _is_extra_passage_flipped()
var from := i if is_passage_fliped else i + 1
var to := i + 1 if is_passage_fliped else i
_connect_sectors(data, first_sectors, from, second_sectors, to)
func _fill_passages_for_unequal_pair(
data : AreaData,
lesser_sectors: Array[SectorData],
greater_sectors: Array[SectorData],
connect_method: Callable
) -> void:
var lesser_size := lesser_sectors.size()
match lesser_size:
1:
_fill_passages_for_unequal_pair_1_to_2_3(
data, lesser_sectors, greater_sectors, connect_method
)
2:
_fill_passages_for_unequal_pair_2_to_3(
data, lesser_sectors, greater_sectors, connect_method
)
func _fill_passages_for_unequal_pair_1_to_2_3(
data : AreaData,
lesser_sectors: Array[SectorData],
greater_sectors: Array[SectorData],
connect_method: Callable
) -> void:
var greater_size := greater_sectors.size()
for i in range(greater_size):
connect_method.call(data, lesser_sectors, 0, greater_sectors, i)
func _fill_passages_for_unequal_pair_2_to_3(
data : AreaData,
lesser_sectors: Array[SectorData],
greater_sectors: Array[SectorData],
connect_method: Callable
) -> void:
connect_method.call(data, lesser_sectors, 0, greater_sectors, 0)
connect_method.call(data, lesser_sectors, 1, greater_sectors, 2)
if _extra_passage_needed():
connect_method.call(data, lesser_sectors, 0, greater_sectors, 1)
connect_method.call(data, lesser_sectors, 1, greater_sectors, 1)
else:
var from := 0 if _is_extra_passage_flipped() else 1
connect_method.call(data, lesser_sectors, from, greater_sectors, 1)
func _extra_passage_needed() -> bool:
return passage_chance_rng.randi_range(1, 100) <= EXTRA_PASSAGE_CHANCE
func _is_extra_passage_flipped() -> bool:
return passage_direction_rng.randi_range(0, 1) == 0
func _connect_sectors(
data : AreaData,
first_sectors: Array[SectorData],
first_index: int,
second_sectors: Array[SectorData],
second_index: int
) -> void:
var seed_value := passage_seed_rng.randi()
var passage := passage_generator.generate(seed_value)
passage.type = _get_passage_type(
first_sectors.size(), first_index,
second_sectors.size(), second_index,
)
var first_sector := first_sectors[first_index]
var second_sector := second_sectors[second_index]
passage.previous_sector = first_sector
passage.next_sector = second_sector
first_sector.next_passages.append(passage)
second_sector.previous_passages.append(passage)
data.passages.append(passage)
func _connect_sectors_flipped(
data : AreaData,
first_sectors: Array[SectorData],
first_index: int,
second_sectors: Array[SectorData],
second_index: int
) -> void:
_connect_sectors(data, second_sectors, second_index, first_sectors, first_index)
func _get_passage_type(
from_size: int, from_index: int, to_size: int, to_index: int
) -> PassageData.PassageType:
var diff := from_index - to_index
var key := "%d %d %d" % [from_size, to_size, diff]
return PASSAGE_TYPES.get(key, PassageData.PassageType.ZeroGrad)
func _update_neighbors(data : AreaData) -> void:
for stage_index in range(data.stages.size()):
var stage := data.stages[stage_index]
for sector_index in range(stage.sectors.size()):
var sector := stage.sectors[sector_index]
sector.sector_to_left = _get_left_neighbor(data, stage_index, sector_index)
sector.sector_to_right = _get_right_neighbor(data, stage_index, sector_index)
func _get_left_neighbor(data : AreaData, stage_index: int, sector_index: int) -> SectorData:
if stage_index == 0: return null
var current_stage := data.stages[stage_index]
var left_stage := data.stages[stage_index-1]
return _get_side_neighbor(sector_index, current_stage, left_stage)
func _get_right_neighbor(data : AreaData, stage_index: int, sector_index: int) -> SectorData:
if stage_index == data.stages.size() - 1: return null
var current_stage := data.stages[stage_index]
var right_stage := data.stages[stage_index+1]
return _get_side_neighbor(sector_index, current_stage, right_stage)
func _get_side_neighbor(
sector_index: int, current_stage: StageData, side_stage: StageData
) -> SectorData:
var current_size := current_stage.sectors.size()
var side_size := side_stage.sectors.size()
if side_size == 0:
return null
if current_size == 1:
return side_stage.sectors[floori(side_size / 2.0)]
var normalized_position := float(sector_index) / float(current_size - 1)
var side_index := floori(normalized_position * (side_size - 1))
side_index = clampi(side_index, 0, side_size - 1)
return side_stage.sectors[side_index]
+1
View File
@@ -0,0 +1 @@
uid://bcq74qwnbylg2
+12
View File
@@ -0,0 +1,12 @@
[gd_scene load_steps=4 format=3 uid="uid://c4l1cv3o25lhv"]
[ext_resource type="Script" uid="uid://bcq74qwnbylg2" path="res://game/generators/area_generator.gd" id="1_hahgo"]
[ext_resource type="PackedScene" uid="uid://bn4r4f3str55v" path="res://game/generators/stage_generator.tscn" id="2_b1pkv"]
[ext_resource type="PackedScene" uid="uid://cfcpr07j58cvx" path="res://game/generators/passage_generator.tscn" id="3_q2vfj"]
[node name="AreaGenerator" type="Node"]
script = ExtResource("1_hahgo")
[node name="StageGenerator" parent="." instance=ExtResource("2_b1pkv")]
[node name="PassageGenerator" parent="." instance=ExtResource("3_q2vfj")]
+75
View File
@@ -0,0 +1,75 @@
class_name EnemyGenerator
extends Node
enum EnemyType {
Small,
Medium,
Heavy,
}
const ENEMY_TYPES : Array[EnemyType] = [
EnemyType.Small,
EnemyType.Medium,
EnemyType.Heavy,
]
const ENEMY_CHANCES : Array[int] = [
45,
35,
20,
]
const ENEMY_SCENES : Dictionary[EnemyType, String] = {
EnemyType.Small: "res://game/entities/ships/enemies/small/small_enemy_ship.tscn",
EnemyType.Medium: "res://game/entities/ships/enemies/medium/medium_enemy_ship.tscn",
EnemyType.Heavy: "res://game/entities/ships/enemies/heavy/heavy_enemy_ship.tscn",
}
const ENEMY_MAX_WEAPON_COUNT : Dictionary[EnemyType, int] = {
EnemyType.Small: 1,
EnemyType.Medium: 2,
EnemyType.Heavy: 3,
}
var local_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var spawn_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var type_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var weapon_rng : RandomNumberGenerator = RandomNumberGenerator.new()
func generate(seed_value: int) -> EnemyData:
local_seed_rng.seed = seed_value
spawn_rng.seed = local_seed_rng.randi()
type_rng.seed = local_seed_rng.randi()
weapon_rng.seed = local_seed_rng.randi()
var type := _get_enemy_type()
var data : EnemyData = EnemyData.new()
data.seed_value = seed_value
_full_spawn(data)
_full_scene(data, type)
_full_weapon(data, type)
return data
func _get_enemy_type() -> EnemyType:
var index := type_rng.rand_weighted(ENEMY_CHANCES)
return ENEMY_TYPES[index]
func _full_spawn(data: EnemyData) -> void:
data.spawn_point.x = 750
data.spawn_point.y = spawn_rng.randf_range(0.0, 360.0)
func _full_scene(data: EnemyData, type: EnemyType) -> void:
data.enemy_scene = ENEMY_SCENES[type]
func _full_weapon(data: EnemyData, type: EnemyType) -> void:
data.weapon_count = randi_range(1, ENEMY_MAX_WEAPON_COUNT[type])
+1
View File
@@ -0,0 +1 @@
uid://r51oawb6oedw
+6
View File
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://bqtiiog23c2ta"]
[ext_resource type="Script" uid="uid://r51oawb6oedw" path="res://game/generators/enemy_generator.gd" id="1_ehucw"]
[node name="EnemyGenerator" type="Node"]
script = ExtResource("1_ehucw")
+97
View File
@@ -0,0 +1,97 @@
class_name PassageGenerator
extends Node
const ENEMY_DELAY_MEAN = 3.0
const ENEMY_DELAY_DEVIATION = 2.0
const LENGTH_MEAN = 300.0
const LENGTH_DEVIATION = 50.0
const SPAWN_START_DELAY = 3.0
const SPAWN_END_DELAY = 3.0
const USE_NEXT_WEAPON_CHANCE = 50
var local_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var weapon_ids_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var length_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var enemy_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var enemy_delay_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var enemy_weapon_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var weapons : Array[WeaponData]
@onready var enemy_generator : EnemyGenerator = $EnemyGenerator
func generate(seed_value: int) -> PassageData:
local_seed_rng.seed = seed_value
weapon_ids_rng.seed = local_seed_rng.randi()
length_rng.seed = local_seed_rng.randi()
enemy_seed_rng.seed = local_seed_rng.randi()
enemy_delay_rng.seed = local_seed_rng.randi()
enemy_weapon_rng.seed = local_seed_rng.randi()
weapons = _get_weapons()
var data : PassageData = PassageData.new()
data.seed_value = seed_value
_fill_length(data)
_fill_enemies(data)
return data
func _get_weapons() -> Array[WeaponData]:
var array : Array[WeaponData] = SaveManager.WEAPONS.duplicate()
for i in range(array.size() - 1, 0, -1):
var j := weapon_ids_rng.randi_range(0, i)
var temp := array[i]
array[i] = array[j]
array[j] = temp
return array
func _fill_length(data: PassageData) -> void:
data.length = length_rng.randfn(LENGTH_MEAN, LENGTH_DEVIATION)
func _fill_enemies(data: PassageData) -> void:
var spawn_end_time := floori(data.length - SPAWN_END_DELAY)
var time := SPAWN_START_DELAY
while time < spawn_end_time:
time += enemy_delay_rng.randfn(ENEMY_DELAY_MEAN, ENEMY_DELAY_DEVIATION)
if time < SPAWN_START_DELAY: time = SPAWN_START_DELAY
elif time > spawn_end_time: time = spawn_end_time
var seed_value := enemy_seed_rng.randi()
var enemy := enemy_generator.generate(seed_value)
enemy.spawn_time = time
enemy.weapon = _get_weapon()
data.enemies.append(enemy)
var enemy_spawn_time_compare := func(a: EnemyData, b: EnemyData) -> bool:
return a.spawn_time < b.spawn_time
data.enemies.sort_custom(enemy_spawn_time_compare)
func _get_weapon() -> WeaponData:
var index := 0
while index < weapons.size() - 1:
if enemy_weapon_rng.randi_range(1, 100) <= USE_NEXT_WEAPON_CHANCE:
index += 1
else:
break
return weapons[index]
+1
View File
@@ -0,0 +1 @@
uid://bi5vt3ikxya8d
+9
View File
@@ -0,0 +1,9 @@
[gd_scene load_steps=3 format=3 uid="uid://cfcpr07j58cvx"]
[ext_resource type="Script" uid="uid://bi5vt3ikxya8d" path="res://game/generators/passage_generator.gd" id="1_3arab"]
[ext_resource type="PackedScene" uid="uid://bqtiiog23c2ta" path="res://game/generators/enemy_generator.tscn" id="2_u6kxl"]
[node name="PassageGenerator" type="Node"]
script = ExtResource("1_3arab")
[node name="EnemyGenerator" parent="." instance=ExtResource("2_u6kxl")]
+34
View File
@@ -0,0 +1,34 @@
class_name SectorGenerator
extends Node
const SECTOR_TYPES : Array[SectorData.SectorType] = [
SectorData.SectorType.ShopSector,
SectorData.SectorType.RepairSector,
SectorData.SectorType.DebrisSector,
]
const SECTOR_CHANCES : Array[int] = [
40,
20,
40,
]
var local_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var sector_type_rng : RandomNumberGenerator = RandomNumberGenerator.new()
func generate(seed_value: int) -> SectorData:
local_seed_rng.seed = seed_value
sector_type_rng.seed = local_seed_rng.randi()
var data : SectorData = SectorData.new()
data.seed_value = seed_value
data.type = _get_sector_type()
return data
func _get_sector_type() -> SectorData.SectorType:
var index := sector_type_rng.rand_weighted(SECTOR_CHANCES)
return SECTOR_TYPES[index]
+1
View File
@@ -0,0 +1 @@
uid://de386hpwwum7o
+6
View File
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://bh1v37wol5ktj"]
[ext_resource type="Script" uid="uid://de386hpwwum7o" path="res://game/generators/sector_generator.gd" id="1_trjpu"]
[node name="SectorGenerator" type="Node"]
script = ExtResource("1_trjpu")
+70
View File
@@ -0,0 +1,70 @@
class_name StageGenerator
extends Node
enum StageType {
Start,
Inner,
Boss,
}
const SECTOR_COUNTS : Array[int] = [
1,
2,
3,
]
const SECTOR_CHANCES : Array[int] = [
20,
30,
50,
]
var local_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var sector_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var sector_count_rng : RandomNumberGenerator = RandomNumberGenerator.new()
@onready var sector_generator : SectorGenerator = $SectorGenerator
func generate(seed_value: int, type: StageType = StageType.Inner) -> StageData:
local_seed_rng.seed = seed_value
sector_seed_rng.seed = local_seed_rng.randi()
sector_count_rng.seed = local_seed_rng.randi()
var data : StageData = StageData.new()
data.seed_value = seed_value
_fill_sectors(data, type)
return data
func _fill_sectors(data : StageData, type: StageType = StageType.Inner) -> void:
var sector_count := _get_sector_count() if type == StageType.Inner else 1
for i in sector_count:
var seed_value := sector_seed_rng.randi()
var sector := sector_generator.generate(seed_value)
data.sectors.append(sector)
match type:
StageType.Start:
sector.type = SectorData.SectorType.StartSector
StageType.Boss:
sector.type = SectorData.SectorType.BossSector
_update_neighbors(data)
func _get_sector_count() -> int:
var index := sector_count_rng.rand_weighted(SECTOR_CHANCES)
return SECTOR_COUNTS[index]
func _update_neighbors(data : StageData) -> void:
var size := data.sectors.size()
for i in range(size):
if i > 0:
data.sectors[i].sector_above = data.sectors[i-1]
if i < size - 1:
data.sectors[i].sector_below = data.sectors[i+1]
+1
View File
@@ -0,0 +1 @@
uid://jn0w7kgstq1j
+9
View File
@@ -0,0 +1,9 @@
[gd_scene load_steps=3 format=3 uid="uid://bn4r4f3str55v"]
[ext_resource type="Script" uid="uid://jn0w7kgstq1j" path="res://game/generators/stage_generator.gd" id="1_7pxno"]
[ext_resource type="PackedScene" uid="uid://bh1v37wol5ktj" path="res://game/generators/sector_generator.tscn" id="2_etmdi"]
[node name="StageGenerator" type="Node"]
script = ExtResource("1_7pxno")
[node name="SectorGenerator" parent="." instance=ExtResource("2_etmdi")]
+52
View File
@@ -0,0 +1,52 @@
class_name WorldGenerator
extends Node
const AREA_COUNT = 3
var local_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var area_seed_rng : RandomNumberGenerator = RandomNumberGenerator.new()
var weapon_rng : RandomNumberGenerator = RandomNumberGenerator.new()
@onready var area_generator : AreaGenerator = $AreaGenerator
func generate(seed_value: int) -> WorldData:
local_seed_rng.seed = seed_value
area_seed_rng.seed = local_seed_rng.randi()
weapon_rng.seed = local_seed_rng.randi()
var data : WorldData = WorldData.new()
data.seed_value = seed_value
_fill_areas(data)
_fill_weapons(data)
return data
func _fill_areas(data : WorldData) -> void:
for i in AREA_COUNT:
var seed_value := area_seed_rng.randi()
var area := area_generator.generate(seed_value)
data.areas.append(area)
func _fill_weapons(data : WorldData) -> void:
var weapons_by_group : Dictionary[String, Array] = {}
for weapon in SaveManager.WEAPONS:
if not weapon.group in weapons_by_group:
weapons_by_group[weapon.group] = [] as Array[WeaponData]
weapons_by_group[weapon.group].append(weapon)
for group in weapons_by_group:
var array : Array[WeaponData] = weapons_by_group[group]
if array.size() == 0: continue
var index := weapon_rng.randi_range(1, array.size()) - 1
data.player_start_weapons.append(array[index])
data.player_start_weapons.shuffle()
+1
View File
@@ -0,0 +1 @@
uid://b7e3xk14le68j
+9
View File
@@ -0,0 +1,9 @@
[gd_scene load_steps=3 format=3 uid="uid://ggf76ayl53bb"]
[ext_resource type="Script" uid="uid://b7e3xk14le68j" path="res://game/generators/world_generator.gd" id="1_c1jvo"]
[ext_resource type="PackedScene" uid="uid://c4l1cv3o25lhv" path="res://game/generators/area_generator.tscn" id="2_exe4n"]
[node name="WorldGenerator" type="Node"]
script = ExtResource("1_c1jvo")
[node name="AreaGenerator" parent="." instance=ExtResource("2_exe4n")]