接上回 https://zhuanlan.zhihu.com/p/61417922
這回可很好的提高了生產力。現在使用正則表達式。和多行操作
將指令腳本 對應的case 轉換成了函數。
local t={} t[0x000b]=walk_one_step t[0x000c]=walk_one_step t[0x000d]=walk_one_step t[0x000e]=walk_one_step t[0x000f]=set_the_direction t[0x0010]=walk_straight_to_pos t[0x0011]=walk_straight_to_pos_lower_speed t[0x0012]=event_object_set_offset_pos t[0x0013]=event_object_set_pos t[0x0014]=event_object_set_gesture t[0x0015]=player_set_direction_and_gesture t[0x0016]=event_object_set_direction_and_gesture t[0x0017]=player_set_extra_attribute --pointer to equipment item t[0x0018]=equip_selected_item t[0x0019]=player_compute_attribute t[0x001a]=player_set_stat t[0x001b]=player_modify_hp t[0x001c]=player_modify_mp t[0x001d]=player_modify_hp_and_mp t[0x001e]=globals_set_cash_amount t[0x001f]=add_item_to_inventory t[0x0020]=remove_item_from_inventory --d.i =9999
t[0x0021]=inflict_damage_to_one_enemy -- battle serire need to bind t[0x0022]=revive_player --need to bind new function t[0x0023]=player_remove_equipment t[0x0024]=evtobj_set_autoscript_entry_addr t[0x0025]=evtobj_set_trigger_script_entry_addr t[0x0026]=menu_buy_item_show t[0x0027]=menu_sell_item_show t[0x0028]=enemy_apply_poison --g_Battle (rgObject,getPoison )(get_rgEnemy,getPoisonItem ) t[0x0029]=player_apply_poison --must look PAL_RunTriggerScript below
t[0x002a]=enemy_cure_poison --Cure poison by object ID for enemy t[0x002b]=player_cure_poison_by_id t[0x002c]=player_cure_poison_by_level t[0x002d]=player_set_status t[0x002e]=enemy_set_status t[0x002f]=player_remove_status
t[0x0030]=palyer_increase_stat_by_percent --temporarily t[0x0031]=player_change_battle_sprite --t[0x0032]= t[0x0033]=enemy_collect_items t[0x0034]=enemy_transform_collected_into_items t[0x0035]=screen_shake t[0x0036]=RNG_set_current_playering_animation t[0x0037]=RNG_play_animation t[0x0038]=party_teleport_out_of_scene t[0x0039]=enemy_drain_HP t[0x003a]=player_flee_frome_battle --t[0x003b]= --t[0x003c]= --t[0x003d]= --t[0x003e]= t[0x003f]=evtobj_rided_to_pos_low_speed --at low speed t[0x0040]=evtobj_set_trigger_method t[0x0041]=script_marked_as_faild t[0x0042]=player_simulate_a_magic t[0x0043]=music_set_background t[0x0044]=evtobj_rided_to_pos_normal_speed t[0x0045]=music_set_battle t[0x0046]=party_set_pos_on_map t[0x0047]=sound_play_effect --[0x0048]= t[0x0049]=evtobj_set_state t[0x004a]=battle_set_current_field t[0x004b]=evtobj_set_nullify_short_while t[0x004c]=monster_chase_player t[0x004d]=sys_wait_for_any_key t[0x004e]=sys_load_last_saved_game t[0x004f]=sys_fade_screen_to_red_color --game over
t[0x0050]=screen_fade_out t[0x0051]=screen_fade_in t[0x0052]=evtobj_set_hide_for_a_while t[0x0053]=palette_use_white_day t[0x0054]=palette_use_night t[0x0055]=player_add_magic t[0x0056]=player_remove_magic t[0x0057]=magic_set_base_damage --according to MP value t[0x0058]=entry_jump_if_less_than_item_number --inventory t[0x0059]=scene_change_to_specified t[0x005a]=player_halve_HP t[0x005b]=enemy_halve_HP t[0x005c]=battle_hide_a_while t[0x005d]=entry_jump_if_player_no_have_specified_poison t[0x005e]=entry_jump_if_enemy_no_have_specified_poison t[0x005f]=player_killed_immediately
t[0x0060]=enemy_Dead_immediate t[0x0061]=entry_jump_if_player_no_poisoned t[0x0062]=enemy_pause_chasing_a_while t[0x0063]=enemy_speed_up_chasing_a_while t[0x0064]=entry_jump_if_enemy_HP_more_than_percentage t[0x0065]=player_set_sprite t[0x0066]=player_throw_weapon_to_enemy t[0x0067]=enemy_use_magic t[0x0068]=entry_jump_if_is_enemy_turn t[0x0069]=enemy_escape_in_battle t[0x006a]=player_steal_from_enemy t[0x006b]=enemy_blow_away t[0x006c]=NPC_walk_in_one_step t[0x006d]=scene_set_entry_and_teleport_script t[0x006e]=player_move_to_pos_in_one_step t[0x006f]=evtobj_sync_state_with_other
t[0x0070]=party_walk_to_pos t[0x0071]=screen_wave --t[0x0072]= t[0x0073]=screen_fade_to_scene t[0x0074]=entry_jump_if_all_players_no_full_HP t[0x0075]=party_set_player t[0x0076]=FBP_show_picture t[0x0077]=music_stop_current_playing t[0x0078]=no_happend --fix me t[0x0079]=entry_jump_if_player_in_party t[0x007a]=party_walk_to_pos_higher_speed t[0x007b]=party_walk_to_pos_highest_speed t[0x007c]=NPC_walk_straight_to_pos t[0x007d]=evtobj_move t[0x007e]=evtobj_set_layer t[0x007f]=viewport_move
t[0x0080]=palette_toggle_day_or_night t[0x0081]=entry_jump_if_player_not_facing_evtobj t[0x0082]=NPC_walk_straight_to_pos_high_speed t[0x0083]=entry_jump_if_evtobj_not_in_specified_zone_of_curr_evtobj t[0x0084]=player_place_item_to_scene --item like a event object --found Z item t[0x0085]=sys_delay_a_period t[0x0086]=entry_jump_if_item_is_not_equipped t[0x0087]=NPC_Animate_the_evtobj t[0x0088]=magic_set_base_damage_look_at_amount_of_money t[0x0089]=battle_set_result t[0x008a]=battle_set_auto_next t[0x008b]=palette_change_current t[0x008c]=color_fade_from_or_to t[0x008d]=player_increase_level --t[0x008e]= t[0x008f]=cash_halve_amount
t[0x0090]=object_set_script t[0x0091]=entry_jump_if_enemy_not_alone t[0x0092]=player_show_magic_casting_animation_in_battle t[0x0093]=screen_fade_and_update_screen_in_process t[0x0094]=entry_jump_if_evtobj_state_is_specified t[0x0095]=entry_jump_if_scene_is_specified t[0x0096]=sys_show_ending_animation t[0x0097]=evtobj_rided_to_pos_higher_speed t[0x0098]=party_set_follower t[0x0099]=map_change_for_scene t[0x009a]=evtobj_set_state_many t[0x009b]=scene_fade_to_current t[0x009c]=enemy_duplicate_itself -- copy itself to another just create new self --t[0x009d]= t[0x009e]=enemy_summons_another_monster -- Z all human t[0x009f]=enemy_transforms_into_sth_else --wan thing changed
t[0x00a0]=sys_quit_game t[0x00a1]=party_set_pos_to_same_as_first_one -- study_first t[0x00a2]=entry_jump_to_one_in_following_instructions_randomly -- jump to t[0x00a3]=music_play_CD t[0x00a4]=FBP_scroll_to_screen t[0x00a5]=FBP_show_picture_with_sprite_effects t[0x00a6]=screen_backup
local dst =_G[fullNameOnClass] if dst then dst[dst_name]=t end return t
呵呵,函數源碼片段
很顯然,我們光看 這些數字0x00xx 根本不知道,調用了什麼函數。
所以說,用表做一個映射,直接通過正則表達式的方法來轉換一下。
就拿到了。
t[0x000b]={func=walk_one_step,name="walk_one_step" } t[0x000c]={func=walk_one_step,name="walk_one_step" } t[0x000d]={func=walk_one_step,name="walk_one_step" } t[0x000e]={func=walk_one_step,name="walk_one_step" } t[0x000f]={func=set_the_direction,name="set_the_direction" } t[0x0010]={func=walk_straight_to_pos,name="walk_straight_to_pos" } t[0x0011]={func=walk_straight_to_pos_lower_speed,name="walk_straight_to_pos_lower_speed" } t[0x0012]={func=event_object_set_offset_pos,name="event_object_set_offset_pos" } t[0x0013]={func=event_object_set_pos,name="event_object_set_pos" } t[0x0014]={func=event_object_set_gesture,name="event_object_set_gesture" } t[0x0015]={func=player_set_direction_and_gesture,name="player_set_direction_and_gesture" } t[0x0016]={func=event_object_set_direction_and_gesture,name="event_object_set_direction_and_gesture" } t[0x0017]={func=player_set_extra_attribute,name="player_set_extra_attribute" } --pointer to equipment item t[0x0018]={func=equip_selected_item,name="equip_selected_item" } t[0x0019]={func=player_compute_attribute,name="player_compute_attribute" } t[0x001a]={func=player_set_stat,name="player_set_stat" } t[0x001b]={func=player_modify_hp,name="player_modify_hp" } t[0x001c]={func=player_modify_mp,name="player_modify_mp" } t[0x001d]={func=player_modify_hp_and_mp,name="player_modify_hp_and_mp" } t[0x001e]={func=globals_set_cash_amount,name="globals_set_cash_amount" } t[0x001f]={func=add_item_to_inventory,name="add_item_to_inventory" } t[0x0020]={func=remove_item_from_inventory,name="remove_item_from_inventory" } --d.i =9999
t[0x0021]={func=inflict_damage_to_one_enemy,name="inflict_damage_to_one_enemy" } -- battle serire need to bind t[0x0022]={func=revive_player,name="revive_player" } --need to bind new function t[0x0023]={func=player_remove_equipment,name="player_remove_equipment" } t[0x0024]={func=evtobj_set_autoscript_entry_addr,name="evtobj_set_autoscript_entry_addr" } t[0x0025]={func=evtobj_set_trigger_script_entry_addr,name="evtobj_set_trigger_script_entry_addr" } t[0x0026]={func=menu_buy_item_show,name="menu_buy_item_show" } t[0x0027]={func=menu_sell_item_show,name="menu_sell_item_show" } t[0x0028]={func=enemy_apply_poison,name="enemy_apply_poison" } --g_Battle (rgObject,getPoison )(get_rgEnemy,getPoisonItem ) t[0x0029]={func=player_apply_poison,name="player_apply_poison" } --must look PAL_RunTriggerScript below
t[0x002a]={func=enemy_cure_poison,name="enemy_cure_poison" } --Cure poison by object ID for enemy t[0x002b]={func=player_cure_poison_by_id,name="player_cure_poison_by_id" } t[0x002c]={func=player_cure_poison_by_level,name="player_cure_poison_by_level" } t[0x002d]={func=player_set_status,name="player_set_status" } t[0x002e]={func=enemy_set_status,name="enemy_set_status" } t[0x002f]={func=player_remove_status,name="player_remove_status" }
t[0x0030]={func=palyer_increase_stat_by_percent,name="palyer_increase_stat_by_percent" } --temporarily t[0x0031]={func=player_change_battle_sprite,name="player_change_battle_sprite" } --t[0x0032]= t[0x0033]={func=enemy_collect_items,name="enemy_collect_items" } t[0x0034]={func=enemy_transform_collected_into_items,name="enemy_transform_collected_into_items" } t[0x0035]={func=screen_shake,name="screen_shake" } t[0x0036]={func=RNG_set_current_playering_animation,name="RNG_set_current_playering_animation" } t[0x0037]={func=RNG_play_animation,name="RNG_play_animation" } t[0x0038]={func=party_teleport_out_of_scene,name="party_teleport_out_of_scene" } t[0x0039]={func=enemy_drain_HP,name="enemy_drain_HP" } t[0x003a]={func=player_flee_frome_battle,name="player_flee_frome_battle" } --t[0x003b]= --t[0x003c]= --t[0x003d]= --t[0x003e]= t[0x003f]={func=evtobj_rided_to_pos_low_speed,name="evtobj_rided_to_pos_low_speed" } --at low speed t[0x0040]={func=evtobj_set_trigger_method,name="evtobj_set_trigger_method" } t[0x0041]={func=script_marked_as_faild,name="script_marked_as_faild" } t[0x0042]={func=player_simulate_a_magic,name="player_simulate_a_magic" } t[0x0043]={func=music_set_background,name="music_set_background" } t[0x0044]={func=evtobj_rided_to_pos_normal_speed,name="evtobj_rided_to_pos_normal_speed" } t[0x0045]={func=music_set_battle,name="music_set_battle" } t[0x0046]={func=party_set_pos_on_map,name="party_set_pos_on_map" } t[0x0047]={func=sound_play_effect,name="sound_play_effect" } --[0x0048]= t[0x0049]={func=evtobj_set_state,name="evtobj_set_state" } t[0x004a]={func=battle_set_current_field,name="battle_set_current_field" } t[0x004b]={func=evtobj_set_nullify_short_while,name="evtobj_set_nullify_short_while" } t[0x004c]={func=monster_chase_player,name="monster_chase_player" } t[0x004d]={func=sys_wait_for_any_key,name="sys_wait_for_any_key" } t[0x004e]={func=sys_load_last_saved_game,name="sys_load_last_saved_game" } t[0x004f]={func=sys_fade_screen_to_red_color,name="sys_fade_screen_to_red_color" } --game over
t[0x0050]={func=screen_fade_out,name="screen_fade_out" } t[0x0051]={func=screen_fade_in,name="screen_fade_in" } t[0x0052]={func=evtobj_set_hide_for_a_while,name="evtobj_set_hide_for_a_while" } t[0x0053]={func=palette_use_white_day,name="palette_use_white_day" } t[0x0054]={func=palette_use_night,name="palette_use_night" } t[0x0055]={func=player_add_magic,name="player_add_magic" } t[0x0056]={func=player_remove_magic,name="player_remove_magic" } t[0x0057]={func=magic_set_base_damage,name="magic_set_base_damage" } --according to MP value t[0x0058]={func=entry_jump_if_less_than_item_number,name="entry_jump_if_less_than_item_number" } --inventory t[0x0059]={func=scene_change_to_specified,name="scene_change_to_specified" } t[0x005a]={func=player_halve_HP,name="player_halve_HP" } t[0x005b]={func=enemy_halve_HP,name="enemy_halve_HP" } t[0x005c]={func=battle_hide_a_while,name="battle_hide_a_while" } t[0x005d]={func=entry_jump_if_player_no_have_specified_poison,name="entry_jump_if_player_no_have_specified_poison" } t[0x005e]={func=entry_jump_if_enemy_no_have_specified_poison,name="entry_jump_if_enemy_no_have_specified_poison" } t[0x005f]={func=player_killed_immediately,name="player_killed_immediately" }
t[0x0060]={func=enemy_Dead_immediate,name="enemy_Dead_immediate" } t[0x0061]={func=entry_jump_if_player_no_poisoned,name="entry_jump_if_player_no_poisoned" } t[0x0062]={func=enemy_pause_chasing_a_while,name="enemy_pause_chasing_a_while" } t[0x0063]={func=enemy_speed_up_chasing_a_while,name="enemy_speed_up_chasing_a_while" } t[0x0064]={func=entry_jump_if_enemy_HP_more_than_percentage,name="entry_jump_if_enemy_HP_more_than_percentage" } t[0x0065]={func=player_set_sprite,name="player_set_sprite" } t[0x0066]={func=player_throw_weapon_to_enemy,name="player_throw_weapon_to_enemy" } t[0x0067]={func=enemy_use_magic,name="enemy_use_magic" } t[0x0068]={func=entry_jump_if_is_enemy_turn,name="entry_jump_if_is_enemy_turn" } t[0x0069]={func=enemy_escape_in_battle,name="enemy_escape_in_battle" } t[0x006a]={func=player_steal_from_enemy,name="player_steal_from_enemy" } t[0x006b]={func=enemy_blow_away,name="enemy_blow_away" } t[0x006c]={func=NPC_walk_in_one_step,name="NPC_walk_in_one_step" } t[0x006d]={func=scene_set_entry_and_teleport_script,name="scene_set_entry_and_teleport_script" } t[0x006e]={func=player_move_to_pos_in_one_step,name="player_move_to_pos_in_one_step" } t[0x006f]={func=evtobj_sync_state_with_other,name="evtobj_sync_state_with_other" }
t[0x0070]={func=party_walk_to_pos,name="party_walk_to_pos" } t[0x0071]={func=screen_wave,name="screen_wave" } --t[0x0072]= t[0x0073]={func=screen_fade_to_scene,name="screen_fade_to_scene" } t[0x0074]={func=entry_jump_if_all_players_no_full_HP,name="entry_jump_if_all_players_no_full_HP" } t[0x0075]={func=party_set_player,name="party_set_player" } t[0x0076]={func=FBP_show_picture,name="FBP_show_picture" } t[0x0077]={func=music_stop_current_playing,name="music_stop_current_playing" } t[0x0078]={func=no_happend,name="no_happend" } --fix me t[0x0079]={func=entry_jump_if_player_in_party,name="entry_jump_if_player_in_party" } t[0x007a]={func=party_walk_to_pos_higher_speed,name="party_walk_to_pos_higher_speed" } t[0x007b]={func=party_walk_to_pos_highest_speed,name="party_walk_to_pos_highest_speed" } t[0x007c]={func=NPC_walk_straight_to_pos,name="NPC_walk_straight_to_pos" } t[0x007d]={func=evtobj_move,name="evtobj_move" } t[0x007e]={func=evtobj_set_layer,name="evtobj_set_layer" } t[0x007f]={func=viewport_move,name="viewport_move" }
t[0x0080]={func=palette_toggle_day_or_night,name="palette_toggle_day_or_night" } t[0x0081]={func=entry_jump_if_player_not_facing_evtobj,name="entry_jump_if_player_not_facing_evtobj" } t[0x0082]={func=NPC_walk_straight_to_pos_high_speed,name="NPC_walk_straight_to_pos_high_speed" } t[0x0083]={func=entry_jump_if_evtobj_not_in_specified_zone_of_curr_evtobj,name="entry_jump_if_evtobj_not_in_specified_zone_of_curr_evtobj" } t[0x0084]={func=player_place_item_to_scene,name="player_place_item_to_scene" } --item like a event object --found Z item t[0x0085]={func=sys_delay_a_period,name="sys_delay_a_period" } t[0x0086]={func=entry_jump_if_item_is_not_equipped,name="entry_jump_if_item_is_not_equipped" } t[0x0087]={func=NPC_Animate_the_evtobj,name="NPC_Animate_the_evtobj" } t[0x0088]={func=magic_set_base_damage_look_at_amount_of_money,name="magic_set_base_damage_look_at_amount_of_money" } t[0x0089]={func=battle_set_result,name="battle_set_result" } t[0x008a]={func=battle_set_auto_next,name="battle_set_auto_next" } t[0x008b]={func=palette_change_current,name="palette_change_current" } t[0x008c]={func=color_fade_from_or_to,name="color_fade_from_or_to" } t[0x008d]={func=player_increase_level,name="player_increase_level" } --t[0x008e]= t[0x008f]={func=cash_halve_amount,name="cash_halve_amount" }
t[0x0090]={func=object_set_script,name="object_set_script" } t[0x0091]={func=entry_jump_if_enemy_not_alone,name="entry_jump_if_enemy_not_alone" } t[0x0092]={func=player_show_magic_casting_animation_in_battle,name="player_show_magic_casting_animation_in_battle" } t[0x0093]={func=screen_fade_and_update_screen_in_process,name="screen_fade_and_update_screen_in_process" } t[0x0094]={func=entry_jump_if_evtobj_state_is_specified,name="entry_jump_if_evtobj_state_is_specified" } t[0x0095]={func=entry_jump_if_scene_is_specified,name="entry_jump_if_scene_is_specified" } t[0x0096]={func=sys_show_ending_animation,name="sys_show_ending_animation" } t[0x0097]={func=evtobj_rided_to_pos_higher_speed,name="evtobj_rided_to_pos_higher_speed" } t[0x0098]={func=party_set_follower,name="party_set_follower" } t[0x0099]={func=map_change_for_scene,name="map_change_for_scene" } t[0x009a]={func=evtobj_set_state_many,name="evtobj_set_state_many" } t[0x009b]={func=scene_fade_to_current,name="scene_fade_to_current" } t[0x009c]={func=enemy_duplicate_itself,name="enemy_duplicate_itself" } -- copy itself to another just create new self --t[0x009d]= t[0x009e]={func=enemy_summons_another_monster,name="enemy_summons_another_monster" } -- Z all human t[0x009f]={func=enemy_transforms_into_sth_else,name="enemy_transforms_into_sth_else" } --wan thing changed
t[0x00a0]={func=sys_quit_game,name="sys_quit_game" } t[0x00a1]={func=party_set_pos_to_same_as_first_one,name="party_set_pos_to_same_as_first_one" } -- study_first t[0x00a2]={func=entry_jump_to_one_in_following_instructions_randomly,name="entry_jump_to_one_in_following_instructions_randomly" } -- jump to t[0x00a3]={func=music_play_CD,name="music_play_CD" } t[0x00a4]={func=FBP_scroll_to_screen,name="FBP_scroll_to_screen" } t[0x00a5]={func=FBP_show_picture_with_sprite_effects,name="FBP_show_picture_with_sprite_effects" } t[0x00a6]={func=screen_backup,name="screen_backup" }
這一套的好處,則是等我們要遍歷
遍歷了這個數組之後,會拿到所有的事件組合。將來可以用行為樹來表示,或者是狀態機。
通過遍歷這個數組,拿到的都是數字。我們根本不知道什麼含義。
但是通過映射表之後,把數字轉成了 funcname之後,就很輕鬆理解。
今天的這個進展,讓我感慨頗深。已經完全摸清了,全部腳本的架構。
腳本系統就是一棵樹,事件物體就是一個個枝幹,擁有多個事件。每個事件entry又擁有多個具體葉節點的操作。
這個我用圖片大致畫了圖片,基本就是這樣的了。
下面則是要繼續翻譯 指令函數,並且進行調試了。
目測代碼翻譯量可能要1-2個月。接近200個函數。
看一下,總腳本量,大約在42992個。
重複性很強啊
看來,這個應該用一個編輯器,來顯示效果更好
明白了這些數據結構,大家就心裡有數了
調整了一下,效果挺好的
可以看到大部分,還是對話,調整npc的朝向和姿勢
遊戲結束,居然放到了4000多行。說明布局的時候,先做的結束畫面
好了,進展不易,看到點贊吶。不點贊(這麼狠心)點個收藏也行。
慢慢就能夠追上 仙劍1各種mod的作者們的研究地步了,然後超越他們。仙劍1為什麼會是經典,他們根本不知道,經典該怎麼改,我覺得沒必要改。但是不看源碼,我敢說,沒人理解真的仙劍1。恐怕姚和謝都沒有辦法理解。
這真不是吹牛。後續的分析,請繼續觀看。
更新一下,補全 函數 和對話
這樣的話,更容易了解,仙劍的數據結構和演算法了。
腳本怎麼用的,現在都明白了。
邏輯好清晰。而且都是按順序進行的。
仙劍1絕對是 一個很好的把劇本寫成 代碼的很好的範例。用行為樹替換很輕鬆。
從源碼來看,原來設計是 多條線的,也就是多結局的。可能是多條主線。
最後給坎了成了一條主線。可見姚謝當年做遊戲有多艱苦,缺錢了,只能靠姚式刀法,仙劍變成了腦補過程和結局了。