在这个文件夹创建:include\dialogue_portraits.h
#ifndef GUARD_DIALOGUE_PORTRAITS_H
#define GUARD_DIALOGUE_PORTRAITS_H
#include "global.h"
// 头像位置定义
#define PORTRAIT_LEFT_X 2 // 左侧头像位置
#define PORTRAIT_RIGHT_X 21 // 右侧头像位置
#define PORTRAIT_Y 7 // 对话框上方位置
// 头像状态枚举
enum PortraitState {
PORTRAIT_STATE_NONE = 0,
PORTRAIT_STATE_SHOWING,
PORTRAIT_STATE_VISIBLE,
PORTRAIT_STATE_HIDING
};
// 头像结构体
struct DialoguePortrait {
u8 spriteId; // 精灵ID
u8 state; // 当前状态
u8 currentFrame; // 当前帧
u8 timer; // 动画计时器
u16 paletteTag; // 调色板标签
u16 gfxTag; // 图形标签
};
// 函数声明
void InitDialoguePortraitSystem(void);
void CleanupDialoguePortraitSystem(void);
bool8 ShowDialoguePortrait(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag);
bool8 ShowDialoguePortraitWithFlip(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag, bool8 hFlip, bool8 vFlip);
void HideDialoguePortrait(u8 side);
void UpdateDialoguePortraits(void);
bool8 ArePortraitsActive(void);
void SetDialoguePortraitFlip(u8 side, bool8 hFlip, bool8 vFlip);
#endif // GUARD_DIALOGUE_PORTRAITS_H在这个文件夹创建:src\dialogue_portraits.c
#include "global.h"
#include "dialogue_portraits.h"
#include "window.h"
#include "menu.h"
#include "sprite.h"
#include "malloc.h"
#include "task.h"
#include "text_window.h"
#include "constants/trainers.h"
#include "data.h"
#include "decompress.h"
#include "constants/songs.h"
#include "portrait_data.h"
// 自定义头像ID范围定义
#define CUSTOM_PORTRAIT_ID_START 1000
#define CUSTOM_PORTRAIT_ID_END 1999
// 头像系统全局变量
static EWRAM_DATA struct DialoguePortrait sPortraits[2] = {0};
static EWRAM_DATA bool8 sPortraitSystemInitialized = FALSE;
// 自定义头像资源声明
extern const u8 gHeadPortrait_001_Gfx[];
extern const u16 gHeadPortrait_001_Pal[];
extern const u8 gHeadPortrait_002_Gfx[];
extern const u16 gHeadPortrait_002_Pal[];
// 加载自定义头像资源
static bool8 LoadCustomPortrait(u16 portraitId, u16 *gfxTag, u16 *paletteTag)
{
u16 localId = portraitId - CUSTOM_PORTRAIT_ID_START + 1;
// 根据ID加载对应的自定义头像资源
const u8 *gfxData = NULL;
const u16 *palData = NULL;
switch (localId) {
case 1:
gfxData = gHeadPortrait_001_Gfx;
palData = gHeadPortrait_001_Pal;
break;
case 2:
gfxData = gHeadPortrait_002_Gfx;
palData = gHeadPortrait_002_Pal;
break;
default:
return FALSE; // 不支持的自定义头像ID
}
if (!gfxData || !palData)
return FALSE;
// 加载自定义头像图形
struct CompressedSpriteSheet spriteSheet = {
.data = (const void *)gfxData,
.size = 0x800, // 64x64像素,4bpp
.tag = portraitId + 0x3000 // 使用0x3000系列标签避免与训练师冲突
};
LoadCompressedSpriteSheet(&spriteSheet);
// 加载自定义头像调色板
struct SpritePalette spritePalette = {
.data = (const void *)palData,
.tag = portraitId + 0x4000 // 使用0x4000系列标签
};
LoadSpritePalette(&spritePalette);
*gfxTag = portraitId + 0x3000;
*paletteTag = portraitId + 0x4000;
return TRUE;
}
// 初始化头像系统
void InitDialoguePortraitSystem(void)
{
// 如果已经初始化,先清理
if (sPortraitSystemInitialized) {
CleanupDialoguePortraitSystem();
}
// 初始化头像数据
memset(sPortraits, 0, sizeof(sPortraits));
// 初始化资源标签为无效值
for (int i = 0; i < 2; i++) {
sPortraits[i].spriteId = 0xFF;
sPortraits[i].gfxTag = 0xFFFF;
sPortraits[i].paletteTag = 0xFFFF;
}
sPortraitSystemInitialized = TRUE;
}
// 清理头像系统
void CleanupDialoguePortraitSystem(void)
{
if (!sPortraitSystemInitialized)
return;
// 销毁精灵
if (sPortraits[0].spriteId != 0xFF && sPortraits[0].spriteId < MAX_SPRITES) {
DestroySprite(&gSprites[sPortraits[0].spriteId]);
}
if (sPortraits[1].spriteId != 0xFF && sPortraits[1].spriteId < MAX_SPRITES) {
DestroySprite(&gSprites[sPortraits[1].spriteId]);
}
memset(sPortraits, 0, sizeof(sPortraits));
sPortraitSystemInitialized = FALSE;
}
// 显示头像
bool8 ShowDialoguePortrait(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag)
{
if (!sPortraitSystemInitialized || side > 1)
return FALSE;
struct DialoguePortrait *portrait = &sPortraits[side];
// 如果已经有头像显示,先隐藏并清理
if (portrait->state != PORTRAIT_STATE_NONE) {
HideDialoguePortrait(side);
}
// 加载头像图形资源
if (gfxTag >= CUSTOM_PORTRAIT_ID_START && gfxTag <= CUSTOM_PORTRAIT_ID_END) {
// 使用自定义头像
if (!LoadCustomPortrait(gfxTag, &portrait->gfxTag, &portrait->paletteTag)) {
return FALSE;
}
} else if (gfxTag < TRAINER_PIC_COUNT) {
// 使用系统预定义的训练师图像
const struct TrainerSprite *trainerSprite = &gTrainerSprites[gfxTag];
// 加载图像数据
struct CompressedSpriteSheet spriteSheet = {
.data = trainerSprite->frontPic.data,
.size = trainerSprite->frontPic.size,
.tag = gfxTag + 0x1000 // 使用唯一标签避免冲突
};
LoadCompressedSpriteSheet(&spriteSheet);
// 加载调色板数据
struct SpritePalette spritePalette = {
.data = trainerSprite->palette.data,
.tag = gfxTag + 0x2000 // 使用唯一标签避免冲突
};
LoadSpritePalette(&spritePalette);
// 更新标签以便后续使用
portrait->gfxTag = gfxTag + 0x1000;
portrait->paletteTag = gfxTag + 0x2000;
} else {
// 对于无效的ID,直接返回失败
return FALSE;
}
// 创建精灵来显示头像
struct SpriteTemplate spriteTemplate = {
.tileTag = portrait->gfxTag,
.paletteTag = portrait->paletteTag,
.oam = &(const struct OamData){
.y = 0,
.affineMode = ST_OAM_AFFINE_OFF,
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
.x = 0,
.size = SPRITE_SIZE(64x64),
.tileNum = 0,
.priority = 1,
.paletteNum = 0,
},
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy
};
// 计算精灵位置
u16 x, y;
if (side == 0) { // 左侧
x = PORTRAIT_LEFT_X * 8 + 32; // 窗口中心位置
} else { // 右侧
x = PORTRAIT_RIGHT_X * 8 + 32;
}
y = PORTRAIT_Y * 8 + 32;
portrait->spriteId = CreateSprite(&spriteTemplate, x, y, 0);
if (portrait->spriteId == MAX_SPRITES) {
// 创建精灵失败,清理资源
FreeSpritePaletteByTag(portrait->paletteTag);
FreeSpriteTilesByTag(portrait->gfxTag);
portrait->gfxTag = 0xFFFF;
portrait->paletteTag = 0xFFFF;
return FALSE;
}
// 设置精灵属性
struct Sprite *sprite = &gSprites[portrait->spriteId];
sprite->oam.priority = 1; // 在对话框之上
sprite->subpriority = 4;
// 设置状态
portrait->state = PORTRAIT_STATE_SHOWING;
portrait->currentFrame = 0;
portrait->timer = 0;
return TRUE;
}
// 显示头像(带翻转参数)
bool8 ShowDialoguePortraitWithFlip(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag, bool8 hFlip, bool8 vFlip)
{
if (!ShowDialoguePortrait(portraitId, side, gfxTag, paletteTag))
return FALSE;
// 设置翻转状态
SetDialoguePortraitFlip(side, hFlip, vFlip);
return TRUE;
}
// 隐藏头像
void HideDialoguePortrait(u8 side)
{
if (!sPortraitSystemInitialized || side > 1)
return;
struct DialoguePortrait *portrait = &sPortraits[side];
if (portrait->state == PORTRAIT_STATE_NONE)
return;
// 销毁精灵
if (portrait->spriteId != 0xFF && portrait->spriteId < MAX_SPRITES) {
DestroySprite(&gSprites[portrait->spriteId]);
portrait->spriteId = 0xFF;
}
// 释放资源
if (portrait->gfxTag != 0xFFFF) {
FreeSpritePaletteByTag(portrait->paletteTag);
FreeSpriteTilesByTag(portrait->gfxTag);
}
// 重置所有状态和标签
portrait->state = PORTRAIT_STATE_NONE;
portrait->currentFrame = 0;
portrait->timer = 0;
portrait->gfxTag = 0xFFFF;
portrait->paletteTag = 0xFFFF;
}
// 更新头像
void UpdateDialoguePortraits(void)
{
if (!sPortraitSystemInitialized)
return;
for (int i = 0; i < 2; i++) {
struct DialoguePortrait *portrait = &sPortraits[i];
switch (portrait->state) {
case PORTRAIT_STATE_SHOWING:
portrait->timer++;
if (portrait->timer > 10) { // 显示动画持续10帧
portrait->state = PORTRAIT_STATE_VISIBLE;
}
break;
case PORTRAIT_STATE_VISIBLE:
// 可以在这里添加呼吸动画等效果
portrait->timer++;
if (portrait->timer > 60) { // 每秒更新一次
portrait->timer = 0;
portrait->currentFrame = (portrait->currentFrame + 1) % 2;
}
break;
case PORTRAIT_STATE_HIDING:
portrait->timer++;
if (portrait->timer > 10) { // 隐藏动画持续10帧
portrait->state = PORTRAIT_STATE_NONE;
}
break;
default:
break;
}
}
}
// 设置头像翻转
void SetDialoguePortraitFlip(u8 side, bool8 hFlip, bool8 vFlip)
{
if (!sPortraitSystemInitialized || side > 1)
return;
struct DialoguePortrait *portrait = &sPortraits[side];
// 检查是否有有效的精灵
if (portrait->spriteId == 0xFF || portrait->spriteId >= MAX_SPRITES)
return;
// 检查精灵是否处于活动状态
if (portrait->state == PORTRAIT_STATE_NONE)
return;
struct Sprite *sprite = &gSprites[portrait->spriteId];
// 设置精灵的翻转属性
sprite->hFlip = hFlip;
sprite->vFlip = vFlip;
// 直接设置OAM翻转位,不使用异或操作
sprite->oam.matrixNum &= 0x7; // 清除翻转位
if (hFlip)
sprite->oam.matrixNum |= (1 << 3); // 设置水平翻转位
if (vFlip)
sprite->oam.matrixNum |= (1 << 4); // 设置垂直翻转位
}
// 检查是否有头像活动
bool8 ArePortraitsActive(void)
{
if (!sPortraitSystemInitialized)
return FALSE;
return (sPortraits[0].state != PORTRAIT_STATE_NONE ||
sPortraits[1].state != PORTRAIT_STATE_NONE);
}在这个文件夹创建:src\portrait_data.c
#include "global.h"
// 自定义头像资源定义
// 这些将由工具链从graphics/head/文件夹中的PNG和PAL文件自动生成
// 头像001 - 玩家头像
const u8 gHeadPortrait_001_Gfx[] = INCBIN_U8("graphics/head/head_001.4bpp.smol");
const u16 gHeadPortrait_001_Pal[] = INCBIN_U16("graphics/head/head_001.gbapal");
// 头像002 - 预留给其他角色
const u8 gHeadPortrait_002_Gfx[] = INCBIN_U8("graphics/head/head_002.4bpp.smol");
const u16 gHeadPortrait_002_Pal[] = INCBIN_U16("graphics/head/head_002.gbapal");修改这个文件:src\field_message_box.c
#include "global.h"
#include "menu.h"
#include "string_util.h"
#include "task.h"
#include "text.h"
#include "match_call.h"
#include "field_message_box.h"
#include "text_window.h"
#include "script.h"
#include "dialogue_portraits.h" //新增代码void InitFieldMessageBox(void)
{
sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;
gTextFlags.canABSpeedUpPrint = FALSE;
gTextFlags.useAlternateDownArrow = FALSE;
gTextFlags.autoScroll = FALSE;
gTextFlags.forceMidTextSpeed = FALSE;
InitDialoguePortraitSystem(); //新增代码
}#define tState data[0]
static void Task_DrawFieldMessage(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch (task->tState)
{
case 0:
if (gMsgIsSignPost)
LoadSignPostWindowFrameGfx();
else
LoadMessageBoxAndBorderGfx();
task->tState++;
break;
case 1:
DrawDialogueFrame(0, TRUE);
task->tState++;
break;
case 2:
UpdateDialoguePortraits(); //新增代码
if (RunTextPrintersAndIsPrinter0Active() != TRUE)
{
sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;
DestroyTask(taskId);
}
}
}void HideFieldMessageBox(void)
{
DestroyTask_DrawFieldMessage();
ClearDialogWindowAndFrame(0, TRUE);
CleanupDialoguePortraitSystem(); //新增代码
sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;
}这个文件添加代码:data\specials.inc
def_special Special_ShowDialoguePortrait
def_special Special_HideDialoguePortrait
def_special Special_UpdateDialoguePortraits
def_special Special_InitDialoguePortraitSystem
def_special Special_ShowDialoguePortrait
def_special Special_ShowDialoguePortraitWithFlip
def_special Special_HideDialoguePortrait
def_special Special_UpdateDialoguePortraits
def_special Special_CleanupDialoguePortraitSystem
def_special Special_SetDialoguePortraitFlip
这个文件新增代码:src\field_specials.c
#include "dialogue_portraits.h" //新增代码
// 头像系统special函数实现
void Special_InitDialoguePortraitSystem(void)
{
InitDialoguePortraitSystem();
}
void Special_ShowDialoguePortrait(void)
{
u8 side = gSpecialVar_0x8004; // 0=左侧,1=右侧
u8 portraitId = gSpecialVar_0x8005; // 头像ID
u16 gfxTag = gSpecialVar_0x8006; // 图形标签
u16 paletteTag = gSpecialVar_0x8007; // 调色板标签
ShowDialoguePortrait(portraitId, side, gfxTag, paletteTag);
}
void Special_ShowDialoguePortraitWithFlip(void)
{
u8 side = gSpecialVar_0x8004; // 0=左侧,1=右侧
u8 portraitId = gSpecialVar_0x8005; // 头像ID
u16 gfxTag = gSpecialVar_0x8006; // 图形标签
u16 paletteTag = gSpecialVar_0x8007; // 调色板标签
bool8 hFlip = gSpecialVar_0x8008; // 水平翻转
bool8 vFlip = gSpecialVar_0x8009; // 垂直翻转
ShowDialoguePortraitWithFlip(portraitId, side, gfxTag, paletteTag, hFlip, vFlip);
}
void Special_HideDialoguePortrait(void)
{
u8 side = gSpecialVar_0x8004; // 0=左侧,1=右侧
HideDialoguePortrait(side);
}
void Special_UpdateDialoguePortraits(void)
{
UpdateDialoguePortraits();
}
void Special_CleanupDialoguePortraitSystem(void)
{
CleanupDialoguePortraitSystem();
}
void Special_SetDialoguePortraitFlip(void)
{
u8 side = gSpecialVar_0x8004; // 0=左侧,1=右侧
bool8 hFlip = gSpecialVar_0x8005; // 水平翻转
bool8 vFlip = gSpecialVar_0x8006; // 垂直翻转
SetDialoguePortraitFlip(side, hFlip, vFlip);
}
新增文件:include\portrait_data.h
#ifndef GUARD_PORTRAIT_DATA_H
#define GUARD_PORTRAIT_DATA_H
// 自定义头像资源声明
// 这些将由工具链从graphics/head/文件夹中的PNG和PAL文件生成
extern const u8 gHeadPortrait_001_Gfx[];
extern const u16 gHeadPortrait_001_Pal[];
extern const u8 gHeadPortrait_002_Gfx[];
extern const u16 gHeadPortrait_002_Pal[];
#endif // GUARD_PORTRAIT_DATA_H文件新增代码:include\constants\field_specials.h
// 头像系统Special函数常量
#define SPECIAL_INIT_DIALOGUE_PORTRAIT_SYSTEM 0x200
#define SPECIAL_SHOW_DIALOGUE_PORTRAIT 0x201
#define SPECIAL_HIDE_DIALOGUE_PORTRAIT 0x202
#define SPECIAL_UPDATE_DIALOGUE_PORTRAITS 0x203
#define SPECIAL_CLEANUP_DIALOGUE_PORTRAIT_SYSTEM 0x204文件新增代码:graphics_file_rules.mk
### Custom Trainer Portraits ###
# Define custom graphics directory
CUSTOMGFXDIR := graphics/head
# Convert PNG to 4bpp format for trainer portraits
$(CUSTOMGFXDIR)/head_001.4bpp: %.4bpp: %.png
$(GFX) $< $@ -num_tiles 64 -Wnum_tiles
# Convert 4bpp to compressed .4bpp.smol format
$(CUSTOMGFXDIR)/head_001.4bpp.smol: %.4bpp.smol: %.4bpp
$(SMOL) -w $< $@
# Extract palette from PNG and convert to GBAPAL format
$(CUSTOMGFXDIR)/head_001.gbapal: %.gbapal: %.png
$(GFX) $< $@ -palette
脚本测试示例:
Text_PortraitFlipIntro:
.string "这是头像翻转功能演示。\n我们将展示各种翻转效果。$"
Text_PortraitNormal:
.string "这是正常方向的头像。$"
Text_PortraitHFlip:
.string "这是水平翻转的头像。\n头像现在面向左边。$"
Text_PortraitVFlip:
.string "这是垂直翻转的头像。\n头像现在上下颠倒。$"
Text_PortraitBothFlip:
.string "这是同时水平和垂直翻转的头像。\n相当于180度旋转。$"
Text_PortraitRestored:
.string "恢复正常方向的头像。$"
Text_DualPortraitIntro:
.string "现在演示双人对话中的翻转效果。$"
Text_LeftCharacterNormal:
.string "左边角色:你好!我是面向右边的。$"
Text_RightCharacterFlipped:
.string "右边角色:你好!我现在面向左边。$"
Text_BothFacingForward:
.string "两个角色都面向前方了!$"
Text_DynamicFlipIntro:
.string "演示动态翻转效果,模拟角色转头。$"
Text_FacingRight:
.string "面向右边...$"
Text_FacingLeft:
.string "面向左边...$"
Text_FacingRightAgain:
.string "又面向右边了!$"
Text_DemoComplete:
.string "头像翻转功能演示完成!$"
// 示例1:基本头像显示和翻转
EventScript_PortraitFlipBasic::
lock
faceplayer
// 初始化头像系统
special Special_InitDialoguePortraitSystem
msgbox Text_PortraitFlipIntro, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 显示左侧头像(使用自定义头像ID)
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // 头像ID 0 (未使用)
setvar VAR_0x8006, 1000 // 自定义头像ID: head_001.png
setvar VAR_0x8007, 0 // 调色板标签 (未使用)
special Special_ShowDialoguePortrait
msgbox Text_PortraitNormal, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 水平翻转头像
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 1 // hFlip=TRUE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_PortraitHFlip, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 垂直翻转头像
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // hFlip=FALSE
setvar VAR_0x8006, 1 // vFlip=TRUE
special Special_SetDialoguePortraitFlip
msgbox Text_PortraitVFlip, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 同时水平和垂直翻转
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 1 // hFlip=TRUE
setvar VAR_0x8006, 1 // vFlip=TRUE
special Special_SetDialoguePortraitFlip
msgbox Text_PortraitBothFlip, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 恢复正常方向
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // hFlip=FALSE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_PortraitRestored, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 隐藏头像
setvar VAR_0x8004, 0 // 左侧
special Special_HideDialoguePortrait
// 清理头像系统
special Special_CleanupDialoguePortraitSystem
release
end
// 示例2:双人对话中的翻转效果
EventScript_PortraitFlipDual::
lock
faceplayer
// 初始化头像系统
special Special_InitDialoguePortraitSystem
msgbox Text_DualPortraitIntro, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 显示两个头像
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // 头像ID 0
setvar VAR_0x8006, 1001 // 训练师ID: Brendan
setvar VAR_0x8007, 0 // 调色板标签
special Special_ShowDialoguePortrait
setvar VAR_0x8004, 1 // 右侧
setvar VAR_0x8005, 1 // 头像ID 1
setvar VAR_0x8006, 1000 // 训练师ID: May
setvar VAR_0x8007, 0 // 调色板标签
special Special_ShowDialoguePortrait
// 左侧角色说话(正常面向右边)
msgbox Text_LeftCharacterNormal, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 右侧角色说话(水平翻转面向左边)
setvar VAR_0x8004, 1 // 右侧
setvar VAR_0x8005, 1 // hFlip=TRUE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_RightCharacterFlipped, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 两个角色都面向前方
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // hFlip=FALSE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
setvar VAR_0x8004, 1 // 右侧
setvar VAR_0x8005, 0 // hFlip=FALSE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_BothFacingForward, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 隐藏头像
setvar VAR_0x8004, 0 // 左侧
special Special_HideDialoguePortrait
setvar VAR_0x8004, 1 // 右侧
special Special_HideDialoguePortrait
// 清理头像系统
special Special_CleanupDialoguePortraitSystem
release
end
// 示例3:动态翻转效果(模拟角色转头)
EventScript_PortraitFlipDynamic::
lock
faceplayer
// 初始化头像系统
special Special_InitDialoguePortraitSystem
msgbox Text_DynamicFlipIntro, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 显示头像
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // 头像ID 0
setvar VAR_0x8006, 1000 // 自定义头像ID
setvar VAR_0x8007, 0 // 调色板标签
special Special_ShowDialoguePortrait
// 正常方向(面向右边)
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // hFlip=FALSE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_FacingRight, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
delay 30
// 水平翻转(面向左边)
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 1 // hFlip=TRUE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_FacingLeft, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
delay 30
// 再次翻转回来
setvar VAR_0x8004, 0 // 左侧
setvar VAR_0x8005, 0 // hFlip=FALSE
setvar VAR_0x8006, 0 // vFlip=FALSE
special Special_SetDialoguePortraitFlip
msgbox Text_FacingRightAgain, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
// 隐藏头像
setvar VAR_0x8004, 0 // 左侧
special Special_HideDialoguePortrait
// 清理头像系统
special Special_CleanupDialoguePortraitSystem
msgbox Text_DemoComplete, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
release
end