class_name AdsManager extends Node signal energy_reward_granted(amount: int) signal ad_unavailable(message: String) const SAVE_PATH := "user://void_bastion_ads.json" const ENERGY_REWARD := 150 const MISSIONS_PER_INTERSTITIAL := 3 const INTERSTITIAL_COOLDOWN_SECONDS := 15 * 60 const ANDROID_TEST_APP_ID := "ca-app-pub-3940256099942544~3347511713" const IOS_TEST_APP_ID := "ca-app-pub-3940256099942544~1458002511" var mobile_ads_supported := false var initialized := false var rewarded_ready := false var interstitial_ready := false var reward_used_this_mission := false var missions_since_interstitial := 0 var last_interstitial_time := 0 var _admob: Node var _initialization_requested := false func _ready() -> void: _load_state() mobile_ads_supported = OS.has_feature("android") or OS.has_feature("ios") if not mobile_ads_supported: return _create_admob_node() _admob.update_consent_info() func _create_admob_node() -> void: var admob_script: Script = load("res://addons/AdmobPlugin/Admob.gd") _admob = admob_script.new() _admob.name = "Admob" _admob.is_real = false _admob.android_debug_application_id = ANDROID_TEST_APP_ID _admob.ios_debug_application_id = IOS_TEST_APP_ID _admob.global_ads_muted = true _admob.global_apply_at_startup = true _admob.att_enabled = false _admob.initialization_completed.connect(_on_initialization_completed) _admob.consent_info_updated.connect(_on_consent_info_updated) _admob.consent_info_update_failed.connect(_on_consent_info_update_failed) _admob.consent_form_loaded.connect(_on_consent_form_loaded) _admob.consent_form_dismissed.connect(_on_consent_form_dismissed) _admob.consent_form_failed_to_load.connect(_on_consent_form_failed_to_load) _admob.rewarded_ad_loaded.connect(_on_rewarded_ad_loaded) _admob.rewarded_ad_failed_to_load.connect(_on_rewarded_ad_failed_to_load) _admob.rewarded_ad_user_earned_reward.connect(_on_rewarded_ad_user_earned_reward) _admob.rewarded_ad_dismissed_full_screen_content.connect(_on_rewarded_ad_dismissed) _admob.interstitial_ad_loaded.connect(_on_interstitial_ad_loaded) _admob.interstitial_ad_failed_to_load.connect(_on_interstitial_ad_failed_to_load) _admob.interstitial_ad_dismissed_full_screen_content.connect(_on_interstitial_ad_dismissed) add_child(_admob) func begin_mission() -> void: reward_used_this_mission = false if initialized and not rewarded_ready: _admob.load_rewarded_ad() func can_offer_rewarded() -> bool: return mobile_ads_supported and initialized and rewarded_ready and not reward_used_this_mission func request_rewarded_energy() -> void: if not can_offer_rewarded(): ad_unavailable.emit("BELOHNUNGSVIDEO IST GERADE NICHT VERFÜGBAR") return rewarded_ready = false _admob.show_rewarded_ad() func record_mission_finished() -> void: missions_since_interstitial += 1 _save_state() if is_interstitial_due() and interstitial_ready: _show_interstitial() elif is_interstitial_due() and initialized: _admob.load_interstitial_ad() func is_interstitial_due(now_unix: int = -1) -> bool: if missions_since_interstitial < MISSIONS_PER_INTERSTITIAL: return false if last_interstitial_time <= 0: return true var now := int(Time.get_unix_time_from_system()) if now_unix < 0 else now_unix return now - last_interstitial_time >= INTERSTITIAL_COOLDOWN_SECONDS func _show_interstitial() -> void: if not mobile_ads_supported or not initialized or not interstitial_ready: return interstitial_ready = false missions_since_interstitial = 0 last_interstitial_time = int(Time.get_unix_time_from_system()) _save_state() _admob.show_interstitial_ad() func _on_consent_info_updated() -> void: var consent = _admob.get_consent_status() var status: String = consent.to_status_string() if consent else "UNKNOWN" if status == "REQUIRED": _admob.load_consent_form() elif status in ["NOT_REQUIRED", "OBTAINED"]: _initialize_ads() func _on_consent_info_update_failed(_error) -> void: _initialize_if_prior_consent_allows() func _on_consent_form_loaded() -> void: _admob.show_consent_form() func _on_consent_form_dismissed(_error) -> void: _initialize_if_prior_consent_allows() func _on_consent_form_failed_to_load(_error) -> void: _initialize_if_prior_consent_allows() func _initialize_if_prior_consent_allows() -> void: var consent = _admob.get_consent_status() var status: String = consent.to_status_string() if consent else "UNKNOWN" if status in ["NOT_REQUIRED", "OBTAINED"]: _initialize_ads() func _initialize_ads() -> void: if _initialization_requested: return _initialization_requested = true _admob.initialize() func _on_initialization_completed(_status) -> void: initialized = true _admob.load_rewarded_ad() _admob.load_interstitial_ad() func _on_rewarded_ad_loaded(_ad_info, _response_info) -> void: rewarded_ready = true func _on_rewarded_ad_failed_to_load(_ad_info, _error) -> void: rewarded_ready = false func _on_rewarded_ad_user_earned_reward(_ad_info, _reward_data) -> void: if reward_used_this_mission: return reward_used_this_mission = true energy_reward_granted.emit(ENERGY_REWARD) func _on_rewarded_ad_dismissed(_ad_info) -> void: rewarded_ready = false _admob.load_rewarded_ad() func _on_interstitial_ad_loaded(_ad_info, _response_info) -> void: interstitial_ready = true func _on_interstitial_ad_failed_to_load(_ad_info, _error) -> void: interstitial_ready = false func _on_interstitial_ad_dismissed(_ad_info) -> void: interstitial_ready = false _admob.load_interstitial_ad() func _save_state() -> void: var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE) if file: file.store_string(JSON.stringify({ "missions_since_interstitial": missions_since_interstitial, "last_interstitial_time": last_interstitial_time })) func _load_state() -> void: if not FileAccess.file_exists(SAVE_PATH): return var file := FileAccess.open(SAVE_PATH, FileAccess.READ) if not file: return var data = JSON.parse_string(file.get_as_text()) if data is Dictionary: missions_since_interstitial = maxi(0, int(data.get("missions_since_interstitial", 0))) last_interstitial_time = maxi(0, int(data.get("last_interstitial_time", 0)))