說點純乾貨吧。我本來還想蓄勢鋪墊的。
人對未知的內容都很恐慌。就比如說,我打算復刻一下仙劍奇俠傳的源碼。也就是純c版本的sdlpal的源碼。我要翻譯成c++,lua+qt的版本。
你說,這麼多文件,凡是帶h的c的,cpp的,都是要處理的。
這個遊戲我玩過,但是到了至於怎麼製造的時候,都是摸石頭過河的感覺。我從game_main函數開始,一路順藤摸瓜,先從菜單著手
原理就是現學現用,很多函數,我不懂,我就改數字,改流程。我在屏幕上面加字。不懂的部分,就暫時使用c語言的原版。說白了就是跳過不懂的部分,去進行其他部分內容。
我原來好大喜功,上來就要搞懂數據結構和演算法,結果現實教育了我。慢慢的我改成了順藤摸瓜。
在主循環裡面有一個start frame函數。
而在start frame函數中,分兩部分函數,一部分是gameupdate,這個是核心部分,我們這些新手,是不能上來就動它的。那麼柿子挑軟的捏,就處理下面的那些各種窗口操作。
因為這些東西所見即所得,所有源碼雖然看不懂,但是我們可以通過修改坐標,就知道,這段代碼寫的是什麼地方的圖。
今天主要講的就是鬥爭經驗和方法。
目標就是先翻譯成lua的腳本,這樣的話,修改起來就容易了,光是lua+sdl,是不行的,缺少編輯器。所以要把sdl換成qt,借qt的東風。最終做成仙劍數據可視化編輯器。
流程由寫死的代碼,更換成行為樹。現在的行為樹都有圖形化工具。
今天剩下的時間,我要做
對就是 從物品到裝備選項,
再到裝備整個過程。
在play。c中,調用部分其實很少
這個翻譯起來很簡單,下面的兩個menu函數,可都是大傢伙。待我下一篇慢慢到來。
翻譯過來了。PAL_EquipItemMenuV2(d,select_opt) 真的好長
local functionName=PAL_EquipItemMenuV2 class_t[functionName]=function(self,d,small_env) local t =small_env or {} local wItem=t.wItem
local palcommon=d.palcommon local util=d.util local bit=d.bit ------------------------- local fpBALL=d.fpBALL local fpFBP=d.fpFBP local g_InputState=d.g_InputState ----------------------------- local gpScreen=d.gpScreen local gpGlobals=d.gpGlobals local gameData=gpGlobals:getGameData() local playerRoles=gameData:getPlayerRoles() local rgParty =gpGlobals:getParty() gpGlobals.wLastUnequippedItem=wItem -------------------------------- local bg_w,bg_h=d.bg_w,d.bg_h local size=bg_w*bg_h bufBackground=ByteVector(size) palcommon:MKFDecompressChunk(bufBackground,size, EQUIPMENU_BACKGROUND_FBPNUM,fpFBP)
local bufImage=ByteVector(2048) -------------------------------- local iCurrentPlayer=0 local bSelectedColor = MENUITEM_COLOR_SELECTED_FIRST local dwColorChangeTime = lua_GetTicks() + (600 / MENUITEM_COLOR_SELECTED_TOTALNUM) ------------------------------------------------------------------------------------ local dwKeyPress ------------------------- local dst,item,obj local w,item_id,text,curr_flag local bColor
while true do wItem=gpGlobals.wLastUnequippedItem item =gameData:getObject(wItem):getItem()
palcommon:FBPBlitToSurface(bufBackground,gpScreen) dst=palcommon:MKFReadChunk(bufImage, 2048,item.wBitmap,fpBALL) if dst>0 then palcommon:RLEBlitToSurface(bufImage,gpScreen,palcommon:pal_XY(16,16)) end
--VIDEO_UpdateScreen(nil) --print(stop) --util:delay(1000000000)
obj=rgParty:at(iCurrentPlayer) w=obj.wPlayerRole for i=0,MAX_PLAYER_EQUIPMENTS do item_id=playerRoles:getEquipmentItem(i,w) if item_id ==0 then else text=PAL_GetWord(item_id) PAL_DrawText(text,palcommon:pal_XY(130,11+i*22),MENUITEM_COLOR, TRUE, FALSE) end end
---------------------------- PAL_DrawNumber(PAL_GetPlayerAttackStrength(w), 4, palcommon:pal_XY(260, 14), kNumColorCyan, kNumAlignRight) PAL_DrawNumber(PAL_GetPlayerMagicStrength(w), 4, palcommon:pal_XY(260, 36), kNumColorCyan, kNumAlignRight) PAL_DrawNumber(PAL_GetPlayerDefense(w), 4, palcommon:pal_XY(260, 58), kNumColorCyan, kNumAlignRight) PAL_DrawNumber(PAL_GetPlayerDexterity(w), 4, palcommon:pal_XY(260, 80), kNumColorCyan, kNumAlignRight) PAL_DrawNumber(PAL_GetPlayerFleeRate(w), 4, palcommon:pal_XY(260, 102), kNumColorCyan, kNumAlignRight) ----------------------------------- PAL_CreateBox(palcommon:pal_XY(2, 95), gpGlobals.wMaxPartyMemberIndex, 2, 0, FALSE)
----------------------------- for i=0,gpGlobals.wMaxPartyMemberIndex do
obj=rgParty:at(i) w=obj.wPlayerRole curr_flag =bit.lshift(kItemFlagEquipableByPlayerRole_First,w)
if iCurrentPlayer==i then --curr select if bit.band(item.wFlags,curr_flag ) ==0 then bColor=MENUITEM_COLOR_SELECTED_INACTIVE else bColor=bSelectedColor end else if bit.band(item.wFlags,curr_flag ) ==0 then bColor=MENUITEM_COLOR_INACTIVE else bColor=MENUITEM_COLOR end
end PAL_DrawText(PAL_GetWord(playerRoles:get_rgwName(w)), palcommon:pal_XY(15, 108 + 18 * i), bColor, TRUE, FALSE); end
-- draw select equip item name and count if wItem==0 then else PAL_DrawText(PAL_GetWord(wItem), palcommon:pal_XY(5, 70), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE); PAL_DrawNumber(PAL_GetItemAmount(wItem), 2, palcommon:pal_XY(65, 73), kNumColorCyan, kNumAlignRight); end --update VIDEO_UpdateScreen(nil) --accept input PAL_ClearKeyState() util:delay(1) local item,obj,curr_flag print(run in PAL_EquipItemMenuV20001) while true do --print(run in PAL_EquipItemMenuV20002)
PAL_ProcessEvent() --print(run in PAL_EquipItemMenuV200021,dwColorChangeTime) --change the highlight color if lua_GetTicks()>dwColorChangeTime then if bSelectedColor+1 >= (MENUITEM_COLOR_SELECTED_FIRST + MENUITEM_COLOR_SELECTED_TOTALNUM) then bSelectedColor=MENUITEM_COLOR_SELECTED_FIRST else bSelectedColor=bSelectedColor+1 end dwColorChangeTime=lua_GetTicks()+ (600 / MENUITEM_COLOR_SELECTED_TOTALNUM) --Redraw the selected item if needed. w=rgParty:at(iCurrentPlayer).wPlayerRole item=gameData:getObject(wItem):getItem() curr_flag=bit.lshift(kItemFlagEquipableByPlayerRole_First,w) if bit.band(item.wFlags,curr_flag ) ==0 then else PAL_DrawText(PAL_GetWord(playerRoles:get_rgwName(w)), palcommon:pal_XY(15, 108 + 18 * iCurrentPlayer), bSelectedColor, TRUE, TRUE)
end end --print(run in PAL_EquipItemMenuV200022) if g_InputState.dwKeyPress==0 then else print(run in PAL_EquipItemMenuV200024) break end -- print(run in PAL_EquipItemMenuV200023) util:delay(1) end print(run in PAL_EquipItemMenuV20007) --print(stop) --util:delay(1000000000) if wItem==0 then return end print(run in PAL_EquipItemMenuV20008) dwKeyPress=g_InputState.dwKeyPress if bit.band(dwKeyPress,bit.bor(kKeyUp ,kKeyLeft ) )~=0 then iCurrentPlayer=iCurrentPlayer-1 if iCurrentPlayer<0 then iCurrentPlayer=0 end print(run in PAL_EquipItemMenuV20009) elseif bit.band(dwKeyPress,bit.bor(kKeyDown ,kKeyRight ) )~=0 then iCurrentPlayer=iCurrentPlayer+1 if iCurrentPlayer> gpGlobals.wMaxPartyMemberIndex then iCurrentPlayer=gpGlobals.wMaxPartyMemberIndex end print(run in PAL_EquipItemMenuV200010)
elseif bit.band(dwKeyPress,kKeyMenu )~=0 then print(run in PAL_EquipItemMenuV200011) return elseif bit.band(dwKeyPress,kKeySearch )~=0 then print(run in PAL_EquipItemMenuV200012) obj=rgParty:at(iCurrentPlayer) item=gameData:getObject(wItem):getItem() w=obj.wPlayerRole curr_flag=bit.lshift(kItemFlagEquipableByPlayerRole_First,w) print(run in PAL_EquipItemMenuV200013) if bit.band(item.wFlags,curr_flag ) ==0 then else print(run in PAL_EquipItemMenuV200014) item.wScriptOnEquip=PAL_RunTriggerScript( item.wScriptOnEquip, obj.wPlayerRole )
end
畫背景的代碼
上圖,裝備是這麼畫的
目標裝備人物,高亮部分代碼
這段代碼就翻譯完畢了。
預告,下一篇翻譯的函數。
更新 PAL_PlayerStatusV2 函數部分的翻譯。
local functionName=PAL_PlayerStatusV2 class_t[functionName]=function(self,d,small_env) local t =small_env or {} local wItem=t.wItem
local palcommon=d.palcommon local util=d.util local bit=d.bit ------------------------- local fpBALL=d.fpBALL local fpFBP=d.fpFBP local fpRGM=d.fpRGM local g_InputState=d.g_InputState ----------------------------- local gpScreen=d.gpScreen local gpSpriteUI=d.gpSpriteUI local gpGlobals=d.gpGlobals local gameData=gpGlobals:getGameData() local playerRoles=gameData:getPlayerRoles() local rgParty =gpGlobals:getParty() local exp =gpGlobals:getExp()
-------------------------------------------------------- local rgEquipPos={ {190, 0}, {248, 40}, {252, 102}, {202, 134}, {142, 142}, {82, 126} }
local bg_w,bg_h=d.bg_w,d.bg_h local size=bg_w*bg_h bufBackground=ByteVector(size) --STATUS_BACKGROUND_FBPNUM palcommon:MKFDecompressChunk(bufBackground,size, EQUIPMENU_BACKGROUND_FBPNUM,fpFBP)
local bufImage=ByteVector(16384) --role image -------------------------------- local wMaxPartyMemberIndex=gpGlobals.wMaxPartyMemberIndex local iCurrent = 0
local obj,item,value,level,pos local curr_exp,ok local w while (iCurrent>=0 and iCurrent<= wMaxPartyMemberIndex ) do obj=rgParty:at(iCurrent) iPlayerRole =obj.wPlayerRole --draw bg
palcommon:FBPBlitToSurface(bufBackground,gpScreen) --exp,level,hp,mp ... PAL_DrawText(PAL_GetWord(STATUS_LABEL_EXP),palcommon:pal_XY(6, 6), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_LEVEL),palcommon:pal_XY(6, 32), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_HP),palcommon:pal_XY(6, 54), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_MP),palcommon:pal_XY(6, 76), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_ATTACKPOWER),palcommon:pal_XY(6, 98), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_MAGICPOWER),palcommon:pal_XY(6, 118), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_RESISTANCE),palcommon:pal_XY(6, 138), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_DEXTERITY),palcommon:pal_XY(6, 158), MENUITEM_COLOR, TRUE, FALSE) PAL_DrawText(PAL_GetWord(STATUS_LABEL_FLEERATE),palcommon:pal_XY(6, 178), MENUITEM_COLOR, TRUE, FALSE) -- player name PAL_DrawText(PAL_GetWord(playerRoles:get_rgwName(iPlayerRole)), palcommon:pal_XY(110, 8), MENUITEM_COLOR_CONFIRMED, TRUE, FALSE) ---------------------------------- curr_exp =exp:getExpItem("rgPrimaryExp",iPlayerRole) PAL_DrawNumber(curr_exp.wExp, 5,palcommon:pal_XY(58, 6), kNumColorYellow, kNumAlignRight); level=playerRoles:get_rgwLevel(iPlayerRole) value =gameData:getLevelUpExp(level) PAL_DrawNumber(value ,5, palcommon:pal_XY(58, 15), kNumColorCyan, kNumAlignRight); PAL_DrawNumber(level, 2,palcommon:pal_XY(54, 35), kNumColorYellow, kNumAlignRight);
palcommon:pal_RLEBlitToSurface( palcommon:pal_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen, palcommon:pal_XY(65,58) ) palcommon:pal_RLEBlitToSurface( palcommon:pal_SpriteGetFrame(gpSpriteUI, SPRITENUM_SLASH), gpScreen,palcommon:pal_XY(65, 80))
PAL_DrawNumber(playerRoles:get_rgwHP(iPlayerRole), 4, palcommon:pal_XY(42, 56), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(playerRoles:get_rgwMaxHP(iPlayerRole), 4, palcommon:pal_XY(63, 61), kNumColorBlue, kNumAlignRight); PAL_DrawNumber(playerRoles:get_rgwMP(iPlayerRole), 4, palcommon:pal_XY(42, 78), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(playerRoles:get_rgwMaxMP(iPlayerRole), 4, palcommon:pal_XY(63, 83), kNumColorBlue, kNumAlignRight);
PAL_DrawNumber(PAL_GetPlayerAttackStrength(iPlayerRole), 4, palcommon:pal_XY(42, 102), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerMagicStrength(iPlayerRole), 4, palcommon:pal_XY(42, 122), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDefense(iPlayerRole), 4, palcommon:pal_XY(42, 142), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerDexterity(iPlayerRole), 4, palcommon:pal_XY(42, 162), kNumColorYellow, kNumAlignRight); PAL_DrawNumber(PAL_GetPlayerFleeRate(iPlayerRole), 4, palcommon:pal_XY(42, 182), kNumColorYellow, kNumAlignRight);
for i=0,MAX_PLAYER_EQUIPMENTS-1 do w=playerRoles:getEquipmentItem(i,iPlayerRole) if w==0 then else item=gameData:getObject(w):getItem() ok=palcommon:MKFReadChunk(bufImage,16384,item.wBitmap,fpBALL) if ok>0 then pos =rgEquipPos[i+1] --draw image palcommon:RLEBlitToSurface(bufImage,gpScreen,palcommon:pal_XY(pos[1],pos[2])) --draw text
PAL_DrawText( PAL_GetWord(w), palcommon:pal_XY(pos[1]+5,pos[2]+38),
STATUS_COLOR_EQUIPMENT,TRUE,FALSE )
end end end ok =palcommon:MKFReadChunk(bufImage,16384,playerRoles:get_rgwAvatar(iPlayerRole),fpRGM) if ok > 0 then palcommon:RLEBlitToSurface(bufImage, gpScreen, palcommon:pal_XY(110, 30)) end ---draw all poisons
y=58
for i=0,MAX_POISONS-1 do w=gpGlobals:getPoisonStatusItem(i,iCurrent).wPoisonID item=gameData:getObject(w):getPoison() if w~=0 and item.wPoisonLevel<=3 then PAL_DrawText(PAL_GetWord(w),palcommon:pal_XY(185, y), item.wColor + 10, TRUE, FALSE) ------- y =y+18 end end
VIDEO_UpdateScreen(nil) PAL_ClearKeyState()
while true do util:delay(1) --PAL_ProcessEvent() ------------------------------------- dwKeyPress=g_InputState.dwKeyPress
if bit.band(dwKeyPress,kKeyMenu)~=0 then iCurrent=-1 break elseif bit.band(dwKeyPress,bit.bor( kKeyLeft,kKeyUp) ) ~=0 then iCurrent=iCurrent-1 break elseif bit.band(dwKeyPress,bit.bor(kKeyRight,kKeyDown,kKeySearch) )~=0 then iCurrent=iCurrent+1 break end end
--VIDEO_UpdateScreen(nil)
更新PAL_SearchV2部分,這下 菜單操作的部分基本完成了。
local functionName=PAL_SearchV2 class_t[functionName]=function(self,d,small_env) local item_menu_helper=d.item_menu_helper local palcommon=d.palcommon local menu_helper=d.menu_helper local bit=d.bit local util=d.util local gpGlobals=d.gpGlobals local gameData=gpGlobals:getGameData() local rgParty=gpGlobals:getParty() ------------------------------ local rgPos={} local x, y, xOffset, yOffset local viewport,partyoffset =gpGlobals.viewport,gpGlobals.partyoffset x=palcommon:get_X(viewport)+palcommon:get_X(partyoffset) y=palcommon:get_Y(viewport)+palcommon:get_Y(partyoffset)
print(string.format("%x,%x,%x,%x",x,y,viewport,partyoffset)) local wPartyDirection=gpGlobals.wPartyDirection --logic error --if bit.bor(wPartyDirection,kDirNorth,kDirEast) FALSE then if wPartyDirection==kDirNorth or wPartyDirection==kDirEast then xOffset=16 else xOffset=-16 end --logic error --if bit.bor(wPartyDirection,kDirEast,kDirSouth)~=FALSE then if wPartyDirection==kDirEast or wPartyDirection==kDirSouth then yOffset=8 else yOffset=-8 end
rgPos[0] =palcommon:pal_XY(x,y) --get 4 player pos in the party for i=0,3 do rgPos[i*3+1]=palcommon:pal_XY(x + xOffset, y + yOffset) rgPos[i*3+2]=palcommon:pal_XY(x, y + yOffset * 2) rgPos[i*3+3]=palcommon:pal_XY(x + xOffset, y)
x =x+ xOffset y =y+ yOffset end
------------------- local pos local dx, dy, dh local ex, ey, eh local p -------------------- local wMaxPartyMemberIndex=gpGlobals.wMaxPartyMemberIndex local wNumScene,wEventObjectIndex,curr_scene,next_scene print(run PAL_SearchV2 004) for i=0,12 do pos =rgPos[i] dx =math.floor( palcommon:get_X(pos)/32 ) dy =math.floor(palcommon:get_Y(pos)/16 ) if palcommon:get_X(pos)%32 ==0 then dh=0 else dh=1 end
--loop through all event objects----------------------------- wNumScene=gpGlobals.wNumScene curr_scene=gameData:getScene(wNumScene-1) next_scene=gameData:getScene(wNumScene) --wEventObjectIndex=curr_scene.wEventObjectIndex
for k=curr_scene.wEventObjectIndex, next_scene.wEventObjectIndex-1 do --------------------------------------- p=gameData:getLprgEventObject(k) ex=math.floor(p.x/32) ey=math.floor(p.y/16) if p.x%32 ~=0 then eh=1 else eh=0 end --[[ print(i,k, (p.sState<=0), (math.abs(dx - ex)<=0.5 ), (math.abs(dy - ey)<=0.5) , dx,ex,dy,ey ) ]] if (p.sState<=0) or (p.wTriggerMode >= kTriggerTouchNear) or (p.wTriggerMode * 6 - 4 < i ) or (dx ~= ex) or (dy ~= ey) or (dh ~= eh) then ---------------------------------------------- else print(run PAL_SearchV2 008) if p.nSpriteFrames * 4 > p.wCurrentFrameNum then p.wCurrentFrameNum=0 p.wDirection =(gpGlobals.wPartyDirection+2)%4 for l=0,wMaxPartyMemberIndex do --All party members should face the event object rgParty:at(l).wFrame =wPartyDirection*3
end PAL_MakeScene() VIDEO_UpdateScreen(nil) end --Execute the script print(p.wTriggerScript=,p.wTriggerScript) p.wTriggerScript = PAL_RunTriggerScript(p.wTriggerScript, k + 1)
--Clear inputs and delay for a short time util:delay(50) PAL_ClearKeyState() print(run PAL_SearchV2 stop) return end
end end for i=0,12 do pos=rgPos[i] print(string.format("i=%d 0x%8x %d %d",i,rgPos[i],bit.band(pos,0xFFFF), bit.band(bit.rshift(pos,16),0xFFFF ) ) ) end
預告。
這3個函數翻譯完了,主幹部分基本完事了,就需要具體細化了,
這個研究課題能不能進行下去,全靠你們了,希望多給我點口頭鼓勵啊,