本帖最後由 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
留言列表