mirror of
https://gitee.com/anod/open_agb_firm.git
synced 2025-05-06 05:44:11 +08:00
938 lines
28 KiB
C
938 lines
28 KiB
C
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <math.h>
|
||
#include "types.h"
|
||
#include "fsutil.h"
|
||
#include "arm11/pages.h"
|
||
#include "arm11/drivers/mcu.h"
|
||
#include "arm11/fmt.h"
|
||
#include "drivers/gfx.h"
|
||
#include "arm11/open_agb_firm.h"
|
||
|
||
atp_error_t disp_str( atp_callerdata_t data, atp_counter_t, atp_linecfg_t *cfg )
|
||
{
|
||
cfg->text = (atp_text_t)data;
|
||
cfg->text_color = ATP_COLOR_RED;
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
/// @brief base process for helping page
|
||
/// @param table
|
||
/// @param index
|
||
/// @param config
|
||
/// @return
|
||
static atp_error_t display_help( atp_callerdata_t table, atp_counter_t index, atp_linecfg_t *config )
|
||
{
|
||
atp_text_t *list = (atp_text_t*)table;
|
||
config->text_align = ATP_PLACEMENT_CENTER;
|
||
config->text_color = index == 0 ? ATP_COLOR_MAGENTA : ATP_COLOR_LIGHT;
|
||
config->text = list[index];
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
/// @brief display a static page for help
|
||
/// @param wording static string array
|
||
/// @param length the size of array
|
||
/// @return
|
||
atp_error_t help_page( atp_text_t *wording, atp_counter_t length )
|
||
{
|
||
atp_text_t current;
|
||
atp_tips( "返回:按A/B", ¤t );
|
||
atp_error_t res = atp_show( length, display_help, (atp_callerdata_t)wording );
|
||
atp_tips( current, NULL );
|
||
return res;
|
||
}
|
||
|
||
// --------------------------
|
||
// code for oaf config page
|
||
// --------------------------
|
||
atp_text_t config_help[] =
|
||
{
|
||
"全局参数编辑操作指引",
|
||
"~ ~ ~ ~ ~ ~ ~",
|
||
"-修改后的全局参数保存在config.ini ",
|
||
"保存修改时,存档方案的修改不会保存",
|
||
"-金手指组合键为下方向+L+R+SELECT",
|
||
" 也可以使用HOME键直接代替组合键 ",
|
||
"~ ~ ~ ~ ~ ~ ~",
|
||
"上下方向键 切换参数项目",
|
||
"左右方向键 翻页",
|
||
"L键和R键 调整当前参数",
|
||
"A键 应用修改退出",
|
||
"B键 放弃修改退出",
|
||
"X键 应用修改保存退出", // X做保存,选中后走A键流程
|
||
};
|
||
atp_text_t CONFIG_OUTPUT = "[general]\n" \
|
||
"backlight=%d\n" \
|
||
"directBoot=%s\n" \
|
||
"useGbaDb=%s\n\n" \
|
||
"[video]\n" \
|
||
"scaler=%d\n" \
|
||
"gbaGamma=%s\n" \
|
||
"lcdGamma=%s\n" \
|
||
"contrast=%s\n" \
|
||
"brightness=%s\n\n" \
|
||
"[advanced]\n" \
|
||
"saveOverride=false\n" \
|
||
"defaultSave=%d\n\n" \
|
||
"[boost]\n" \
|
||
"cheatMode=%d\n"\
|
||
"haltMode=%d\n";
|
||
|
||
typedef struct global_oaf_config OafConfig;
|
||
|
||
static char page_strbuf[512];
|
||
|
||
#define LIGHT_MIN (MCU_getSystemModel() > 3 ? 50 : 20)
|
||
#define LIGHT_MAX (MCU_getSystemModel() > 3 ? 800 : 500)
|
||
#define SCALER_SIZE 4
|
||
static atp_error_t config_item( atp_callerdata_t gblcfg, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
//static char buf[16];
|
||
OafConfig *g_oafConfig = (OafConfig*)gblcfg;
|
||
const char *scaler_val[] = {"上屏无缩放", "上屏GPU放大", "上屏DMA放大", "下屏无缩放"};
|
||
const char *savetype_name[] = {"和卡带序列号一致", "读取ROM的特定标记", "汉化带SRAM补丁", "自行决定"};
|
||
const char *cheatmode_name[] = {"关闭金手指", "全程激活", "组合键单次激活", "组合键激活/关闭"};
|
||
const char *haltmode_name[] = {"关闭3DS", "停止游戏"};
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
if( index == 0 )
|
||
{
|
||
ee_snprintf(page_strbuf, sizeof(page_strbuf), "%d", g_oafConfig->backlight);
|
||
cfg->text = "屏幕亮度";
|
||
cfg->extra_text = page_strbuf;
|
||
if( g_oafConfig->backlight == LIGHT_MIN || g_oafConfig->backlight == LIGHT_MAX )
|
||
cfg->extra_text_color = ATP_COLOR_RED;
|
||
}
|
||
else if( index == 1 )
|
||
{
|
||
cfg->text = "GAME BOY画面";
|
||
cfg->extra_text = g_oafConfig->directBoot ? "跳过" : "显示";
|
||
}
|
||
else if( index == 2 )
|
||
{
|
||
cfg->text = "画面输出";
|
||
cfg->extra_text = scaler_val[g_oafConfig->scaler];
|
||
}
|
||
else if( index == 3 )
|
||
{
|
||
cfg->text = "存档方案";
|
||
cfg->extra_text = savetype_name[g_oafConfig->savePolicy];
|
||
}
|
||
else if( index == 4 )
|
||
{
|
||
cfg->text = "激活金手指";
|
||
cfg->extra_text = cheatmode_name[g_oafConfig->cheatMode];
|
||
}
|
||
else if( index == 5 )
|
||
{
|
||
cfg->text = "游戏中按住电源键";
|
||
cfg->extra_text = haltmode_name[g_oafConfig->haltMode];
|
||
}
|
||
cfg->value = index;
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static char* float2str( float f, char out[16] )
|
||
{
|
||
int s = (int)f;
|
||
if( f < 0 ) f = -f;
|
||
f = f - floor(f);
|
||
f *= 100;
|
||
int n = floor(f);
|
||
f = f - n;
|
||
if( f > 0.5) ++n;
|
||
if( n == 100 )
|
||
{
|
||
++s;
|
||
n = 0;
|
||
}
|
||
ee_snprintf(out, 16, "%d.%02d", s, n);
|
||
return out;
|
||
}
|
||
|
||
static atp_pageopt_t config_adjust( atp_callerdata_t gblcfg, atp_counter_t index, atp_boolean_t x, atp_boolean_t, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t )
|
||
{
|
||
OafConfig *g_oafConfig = (OafConfig*)gblcfg;
|
||
if( l || r )
|
||
{
|
||
if( index == 0 )
|
||
{
|
||
u16 light = g_oafConfig->backlight;
|
||
if( l )
|
||
{
|
||
light -= 10;
|
||
if( light % 10 ) light += 10 - light%10;
|
||
}
|
||
else if( r )
|
||
{
|
||
light += 10;
|
||
if( light % 10 ) light -= light % 10;
|
||
}
|
||
if( light > LIGHT_MAX ) light = LIGHT_MAX;
|
||
else if( light < LIGHT_MIN ) light = LIGHT_MIN;
|
||
g_oafConfig->backlight = light;
|
||
}
|
||
else if( index == 1 ) g_oafConfig->directBoot = !g_oafConfig->directBoot;
|
||
else if( index == 2 ) g_oafConfig->scaler = ( SCALER_SIZE + ( g_oafConfig->scaler+(l?-1:1) ) ) % SCALER_SIZE;
|
||
else if( index == 3 ) g_oafConfig->savePolicy = ( SAVE_POLICY_SIZE + ( g_oafConfig->savePolicy+(l?-1:1) ) ) % SAVE_POLICY_SIZE;
|
||
else if( index == 4 ) g_oafConfig->cheatMode = ( CHEAT_MODE_SIZE + (g_oafConfig->cheatMode+(l?-1:1) ) ) % CHEAT_MODE_SIZE;
|
||
else if( index == 5 ) {
|
||
size_t len = strlen( FIRMPATH_INCOME );
|
||
if( len < FIRMPATH_SIZELIMIT )
|
||
{
|
||
g_oafConfig->haltMode = ( HALT_MODE_SIZE + (g_oafConfig->haltMode+(l?-1:1) ) ) % HALT_MODE_SIZE;
|
||
}
|
||
else if( !oafRebootReady() )
|
||
{
|
||
return ATP_POWER_OFF == atp_show(1, disp_str, "请正确放置boot.firm文件")
|
||
? ATP_POWER_OFF : ATP_PAGE_REFRESH;
|
||
}
|
||
else
|
||
{
|
||
return ATP_POWER_OFF == atp_show(1, disp_str, "SD卡的open_agb_firm文件名太长")
|
||
? ATP_POWER_OFF : ATP_PAGE_REFRESH;
|
||
}
|
||
}
|
||
}
|
||
else if( start )
|
||
{
|
||
return ATP_POWER_OFF == help_page( config_help, sizeof(config_help)/sizeof(atp_text_t) )
|
||
? ATP_POWER_OFF : ATP_PAGE_REFRESH;
|
||
}
|
||
else if( x )
|
||
{
|
||
int len = strlen(CONFIG_OUTPUT) + 40;
|
||
char *data = malloc( len );
|
||
if( data == NULL ) return ATP_PAGE_DOSELECT; // only ignore this save
|
||
|
||
char gbaGamma[16];
|
||
char lcdGamma[16];
|
||
char contract[16];
|
||
char brightness[16];
|
||
len = ee_snprintf(
|
||
data, len, CONFIG_OUTPUT,
|
||
g_oafConfig->backlight,
|
||
g_oafConfig->directBoot ? "true":"false",
|
||
g_oafConfig->useGbaDb ? "true" : "false",
|
||
g_oafConfig->scaler,
|
||
float2str(g_oafConfig->gbaGamma, gbaGamma),
|
||
float2str(g_oafConfig->lcdGamma, lcdGamma),
|
||
float2str(g_oafConfig->contrast, contract),
|
||
float2str(g_oafConfig->brightness, brightness),
|
||
g_oafConfig->defaultSave,
|
||
g_oafConfig->cheatMode,
|
||
g_oafConfig->haltMode
|
||
);
|
||
fsQuickWrite("config.ini", data, len);
|
||
free( data );
|
||
return ATP_PAGE_DOSELECT;
|
||
}
|
||
return ATP_PAGE_UPDATE;
|
||
}
|
||
|
||
atp_error_t use_config_page( OafConfig *g_oafConfig )
|
||
{
|
||
u8 base[sizeof(OafConfig)];
|
||
memcpy( base, g_oafConfig, sizeof(OafConfig) );
|
||
OafConfig *prev = (OafConfig*)&base[0];
|
||
|
||
atp_text_t oldtips;
|
||
atp_tips("保存X/确定A/返回B", &oldtips);
|
||
|
||
ee_snprintf(
|
||
page_strbuf, sizeof(page_strbuf),
|
||
"参数配置 当前电量:%3d%%"
|
||
"每次开机存档方案重置为“和卡带序列号一致”,这个方案会优先使用游戏最后一次启动时设置的存档类型", MCU_getBatteryLevel());
|
||
atp_error_t res = atp_select( page_strbuf, 6, config_item, config_adjust, g_oafConfig, 0, 0, NULL );
|
||
atp_tips( oldtips, NULL );
|
||
if( res == ATP_NO_ACTION )
|
||
{
|
||
memcpy( g_oafConfig, prev, sizeof(OafConfig) );
|
||
return ATP_SUCCESS;
|
||
}
|
||
else if( res == ATP_SUCCESS )
|
||
{
|
||
if( prev->backlight != g_oafConfig->backlight )
|
||
GFX_setBrightness(g_oafConfig->backlight, g_oafConfig->backlight);
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
|
||
// --------------------------
|
||
// code for oaf cheat page
|
||
// --------------------------
|
||
|
||
#define DISP_DONE 0
|
||
#define DISP_REGION 1
|
||
#define DISP_HOLES 2
|
||
#define DISP_KEYS 3
|
||
#define SAFE_CALLACL( r ) if( ACHTLIB_SUCCESS!=r ) \
|
||
{\
|
||
res = WAIT_ON_ERRPAGE( display_selcht );\
|
||
break;\
|
||
}
|
||
|
||
DECLARE_ERROR_PAGE( display_selcht, "查找金手指配置出错" )
|
||
DECLARE_ERROR_PAGE( display_openlib, "打开金手指文件出错" )
|
||
DECLARE_ERROR_PAGE( display_nocheat, "找不到对应的金手指配置" )
|
||
|
||
static atp_error_t select_region( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *config )
|
||
{
|
||
acl_region_t sreg;
|
||
acl_chtid_t sid, id;
|
||
if( ACHTLIB_SUCCESS != acl_query_cheat_set(index, &sid, &sreg) )
|
||
{
|
||
config->text = "导出文件";
|
||
config->value = index;
|
||
return ATP_SUCCESS;
|
||
}
|
||
char *t;
|
||
switch( sreg )
|
||
{
|
||
case 'C': t = "官方中文"; break;
|
||
case 'J': t = "日文版"; break;
|
||
case 'E': t = "英文版"; break;
|
||
case 'F': t = "法语版"; break;
|
||
case 'S': t = "西班牙语"; break;
|
||
case 'I': t = "意大利语"; break;
|
||
case 'D': t = "德语版"; break;
|
||
case 'K': t = "韩文版"; break;
|
||
case 'X': case 'P': t = "欧洲语种"; break;
|
||
default: t = "其他语种"; break;
|
||
}
|
||
ee_sprintf(page_strbuf, "%c-%s", 'A'+(char)index, t);
|
||
|
||
if( CCHT_NOT_INIT == info_current_cheat( &id, NULL ) )
|
||
id = 0;
|
||
|
||
config->text = page_strbuf;
|
||
config->value = index;
|
||
|
||
// show saved information
|
||
if( sid == id )
|
||
{
|
||
config->extra_text = "已启用";
|
||
config->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t select_holes( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
acl_text_t text;
|
||
acl_error_t res = acl_entry_get_label(index, &text);
|
||
if( res == ACHTLIB_SUCCESS )
|
||
cfg->text = text;
|
||
else cfg->text = "无效数据";
|
||
cfg->value = 1+index;
|
||
|
||
// show saved information
|
||
acl_entryid_t id;
|
||
if( CCHT_OK == get_current_cheat( index, &id ) && ENT_USING(id) )
|
||
{
|
||
cfg->extra_text = "开";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t select_keys( atp_callerdata_t data, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
acl_text_t text;
|
||
if( index == 0 )
|
||
{
|
||
cfg->text = "不开启";
|
||
}
|
||
else
|
||
{
|
||
acl_error_t res = acl_entry_get_label(index-1, &text);
|
||
if( res == ACHTLIB_SUCCESS )
|
||
cfg->text = text;
|
||
else cfg->text = "无效数据";
|
||
}
|
||
acl_entryid_t eid = (acl_entryid_t)data;
|
||
cfg->value = index<<16 | eid;
|
||
|
||
if( CCHT_OK == include_current_cheat((acl_entryid_t)cfg->value) )
|
||
{
|
||
cfg->extra_text = "选中";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t select_onoff( atp_callerdata_t data, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
acl_entryid_t eid = (acl_entryid_t)data;
|
||
eid &= 0xffff;
|
||
if( index == 0 )
|
||
{
|
||
cfg->text = "不开启";
|
||
cfg->value = eid;
|
||
}
|
||
else if( index == 1 )
|
||
{
|
||
cfg->text = "开启";
|
||
cfg->value = 1<<16 | eid;
|
||
}
|
||
else
|
||
{
|
||
cfg->text = "调整数值开启[结果未知]";
|
||
cfg->value = 0;
|
||
}
|
||
|
||
// show saved information
|
||
if( CCHT_OK == include_current_cheat((acl_entryid_t)cfg->value) )
|
||
{
|
||
cfg->extra_text = "选中";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
ALWAYS_INLINE u16 calc_step( u16 value )
|
||
{
|
||
u16 n = value / 50;
|
||
if( n == 0 ) return 1;
|
||
else
|
||
{
|
||
u16 base = 1;
|
||
while( n > 10 )
|
||
{
|
||
n = n/10;
|
||
base *= 10;
|
||
}
|
||
if( n < 5 ) return base * 5;
|
||
else return base * 10;
|
||
}
|
||
}
|
||
|
||
static atp_error_t step_provider( atp_callerdata_t mixid, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
u32 mix = (u32)mixid;
|
||
u16 max = mix & 0xffff;
|
||
u16 step = mix >> 16;
|
||
u16 res = step * (index+1);
|
||
ee_snprintf( page_strbuf, 8, "%d", res < max ? res : max );
|
||
cfg->text = page_strbuf;
|
||
cfg->value = res < max ? res : max;
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t handle_onoff_entry( acl_entryid_t id, acl_elemlen_t codelen, atp_itemval_t *item )
|
||
{
|
||
#define DEFAULT_ONOFF_HANDLER atp_select("选择此项目对应的设置", 2, select_onoff, NULL, (atp_callerdata_t)id, 0, 0, item);
|
||
#define ONOFF_SAFE_CALLACL( statement ) if( ACHTLIB_SUCCESS != statement ) return DEFAULT_ONOFF_HANDLER;
|
||
|
||
if( codelen > 4 )// more than 2 address
|
||
return DEFAULT_ONOFF_HANDLER;
|
||
|
||
u16 targetval = 0;
|
||
acl_armcode_t code;
|
||
|
||
// one address
|
||
if( codelen == 2 )
|
||
{
|
||
ONOFF_SAFE_CALLACL( acl_entry_get_armcode(1, &code) );
|
||
targetval = code & 0xff;
|
||
}
|
||
// two addresses
|
||
else if( codelen == 4 )
|
||
{
|
||
u32 addr0, addr1;
|
||
ONOFF_SAFE_CALLACL( acl_entry_get_armcode(0, &addr0) );
|
||
ONOFF_SAFE_CALLACL( acl_entry_get_armcode(2, &addr1) );
|
||
if( (addr0 & 1) || (addr0 | 1) != addr1 ) // valid u16 address
|
||
return DEFAULT_ONOFF_HANDLER;
|
||
|
||
ONOFF_SAFE_CALLACL( acl_entry_get_armcode(1, &code) );
|
||
targetval = code & 0xff;
|
||
ONOFF_SAFE_CALLACL( acl_entry_get_armcode(3, &code) );
|
||
targetval |= (code & 0xff) << 8;
|
||
}
|
||
// more than two address, should not overwrite values
|
||
else return DEFAULT_ONOFF_HANDLER;
|
||
|
||
atp_error_t res = atp_select( "选择此项目对应的设置", 3, select_onoff, NULL, targetval << 16 | id, 0, 0, item );
|
||
if( res == ATP_SUCCESS && *item == 0 )
|
||
{
|
||
ee_snprintf( page_strbuf, sizeof(page_strbuf), "默认值:%d", targetval );
|
||
u16 step = calc_step( targetval );
|
||
atp_counter_t n = (targetval-1+step)/step;
|
||
res = atp_select(page_strbuf, n, step_provider, NULL, (atp_callerdata_t)(step<<16|targetval), n, 0, item );
|
||
if( res == ATP_SUCCESS && *item != targetval )
|
||
overwrite_current_cheat( 1<<16|id, *item );
|
||
|
||
*item = 1<<16 | id;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
atp_error_t use_cheat_page( const char *serial )
|
||
{
|
||
acl_count_t len;
|
||
if( ACHTLIB_SUCCESS != acl_open_lib( "gba.acl" ) )
|
||
{
|
||
return WAIT_ON_ERRPAGE( display_openlib );
|
||
}
|
||
if( ACHTLIB_SUCCESS != acl_select_game( serial, 0, &len ) )
|
||
{
|
||
acl_close_lib();
|
||
return WAIT_ON_ERRPAGE( display_selcht );
|
||
}
|
||
if( len == 0 )
|
||
{
|
||
acl_close_lib();
|
||
return WAIT_ON_ERRPAGE( display_nocheat );
|
||
}
|
||
|
||
// 显示配置页面
|
||
atp_error_t res;
|
||
atp_itemval_t item;
|
||
acl_elemlen_t cnt;
|
||
|
||
uint8_t status = DISP_REGION;
|
||
atp_counter_t defi = 0;
|
||
acl_entryid_t eid = 0;
|
||
atp_text_t oldtips;
|
||
atp_tips("确定A/返回B", &oldtips);
|
||
|
||
while( status != DISP_DONE )
|
||
{
|
||
if( status == DISP_REGION )
|
||
{
|
||
#ifdef NDEBUG
|
||
res = atp_select("请谨慎使用金手指!金手指可能会引起卡顿、死机、损坏存档等现象。 "
|
||
"选择一个金手指配置:", len, select_region, NULL, NULL, defi, 0, &item );
|
||
#else
|
||
res = atp_select("请谨慎使用金手指!金手指可能会引起卡顿、死机、损坏存档等现象。 "
|
||
"选择一个金手指配置:", len+1, select_region, NULL, NULL, defi, 0, &item );
|
||
#endif
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
#ifndef NDEBUG
|
||
if( item == len )
|
||
{
|
||
extern u8 dump_patched_rom;
|
||
dump_patched_rom = 1;
|
||
break;
|
||
}
|
||
#endif
|
||
defi = item;
|
||
acl_chtid_t sid;
|
||
acl_elemlen_t len;
|
||
u32 ccid, cclen;
|
||
SAFE_CALLACL( acl_query_cheat_set((acl_index_t)item, &sid, NULL ) );
|
||
SAFE_CALLACL( acl_select_cheat_set( sid ) );
|
||
SAFE_CALLACL( acl_select_entry(0, &len) );
|
||
|
||
if( CCHT_OK == info_current_cheat(&ccid, &cclen) )
|
||
{
|
||
// SKIP the init process when id and len is the same
|
||
if( ccid != sid || cclen != len )
|
||
init_current_cheat( sid, len );
|
||
}
|
||
else init_current_cheat( sid, len );
|
||
|
||
eid = 0;
|
||
status = DISP_HOLES;
|
||
}
|
||
else if( res == ATP_NO_ACTION)
|
||
{
|
||
status = DISP_DONE;
|
||
}
|
||
else break;
|
||
}
|
||
else if( status == DISP_HOLES )
|
||
{
|
||
SAFE_CALLACL( acl_select_entry(0, &cnt) );
|
||
res = atp_select("选择一个金手指项目", cnt, select_holes, NULL, NULL, eid > 0 ? (eid&0xffff)-1 : 0, 0, &item);
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
eid = (acl_entryid_t)item;
|
||
status = DISP_KEYS;
|
||
}
|
||
else if( res == ATP_NO_ACTION )
|
||
{
|
||
status = DISP_REGION;
|
||
}
|
||
else break;
|
||
}
|
||
else // DISP_KEYS
|
||
{
|
||
SAFE_CALLACL( acl_select_entry( eid, &cnt ) );
|
||
if( cnt == 0 )
|
||
{
|
||
SAFE_CALLACL( acl_select_entry( 1<<16 | eid, &cnt ) );
|
||
res = handle_onoff_entry( eid, cnt, &item );
|
||
}
|
||
else
|
||
{
|
||
res = atp_select("选择此项目对应的设置", cnt, select_keys, NULL, (atp_callerdata_t)eid, 0, 0, &item);
|
||
}
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
put_current_cheat( (acl_entryid_t)item );
|
||
status = DISP_HOLES;
|
||
}
|
||
else if( res == ATP_NO_ACTION )
|
||
{
|
||
status = DISP_HOLES;
|
||
}
|
||
else break;
|
||
}
|
||
}
|
||
|
||
acl_close_lib();
|
||
atp_tips( oldtips, NULL );
|
||
return res;
|
||
}
|
||
|
||
// --------------------------
|
||
// code for oaf cheat page
|
||
// --------------------------
|
||
|
||
#define DISP_KPOS 1
|
||
#define DISP_SETK 2 // SET KEY
|
||
#define DISP_KMAP 3 // REMUX TYPE
|
||
#define DISP_3DSK 4 // 3DS KEY
|
||
#define DISP_GBAK 5 // GBA KEY
|
||
|
||
#define KCP_OPTION_BASE 1000
|
||
|
||
#define KRFIELD_REMIX 0
|
||
#define KRFIELD_DEVICE 1
|
||
#define KRFIELD_GAME 2
|
||
|
||
DECLARE_ERROR_PAGE( display_conflictkey, "和已有键位产生冲突" )
|
||
|
||
const char *key_name[] = {
|
||
"上", "下", "左", "右", "A", "B", "L", "R", "SELECT", "START", "X", "Y", "ZL", "ZR"
|
||
};
|
||
const u16 key_val[] = {
|
||
KEY_DUP, KEY_DDOWN, KEY_DLEFT, KEY_DRIGHT, KEY_A, KEY_B, KEY_L, KEY_R, KEY_SELECT, KEY_START, KEY_X, KEY_Y, KEY_ZL, KEY_ZR
|
||
};
|
||
#define key_val_len (sizeof(key_val)/sizeof(u16))
|
||
|
||
static inline void key_tips( key_remix_t *p, atp_boolean_t checking, atp_itemcfg_t *cfg )
|
||
{
|
||
if( p->remix_type == REMIX_TYPE_NONE )
|
||
{
|
||
cfg->extra_text = "未添加";
|
||
cfg->extra_text_color = ATP_COLOR_LIGHT;
|
||
}
|
||
else
|
||
{
|
||
if( p->remix_type == REMIX_TYPE_CHEAT )
|
||
{
|
||
if( checking && p->game_keys == 0)
|
||
{
|
||
cfg->extra_text = "配置不齐";
|
||
cfg->extra_text_color = ATP_COLOR_RED;
|
||
}
|
||
else
|
||
{
|
||
cfg->extra_text = "金手指键";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
}
|
||
else if( p->remix_type == REMIX_TYPE_REMAP )
|
||
{
|
||
if( checking && (p->game_keys==0 || p->device_keys==0) )
|
||
{
|
||
cfg->extra_text = "配置不齐";
|
||
cfg->extra_text_color = ATP_COLOR_RED;
|
||
}
|
||
else
|
||
{
|
||
cfg->extra_text = "键位映射";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
}
|
||
else if( p->remix_type == REMIX_TYPE_HOLD )
|
||
{
|
||
if( checking && (p->game_keys==0 || p->device_keys==0) )
|
||
{
|
||
cfg->extra_text = "配置不齐";
|
||
cfg->extra_text_color = ATP_COLOR_RED;
|
||
}
|
||
else
|
||
{
|
||
cfg->extra_text = "模拟长按";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static atp_error_t select_krp( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
if( index < KEY_REMIX_LIMIT )
|
||
{
|
||
ee_snprintf(page_strbuf, sizeof(page_strbuf), "键位配置项%ld", index+1);
|
||
cfg->text = page_strbuf;
|
||
cfg->value = index;
|
||
key_remix_t *p = &g_keyremixConfig[index];
|
||
key_tips(p, 1, cfg);
|
||
}
|
||
else
|
||
{
|
||
cfg->text = index == KEY_REMIX_LIMIT ? "保存当前配置到SD卡" : "从SD卡加载已保存的配置";
|
||
cfg->value = KCP_OPTION_BASE + index-KEY_REMIX_LIMIT;
|
||
}
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t select_kcf( atp_callerdata_t p, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
key_remix_t *kcfg = (key_remix_t*)p;
|
||
if( index == KRFIELD_REMIX )
|
||
{
|
||
cfg->text = "选择键位功能";
|
||
key_tips(kcfg, 0, cfg);
|
||
}
|
||
else if( index == KRFIELD_DEVICE )
|
||
{
|
||
cfg->text = "选择实机键位";
|
||
if( kcfg->device_keys )
|
||
{
|
||
for( u8 i=0; i < key_val_len; ++i)
|
||
{
|
||
if( key_val[i] == kcfg->device_keys )
|
||
{
|
||
cfg->extra_text = key_name[i];
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
}
|
||
}
|
||
else if( kcfg->remix_type == REMIX_TYPE_CHEAT )
|
||
{
|
||
cfg->extra_text = "HOME";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
else
|
||
{
|
||
cfg->extra_text = "未设置";
|
||
cfg->extra_text_color = ATP_COLOR_LIGHT;
|
||
}
|
||
}
|
||
else if( index == KRFIELD_GAME )
|
||
{
|
||
cfg->text = "游戏中对应键位";
|
||
if( kcfg->game_keys == 0 )
|
||
{
|
||
cfg->extra_text = "未设置";
|
||
cfg->extra_text_color = ATP_COLOR_LIGHT;
|
||
}
|
||
else
|
||
{
|
||
cfg->extra_text = "已设置";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
}
|
||
cfg->value = index;
|
||
return ATP_SUCCESS;
|
||
}
|
||
static atp_error_t select_remixtype( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
if( index == REMIX_TYPE_NONE ) cfg->text = "停用设置";
|
||
else if( index == REMIX_TYPE_REMAP ) cfg->text = "键位映射";
|
||
else if( index == REMIX_TYPE_CHEAT ) cfg->text = "金手指键";
|
||
else if( index == REMIX_TYPE_HOLD ) cfg->text = "模拟长按";
|
||
cfg->value = index;
|
||
return ATP_SUCCESS;
|
||
}
|
||
static atp_error_t select_unikey( atp_callerdata_t str, atp_counter_t, atp_itemcfg_t *cfg )
|
||
{
|
||
cfg->text = (atp_text_t)str;
|
||
cfg->value = 0;
|
||
return ATP_SUCCESS;
|
||
}
|
||
static atp_error_t select_hostkey( atp_callerdata_t dat, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
phykey_t k = (phykey_t)dat;
|
||
cfg->text = key_name[index];
|
||
cfg->value = key_val[index];
|
||
if( k == key_val[index] )
|
||
{
|
||
cfg->extra_text = "选中";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t select_gbakey( atp_callerdata_t p_curkey, atp_counter_t index, atp_itemcfg_t *cfg )
|
||
{
|
||
conkey_t key = *(conkey_t*)p_curkey;
|
||
cfg->text = key_name[index];
|
||
cfg->value = key_val[index];
|
||
if( key & key_val[index] )
|
||
{
|
||
cfg->extra_text = "选中";
|
||
cfg->extra_text_color = ATP_COLOR_GREEN;
|
||
}
|
||
return ATP_SUCCESS;
|
||
}
|
||
|
||
static atp_error_t active_gbakey( atp_callerdata_t p_curkey, atp_counter_t index, atp_boolean_t x, atp_boolean_t y, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t select )
|
||
{
|
||
conkey_t *pkey = (conkey_t*)p_curkey;
|
||
if( x )
|
||
{
|
||
conkey_t res = *pkey & key_val[index];
|
||
if( res ) *pkey &= ~key_val[index];
|
||
else *pkey |= key_val[index];
|
||
return ATP_PAGE_UPDATE;
|
||
}
|
||
else return ATP_PAGE_NOOPTION;
|
||
}
|
||
|
||
atp_error_t use_keyremix_page( char *file )
|
||
{
|
||
atp_itemval_t position=0, field=0, value;
|
||
atp_error_t res;
|
||
atp_text_t oldtips;
|
||
atp_tips( "确定A/返回B", &oldtips );
|
||
|
||
uint8_t status = DISP_KPOS;
|
||
while ( status != DISP_DONE )
|
||
{
|
||
if ( status == DISP_KPOS)
|
||
{
|
||
res = atp_select( "选择配置项后,按A进行键位配置", KEY_REMIX_LIMIT+2, select_krp, NULL, NULL, position, 0, &position );
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
if( position < KEY_REMIX_LIMIT )
|
||
{
|
||
status = DISP_SETK;
|
||
field = 0;
|
||
}
|
||
else if( position == KCP_OPTION_BASE )
|
||
{
|
||
const char *err = keyremix_dump( file );
|
||
if( !err ) status = DISP_DONE;
|
||
else atp_show( 1, disp_str, err );
|
||
}
|
||
else
|
||
{
|
||
const char *err = keyremix_load( file );
|
||
if( !err ) position = 0;
|
||
else atp_show( 1, disp_str, err );
|
||
}
|
||
}
|
||
else break;
|
||
}
|
||
else if( status == DISP_SETK )
|
||
{
|
||
ee_snprintf(page_strbuf, sizeof(page_strbuf), "编辑配置项%ld", position+1);
|
||
key_remix_t *cur = &g_keyremixConfig[position];
|
||
res = atp_select( page_strbuf, 3, select_kcf, NULL, cur, field, 0, &field );
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
status = field == KRFIELD_REMIX ? DISP_KMAP : (field == KRFIELD_DEVICE ? DISP_3DSK : DISP_GBAK);
|
||
}
|
||
else if( res == ATP_NO_ACTION )
|
||
{
|
||
int fault = 0;
|
||
for( int i=0; i < KEY_REMIX_LIMIT; ++i )
|
||
{
|
||
if( i!=position )
|
||
{
|
||
if( g_keyremixConfig[i].remix_type == cur->remix_type
|
||
&& g_keyremixConfig[i].device_keys == cur->device_keys )
|
||
{
|
||
fault = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if( fault && cur->remix_type != REMIX_TYPE_NONE )
|
||
atp_show(1, display_conflictkey, NULL);
|
||
else status = DISP_KPOS;
|
||
}
|
||
else break;
|
||
}
|
||
else if( status == DISP_KMAP )
|
||
{
|
||
key_remix_t *cur = &g_keyremixConfig[position];
|
||
res = atp_select( "配置键位功能", REMIX_TYPE_COUNT, select_remixtype, NULL, cur->remix_type, 0, 0, &value );
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
if( cur->remix_type != value )
|
||
{
|
||
cur->remix_type = value;
|
||
cur->device_keys = 0;
|
||
cur->game_keys = value == REMIX_TYPE_CHEAT ? DEFAULT_CHEATKEY : 0;
|
||
}
|
||
status = DISP_SETK;
|
||
}
|
||
else if( res == ATP_NO_ACTION )
|
||
{
|
||
status = DISP_SETK;
|
||
}
|
||
else break;
|
||
}
|
||
else if( status == DISP_3DSK )
|
||
{
|
||
key_remix_t *cur = &g_keyremixConfig[position];
|
||
atp_counter_t keys_count = 12; // old 3ds, old 3dsLL, 2ds
|
||
u8 host = MCU_getSystemModel();// 0=3ds 1=3dsll 2=n3ds 3=2ds 4=n3dsll 5=n2dsll
|
||
atp_text_t text;
|
||
if( cur->remix_type == REMIX_TYPE_CHEAT )
|
||
{
|
||
keys_count = 1;
|
||
text = "HOME";
|
||
}
|
||
else if( host > 1 && host != 3 ) // N3DS/N3DSLL/N2DSLL
|
||
{
|
||
keys_count = 14;
|
||
}
|
||
u8 selected = 31;
|
||
for( u8 i=0; i < key_val_len; ++i )
|
||
{
|
||
if( key_val[i] == cur->device_keys )
|
||
{
|
||
selected = i;
|
||
break;
|
||
}
|
||
}
|
||
if( keys_count == 1 ) res = atp_select("选择实机键位(单选)", 1, select_unikey, NULL, text, 0, 0, &value);
|
||
else res = atp_select( "选择实机键位(单选)", keys_count, select_hostkey, NULL, cur->device_keys, selected>keys_count?0:selected, 0, &value);
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
cur->device_keys = value;
|
||
status = DISP_SETK;
|
||
}
|
||
else if( res == ATP_NO_ACTION )
|
||
{
|
||
status = DISP_SETK;
|
||
}
|
||
else break;
|
||
}
|
||
else if( status == DISP_GBAK )
|
||
{
|
||
key_remix_t *cur = &g_keyremixConfig[position];
|
||
conkey_t key_editing = cur->game_keys;
|
||
atp_text_t current;
|
||
atp_tips("选择X/确定A/返回B", ¤t);
|
||
res = atp_select( "选择游戏中对应键位[多选,按X键设置选中]", 10, select_gbakey, active_gbakey, &key_editing, 0, 0, &value);
|
||
atp_tips( current, NULL );
|
||
if( res == ATP_SUCCESS )
|
||
{
|
||
cur->game_keys = key_editing;
|
||
status = DISP_SETK;
|
||
}
|
||
else if( res == ATP_NO_ACTION )
|
||
{
|
||
status = DISP_SETK;
|
||
}
|
||
else break;
|
||
}
|
||
}
|
||
|
||
atp_tips( oldtips, NULL );
|
||
return res;
|
||
} |