feat: add dailylogin feature
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
## [NEXT]
|
||||
|
||||
## [2.2.1] — 2026-05-01
|
||||
- Updated daily login logic to support multiple reward types (star, gold, fragments).
|
||||
- Fixed leaderboard UI to dynamically update with player changes.
|
||||
- Added full backend Nakama support for daily login claiming and administration.
|
||||
- Refactored Admin Panel to include a bordered 30-day grid layout with January-December selection.
|
||||
|
||||
## [2.2.0] — 2026-04-30
|
||||
- Redesigned Social Panel with a 3-tab layout (Search, Requests, Friends) to fix UI overlap issues.
|
||||
- Fixed an issue where offline friend requests were not being delivered properly.
|
||||
|
||||
@@ -1,7 +1,34 @@
|
||||
{
|
||||
"latest_version": "2.1.9",
|
||||
"latest_version": "2.2.1",
|
||||
"minimum_app_version": "2.1.0",
|
||||
"releases": [
|
||||
{
|
||||
"version": "2.2.1",
|
||||
"date": "2026-05-01",
|
||||
"pck_url": "https://raw.githubusercontent.com/adtpdn/tekton-updates/main/latest/patch.pck",
|
||||
"pck_size": 0,
|
||||
"changelog": [
|
||||
"Updated daily login logic to support multiple reward types (star, gold, fragments).",
|
||||
"Fixed leaderboard UI to dynamically update with player changes.",
|
||||
"Added full backend Nakama support for daily login claiming and administration.",
|
||||
"Refactored Admin Panel to include a bordered 30-day grid layout with January-December selection."
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.2.0",
|
||||
"date": "2026-04-30",
|
||||
"pck_url": "https://raw.githubusercontent.com/adtpdn/tekton-updates/main/latest/patch.pck",
|
||||
"pck_size": 0,
|
||||
"changelog": [
|
||||
"Redesigned Social Panel with a 3-tab layout (Search, Requests, Friends) to fix UI overlap issues.",
|
||||
"Fixed an issue where offline friend requests were not being delivered properly.",
|
||||
"Added persistent storage for Direct Messages, loading previous chat history when opening a DM.",
|
||||
"Improved real-time Nakama socket listening to allow incoming DMs to be received instantly even when the chat tab is closed.",
|
||||
"Fixed account state pollution where friend data leaked when switching users without restarting the client.",
|
||||
"Corrected server-side RPCs for Nakama send_friend_request ensuring persistent push notifications.",
|
||||
"Re-themed Social Panel DM UI to use dark brown fonts for high-contrast readability."
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.1.9",
|
||||
"date": "2026-04-29",
|
||||
@@ -72,4 +99,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+237
-28
@@ -8,7 +8,7 @@ custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="build/tekton_armageddon_v2.1.8.exe"
|
||||
export_path="build/tekton_armageddon_v2.2.1.exe"
|
||||
patches=PackedStringArray()
|
||||
patch_delta_encoding=false
|
||||
patch_delta_compression_level_zstd=19
|
||||
@@ -70,7 +70,6 @@ ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debu
|
||||
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
|
||||
Remove-Item -Recurse -Force '{temp_dir}'"
|
||||
|
||||
|
||||
[preset.1]
|
||||
|
||||
name="Android"
|
||||
@@ -81,7 +80,7 @@ custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="build/tekton-dash-armageddon-v.2.1.8.apk"
|
||||
export_path="build/tekton-dash-armageddon-v.2.2.1.apk"
|
||||
patches=PackedStringArray()
|
||||
patch_delta_encoding=false
|
||||
patch_delta_compression_level_zstd=19
|
||||
@@ -307,7 +306,7 @@ custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="build/tekton_armageddon_v2.1.8.zip"
|
||||
export_path="build/tekton_armageddon_v2.2.1.zip"
|
||||
patches=PackedStringArray()
|
||||
patch_delta_encoding=false
|
||||
patch_delta_compression_level_zstd=19
|
||||
@@ -323,32 +322,228 @@ script_export_mode=2
|
||||
|
||||
[preset.2.options]
|
||||
|
||||
export/distribution_type=1
|
||||
binary_format/architecture="universal"
|
||||
custom_template/debug=""
|
||||
custom_template/release=""
|
||||
debug/export_console_wrapper=0
|
||||
binary_format/embed_pck=true
|
||||
texture_format/s3tc_bptc=true
|
||||
texture_format/etc2_astc=false
|
||||
shader_baker/enabled=true
|
||||
binary_format/architecture="universal"
|
||||
codesign/enable=false
|
||||
codesign/timestamp=true
|
||||
codesign/timestamp_server_url=""
|
||||
codesign/digest_algorithm=1
|
||||
codesign/identity=""
|
||||
codesign/identity_type=0
|
||||
codesign/custom_options=PackedStringArray()
|
||||
application/modify_resources=false
|
||||
application/liquid_glass_icon=""
|
||||
application/icon=""
|
||||
application/console_wrapper_icon=""
|
||||
application/icon_interpolation=4
|
||||
application/file_version="2.1"
|
||||
application/product_version="2.1"
|
||||
application/company_name="DanchieGo"
|
||||
application/product_name="Tekton Armageddon"
|
||||
application/file_description=""
|
||||
application/bundle_identifier=""
|
||||
application/signature=""
|
||||
application/app_category="Games"
|
||||
application/short_version=""
|
||||
application/version=""
|
||||
application/copyright=""
|
||||
application/trademarks=""
|
||||
application/copyright_localized={}
|
||||
application/min_macos_version_x86_64="10.12"
|
||||
application/min_macos_version_arm64="11.00"
|
||||
application/export_angle=0
|
||||
display/high_res=true
|
||||
shader_baker/enabled=true
|
||||
application/additional_plist_content=""
|
||||
xcode/platform_build="14C18"
|
||||
xcode/sdk_version="13.1"
|
||||
xcode/sdk_build="22C55"
|
||||
xcode/sdk_name="macosx13.1"
|
||||
xcode/xcode_version="1420"
|
||||
xcode/xcode_build="14C18"
|
||||
codesign/codesign=1
|
||||
codesign/installer_identity=""
|
||||
codesign/apple_team_id=""
|
||||
codesign/identity=""
|
||||
codesign/entitlements/custom_file=""
|
||||
codesign/entitlements/allow_jit_code_execution=false
|
||||
codesign/entitlements/allow_unsigned_executable_memory=false
|
||||
codesign/entitlements/allow_dyld_environment_variables=false
|
||||
codesign/entitlements/disable_library_validation=false
|
||||
codesign/entitlements/audio_input=false
|
||||
codesign/entitlements/camera=false
|
||||
codesign/entitlements/location=false
|
||||
codesign/entitlements/address_book=false
|
||||
codesign/entitlements/calendars=false
|
||||
codesign/entitlements/photos_library=false
|
||||
codesign/entitlements/apple_events=false
|
||||
codesign/entitlements/debugging=false
|
||||
codesign/entitlements/app_sandbox/enabled=false
|
||||
codesign/entitlements/app_sandbox/network_server=false
|
||||
codesign/entitlements/app_sandbox/network_client=false
|
||||
codesign/entitlements/app_sandbox/device_usb=false
|
||||
codesign/entitlements/app_sandbox/device_bluetooth=false
|
||||
codesign/entitlements/app_sandbox/files_downloads=0
|
||||
codesign/entitlements/app_sandbox/files_pictures=0
|
||||
codesign/entitlements/app_sandbox/files_music=0
|
||||
codesign/entitlements/app_sandbox/files_movies=0
|
||||
codesign/entitlements/app_sandbox/files_user_selected=0
|
||||
codesign/entitlements/app_sandbox/helper_executables=[]
|
||||
codesign/entitlements/additional=""
|
||||
codesign/custom_options=PackedStringArray()
|
||||
notarization/notarization=0
|
||||
privacy/microphone_usage_description=""
|
||||
privacy/microphone_usage_description_localized={}
|
||||
privacy/camera_usage_description=""
|
||||
privacy/camera_usage_description_localized={}
|
||||
privacy/location_usage_description=""
|
||||
privacy/location_usage_description_localized={}
|
||||
privacy/address_book_usage_description=""
|
||||
privacy/address_book_usage_description_localized={}
|
||||
privacy/calendar_usage_description=""
|
||||
privacy/calendar_usage_description_localized={}
|
||||
privacy/photos_library_usage_description=""
|
||||
privacy/photos_library_usage_description_localized={}
|
||||
privacy/desktop_folder_usage_description=""
|
||||
privacy/desktop_folder_usage_description_localized={}
|
||||
privacy/documents_folder_usage_description=""
|
||||
privacy/documents_folder_usage_description_localized={}
|
||||
privacy/downloads_folder_usage_description=""
|
||||
privacy/downloads_folder_usage_description_localized={}
|
||||
privacy/network_volumes_usage_description=""
|
||||
privacy/network_volumes_usage_description_localized={}
|
||||
privacy/removable_volumes_usage_description=""
|
||||
privacy/removable_volumes_usage_description_localized={}
|
||||
privacy/tracking_enabled=false
|
||||
privacy/tracking_domains=PackedStringArray()
|
||||
privacy/collected_data/name/collected=false
|
||||
privacy/collected_data/name/linked_to_user=false
|
||||
privacy/collected_data/name/used_for_tracking=false
|
||||
privacy/collected_data/name/collection_purposes=0
|
||||
privacy/collected_data/email_address/collected=false
|
||||
privacy/collected_data/email_address/linked_to_user=false
|
||||
privacy/collected_data/email_address/used_for_tracking=false
|
||||
privacy/collected_data/email_address/collection_purposes=0
|
||||
privacy/collected_data/phone_number/collected=false
|
||||
privacy/collected_data/phone_number/linked_to_user=false
|
||||
privacy/collected_data/phone_number/used_for_tracking=false
|
||||
privacy/collected_data/phone_number/collection_purposes=0
|
||||
privacy/collected_data/physical_address/collected=false
|
||||
privacy/collected_data/physical_address/linked_to_user=false
|
||||
privacy/collected_data/physical_address/used_for_tracking=false
|
||||
privacy/collected_data/physical_address/collection_purposes=0
|
||||
privacy/collected_data/other_contact_info/collected=false
|
||||
privacy/collected_data/other_contact_info/linked_to_user=false
|
||||
privacy/collected_data/other_contact_info/used_for_tracking=false
|
||||
privacy/collected_data/other_contact_info/collection_purposes=0
|
||||
privacy/collected_data/health/collected=false
|
||||
privacy/collected_data/health/linked_to_user=false
|
||||
privacy/collected_data/health/used_for_tracking=false
|
||||
privacy/collected_data/health/collection_purposes=0
|
||||
privacy/collected_data/fitness/collected=false
|
||||
privacy/collected_data/fitness/linked_to_user=false
|
||||
privacy/collected_data/fitness/used_for_tracking=false
|
||||
privacy/collected_data/fitness/collection_purposes=0
|
||||
privacy/collected_data/payment_info/collected=false
|
||||
privacy/collected_data/payment_info/linked_to_user=false
|
||||
privacy/collected_data/payment_info/used_for_tracking=false
|
||||
privacy/collected_data/payment_info/collection_purposes=0
|
||||
privacy/collected_data/credit_info/collected=false
|
||||
privacy/collected_data/credit_info/linked_to_user=false
|
||||
privacy/collected_data/credit_info/used_for_tracking=false
|
||||
privacy/collected_data/credit_info/collection_purposes=0
|
||||
privacy/collected_data/other_financial_info/collected=false
|
||||
privacy/collected_data/other_financial_info/linked_to_user=false
|
||||
privacy/collected_data/other_financial_info/used_for_tracking=false
|
||||
privacy/collected_data/other_financial_info/collection_purposes=0
|
||||
privacy/collected_data/precise_location/collected=false
|
||||
privacy/collected_data/precise_location/linked_to_user=false
|
||||
privacy/collected_data/precise_location/used_for_tracking=false
|
||||
privacy/collected_data/precise_location/collection_purposes=0
|
||||
privacy/collected_data/coarse_location/collected=false
|
||||
privacy/collected_data/coarse_location/linked_to_user=false
|
||||
privacy/collected_data/coarse_location/used_for_tracking=false
|
||||
privacy/collected_data/coarse_location/collection_purposes=0
|
||||
privacy/collected_data/sensitive_info/collected=false
|
||||
privacy/collected_data/sensitive_info/linked_to_user=false
|
||||
privacy/collected_data/sensitive_info/used_for_tracking=false
|
||||
privacy/collected_data/sensitive_info/collection_purposes=0
|
||||
privacy/collected_data/contacts/collected=false
|
||||
privacy/collected_data/contacts/linked_to_user=false
|
||||
privacy/collected_data/contacts/used_for_tracking=false
|
||||
privacy/collected_data/contacts/collection_purposes=0
|
||||
privacy/collected_data/emails_or_text_messages/collected=false
|
||||
privacy/collected_data/emails_or_text_messages/linked_to_user=false
|
||||
privacy/collected_data/emails_or_text_messages/used_for_tracking=false
|
||||
privacy/collected_data/emails_or_text_messages/collection_purposes=0
|
||||
privacy/collected_data/photos_or_videos/collected=false
|
||||
privacy/collected_data/photos_or_videos/linked_to_user=false
|
||||
privacy/collected_data/photos_or_videos/used_for_tracking=false
|
||||
privacy/collected_data/photos_or_videos/collection_purposes=0
|
||||
privacy/collected_data/audio_data/collected=false
|
||||
privacy/collected_data/audio_data/linked_to_user=false
|
||||
privacy/collected_data/audio_data/used_for_tracking=false
|
||||
privacy/collected_data/audio_data/collection_purposes=0
|
||||
privacy/collected_data/gameplay_content/collected=false
|
||||
privacy/collected_data/gameplay_content/linked_to_user=false
|
||||
privacy/collected_data/gameplay_content/used_for_tracking=false
|
||||
privacy/collected_data/gameplay_content/collection_purposes=0
|
||||
privacy/collected_data/customer_support/collected=false
|
||||
privacy/collected_data/customer_support/linked_to_user=false
|
||||
privacy/collected_data/customer_support/used_for_tracking=false
|
||||
privacy/collected_data/customer_support/collection_purposes=0
|
||||
privacy/collected_data/other_user_content/collected=false
|
||||
privacy/collected_data/other_user_content/linked_to_user=false
|
||||
privacy/collected_data/other_user_content/used_for_tracking=false
|
||||
privacy/collected_data/other_user_content/collection_purposes=0
|
||||
privacy/collected_data/browsing_history/collected=false
|
||||
privacy/collected_data/browsing_history/linked_to_user=false
|
||||
privacy/collected_data/browsing_history/used_for_tracking=false
|
||||
privacy/collected_data/browsing_history/collection_purposes=0
|
||||
privacy/collected_data/search_history/collected=false
|
||||
privacy/collected_data/search_history/linked_to_user=false
|
||||
privacy/collected_data/search_history/used_for_tracking=false
|
||||
privacy/collected_data/search_history/collection_purposes=0
|
||||
privacy/collected_data/user_id/collected=false
|
||||
privacy/collected_data/user_id/linked_to_user=false
|
||||
privacy/collected_data/user_id/used_for_tracking=false
|
||||
privacy/collected_data/user_id/collection_purposes=0
|
||||
privacy/collected_data/device_id/collected=false
|
||||
privacy/collected_data/device_id/linked_to_user=false
|
||||
privacy/collected_data/device_id/used_for_tracking=false
|
||||
privacy/collected_data/device_id/collection_purposes=0
|
||||
privacy/collected_data/purchase_history/collected=false
|
||||
privacy/collected_data/purchase_history/linked_to_user=false
|
||||
privacy/collected_data/purchase_history/used_for_tracking=false
|
||||
privacy/collected_data/purchase_history/collection_purposes=0
|
||||
privacy/collected_data/product_interaction/collected=false
|
||||
privacy/collected_data/product_interaction/linked_to_user=false
|
||||
privacy/collected_data/product_interaction/used_for_tracking=false
|
||||
privacy/collected_data/product_interaction/collection_purposes=0
|
||||
privacy/collected_data/advertising_data/collected=false
|
||||
privacy/collected_data/advertising_data/linked_to_user=false
|
||||
privacy/collected_data/advertising_data/used_for_tracking=false
|
||||
privacy/collected_data/advertising_data/collection_purposes=0
|
||||
privacy/collected_data/other_usage_data/collected=false
|
||||
privacy/collected_data/other_usage_data/linked_to_user=false
|
||||
privacy/collected_data/other_usage_data/used_for_tracking=false
|
||||
privacy/collected_data/other_usage_data/collection_purposes=0
|
||||
privacy/collected_data/crash_data/collected=false
|
||||
privacy/collected_data/crash_data/linked_to_user=false
|
||||
privacy/collected_data/crash_data/used_for_tracking=false
|
||||
privacy/collected_data/crash_data/collection_purposes=0
|
||||
privacy/collected_data/performance_data/collected=false
|
||||
privacy/collected_data/performance_data/linked_to_user=false
|
||||
privacy/collected_data/performance_data/used_for_tracking=false
|
||||
privacy/collected_data/performance_data/collection_purposes=0
|
||||
privacy/collected_data/other_diagnostic_data/collected=false
|
||||
privacy/collected_data/other_diagnostic_data/linked_to_user=false
|
||||
privacy/collected_data/other_diagnostic_data/used_for_tracking=false
|
||||
privacy/collected_data/other_diagnostic_data/collection_purposes=0
|
||||
privacy/collected_data/environment_scanning/collected=false
|
||||
privacy/collected_data/environment_scanning/linked_to_user=false
|
||||
privacy/collected_data/environment_scanning/used_for_tracking=false
|
||||
privacy/collected_data/environment_scanning/collection_purposes=0
|
||||
privacy/collected_data/hands/collected=false
|
||||
privacy/collected_data/hands/linked_to_user=false
|
||||
privacy/collected_data/hands/used_for_tracking=false
|
||||
privacy/collected_data/hands/collection_purposes=0
|
||||
privacy/collected_data/head/collected=false
|
||||
privacy/collected_data/head/linked_to_user=false
|
||||
privacy/collected_data/head/used_for_tracking=false
|
||||
privacy/collected_data/head/collection_purposes=0
|
||||
privacy/collected_data/other_data_types/collected=false
|
||||
privacy/collected_data/other_data_types/linked_to_user=false
|
||||
privacy/collected_data/other_data_types/used_for_tracking=false
|
||||
privacy/collected_data/other_data_types/collection_purposes=0
|
||||
ssh_remote_deploy/enabled=false
|
||||
ssh_remote_deploy/host="user@host_ip"
|
||||
ssh_remote_deploy/port="22"
|
||||
@@ -360,19 +555,34 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||
ssh_remote_deploy/cleanup_script="#!/bin/bash
|
||||
kill $(pgrep -x \"{exe_name}\")
|
||||
rm -rf \"{temp_dir}\""
|
||||
|
||||
binary_format/embed_pck=true
|
||||
texture_format/s3tc_bptc=true
|
||||
texture_format/etc2_astc=false
|
||||
codesign/enable=false
|
||||
codesign/timestamp=true
|
||||
codesign/timestamp_server_url=""
|
||||
codesign/digest_algorithm=1
|
||||
codesign/identity_type=0
|
||||
application/modify_resources=false
|
||||
application/console_wrapper_icon=""
|
||||
application/file_version="2.1"
|
||||
application/product_version="2.1"
|
||||
application/company_name="DanchieGo"
|
||||
application/product_name="Tekton Armageddon"
|
||||
application/file_description=""
|
||||
application/trademarks=""
|
||||
|
||||
[preset.3]
|
||||
|
||||
name="Linux/X11"
|
||||
platform="Linux/X11"
|
||||
platform="Linux"
|
||||
runnable=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="build/tekton_armageddon_v2.1.8.x86_64"
|
||||
export_path="build/tekton_armageddon_v2.2.1.x86_64"
|
||||
patches=PackedStringArray()
|
||||
patch_delta_encoding=false
|
||||
patch_delta_compression_level_zstd=19
|
||||
@@ -407,4 +617,3 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||
ssh_remote_deploy/cleanup_script="#!/bin/bash
|
||||
kill $(pgrep -x \"{exe_name}\")
|
||||
rm -rf \"{temp_dir}\""
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
||||
[application]
|
||||
|
||||
config/name="Tekton Dash Armageddon"
|
||||
config/version="2.1.8"
|
||||
config/version="2.2.1"
|
||||
run/main_scene="res://scenes/ui/boot_screen.tscn"
|
||||
config/features=PackedStringArray("4.6", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
@@ -30,6 +30,7 @@ extends Control
|
||||
@onready var shop_btn = %CartBtn
|
||||
@onready var top_right_profile_btn = %ProfileBtn
|
||||
@onready var banner1_btn = %Banner1
|
||||
@onready var ticket_btn = $MainMenuPanel/MainMargin/MainHBox/RightCol/TopRightPanel/TicketBtn
|
||||
|
||||
# UI References - Room List
|
||||
@onready var room_list_panel = $RoomListPanel
|
||||
@@ -118,6 +119,7 @@ var current_match_id: String = ""
|
||||
|
||||
var leaderboard_panel_instance: Control
|
||||
var shop_panel_instance: Control
|
||||
var daily_reward_panel_instance: Control
|
||||
|
||||
# Bot name tracking keyed by slot index to avoid re-generating on each update
|
||||
var _bot_names: Dictionary = {}
|
||||
@@ -180,6 +182,8 @@ func _ready():
|
||||
|
||||
if leaderboard_btn:
|
||||
leaderboard_btn.pressed.connect(_on_leaderboard_pressed)
|
||||
if ticket_btn:
|
||||
ticket_btn.pressed.connect(_on_ticket_pressed)
|
||||
if quit_btn:
|
||||
quit_btn.pressed.connect(_on_quit_pressed)
|
||||
|
||||
@@ -862,6 +866,25 @@ func _on_leaderboard_pressed() -> void:
|
||||
main_menu_panel.hide()
|
||||
leaderboard_panel_instance.show_panel()
|
||||
|
||||
func _on_ticket_pressed() -> void:
|
||||
if not NakamaManager.session:
|
||||
connection_status.text = "Must be logged in"
|
||||
return
|
||||
|
||||
if not daily_reward_panel_instance:
|
||||
var scene = load("res://scenes/ui/daily_reward_panel.tscn")
|
||||
if scene:
|
||||
daily_reward_panel_instance = scene.instantiate()
|
||||
daily_reward_panel_instance.closed.connect(func():
|
||||
if main_menu_panel: main_menu_panel.show()
|
||||
)
|
||||
add_child(daily_reward_panel_instance)
|
||||
|
||||
if daily_reward_panel_instance:
|
||||
if main_menu_panel:
|
||||
main_menu_panel.hide()
|
||||
daily_reward_panel_instance.show_panel()
|
||||
|
||||
func _go_to_login() -> void:
|
||||
if get_tree():
|
||||
get_tree().change_scene_to_file("res://scenes/ui/login_screen.tscn")
|
||||
|
||||
@@ -395,7 +395,6 @@ unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(44, 44)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("5_pc087")
|
||||
disabled = true
|
||||
text = "BATTLE PASS"
|
||||
|
||||
[node name="SocialBtn" type="Button" parent="MainMenuPanel/MainMargin/MainHBox/RightCol/TopRightPanel" unique_id=82719328]
|
||||
|
||||
@@ -162,6 +162,106 @@ custom_minimum_size = Vector2(120, 36)
|
||||
layout_mode = 2
|
||||
text = "Reset All Scores"
|
||||
|
||||
[node name="Daily Rewards" type="VBoxContainer" parent="Margin/VBox/Tabs"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 8
|
||||
metadata/_tab_index = 2
|
||||
|
||||
[node name="MonthHBox" type="HBoxContainer" parent="Margin/VBox/Tabs/Daily Rewards"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 12
|
||||
|
||||
[node name="Label" type="Label" parent="Margin/VBox/Tabs/Daily Rewards/MonthHBox"]
|
||||
layout_mode = 2
|
||||
text = "Target Month:"
|
||||
|
||||
[node name="MonthOptionBtn" type="OptionButton" parent="Margin/VBox/Tabs/Daily Rewards/MonthHBox"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(150, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DaysScroll" type="ScrollContainer" parent="Margin/VBox/Tabs/Daily Rewards"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="DaysGrid" type="GridContainer" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/h_separation = 10
|
||||
theme_override_constants/v_separation = 10
|
||||
columns = 6
|
||||
|
||||
[node name="DayConfigTemplate" type="PanelContainer" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate"]
|
||||
layout_mode = 2
|
||||
color = Color(0.12, 0.12, 0.12, 1)
|
||||
|
||||
[node name="Border" type="ReferenceRect" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate"]
|
||||
layout_mode = 2
|
||||
border_color = Color(0.25, 0.25, 0.25, 1)
|
||||
border_width = 1.0
|
||||
editor_only = false
|
||||
|
||||
[node name="Margin" type="MarginContainer" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 4
|
||||
theme_override_constants/margin_top = 4
|
||||
theme_override_constants/margin_right = 4
|
||||
theme_override_constants/margin_bottom = 4
|
||||
|
||||
[node name="VBox" type="VBoxContainer" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate/Margin"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DayLabel" type="Label" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate/Margin/VBox"]
|
||||
layout_mode = 2
|
||||
text = "Day 1"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="TypeOptionBtn" type="OptionButton" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate/Margin/VBox"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
item_count = 5
|
||||
popup/item_0/text = "star"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "gold"
|
||||
popup/item_1/id = 1
|
||||
popup/item_2/text = "frag_common"
|
||||
popup/item_2/id = 2
|
||||
popup/item_3/text = "frag_uncommon"
|
||||
popup/item_3/id = 3
|
||||
popup/item_4/text = "frag_rare"
|
||||
popup/item_4/id = 4
|
||||
|
||||
[node name="AmountSpinBox" type="SpinBox" parent="Margin/VBox/Tabs/Daily Rewards/DaysScroll/DaysGrid/DayConfigTemplate/Margin/VBox"]
|
||||
layout_mode = 2
|
||||
max_value = 10000.0
|
||||
alignment = 1
|
||||
|
||||
[node name="DRActionBar" type="HBoxContainer" parent="Margin/VBox/Tabs/Daily Rewards"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 8
|
||||
alignment = 2
|
||||
|
||||
[node name="LoadDRConfigBtn" type="Button" parent="Margin/VBox/Tabs/Daily Rewards/DRActionBar"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(160, 36)
|
||||
layout_mode = 2
|
||||
text = "Reload Config"
|
||||
|
||||
[node name="SaveDRConfigBtn" type="Button" parent="Margin/VBox/Tabs/Daily Rewards/DRActionBar"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(160, 36)
|
||||
layout_mode = 2
|
||||
text = "Save Config"
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="Margin/VBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
[gd_scene format=3 uid="uid://sdnq3e6jnnby"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/ui/daily_reward_config_panel.gd" id="1_script"]
|
||||
[ext_resource type="Theme" uid="uid://da337sh5qxi0s" path="res://assets/themes/ui_theme.tres" id="2_theme"]
|
||||
|
||||
[node name="DailyRewardConfigPanel" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("2_theme")
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0, 0, 0, 0.85)
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -400.0
|
||||
offset_top = -300.0
|
||||
offset_right = 400.0
|
||||
offset_bottom = 300.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 20.0
|
||||
offset_top = 20.0
|
||||
offset_right = -20.0
|
||||
offset_bottom = -20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 15
|
||||
|
||||
[node name="Label" type="Label" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "Daily Reward Config (Admin)"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="TextEdit" type="TextEdit" parent="Panel/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_font_sizes/font_size = 14
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="Panel/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="CloseBtn" type="Button" parent="Panel/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(150, 40)
|
||||
layout_mode = 2
|
||||
text = "Close"
|
||||
|
||||
[node name="SaveBtn" type="Button" parent="Panel/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(150, 40)
|
||||
layout_mode = 2
|
||||
text = "Save Config"
|
||||
@@ -0,0 +1,273 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://dailyreward1234"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/ui/daily_reward_panel.gd" id="1_script"]
|
||||
[ext_resource type="Theme" uid="uid://da337sh5qxi0s" path="res://assets/themes/ui_theme.tres" id="2_theme"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bg"]
|
||||
bg_color = Color(0.1, 0.1, 0.1, 0.95)
|
||||
corner_radius_top_left = 8
|
||||
corner_radius_top_right = 8
|
||||
corner_radius_bottom_right = 8
|
||||
corner_radius_bottom_left = 8
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yellow"]
|
||||
bg_color = Color(0.95, 0.76, 0.2, 1)
|
||||
|
||||
[node name="DailyRewardPanel" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("2_theme")
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0, 0, 0, 0.7)
|
||||
|
||||
[node name="MainWindow" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -450.0
|
||||
offset_top = -280.0
|
||||
offset_right = 450.0
|
||||
offset_bottom = 280.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_bg")
|
||||
|
||||
[node name="HBox" type="HBoxContainer" parent="MainWindow"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="LeftCol" type="VBoxContainer" parent="MainWindow/HBox"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 2.0
|
||||
|
||||
[node name="HeaderMargin" type="MarginContainer" parent="MainWindow/HBox/LeftCol"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 20
|
||||
theme_override_constants/margin_top = 20
|
||||
theme_override_constants/margin_right = 20
|
||||
theme_override_constants/margin_bottom = 10
|
||||
|
||||
[node name="HeaderHBox" type="HBoxContainer" parent="MainWindow/HBox/LeftCol/HeaderMargin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 15
|
||||
|
||||
[node name="MonthLabel" type="Label" parent="MainWindow/HBox/LeftCol/HeaderMargin/HeaderHBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 28
|
||||
text = "Month Sign-in"
|
||||
|
||||
[node name="FlavorLabel" type="Label" parent="MainWindow/HBox/LeftCol/HeaderMargin/HeaderHBox"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_colors/font_color = Color(0.7, 0.7, 0.7, 1)
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "A day's plan starts in the morning.
|
||||
Sign in daily for rewards."
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="CloseBtn" type="Button" parent="MainWindow/HBox/LeftCol/HeaderMargin/HeaderHBox"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(40, 40)
|
||||
layout_mode = 2
|
||||
text = "X"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MainWindow/HBox/LeftCol"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
horizontal_scroll_mode = 0
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MainWindow/HBox/LeftCol/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/margin_left = 20
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_right = 20
|
||||
theme_override_constants/margin_bottom = 20
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 10
|
||||
theme_override_constants/v_separation = 10
|
||||
columns = 7
|
||||
|
||||
[node name="RewardSlotTemplate" type="Control" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(75, 90)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Bg" type="ColorRect" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.15, 0.15, 0.15, 0.8)
|
||||
|
||||
[node name="DayNumber" type="Label" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate"]
|
||||
layout_mode = 1
|
||||
offset_left = 5.0
|
||||
offset_top = 0.0
|
||||
theme_override_font_sizes/font_size = 40
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 0.15)
|
||||
text = "1"
|
||||
|
||||
[node name="IconLabel" type="Label" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_font_sizes/font_size = 32
|
||||
text = "⭐"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Amount" type="Label" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -40.0
|
||||
offset_top = -23.0
|
||||
offset_right = -5.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "10"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="ClaimedOverlay" type="ColorRect" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate"]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0, 0, 0, 0.6)
|
||||
|
||||
[node name="Checkmark" type="Label" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate/ClaimedOverlay"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
theme_override_font_sizes/font_size = 60
|
||||
theme_override_colors/font_color = Color(0.9, 0.9, 0.9, 1)
|
||||
text = "✓"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="TodayBorder" type="ReferenceRect" parent="MainWindow/HBox/LeftCol/ScrollContainer/MarginContainer/GridContainer/RewardSlotTemplate"]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
border_color = Color(1, 0.84, 0, 1)
|
||||
border_width = 3.0
|
||||
editor_only = false
|
||||
|
||||
|
||||
[node name="RightCol" type="VBoxContainer" parent="MainWindow/HBox"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="TopTime" type="ColorRect" parent="MainWindow/HBox/RightCol"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
color = Color(0.12, 0.12, 0.12, 1)
|
||||
|
||||
[node name="TimeLabel" type="Label" parent="MainWindow/HBox/RightCol/TopTime"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
|
||||
text = "Daily Supply"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="MiddleDetails" type="ColorRect" parent="MainWindow/HBox/RightCol"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
color = Color(0.18, 0.18, 0.18, 1)
|
||||
|
||||
[node name="VBox" type="VBoxContainer" parent="MainWindow/HBox/RightCol/MiddleDetails"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="BigIcon" type="Label" parent="MainWindow/HBox/RightCol/MiddleDetails/VBox"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 100
|
||||
text = "⭐"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="RewardName" type="Label" parent="MainWindow/HBox/RightCol/MiddleDetails/VBox"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
theme_override_colors/font_color = Color(0.4, 0.8, 1, 1)
|
||||
text = "Star Currency"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="RewardAmount" type="Label" parent="MainWindow/HBox/RightCol/MiddleDetails/VBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 28
|
||||
text = "x 0"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="MainWindow/HBox/RightCol/MiddleDetails/VBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.8, 0.4, 0.4, 1)
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="BottomAction" type="PanelContainer" parent="MainWindow/HBox/RightCol"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_yellow")
|
||||
|
||||
[node name="ClaimBtn" type="Button" parent="MainWindow/HBox/RightCol/BottomAction"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.1, 0.1, 0.1, 1)
|
||||
theme_override_colors/font_pressed_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_hover_color = Color(0.2, 0.2, 0.2, 1)
|
||||
theme_override_colors/font_disabled_color = Color(0.3, 0.3, 0.3, 1)
|
||||
theme_override_font_sizes/font_size = 28
|
||||
text = "Sign In"
|
||||
flat = true
|
||||
@@ -15,6 +15,7 @@ signal profile_loaded(profile: Dictionary)
|
||||
signal profile_updated
|
||||
signal profile_update_failed(error: String)
|
||||
signal avatar_changed(url: String)
|
||||
signal stats_updated
|
||||
|
||||
# Profile data
|
||||
var profile: Dictionary = {}
|
||||
@@ -423,6 +424,7 @@ func save_wallet() -> void:
|
||||
|
||||
func update_stats(new_stats: Dictionary) -> bool:
|
||||
stats.merge(new_stats, true)
|
||||
emit_signal("stats_updated")
|
||||
|
||||
if not NakamaManager.session:
|
||||
return false
|
||||
|
||||
+117
-2
@@ -26,6 +26,18 @@ signal closed
|
||||
@onready var sync_lb_btn := %SyncLeaderboardBtn as Button
|
||||
@onready var reset_lb_btn := %ResetLBBtn as Button
|
||||
|
||||
# Tab: Daily Rewards
|
||||
@onready var month_option_btn := %MonthOptionBtn as OptionButton
|
||||
@onready var days_grid := %DaysGrid as GridContainer
|
||||
@onready var day_config_template := %DayConfigTemplate as VBoxContainer
|
||||
@onready var load_dr_btn := %LoadDRConfigBtn as Button
|
||||
@onready var save_dr_btn := %SaveDRConfigBtn as Button
|
||||
|
||||
var _daily_reward_config_data: Dictionary = {}
|
||||
var _current_dr_month: String = ""
|
||||
|
||||
const MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
||||
|
||||
# -- Data --
|
||||
var all_users: Array = []
|
||||
var lb_data: Array = []
|
||||
@@ -62,7 +74,7 @@ func _apply_plain_style() -> void:
|
||||
count_label.add_theme_color_override("font_color", CLR_HEADER)
|
||||
status_label.add_theme_color_override("font_color", CLR_DIM)
|
||||
|
||||
for btn: Button in [refresh_btn, close_btn, select_all_btn, deselect_btn]:
|
||||
for btn: Button in [refresh_btn, close_btn, select_all_btn, deselect_btn, load_dr_btn, save_dr_btn]:
|
||||
_style_button(btn, Color(0.2, 0.2, 0.24), CLR_TEXT)
|
||||
_style_button(ban_btn, Color(0.3, 0.2, 0.1), CLR_BTN_BAN)
|
||||
_style_button(unban_btn, Color(0.1, 0.22, 0.1), CLR_BTN_UNBAN)
|
||||
@@ -134,6 +146,11 @@ func _connect_signals() -> void:
|
||||
# LB actions
|
||||
lb_tree.button_clicked.connect(_on_lb_tree_button_clicked)
|
||||
sync_lb_btn.pressed.connect(_on_sync_leaderboard)
|
||||
|
||||
# DR actions
|
||||
load_dr_btn.pressed.connect(_load_daily_rewards_config)
|
||||
save_dr_btn.pressed.connect(_save_daily_rewards_config)
|
||||
month_option_btn.item_selected.connect(_on_dr_month_selected)
|
||||
|
||||
# =============================================================================
|
||||
# Core Panel Logic
|
||||
@@ -153,8 +170,10 @@ func _on_tab_changed(tab_index: int) -> void:
|
||||
_set_status("")
|
||||
if tab_index == 0:
|
||||
await _load_users()
|
||||
else:
|
||||
elif tab_index == 1:
|
||||
await _load_leaderboard()
|
||||
elif tab_index == 2:
|
||||
await _load_daily_rewards_config()
|
||||
|
||||
# =============================================================================
|
||||
# RPC Helper
|
||||
@@ -508,3 +527,99 @@ func _get_edit_icon() -> Texture2D:
|
||||
img.set_pixel(i, 11 - i + 4, CLR_TEXT)
|
||||
img.set_pixel(i, 12 - i + 4, CLR_TEXT)
|
||||
return ImageTexture.create_from_image(img)
|
||||
|
||||
# =============================================================================
|
||||
# TAB 3: DAILY REWARDS
|
||||
# =============================================================================
|
||||
func _load_daily_rewards_config() -> void:
|
||||
_set_status("Loading Daily Rewards Config...")
|
||||
var res := await _rpc("get_daily_reward_config_admin", {})
|
||||
if res.has("error"):
|
||||
_set_status("Failed to load DR config", CLR_STATUS_ERR)
|
||||
return
|
||||
|
||||
var config = res.get("config", {})
|
||||
if config.is_empty():
|
||||
for m in range(1, 13):
|
||||
var m_str = "%02d" % m
|
||||
var arr = []
|
||||
for d in range(30):
|
||||
arr.append({"type": "star", "amount": min(10 + d*5, 100)})
|
||||
config[m_str] = arr
|
||||
|
||||
_daily_reward_config_data = config
|
||||
|
||||
month_option_btn.clear()
|
||||
for i in range(1, 13):
|
||||
month_option_btn.add_item(MONTH_NAMES[i - 1])
|
||||
month_option_btn.set_item_metadata(i - 1, "%02d" % i)
|
||||
|
||||
if not _daily_reward_config_data.is_empty():
|
||||
_current_dr_month = "01"
|
||||
month_option_btn.select(0)
|
||||
_build_dr_grid()
|
||||
|
||||
_set_status("Config Loaded", CLR_STATUS_OK)
|
||||
|
||||
func _on_dr_month_selected(index: int) -> void:
|
||||
# Save current grid values into the dictionary before switching
|
||||
_save_current_grid_to_dict()
|
||||
|
||||
_current_dr_month = month_option_btn.get_item_metadata(index)
|
||||
_build_dr_grid()
|
||||
|
||||
func _save_current_grid_to_dict() -> void:
|
||||
if _current_dr_month.is_empty(): return
|
||||
var arr = []
|
||||
for child in days_grid.get_children():
|
||||
if child != day_config_template:
|
||||
var opt = child.get_node("Margin/VBox/TypeOptionBtn") as OptionButton
|
||||
var spin = child.get_node("Margin/VBox/AmountSpinBox") as SpinBox
|
||||
var item_type = opt.get_item_text(opt.selected) if opt.selected >= 0 else "star"
|
||||
arr.append({"type": item_type, "amount": int(spin.value)})
|
||||
if not arr.is_empty():
|
||||
_daily_reward_config_data[_current_dr_month] = arr
|
||||
|
||||
func _build_dr_grid() -> void:
|
||||
for child in days_grid.get_children():
|
||||
if child != day_config_template:
|
||||
child.queue_free()
|
||||
|
||||
var arr = _daily_reward_config_data.get(_current_dr_month, [])
|
||||
for i in range(arr.size()):
|
||||
var slot = day_config_template.duplicate()
|
||||
slot.visible = true
|
||||
days_grid.add_child(slot)
|
||||
|
||||
var lbl = slot.get_node("Margin/VBox/DayLabel") as Label
|
||||
var opt = slot.get_node("Margin/VBox/TypeOptionBtn") as OptionButton
|
||||
var spin = slot.get_node("Margin/VBox/AmountSpinBox") as SpinBox
|
||||
|
||||
lbl.text = "Day " + str(i + 1)
|
||||
var rdata = arr[i]
|
||||
if typeof(rdata) == TYPE_DICTIONARY:
|
||||
spin.value = rdata.get("amount", 0)
|
||||
var type_str = rdata.get("type", "star")
|
||||
var found = false
|
||||
for j in range(opt.item_count):
|
||||
if opt.get_item_text(j) == type_str:
|
||||
opt.select(j)
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
opt.add_item(type_str)
|
||||
opt.select(opt.item_count - 1)
|
||||
else:
|
||||
# Fallback for old int format
|
||||
spin.value = int(rdata)
|
||||
opt.select(0)
|
||||
|
||||
func _save_daily_rewards_config() -> void:
|
||||
_save_current_grid_to_dict()
|
||||
_set_status("Saving config...")
|
||||
var req = { "config": _daily_reward_config_data }
|
||||
var res = await _rpc("set_daily_reward_config", req)
|
||||
if res.has("error"):
|
||||
_set_status("Save failed: " + res.get("error"), CLR_STATUS_ERR)
|
||||
else:
|
||||
_set_status("Config saved successfully!", CLR_STATUS_OK)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
extends Control
|
||||
|
||||
@onready var close_btn = %CloseBtn
|
||||
@onready var save_btn = %SaveBtn
|
||||
@onready var status_lbl = %StatusLabel
|
||||
@onready var text_edit = %TextEdit
|
||||
|
||||
func _ready():
|
||||
close_btn.pressed.connect(func(): queue_free())
|
||||
save_btn.pressed.connect(_on_save)
|
||||
_load_config()
|
||||
|
||||
func _load_config():
|
||||
if not NakamaManager.session:
|
||||
status_lbl.text = "Not authenticated"
|
||||
return
|
||||
status_lbl.text = "Loading..."
|
||||
var res = await NakamaManager.client.rpc_async(NakamaManager.session, "get_daily_reward_config_admin", "{}")
|
||||
if res.is_exception():
|
||||
status_lbl.text = "Error: " + res.get_exception().message
|
||||
return
|
||||
|
||||
var json = JSON.new()
|
||||
if json.parse(res.payload) == OK:
|
||||
var config = json.get_data().get("config", {})
|
||||
if config.is_empty():
|
||||
# generate default 12 months for 2026/2027
|
||||
var year = 2026
|
||||
for m in range(1, 13):
|
||||
var m_str = "%d-%02d" % [year, m]
|
||||
var arr = []
|
||||
for d in range(30):
|
||||
arr.append(min(10 + d*5, 100)) # Reward is star currency, max 100
|
||||
config[m_str] = arr
|
||||
|
||||
text_edit.text = JSON.stringify(config, "\t")
|
||||
status_lbl.text = "Loaded"
|
||||
|
||||
func _on_save():
|
||||
var json = JSON.new()
|
||||
if json.parse(text_edit.text) != OK:
|
||||
status_lbl.text = "Invalid JSON syntax. Please check your formatting."
|
||||
return
|
||||
|
||||
status_lbl.text = "Saving..."
|
||||
var req = { "config": json.get_data() }
|
||||
var res = await NakamaManager.client.rpc_async(NakamaManager.session, "set_daily_reward_config", JSON.stringify(req))
|
||||
if res.is_exception():
|
||||
status_lbl.text = "Save error: " + res.get_exception().message
|
||||
else:
|
||||
status_lbl.text = "Config saved successfully!"
|
||||
@@ -0,0 +1 @@
|
||||
uid://v0h4qheiyh1k
|
||||
@@ -0,0 +1,151 @@
|
||||
extends Control
|
||||
|
||||
signal closed
|
||||
|
||||
@onready var close_btn = %CloseBtn
|
||||
@onready var grid_container = %GridContainer
|
||||
@onready var status_label = %StatusLabel
|
||||
@onready var claim_btn = %ClaimBtn
|
||||
@onready var slot_template = %RewardSlotTemplate
|
||||
@onready var month_label = %MonthLabel
|
||||
@onready var time_label = %TimeLabel
|
||||
@onready var reward_amount_label = %RewardAmount
|
||||
@onready var big_icon_label = $MainWindow/HBox/RightCol/MiddleDetails/VBox/BigIcon
|
||||
@onready var reward_name_label = $MainWindow/HBox/RightCol/MiddleDetails/VBox/RewardName
|
||||
|
||||
var _month_rewards: Array = []
|
||||
var _claimed_days: int = 0
|
||||
var _can_claim: bool = false
|
||||
var _today: String = ""
|
||||
|
||||
func _ready():
|
||||
close_btn.pressed.connect(func():
|
||||
hide()
|
||||
emit_signal("closed")
|
||||
)
|
||||
claim_btn.pressed.connect(_on_claim_pressed)
|
||||
|
||||
var time_dict = Time.get_datetime_dict_from_system()
|
||||
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
||||
month_label.text = months[time_dict.month - 1] + " Sign-in"
|
||||
|
||||
func show_panel():
|
||||
show()
|
||||
status_label.text = "Loading rewards..."
|
||||
claim_btn.disabled = true
|
||||
claim_btn.text = "Loading..."
|
||||
_fetch_state()
|
||||
|
||||
func _fetch_state():
|
||||
if not NakamaManager.session:
|
||||
status_label.text = "Must be logged in to claim rewards."
|
||||
return
|
||||
|
||||
var result = await NakamaManager.client.rpc_async(NakamaManager.session, "get_daily_reward_state", "{}")
|
||||
if result.is_exception():
|
||||
status_label.text = "Failed to load: " + result.get_exception().message
|
||||
return
|
||||
|
||||
var json = JSON.new()
|
||||
if json.parse(result.payload) == OK:
|
||||
var data = json.get_data()
|
||||
_month_rewards = data.get("month_rewards", [])
|
||||
var state = data.get("state", {})
|
||||
_claimed_days = state.get("claimed_days", 0)
|
||||
_can_claim = data.get("can_claim_today", false)
|
||||
_today = data.get("today_date", "")
|
||||
|
||||
_update_ui()
|
||||
else:
|
||||
status_label.text = "Error parsing data."
|
||||
|
||||
func _get_reward_display_data(type: String) -> Dictionary:
|
||||
if type == "gold": return {"icon": "💰", "name": "Gold"}
|
||||
elif type == "frag_common": return {"icon": "🧩", "name": "Common Fragment"}
|
||||
elif type == "frag_uncommon": return {"icon": "📦", "name": "Uncommon Fragment"}
|
||||
elif type == "frag_rare": return {"icon": "💎", "name": "Rare Fragment"}
|
||||
return {"icon": "⭐", "name": "Star Currency"}
|
||||
|
||||
func _update_ui():
|
||||
for child in grid_container.get_children():
|
||||
if child != slot_template:
|
||||
child.queue_free()
|
||||
|
||||
var today_reward_amount = 0
|
||||
var today_reward_type = "star"
|
||||
if _claimed_days < _month_rewards.size():
|
||||
var r = _month_rewards[_claimed_days]
|
||||
if typeof(r) == TYPE_DICTIONARY:
|
||||
today_reward_amount = r.get("amount", 0)
|
||||
today_reward_type = r.get("type", "star")
|
||||
else:
|
||||
today_reward_amount = int(r)
|
||||
|
||||
reward_amount_label.text = "x " + str(today_reward_amount)
|
||||
|
||||
var r_data = _get_reward_display_data(today_reward_type)
|
||||
big_icon_label.text = r_data.icon
|
||||
reward_name_label.text = r_data.name
|
||||
|
||||
for i in range(_month_rewards.size()):
|
||||
var reward_raw = _month_rewards[i]
|
||||
var reward_amount = 0
|
||||
var reward_type = "star"
|
||||
if typeof(reward_raw) == TYPE_DICTIONARY:
|
||||
reward_amount = reward_raw.get("amount", 0)
|
||||
reward_type = reward_raw.get("type", "star")
|
||||
else:
|
||||
reward_amount = int(reward_raw)
|
||||
|
||||
var r_slot_data = _get_reward_display_data(reward_type)
|
||||
|
||||
var is_claimed = i < _claimed_days
|
||||
var is_today = i == _claimed_days
|
||||
|
||||
var slot = slot_template.duplicate()
|
||||
slot.visible = true
|
||||
grid_container.add_child(slot)
|
||||
|
||||
var day_lbl = slot.get_node("DayNumber")
|
||||
var amt_lbl = slot.get_node("Amount")
|
||||
var icon_lbl = slot.get_node("IconLabel")
|
||||
var claimed_overlay = slot.get_node("ClaimedOverlay")
|
||||
var today_border = slot.get_node("TodayBorder")
|
||||
|
||||
day_lbl.text = str(i + 1)
|
||||
amt_lbl.text = str(reward_amount)
|
||||
icon_lbl.text = r_slot_data.icon
|
||||
|
||||
claimed_overlay.visible = is_claimed
|
||||
today_border.visible = is_today
|
||||
|
||||
if _can_claim:
|
||||
status_label.text = ""
|
||||
claim_btn.disabled = false
|
||||
claim_btn.text = "Sign In"
|
||||
else:
|
||||
status_label.text = "Come back tomorrow!"
|
||||
claim_btn.disabled = true
|
||||
claim_btn.text = "Signed-in"
|
||||
|
||||
func _on_claim_pressed():
|
||||
if not _can_claim or not NakamaManager.session:
|
||||
return
|
||||
|
||||
claim_btn.disabled = true
|
||||
claim_btn.text = "Claiming..."
|
||||
status_label.text = ""
|
||||
|
||||
var result = await NakamaManager.client.rpc_async(NakamaManager.session, "claim_daily_reward", "{}")
|
||||
if result.is_exception():
|
||||
status_label.text = "Failed to claim: " + result.get_exception().message
|
||||
claim_btn.disabled = false
|
||||
claim_btn.text = "Sign In"
|
||||
return
|
||||
|
||||
# Refresh wallet
|
||||
if UserProfileManager.has_method("_reload_wallet"):
|
||||
UserProfileManager._reload_wallet()
|
||||
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
_fetch_state()
|
||||
@@ -0,0 +1 @@
|
||||
uid://332tmk1jxdw4
|
||||
@@ -51,6 +51,15 @@ func _ready() -> void:
|
||||
_update_tab_visuals()
|
||||
_setup_3d_preview()
|
||||
|
||||
# Listen to profile and stats changes to keep the panel updated
|
||||
UserProfileManager.profile_updated.connect(_on_profile_or_stats_changed)
|
||||
UserProfileManager.stats_updated.connect(_on_profile_or_stats_changed)
|
||||
UserProfileManager.avatar_changed.connect(func(_url): _on_profile_or_stats_changed())
|
||||
|
||||
func _on_profile_or_stats_changed() -> void:
|
||||
if visible:
|
||||
_fetch_leaderboard_data()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Show / Close
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -97,6 +106,7 @@ func _fetch_leaderboard_data() -> void:
|
||||
var native_data = await _fetch_native_leaderboard()
|
||||
|
||||
if native_data.size() > 0:
|
||||
_apply_local_overrides(native_data)
|
||||
leaderboard_data = native_data
|
||||
_calculate_win_rates()
|
||||
status_label.text = ""
|
||||
@@ -156,6 +166,7 @@ func _fetch_via_rpc() -> void:
|
||||
if json.parse(result.payload) == OK:
|
||||
var data = json.get_data()
|
||||
if data.has("leaderboard") and data.leaderboard.size() > 0:
|
||||
_apply_local_overrides(data.leaderboard)
|
||||
leaderboard_data = data.leaderboard
|
||||
_calculate_win_rates()
|
||||
status_label.text = ""
|
||||
@@ -174,6 +185,28 @@ func _calculate_win_rates() -> void:
|
||||
var won = entry.get("games_won", 0)
|
||||
entry["win_rate"] = float(won) / float(played) * 100.0 if played > 0 else 0.0
|
||||
|
||||
func _apply_local_overrides(data: Array) -> void:
|
||||
if not NakamaManager.session:
|
||||
return
|
||||
var my_id = NakamaManager.session.user_id
|
||||
for entry in data:
|
||||
if entry.get("user_id") == my_id:
|
||||
entry["display_name"] = UserProfileManager.get_display_name(entry.get("display_name", "Unknown"))
|
||||
entry["avatar_url"] = UserProfileManager.get_avatar_url()
|
||||
entry["loadout_character"] = UserProfileManager.profile.get("loadout_character", entry.get("loadout_character", "Copper"))
|
||||
|
||||
var local_score = UserProfileManager.stats.get("high_score", 0)
|
||||
if local_score >= entry.get("high_score", 0):
|
||||
entry["high_score"] = local_score
|
||||
|
||||
var local_played = UserProfileManager.stats.get("games_played", 0)
|
||||
if local_played >= entry.get("games_played", 0):
|
||||
entry["games_played"] = local_played
|
||||
|
||||
var local_won = UserProfileManager.stats.get("games_won", 0)
|
||||
if local_won >= entry.get("games_won", 0):
|
||||
entry["games_won"] = local_won
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Sorting / Display
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -43,6 +43,12 @@ function InitModule(ctx, logger, nk, initializer) {
|
||||
initializer.registerRpc("send_lobby_invite", rpcSendLobbyInvite);
|
||||
initializer.registerRpc("send_friend_request", rpcSendFriendRequest);
|
||||
|
||||
// Daily Rewards RPCs
|
||||
initializer.registerRpc("claim_daily_reward", rpcClaimDailyReward);
|
||||
initializer.registerRpc("get_daily_reward_state", rpcGetDailyRewardState);
|
||||
initializer.registerRpc("set_daily_reward_config", rpcSetDailyRewardConfig);
|
||||
initializer.registerRpc("get_daily_reward_config_admin", rpcGetDailyRewardConfigAdmin);
|
||||
|
||||
// Steam auth hooks
|
||||
initializer.registerAfterAuthenticateSteam(afterAuthenticateSteam);
|
||||
|
||||
@@ -593,6 +599,155 @@ function rpcPurchaseItem(ctx, logger, nk, payload) {
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Daily Rewards RPCs
|
||||
// =============================================================================
|
||||
|
||||
function rpcClaimDailyReward(ctx, logger, nk, payload) {
|
||||
if (!ctx.userId) throw new Error("Not authenticated");
|
||||
var now = new Date();
|
||||
var currentMonth = now.toISOString().substring(5, 7); // e.g. "05"
|
||||
var todayStr = now.toISOString().substring(0, 10);
|
||||
|
||||
var stateObjs = nk.storageRead([{ collection: "daily_rewards", key: "state", userId: ctx.userId }]);
|
||||
var state = { claimed_days: 0, last_claim_date: "", month: "" };
|
||||
if (stateObjs && stateObjs.length > 0) {
|
||||
state = stateObjs[0].value;
|
||||
}
|
||||
|
||||
if (state.month !== currentMonth) {
|
||||
state.claimed_days = 0;
|
||||
state.month = currentMonth;
|
||||
}
|
||||
|
||||
if (state.last_claim_date === todayStr) {
|
||||
throw new Error("Already claimed today");
|
||||
}
|
||||
|
||||
var configObjs = nk.storageRead([{ collection: "config", key: "daily_rewards", userId: "00000000-0000-0000-0000-000000000000" }]);
|
||||
var config = {};
|
||||
if (configObjs && configObjs.length > 0) {
|
||||
config = configObjs[0].value;
|
||||
}
|
||||
|
||||
var monthRewards = config[currentMonth];
|
||||
if (!monthRewards || monthRewards.length === 0) {
|
||||
monthRewards = [];
|
||||
for (var i = 0; i < 31; i++) {
|
||||
monthRewards.push({ type: "star", amount: Math.min(10 + i * 5, 100) });
|
||||
}
|
||||
}
|
||||
|
||||
var dayIndex = state.claimed_days;
|
||||
if (dayIndex >= monthRewards.length) {
|
||||
throw new Error("Already claimed all rewards for this month");
|
||||
}
|
||||
|
||||
var rewardData = monthRewards[dayIndex];
|
||||
if (typeof rewardData === "number") {
|
||||
rewardData = { type: "star", amount: rewardData };
|
||||
}
|
||||
|
||||
var rewardType = rewardData.type || "star";
|
||||
var rewardAmount = rewardData.amount || 0;
|
||||
|
||||
if (rewardType === "star" || rewardType === "gold") {
|
||||
var changes = {};
|
||||
changes[rewardType] = rewardAmount;
|
||||
nk.walletUpdate(ctx.userId, changes, {}, true);
|
||||
} else if (rewardType.startsWith("frag_")) {
|
||||
var invObjs = nk.storageRead([{ collection: "inventory", key: "fragments", userId: ctx.userId }]);
|
||||
var frags = {};
|
||||
if (invObjs && invObjs.length > 0) {
|
||||
frags = invObjs[0].value;
|
||||
}
|
||||
frags[rewardType] = (frags[rewardType] || 0) + rewardAmount;
|
||||
nk.storageWrite([{
|
||||
collection: "inventory",
|
||||
key: "fragments",
|
||||
userId: ctx.userId,
|
||||
value: frags,
|
||||
permissionRead: 1,
|
||||
permissionWrite: 0
|
||||
}]);
|
||||
}
|
||||
|
||||
state.claimed_days++;
|
||||
state.last_claim_date = todayStr;
|
||||
|
||||
nk.storageWrite([{
|
||||
collection: "daily_rewards",
|
||||
key: "state",
|
||||
userId: ctx.userId,
|
||||
value: state,
|
||||
permissionRead: 1,
|
||||
permissionWrite: 0
|
||||
}]);
|
||||
|
||||
return JSON.stringify({ success: true, reward_type: rewardType, reward_amount: rewardAmount, day: state.claimed_days });
|
||||
}
|
||||
|
||||
function rpcGetDailyRewardState(ctx, logger, nk, payload) {
|
||||
if (!ctx.userId) throw new Error("Not authenticated");
|
||||
var now = new Date();
|
||||
var currentMonth = now.toISOString().substring(5, 7); // e.g. "05"
|
||||
var todayStr = now.toISOString().substring(0, 10);
|
||||
|
||||
var stateObjs = nk.storageRead([{ collection: "daily_rewards", key: "state", userId: ctx.userId }]);
|
||||
var state = { claimed_days: 0, last_claim_date: "", month: "" };
|
||||
if (stateObjs && stateObjs.length > 0) {
|
||||
state = stateObjs[0].value;
|
||||
}
|
||||
if (state.month !== currentMonth) {
|
||||
state.claimed_days = 0;
|
||||
state.month = currentMonth;
|
||||
}
|
||||
|
||||
var configObjs = nk.storageRead([{ collection: "config", key: "daily_rewards", userId: "00000000-0000-0000-0000-000000000000" }]);
|
||||
var config = {};
|
||||
if (configObjs && configObjs.length > 0) {
|
||||
config = configObjs[0].value;
|
||||
}
|
||||
var monthRewards = config[currentMonth];
|
||||
if (!monthRewards || monthRewards.length === 0) {
|
||||
monthRewards = [];
|
||||
for (var i = 0; i < 31; i++) {
|
||||
monthRewards.push({ type: "star", amount: Math.min(10 + i * 5, 100) });
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
state: state,
|
||||
month_rewards: monthRewards,
|
||||
can_claim_today: state.last_claim_date !== todayStr && state.claimed_days < monthRewards.length,
|
||||
today_date: todayStr
|
||||
});
|
||||
}
|
||||
|
||||
function rpcSetDailyRewardConfig(ctx, logger, nk, payload) {
|
||||
requireAdmin(ctx, nk);
|
||||
var request = JSON.parse(payload || "{}");
|
||||
nk.storageWrite([{
|
||||
collection: "config",
|
||||
key: "daily_rewards",
|
||||
userId: "00000000-0000-0000-0000-000000000000",
|
||||
value: request.config,
|
||||
permissionRead: 2,
|
||||
permissionWrite: 0
|
||||
}]);
|
||||
return JSON.stringify({ success: true });
|
||||
}
|
||||
|
||||
function rpcGetDailyRewardConfigAdmin(ctx, logger, nk, payload) {
|
||||
requireAdmin(ctx, nk);
|
||||
var configObjs = nk.storageRead([{ collection: "config", key: "daily_rewards", userId: "00000000-0000-0000-0000-000000000000" }]);
|
||||
var config = {};
|
||||
if (configObjs && configObjs.length > 0) {
|
||||
config = configObjs[0].value;
|
||||
}
|
||||
return JSON.stringify({ config: config });
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// User Profile RPCs
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user