sdlpal精灵素材内存截取并保存到硬盘
github地址
https://github.com/sdlpal/sdlpal
简单阅读了一下源码,虽然项目用到了stb_image.h,但是我们还需要stb_image_write.h来写文件,所以还得再搞一下
https://github.com/nothings/stb
打开项目文件
sdlpal\win32\sdlpal.sln
确保先能编译,并正确运行,我以DOS仙剑为例测试的
首先,关闭一些启动动画
打开 main.c 文件
//PAL_TrademarkScreen(); //PAL_SplashScreen();
项目中加入stb_image_write.h的include路径
打开 palette.c 文件,头部加入
#define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h"
加入全局变量和控制变量
SDL_Color pe_palette[256]; int pe_palette_ready = 0; static int bOnce_day = 0; static int bOnce_night = 0; static int bRec_day = 0; static int bRec_night = 0; static int pe_id = 0;
在下面的 PAL_GetPalette 函数中找到 palette 部分代码,修改如下
for (i = 0; i < 256; i++) { palette[i].r = buf[(fNight ? 256 * 3 : 0) + i * 3] << 2; palette[i].g = buf[(fNight ? 256 * 3 : 0) + i * 3 + 1] << 2; palette[i].b = buf[(fNight ? 256 * 3 : 0) + i * 3 + 2] << 2; if (iPaletteNum == 0) { if (pe_id == 1) { pe_palette[i].r = palette[i].r; pe_palette[i].g = palette[i].g; pe_palette[i].b = palette[i].b; } } #if 0 palette[i].r += (255 - palette[i].r) / 5; palette[i].g += (255 - palette[i].g) / 5; palette[i].b += (255 - palette[i].b) / 5; #endif } if (iPaletteNum == 0) { if (!fNight) { if (bRec_day) { if (pe_id == 1) { if (!bOnce_day) { bOnce_day = 1; char* peOutFile = "pat_0_day.png"; int bRet = access(peOutFile, 0); //0为存在 if (bRet != 0) { int w = 256; int h = 1; int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int i = 0; i < 256; i++) { data[i * 4 + 0] = palette[i].r; data[i * 4 + 1] = palette[i].g; data[i * 4 + 2] = palette[i].b; data[i * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(data); } } } } } if (pe_id == 1) { pe_palette_ready = 1; } pe_id++; } //night palette else { if (bRec_night) { if (!bOnce_night) { bOnce_night = 1; char* peOutFile = "pat_0_night.png"; int bRet = access(peOutFile, 0); if (bRet != 0) { int w = 256; int h = 1; int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int i = 0; i < 256; i++) { data[i * 4 + 0] = palette[i].r; data[i * 4 + 1] = palette[i].g; data[i * 4 + 2] = palette[i].b; data[i * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(data); } } } } } }
调试运行,读档进入游戏后,在bOnce_day和bOnce_night处下断点,变量设为1,即可dump两个调色板
白天
夜晚
然后打开 palcommon.c 文件
参考 PAL_RLEBlitToSurfaceWithShadow 函数,写一个类似的函数,起名叫 PE_RLEBlitToSurface,内容如下,其实就是简化版,低依赖版本
INT PE_RLEBlitToSurface( LPCBITMAPRLE lpBitmapRLE, LPCBYTE lpDstSurface, int surfaceWidth, int surfaceHeight ) { UINT i, j, k, sx; INT x, y; UINT uiLen = 0; UINT uiWidth = 0; UINT uiHeight = 0; UINT uiSrcX = 0; BYTE T; INT dx = 0; INT dy = 0; LPBYTE p; // // Check for NULL pointer. // if (lpBitmapRLE == NULL || lpDstSurface == NULL) { return -1; } // // Skip the 0x00000002 in the file header. // if (lpBitmapRLE[0] == 0x02 && lpBitmapRLE[1] == 0x00 && lpBitmapRLE[2] == 0x00 && lpBitmapRLE[3] == 0x00) { lpBitmapRLE += 4; } // // Get the width and height of the bitmap. // uiWidth = lpBitmapRLE[0] | (lpBitmapRLE[1] << 8); uiHeight = lpBitmapRLE[2] | (lpBitmapRLE[3] << 8); // // Check whether bitmap intersects the surface. // if (uiWidth + dx <= 0 || dx >= surfaceWidth || uiHeight + dy <= 0 || dy >= surfaceHeight) { goto end; } // // Calculate the total length of the bitmap. // The bitmap is 8-bpp, each pixel will use 1 byte. // uiLen = uiWidth * uiHeight; // // Start decoding and blitting the bitmap. // lpBitmapRLE += 4; for (i = 0; i < uiLen;) { T = *lpBitmapRLE++; if ((T & 0x80) && T <= 0x80 + uiWidth) { i += T - 0x80; uiSrcX += T - 0x80; if (uiSrcX >= uiWidth) { uiSrcX -= uiWidth; dy++; } } else { // // Prepare coordinates. // j = 0; sx = uiSrcX; x = dx + uiSrcX; y = dy; // // Skip the points which are out of the surface. // if (y < 0) { j += -y * uiWidth; y = 0; } else if (y >= surfaceHeight) { goto end; // No more pixels needed, break out } while (j < T) { // // Skip the points which are out of the surface. // if (x < 0) { j += -x; if (j >= T) break; sx += -x; x = 0; } else if (x >= surfaceWidth) { j += uiWidth - sx; x -= sx; sx = 0; y++; if (y >= surfaceHeight) { goto end; // No more pixels needed, break out } continue; } // // Put the pixels in row onto the surface // k = T - j; if (surfaceWidth - x < k) k = surfaceWidth - x; if (uiWidth - sx < k) k = uiWidth - sx; sx += k; p = lpDstSurface + y * surfaceWidth; //if (bShadow) //{ // j += k; // for (; k != 0; k--) // { // p[x] = PAL_CalcShadowColor(p[x]); // x++; // } //} //else { for (; k != 0; k--) { p[x] = lpBitmapRLE[j]; j++; x++; } } if (sx >= uiWidth) { sx -= uiWidth; x -= uiWidth; y++; if (y >= surfaceHeight) { goto end; // No more pixels needed, break out } } } lpBitmapRLE += T; i += T; uiSrcX += T; while (uiSrcX >= uiWidth) { uiSrcX -= uiWidth; dy++; } } } end: // // Success // return 0; }
记得 palcommon.h 中声明一下
INT PE_RLEBlitToSurface( LPCBITMAPRLE lpBitmapRLE, LPCBYTE lpDstSurface, int surfaceWidth, int surfaceHeight );
写好之后,我们就有把单张精灵写入指定内存的能力了
精灵素材一般在两个位置,一是地图精灵,二是战斗精灵
我们先来dump地图精灵
打开 scene.c 文件
头部引入全局变量和控制变量
extern SDL_Color pe_palette[256]; extern int pe_palette_ready; static int bLockRec2 = 0; static int bLockRec3 = 0; static int bLockRec4 = 0;
extern 的两个变量是之前 palette.c 中定义的
向下找到注释
//
// Put all the sprites to be drawn into our array.
//
//
// Players
//
这是地图模式下,玩家渲染的代码
修改如下
for (i = 0; i <= (short)gpGlobals->wMaxPartyMemberIndex + gpGlobals->nFollower; i++) { LPCBITMAPRLE lpBitmap = PAL_SpriteGetFrame(PAL_GetPlayerSprite((BYTE)i), gpGlobals->rgParty[i].wFrame); if (lpBitmap == NULL) { continue; } //BOOKMARK 保存地图模式 玩家精灵 if (pe_palette_ready) { if (bLockRec3) { LPSPRITE curSpr = PAL_GetPlayerSprite((BYTE)i); int imagecount = (curSpr[0] | (curSpr[1] << 8)); for (int k = 0; k < imagecount; k++) { LPCBITMAPRLE curBitmap = PAL_SpriteGetFrame(PAL_GetPlayerSprite((BYTE)i), k); LPBYTE p_p = curBitmap; int w = p_p[0] | (p_p[1] << 8); int h = p_p[2] | (p_p[3] << 8); if (w > 1024 || h > 1024) { continue; } int len = w * h; unsigned char* pe_surface = malloc(len); PE_RLEBlitToSurface(curBitmap, pe_surface, w, h); LPBYTE p_now = pe_surface; LPBYTE pixel = p_now; char peOutFile[256] = {0}; char tmp[256] = { 0 }; char* startStr = "player"; char* cont = "__"; char* ext = ".png"; strcat(peOutFile, startStr); strcat(peOutFile, cont); itoa(i, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, cont); itoa(k, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, ext); //player__i__k.png int bRet = access(peOutFile, 0); //0为存在 if (bRet != 0) { int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int j = 0; j < len; j++) { BYTE cur = pixel[j]; data[j * 4 + 0] = pe_palette[cur].r; data[j * 4 + 1] = pe_palette[cur].g; data[j * 4 + 2] = pe_palette[cur].b; data[j * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(pe_surface); free(data); } } } } } // // Add it to our array // PAL_AddSpriteToDraw(lpBitmap, gpGlobals->rgParty[i].x - PAL_RLEGetWidth(lpBitmap) / 2, gpGlobals->rgParty[i].y + gpGlobals->wLayer + 10, gpGlobals->wLayer + 6); // // Calculate covering tiles on the map // PAL_CalcCoverTiles(&g_rgSpriteToDraw[g_nSpriteToDraw - 1]); }
bLockRec3 下断点开启,就可以得到地图模式下,玩家移动图了
然后找到下面的注释
//
// Event Objects (Monsters/NPCs/others)
//
就可以得到玩家外的角色,比如电脑NPC版的赵灵儿
for (i = gpGlobals->g.rgScene[gpGlobals->wNumScene - 1].wEventObjectIndex; i < gpGlobals->g.rgScene[gpGlobals->wNumScene].wEventObjectIndex; i++) { LPCBITMAPRLE lpFrame; LPCSPRITE lpSprite; LPEVENTOBJECT lpEvtObj = &(gpGlobals->g.lprgEventObject[i]); int iFrame; if (lpEvtObj->sState == kObjStateHidden || lpEvtObj->sVanishTime > 0 || lpEvtObj->sState < 0) { continue; } // // Get the sprite // lpSprite = PAL_GetEventObjectSprite((WORD)i + 1); if (lpSprite == NULL) { continue; } iFrame = lpEvtObj->wCurrentFrameNum; if (lpEvtObj->nSpriteFrames == 3) { // // walking character // if (iFrame == 2) { iFrame = 0; } if (iFrame == 3) { iFrame = 2; } } lpFrame = PAL_SpriteGetFrame(lpSprite, lpEvtObj->wDirection * lpEvtObj->nSpriteFrames + iFrame); if (lpFrame == NULL) { continue; } // // Calculate the coordinate and check if outside the screen // x = (SHORT)lpEvtObj->x - PAL_X(gpGlobals->viewport); x -= PAL_RLEGetWidth(lpFrame) / 2; if (x >= 320 || x < -(int)PAL_RLEGetWidth(lpFrame)) { // // outside the screen; skip it // continue; } y = (SHORT)lpEvtObj->y - PAL_Y(gpGlobals->viewport); y += lpEvtObj->sLayer * 8 + 9; vy = y - PAL_RLEGetHeight(lpFrame) - lpEvtObj->sLayer * 8 + 2; if (vy >= 200 || vy < -(int)PAL_RLEGetHeight(lpFrame)) { // // outside the screen; skip it // continue; } // // Add it into the array // PAL_AddSpriteToDraw(lpFrame, x, y, lpEvtObj->sLayer * 8 + 2); // // Calculate covering map tiles // PAL_CalcCoverTiles(&g_rgSpriteToDraw[g_nSpriteToDraw - 1]); //BOOKMARK 保存地图模式 Monsters/NPCs/others if (pe_palette_ready) { if (bLockRec4) { LPCBITMAPRLE curBitmap = lpFrame; LPBYTE p_p = curBitmap; int w = p_p[0] | (p_p[1] << 8); int h = p_p[2] | (p_p[3] << 8); if (w > 1024 || h > 1024) { continue; } int len = w * h; unsigned char* pe_surface = malloc(len); PE_RLEBlitToSurface(curBitmap, pe_surface, w, h); LPBYTE p_now = pe_surface; LPBYTE pixel = p_now; char peOutFile[256] = { 0 }; char tmp[256] = { 0 }; char* cont = "__"; char* ext = ".png"; itoa(i, peOutFile, 10); strcat(peOutFile, cont); itoa(lpEvtObj->wDirection, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, cont); itoa(lpEvtObj->nSpriteFrames, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, cont); itoa(iFrame, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, ext); //i__wDirection__nSpriteFrames__iFrame.png int bRet = access(peOutFile, 0); //0为存在 if (bRet != 0) { int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int j = 0; j < len; j++) { BYTE cur = pixel[j]; data[j * 4 + 0] = pe_palette[cur].r; data[j * 4 + 1] = pe_palette[cur].g; data[j * 4 + 2] = pe_palette[cur].b; data[j * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(pe_surface); free(data); } } } } }
接下来看看战斗部分 battle.c
头部引入全局变量和控制变量
extern SDL_Color pe_palette[256]; extern int pe_palette_ready; static int bLockRec5 = 0; static int bLockRec6 = 0; static int bLockRec7 = 0;
找到下面的注释,dump敌人战斗精灵
//
// Draw the enemies
//
for (j = g_Battle.wMaxEnemyIndex; j >= 0; j--) { i = enemyDrawSeq[j]; pos = g_Battle.rgEnemy[i].pos; if (g_Battle.rgEnemy[i].rgwStatus[kStatusConfused] > 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusSleep] == 0 && g_Battle.rgEnemy[i].rgwStatus[kStatusParalyzed] == 0) { // // Enemy is confused // pos = PAL_XY(PAL_X(pos) + RandomLong(-1, 1), PAL_Y(pos)); } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame))); if (g_Battle.rgEnemy[i].wObjectID != 0) { if (g_Battle.rgEnemy[i].iColorShift) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgEnemy[i].iColorShift); } else { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); //BOOKMARK 保存战斗模式 敌人 if (pe_palette_ready) { if (bLockRec5) { LPCBITMAPRLE curBitmap = PAL_SpriteGetFrame(g_Battle.rgEnemy[i].lpSprite, g_Battle.rgEnemy[i].wCurrentFrame); LPBYTE p_p = curBitmap; int w = p_p[0] | (p_p[1] << 8); int h = p_p[2] | (p_p[3] << 8); if (w > 1024 || h > 1024) { continue; } int len = w * h; unsigned char* pe_surface = malloc(len); PE_RLEBlitToSurface(curBitmap, pe_surface, w, h); LPBYTE p_now = pe_surface; LPBYTE pixel = p_now; char peOutFile[256] = { 0 }; char tmp[256] = { 0 }; char* cont = "__"; char* ext = ".png"; itoa(i, peOutFile, 10); strcat(peOutFile, cont); itoa(g_Battle.rgEnemy[i].wCurrentFrame, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, ext); //i__wCurrentFrame.png int bRet = access(peOutFile, 0); //0为存在 if (bRet != 0) { int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int k = 0; k < len; k++) { BYTE cur = pixel[k]; data[k * 4 + 0] = pe_palette[cur].r; data[k * 4 + 1] = pe_palette[cur].g; data[k * 4 + 2] = pe_palette[cur].b; data[k * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(pe_surface); free(data); } } } } } } }
找到下面的注释,dump玩家召唤神和玩家,战斗精灵
//
// Draw the summoned god
//
if (g_Battle.lpSummonSprite != NULL) { // // Draw the summoned god // pos = PAL_XY(PAL_X(g_Battle.posSummon) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame)) / 2, PAL_Y(g_Battle.posSummon) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame))); PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame), g_Battle.lpSceneBuf, pos); //BOOKMARK 保存战斗模式 召唤神 if (pe_palette_ready) { if (bLockRec7) { LPCBITMAPRLE curBitmap = PAL_SpriteGetFrame(g_Battle.lpSummonSprite, g_Battle.iSummonFrame); LPBYTE p_p = curBitmap; int w = p_p[0] | (p_p[1] << 8); int h = p_p[2] | (p_p[3] << 8); if (w < 1024 && h < 1024) { int len = w * h; unsigned char* pe_surface = malloc(len); PE_RLEBlitToSurface(curBitmap, pe_surface, w, h); LPBYTE p_now = pe_surface; LPBYTE pixel = p_now; char peOutFile[256] = { 0 }; char tmp[256] = { 0 }; char* startStr = "god"; char* cont = "__"; char* ext = ".png"; strcat(peOutFile, startStr); strcat(peOutFile, cont); itoa(g_Battle.iSummonFrame, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, ext); //god__i__wCurrentFrame.png int bRet = access(peOutFile, 0); //0为存在 if (bRet != 0) { int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int k = 0; k < len; k++) { BYTE cur = pixel[k]; data[k * 4 + 0] = pe_palette[cur].r; data[k * 4 + 1] = pe_palette[cur].g; data[k * 4 + 2] = pe_palette[cur].b; data[k * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(pe_surface); free(data); } } } } } } else { // // Draw the players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { pos = g_Battle.rgPlayer[i].pos; if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // continue; } pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); //BOOKMARK 保存战斗模式 玩家 if (pe_palette_ready) { if (bLockRec6) { LPCBITMAPRLE curBitmap = PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame); LPBYTE p_p = curBitmap; int w = p_p[0] | (p_p[1] << 8); int h = p_p[2] | (p_p[3] << 8); if (w > 1024 || h > 1024) { continue; } int len = w * h; unsigned char* pe_surface = malloc(len); PE_RLEBlitToSurface(curBitmap, pe_surface, w, h); LPBYTE p_now = pe_surface; LPBYTE pixel = p_now; char peOutFile[256] = { 0 }; char tmp[256] = { 0 }; char* startStr = "player"; char* cont = "__"; char* ext = ".png"; strcat(peOutFile, startStr); strcat(peOutFile, cont); itoa(i, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, cont); itoa(g_Battle.rgPlayer[i].wCurrentFrame, tmp, 10); strcat(peOutFile, tmp); strcat(peOutFile, ext); //player__i__wCurrentFrame.png int bRet = access(peOutFile, 0); //0为存在 if (bRet != 0) { int n = 4; unsigned char* data = malloc(w * h * n); if (data != 0) { for (int k = 0; k < len; k++) { BYTE cur = pixel[k]; data[k * 4 + 0] = pe_palette[cur].r; data[k * 4 + 1] = pe_palette[cur].g; data[k * 4 + 2] = pe_palette[cur].b; data[k * 4 + 3] = 255; } stbi_write_png(peOutFile, w, h, n, data, w * n); free(pe_surface); free(data); } } } } } } // // Confused players should be drawn on top of normal players // for (i = gpGlobals->wMaxPartyMemberIndex; i >= 0; i--) { if (gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusConfused] != 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusSleep] == 0 && gpGlobals->rgPlayerStatus[gpGlobals->rgParty[i].wPlayerRole][kStatusParalyzed] == 0 && gpGlobals->g.PlayerRoles.rgwHP[gpGlobals->rgParty[i].wPlayerRole] > 0) { // // Player is confused // int xd = PAL_X(g_Battle.rgPlayer[i].pos), yd = PAL_Y(g_Battle.rgPlayer[i].pos); if(!PAL_IsPlayerDying(gpGlobals->rgParty[i].wPlayerRole)) yd += RandomLong(-1, 1); pos = PAL_XY(xd, yd); pos = PAL_XY(PAL_X(pos) - PAL_RLEGetWidth(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame)) / 2, PAL_Y(pos) - PAL_RLEGetHeight(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame))); if (g_Battle.rgPlayer[i].iColorShift != 0) { PAL_RLEBlitWithColorShift(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos, g_Battle.rgPlayer[i].iColorShift); } else if (g_Battle.iHidingTime == 0) { PAL_RLEBlitToSurface(PAL_SpriteGetFrame(g_Battle.rgPlayer[i].lpSprite, g_Battle.rgPlayer[i].wCurrentFrame), g_Battle.lpSceneBuf, pos); } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步