本帖最後由 sofax222 於 2012-8-9 14:06 分享編輯

目前在 OpenKore 的 tables/portals.txt 傳點資料檔中,
可以設定兩種傳點格式:
1. 一般座標傳點: 只要角色移動至指定座標上,即可傳送 !
2. NPC 對話傳點: 移動到指定 NPC 位置(附近),
對該 NPC 啟動對話,再以特定的對話流程,完成對話後即可傳送 !

但是在遊戲中尚有另一種型式的傳點:
主動式 NPC 對話傳點,所謂「主動式」意即不是由角色啟動對話,
而是當角色移動到指定 NPC 位置(附近)時,就會觸發 NPC「自動」啟動對話,
目前遇到這種 NPC 的解法,都是以「一般座標傳點」+ 巨集的方法解決 !

但由於不同的 NPC 可能會有不同的對話流程,
所以得針對特定的 NPC,撰寫相對應的巨集,
如此增加巨集的數量 !

有鑒於此,小弟不才試著將這種「主動式 NPC 對話傳點」,
以修改程式方式,整合到現有的 tables/portals.txt 傳點資料架構之下,
也就是說,只要在 tables/portals.txt 檔案中設定傳點資料行,
即可完成「主動式 NPC 對話傳點」的對話傳送 !

程式需要修改 3 個檔案 11 處程式碼,
修改程序頗為複雜,若無把握切勿嘗試,
有意修改者,切記先將程式檔備份留存,
以防修改失敗時,至少可回存備份檔 !!


在進行程式修改前,先說明如何在 tables/portals.txt 檔案中,
加入這種「主動式 NPC 對話傳點」的資料行;
目前小弟測試成功的傳點有以下 4 個傳點:

#伊達 平原 搭乘飛行船傳點
ra_fild12 295 208 airplane_01 245 60 -1 r0

#田園都市 毀葛 搭乘飛行船傳點
hugel 178 142 airplane 244 58 -1 r0

#莫斯科比亞碼頭到鯨魚島傳點
moscovia 136 46 mosk_fild01 95 93 -5 r0 n

#史波浪壯麗原野進入粗暴者的傷口傳點
spl_fild01 375 109 nyd_dun01 72 125 -1 r0

從以上四個範例傳點看來,
最明顯的就是中間原傳送 zeny 費用的資料值變成了「負」值;
沒錯;把這個傳送 zeny 費用設成負值,
這個傳點就變成了「主動式 NPC 對話傳點」,
而其負值的意義是與 NPC 的距離值,
也就觸發 NPC 啟動對話的距離值,
但要注意的是,因為必須為負值,
所以距離值是設定的絕對值減 1,
也就是,
設定若為「-1」表示距進值為「0」,
設定若為「-2」表示距進值為「1」,
設定若為「-3」表示距進值為「2」... 以此類推。

至於修改程式部分,實因需修改以下三只程式檔:
src/Network/Receive/Servertype0.pm
src/Task/TalkNPC.pm
src/Task/MapRoute.pm


 


--------------------------------------------------------------------------------------


修改 src/Network/Receive/Servertype0.pm
共 3 處修改

但請注意:因為是修改主程式,若無把握請勿嘗試,
若改錯了, 可能會造成 openkore 跑不起來。
建議修改前先備份該檔案


開啟 src/Network/Receive/ServerType0.pm 程式檔

修改(1)


先找尋到「# TODO: move this stuff to AI()」字串,
原程式檔片段:


                # TODO: move this stuff to AI()
 
                if ($ai_v{npc_talk}{itemID} eq $item->{nameID}) {
 
                        $ai_v{'npc_talk'}{'talk'} = 'buy';
 
                        $ai_v{'npc_talk'}{'time'} = time;
 
                }


修改後程式碼為:


                # TODO: move this stuff to AI()
 
                if ($ai_v{npc_talk}{itemID} eq $item->{nameID}) {
 
                        $ai_v{'npc_talk'}{'talk'} = 'buy';
 
                        $ai_v{'npc_talk'}{'time'} = time;
 
                        $ai_v{'npc_talk'}{'ID'} = "";
 
                }


修改(2)
先找尋到「sub npc_talk_number {」字串,
原程式檔片段:


sub npc_talk_number {
 
        my ($self, $args) = @_;
 


        my $ID = $args->{ID};
 


        my $name = getNPCName($ID);
 
        $ai_v{npc_talk}{talk} = 'number';
 
        $ai_v{npc_talk}{time} = time;
 


        message TF("%s: Type 'talk num ' to input a number.\n", $name), "input";
 
        $ai_v{'npc_talk'}{'talk'} = 'num';
 
        $ai_v{'npc_talk'}{'time'} = time;
 
}


修改後程式碼為:


sub npc_talk_number {
 
        my ($self, $args) = @_;
 


        my $ID = $args->{ID};
 


        my $name = getNPCName($ID);
 
        $ai_v{npc_talk}{talk} = 'number';
 
        $ai_v{npc_talk}{time} = time;
 


        message TF("%s: Type 'talk num ' to input a number.\n", $name), "input";
 
        $ai_v{'npc_talk'}{'talk'} = 'num';
 
        $ai_v{'npc_talk'}{'time'} = time;
 
        $ai_v{'npc_talk'}{'ID'} = $ID;
 
}


新增第 13 行

修改(3)
先找尋到「$talk{responses}[@{$talk{responses}}]」字串,
原程式檔片段:


        $talk{responses}[@{$talk{responses}}] = "Cancel Chat";
 


        $ai_v{'npc_talk'}{'talk'} = 'select';
 
        $ai_v{'npc_talk'}{'time'} = time;
 


        my $list = T("----------Responses-----------\n" .


修改後程式碼為:


        $talk{responses}[@{$talk{responses}}] = "Cancel Chat";
 


        $ai_v{'npc_talk'}{'talk'} = 'select';
 
        $ai_v{'npc_talk'}{'time'} = time;
 
        $ai_v{'npc_talk'}{'ID'} = $ID;
 


        my $list = T("----------Responses-----------\n" .


新增第 05 行


---------------------------------------------------------------------------------------------------------


修改 src/Task/TalkNPC.pm
共 5 處修改

但請注意:因為是修改主程式,若無把握請勿嘗試,
若改錯了, 可能會造成 openkore 跑不起來。
建議修改前先備份該檔案


開啟 src/Task/TalkNPC.pm 程式檔

修改(1)
先找尋到「sub new {」字串,
原程式檔片段:


sub new {
 
        my $class = shift;
 
        my %args = @_;
 
        my $self = $class->SUPER::new(@_, mutexes => MUTEXES);
 


        $self->{x} = $args{x};
 
        $self->{y} = $args{y};
 
        $self->{sequence} = $args{sequence};
 
        $self->{sequence} =~ s/^ +| +$//g;


修改後程式碼為:


sub new {
 
        my $class = shift;
 
        my %args = @_;
 
        my $self = $class->SUPER::new(@_, mutexes => MUTEXES);
 


        $self->{x} = $args{x};
 
        $self->{y} = $args{y};
 
        $self->{sequence} = $args{sequence};
 
        $self->{sequence} =~ s/^ +| +$//g;
 
        $self->{cost} = (defined $args{cost}) ? $args{cost} : 0;


新增第 10 行

修改(2)
先找尋到「[parseArgs("x $self->{sequence}")]」字串,
原程式檔片段:


                        if ($target) {
 
                                $self->{target} = $target;
 
                                $self->{ID} = $target->{ID};
 
                                $self->{stage} = 'Talking to NPC';
 
                                $self->{steps} = [parseArgs("x $self->{sequence}")];
 
                                $self->{time} = time;
 
                                undef $ai_v{npc_talk}{time};
 
                                undef $ai_v{npc_talk}{talk};
 
                                lookAtPosition($self);
 
                        }


修改後程式碼為:


                        if ($self->{cost} < 0) {
 
                                $self->{target} = $target;
 
                                $self->{ID} = $target->{ID};
 
                                $self->{stage} = 'Talking to NPC';
 
                                $self->{steps} = [parseArgs("w1 $self->{sequence}")];
 
                                $self->{time} = time;
 
                                $ai_v{npc_talk}{time} = time;
 
                                lookAtPosition($self);
 
                        } elsif ($target) {
 
                                $self->{target} = $target;
 
                                $self->{ID} = $target->{ID};
 
                                $self->{stage} = 'Talking to NPC';
 
                                $self->{steps} = [parseArgs("x $self->{sequence}")];
 
                                $self->{time} = time;
 
                                undef $ai_v{npc_talk}{time};
 
                                undef $ai_v{npc_talk}{talk};
 
                                lookAtPosition($self);
 
                        }


把原程式碼的第 01 行改成新程式碼的第 01 ~ 09 行

修改(3)
先找尋到「elsif ($self->{mapChanged}」字串,
原程式檔片段:


        } elsif ($self->{mapChanged} || ($ai_v{npc_talk}{talk} eq 'close' && $self->{steps}[0] !~ /x/i)) {
 
                # Cancel conversation only if NPC is still around; otherwise
 
                # we could get disconnected.
 
                #$messageSender->sendTalkCancel($self->{ID}) if ($npcsList->getByID($self->{ID}));
 
                $self->setDone();
 
                message TF("Done talking with %s.\n", $self->{target}->name), "ai_npcTalk";


修改後程式碼為:


        } elsif ($self->{mapChanged} || ($ai_v{npc_talk}{talk} eq 'close' && $self->{steps}[0] !~ /x/i)) {
 
                # Cancel conversation only if NPC is still around; otherwise
 
                # we could get disconnected.
 
                #$messageSender->sendTalkCancel($self->{ID}) if ($npcsList->getByID($self->{ID}));
 
                $self->setDone();
 
                if ($self->{target}) {
 
                        message TF("Done talking with %s.\n", $self->{target}->name), "ai_npcTalk";
 
                } else {
 
                        message TF("Done talking with .....\n"), "ai_npcTalk";
 
                }


把原程式碼的第 06 行改成新程式碼的第 06 ~ 10 行

修改(4)
先找尋到「$messageSender->sendTalkContinue($self->{ID});」字串,
原程式檔片段:


                } elsif ( $step =~ /c/i ) {
 
                        # Click Next.
 
                        if ($npcTalkType eq 'next') {
 
                                $messageSender->sendTalkContinue($self->{ID});
 
                        } else {


修改後程式碼為:


                } elsif ( $step =~ /c/i ) {
 
                        # Click Next.
 
                        if ($npcTalkType eq 'next') {
 
                                my $npcID = $ai_v{npc_talk}{ID} ? $ai_v{npc_talk}{ID} : $self->{ID};
 
                                $messageSender->sendTalkContinue($npcID);
 
                        } else {


把原程式碼的第 04 行改成新程式碼的第 04 ~ 05 行

修改(5)
先找尋到「$messageSender->sendTalkResponse($self->{ID}, $choice」字串,
原程式檔片段:


                } elsif ( $step =~ /r(\d+)/i ) {
 
                        # Choose a menu item.
 
                        my $choice = $1;
 
                        if ($npcTalkType eq 'select') {
 
                                if ($choice < @{$talk{responses}} - 1) {
 
                                        $messageSender->sendTalkResponse($self->{ID}, $choice + 1);
 
                                } else {


修改後程式碼為:


                } elsif ( $step =~ /r(\d+)/i ) {
 
                        # Choose a menu item.
 
                        my $choice = $1;
 
                        if ($npcTalkType eq 'select') {
 
                                if ($choice < @{$talk{responses}} - 1) {
 
                                        my $npcID = $ai_v{npc_talk}{ID} ? $ai_v{npc_talk}{ID} : $self->{ID};
 
                                        $messageSender->sendTalkResponse($npcID, $choice + 1);
 
                                } else {


把原程式碼的第 06 行改成新程式碼的第 06 ~ 07 行


-------------------------------------------------------------------------------------------------------------------------


修改 src/Task/MapRoute.pm
共 3 處修改

但請注意:因為是修改主程式,若無把握請勿嘗試,
若改錯了, 可能會造成 openkore 跑不起來。
建議修改前先備份該檔案


開啟 src/Task/MapRoute.pm 程式檔

修改(1)
先找尋到「# If current solution has conversation steps specified」字串,
原程式檔片段:


        } elsif ( $self->{mapSolution}[0]{steps} ) {
 
                # If current solution has conversation steps specified
 
                if ( $self->{substage} eq 'Waiting for Warp' ) {
 
                        $self->{timeout} = time unless $self->{timeout};


修改後程式碼為:


        } elsif ( $self->{mapSolution}[0]{steps} ) {
 
                # If current solution has conversation steps specified
 
                my ($from, $to) = split /=/, $self->{mapSolution}[0]{portal};
 
                my $distNPC = ($portals_lut{$from}{dest}{$to}{cost} < 0)
 
                        ? -($portals_lut{$from}{dest}{$to}{cost} + 1)
 
                        : ($config{MapWrapNPCMaxDistance} ? $config{MapWrapNPCMaxDistance} : 7);
 
                if ( $self->{substage} eq 'Waiting for Warp' ) {
 
                        $self->{timeout} = time unless $self->{timeout};


把原程式碼的第 02 行之後插入新程式碼的第 03 ~ 06 行

修改(2)
先找尋到「# We have enough money for this service.」字串,
原程式檔片段:


                } elsif (distance($self->{actor}{pos_to}, $self->{mapSolution}[0]{pos}) <= 10) {
 
                        my ($from,$to) = split /=/, $self->{mapSolution}[0]{portal};
 
                        if ($self->{actor}{zeny} >= $portals_lut{$from}{dest}{$to}{cost}) {
 
                                # We have enough money for this service.
 
                                $self->{substage} = 'Waiting for Warp';
 
                                @{$self}{qw(old_x old_y)} = @{$self->{actor}{pos_to}}{qw(x y)};
 
                                $self->{old_map} = $field->baseName;
 
                                my $task = new Task::TalkNPC(
 
                                        x => $self->{mapSolution}[0]{pos}{x},
 
                                        y => $self->{mapSolution}[0]{pos}{y},
 
                                        sequence => $self->{mapSolution}[0]{steps});
 
                                $self->setSubtask($task);


修改後程式碼為:


                 } elsif (int(distance($self->{actor}{pos_to}, $self->{mapSolution}[0]{pos})) <= $distNPC) {
 
                        if ($self->{actor}{zeny} >= $portals_lut{$from}{dest}{$to}{cost}) {
 
                                # We have enough money for this service.
 
                                $self->{substage} = 'Waiting for Warp';
 
                                @{$self}{qw(old_x old_y)} = @{$self->{actor}{pos_to}}{qw(x y)};
 
                                $self->{old_map} = $field->baseName;
 
                                my $task = new Task::TalkNPC(
 
                                        x => $self->{mapSolution}[0]{pos}{x},
 
                                        y => $self->{mapSolution}[0]{pos}{y},
 
                                        sequence => $self->{mapSolution}[0]{steps},
 
                                        cost => $portals_lut{$from}{dest}{$to}{cost});
 
                                $self->setSubtask($task);


1. 把原程式碼的第 01 ~ 03 行改成新程式碼的第 01 ~ 02 行
2. 把原程式碼的第 11 行改成新程式碼的第 10 ~ 11 行


修改(3)
先找尋到「# NPC is reachable from current position」字串,
原程式檔片段:


                } elsif ( Task::Route->getRoute(\@solution, $field, $self->{actor}{pos_to}, $self->{mapSolution}[0]{pos}) ) {
 
                        # NPC is reachable from current position
 
                        # >> Then "route" to it
 
                        debug "Walking towards the NPC\n", "route";
 
                        my $task = new Task::Route(
 
                                actor => $self->{actor},
 
                                x => $self->{mapSolution}[0]{pos}{x},
 
                                y => $self->{mapSolution}[0]{pos}{y},
 
                                maxTime => $self->{maxTime},
 
                                distFromGoal => 10,
 
                                avoidWalls => $self->{avoidWalls},
 
                                solution => \@solution
 
                        );
 
                        $self->setSubtask($task);


修改後程式碼為:


                } elsif ( Task::Route->getRoute(\@solution, $field, $self->{actor}{pos_to}, $self->{mapSolution}[0]{pos}) ) {
 
                        # NPC is reachable from current position
 
                        # >> Then "route" to it
 
                        debug "Walking towards the NPC\n", "route";
 
                        my $task = new Task::Route(
 
                                actor => $self->{actor},
 
                                x => $self->{mapSolution}[0]{pos}{x},
 
                                y => $self->{mapSolution}[0]{pos}{y},
 
                                maxTime => $self->{maxTime},
 
                                distFromGoal => ($distNPC > 1) ? $distNPC - 1 : $distNPC,
 
                                avoidWalls => $self->{avoidWalls},
 
                                solution => \@solution
 
                        );
 
                        $self->setSubtask($task);


把原程式碼的第 10 行改成新程式碼的第 10 行


 


轉至 http://ro2.game.tw/Discuz/viewthread.php?tid=59291&rpid=325807&ordertype=0&page=1#pid325807

arrow
arrow
    全站熱搜

    aaa1314 發表在 痞客邦 留言(0) 人氣()