Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e93ddc1fdd | |||
| 5a05a5ee2a |
@@ -1,19 +1,13 @@
|
|||||||
---
|
---
|
||||||
name: Godot 4.7 Core Rules
|
name: Godot 4.4 Core Rules
|
||||||
priority: high
|
priority: high
|
||||||
---
|
---
|
||||||
|
|
||||||
Ты — senior Godot 4.7 GDScript разработчик.
|
Ты — senior Godot 4.4 GDScript разработчик.
|
||||||
|
|
||||||
- Use Godot 4.7+ API.
|
|
||||||
- Do not use Godot 3.x syntax or APIs.
|
|
||||||
- Follow the existing project architecture and coding style.
|
|
||||||
- Do not introduce unnecessary abstractions.
|
|
||||||
- Do not modify unrelated files.
|
|
||||||
|
|
||||||
|
- Всегда используй Godot 4.4+ API.
|
||||||
- Пиши строго типизированный код (`var health: int = 100`, `: Array[Node]` и т.д.).
|
- Пиши строго типизированный код (`var health: int = 100`, `: Array[Node]` и т.д.).
|
||||||
- Предпочитай Signals вместо проверки в _process.
|
- Предпочитай Signals вместо проверки в _process.
|
||||||
- Используй @export, @export_range, @export_enum, @onready.
|
- Используй @export, @export_range, @export_enum, @onready.
|
||||||
- Composition over deep inheritance.
|
- Composition over deep inheritance.
|
||||||
- Менеджеры и автолоады выноси в отдельные singleton'ы.
|
- Менеджеры и автолоады выноси в отдельные singleton'ы.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
- use spaces not tabs for indentation
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
name: Android production release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-build-publish:
|
|
||||||
runs-on: godot
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
lfs: true
|
|
||||||
|
|
||||||
- name: Verify tag belongs to main
|
|
||||||
run: |
|
|
||||||
git fetch origin main
|
|
||||||
git merge-base --is-ancestor "${GITHUB_SHA}" origin/main
|
|
||||||
|
|
||||||
- name: Show Godot version
|
|
||||||
run: godot --version
|
|
||||||
|
|
||||||
- name: Import project
|
|
||||||
run: |
|
|
||||||
rm -rf .godot
|
|
||||||
godot --headless --path . --editor --import --quit --verbose
|
|
||||||
|
|
||||||
- name: Run all tests
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
mapfile -t tests < <(find tests -maxdepth 1 -type f -name 'test_*.gd' | sort)
|
|
||||||
test "${#tests[@]}" -gt 0
|
|
||||||
|
|
||||||
for test_file in "${tests[@]}"; do
|
|
||||||
echo "::group::${test_file}"
|
|
||||||
godot --headless --path . --script "res://${test_file}"
|
|
||||||
echo "::endgroup::"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Prepare Android signing
|
|
||||||
env:
|
|
||||||
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
|
||||||
run: |
|
|
||||||
test -n "${ANDROID_KEYSTORE_BASE64}"
|
|
||||||
printf '%s' "${ANDROID_KEYSTORE_BASE64}" | base64 --decode > "${RUNNER_TEMP}/release.keystore"
|
|
||||||
test -s "${RUNNER_TEMP}/release.keystore"
|
|
||||||
|
|
||||||
- name: Configure release AAB
|
|
||||||
env:
|
|
||||||
RELEASE_VERSION: ${{ github.ref_name }}
|
|
||||||
RELEASE_VERSION_CODE: ${{ github.run_number }}
|
|
||||||
run: |
|
|
||||||
python3 - <<'PY'
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
path = Path("export_presets.cfg")
|
|
||||||
text = path.read_text()
|
|
||||||
start = text.index('[preset.1.options]')
|
|
||||||
head, android = text[:start], text[start:]
|
|
||||||
replacements = (
|
|
||||||
(r'gradle_build/use_gradle_build=false', 'gradle_build/use_gradle_build=true'),
|
|
||||||
(r'gradle_build/export_format=0', 'gradle_build/export_format=1'),
|
|
||||||
(r'package/signed=false', 'package/signed=true'),
|
|
||||||
(r'version/code=\d+', f'version/code={100000 + int(os.environ["RELEASE_VERSION_CODE"])}'),
|
|
||||||
(r'version/name="[^"]*"', f'version/name="{os.environ["RELEASE_VERSION"].removeprefix("v")}"'),
|
|
||||||
)
|
|
||||||
for pattern, replacement in replacements:
|
|
||||||
android, count = re.subn(pattern, replacement, android, count=1)
|
|
||||||
if count != 1:
|
|
||||||
raise RuntimeError(f'Expected one Android preset match for {pattern!r}, got {count}')
|
|
||||||
path.write_text(head + android)
|
|
||||||
PY
|
|
||||||
|
|
||||||
- name: Build signed Android App Bundle
|
|
||||||
env:
|
|
||||||
GODOT_ANDROID_KEYSTORE_RELEASE_USER: ${{ secrets.ANDROID_KEYSTORE_ALIAS }}
|
|
||||||
GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
export GODOT_ANDROID_KEYSTORE_RELEASE_PATH="${RUNNER_TEMP}/release.keystore"
|
|
||||||
mkdir -p build
|
|
||||||
godot --headless --path . --export-release "Android" build/owniverse-${GITHUB_REF_NAME}.aab
|
|
||||||
test -s "build/owniverse-${GITHUB_REF_NAME}.aab"
|
|
||||||
ls -lh "build/owniverse-${GITHUB_REF_NAME}.aab"
|
|
||||||
|
|
||||||
- name: Publish to Google Play production
|
|
||||||
uses: r0adkll/upload-google-play@v1
|
|
||||||
with:
|
|
||||||
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
|
|
||||||
packageName: com.KIDGameProduction.Owniverse
|
|
||||||
releaseFiles: build/owniverse-${{ github.ref_name }}.aab
|
|
||||||
tracks: production
|
|
||||||
status: completed
|
|
||||||
|
|
||||||
- name: Upload release bundle
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: owniverse-${{ github.ref_name }}-aab
|
|
||||||
path: build/owniverse-${{ github.ref_name }}.aab
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 90
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
name: Android
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
android:
|
||||||
|
runs-on: godot
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|
||||||
|
- name: Godot version
|
||||||
|
run: |
|
||||||
|
godot --version
|
||||||
|
|
||||||
|
|
||||||
|
- name: Java version
|
||||||
|
run: |
|
||||||
|
java -version
|
||||||
|
|
||||||
|
|
||||||
|
- name: Android SDK
|
||||||
|
run: |
|
||||||
|
sdkmanager --list | grep "platforms;android-35"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Build APK
|
||||||
|
run: |
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
godot \
|
||||||
|
--headless \
|
||||||
|
--path . \
|
||||||
|
--export-release "Android" \
|
||||||
|
build/app.apk
|
||||||
|
|
||||||
|
|
||||||
|
- name: Verify APK
|
||||||
|
run: |
|
||||||
|
test -f build/app.apk
|
||||||
|
ls -lh build/app.apk
|
||||||
|
|
||||||
|
|
||||||
|
- name: Upload APK
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: android-apk
|
||||||
|
path: build/app.apk
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
name: Testing builds
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- testing
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-and-build:
|
|
||||||
runs-on: godot
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
|
|
||||||
- name: Show Godot version
|
|
||||||
run: godot --version
|
|
||||||
|
|
||||||
- name: Import project
|
|
||||||
run: |
|
|
||||||
rm -rf .godot
|
|
||||||
godot --headless --path . --editor --import --quit --verbose
|
|
||||||
|
|
||||||
- name: Run all tests
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
mapfile -t tests < <(find tests -maxdepth 1 -type f -name 'test_*.gd' | sort)
|
|
||||||
test "${#tests[@]}" -gt 0
|
|
||||||
|
|
||||||
for test_file in "${tests[@]}"; do
|
|
||||||
echo "::group::${test_file}"
|
|
||||||
godot --headless --path . --script "res://${test_file}"
|
|
||||||
echo "::endgroup::"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Build Android APK
|
|
||||||
run: |
|
|
||||||
mkdir -p build
|
|
||||||
godot --headless --path . --export-release "Android" build/owniverse-testing.apk
|
|
||||||
|
|
||||||
- name: Build Windows EXE
|
|
||||||
run: |
|
|
||||||
godot --headless --path . --export-release "Windows Desktop" build/owniverse-testing.exe
|
|
||||||
|
|
||||||
- name: Verify builds
|
|
||||||
run: |
|
|
||||||
test -s build/owniverse-testing.apk
|
|
||||||
test -s build/owniverse-testing.exe
|
|
||||||
ls -lh build/owniverse-testing.apk build/owniverse-testing.exe
|
|
||||||
|
|
||||||
- name: Upload testing builds
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: owniverse-testing-${{ github.sha }}
|
|
||||||
path: |
|
|
||||||
build/owniverse-testing.apk
|
|
||||||
build/owniverse-testing.exe
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 14
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
/android/
|
/android/
|
||||||
*.import
|
*.import
|
||||||
!data/*.txt.import
|
|
||||||
|
|
||||||
# MacOS specific ignores
|
# MacOS specific ignores
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
extends Node
|
extends Node
|
||||||
const E = preload("res://world/owniverse/math/exact.gd")
|
|
||||||
|
|
||||||
const SPEED_LIMIT: int = 6
|
const SPEED_LIMIT: int = 4
|
||||||
|
|
||||||
# Write a readable diagnostic copy next to the encrypted save. Never used for loading.
|
|
||||||
var save_plaintext_copy: bool = true
|
|
||||||
|
|
||||||
var Settings: Dictionary = {
|
var Settings: Dictionary = {
|
||||||
"filename": "save-0001",
|
"filename": "save-0001",
|
||||||
@@ -20,8 +16,6 @@ var Locale = "en"
|
|||||||
var OwniverseEntities: Dictionary = {}
|
var OwniverseEntities: Dictionary = {}
|
||||||
var OwniverseItems: Dictionary = {}
|
var OwniverseItems: Dictionary = {}
|
||||||
var Templates: Dictionary = {}
|
var Templates: Dictionary = {}
|
||||||
var LifeRules: Dictionary = {}
|
|
||||||
var CivilizationRules: Dictionary = {}
|
|
||||||
|
|
||||||
var batch_count: float = 40.0 # must be even not odd
|
var batch_count: float = 40.0 # must be even not odd
|
||||||
|
|
||||||
@@ -32,59 +26,35 @@ func get_localized_item_description(item_id: String, item: String) -> String:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
# Russian templates include the class; legacy English keys omit it.
|
|
||||||
func get_template(id: String, category: String, field: String) -> Dictionary:
|
|
||||||
var rows: Dictionary = Templates.get(Locale, {})
|
|
||||||
for key in [id + "." + category + "." + field, id + "." + field]:
|
|
||||||
if rows.has(key):
|
|
||||||
return rows[key]
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
func render_template(row: Dictionary, variables: Dictionary) -> String:
|
|
||||||
var result: String = str(row.get("text", ""))
|
|
||||||
for i in range(5):
|
|
||||||
var variable: String = str(row.get("value" + str(i), "")).strip_edges()
|
|
||||||
var value: String = str(variables.get(variable, "—")) if variable != "" else ""
|
|
||||||
result = result.replace("%value" + str(i) + "%", value)
|
|
||||||
return result.replace("<br>", "\n").replace("[p]", "\n")
|
|
||||||
|
|
||||||
|
|
||||||
func get_description(item_id: String, items: Array = []) -> String:
|
func get_description(item_id: String, items: Array = []) -> String:
|
||||||
var row: Dictionary = Templates.get(Locale, {}).get(item_id, {})
|
if !Templates[Locale].has(item_id):
|
||||||
var variables: Dictionary = {}
|
return ""
|
||||||
for i in mini(items.size(), 5):
|
var description: String = Templates[Locale][item_id]["text"]
|
||||||
variables[str(row.get("value" + str(i), ""))] = items[i]
|
var value = 0
|
||||||
return render_template(row, variables)
|
for item in items:
|
||||||
|
description.replace("value" + str(value), str(item))
|
||||||
|
return description
|
||||||
|
|
||||||
|
|
||||||
func format_number(value, digits: int = 0) -> String:
|
func format_number(value: float, digits: int = 0) -> String:
|
||||||
return E.grouped(value, digits)
|
if value == 0: return ""
|
||||||
|
if value < 10_000:
|
||||||
|
return "%.*f" % [digits, value]
|
||||||
|
|
||||||
|
var exp_value = int(floor(log(abs(value)) / log(10.0)))
|
||||||
|
var mantissa = value / pow(10.0, exp_value)
|
||||||
|
|
||||||
|
return "%.*f" % [digits, mantissa] + "E%+d" % exp_value
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
CivilizationRules.clear()
|
OwniverseEntities = _read_from_csv("res://data/owniverse_entitites.txt")
|
||||||
for row: Dictionary in _read_from_csv("res://data/civilization_rules.txt").values():
|
|
||||||
if not CivilizationRules.has(row.stage):
|
|
||||||
CivilizationRules[row.stage] = {"home": row.home, "span": E.of(row.span), "stars": E.of(row.stars), "ethics": {},
|
|
||||||
"colonizes": row.colonizes == "1", "fights": row.fights == "1", "diplomacy": row.diplomacy == "1", "worships": row.worships == "1"}
|
|
||||||
CivilizationRules[row.stage].ethics[row.ethic] = row
|
|
||||||
var stages: Array = CivilizationRules.keys()
|
|
||||||
stages.sort()
|
|
||||||
for i in stages.size():
|
|
||||||
CivilizationRules[stages[i]].next = stages[i + 1] if i + 1 < stages.size() else "Ct"
|
|
||||||
CivilizationRules[stages[i]].previous = stages[i - 1] if i > 0 else "C0.1"
|
|
||||||
CivilizationRules[stages[i]].colony = stages[maxi(0, i - 2)]
|
|
||||||
CivilizationRules.Ct = {"home": "", "span": 0.0, "stars": 0.0, "ethics": {}, "next": "Ct", "previous": "C4.4", "colonizes": false, "fights": false, "diplomacy": false, "worships": false}
|
|
||||||
LifeRules = _read_from_csv("res://data/life_rules.txt")
|
|
||||||
OwniverseEntities = _read_from_csv("res://data/owniverse_entities.txt")
|
|
||||||
OwniverseItems = _read_from_csv("res://data/owniverse_items.txt")
|
OwniverseItems = _read_from_csv("res://data/owniverse_items.txt")
|
||||||
|
|
||||||
Locales["en"] = _read_from_csv("res://data/locale.en.txt")
|
Locales["en"] = _read_from_csv("res://data/locale.en.txt")
|
||||||
Locales["ru"] = _read_from_csv("res://data/locale.ru.txt")
|
Locales["ru"] = _read_from_csv("res://data/locale.ru.txt")
|
||||||
|
|
||||||
|
Templates["en"] = _read_from_csv("res://data/templates.en.txt")
|
||||||
Templates = OwniverseTemplate.get_data()
|
|
||||||
|
|
||||||
|
|
||||||
func _read_from_csv(file_path: String) -> Dictionary:
|
func _read_from_csv(file_path: String) -> Dictionary:
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dojk16crca3cx
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# SaveManager.gd (добавить в AutoLoad)
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# ~/Library/Application Support/Godot/app_userdata/Owniverse Adventure/savegame.cfg
|
||||||
|
const SETTING_SECTION := "Settings"
|
||||||
|
const SAVE_PATH = "user://settings.cfg"
|
||||||
|
|
||||||
|
#region Save Load routines
|
||||||
|
|
||||||
|
|
||||||
|
func save_data(filename: String, password: String, data: Dictionary) -> void:
|
||||||
|
filename = "user://" + filename + ".adventure"
|
||||||
|
var file := FileAccess.open_encrypted_with_pass(filename, FileAccess.WRITE, password)
|
||||||
|
if file == null:
|
||||||
|
push_error("Can't write to the file: ", filename)
|
||||||
|
return
|
||||||
|
|
||||||
|
file.store_var(data) # бинарно + быстрее + сериализация
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
func load_data(filename: String, password: String) -> Dictionary:
|
||||||
|
filename = "user://" + filename + ".adventure"
|
||||||
|
if not FileAccess.file_exists(filename):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
var file := FileAccess.open_encrypted_with_pass(filename, FileAccess.READ, password)
|
||||||
|
if file == null:
|
||||||
|
push_error(filename, " couldn't be decrypted.")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
var data: Variant = file.get_var()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
return data if data is Dictionary else {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Settings
|
||||||
|
func save_settings():
|
||||||
|
var config = ConfigFile.new()
|
||||||
|
|
||||||
|
for item in Global.Settings:
|
||||||
|
config.set_value(SETTING_SECTION, item, Global.Settings[item])
|
||||||
|
config.save(SAVE_PATH)
|
||||||
|
|
||||||
|
func load_settings():
|
||||||
|
var config = ConfigFile.new()
|
||||||
|
var err = config.load(SAVE_PATH)
|
||||||
|
if err != OK:
|
||||||
|
return false
|
||||||
|
for item in Global.Settings:
|
||||||
|
Global.Settings[item] = config.get_value(SETTING_SECTION, item, Global.Settings[item])
|
||||||
|
return true
|
||||||
|
#endregion
|
||||||
+306
@@ -0,0 +1,306 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
const OWNIVERSE_ITEM = preload("uid://d3xjfxwe3w16v")
|
||||||
|
|
||||||
|
const SPEED_TEXTURE_NAME_TEMPLATE = "res://ui/topmenu/time&speed/time%s.png"
|
||||||
|
|
||||||
|
const PAGE_COUNT = 5
|
||||||
|
const PAGE_WIDTH = 1080
|
||||||
|
const DRAG_TOLERANCE = 360
|
||||||
|
const SWIPE_DURATION: float = 0.4
|
||||||
|
|
||||||
|
@onready var stage_page_scroller: ScrollContainer = $StageRows/PageScroller
|
||||||
|
|
||||||
|
@onready var item_pages: Array[Control] = [
|
||||||
|
$StageRows/PageScroller/HBoxContainer/ForcePage/Forces,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/ResourcePage/HBoxContainer/Resources,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/StarPage/Stars,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/StructurePage/Structures,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/Life,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/LivingPlanet,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/Civ0,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/Civ1,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/Civ2,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/Civ3,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Planets/Civ4
|
||||||
|
]
|
||||||
|
|
||||||
|
@onready var page_actions: Dictionary[int, OwniverseAction] = {
|
||||||
|
2: $StageRows/PageScroller/HBoxContainer/StarPage/Actions,
|
||||||
|
3: $StageRows/PageScroller/HBoxContainer/StructurePage/Actions,
|
||||||
|
}
|
||||||
|
|
||||||
|
@onready var g_item_descriptions: Array = [
|
||||||
|
$StageRows/PageScroller/HBoxContainer/ForcePage/Description,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/ResourcePage/Description,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/StarPage/Description,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/StructurePage/Description,
|
||||||
|
$StageRows/PageScroller/HBoxContainer/LifePage/Description
|
||||||
|
]
|
||||||
|
|
||||||
|
@onready var date_time: Label = $StageRows/TopMenu/InfoPanel/DateTime
|
||||||
|
|
||||||
|
@onready var g_speed_icons: Array = [
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed1,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed2,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed3,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed4,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed5,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed6,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed7,
|
||||||
|
$StageRows/TopMenu/InfoPanel/Speed/Speed8
|
||||||
|
]
|
||||||
|
|
||||||
|
@onready var g_time_minus: TextureButton = $StageRows/TopMenu/TimeMinus
|
||||||
|
@onready var g_time_plus: TextureButton = $StageRows/TopMenu/TimePlus
|
||||||
|
|
||||||
|
|
||||||
|
var g_tween: Tween = null
|
||||||
|
var g_dragged_start: Vector2 = Vector2.ZERO
|
||||||
|
var g_scroll_start: int = 0
|
||||||
|
#var g_current_page: int = 0
|
||||||
|
|
||||||
|
var g_last_scroll_updated: int = 0
|
||||||
|
|
||||||
|
var f_check_swipe: bool = false
|
||||||
|
var g_swipe_time_delta: float = 0
|
||||||
|
|
||||||
|
var g_counters: Dictionary[String, Counter] = {
|
||||||
|
"swipe": Counter.new(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var g_active_items: Dictionary = {}
|
||||||
|
|
||||||
|
var owniverse:Owniverse = Owniverse.new()
|
||||||
|
var owniverse_items: Dictionary[String, OwniverseItem] = {}
|
||||||
|
|
||||||
|
var item_list_to_update: Dictionary = {}
|
||||||
|
|
||||||
|
func set_datetime(value: float):
|
||||||
|
date_time.text = str(snapped(value, 0.1))
|
||||||
|
|
||||||
|
#region Item manipulations: update and visibility
|
||||||
|
|
||||||
|
|
||||||
|
func add_to_update_list(item_id: String, amount: int) -> void:
|
||||||
|
if item_list_to_update.has(item_id):
|
||||||
|
item_list_to_update[item_id] += amount
|
||||||
|
else:
|
||||||
|
item_list_to_update[item_id] = amount
|
||||||
|
|
||||||
|
|
||||||
|
func set_owniverse_item_value() -> void:
|
||||||
|
for item_id in owniverse.items_to_update:
|
||||||
|
if owniverse_items.has(item_id):
|
||||||
|
owniverse_items[item_id].set_label(owniverse.items_to_update[item_id])
|
||||||
|
owniverse.items_to_update = {}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
func _on_indicator_pressed(indicator_name: String, page: int = 0):
|
||||||
|
_set_description(indicator_name, page)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_item_description(item: OwniverseItem) -> void:
|
||||||
|
var description: String = "[b]" \
|
||||||
|
+ Global.get_localized_item_description(item.item_name, "label") \
|
||||||
|
+"[/b]" \
|
||||||
|
+"\n" \
|
||||||
|
+ Global.get_localized_item_description(item.item_name, "description")
|
||||||
|
var desc_page = clamp(item.item_page, 0, 4)
|
||||||
|
g_item_descriptions[desc_page].text = description
|
||||||
|
|
||||||
|
|
||||||
|
func _set_description(item_name: String, page: int) -> void:
|
||||||
|
var description = Global.get_description(item_name + ".Name")
|
||||||
|
description += "\n"
|
||||||
|
description += Global.get_description(item_name + ".Description")
|
||||||
|
g_item_descriptions[page].text = description
|
||||||
|
|
||||||
|
|
||||||
|
func _control_page(item: OwniverseItem) -> void:
|
||||||
|
# TODO переписать это ↓
|
||||||
|
if !g_active_items.has(item.item_page):
|
||||||
|
g_active_items[item.item_page] = null
|
||||||
|
|
||||||
|
var current_item: OwniverseItem = g_active_items[item.item_page]
|
||||||
|
if current_item == item:
|
||||||
|
return
|
||||||
|
|
||||||
|
g_active_items[item.item_page] = item
|
||||||
|
|
||||||
|
if current_item != null and current_item.item_page == item.item_page:
|
||||||
|
current_item.set_selection(false)
|
||||||
|
|
||||||
|
item.set_selection(true)
|
||||||
|
|
||||||
|
# subpages
|
||||||
|
if item.item_sub_page != -1:
|
||||||
|
item_pages[item.item_sub_page].visible = true
|
||||||
|
|
||||||
|
if current_item == null \
|
||||||
|
or current_item.item_sub_page == -1 \
|
||||||
|
or current_item.item_sub_page == item.item_sub_page:
|
||||||
|
return
|
||||||
|
item_pages[current_item.item_sub_page].visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _init_owniverse_items() -> bool:
|
||||||
|
owniverse_items = {}
|
||||||
|
for item_id in Global.OwniverseItems:
|
||||||
|
var item_props: Dictionary = Global.OwniverseItems[item_id]
|
||||||
|
var item: OwniverseItem = OWNIVERSE_ITEM.instantiate()
|
||||||
|
if !item_props.has("page"):
|
||||||
|
printerr("Item `", item_id, "` has no `page` key.")
|
||||||
|
return false
|
||||||
|
var page: int = int(item_props.page)
|
||||||
|
item_pages[page].add_child(item)
|
||||||
|
item.init_button(item_props)
|
||||||
|
item.item_activated.connect(item_activated)
|
||||||
|
|
||||||
|
owniverse_items[item_id] = item
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func item_activated(item: OwniverseItem) -> void:
|
||||||
|
_control_page(item)
|
||||||
|
_set_item_description(item)
|
||||||
|
|
||||||
|
if item.item_id == "S" or item.item_id == "H":
|
||||||
|
owniverse.produce(item.item_id, 100_000)
|
||||||
|
|
||||||
|
func _unlock_item(item_id: String):
|
||||||
|
owniverse_items[item_id].set_visible(true)
|
||||||
|
|
||||||
|
|
||||||
|
func _check_counters(delta: float) -> Array:
|
||||||
|
var actions: Array = []
|
||||||
|
for k in g_counters:
|
||||||
|
var cnt: Counter = g_counters[k]
|
||||||
|
if not cnt.is_active:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cnt.value += delta
|
||||||
|
if cnt.value >= cnt.sec:
|
||||||
|
actions.append(k)
|
||||||
|
cnt.value = 0
|
||||||
|
cnt.is_active = false
|
||||||
|
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
#region Swipe
|
||||||
|
|
||||||
|
func _do_actions(actions: Array) -> void:
|
||||||
|
for action: String in actions:
|
||||||
|
match action:
|
||||||
|
"swipe":
|
||||||
|
_swipe_to_nearest_page()
|
||||||
|
|
||||||
|
|
||||||
|
func _swipe_to_nearest_page() -> void:
|
||||||
|
if stage_page_scroller.scroll_horizontal % PAGE_WIDTH == 0: return
|
||||||
|
|
||||||
|
var new_page: int = round(1.0 * stage_page_scroller.scroll_horizontal / PAGE_WIDTH)
|
||||||
|
|
||||||
|
if g_tween != null:
|
||||||
|
if g_tween.is_running():
|
||||||
|
return
|
||||||
|
|
||||||
|
g_tween = stage_page_scroller.get_tree().create_tween()
|
||||||
|
g_tween.tween_property(stage_page_scroller, "scroll_horizontal",
|
||||||
|
new_page * PAGE_WIDTH, SWIPE_DURATION).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT)
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventScreenDrag:
|
||||||
|
stage_page_scroller.scroll_horizontal = clamp(
|
||||||
|
stage_page_scroller.scroll_horizontal - PAGE_COUNT * event.screen_relative.x,
|
||||||
|
0, PAGE_WIDTH * (PAGE_COUNT - 1))
|
||||||
|
g_counters.swipe.is_active = true
|
||||||
|
g_counters.swipe.value = 0
|
||||||
|
elif event is InputEventPanGesture:
|
||||||
|
g_counters.swipe.is_active = true
|
||||||
|
g_counters.swipe.value = 0
|
||||||
|
elif event is InputEventScreenTouch:
|
||||||
|
pass
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
owniverse.init_enitities()
|
||||||
|
owniverse.load_data()
|
||||||
|
_init_owniverse_items()
|
||||||
|
|
||||||
|
owniverse.unlock_item.connect(_unlock_item)
|
||||||
|
g_counters.swipe.sec = 0.2
|
||||||
|
|
||||||
|
for pa in page_actions:
|
||||||
|
page_actions[pa].action_pressed.connect(_page_action_pressed)
|
||||||
|
page_actions[pa].page_id = pa
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
|
||||||
|
var year_delta: float = owniverse.add_time_delta(delta)
|
||||||
|
set_datetime(year_delta)
|
||||||
|
owniverse.cycle(year_delta)
|
||||||
|
|
||||||
|
var actions = _check_counters(delta)
|
||||||
|
_do_actions(actions)
|
||||||
|
|
||||||
|
_set_active_page_actions()
|
||||||
|
|
||||||
|
func _set_active_page_actions() -> void:
|
||||||
|
for pa in page_actions:
|
||||||
|
if !g_active_items.has(pa): continue
|
||||||
|
|
||||||
|
var item_id: String = g_active_items[pa].item_id
|
||||||
|
var amount = owniverse.get_available_to_produce(item_id)
|
||||||
|
page_actions[pa].set_actions(item_id, amount)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _page_action_pressed(page_id: int, action_amount: float) -> void:
|
||||||
|
if !g_active_items.has(page_id):
|
||||||
|
return
|
||||||
|
|
||||||
|
var item_id: String = g_active_items[page_id].item_id
|
||||||
|
|
||||||
|
if action_amount > 0:
|
||||||
|
owniverse.produce(item_id, action_amount)
|
||||||
|
|
||||||
|
|
||||||
|
func _change_speed(delta: int) -> void:
|
||||||
|
var speed: int = owniverse.change_speed(delta)
|
||||||
|
var ind: int = 1
|
||||||
|
for icon in g_speed_icons:
|
||||||
|
if ind <= speed:
|
||||||
|
icon.visible = true
|
||||||
|
else:
|
||||||
|
icon.visible = false
|
||||||
|
ind += 1
|
||||||
|
if speed == 1:
|
||||||
|
g_time_minus.texture_normal = load(SPEED_TEXTURE_NAME_TEMPLATE % "x")
|
||||||
|
g_time_plus.texture_normal = load(SPEED_TEXTURE_NAME_TEMPLATE % "2")
|
||||||
|
elif speed == Global.SPEED_LIMIT:
|
||||||
|
g_time_minus.texture_normal = load(SPEED_TEXTURE_NAME_TEMPLATE % str(Global.SPEED_LIMIT - 1))
|
||||||
|
g_time_plus.texture_normal = load(SPEED_TEXTURE_NAME_TEMPLATE % "x")
|
||||||
|
else:
|
||||||
|
g_time_minus.texture_normal = load(SPEED_TEXTURE_NAME_TEMPLATE % str(speed - 1))
|
||||||
|
g_time_plus.texture_normal = load(SPEED_TEXTURE_NAME_TEMPLATE % str(speed + 1))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_topmenu_button_pressed(ButtonName) -> void:
|
||||||
|
print(ButtonName)
|
||||||
|
#var s: float = 1E15
|
||||||
|
#var z = 1.0
|
||||||
|
#for i in range(30):
|
||||||
|
#print(i, " | ", z, " | ", " | ", s - z)
|
||||||
|
#z *= 10
|
||||||
|
|
||||||
|
|
||||||
|
func _on_save_data() -> void:
|
||||||
|
owniverse.save_data()
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user