Added startup scripts

This commit is contained in:
Vladislav Khorev committed 2026-05-09 14:14:04 +03:00
1 parent a479fa4ac1
commit 13ef92160d
26 files changed
+117164 -150

No files matched your search

+1
View File
@@ -174,6 +174,7 @@ set(EMSCRIPTEN_LINK_FLAGS
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start.lua@resources/start.lua" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start.lua@resources/start.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start2.lua@resources/start2.lua" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start2.lua@resources/start2.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_dorm.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../audio@audio" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../audio@audio"
) )
+81
View File
@@ -51,6 +51,87 @@
"positionZ": 0.0, "positionZ": 0.0,
"scale": 1.0, "scale": 1.0,
"interactive": false "interactive": false
},
{
"name": "Bed001",
"texturePath": "resources/w/dorm/ikea_bed_bake002.png",
"meshPath": "resources/w/dorm/ikea_bed001.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 0.0,
"positionY": -0.1,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "Chair001",
"texturePath": "resources/w/dorm/ikea_chair_bake002.png",
"meshPath": "resources/w/dorm/ikea_chair001.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 0.0,
"positionY": -0.1,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "Table001",
"texturePath": "resources/w/dorm/ikea_table_bake003.png",
"meshPath": "resources/w/dorm/ikea_table001.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 0.0,
"positionY": -0.1,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "Phone001",
"texturePath": "resources/w/dorm/phone001_tex001.png",
"meshPath": "resources/w/dorm/phone001.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 5.8729,
"positionY": 1.04917,
"positionZ": -12.5262,
"scale": 1.0,
"interactive": true,
"item": {
"id": "phone",
"name": "Телефон",
"description": "Я не могу себе представить жизнь без своего телефона",
"icon": "resources/fire2.png",
"radius": 0.3
},
"activateFunction" : "on_phone_pickup"
},
{
"name": "Journal001",
"texturePath": "resources/w/dorm/journal001_tex002.png",
"meshPath": "resources/w/dorm/journal001.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 5.05146,
"positionY": 1.06711,
"positionZ": -12.4661,
"scale": 1.0,
"interactive": true,
"item": {
"id": "journal",
"name": "Телефон",
"description": "Это мой журнал куда я вношу свои заметки.",
"icon": "resources/fire2.png",
"radius": 0.3
},
"activateFunction" : "on_journal_pickup"
} }
] ]
} }
+199 -75
View File
@@ -28,25 +28,26 @@
] ]
} }
], ],
"obstacles": [ "obstacles": [
{ {
"name": "editor_obstacle_1", "name": "editor_obstacle_1",
"polygon": [ "polygon": [
[ [
1.4521160125732422, 1.2386366128921509,
-15.647087097167969 -16.910831451416016
], ],
[ [
0.7836513519287109, 1.2082710266113281,
-15.604467391967773 -15.74820327758789
], ],
[ [
0.8457736968994141, 0.9836082458496094,
-17.430662155151367 -15.767669677734375
], ],
[ [
1.3778166770935059, 0.9937065839767456,
-17.40001678466797 -16.89757537841797
] ]
] ]
}, },
@@ -54,20 +55,20 @@
"name": "editor_obstacle_2", "name": "editor_obstacle_2",
"polygon": [ "polygon": [
[ [
1.238701343536377, 1.2371597290039063,
-17.41904640197754 -14.667628288269043
], ],
[ [
1.2542033195495605, 1.0021405220031738,
-16.888349533081055 -14.565974235534668
], ],
[ [
8.557634353637695, 0.8893742561340332,
-16.686010360717773 -11.02865982055664
], ],
[ [
8.580190658569336, 1.2916733026504517,
-17.49493980407715 -11.256534576416016
] ]
] ]
}, },
@@ -75,20 +76,20 @@
"name": "editor_obstacle_3", "name": "editor_obstacle_3",
"polygon": [ "polygon": [
[ [
8.581539154052734, 1.15517258644104,
-17.44879150390625 -16.825780868530273
], ],
[ [
9.2276029586792, 8.42333698272705,
-17.467662811279297 -16.937246322631836
], ],
[ [
9.311224937438965, 8.639735221862793,
-11.442724227905273 -17.410985946655273
], ],
[ [
8.525369644165039, 1.1124024391174316,
-11.465954780578613 -17.468708038330078
] ]
] ]
}, },
@@ -96,20 +97,20 @@
"name": "editor_obstacle_4", "name": "editor_obstacle_4",
"polygon": [ "polygon": [
[ [
8.59122085571289, 1.952521800994873,
-11.583345413208008 -13.470939636230469
], ],
[ [
8.580953598022461, 1.947329044342041,
-11.144271850585938 -13.262446403503418
], ],
[ [
3.9417855739593506, 1.2782373428344727,
-11.05494213104248 -13.2465238571167
], ],
[ [
3.879462718963623, 1.2633711099624634,
-11.607364654541016 -13.548421859741211
] ]
] ]
}, },
@@ -117,20 +118,20 @@
"name": "editor_obstacle_5", "name": "editor_obstacle_5",
"polygon": [ "polygon": [
[ [
4.017904758453369, 2.958512783050537,
-11.611408233642578 -13.523996353149414
], ],
[ [
4.006087303161621, 2.934694528579712,
-13.59709644317627 -13.240300178527832
], ],
[ [
3.777372121810913, 3.9795844554901123,
-13.521135330200195 -13.26203727722168
], ],
[ [
3.7294042110443115, 3.9670143127441406,
-11.210392951965332 -13.51730728149414
] ]
] ]
}, },
@@ -138,20 +139,20 @@
"name": "editor_obstacle_6", "name": "editor_obstacle_6",
"polygon": [ "polygon": [
[ [
2.783853769302368, 3.643568992614746,
-13.538301467895508 -13.285079956054688
], ],
[ [
2.766845703125, 3.648775577545166,
-13.329962730407715 -11.270064353942871
], ],
[ [
3.921206474304199, 3.9994444847106934,
-13.34058952331543 -11.282587051391602
], ],
[ [
3.937540054321289, 3.920609474182129,
-13.572001457214355 -13.174944877624512
] ]
] ]
}, },
@@ -159,20 +160,79 @@
"name": "editor_obstacle_7", "name": "editor_obstacle_7",
"polygon": [ "polygon": [
[ [
2.046168327331543, 1.3403878211975098,
-13.493659019470215 -11.485700607299805
], ],
[ [
2.006760597229004, 8.704232215881348,
-13.261573791503906 -11.600449562072754
], ],
[ [
1.1306328773498535, 8.6791410446167,
-13.21288776397705 -11.190678596496582
], ],
[ [
1.190417766571045, 1.2627182006835938,
-13.537941932678223 -10.95035457611084
]
]
},
{
"name": "editor_obstacle_1",
"polygon": [
[
5.460248947143555,
-16.92827796936035
],
[
5.473773956298828,
-15.50655746459961
],
[
8.639936447143555,
-15.49016284942627
],
[
8.641860961914063,
-17.03392791748047
]
]
},
{
"name": "editor_obstacle_2",
"polygon": [
[
4.033830165863037,
-12.481351852416992
],
[
6.007711887359619,
-12.465056419372559
],
[
6.156071186065674,
-11.502941131591797
],
[
4.018871784210205,
-11.45417594909668
]
]
},
{
"name": "editor_obstacle_3",
"polygon": [
[
3.942854404449463,
-13.410148620605469
],
[
3.99332594871521,
-12.681471824645996
],
[
4.6172685623168945,
-12.7000093460083
] ]
] ]
}, },
@@ -180,42 +240,106 @@
"name": "editor_obstacle_8", "name": "editor_obstacle_8",
"polygon": [ "polygon": [
[ [
1.2021913528442383, 8.662647247314453,
-14.716050148010254 -11.577871322631836
], ],
[ [
1.3182783126831055, 8.59707260131836,
-11.532548904418945 -17.01089096069336
], ],
[ [
1.0644679069519043, 8.989262580871582,
-11.525135040283203 -16.998661041259766
], ],
[ [
0.9918317794799805, 9.054760932922363,
-14.802279472351074 -11.652122497558594
] ]
] ]
}, },
{ {
"name": "editor_obstacle_9", "name": "editor_obstacle_1x",
"polygon": [ "polygon": [
[ [
1.2470345497131348, 2.8632972240448,
-11.599748611450195 -4.288420677185059
], ],
[ [
3.9473354816436768, 2.4562156200408936,
-11.655533790588379 -4.224598407745361
], ],
[ [
3.9574456214904785, 2.397826910018921,
-11.309428215026855 -5.586108684539795
], ],
[ [
1.2795448303222656, 2.843082904815674,
-11.27739143371582 -5.562361717224121
] ]
] ]
}] },
{
"name": "editor_obstacle_2x",
"polygon": [
[
2.669132709503174,
-5.488218307495117
],
[
8.675596237182617,
-5.436037540435791
],
[
8.74371337890625,
-6.103575706481934
],
[
2.6533708572387695,
-6.057576656341553
]
]
},
{
"name": "editor_obstacle_3x",
"polygon": [
[
2.490814208984375,
-2.175637722015381
],
[
2.5649731159210205,
5.601792812347412
],
[
9.002458572387695,
5.9258809089660645
],
[
8.68370532989502,
-2.235023021697998
]
]
},
{
"name": "editor_obstacle_4x",
"polygon": [
[
6.314299583435059,
-2.1619086265563965
],
[
6.418157577514648,
-5.558330535888672
],
[
8.6978759765625,
-5.538100242614746
],
[
8.630842208862305,
-2.2032206058502197
]
]
}
]
} }
@@ -0,0 +1,367 @@
{
"cellSize": 0.1,
"agentRadius": 0.25,
"floorY": 0.0,
"objectPadding": 0.15,
"boundaryPadding": 0.15,
"areas": [
{
"name": "main_corridor",
"available": true,
"polygon": [
[
-100,
100
],
[
100,
100
],
[
100,
-100
],
[
-100,
-100
]
]
}
],
"obstacles": [
{
"name": "editor_obstacle_1",
"polygon": [
[
1.2386366128921509,
-16.910831451416016
],
[
1.2082710266113281,
-15.74820327758789
],
[
0.9836082458496094,
-15.767669677734375
],
[
0.9937065839767456,
-16.89757537841797
]
]
},
{
"name": "editor_obstacle_2",
"polygon": [
[
1.2371597290039063,
-14.667628288269043
],
[
1.0021405220031738,
-14.565974235534668
],
[
0.8893742561340332,
-11.02865982055664
],
[
1.2916733026504517,
-11.256534576416016
]
]
},
{
"name": "editor_obstacle_3",
"polygon": [
[
1.15517258644104,
-16.825780868530273
],
[
8.42333698272705,
-16.937246322631836
],
[
8.639735221862793,
-17.410985946655273
],
[
1.1124024391174316,
-17.468708038330078
]
]
},
{
"name": "editor_obstacle_4",
"polygon": [
[
1.952521800994873,
-13.470939636230469
],
[
1.947329044342041,
-13.262446403503418
],
[
1.2782373428344727,
-13.2465238571167
],
[
1.2633711099624634,
-13.548421859741211
]
]
},
{
"name": "editor_obstacle_5",
"polygon": [
[
2.958512783050537,
-13.523996353149414
],
[
2.934694528579712,
-13.240300178527832
],
[
3.9795844554901123,
-13.26203727722168
],
[
3.9670143127441406,
-13.51730728149414
]
]
},
{
"name": "editor_obstacle_6",
"polygon": [
[
3.643568992614746,
-13.285079956054688
],
[
3.648775577545166,
-11.270064353942871
],
[
3.9994444847106934,
-11.282587051391602
],
[
3.920609474182129,
-13.174944877624512
]
]
},
{
"name": "editor_obstacle_7",
"polygon": [
[
1.3403878211975098,
-11.485700607299805
],
[
8.704232215881348,
-11.600449562072754
],
[
8.6791410446167,
-11.190678596496582
],
[
1.2627182006835938,
-10.95035457611084
]
]
},
{
"name": "editor_obstacle_8",
"polygon": [
[
8.662647247314453,
-11.577871322631836
],
[
8.59707260131836,
-17.01089096069336
],
[
8.989262580871582,
-16.998661041259766
],
[
9.054760932922363,
-11.652122497558594
]
]
},
{
"name": "editor_obstacle_1x",
"polygon": [
[
2.8632972240448,
-4.288420677185059
],
[
2.4562156200408936,
-4.224598407745361
],
[
2.397826910018921,
-5.586108684539795
],
[
2.843082904815674,
-5.562361717224121
]
]
},
{
"name": "editor_obstacle_2x",
"polygon": [
[
2.669132709503174,
-5.488218307495117
],
[
8.675596237182617,
-5.436037540435791
],
[
8.74371337890625,
-6.103575706481934
],
[
2.6533708572387695,
-6.057576656341553
]
]
},
{
"name": "editor_obstacle_3x",
"polygon": [
[
2.490814208984375,
-2.175637722015381
],
[
2.5649731159210205,
5.601792812347412
],
[
9.002458572387695,
5.9258809089660645
],
[
8.68370532989502,
-2.235023021697998
]
]
},
{
"name": "editor_obstacle_4x",
"polygon": [
[
6.314299583435059,
-2.1619086265563965
],
[
6.418157577514648,
-5.558330535888672
],
[
8.6978759765625,
-5.538100242614746
],
[
8.630842208862305,
-2.2032206058502197
]
]
},
{
"name": "editor_obstacle_1",
"polygon": [
[
5.460248947143555,
-16.92827796936035
],
[
5.473773956298828,
-15.50655746459961
],
[
8.639936447143555,
-15.49016284942627
],
[
8.641860961914063,
-17.03392791748047
]
]
},
{
"name": "editor_obstacle_2",
"polygon": [
[
4.033830165863037,
-12.481351852416992
],
[
6.007711887359619,
-12.465056419372559
],
[
6.156071186065674,
-11.502941131591797
],
[
4.018871784210205,
-11.45417594909668
]
]
},
{
"name": "editor_obstacle_3",
"polygon": [
[
3.942854404449463,
-13.410148620605469
],
[
3.99332594871521,
-12.681471824645996
],
[
4.6172685623168945,
-12.7000093460083
]
]
},
{
"name": "dialog_start_block001",
"polygon": [
[
0.9441208839416504,
-14.674051284790039
],
[
1.351646900177002,
-14.717156410217285
],
[
1.3264522552490234,
-15.757955551147461
],
[
0.9525976181030273,
-15.736042976379395
]
]
}
]
}
+4
View File
@@ -0,0 +1,4 @@
{
"trigger_zones": [
]
}
+4
View File
@@ -0,0 +1,4 @@
{
"trigger_zones": [
]
}
+22
View File
@@ -0,0 +1,22 @@
{
"trigger_zones": [
{
"id": "pickup_phone_zone001",
"positionX": 2.54938,
"positionY": 0.0,
"positionZ": -15.2422,
"radius": 1.0,
"hysteresis": 0.1,
"enabled": true
},
{
"id": "ladder_zone001",
"positionX": 3.7569,
"positionY": 0.0,
"positionZ": -3.50058,
"radius": 2.0,
"hysteresis": 0.1,
"enabled": true
}
]
}
+54
View File
@@ -25,6 +25,60 @@
"type": "End" "type": "End"
} }
] ]
},
{
"id": "dialog_phone001",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Бекзат",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Я не буду никуда идти без своего телефона и записной книжки!",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "dialog_phone_pickup001",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Бекзат",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Отлично, вот и мой телефон! Надо проверить новые сообщения.",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "dialog_journal_pickup001",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Бекзат",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Возьму журнал с собой! Там все мои записи.",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
}, },
{ {
"id": "dialog_taxi001", "id": "dialog_taxi001",
+44
View File
@@ -14,4 +14,48 @@ step1()
game_api.start_dialogue("dialog_start001") game_api.start_dialogue("dialog_start001")
phone_picked_up = false
journal_picked_up = false
function on_phone_pickup()
game_api.pickup_item("phone")
game_api.start_dialogue("dialog_phone_pickup001")
phone_picked_up = true
end
function on_journal_pickup()
game_api.pickup_item("journal")
game_api.start_dialogue("dialog_journal_pickup001")
journal_picked_up = true
end
function pickup_phone_zone001_enter_callback()
print("pickup_phone_zone001_enter_callback--!")
if (not phone_picked_up) or (not journal_picked_up) then
game_api.start_dialogue("dialog_phone001")
game_api.switch_navigation(1)
end
end
function pickup_phone_zone001_exit_callback()
print("pickup_phone_zone001_exit_callback--!")
game_api.switch_navigation(0)
end
game_api.set_trigger_zone_callbacks("pickup_phone_zone001",
pickup_phone_zone001_enter_callback,
pickup_phone_zone001_exit_callback
)
function ladder_zone001_enter_callback()
game_api.start_dialogue("dialog_second_floor001")
end
game_api.set_trigger_zone_callbacks("ladder_zone001",
ladder_zone001_enter_callback,
nil
)
print("Lua script loaded successfully--!") print("Lua script loaded successfully--!")
File diff suppressed because it is too large. Load diff
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
===Vertices (Split by UV/Normal): 24
V 0: Pos(0.26, 0.15, 0.02) Norm(0.577351, 0.57735, 0.57735) UV(0.944444, 0.416667)
V 1: Pos(0.26, -0.15, -0.02) Norm(0.577351, -0.57735, -0.57735) UV(1.0, 0.0)
V 2: Pos(0.26, 0.15, -0.02) Norm(0.577349, 0.577358, -0.577343) UV(1.0, 0.416667)
V 3: Pos(0.26, -0.15, 0.02) Norm(0.577349, -0.577358, 0.577343) UV(0.833333, 0.722223)
V 4: Pos(-0.26, -0.15, -0.02) Norm(-0.577349, -0.577358, -0.577343) UV(0.888889, 0.0)
V 5: Pos(0.26, -0.15, -0.02) Norm(0.577351, -0.57735, -0.57735) UV(0.888889, 0.722223)
V 6: Pos(-0.26, -0.15, 0.02) Norm(-0.577351, -0.57735, 0.57735) UV(0.944444, 0.833334)
V 7: Pos(-0.26, 0.15, -0.02) Norm(-0.577351, 0.57735, -0.57735) UV(1.0, 0.416667)
V 8: Pos(-0.26, -0.15, -0.02) Norm(-0.577349, -0.577358, -0.577343) UV(1.0, 0.833334)
V 9: Pos(-0.26, 0.15, 0.02) Norm(-0.577349, 0.577358, 0.577343) UV(0.888889, 0.722223)
V 10: Pos(0.26, 0.15, -0.02) Norm(0.577349, 0.577358, -0.577343) UV(0.944445, 0.0)
V 11: Pos(-0.26, 0.15, -0.02) Norm(-0.577351, 0.57735, -0.57735) UV(0.944444, 0.722223)
V 12: Pos(-0.26, -0.15, -0.02) Norm(-0.577349, -0.577358, -0.577343) UV(0.0, 0.0)
V 13: Pos(0.26, 0.15, -0.02) Norm(0.577349, 0.577358, -0.577343) UV(0.416667, 0.722223)
V 14: Pos(0.26, -0.15, -0.02) Norm(0.577351, -0.57735, -0.57735) UV(-0.0, 0.722223)
V 15: Pos(0.26, -0.15, 0.02) Norm(0.577349, -0.577358, 0.577343) UV(0.416667, 0.0)
V 16: Pos(-0.26, 0.15, 0.02) Norm(-0.577349, 0.577358, 0.577343) UV(0.833333, 0.722223)
V 17: Pos(-0.26, -0.15, 0.02) Norm(-0.577351, -0.57735, 0.57735) UV(0.416667, 0.722223)
V 18: Pos(0.26, -0.15, 0.02) Norm(0.577349, -0.577358, 0.577343) UV(0.944445, 0.0)
V 19: Pos(-0.26, -0.15, 0.02) Norm(-0.577351, -0.57735, 0.57735) UV(0.833334, 0.0)
V 20: Pos(-0.26, 0.15, 0.02) Norm(-0.577349, 0.577358, 0.577343) UV(0.944444, 0.416667)
V 21: Pos(0.26, 0.15, 0.02) Norm(0.577351, 0.57735, 0.57735) UV(0.888889, 0.0)
V 22: Pos(-0.26, 0.15, -0.02) Norm(-0.577351, 0.57735, -0.57735) UV(0.416667, 0.0)
V 23: Pos(0.26, 0.15, 0.02) Norm(0.577351, 0.57735, 0.57735) UV(0.833334, 0.0)
===Triangles (Indices): 12
Tri: 0 1 2
Tri: 3 4 5
Tri: 6 7 8
Tri: 9 10 11
Tri: 12 13 14
Tri: 15 16 17
Tri: 0 18 1
Tri: 3 19 4
Tri: 6 20 7
Tri: 9 21 10
Tri: 12 22 13
Tri: 15 23 16
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
===Vertices (Split by UV/Normal): 24
V 0: Pos(0.180001, 0.08, 0.02) Norm(0.577335, 0.577358, 0.577358) UV(0.909091, 0.363636)
V 1: Pos(0.180001, -0.08, -0.02) Norm(0.577335, -0.577358, -0.577358) UV(1.0, 0.0)
V 2: Pos(0.180001, 0.08, -0.02) Norm(0.577357, 0.577362, -0.577332) UV(1.0, 0.363636)
V 3: Pos(0.180001, -0.08, 0.02) Norm(0.577357, -0.577362, 0.577332) UV(0.727273, 0.818184)
V 4: Pos(-0.179999, -0.08, -0.02) Norm(-0.577357, -0.577362, -0.577332) UV(0.818182, 0.0)
V 5: Pos(0.180001, -0.08, -0.02) Norm(0.577335, -0.577358, -0.577358) UV(0.818182, 0.818184)
V 6: Pos(-0.179999, -0.08, 0.02) Norm(-0.577335, -0.577358, 0.577358) UV(0.909091, 0.727273)
V 7: Pos(-0.179999, 0.08, -0.02) Norm(-0.577335, 0.577358, -0.577358) UV(1.0, 0.363636)
V 8: Pos(-0.179999, -0.08, -0.02) Norm(-0.577357, -0.577362, -0.577332) UV(1.0, 0.727273)
V 9: Pos(-0.179999, 0.08, 0.02) Norm(-0.577357, 0.577362, 0.577332) UV(0.818182, 0.818184)
V 10: Pos(0.180001, 0.08, -0.02) Norm(0.577357, 0.577362, -0.577332) UV(0.909091, 0.0)
V 11: Pos(-0.179999, 0.08, -0.02) Norm(-0.577335, 0.577358, -0.577358) UV(0.909091, 0.818184)
V 12: Pos(-0.179999, -0.08, -0.02) Norm(-0.577357, -0.577362, -0.577332) UV(0.0, 0.0)
V 13: Pos(0.180001, 0.08, -0.02) Norm(0.577357, 0.577362, -0.577332) UV(0.363636, 0.818184)
V 14: Pos(0.180001, -0.08, -0.02) Norm(0.577335, -0.577358, -0.577358) UV(-0.0, 0.818184)
V 15: Pos(0.180001, -0.08, 0.02) Norm(0.577357, -0.577362, 0.577332) UV(0.363636, 0.0)
V 16: Pos(-0.179999, 0.08, 0.02) Norm(-0.577357, 0.577362, 0.577332) UV(0.727273, 0.818184)
V 17: Pos(-0.179999, -0.08, 0.02) Norm(-0.577335, -0.577358, 0.577358) UV(0.363636, 0.818184)
V 18: Pos(0.180001, -0.08, 0.02) Norm(0.577357, -0.577362, 0.577332) UV(0.909091, 0.0)
V 19: Pos(-0.179999, -0.08, 0.02) Norm(-0.577335, -0.577358, 0.577358) UV(0.727273, 0.0)
V 20: Pos(-0.179999, 0.08, 0.02) Norm(-0.577357, 0.577362, 0.577332) UV(0.909091, 0.363636)
V 21: Pos(0.180001, 0.08, 0.02) Norm(0.577335, 0.577358, 0.577358) UV(0.818182, 0.0)
V 22: Pos(-0.179999, 0.08, -0.02) Norm(-0.577335, 0.577358, -0.577358) UV(0.363636, 0.0)
V 23: Pos(0.180001, 0.08, 0.02) Norm(0.577335, 0.577358, 0.577358) UV(0.727273, 0.0)
===Triangles (Indices): 12
Tri: 0 1 2
Tri: 3 4 5
Tri: 6 7 8
Tri: 9 10 11
Tri: 12 13 14
Tri: 15 16 17
Tri: 0 18 1
Tri: 3 19 4
Tri: 6 20 7
Tri: 9 21 10
Tri: 12 22 13
Tri: 15 23 16
Binary file not shown.
+9 -8
View File
@@ -164,8 +164,9 @@ namespace ZL
params1.gameObjectsJsonPath = "resources/config2/gameobjects.json"; params1.gameObjectsJsonPath = "resources/config2/gameobjects.json";
params1.npcsJsonPath = "resources/config2/npcs.json"; params1.npcsJsonPath = "resources/config2/npcs.json";
params1.dialoguesJsonPath = "resources/dialogue/sample_dialogues.json"; params1.dialoguesJsonPath = "resources/dialogue/sample_dialogues.json";
params1.navigationJsonPath = "resources/config2/navigation.json"; params1.navigationJsonPaths = {"resources/config2/navigation.json"};
params1.teleportsJsonPath = "resources/config2/teleports.json"; params1.teleportsJsonPath = "resources/config2/teleports.json";
params1.triggerZonesJsonPath = "resources/config2/trigger_zones.json";
params1.scriptPath = "resources/start.lua"; params1.scriptPath = "resources/start.lua";
params1.playerPosition = Eigen::Vector3f(0.942694, 0, -9.63104); params1.playerPosition = Eigen::Vector3f(0.942694, 0, -9.63104);
@@ -176,8 +177,9 @@ namespace ZL
params2.roomMeshPath = "resources/w/exterior/Segmented_Plane002.txt"; params2.roomMeshPath = "resources/w/exterior/Segmented_Plane002.txt";
params2.roomTexturePath = "resources/w/exterior/Segmented_Plane002.png"; params2.roomTexturePath = "resources/w/exterior/Segmented_Plane002.png";
params2.gameObjectsJsonPath = "resources/config2/gameobjects2.json"; params2.gameObjectsJsonPath = "resources/config2/gameobjects2.json";
params2.navigationJsonPath = "resources/config2/navigation2.json"; params2.navigationJsonPaths = {"resources/config2/navigation2.json"};
params2.teleportsJsonPath = "resources/config2/teleports2.json"; params2.teleportsJsonPath = "resources/config2/teleports2.json";
params2.triggerZonesJsonPath = "resources/config2/trigger_zones2.json";
params2.scriptPath = "resources/start2.lua"; params2.scriptPath = "resources/start2.lua";
params2.playerPosition = Eigen::Vector3f(5, 0, -18.4); params2.playerPosition = Eigen::Vector3f(5, 0, -18.4);
params2.npcsJsonPath = "resources/config2/npcs2.json"; params2.npcsJsonPath = "resources/config2/npcs2.json";
@@ -191,11 +193,11 @@ namespace ZL
params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm.json"; params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm.json";
params_dorm.npcsJsonPath = "resources/config2/npcs_dorm.json"; params_dorm.npcsJsonPath = "resources/config2/npcs_dorm.json";
params_dorm.dialoguesJsonPath = "resources/dialogue/dorm_dialogues.json"; params_dorm.dialoguesJsonPath = "resources/dialogue/dorm_dialogues.json";
params_dorm.navigationJsonPath = "resources/config2/navigation_dorm.json"; params_dorm.navigationJsonPaths = {"resources/config2/navigation_dorm.json", "resources/config2/navigation_dorm_tutorial001.json" };
params_dorm.teleportsJsonPath = "resources/config2/teleports_dorm.json"; params_dorm.teleportsJsonPath = "resources/config2/teleports_dorm.json";
params_dorm.triggerZonesJsonPath = "resources/config2/trigger_zones_dorm.json";
params_dorm.scriptPath = "resources/start_dorm.lua"; params_dorm.scriptPath = "resources/start_dorm.lua";
params_dorm.playerPosition = Eigen::Vector3f(6.0357, 0, -16.0581); params_dorm.playerPosition = Eigen::Vector3f(6.76345, 0, -14.6022);
locations["location_dorm"] = std::make_shared<Location>(renderer, inventory); locations["location_dorm"] = std::make_shared<Location>(renderer, inventory);
locations["location_dorm"]->setup(params_dorm); locations["location_dorm"]->setup(params_dorm);
@@ -534,15 +536,14 @@ namespace ZL
case SDLK_o: case SDLK_o:
//y = y + 0.002; //y = y + 0.002;
//currentLocation->player->hp = 200; //currentLocation->player->hp = 200;
currentLocation->npcs[0]->walkSpeed += 0.02f; currentLocation->npcs[0]->walkSpeed += 0.01f;
std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl; std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl;
break; break;
case SDLK_k: case SDLK_k:
//y = y - 0.002; //y = y - 0.002;
std::cout << "Player pos: " << currentLocation->player->position.transpose() << std::endl; std::cout << "Player pos: " << currentLocation->player->position.transpose() << std::endl;
currentLocation->npcs[0]->walkSpeed -= 0.02f; currentLocation->npcs[0]->walkSpeed -= 0.01f;
std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl; std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl;
break; break;
+120 -22
View File
@@ -137,6 +137,7 @@ namespace ZL
} }
loadTeleportZones(params.teleportsJsonPath, CONST_ZIP_FILE); loadTeleportZones(params.teleportsJsonPath, CONST_ZIP_FILE);
loadTriggerZones(params.triggerZonesJsonPath, CONST_ZIP_FILE);
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
// Create shadow map (2048x2048, ortho size 40, near 0.1, far 100) // Create shadow map (2048x2048, ortho size 40, near 0.1, far 100)
@@ -145,7 +146,7 @@ namespace ZL
std::cout << "Shadow map initialized" << std::endl; std::cout << "Shadow map initialized" << std::endl;
#endif #endif
setupNavigation(params.navigationJsonPath); setupNavigation(params.navigationJsonPaths);
dialogueSystem.init(renderer, CONST_ZIP_FILE); dialogueSystem.init(renderer, CONST_ZIP_FILE);
dialogueSystem.loadDatabase(params.dialoguesJsonPath); dialogueSystem.loadDatabase(params.dialoguesJsonPath);
@@ -165,7 +166,7 @@ namespace ZL
false false
});*/ });*/
navigationEditorConfigPath = params.navigationJsonPath; // navigationMapPaths is already populated by setupNavigation
scriptEngine.init(this, &inventory, params.scriptPath); scriptEngine.init(this, &inventory, params.scriptPath);
@@ -231,13 +232,84 @@ namespace ZL
std::cout << "[TELEPORT] Loaded " << teleportZones.size() << " teleport(s) from " << jsonPath << std::endl; std::cout << "[TELEPORT] Loaded " << teleportZones.size() << " teleport(s) from " << jsonPath << std::endl;
} }
void Location::setupNavigation(const std::string& navigationJsonPath) void Location::loadTriggerZones(const std::string& jsonPath, const char* zipFile)
{ {
// Static navigation blockers are defined in the navigation JSON as polygons. if (jsonPath.empty()) return;
// NPC + player are handled as dynamic obstacles, so they are intentionally NOT in JSON.
navigation.build({}, navigationJsonPath, CONST_ZIP_FILE);
if (navigationEditorMode) { std::string content;
try {
if (!zipFile || zipFile[0] == '\0') {
content = readTextFile(jsonPath);
} else {
auto buf = readFileFromZIP(jsonPath, zipFile);
if (buf.empty()) {
std::cerr << "[TRIGGER] Failed to read " << jsonPath << " from zip" << std::endl;
return;
}
content.assign(buf.begin(), buf.end());
}
} catch (const std::exception& e) {
std::cerr << "[TRIGGER] Failed to open " << jsonPath << ": " << e.what() << std::endl;
return;
}
using json = nlohmann::json;
json j;
try {
j = json::parse(content);
} catch (const std::exception& e) {
std::cerr << "[TRIGGER] JSON parse error in " << jsonPath << ": " << e.what() << std::endl;
return;
}
if (!j.contains("trigger_zones") || !j["trigger_zones"].is_array()) return;
for (const auto& item : j["trigger_zones"]) {
TriggerZone tz;
tz.id = item.value("id", "");
tz.enabled = item.value("enabled", true);
tz.radius = item.value("radius", 1.5f);
tz.hysteresis = item.value("hysteresis", 0.3f);
tz.position = Eigen::Vector3f(
item.value("positionX", 0.0f),
item.value("positionY", 0.0f),
item.value("positionZ", 0.0f)
);
triggerZones.push_back(std::move(tz));
}
std::cout << "[TRIGGER] Loaded " << triggerZones.size() << " trigger zone(s) from " << jsonPath << std::endl;
}
void Location::updateTriggerZones(const Eigen::Vector3f& playerPos)
{
for (auto& tz : triggerZones) {
if (!tz.enabled) continue;
const float dist = (playerPos - tz.position).norm();
if (!tz.playerInside && dist <= tz.radius) {
tz.playerInside = true;
scriptEngine.callTriggerEnterCallback(tz.id);
} else if (tz.playerInside && dist > tz.radius + tz.hysteresis) {
tz.playerInside = false;
scriptEngine.callTriggerExitCallback(tz.id);
}
}
}
void Location::setupNavigation(const std::vector<std::string>& paths)
{
navigationMapPaths = paths;
navigationMaps.clear();
navigationMaps.resize(paths.size());
for (size_t i = 0; i < paths.size(); ++i) {
navigationMaps[i].build({}, paths[i], CONST_ZIP_FILE);
}
activeNavigationIndex = 0;
navigation = navigationMaps.empty() ? nullptr : &navigationMaps[0];
if (navigationEditorMode && navigation) {
navigationEditorBuildNavMeshes(); navigationEditorBuildNavMeshes();
} }
@@ -245,6 +317,7 @@ namespace ZL
auto makePlanner = [this](const Character* self) { auto makePlanner = [this](const Character* self) {
return [this, self](const Eigen::Vector3f& start, const Eigen::Vector3f& end) { return [this, self](const Eigen::Vector3f& start, const Eigen::Vector3f& end) {
if (!navigation) return std::vector<Eigen::Vector3f>{};
std::vector<PathFinder::DynamicObstacle> dynamicObstacles; std::vector<PathFinder::DynamicObstacle> dynamicObstacles;
dynamicObstacles.reserve(npcs.size() + 1); dynamicObstacles.reserve(npcs.size() + 1);
@@ -257,7 +330,7 @@ namespace ZL
} }
PathFinder::DynamicObstacle obs; PathFinder::DynamicObstacle obs;
obs.position = Eigen::Vector3f(other->position.x(), navigation.getFloorY(), other->position.z()); obs.position = Eigen::Vector3f(other->position.x(), navigation->getFloorY(), other->position.z());
obs.radius = (std::max)(0.0f, other->collisionRadius); obs.radius = (std::max)(0.0f, other->collisionRadius);
dynamicObstacles.push_back(obs); dynamicObstacles.push_back(obs);
}; };
@@ -267,7 +340,7 @@ namespace ZL
addCharacter(npc.get()); addCharacter(npc.get());
} }
return navigation.findPath(start, end, dynamicObstacles); return navigation->findPath(start, end, dynamicObstacles);
}; };
}; };
@@ -282,12 +355,35 @@ namespace ZL
} }
} }
bool Location::switchNavigation(int index)
{
if (index < 0 || index >= static_cast<int>(navigationMaps.size())) {
std::cerr << "[NAV] switchNavigation: index " << index << " out of range\n";
return false;
}
activeNavigationIndex = index;
navigation = &navigationMaps[index];
// Force all characters to replan their paths against the new nav map.
if (player) player->forceReplan();
for (auto& npc : npcs) {
if (npc) npc->forceReplan();
}
if (navigationEditorMode) {
navigationEditorBuildNavMeshes();
}
std::cout << "[NAV] Switched to navigation map " << index << "\n";
return true;
}
void Location::navigationEditorBuildNavMeshes() void Location::navigationEditorBuildNavMeshes()
{ {
navigationEditorNavMeshes.clear(); navigationEditorNavMeshes.clear();
const float y = navigation.getFloorY() + 0.02f; if (!navigation) return;
const float y = navigation->getFloorY() + 0.02f;
const Eigen::Vector3f red(1.0f, 0.0f, 0.0f); const Eigen::Vector3f red(1.0f, 0.0f, 0.0f);
for (const auto& obs : navigation.getObstaclePolygons()) { for (const auto& obs : navigation->getObstaclePolygons()) {
if (obs.polygon.size() < 3) continue; if (obs.polygon.size() < 3) continue;
VertexRenderStruct mesh; VertexRenderStruct mesh;
mesh.data = CreatePolygonFloor(obs.polygon, y, red); mesh.data = CreatePolygonFloor(obs.polygon, y, red);
@@ -311,7 +407,7 @@ namespace ZL
{ {
VertexDataStruct data; VertexDataStruct data;
const Eigen::Vector3f yellow(1.0f, 1.0f, 0.0f); const Eigen::Vector3f yellow(1.0f, 1.0f, 0.0f);
const float y = navigation.getFloorY() + 0.05f; const float y = navigation ? navigation->getFloorY() + 0.05f : 0.05f;
const float s = 0.2f; const float s = 0.2f;
for (const auto& pt : navigationEditorPoints) { for (const auto& pt : navigationEditorPoints) {
@@ -381,13 +477,13 @@ namespace ZL
poly.polygon.emplace_back(pt.x(), pt.z()); poly.polygon.emplace_back(pt.x(), pt.z());
} }
navigation.addObstaclePolygon(poly); if (navigation) navigation->addObstaclePolygon(poly);
std::cout << "[NAV_EDITOR] Added obstacle '" << poly.name << "' with " std::cout << "[NAV_EDITOR] Added obstacle '" << poly.name << "' with "
<< poly.polygon.size() << " vertices\n"; << poly.polygon.size() << " vertices\n";
// Add a red mesh for the new obstacle polygon so it's visible immediately. // Add a red mesh for the new obstacle polygon so it's visible immediately.
{ {
const float y = navigation.getFloorY() + 0.02f; const float y = navigation ? navigation->getFloorY() + 0.02f : 0.02f;
const Eigen::Vector3f red(1.0f, 0.0f, 0.0f); const Eigen::Vector3f red(1.0f, 0.0f, 0.0f);
VertexRenderStruct mesh; VertexRenderStruct mesh;
mesh.data = CreatePolygonFloor(poly.polygon, y, red); mesh.data = CreatePolygonFloor(poly.polygon, y, red);
@@ -409,7 +505,7 @@ namespace ZL
if (!std::filesystem::exists(filename)) break; if (!std::filesystem::exists(filename)) break;
} }
if (navigation.saveConfig(filename)) { if (navigation && navigation->saveConfig(filename)) {
std::cout << "[NAV_EDITOR] Saved navigation config to: " << filename << "\n"; std::cout << "[NAV_EDITOR] Saved navigation config to: " << filename << "\n";
} else { } else {
std::cerr << "[NAV_EDITOR] Failed to save to: " << filename << "\n"; std::cerr << "[NAV_EDITOR] Failed to save to: " << filename << "\n";
@@ -418,8 +514,8 @@ namespace ZL
void Location::navigationEditorReload() void Location::navigationEditorReload()
{ {
setupNavigation(navigationEditorConfigPath); setupNavigation(navigationMapPaths);
std::cout << "[NAV_EDITOR] Reloaded navigation from: " << navigationEditorConfigPath << "\n"; std::cout << "[NAV_EDITOR] Reloaded navigation maps (" << navigationMapPaths.size() << " maps)\n";
} }
@@ -821,7 +917,8 @@ namespace ZL
bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available) bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available)
{ {
return navigation.setAreaAvailable(areaName, available); if (!navigation) return false;
return navigation->setAreaAvailable(areaName, available);
} }
void Location::resolveCharacterCollisions() void Location::resolveCharacterCollisions()
@@ -882,9 +979,9 @@ namespace ZL
newB.z() += normal.y() * push; newB.z() += normal.y() * push;
newB.y() = 0.f; newB.y() = 0.f;
if (navigation.isReady()) { if (navigation && navigation->isReady()) {
const bool aOk = navigation.isWalkable(newA); const bool aOk = navigation->isWalkable(newA);
const bool bOk = navigation.isWalkable(newB); const bool bOk = navigation->isWalkable(newB);
if (aOk && bOk) { if (aOk && bOk) {
a->position = newA; a->position = newA;
@@ -978,7 +1075,8 @@ namespace ZL
{ {
if (player) { if (player) {
player->update(delta); player->update(delta);
dialogueSystem.update(static_cast<int>(delta), player->position); dialogueSystem.update(static_cast<int>(delta));
updateTriggerZones(player->position);
} }
for (auto& npc : npcs) for (auto& npc : npcs)
{ {
+22 -4
View File
@@ -19,6 +19,16 @@
namespace ZL namespace ZL
{ {
struct TriggerZone
{
std::string id;
Eigen::Vector3f position = Eigen::Vector3f::Zero();
float radius = 1.5f;
float hysteresis = 0.3f; // exit fires at radius + hysteresis to prevent flickering
bool enabled = true;
bool playerInside = false; // runtime tracking state, not serialized
};
struct LocationSetup struct LocationSetup
{ {
std::string roomMeshPath; std::string roomMeshPath;
@@ -26,9 +36,10 @@ namespace ZL
std::string gameObjectsJsonPath; std::string gameObjectsJsonPath;
std::string npcsJsonPath; std::string npcsJsonPath;
std::string dialoguesJsonPath; std::string dialoguesJsonPath;
std::string navigationJsonPath; std::vector<std::string> navigationJsonPaths;
std::string scriptPath; std::string scriptPath;
std::string teleportsJsonPath; std::string teleportsJsonPath;
std::string triggerZonesJsonPath;
Eigen::Vector3f playerPosition = Eigen::Vector3f::Zero(); Eigen::Vector3f playerPosition = Eigen::Vector3f::Zero();
}; };
@@ -52,7 +63,9 @@ namespace ZL
float cameraAzimuth = 0.0f; float cameraAzimuth = 0.0f;
float cameraInclination = M_PI * 30.f / 180.f; float cameraInclination = M_PI * 30.f / 180.f;
PathFinder navigation; std::vector<PathFinder> navigationMaps;
PathFinder* navigation = nullptr;
int activeNavigationIndex = 0;
std::unique_ptr<ShadowMap> shadowMap; std::unique_ptr<ShadowMap> shadowMap;
Eigen::Matrix4f cameraViewMatrix = Eigen::Matrix4f::Identity(); Eigen::Matrix4f cameraViewMatrix = Eigen::Matrix4f::Identity();
@@ -73,13 +86,15 @@ namespace ZL
TeleportZone* targetTeleportZone = nullptr; TeleportZone* targetTeleportZone = nullptr;
std::function<void(const std::string&, const Eigen::Vector3f&, float)> onTeleport; std::function<void(const std::string&, const Eigen::Vector3f&, float)> onTeleport;
std::vector<TriggerZone> triggerZones;
// Navigation editor — toggle with 'N', save with 'B', right-click to finalize polygon // Navigation editor — toggle with 'N', save with 'B', right-click to finalize polygon
bool navigationEditorMode = false; bool navigationEditorMode = false;
std::vector<Eigen::Vector3f> navigationEditorPoints; std::vector<Eigen::Vector3f> navigationEditorPoints;
VertexRenderStruct navigationEditorPointsMesh; VertexRenderStruct navigationEditorPointsMesh;
std::vector<VertexRenderStruct> navigationEditorNavMeshes; std::vector<VertexRenderStruct> navigationEditorNavMeshes;
std::string navigationEditorConfigPath; std::vector<std::string> navigationMapPaths;
int navigationEditorObstacleCounter = 0; int navigationEditorObstacleCounter = 0;
void navigationEditorBuildNavMeshes(); void navigationEditorBuildNavMeshes();
@@ -99,7 +114,8 @@ namespace ZL
void setup(const LocationSetup& params); void setup(const LocationSetup& params);
void setupNavigation(const std::string& navigationJsonPath); void setupNavigation(const std::vector<std::string>& paths);
bool switchNavigation(int index);
InteractiveObject* raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir); InteractiveObject* raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir);
Character* raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance = 100.0f); Character* raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance = 100.0f);
@@ -127,6 +143,8 @@ namespace ZL
void resolveCharacterCollisions(); void resolveCharacterCollisions();
void updateDynamicReplans(int64_t deltaMs); void updateDynamicReplans(int64_t deltaMs);
void loadTeleportZones(const std::string& jsonPath, const char* zipFile); void loadTeleportZones(const std::string& jsonPath, const char* zipFile);
void loadTriggerZones(const std::string& jsonPath, const char* zipFile);
void updateTriggerZones(const Eigen::Vector3f& playerPos);
std::unordered_map<Character*, Eigen::Vector3f> lastCharacterPositions; std::unordered_map<Character*, Eigen::Vector3f> lastCharacterPositions;
std::unordered_map<Character*, int64_t> replanCooldownRemainingMs; std::unordered_map<Character*, int64_t> replanCooldownRemainingMs;
+43
View File
@@ -2,6 +2,7 @@
#include "Game.h" #include "Game.h"
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <unordered_map>
#include "Location.h" #include "Location.h"
#define SOL_ALL_SAFETIES_ON 1 #define SOL_ALL_SAFETIES_ON 1
@@ -11,6 +12,8 @@ namespace ZL {
struct ScriptEngine::Impl { struct ScriptEngine::Impl {
sol::state lua; sol::state lua;
std::unordered_map<std::string, sol::protected_function> triggerEnterCallbacks;
std::unordered_map<std::string, sol::protected_function> triggerExitCallbacks;
}; };
ScriptEngine::ScriptEngine() = default; ScriptEngine::ScriptEngine() = default;
@@ -133,6 +136,24 @@ namespace ZL {
} }
}); });
api.set_function("switch_navigation",
[game](int index) {
if (!game->switchNavigation(index)) {
std::cerr << "[script] switch_navigation: index " << index << " out of range\n";
}
});
// set_trigger_zone_callbacks(zone_id, on_enter, on_exit)
// on_enter and on_exit are optional Lua functions (pass nil to omit).
// Called when the player enters or exits the named trigger zone.
api.set_function("set_trigger_zone_callbacks",
[this_impl = impl.get()](const std::string& zoneId, sol::object onEnter, sol::object onExit) {
if (onEnter.is<sol::protected_function>())
this_impl->triggerEnterCallbacks[zoneId] = onEnter.as<sol::protected_function>();
if (onExit.is<sol::protected_function>())
this_impl->triggerExitCallbacks[zoneId] = onExit.as<sol::protected_function>();
});
// receive_npc_gift(npc_index) // receive_npc_gift(npc_index)
api.set_function("receive_npc_gift", [game, inventory](int npcIndex) { api.set_function("receive_npc_gift", [game, inventory](int npcIndex) {
std::cout << "[script] receive_npc_gift: npc index " << npcIndex << std::endl; std::cout << "[script] receive_npc_gift: npc index " << npcIndex << std::endl;
@@ -254,4 +275,26 @@ namespace ZL {
} }
} }
void ScriptEngine::callTriggerEnterCallback(const std::string& zoneId) {
if (!impl) return;
auto it = impl->triggerEnterCallbacks.find(zoneId);
if (it == impl->triggerEnterCallbacks.end()) return;
auto result = it->second();
if (!result.valid()) {
sol::error err = result;
std::cerr << "[SCRIPT] trigger enter callback error for '" << zoneId << "': " << err.what() << "\n";
}
}
void ScriptEngine::callTriggerExitCallback(const std::string& zoneId) {
if (!impl) return;
auto it = impl->triggerExitCallbacks.find(zoneId);
if (it == impl->triggerExitCallbacks.end()) return;
auto result = it->second();
if (!result.valid()) {
sol::error err = result;
std::cerr << "[SCRIPT] trigger exit callback error for '" << zoneId << "': " << err.what() << "\n";
}
}
} // namespace ZL } // namespace ZL
+3
View File
@@ -24,6 +24,9 @@ public:
void callNpcInteractCallback(int npcIndex); void callNpcInteractCallback(int npcIndex);
void callTriggerEnterCallback(const std::string& zoneId);
void callTriggerExitCallback(const std::string& zoneId);
private: private:
struct Impl; struct Impl;
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;
+1 -25
View File
@@ -11,23 +11,7 @@ bool DialogueSystem::loadDatabase(const std::string& path) {
return database.loadFromFile(path); return database.loadFromFile(path);
} }
void DialogueSystem::update(int deltaMs, const Eigen::Vector3f& playerPosition) { void DialogueSystem::update(int deltaMs) {
if (!runtime.isActive()) {
for (TriggerZone& zone : triggerZones) {
if (zone.once && zone.triggered) {
continue;
}
const Eigen::Vector3f diff = playerPosition - zone.center;
if (diff.norm() <= zone.radius) {
if (startDialogue(zone.dialogueId)) {
zone.triggered = true;
break;
}
}
}
}
runtime.update(deltaMs); runtime.update(deltaMs);
overlay.update(runtime.getPresentation(), deltaMs); overlay.update(runtime.getPresentation(), deltaMs);
if (overlay.consumeSkipRequested()) { if (overlay.consumeSkipRequested()) {
@@ -139,12 +123,4 @@ void DialogueSystem::stopDialogue() {
runtime.stop(); runtime.stop();
} }
void DialogueSystem::addTriggerZone(const TriggerZone& zone) {
triggerZones.push_back(zone);
}
void DialogueSystem::clearTriggerZones() {
triggerZones.clear();
}
} // namespace ZL::Dialogue } // namespace ZL::Dialogue
+1 -16
View File
@@ -2,28 +2,17 @@
#include "dialogue/DialogueOverlay.h" #include "dialogue/DialogueOverlay.h"
#include "dialogue/DialogueRuntime.h" #include "dialogue/DialogueRuntime.h"
#include <Eigen/Dense>
#include <SDL.h> #include <SDL.h>
#include <string> #include <string>
#include <vector>
namespace ZL::Dialogue { namespace ZL::Dialogue {
struct TriggerZone {
std::string id;
std::string dialogueId;
Eigen::Vector3f center = Eigen::Vector3f::Zero();
float radius = 1.5f;
bool once = true;
bool triggered = false;
};
class DialogueSystem { class DialogueSystem {
public: public:
bool init(Renderer& renderer, const std::string& zipFile = ""); bool init(Renderer& renderer, const std::string& zipFile = "");
bool loadDatabase(const std::string& path); bool loadDatabase(const std::string& path);
void update(int deltaMs, const Eigen::Vector3f& playerPosition); void update(int deltaMs);
void draw(Renderer& renderer); void draw(Renderer& renderer);
bool handleKeyDown(SDL_Keycode key); bool handleKeyDown(SDL_Keycode key);
@@ -40,14 +29,10 @@ public:
void setFlag(const std::string& name, int value) { runtime.setFlag(name, value); } void setFlag(const std::string& name, int value) { runtime.setFlag(name, value); }
int getFlag(const std::string& name) const { return runtime.getFlag(name); } int getFlag(const std::string& name) const { return runtime.getFlag(name); }
void addTriggerZone(const TriggerZone& zone);
void clearTriggerZones();
private: private:
DialogueDatabase database; DialogueDatabase database;
DialogueRuntime runtime; DialogueRuntime runtime;
DialogueOverlay overlay; DialogueOverlay overlay;
std::vector<TriggerZone> triggerZones;
}; };
} // namespace ZL::Dialogue } // namespace ZL::Dialogue