feat(death): 사망/부활 시스템 개선
- DeathInfo에 lostItem 필드 추가 (광고 부활 시 복구용) - 세이브 데이터 v4: MonetizationState 포함 - 사망 오버레이 UI 개선 - 부활 서비스 광고 연동
This commit is contained in:
@@ -8,17 +8,19 @@ import 'package:asciineverdie/src/core/model/game_state.dart';
|
||||
import 'package:asciineverdie/src/core/model/item_stats.dart';
|
||||
import 'package:asciineverdie/src/shared/retro_colors.dart';
|
||||
|
||||
/// 사망 오버레이 위젯 (Phase 4)
|
||||
/// 사망 오버레이 위젯
|
||||
///
|
||||
/// 플레이어 사망 시 표시되는 전체 화면 오버레이
|
||||
/// - 무료 부활: HP 50%, 아이템 희생
|
||||
/// - 광고 부활: HP 100%, 아이템 복구, 10분 자동부활 버프
|
||||
class DeathOverlay extends StatelessWidget {
|
||||
const DeathOverlay({
|
||||
super.key,
|
||||
required this.deathInfo,
|
||||
required this.traits,
|
||||
required this.onResurrect,
|
||||
this.isAutoResurrectEnabled = false,
|
||||
this.onToggleAutoResurrect,
|
||||
this.onAdRevive,
|
||||
this.isPaidUser = false,
|
||||
});
|
||||
|
||||
/// 사망 정보
|
||||
@@ -27,14 +29,15 @@ class DeathOverlay extends StatelessWidget {
|
||||
/// 캐릭터 특성 (이름, 직업 등)
|
||||
final Traits traits;
|
||||
|
||||
/// 부활 버튼 콜백
|
||||
/// 무료 부활 버튼 콜백 (HP 50%, 아이템 희생)
|
||||
final VoidCallback onResurrect;
|
||||
|
||||
/// 자동 부활 활성화 여부
|
||||
final bool isAutoResurrectEnabled;
|
||||
/// 광고 부활 버튼 콜백 (HP 100% + 아이템 복구 + 10분 자동부활)
|
||||
/// null이면 광고 부활 버튼 숨김
|
||||
final VoidCallback? onAdRevive;
|
||||
|
||||
/// 자동 부활 토글 콜백
|
||||
final VoidCallback? onToggleAutoResurrect;
|
||||
/// 유료 유저 여부 (광고 아이콘 표시용)
|
||||
final bool isPaidUser;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -135,13 +138,13 @@ class DeathOverlay extends StatelessWidget {
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 부활 버튼
|
||||
// 일반 부활 버튼 (HP 50%, 아이템 희생)
|
||||
_buildResurrectButton(context),
|
||||
|
||||
// 자동 부활 버튼
|
||||
if (onToggleAutoResurrect != null) ...[
|
||||
// 광고 부활 버튼 (HP 100% + 아이템 복구 + 10분 자동부활)
|
||||
if (onAdRevive != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
_buildAutoResurrectButton(context),
|
||||
_buildAdReviveButton(context),
|
||||
],
|
||||
],
|
||||
),
|
||||
@@ -464,77 +467,149 @@ class DeathOverlay extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// 자동 부활 토글 버튼
|
||||
Widget _buildAutoResurrectButton(BuildContext context) {
|
||||
final mpColor = RetroColors.mpOf(context);
|
||||
final mpDark = RetroColors.mpDarkOf(context);
|
||||
/// 광고 부활 버튼 (HP 100% + 아이템 복구 + 10분 자동부활)
|
||||
Widget _buildAdReviveButton(BuildContext context) {
|
||||
final gold = RetroColors.goldOf(context);
|
||||
final goldDark = RetroColors.goldDarkOf(context);
|
||||
final muted = RetroColors.textMutedOf(context);
|
||||
|
||||
// 활성화 상태에 따른 색상
|
||||
final buttonColor = isAutoResurrectEnabled ? mpColor : muted;
|
||||
final buttonDark = isAutoResurrectEnabled
|
||||
? mpDark
|
||||
: muted.withValues(alpha: 0.5);
|
||||
final hasLostItem = deathInfo.lostItemName != null;
|
||||
final itemRarityColor = _getRarityColor(deathInfo.lostItemRarity);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onToggleAutoResurrect,
|
||||
onTap: onAdRevive,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor.withValues(alpha: 0.15),
|
||||
color: gold.withValues(alpha: 0.2),
|
||||
border: Border(
|
||||
top: BorderSide(color: buttonColor, width: 2),
|
||||
left: BorderSide(color: buttonColor, width: 2),
|
||||
bottom: BorderSide(
|
||||
color: buttonDark.withValues(alpha: 0.8),
|
||||
width: 2,
|
||||
),
|
||||
right: BorderSide(
|
||||
color: buttonDark.withValues(alpha: 0.8),
|
||||
width: 2,
|
||||
),
|
||||
top: BorderSide(color: gold, width: 3),
|
||||
left: BorderSide(color: gold, width: 3),
|
||||
bottom: BorderSide(color: goldDark.withValues(alpha: 0.8), width: 3),
|
||||
right: BorderSide(color: goldDark.withValues(alpha: 0.8), width: 3),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
isAutoResurrectEnabled ? '◉' : '○',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: buttonColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
// 메인 버튼 텍스트
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'✨',
|
||||
style: TextStyle(fontSize: 20, color: gold),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.deathAdRevive.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 14,
|
||||
color: gold,
|
||||
letterSpacing: 1,
|
||||
),
|
||||
),
|
||||
// 광고 뱃지 (무료 유저만)
|
||||
if (!isPaidUser) ...[
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Text(
|
||||
'▶ AD',
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 10,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.deathAutoResurrect.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 13,
|
||||
color: buttonColor,
|
||||
letterSpacing: 1,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 혜택 목록
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// HP 100% 회복
|
||||
_buildBenefitRow(
|
||||
context,
|
||||
icon: '♥',
|
||||
text: l10n.deathAdReviveHp,
|
||||
color: RetroColors.hpOf(context),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
// 아이템 복구 (잃은 아이템이 있을 때만)
|
||||
if (hasLostItem) ...[
|
||||
_buildBenefitRow(
|
||||
context,
|
||||
icon: '🔄',
|
||||
text: '${l10n.deathAdReviveItem}: ${deathInfo.lostItemName}',
|
||||
color: itemRarityColor,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
],
|
||||
// 10분 자동부활
|
||||
_buildBenefitRow(
|
||||
context,
|
||||
icon: '⏱',
|
||||
text: l10n.deathAdReviveAuto,
|
||||
color: RetroColors.mpOf(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isAutoResurrectEnabled) ...[
|
||||
const SizedBox(width: 6),
|
||||
const SizedBox(height: 6),
|
||||
// 유료 유저 설명
|
||||
if (isPaidUser)
|
||||
Text(
|
||||
'ON',
|
||||
l10n.deathAdRevivePaidDesc,
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 13,
|
||||
color: mpColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 9,
|
||||
color: muted,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 혜택 항목 행
|
||||
Widget _buildBenefitRow(
|
||||
BuildContext context, {
|
||||
required String icon,
|
||||
required String text,
|
||||
required Color color,
|
||||
}) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(icon, style: TextStyle(fontSize: 14, color: color)),
|
||||
const SizedBox(width: 6),
|
||||
Flexible(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 10,
|
||||
color: color,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 사망 직전 전투 로그 표시
|
||||
Widget _buildCombatLog(BuildContext context) {
|
||||
final events = deathInfo.lastCombatEvents;
|
||||
|
||||
Reference in New Issue
Block a user