Client Navigation Generator (#6023)

Creates navigation files for the client.
This commit is contained in:
Vincent Stumpf 2022-08-26 21:31:45 -07:00 committed by GitHub
parent b1b371f4b8
commit c751ca6b74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1669 additions and 0 deletions

3
.gitignore vendored
View File

@ -144,3 +144,6 @@ Thumbs.db
# CMakeFiles
/CMakeFiles/
# generated files
generated

View File

@ -60,6 +60,7 @@ libconfig:
tools:
@$(MAKE) -C src/tool
@$(MAKE) -C src/map tools
rapidyaml:
@$(MAKE) -C 3rdparty/rapidyaml

View File

@ -978,6 +978,11 @@ Only the special labels which are not associated with any script command are
listed here. There are other kinds of labels which may be triggered in a similar
manner, but they are described with their associated commands.
OnNaviGenerate:
This special label triggers when running the map-server-generator binary. It is used
in combination with 'naviregisterwarp' to register extra warps for an npc.
On<label name>:
These special labels are used with Mob scripts mostly, and script commands
@ -9446,6 +9451,20 @@ with the given character id.
---------------------------------------
*naviregisterwarp("<Name of Link>", "<dest_map>", <dest_x>, <dest_y>)
Only useful when using the map-server-generator. Registers an extra warp from this
npc to the destination map/x/y for the generated client files.
---------------------------------------
*navihide
Only useful when using the map-server-generator. Hides this npc and all links from
this npc in the navigation generation.
---------------------------------------
========================
|7.- Instance commands.|
========================

View File

@ -526,6 +526,707 @@ S9: Restrict("RE");
Go("paramk",97,17);
S10: Go("turbo_room",99,114);
OnNaviGenerate:
// for non-prontera warpers, just give it warp to prontera
// this cuts down the number of links considerably
if (strnpcinfo(4) != "prontera") {
naviregisterwarp("Warper > Prontera", "prontera", 155, 183);
end;
}
naviregisterwarp("Warper > Prontera", "prontera", 155, 183);
naviregisterwarp("Warper > Alberta", "alberta", 28, 234);
naviregisterwarp("Warper > Al De Baran", "aldebaran", 140, 131);
naviregisterwarp("Warper > Amatsu", "amatsu", 198, 84);
naviregisterwarp("Warper > Ayothaya", "ayothaya", 208, 166);
naviregisterwarp("Warper > Einbech", "einbech",63,35);
naviregisterwarp("Warper > Einbroch", "einbroch",64,200);
naviregisterwarp("Warper > Geffen", "geffen",119,59);
naviregisterwarp("Warper > Hugel", "hugel",96,145);
naviregisterwarp("Warper > Izlude", "izlude",128,(checkre(3)?146:114));
naviregisterwarp("Warper > Jawaii", "jawaii",251,132);
naviregisterwarp("Warper > Juno", "yuno",157,51);
naviregisterwarp("Warper > Kunlun", "gonryun",160,120);
naviregisterwarp("Warper > Lighthalzen", "lighthalzen",158,92);
naviregisterwarp("Warper > Luoyang", "louyang",217,100);
naviregisterwarp("Warper > Lutie", "xmas",147,134);
naviregisterwarp("Warper > Manuk", "manuk",282,138);
naviregisterwarp("Warper > Midgarts Expedition Camp", "mid_camp",210,288);
naviregisterwarp("Warper > Morocc", "morocc",156,93);
naviregisterwarp("Warper > Moscovia", "moscovia",223,184);
naviregisterwarp("Warper > Nameless Island", "nameless_n",256,215);
naviregisterwarp("Warper > Niflheim", "niflheim",202,174);
naviregisterwarp("Warper > Payon", "payon",179,100);
naviregisterwarp("Warper > Rachel", "rachel",130,110);
naviregisterwarp("Warper > Splendide", "splendide",201,147);
naviregisterwarp("Warper > Thor Camp", "thor_camp",246,68);
naviregisterwarp("Warper > Umbala", "umbala",97,153);
naviregisterwarp("Warper > Veins", "veins",216,123);
if (checkre(0)) {
naviregisterwarp("Warper > Brasilis", "brasilis", 196, 217);
naviregisterwarp("Warper > Dewata", "dewata",200,180);
naviregisterwarp("Warper > Eclage", "ecl_in01",48,53);
naviregisterwarp("Warper > El Dicastes", "dicastes01",198,187);
naviregisterwarp("Warper > Lasagna", "lasagna",193,182);
naviregisterwarp("Warper > Malangdo", "malangdo",140,114);
naviregisterwarp("Warper > Malaya", "malaya",231,200);
naviregisterwarp("Warper > Mora", "mora",55,146);
}
// fields
naviregisterwarp("Warper > Amatsu Field", "ama_fild01", 190, 197);
naviregisterwarp("Warper > Ayothaya Field", "ayo_fild01", 173, 134);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Ayothaya Field", "ayo_fild02", 212, 150);
}
if (checkre(0)) {
naviregisterwarp("Warper > Bifrost Field", "bif_fild01", 193, 220);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Bifrost Field", "bif_fild02", 220, 187);
}
naviregisterwarp("Warper > Brasilis Field", "bra_fild01", 74, 32);
}
naviregisterwarp("Warper > Comodo Field", "cmd_fild01", 180, 178);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Comodo Field", "cmd_fild02", 231, 160);
naviregisterwarp("Warper > Comodo Field", "cmd_fild03", 191, 172);
naviregisterwarp("Warper > Comodo Field", "cmd_fild04", 228, 194);
if (!checkre(0)) {
naviregisterwarp("Warper > Comodo Field", "cmd_fild05", 224, 203);
}
naviregisterwarp("Warper > Comodo Field", "cmd_fild06", 190, 223);
naviregisterwarp("Warper > Comodo Field", "cmd_fild07", 234, 177);
naviregisterwarp("Warper > Comodo Field", "cmd_fild08", 194, 175);
naviregisterwarp("Warper > Comodo Field", "cmd_fild09", 172, 172);
}
if (checkre(0)) {
naviregisterwarp("Warper > Dewata Field", "dew_fild01", 371, 212);
naviregisterwarp("Warper > Eclage Field", "ecl_fild01", 97, 314);
}
naviregisterwarp("Warper > Einbroch Field", "ein_fild01", 142, 225);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Einbroch Field", "ein_fild03", 187, 228);
naviregisterwarp("Warper > Einbroch Field", "ein_fild04", 185, 173);
naviregisterwarp("Warper > Einbroch Field", "ein_fild05", 216, 173);
naviregisterwarp("Warper > Einbroch Field", "ein_fild06", 195, 148);
naviregisterwarp("Warper > Einbroch Field", "ein_fild07", 272, 220);
naviregisterwarp("Warper > Einbroch Field", "ein_fild08", 173, 214);
naviregisterwarp("Warper > Einbroch Field", "ein_fild09", 207, 174);
if (!checkre(0)) {
naviregisterwarp("Warper > Einbroch Field", "ein_fild02", 182, 141);
naviregisterwarp("Warper > Einbroch Field", "ein_fild10", 196, 200);
}
}
if (checkre(0)) {
naviregisterwarp("Warper > El Dicastes Field", "dic_fild01", 143, 132);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > El Dicastes Field", "dic_fild02", 143, 217);
}
}
naviregisterwarp("Warper > Geffen Field 0", "gef_fild00", 46, 199);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Geffen Field 1", "gef_fild01", 213, 204);
naviregisterwarp("Warper > Geffen Field 2", "gef_fild02", 195, 212);
naviregisterwarp("Warper > Geffen Field 3", "gef_fild03", 257, 192);
naviregisterwarp("Warper > Geffen Field 4", "gef_fild04", 188, 171);
naviregisterwarp("Warper > Geffen Field 5", "gef_fild05", 166, 263);
naviregisterwarp("Warper > Geffen Field 6", "gef_fild06", 248, 158);
naviregisterwarp("Warper > Geffen Field 7", "gef_fild07", 195, 191);
naviregisterwarp("Warper > Geffen Field 8", "gef_fild08", 186, 183);
naviregisterwarp("Warper > Geffen Field 9", "gef_fild09", 221, 117);
naviregisterwarp("Warper > Geffen Field 10", "gef_fild10", 178, 218);
naviregisterwarp("Warper > Geffen Field 11", "gef_fild11", 136, 328);
naviregisterwarp("Warper > Geffen Field 13", "gef_fild13", 235, 235);
if (checkre(0)) {
naviregisterwarp("Warper > Geffen Field 12", "gef_fild12", 240, 181);
naviregisterwarp("Warper > Geffen Field 14", "gef_fild14", 211, 185);
}
}
naviregisterwarp("Warper > Kunlun Field 1", "gon_fild01", 220, 227);
naviregisterwarp("Warper > Hugel Field 1", "hu_fild01", 268, 101);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Hugel Field 2", "hu_fild02", 222, 193);
naviregisterwarp("Warper > Hugel Field 4", "hu_fild04", 252, 189);
naviregisterwarp("Warper > Hugel Field 5", "hu_fild05", 196, 106);
naviregisterwarp("Warper > Hugel Field 6", "hu_fild06", 216, 220);
if (!checkre(0)) {
naviregisterwarp("Warper > Hugel Field 3", "hu_fild03", 232, 185);
naviregisterwarp("Warper > Hugel Field 7", "hu_fild07", 227, 197);
}
}
if (checkre(0)) {
naviregisterwarp("Warper > Lasagna Field 1", "lasa_fild01", 344, 371);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Lasagna Field 2", "lasa_fild02", 20, 98);
}
}
naviregisterwarp("Warper > Lighthalzen Field 1", "lhz_fild01", 240, 179);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Lighthalzen Field 2", "lhz_fild02", 185, 235);
naviregisterwarp("Warper > Lighthalzen Field 3", "lhz_fild03", 240, 226);
}
naviregisterwarp("Warper > Luoyang Field 1", "lou_fild01", 229, 187);
naviregisterwarp("Warper > Lutie Field 1", "xmas_fild01", 115, 145);
if (checkre(0)) {
naviregisterwarp("Warper > Malaya Field 1", "ma_fild01", 40, 272);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Malaya Field 2", "ma_fild02", 207, 180);
}
}
naviregisterwarp("Warper > Manuk Field 1", "man_fild01", 35, 236);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Manuk Field 2", "man_fild02", 35, 262);
naviregisterwarp("Warper > Manuk Field 3", "man_fild03", 84, 365);
}
naviregisterwarp("Warper > Mjolnir Field 1", "mjolnir_01", 204, 120);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Mjolnir Field 2", "mjolnir_02", 175, 193);
naviregisterwarp("Warper > Mjolnir Field 3", "mjolnir_03", 208, 213);
naviregisterwarp("Warper > Mjolnir Field 4", "mjolnir_04", 179, 180);
naviregisterwarp("Warper > Mjolnir Field 5", "mjolnir_05", 181, 240);
naviregisterwarp("Warper > Mjolnir Field 6", "mjolnir_06", 195, 270);
naviregisterwarp("Warper > Mjolnir Field 7", "mjolnir_07", 235, 202);
naviregisterwarp("Warper > Mjolnir Field 8", "mjolnir_08", 188, 215);
naviregisterwarp("Warper > Mjolnir Field 9", "mjolnir_09", 205, 144);
naviregisterwarp("Warper > Mjolnir Field 10", "mjolnir_10", 245, 223);
naviregisterwarp("Warper > Mjolnir Field 11", "mjolnir_11", 180, 206);
naviregisterwarp("Warper > Mjolnir Field 12", "mjolnir_12", 196, 208);
}
naviregisterwarp("Warper > Moscovia Field 1", "mosk_fild01", 82, 104);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Moscovia Field 2", "mosk_fild02", 131, 147);
}
naviregisterwarp("Warper > Niflheim Field 1", "nif_fild01", 215, 229);
if (!.OnlyFirstFld) {
naviregisterwarp("Warer > Niflheim Field 2", "nif_fild02", 167, 234);
}
naviregisterwarp("Warper > Payon Forest 1", "pay_fild01", 158, 206);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Payon Forest 2", "pay_fild02", 151, 219);
naviregisterwarp("Warper > Payon Forest 3", "pay_fild03", 205, 148);
naviregisterwarp("Warper > Payon Forest 4", "pay_fild04", 186, 247);
naviregisterwarp("Warper > Payon Forest 6", "pay_fild06", 193, 235);
naviregisterwarp("Warper > Payon Forest 7", "pay_fild07", 200, 177);
naviregisterwarp("Warper > Payon Forest 8", "pay_fild08", 137, 189);
naviregisterwarp("Warper > Payon Forest 9", "pay_fild09", 201, 224);
naviregisterwarp("Warper > Payon Forest 10", "pay_fild10", 160, 205);
if (!checkre(0)) {
naviregisterwarp("Warper > Payon Forest 5", "pay_fild05", 134, 204);
naviregisterwarp("Warper > Payon Forest 11", "pay_fild11", 194, 150);
}
}
naviregisterwarp("Warper > Prontera Field 0", "prt_fild00", 208, 227);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Prontera Field 1", "prt_fild01", 190, 206);
naviregisterwarp("Warper > Prontera Field 2", "prt_fild02", 240, 206);
naviregisterwarp("Warper > Prontera Field 3", "prt_fild03", 190, 143);
naviregisterwarp("Warper > Prontera Field 4", "prt_fild04", 307, 252);
naviregisterwarp("Warper > Prontera Field 5", "prt_fild05", 239, 213);
naviregisterwarp("Warper > Prontera Field 6", "prt_fild06", 185, 188);
naviregisterwarp("Warper > Prontera Field 7", "prt_fild07", 193, 194);
naviregisterwarp("Warper > Prontera Field 8", "prt_fild08", 187, 218);
naviregisterwarp("Warper > Prontera Field 9", "prt_fild09", 210, 183);
naviregisterwarp("Warper > Prontera Field 10", "prt_fild10", 195, 149);
naviregisterwarp("Warper > Prontera Field 11", "prt_fild11", 198, 164);
}
naviregisterwarp("Warper > Rachel Field 1", "ra_fild01", 192, 162);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Rachel Field 3", "ra_fild03", 202, 206);
naviregisterwarp("Warper > Rachel Field 4", "ra_fild04", 202, 208);
naviregisterwarp("Warper > Rachel Field 5", "ra_fild05", 225, 202);
naviregisterwarp("Warper > Rachel Field 6", "ra_fild06", 202, 214);
naviregisterwarp("Warper > Rachel Field 8", "ra_fild08", 217, 201);
naviregisterwarp("Warper > Rachel Field 12", "ra_fild12", 175, 200);
if (!checkre(0)) {
naviregisterwarp("Warper > Rachel Field 2", "ra_fild02", 235, 166);
naviregisterwarp("Warper > Rachel Field 7", "ra_fild07", 263, 196);
naviregisterwarp("Warper > Rachel Field 9", "ra_fild09", 87, 121);
naviregisterwarp("Warper > Rachel Field 10", "ra_fild10", 277, 181);
naviregisterwarp("Warper > Rachel Field 11", "ra_fild11", 221, 185);
naviregisterwarp("Warper > Rachel Field 13", "ra_fild13", 174, 197);
}
}
if (.Satan_Morocc) {
naviregisterwarp("Warper > Sograt Desert 1", "moc_fild01", 219, 205);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Sograt Desert 2", "moc_fild02", 177, 206);
naviregisterwarp("Warper > Sograt Desert 3", "moc_fild03", 194, 182);
naviregisterwarp("Warper > Sograt Desert 7", "moc_fild07", 224, 170);
naviregisterwarp("Warper > Sograt Desert 11", "moc_fild11", 198, 216);
naviregisterwarp("Warper > Sograt Desert 12", "moc_fild12", 156, 187);
naviregisterwarp("Warper > Sograt Desert 13", "moc_fild13", 185, 263);
naviregisterwarp("Warper > Sograt Desert 16", "moc_fild16", 206, 228);
naviregisterwarp("Warper > Sograt Desert 17", "moc_fild17", 208, 238);
naviregisterwarp("Warper > Sograt Desert 18", "moc_fild18", 209, 223);
naviregisterwarp("Warper > Sograt Desert 19", "moc_fild19", 85, 97);
naviregisterwarp("Warper > Sograt Desert 20", "moc_fild20", 207, 202);
naviregisterwarp("Warper > Sograt Desert 21", "moc_fild21", 31, 195);
naviregisterwarp("Warper > Sograt Desert 22", "moc_fild22", 38, 195);
}
} else {
naviregisterwarp("Warper > Sograt Desert 1", "moc_fild01", 219, 205);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Sograt Desert 2", "moc_fild02", 177, 206);
naviregisterwarp("Warper > Sograt Desert 3", "moc_fild03", 194, 182);
naviregisterwarp("Warper > Sograt Desert 4", "moc_fild04", 146, 297);
naviregisterwarp("Warper > Sograt Desert 5", "moc_fild05", 204, 197);
naviregisterwarp("Warper > Sograt Desert 6", "moc_fild06", 275, 302);
naviregisterwarp("Warper > Sograt Desert 7", "moc_fild07", 224, 170);
naviregisterwarp("Warper > Sograt Desert 8", "moc_fild08", 139, 123);
naviregisterwarp("Warper > Sograt Desert 9", "moc_fild09", 101, 110);
naviregisterwarp("Warper > Sograt Desert 10", "moc_fild10", 341, 39);
naviregisterwarp("Warper > Sograt Desert 11", "moc_fild11", 198, 216);
naviregisterwarp("Warper > Sograt Desert 12", "moc_fild12", 156, 187);
naviregisterwarp("Warper > Sograt Desert 13", "moc_fild13", 185, 263);
naviregisterwarp("Warper > Sograt Desert 14", "moc_fild14", 223, 222);
naviregisterwarp("Warper > Sograt Desert 15", "moc_fild15", 170, 257);
naviregisterwarp("Warper > Sograt Desert 16", "moc_fild16", 206, 228);
naviregisterwarp("Warper > Sograt Desert 17", "moc_fild17", 208, 238);
naviregisterwarp("Warper > Sograt Desert 18", "moc_fild18", 209, 223);
naviregisterwarp("Warper > Sograt Desert 19", "moc_fild19", 85, 97);
}
}
naviregisterwarp("Warper > Splendide Field 1", "spl_fild01", 175, 186);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Splendide Field 2", "spl_fild02", 236, 184);
naviregisterwarp("Warper > Splendide Field 3", "spl_fild03", 188, 204);
}
naviregisterwarp("Warper > Umbala Field 1", "um_fild01", 217, 206);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Umbala Field 2", "um_fild02", 223, 221);
naviregisterwarp("Warper > Umbala Field 3", "um_fild03", 237, 215);
naviregisterwarp("Warper > Umbala Field 4", "um_fild04", 202, 197);
}
naviregisterwarp("Warper > Veins Field 1", "ve_fild01", 186, 175);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Veins Field 2", "ve_fild02", 196, 370);
naviregisterwarp("Warper > Veins Field 3", "ve_fild03", 222, 45);
naviregisterwarp("Warper > Veins Field 4", "ve_fild04", 51, 250);
naviregisterwarp("Warper > Veins Field 6", "ve_fild06", 150, 223);
naviregisterwarp("Warper > Veins Field 7", "ve_fild07", 149, 307);
if (!checkre(0)) {
naviregisterwarp("Warper > Veins Field 5", "ve_fild05", 202, 324);
}
}
naviregisterwarp("Warper > Juno Field 1", "yuno_fild01", 189, 224);
if (!.OnlyFirstFld) {
naviregisterwarp("Warper > Juno Field 2", "yuno_fild02", 192, 207);
naviregisterwarp("Warper > Juno Field 3", "yuno_fild03", 221, 157);
naviregisterwarp("Warper > Juno Field 4", "yuno_fild04", 226, 199);
naviregisterwarp("Warper > Juno Field 6", "yuno_fild06", 187, 232);
naviregisterwarp("Warper > Juno Field 7", "yuno_fild07", 231, 174);
naviregisterwarp("Warper > Juno Field 8", "yuno_fild08", 196, 203);
naviregisterwarp("Warper > Juno Field 9", "yuno_fild09", 183, 214);
naviregisterwarp("Warper > Juno Field 11", "yuno_fild11", 195, 226);
naviregisterwarp("Warper > Juno Field 12", "yuno_fild12", 210, 304);
if (!checkre(0)) {
naviregisterwarp("Warper > Juno Field 5", "yuno_fild05", 223, 177);
naviregisterwarp("Warper > Juno Field 10", "yuno_fild10", 200, 124);
}
}
naviregisterwarp("Warper > Abyss Lakes 1", "abyss_01", 261, 272);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Abyss Lakes 2", "abyss_02", 275, 270);
naviregisterwarp("Warper > Abyss Lakes 3", "abyss_03", 116, 27);
}
naviregisterwarp("Warper > Amatsu Dungeon 1", "ama_dun01", 228, 11);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Amatsu Dungeon 2", "ama_dun02", 34, 41);
naviregisterwarp("Warper > Amatsu Dungeon 3", "ama_dun03", 119, 14);
}
naviregisterwarp("Warper > Anthell 1", "anthell01", 35, 262);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Anthell 2", "anthell02", 168, 170);
}
naviregisterwarp("Warper > Ancient Shrine Maze", "ayo_dun01", 275, 19);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Inside Ancient Shrine", "ayo_dun02", 24, 26);
}
naviregisterwarp("Warper > Beach Dungeon 1", "beach_dun", 266, 67);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Beach Dungeon 2", "beach_dun2", 255, 244);
naviregisterwarp("Warper > Beach Dungeon 3", "beach_dun3", 23, 260);
}
naviregisterwarp("Warper > Bio Lab 1", "lhz_dun01", 150, 288);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Bio Lab 2", "lhz_dun02", 150, 18);
naviregisterwarp("Warper > Bio Lab 3", "lhz_dun03", 140, 134);
if (checkre(0)) {
naviregisterwarp("Warper > Bio Lab 4", "lhz_dun04", 244, 52);
}
}
naviregisterwarp("Warper > Brasilis Dungeon 1", "bra_dun01", 87, 47);
if (!.OnlyFirstDun) {
if (checkre(0)) {
naviregisterwarp("Warper > Brasilis Dungeon 2", "bra_dun02", 262, 262);
}
}
naviregisterwarp("Warper > Byalan Dungeon 1", "iz_dun00", 168, 168);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Byalan Dungeon 2", "iz_dun01", 253, 252);
naviregisterwarp("Warper > Byalan Dungeon 3", "iz_dun02", 236, 204);
naviregisterwarp("Warper > Byalan Dungeon 4", "iz_dun03", 32, 63);
naviregisterwarp("Warper > Byalan Dungeon 5", "iz_dun04", 26, 27);
if (checkre(0)) {
naviregisterwarp("Warper > Byalan Dungeon 6", "iz_dun05", 141, 187);
}
}
naviregisterwarp("Warper > Clock Tower 1", "c_tower1", 199, 159);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Clock Tower 2", "c_tower2", 148, 283);
naviregisterwarp("Warper > Clock Tower 3", "c_tower3", 65, 147);
naviregisterwarp("Warper > Clock Tower 4", "c_tower4", 56, 155);
naviregisterwarp("Warper > Basement 1", "alde_dun01", 297, 25);
naviregisterwarp("Warper > Basement 2", "alde_dun02", 127, 169);
naviregisterwarp("Warper > Basement 3", "alde_dun03", 277, 178);
naviregisterwarp("Warper > Basement 4", "alde_dun04", 268, 74);
}
naviregisterwarp("Warper > Coal Mines 1", "mjo_dun01", 52, 17);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Coal Mines 2", "mjo_dun02", 381, 343);
naviregisterwarp("Warper > Coal Mines 3", "mjo_dun03", 302, 262);
}
naviregisterwarp("Warper > Culvert 1", "prt_sewb1", 131, 247);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Culvert 2", "prt_sewb2", 19, 19);
naviregisterwarp("Warper > Culvert 3", "prt_sewb3", 180, 169);
naviregisterwarp("Warper > Culvert 4", "prt_sewb4", 100, 92);
}
naviregisterwarp("Warper > Cursed Abbey 1", "abbey01", 51, 14);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Cursed Abbey 2", "abbey02", 150, 11);
naviregisterwarp("Warper > Cursed Abbey 3", "abbey03", 120, 10);
}
if (checkre(0)) {
naviregisterwarp("Warper > Dewata Dungeon 1", "dew_dun01", 285, 160);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Dewata Dungeon 2", "dew_dun02", 299, 29);
}
}
naviregisterwarp("Warper > Einbroch Dungeon 1", "ein_dun01", 22, 14);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Einbroch Dungeon 2", "ein_dun02", 292, 290);
}
naviregisterwarp("Warper > Gefenia 1", "gefenia01", 40, 103);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Gefenia 2", "gefenia02", 203, 34);
naviregisterwarp("Warper > Gefenia 3", "gefenia03", 266, 168);
naviregisterwarp("Warper > Gefenia 4", "gefenia04", 130, 272);
}
naviregisterwarp("Warper > Geffen Dungeon 1", "gef_dun00", 104, 99);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Geffen Dungeon 2", "gef_dun01", 115, 236);
naviregisterwarp("Warper > Geffen Dungeon 3", "gef_dun02", 106, 132);
naviregisterwarp("Warper > Geffen Dungeon 4", "gef_dun03", 203, 200);
}
naviregisterwarp("Warper > Entrance", "glast_01", 370, 304);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Castle 1", "gl_cas01", 199, 29);
naviregisterwarp("Warper > Castle 2", "gl_cas02", 104, 25);
naviregisterwarp("Warper > Chivalry 1", "gl_knt01", 150, 15);
naviregisterwarp("Warper > Chivalry 2", "gl_knt02", 157, 287);
naviregisterwarp("Warper > Churchyard", "gl_chyard", 147, 15);
naviregisterwarp("Warper > Culvert 1", "gl_sew01", 258, 255);
naviregisterwarp("Warper > Culvert 2", "gl_sew02", 108, 291);
naviregisterwarp("Warper > Culvert 3", "gl_sew03", 171, 283);
naviregisterwarp("Warper > Culvert 4", "gl_sew04", 68, 277);
naviregisterwarp("Warper > St. Abbey", "gl_church", 156, 7);
naviregisterwarp("Warper > Staircase Dungeon", "gl_step", 12, 7);
naviregisterwarp("Warper > Underground Cave 1", "gl_dun01", 133, 271);
naviregisterwarp("Warper > Underground Cave 2", "gl_dun02", 224, 274);
naviregisterwarp("Warper > Underground Prison 1", "gl_prison", 14, 70);
naviregisterwarp("Warper > Underground Prison 2", "gl_prison1", 150, 14);
}
naviregisterwarp("Warper > Kunlun Dungeon 1", "gon_dun01", 153, 53);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Kunlun Dungeon 2", "gon_dun02", 28, 113);
naviregisterwarp("Warper > Kunlun Dungeon 3", "gon_dun03", 68, 16);
}
naviregisterwarp("Warper > Hidden Dungeon 1", "prt_maze01", 176, 7);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Hidden Dungeon 2", "prt_maze02", 93, 20);
naviregisterwarp("Warper > Hidden Dungeon 3", "prt_maze03", 23, 8);
}
naviregisterwarp("Warper > Ice Dungeon 1", "ice_dun01", 157, 14);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Ice Dungeon 2", "ice_dun02", 151, 155);
naviregisterwarp("Warper > Ice Dungeon 3", "ice_dun03", 149, 22);
naviregisterwarp("Warper > Ice Dungeon 4", "ice_dun04", 33, 158);
}
naviregisterwarp("Warper > Entrance", "jupe_cave", 140, 51);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Juperos 1", "juperos_01", 53, 247);
naviregisterwarp("Warper > Juperos 2", "juperos_02", 37, 63);
naviregisterwarp("Warper > Core", "jupe_core", 150, 285);
}
naviregisterwarp("Warper > Kiel Dungeon 1", "kh_dun01", 28, 226);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Kiel Dungeon 2", "kh_dun02", 41, 198);
}
if (checkre(0)) {
naviregisterwarp("Warper > Lasagna Dungeon 1", "lasa_dun01", 24, 143);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Lasagna Dungeon 2", "lasa_dun02", 22, 171);
naviregisterwarp("Warper > Lasagna Dungeon 3", "lasa_dun03", 190, 18);
}
}
naviregisterwarp("Warper > The Royal Tomb", "lou_dun01", 218, 196);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Inside the Royal Tomb", "lou_dun02", 282, 20);
naviregisterwarp("Warper > Suei Long Gon", "lou_dun03", 165, 38);
}
naviregisterwarp("Warper > Magma Dungeon 1", "mag_dun01", 126, 68);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Magma Dungeon 2", "mag_dun02", 47, 30);
}
if (checkre(0)) {
naviregisterwarp("Warper > Malangdo Dungeon 1", "mal_dun01", 33, 230);
}
naviregisterwarp("Warper > Moscovia Dungeon 1", "mosk_dun01", 189, 48);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Moscovia Dungeon 2", "mosk_dun02", 165, 30);
naviregisterwarp("Warper > Moscovia Dungeon 3", "mosk_dun03", 32, 135);
}
naviregisterwarp("Warper > Nidhogg's Dungeon 1", "nyd_dun01", 61, 239);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Nidhogg's Dungeon 2", "nyd_dun02", 60, 271);
}
naviregisterwarp("Warper > Odin Temple 1", "odin_tem01", 298, 167);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Odin Temple 2", "odin_tem02", 224, 149);
naviregisterwarp("Warper > Odin Temple 3", "odin_tem03", 266, 280);
}
naviregisterwarp("Warper > Orc Dungeon 1", "orcsdun01", 32, 170);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Orc Dungeon 2", "orcsdun02", 21, 185);
}
naviregisterwarp("Warper > Payon Dungeon 1", "pay_dun00", 21, 183);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Payon Dungeon 2", "pay_dun01", 19, 33);
naviregisterwarp("Warper > Payon Dungeon 3", "pay_dun02", 19, 63);
naviregisterwarp("Warper > Payon Dungeon 4", "pay_dun03", 155, 159);
naviregisterwarp("Warper > Payon Dungeon 5", "pay_dun04", 201, 204);
}
naviregisterwarp("Warper > Pyramids 1", "moc_pryd01", 192, 9);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Pyramids 2", "moc_pryd02", 10, 192);
naviregisterwarp("Warper > Pyramids 3", "moc_pryd03", 100, 92);
naviregisterwarp("Warper > Pyramids 4", "moc_pryd04", 181, 11);
naviregisterwarp("Warper > Basement 1", "moc_pryd05", 94, 96);
naviregisterwarp("Warper > Basement 2", "moc_pryd06", 192, 8);
if (checkre(0)) {
naviregisterwarp("Warper > Basement 1 - Nightmare Mode", "moc_prydn1", 94, 96);
naviregisterwarp("Warper > Basement 2 - Nightmare Mode", "moc_prydn2", 192, 8);
}
}
naviregisterwarp("Warper > Rachel Sanctuary 1", "ra_san01", 140, 11);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Rachel Sanctuary 2", "ra_san02", 32, 21);
naviregisterwarp("Warper > Rachel Sanctuary 3", "ra_san03", 8, 149);
naviregisterwarp("Warper > Rachel Sanctuary 4", "ra_san04", 204, 218);
naviregisterwarp("Warper > Rachel Sanctuary 5", "ra_san05", 150, 9);
}
if (checkre(0)) {
naviregisterwarp("Warper > Scaraba Hole 1", "dic_dun01", 364, 44);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Scaraba Hole 2", "dic_dun02", 101, 141);
}
}
naviregisterwarp("Warper > Sphinx 1", "in_sphinx1", 288, 9);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Sphinx 2", "in_sphinx2", 149, 81);
naviregisterwarp("Warper > Sphinx 3", "in_sphinx3", 210, 54);
naviregisterwarp("Warper > Sphinx 4", "in_sphinx4", 10, 222);
naviregisterwarp("Warper > Sphinx 5", "in_sphinx5", 100, 99);
}
naviregisterwarp("Warper > Sunken Ship 1", "treasure01", 69, 24);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Sunken Ship 2", "treasure02", 102, 27);
}
naviregisterwarp("Warper > Thanatos Tower 1", "tha_t01", 150, 39);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Thanatos Tower 2", "tha_t02", 150, 136);
naviregisterwarp("Warper > Thanatos Tower 3", "tha_t03", 220, 158);
naviregisterwarp("Warper > Thanatos Tower 4", "tha_t04", 59, 143);
naviregisterwarp("Warper > Thanatos Tower 5", "tha_t05", 62, 11);
naviregisterwarp("Warper > Thanatos Tower 6", "tha_t06", 89, 221);
naviregisterwarp("Warper > Thanatos Tower 7", "tha_t07", 35, 166);
naviregisterwarp("Warper > Thanatos Tower 8", "tha_t08", 93, 148);
naviregisterwarp("Warper > Thanatos Tower 9", "tha_t09", 29, 107);
naviregisterwarp("Warper > Thanatos Tower 10", "tha_t10", 159, 138);
naviregisterwarp("Warper > Thanatos Tower 11", "tha_t11", 19, 20);
naviregisterwarp("Warper > Thanatos Tower 12", "tha_t12", 130, 52);
}
naviregisterwarp("Warper > Thor Volcano 1", "thor_v01", 21, 228);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Thor Volcano 2", "thor_v02", 75, 205);
naviregisterwarp("Warper > Thor Volcano 3", "thor_v03", 34, 272);
}
naviregisterwarp("Warper > Toy Factory 1", "xmas_dun01", 205, 15);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Toy Factory 2", "xmas_dun02", 129, 133);
}
naviregisterwarp("Warper > Entrance", "tur_dun01", 154, 49);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Turtle Dungeon 1", "tur_dun02", 148, 261);
naviregisterwarp("Warper > Turtle Dungeon 2", "tur_dun03", 132, 189);
naviregisterwarp("Warper > Turtle Dungeon 3", "tur_dun04", 100, 192);
}
naviregisterwarp("Warper > Carpenter's Shop in the Tree", "um_dun01", 42, 31);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Passage to a Foreign World", "um_dun02", 48, 30);
naviregisterwarp("Warper > Hvergermil's Fountain", "yggdrasil01", 204, 78);
}
if (checkre(0)) {
naviregisterwarp("Warper > Bifrost Tower 1", "ecl_tdun01", 57, 13);
if (!.OnlyFirstDun) {
naviregisterwarp("Warper > Bifrost Tower 2", "ecl_tdun02", 64, 88);
naviregisterwarp("Warper > Bifrost Tower 3", "ecl_tdun03", 45, 14);
naviregisterwarp("Warper > Bifrost Tower 4", "ecl_tdun04", 26, 23);
}
}
// castles
naviregisterwarp("Warper > Neuschwanstein", "alde_gld", 48, 83);
naviregisterwarp("Warper > Hohenschwangau", "alde_gld", 95, 249);
naviregisterwarp("Warper > Nuenberg", "alde_gld", 142, 85);
naviregisterwarp("Warper > Wuerzburg", "alde_gld", 239, 242);
naviregisterwarp("Warper > Rothenburg", "alde_gld", 264, 90);
naviregisterwarp("Warper > Repherion", "gef_fild13", 214, 75);
naviregisterwarp("Warper > Eeyolbriggar", "gef_fild13", 308, 240);
naviregisterwarp("Warper > Yesnelph", "gef_fild13", 143, 240);
naviregisterwarp("Warper > Bergel", "gef_fild13", 193, 278);
naviregisterwarp("Warper > Mersetzdeitz", "gef_fild13", 305, 87);
naviregisterwarp("Warper > Bright Arbor", "pay_gld", 121, 233);
naviregisterwarp("Warper > Scarlet Palace", "pay_gld", 295, 116);
naviregisterwarp("Warper > Holy Shadow", "pay_gld", 317, 293);
naviregisterwarp("Warper > Sacred Altar", "pay_gld", 140, 160);
naviregisterwarp("Warper > Bamboo Grove Hill", "pay_gld", 204, 266);
naviregisterwarp("Warper > Kriemhild", "prt_gld", 134, 65);
naviregisterwarp("Warper > Swanhild", "prt_gld", 240, 128);
naviregisterwarp("Warper > Fadhgridh", "prt_gld", 153, 137);
naviregisterwarp("Warper > Skoegul", "prt_gld", 111, 240);
naviregisterwarp("Warper > Gondul", "prt_gld", 208, 240);
naviregisterwarp("Warper > Mardol", "aru_gld", 158, 272);
naviregisterwarp("Warper > Cyr", "aru_gld", 83, 47);
naviregisterwarp("Warper > Horn", "aru_gld", 68, 155);
naviregisterwarp("Warper > Gefn", "aru_gld", 299, 345);
naviregisterwarp("Warper > Banadis", "aru_gld", 292, 107);
naviregisterwarp("Warper > Himinn", "sch_gld", 293, 100);
naviregisterwarp("Warper > Andlangr", "sch_gld", 288, 252);
naviregisterwarp("Warper > Viblainn", "sch_gld", 97, 196);
naviregisterwarp("Warper > Hljod", "sch_gld", 137, 90);
naviregisterwarp("Warper > Skidbladnir", "sch_gld", 71, 315);
if (checkre(0)) {
naviregisterwarp("Warper > Kafragarten 1", "te_alde_gld", 48, 83);
naviregisterwarp("Warper > Kafragarten 2", "te_alde_gld", 95, 249);
naviregisterwarp("Warper > Kafragarten 3", "te_alde_gld", 142, 85);
naviregisterwarp("Warper > Kafragarten 4", "te_alde_gld", 239, 242);
naviregisterwarp("Warper > Kafragarten 5", "te_alde_gld", 264, 90);
naviregisterwarp("Warper > Gloria 1", "te_prt_gld", 134, 65);
naviregisterwarp("Warper > Gloria 2", "te_prt_gld", 240, 128);
naviregisterwarp("Warper > Gloria 3", "te_prt_gld", 153, 137);
naviregisterwarp("Warper > Gloria 4", "te_prt_gld", 111, 240);
naviregisterwarp("Warper > Gloria 5", "te_prt_gld", 208, 240);
}
// guild dungeons
naviregisterwarp("Warper > Baldur F1", "gld_dun01", 119, 93);
naviregisterwarp("Warper > Luina F1", "gld_dun02", 39, 161);
naviregisterwarp("Warper > Valkyrie F1", "gld_dun03", 50, 44);
naviregisterwarp("Warper > Britoniah F1", "gld_dun04", 116, 45);
naviregisterwarp("Warper > Arunafeltz", "arug_dun01", 199, 195);
naviregisterwarp("Warper > Schwarzwald", "schg_dun01", 200,124);
if (checkre(0)) {
naviregisterwarp("Warper > Baldur F2", "gld_dun01_2", 119, 93);
naviregisterwarp("Warper > Hall of Abyss", "gld2_pay", 120, 130);
naviregisterwarp("Warper > Luina F2", "gld_dun02_2", 39, 161);
naviregisterwarp("Warper > Hall of Abyss", "gld2_ald", 147, 155);
naviregisterwarp("Warper > Valkyrie F2", "gld_dun03_2", 50, 44);
naviregisterwarp("Warper > Hall of Abyss", "gld2_prt", 140, 132);
naviregisterwarp("Warper > Britoniah F2", "gld_dun04_2", 116, 45);
naviregisterwarp("Warper > Hall of Abyss", "gld2_gef", 152, 118);
naviregisterwarp("Warper > Kafragarten", "teg_dun01", 42, 36);
naviregisterwarp("Warper > Gloria", "teg_dun02", 26, 160);
}
end;
// instances
naviregisterwarp("Warper > Endless Tower", "e_tower", 72, 112);
naviregisterwarp("Warper > Nidhoggur's Nest", "nyd_dun02", 95, 193);
naviregisterwarp("Warper > Orc's Memory", "gef_fild10", 240, 198);
naviregisterwarp("Warper > Sealed Shrine", "monk_test", 306, 143);
if (checkre(0)) {
naviregisterwarp("Warper > Bakonawa Lake", "ma_scene01", 172, 175);
naviregisterwarp("Warper > Bangungot Hospital 2F", "ma_dun01", 151, 8);
naviregisterwarp("Warper > Buwaya Cave", "ma_fild02", 316, 317);
naviregisterwarp("Warper > Devil Tower", "dali02", 137, 115);
naviregisterwarp("Warper > Eclage Interior", "ecl_hub01", 129, 12);
naviregisterwarp("Warper > Faceworms Nest", "dali", 85, 64);
naviregisterwarp("Warper > Geffen Magic Tournament", "dali", 94, 141);
naviregisterwarp("Warper > Ghost Palace", "dali02", 46, 128);
naviregisterwarp("Warper > Hazy Forest", "bif_fild01", 161, 334);
naviregisterwarp("Warper > Horror Toy Factory", "xmas", 234, 298);
naviregisterwarp("Warper > Malangdo Culvert", "mal_in01", 164, 21);
naviregisterwarp("Warper > Octopus Cave", "mal_dun01", 152, 230);
naviregisterwarp("Warper > Old Glast Heim", "glast_01", 204, 268);
naviregisterwarp("Warper > Sarah and Fenrir", "dali02", 92, 141);
naviregisterwarp("Warper > Sara Memory", "dali", 133, 108);
naviregisterwarp("Warper > Wolfchev's Laboratory", "lhz_dun04", 148, 269);
}
// special
naviregisterwarp("Warper > Auction Hall", "auction_01", 22, 68);
naviregisterwarp("Warper > Battlegrounds", "bat_room", 154, 150);
naviregisterwarp("Warper > Casino", "cmd_in02", 179, 129);
naviregisterwarp("Warper > Kunlun Arena", "gon_test", 48, 10);
naviregisterwarp("Warper > Izlude Arena", "arena_room", 100, 88);
naviregisterwarp("Warper > Monster Race Arena", "p_track01", 62, 41);
naviregisterwarp("Warper > Turbo Track", "turbo_room", 99, 114);
if (checkre(0)) {
naviregisterwarp("Warper > Dimensional Rift", "dali", 113, 82);
naviregisterwarp("Warper > Eden Group Headquarters", "moc_para01", 31, 14);
naviregisterwarp("Warper > Para Market", "paramk", 97, 17);
}
OnInit:
.Satan_Morocc = true; // false will enable moc_fild 4,5,6,8,9,10,14,15 while disable moc_fild 20,21,22 Default is true.
.OnlyFirstFld = false; // true will teleport to the first level of the Fields Default is false.

View File

@ -16,6 +16,7 @@ RAPIDYAML_INCLUDE = -I../../3rdparty/rapidyaml/src -I../../3rdparty/rapidyaml/ex
MAP_OBJ = $(shell ls *.cpp | sed -e "s/\.cpp/\.o/g")
#MAP_OBJ += $(shell ls *.c | sed -e "s/\.c/\.o/g")
MAP_DIR_OBJ = $(MAP_OBJ:%=obj/%)
MAP_GEN_DIR_OBJ = $(MAP_OBJ:%=obj-gen/%)
MAP_H = $(shell ls ../map/*.hpp) \
$(shell ls ../config/*.hpp)
@ -34,6 +35,9 @@ else
PCRE_CFLAGS=
endif
TOOLS_DEPENDS=map-server-generator
TOOLS_FLAGS="-DGENERATE_NAVI"
@SET_MAKE@
#####################################################################
@ -43,6 +47,8 @@ all: $(ALL_DEPENDS)
server: $(SERVER_DEPENDS)
tools: $(TOOLS_DEPENDS)
clean:
@echo " CLEAN map"
@rm -rf *.o obj ../../@OMAP@@EXEEXT@
@ -66,6 +72,10 @@ obj:
@echo " MKDIR obj"
@-mkdir obj
obj-gen:
@echo " MDIR obj-gen"
@-mkdir obj-gen
# executables
map-server: obj $(MAP_DIR_OBJ) $(COMMON_AR) $(LIBCONFIG_AR) $(RAPIDYAML_AR)
@ -73,6 +83,11 @@ map-server: obj $(MAP_DIR_OBJ) $(COMMON_AR) $(LIBCONFIG_AR) $(RAPIDYAML_AR)
@@CXX@ @LDFLAGS@ -o ../../@OMAP@@EXEEXT@ $(MAP_DIR_OBJ) $(COMMON_AR) $(LIBCONFIG_AR) $(RAPIDYAML_AR) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@
map-server-generator: obj-gen $(MAP_GEN_DIR_OBJ) $(COMMON_AR) $(LIBCONFIG_AR) $(RAPIDYAML_AR)
@echo " LD map-server-generator@EXEEXT@"
@@CXX@ @LDFLAGS@ -o ../../map-server-generator@EXEEXT@ $(MAP_GEN_DIR_OBJ) $(COMMON_AR) $(LIBCONFIG_AR) $(RAPIDYAML_AR) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@
# map object files
#cause this one failling otherwise
obj/npc.o: npc.cpp $(MAP_H) $(COMMON_H) $(LIBCONFIG_H) $(RAPIDYAML_H)
@ -83,6 +98,14 @@ obj/%.o: %.cpp $(MAP_H) $(COMMON_H) $(LIBCONFIG_H) $(RAPIDYAML_H)
@echo " CXX $<"
@@CXX@ @CXXFLAGS@ $(COMMON_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) $(RAPIDYAML_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
obj-gen/npc.o: npc.cpp $(MAP_H) $(COMMON_H) $(LIBCONFIG_H) $(RAPIDYAML_H)
@echo " CXX $< (custom rule)"
@@CXX@ @CXXFLAG_CLEARS@ $(TOOLS_FLAGS) $(COMMON_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) $(RAPIDYAML_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
obj-gen/%.o: %.cpp $(MAP_H) $(COMMON_H) $(LIBCONFIG_H) $(RAPIDYAML_H)
@echo " CXX $<"
@@CXX@ @CXXFLAGS@ $(TOOLS_FLAGS) $(COMMON_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) $(RAPIDYAML_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
# missing object files
$(COMMON_AR):
@$(MAKE) -C ../common server

View File

@ -10465,6 +10465,10 @@ void battle_adjust_conf()
if (battle_config.custom_cell_stack_limit != 1)
ShowWarning("Battle setting 'custom_cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");
#endif
#ifdef GENERATE_NAVI
battle_config.dynamic_mobs = 1;
#endif
}
/*=====================================

View File

@ -209,6 +209,7 @@
<ClInclude Include="mapreg.hpp" />
<ClInclude Include="mercenary.hpp" />
<ClInclude Include="mob.hpp" />
<ClInclude Include="navi.hpp" />
<ClInclude Include="npc.hpp" />
<ClInclude Include="packets.hpp" />
<ClInclude Include="packets_struct.hpp" />
@ -256,6 +257,7 @@
<ClCompile Include="mob.cpp">
<Optimization Condition="'$(Configuration)'=='Release'">Disabled</Optimization>
</ClCompile>
<ClCompile Include="navi.cpp" />
<ClCompile Include="npc.cpp" />
<ClCompile Include="npc_chat.cpp" />
<ClCompile Include="party.cpp" />

View File

@ -95,6 +95,9 @@
<ClInclude Include="mob.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="navi.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="npc.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@ -226,6 +229,9 @@
<ClCompile Include="mob.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="navi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="npc.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -6,6 +6,8 @@
#include <stdlib.h>
#include <math.h>
#include "../config/core.hpp"
#include "../common/cbasetypes.hpp"
#include "../common/cli.hpp"
#include "../common/core.hpp"
@ -41,6 +43,7 @@
#include "mapreg.hpp"
#include "mercenary.hpp"
#include "mob.hpp"
#include "navi.hpp"
#include "npc.hpp"
#include "party.hpp"
#include "path.hpp"
@ -4868,7 +4871,9 @@ void do_final(void){
do_final_battle();
do_final_chrif();
do_final_clan();
#ifndef GENERATE_NAVI
do_final_clif();
#endif
do_final_npc();
do_final_quest();
do_final_achievement();
@ -5203,7 +5208,9 @@ int do_init(int argc, char *argv[])
do_init_instance();
do_init_chrif();
do_init_clan();
#ifndef GENERATE_NAVI
do_init_clif();
#endif
do_init_script();
do_init_itemdb();
do_init_channel();
@ -5235,6 +5242,11 @@ int do_init(int argc, char *argv[])
ShowStatus("Server is '" CL_GREEN "ready" CL_RESET "' and listening on port '" CL_WHITE "%d" CL_RESET "'.\n\n", map_port);
#ifdef GENERATE_NAVI
navi_create_lists();
runflag = CORE_ST_STOP;
#endif
if( runflag != CORE_ST_STOP )
{
shutdown_callback = do_shutdown;

View File

@ -19,6 +19,7 @@
#include "../common/timer.hpp"
#include "../config/core.hpp"
#include "navi.hpp"
#include "script.hpp"
struct npc_data;
@ -812,6 +813,13 @@ struct map_data {
/* speeds up clif_updatestatus processing by causing hpmeter to run only when someone with the permission can view it */
unsigned short hpmeter_visible;
#ifdef GENERATE_NAVI
struct {
std::vector<const struct npc_data *> npcs;
std::vector<const struct navi_link *> warps_into;
std::vector<const struct navi_link *> warps_outof;
} navi;
#endif
};
/// Stores information about a remote map (for multi-mapserver setups).

649
src/map/navi.cpp Normal file
View File

@ -0,0 +1,649 @@
#include "../config/core.hpp"
#ifdef GENERATE_NAVI
#include <sys/stat.h>
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <chrono>
#include <queue>
#include <vector>
#include "../common/db.hpp"
#include "../common/showmsg.hpp"
#include "../common/malloc.hpp"
#include "map.hpp"
#include "mob.hpp"
#include "navi.hpp"
#include "npc.hpp"
#include "path.hpp"
std::string filePrefix = "generated/clientside/data/luafiles514/lua files/navigation/";
#define SET_OPEN 0
#define SET_CLOSED 1
#define PATH_DIR_NORTH 1
#define PATH_DIR_WEST 2
#define PATH_DIR_SOUTH 4
#define PATH_DIR_EAST 8
// @name Structures and defines for A* pathfinding
// @{
// Path node
struct path_node {
struct path_node *parent; // pointer to parent
short x; // x coord
short y; // y coord
short g_cost; // Actual cost from start to this node
short f_cost; // g_cost + heuristic(this, goal)
short flag; // SET_OPEN / SET_CLOSED
};
/// Binary heap of path nodes
BHEAP_STRUCT_DECL(node_heap, struct path_node*);
static BHEAP_STRUCT_VAR(node_heap, g_open_set); // use static heap for all path calculations
// it get's initialized in do_init_path, freed in do_final_path.
/// Comparator for binary heap of path nodes (minimum cost at top)
#define NODE_MINTOPCMP(i,j) ((i)->f_cost - (j)->f_cost)
#define calc_index(x,y) (((x)+(y)*MAX_WALKPATH_NAVI) & (MAX_WALKPATH_NAVI*MAX_WALKPATH_NAVI-1))
/// Estimates the cost from (x0,y0) to (x1,y1).
/// This is inadmissible (overestimating) heuristic used by game client.
#define heuristic(x0, y0, x1, y1) (MOVE_COST * (abs((x1) - (x0)) + abs((y1) - (y0)))) // Manhattan distance
/// @}
// Translates dx,dy into walking direction
static enum directions walk_choices [3][3] =
{
{DIR_NORTHWEST,DIR_NORTH,DIR_NORTHEAST},
{DIR_WEST,DIR_CENTER,DIR_EAST},
{DIR_SOUTHWEST,DIR_SOUTH,DIR_SOUTHEAST},
};
/// @name A* pathfinding related functions
/// @{
/// Pushes path_node to the binary node_heap.
/// Ensures there is enough space in array to store new element.
#define swap_ptrcast_pathnode(a, b) swap_ptrcast(struct path_node *, a, b)
static void heap_push_node(struct node_heap *heap, struct path_node *node)
{
#ifndef __clang_analyzer__ // TODO: Figure out why clang's static analyzer doesn't like this
BHEAP_ENSURE2(*heap, 1, 256, struct path_node **);
BHEAP_PUSH2(*heap, node, NODE_MINTOPCMP, swap_ptrcast_pathnode);
#endif // __clang_analyzer__
}
/// Updates path_node in the binary node_heap.
static int heap_update_node(struct node_heap *heap, struct path_node *node)
{
int i;
ARR_FIND(0, BHEAP_LENGTH(*heap), i, BHEAP_DATA(*heap)[i] == node);
if (i == BHEAP_LENGTH(*heap)) {
ShowError("heap_update_node: node not found\n");
return 1;
}
BHEAP_UPDATE(*heap, i, NODE_MINTOPCMP, swap_ptrcast_pathnode);
return 0;
}
// end 1:1 copy of definitions from path.cpp
// So we don't have to allocate every time, use static structures
static struct path_node tp[MAX_WALKPATH_NAVI * MAX_WALKPATH_NAVI + 1];
static int tpused[MAX_WALKPATH_NAVI * MAX_WALKPATH_NAVI + 1];
/// Path_node processing in A* pathfinding.
/// Adds new node to heap and updates/re-adds old ones if necessary.
static int add_path(struct node_heap *heap, int16 x, int16 y, int g_cost, struct path_node *parent, int h_cost)
{
int i = calc_index(x, y);
if (tpused[i] && tpused[i] == 1 + (x << 16 | y)) { // We processed this node before
if (g_cost < tp[i].g_cost) { // New path to this node is better than old one
// Update costs and parent
tp[i].g_cost = g_cost;
tp[i].parent = parent;
tp[i].f_cost = g_cost + h_cost;
if (tp[i].flag == SET_CLOSED) {
heap_push_node(heap, &tp[i]); // Put it in open set again
}
else if (heap_update_node(heap, &tp[i])) {
return 1;
}
tp[i].flag = SET_OPEN;
}
return 0;
}
if (tpused[i]) // Index is already taken; see `tp` array FIXME for details
return 1;
// New node
tp[i].x = x;
tp[i].y = y;
tp[i].g_cost = g_cost;
tp[i].parent = parent;
tp[i].f_cost = g_cost + h_cost;
tp[i].flag = SET_OPEN;
tpused[i] = 1 + (x << 16 | y);
heap_push_node(heap, &tp[i]);
return 0;
}
///@}
/*==========================================
* path search (from)->(dest)
* wpd: path info will be written here
* cell: type of obstruction to check for
*
* Note: uses global g_open_set, therefore this method can't be called in parallel or recursivly.
*------------------------------------------*/
bool navi_path_search(struct navi_walkpath_data *wpd, const struct navi_pos *from, const struct navi_pos *dest, cell_chk cell) {
register int i, x, y, dx = 0, dy = 0;
struct map_data *mapdata = map_getmapdata(from->m);
struct navi_walkpath_data s_wpd;
if (wpd == NULL)
wpd = &s_wpd; // use dummy output variable
if (from->m != dest->m)
return false;
if (!mapdata->cell)
return false;
//Do not check starting cell as that would get you stuck.
if (from->x < 0 || from->x > mapdata->xs || from->y < 0 || from->y > mapdata->ys /*|| map_getcellp(mapdata,x0,y0,cell)*/)
return false;
// Check destination cell
if (dest->x < 0 || dest->x > mapdata->xs || dest->y < 0 || dest->y > mapdata->ys || map_getcellp(mapdata, dest->x, dest->y, cell))
return false;
if (from->x == dest->x && from->y == dest->y) {
wpd->path_len = 0;
wpd->path_pos = 0;
return true;
}
struct path_node *current, *it;
int xs = mapdata->xs - 1;
int ys = mapdata->ys - 1;
int len = 0;
int j;
// A* (A-star) pathfinding
// We always use A* for finding walkpaths because it is what game client uses.
// Easy pathfinding cuts corners of non-walkable cells, but client always walks around it.
BHEAP_RESET(g_open_set);
memset(tpused, 0, sizeof(tpused));
// Start node
i = calc_index(from->x, from->y);
tp[i].parent = NULL;
tp[i].x = from->x;
tp[i].y = from->y;
tp[i].g_cost = 0;
tp[i].f_cost = heuristic(from->x, from->y, dest->x, dest->y);
tp[i].flag = SET_OPEN;
tpused[i] = 1 + (from->x << 16 | from->y);
heap_push_node(&g_open_set, &tp[i]); // Put start node to 'open' set
for (;;) {
int e = 0; // error flag
// Saves allowed directions for the current cell. Diagonal directions
// are only allowed if both directions around it are allowed. This is
// to prevent cutting corner of nearby wall.
// For example, you can only go NW from the current cell, if you can
// go N *and* you can go W. Otherwise you need to walk around the
// (corner of the) non-walkable cell.
int allowed_dirs = 0;
int g_cost;
if (BHEAP_LENGTH(g_open_set) == 0) {
return false;
}
current = BHEAP_PEEK(g_open_set); // Look for the lowest f_cost node in the 'open' set
BHEAP_POP2(g_open_set, NODE_MINTOPCMP, swap_ptrcast_pathnode); // Remove it from 'open' set
x = current->x;
y = current->y;
g_cost = current->g_cost;
current->flag = SET_CLOSED; // Add current node to 'closed' set
if (x == dest->x && y == dest->y) {
break;
}
if (y < ys && !map_getcellp(mapdata, x, y+1, cell)) allowed_dirs |= PATH_DIR_NORTH;
if (y > 0 && !map_getcellp(mapdata, x, y-1, cell)) allowed_dirs |= PATH_DIR_SOUTH;
if (x < xs && !map_getcellp(mapdata, x+1, y, cell)) allowed_dirs |= PATH_DIR_EAST;
if (x > 0 && !map_getcellp(mapdata, x-1, y, cell)) allowed_dirs |= PATH_DIR_WEST;
#define chk_dir(d) ((allowed_dirs & (d)) == (d))
// Process neighbors of current node
if (chk_dir(PATH_DIR_SOUTH|PATH_DIR_EAST) && !map_getcellp(mapdata, x+1, y-1, cell))
e += add_path(&g_open_set, x+1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y-1, dest->x, dest->y)); // (x+1, y-1) 5
if (chk_dir(PATH_DIR_EAST))
e += add_path(&g_open_set, x+1, y, g_cost + MOVE_COST, current, heuristic(x+1, y, dest->x, dest->y)); // (x+1, y) 6
if (chk_dir(PATH_DIR_NORTH|PATH_DIR_EAST) && !map_getcellp(mapdata, x+1, y+1, cell))
e += add_path(&g_open_set, x+1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y+1, dest->x, dest->y)); // (x+1, y+1) 7
if (chk_dir(PATH_DIR_NORTH))
e += add_path(&g_open_set, x, y+1, g_cost + MOVE_COST, current, heuristic(x, y+1, dest->x, dest->y)); // (x, y+1) 0
if (chk_dir(PATH_DIR_NORTH|PATH_DIR_WEST) && !map_getcellp(mapdata, x-1, y+1, cell))
e += add_path(&g_open_set, x-1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y+1, dest->x, dest->y)); // (x-1, y+1) 1
if (chk_dir(PATH_DIR_WEST))
e += add_path(&g_open_set, x-1, y, g_cost + MOVE_COST, current, heuristic(x-1, y, dest->x, dest->y)); // (x-1, y) 2
if (chk_dir(PATH_DIR_SOUTH|PATH_DIR_WEST) && !map_getcellp(mapdata, x-1, y-1, cell))
e += add_path(&g_open_set, x-1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y-1, dest->x, dest->y)); // (x-1, y-1) 3
if (chk_dir(PATH_DIR_SOUTH))
e += add_path(&g_open_set, x, y-1, g_cost + MOVE_COST, current, heuristic(x, y-1, dest->x, dest->y)); // (x, y-1) 4
#undef chk_dir
if (e) {
return false;
}
}
for (it = current; it->parent != NULL; it = it->parent, len++);
if (len > sizeof(wpd->path)) {
return false;
}
// Recreate path
wpd->path_len = len;
wpd->path_pos = 0;
for (it = current, j = len-1; j >= 0; it = it->parent, j--) {
dx = it->x - it->parent->x;
dy = it->y - it->parent->y;
wpd->path[j] = walk_choices[-dy + 1][dx + 1];
}
return true;
}
bool fileExists(const std::string& path) {
std::ifstream in;
in.open(path);
if (in.is_open()) {
in.close();
return true;
} else {
return false;
}
}
void write_header(std::ostream &os, std::string name) {
os << name << " = {\n";
}
void write_footer(std::ostream &os) {
os << "}\n";
}
// 5001 = normal, 5002 = airport/airship, 5003 = indoor maps
// 5001 = default
// 5002 = airport/airship
// 5003 = maps that are segmented
// 5005 = 5003 + monsters??? i really have no clue
// maybe it's maps that you must leave to reach parts of it
// for example, ptr_fild04?
int map_type(const struct map_data * m) {
bool segmented = false;
bool has_mob = false;
if (strstr(m->name, "air"))
return 5002;
// this is n^2, yikes!
if (std::find_if(m->navi.warps_outof.begin(), m->navi.warps_outof.end(), [&m](const navi_link* link) {
return std::find_if(m->navi.warps_outof.begin(), m->navi.warps_outof.end(), [&link](const navi_link* link2) {
// find if any two warps in a map cannot be reached
return !navi_path_search(nullptr, &link->pos, &link2->pos, CELL_CHKNOREACH);
}) != m->navi.warps_into.end();
}) != m->navi.warps_into.end())
segmented = true;
if (m->moblist[0] != nullptr) {
has_mob = true;
}
if (segmented && has_mob) {
return 5005;
} else if (segmented) {
return 5003;
}
return 5001;
}
void write_map(std::ostream& os, const struct map_data * m) {
os << "\t{\"" << m->name << "\", \"" << m->name << "\", ";
os << map_type(m) << ", " << m->xs << ", " << m->ys << "},\n";
}
void write_warp(std::ostream& os, const struct navi_link &nl) {
const struct map_data *msrc, *mdest;
msrc = map_getmapdata(nl.pos.m);
mdest = map_getmapdata(nl.warp_dest.m);
if (msrc == nullptr || mdest == nullptr)
return;
os << "\t{";
os << "\"" << msrc->name << "\", ";
os << nl.id << ", "; // gid
// 200 = warp , 201 = npc script, 202 = Kafra Dungeon Warp,
// 203 = Cool Event Dungeon Warp, 204 Kafra/Cool Event/Alberta warp,
// 205 = airport (currently we only support warps)
os << ((nl.npc->subtype == NPCTYPE_WARP) ? 200 : 201) << ", ";
// sprite id, 99999 = warp portal
os << ((nl.npc->vd.class_ == JT_WARPNPC) ? 99999 : (int)nl.npc->vd.class_) << ", ";
if (nl.name.empty())
os << "\"" << msrc->name << "_" << mdest->name << "_" << nl.id << "\", ";
else
os << "\"" << nl.name << "\", ";
os << "\"\", "; // unique name
os << nl.pos.x << ", " << nl.pos.y << ", ";
os << "\"" << mdest->name << "\", ";
os << nl.warp_dest.x << ", " << nl.warp_dest.y;
os << "},\n";
}
void write_npc(std::ostream &os, const struct npc_data *nd) {
if (nd == nullptr) {
ShowError("Unable to find NPC ID for NPC '%s'. Skipping...\n", nd->exname);
return;
}
std::string name = nd->name;
std::string visible_name = name.substr(0, name.find('#'));
const struct map_data *m;
m = map_getmapdata(nd->navi.pos.m);
os << "\t{ ";
os << "\"" << m->name << "\", ";
os << nd->navi.id << ", ";
os << ((nd->subtype == NPCTYPE_SHOP || nd->subtype == NPCTYPE_CASHSHOP) ? 102 : 101) << ", ";
os << nd->class_ << ", ";
os << "\"" << visible_name << "\", ";
os << "\"\", ";
os << nd->navi.pos.x << ", " << nd->navi.pos.y;
os << "},\n";
}
void write_spawn(std::ostream &os, const struct map_data * m, const std::shared_ptr<s_mob_db> mobinfo, int amount, int idx) {
os << "\t{";
os << "\"" << m->name << "\", ";
os << "" << idx << ", ";
os << "" << (mobinfo->mexp ? 301 : 300) << ", ";
#if PACKETVER >= 20140000
os << "" << (amount << 16 | (mobinfo->vd.class_ & 0xFFFF)) << ", ";
#else
os << "\t\t" << mobinfo->vd.class_ << ", ";
#endif
os << "\"" << mobinfo->jname.c_str() << "\", "; //c_str'ed because the strings have been resized to 24
os << "\"" << mobinfo->sprite.c_str() << "\", ";
os << "" << mobinfo->lv << ", ";
os << "" <<
(((mobinfo->status.ele_lv * 20 + mobinfo->status.def_ele) << 16)
| (mobinfo->status.size << 8)
| mobinfo->status.race);
os << "},\n";
}
void write_object_lists() {
auto mob_file = std::ofstream(filePrefix + "./navi_mob_krpri.lub");
auto links_file = std::ofstream(filePrefix + "./navi_link_krpri.lub");
auto npc_file = std::ofstream(filePrefix + "./navi_npc_krpri.lub");
auto map_file = std::ofstream(filePrefix + "./navi_map_krpri.lub");
int warp_count = 0;
int npc_count = 0;
int spawn_count = 0;
write_header(links_file, "Navi_Link");
write_header(npc_file, "Navi_Npc");
write_header(mob_file, "Navi_Mob");
write_header(map_file, "Navi_Map");
for (int mapid = 0; mapid < map_num; mapid++) {
auto m = map_getmapdata(mapid);
// Warps/NPCs
for (int npcidx = 0; npcidx < m->npc_num; npcidx++) {
struct npc_data *nd = m->npc[npcidx];
if (nd == nullptr)
continue;
if (nd->subtype == NPCTYPE_WARP) {
int target = nd->navi.warp_dest.m;
if (target < 0)
continue;
nd->navi.id = 13350 + warp_count++;
write_warp(links_file, nd->navi);
m->navi.warps_outof.push_back(&nd->navi);
map[target].navi.warps_into.push_back(&nd->navi);
} else { // Other NPCs
if (nd->class_ == -1 || nd->class_ == JT_HIDDEN_NPC
|| nd->class_ == JT_HIDDEN_WARP_NPC || nd->class_ == JT_GUILD_FLAG
|| nd->navi.hidden)
continue;
nd->navi.id = 11984 + npc_count;
write_npc(npc_file, nd);
m->navi.npcs.push_back(nd);
for (auto &link : nd->links) {
int target = link.warp_dest.m;
if (target < 0)
continue;
link.id = 13350 + warp_count++;
write_warp(links_file, link);
m->navi.warps_outof.push_back(&link);
map[target].navi.warps_into.push_back(&link);
}
npc_count++;
}
}
// Mobs
for (int mobidx = 0; mobidx < MAX_MOB_LIST_PER_MAP; mobidx++) {
if (m->moblist[mobidx] == nullptr)
continue;
const auto mobinfo = mob_db.find(m->moblist[mobidx]->id);
if (mobinfo == nullptr)
continue;
write_spawn(mob_file, m, mobinfo, m->moblist[mobidx]->num, 17104 + spawn_count);
spawn_count++;
}
write_map(map_file, m);
}
ShowStatus("Generated %d maps\n", map_num);
ShowStatus("Generated %d npcs\n", npc_count);
ShowStatus("Generated %d mobs\n", spawn_count);
ShowStatus("Generated %d links\n", warp_count);
write_footer(map_file);
write_footer(links_file);
write_footer(npc_file);
write_footer(mob_file);
}
void write_map_header(std::ostream &os, const struct map_data * m) {
os << "\t\"" << m->name << "\", " << m->navi.npcs.size() << ",\n";
os << "\t{\n";
}
/*
Given an NPC in a map (nd)
For every warp into the map (warp)
Find a path from nd to warp
*/
void write_npc_distance(std::ostream &os, const struct npc_data * nd, const struct map_data * msrc) {
os << "\t\t{ " << nd->navi.id << ", -- (" << nd->name << " " << msrc->name << ", " << nd->navi.pos.x << ", " << nd->navi.pos.y << ")\n";
for (const auto warp : msrc->navi.warps_into) {
struct navi_walkpath_data wpd = {0};
auto mdest = map_getmapdata(warp->pos.m);
// Find a path from the npc to the warp destination
// The warp is into the map, so this makes sense
if (!navi_path_search(&wpd, &nd->navi.pos, &warp->warp_dest, CELL_CHKNOREACH)) {
continue;
}
os << "\t\t\t{ \"" << mdest->name << "\", " << warp->id << ", " << std::to_string(wpd.path_len) << "}, -- (" << msrc->name << ", " << warp->pos.x << ", " << warp->pos.y << ")\n";
}
os << "\t\t\t{\"\", 0, 0}\n";
os << "\t\t},\n";
}
void write_npc_distances() {
auto dist_npc_file = std::ofstream(filePrefix + "./navi_npcdistance_krpri.lub");
write_header(dist_npc_file, "Navi_NpcDistance");
for (int mapid = 0; mapid < map_num; mapid++) {
auto m = map_getmapdata(mapid);
if (m->navi.npcs.size() == 0) {
// ShowStatus("Skipped %s NPC distance table, no NPCs in map (%d/%d)\n", map[m].name, m, map_num);
continue;
}
if (m->navi.warps_into.size() == 0) {
// ShowStatus("Skipped %s NPC distance table, no warps into map (%d/%d)\n", map[m].name, m, map_num);
continue;
}
write_map_header(dist_npc_file, m);
for (auto nd : m->navi.npcs) {
write_npc_distance(dist_npc_file, nd, m);
}
dist_npc_file << "\t},\n";
}
ShowStatus("Generated NPC Distances for %d maps\n", map_num);
write_footer(dist_npc_file);
}
void write_mapdist_header(std::ostream &os, const struct map_data * m) {
os << "\t\"" << m->name << "\", " << m->navi.warps_outof.size() << ",\n";
os << "\t{\n";
}
/*
Given a warp out of a map (warp1, m)
for every warp out of the map (warp2)
find a path from the warp1->src to warp2->src
Add this as a "P" Warp
for every warp out of warp1->dest.m (warp3)
find a path from warp1->dest to warp3->src
Add this as an "E" Warp
*/
void write_map_distance(std::ostream &os, const struct navi_link * warp1, const struct map_data * m) {
os << "\t\t{ " << warp1->id << ", -- (" << " " << m->name << ", " << warp1->pos.x << ", " << warp1->pos.y << ")\n";
// for (const auto warp2 : m->navi.warps_outof) {
// struct navi_walkpath_data wpd = {0};
// if (warp1 == warp2)
// continue;
// if (!navi_path_search(&wpd, &warp1->pos, &warp2->pos, CELL_CHKNOREACH))
// continue;
// os << "\t\t\t{ \"P\", " << warp2->id << ", " << std::to_string(wpd.path_len) << "}, -- ReachableFromSrc warp (" << m->name << ", " << warp2->pos.x << ", " << warp2->pos.y << ")\n";
// }
for (const auto warp3 : map_getmapdata(warp1->warp_dest.m)->navi.warps_outof) {
struct navi_walkpath_data wpd = {0};
if (!navi_path_search(&wpd, &warp1->warp_dest, &warp3->pos, CELL_CHKNOREACH))
continue;
os << "\t\t\t{ \"E\", " << warp3->id << ", " << std::to_string(wpd.path_len) << "}, -- ReachableFromDst warp (" << map_getmapdata(warp3->pos.m)->name << ", " << warp3->pos.x << ", " << warp3->pos.y << ")\n";
}
os << "\t\t\t{\"NULL\", 0, 0}\n";
os << "\t\t},\n";
}
void write_map_distances() {
auto dist_map_file = std::ofstream(filePrefix + "./navi_linkdistance_krpri.lub");
write_header(dist_map_file, "Navi_Distance");
for (int mapid = 0; mapid < map_num; mapid++) {
const struct map_data * m = map_getmapdata(mapid);
write_mapdist_header(dist_map_file, m);
for (auto nd : m->navi.warps_outof) {
write_map_distance(dist_map_file, nd, m);
}
dist_map_file << "\t},\n";
}
ShowStatus("Generated Map Distances for %d maps\n", map_num);
write_footer(dist_map_file);
}
void navi_create_lists() {
BHEAP_INIT(g_open_set);
auto starttime = std::chrono::system_clock::now();
if (!fileExists(filePrefix)) {
ShowError("File directory %s does not exist.\n", filePrefix.c_str());
ShowInfo("Create the directory and rerun map-server");
exit(1);
}
npc_event_runall(script_config.navi_generate_name);
write_object_lists();
auto currenttime = std::chrono::system_clock::now();
ShowInfo("Object lists took %ums\n", std::chrono::duration_cast<std::chrono::milliseconds>(currenttime - starttime));
starttime = std::chrono::system_clock::now();
write_npc_distances();
currenttime = std::chrono::system_clock::now();
ShowInfo("NPC Distances took %ums\n", std::chrono::duration_cast<std::chrono::milliseconds>(currenttime - starttime));
starttime = std::chrono::system_clock::now();
write_map_distances();
currenttime = std::chrono::system_clock::now();
ShowInfo("Link Distances took %ums\n", std::chrono::duration_cast<std::chrono::milliseconds>(currenttime - starttime));
BHEAP_CLEAR(g_open_set);
}
#endif

43
src/map/navi.hpp Normal file
View File

@ -0,0 +1,43 @@
#ifndef NAVI_H
#define NAVI_H
#include "../config/core.hpp"
#ifdef GENERATE_NAVI
struct navi_pos {
int m;
int x;
int y;
};
struct npc_data;
struct navi_npc {
struct npc_data * npc;
int id;
struct navi_pos pos;
};
struct navi_link {
struct npc_data * npc;
int id;
struct navi_pos pos;
struct navi_pos warp_dest; // only set for warps
bool hidden; // hidden by script
std::string name; // custom name
};
// We need a bigger max path length than stock walkpath
#define MAX_WALKPATH_NAVI 1024
struct navi_walkpath_data {
uint8 path_len, path_pos;
uint8 path[MAX_WALKPATH_NAVI];
};
void navi_create_lists();
#endif // ifdef GENERATE_NAVI
#endif

View File

@ -30,6 +30,7 @@
#include "log.hpp"
#include "map.hpp"
#include "mob.hpp"
#include "navi.hpp"
#include "pc.hpp"
#include "pet.hpp"
#include "script.hpp" // script_config
@ -3715,6 +3716,12 @@ struct npc_data *npc_create_npc(int16 m, int16 x, int16 y){
nd->progressbar.timeout = 0;
nd->vd = npc_viewdb[0]; // Default to JT_INVISIBLE
#ifdef GENERATE_NAVI
nd->navi.pos = {m, x, y};
nd->navi.id = 0;
nd->navi.npc = nd;
#endif
return nd;
}
@ -3834,6 +3841,11 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const
nd->u.warp.y = to_y;
nd->u.warp.xs = xs;
nd->u.warp.ys = ys;
#ifdef GENERATE_NAVI
nd->navi.warp_dest = {map_mapindex2mapid(i), to_x, to_y};
#endif
npc_warp++;
nd->bl.type = BL_NPC;
nd->subtype = NPCTYPE_WARP;

View File

@ -9,11 +9,13 @@
#include "../common/database.hpp"
#include "../common/timer.hpp"
#include "../config/core.hpp"
#include "clif.hpp" //
#include "map.hpp" // struct block_list
#include "status.hpp" // struct status_change
#include "unit.hpp" // struct unit_data
#include "navi.hpp" // navi stuff
struct block_list;
struct npc_data;
@ -205,6 +207,11 @@ struct npc_data {
t_tick timeout;
unsigned long color;
} progressbar;
#ifdef GENERATE_NAVI
struct navi_link navi; // for warps and the src of npcs
std::vector<navi_link> links; // for extra links, like warper npc
#endif
};
struct eri;

View File

@ -306,6 +306,7 @@ struct Script_Config script_config = {
// Instance related
"OnInstanceInit", //instance_init_event_name (is executed right after instance creation)
"OnInstanceDestroy", //instance_destroy_event_name (is executed right before instance destruction)
"OnNaviGenerate", //navi_generate_name (is executed right before navi generation)
};
static jmp_buf error_jump;
@ -25827,7 +25828,38 @@ BUILDIN_FUNC(getenchantgrade){
script_pushint(st, -1);
else
script_pushint(st, sd->inventory.u.items_inventory[index].enchantgrade);
return SCRIPT_CMD_SUCCESS;
}
BUILDIN_FUNC(naviregisterwarp) {
#ifdef GENERATE_NAVI
TBL_NPC* nd;
int x, y, m;
const char *warpname, *mapname=NULL;
struct navi_link link;
nd = map_id2nd(st->oid);
if (!nd) {
return SCRIPT_CMD_SUCCESS;
}
warpname = script_getstr(st, 2);
mapname = script_getstr(st, 3);
x = script_getnum(st,4);
y = script_getnum(st,5);
m = map_mapname2mapid(mapname);
link.npc = nd;
link.id = 0;
link.pos = nd->navi.pos;
link.warp_dest = {m, x, y};
link.name = warpname;
link.hidden = nd->navi.hidden;
nd->links.push_back(link);
#endif
return SCRIPT_CMD_SUCCESS;
}
@ -25875,6 +25907,23 @@ BUILDIN_FUNC( openstylist ){
#endif
}
BUILDIN_FUNC(navihide) {
#ifdef GENERATE_NAVI
TBL_NPC *nd;
nd = map_id2nd(st->oid);
if (!nd) {
return SCRIPT_CMD_SUCCESS;
}
nd->navi.hidden = true;
for (auto &link : nd->links) {
link.hidden = true;
}
#endif
return SCRIPT_CMD_SUCCESS;
}
BUILDIN_FUNC(getitempos) {
struct map_session_data* sd;
@ -26972,6 +27021,10 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(setinstancevar,"rvi"),
BUILDIN_DEF(openstylist, "?"),
// Navigation Generation System
BUILDIN_DEF(naviregisterwarp, "ssii"),
BUILDIN_DEF(navihide, ""),
BUILDIN_DEF(getitempos,""),
BUILDIN_DEF(laphine_synthesis, ""),
BUILDIN_DEF(laphine_upgrade, ""),

View File

@ -211,6 +211,9 @@ struct Script_Config {
// Instance related
const char* instance_init_event_name;
const char* instance_destroy_event_name;
// Navigation related
const char* navi_generate_name;
};
extern struct Script_Config script_config;

123
tools/navi.py Executable file
View File

@ -0,0 +1,123 @@
#!/usr/bin/python3
import re
def parse_setarray(s):
"""
parse setarray
returns list of x,y tuples
"""
# D1: setarray @c[2],261,272,275,270,116,27;
res = re.match(r".*\],(.*);", s)
# print(res.group(1))
spl = res.group(1).split(',')
l = [spl[i:i + 2] for i in range(0, len(spl), 2)]
# print(l)
return l
def parse_disp(s):
"""
parse disp
returns name for all, or list of names for each
"""
# Disp("Comodo Field",1,9);
res = re.match(r""".*"(.*)".*,.*(\d+),(\d+)\).*""", s)
if res:
# print(res.group(1))
# print(res.group(2))
# print(res.group(3))
l = [f"{res.group(1)} {i}" for i in range(int(res.group(2)), int(res.group(3)) + 1)]
# print(l)
return l
res = re.match(r'.*Disp\("(.*)"\);.*', s)
l = res.group(1).split(':')
# print(l)
return l
def parse_pick(s):
"""
parse pick
returns base fld for all, or list of flds for all
"""
if s.count('"') > 2:
# need to return lsit of fields
res = re.match(r'Pick\("",(.*)\).*', s)
# print(res.group(1))
l = res.group(1).split(',')
l = [m[1:-1] for m in l], 0
return l
elif ',' in s:
# need to subtract number
res = re.match(r""".*\("(.*)".*(\d+).*\)""", s)
# print(res.group(1))
return res.group(1), int(res.group(2))
else:
res = re.match(r""".*\("(.*)"\)""", s)
# print(res.group(1))
return res.group(1), 0
def split_disp_pick(s):
"""
returns tuple of <"disp(..)", "pick(...)">
"""
res = re.match(r""".*(Disp\(.*\);).*(Pick\(.*\);).*""", s)
# print(res.group(1))
# print(res.group(2))
return res.group(1), res.group(2)
def gen_mapname(map, i, diff):
"""
take man_fild, 3, 0
output man_fild03
diff is the subtract for gef_fild00
"""
if isinstance(map, str):
i = i + 1 - diff
return f"{map}{'0' if i < 10 else ''}{i}"
elif isinstance(map, list):
return map[i]
else:
raise Exception
def main():
# parse_disp('Disp("Sograt Desert 1:Sograt Desert 2:Sograt Desert 3:Sograt Desert 7:Sograt Desert 11:Sograt Desert 12:Sograt Desert 13:Sograt Desert 16:Sograt Desert 17:Sograt Desert 18:Sograt Desert 19:Sograt Desert 20:Sograt Desert 21:Sograt Desert 22");')
# parse_setarray(
# ' setarray @c[2],219,205,177,206,194,182,224,170,198,216,156,187,185,263,206,228,208,238,209,223,85,97,207,202,31,195,38,195;')
# return
while (1):
setarray = input("input setarray")
disppick = input("input disppick")
poses = parse_setarray(setarray)
disp, pick = split_disp_pick(disppick)
names = parse_disp(disp)
maps, diff = parse_pick(pick)
for i in range(len(poses)):
if i == 1:
print("if (!.OnlyFirstDun) {")
if i > 0:
tabs = " "
else:
tabs = ""
print(
f'{tabs}naviregisterwarp("Warper > {names[i]}", "{gen_mapname(maps, i, diff)}", {poses[i][0]}, {poses[i][1]});')
if i > 0 and i == len(poses) - 1:
print("}")
if __name__ == "__main__":
main()