Added bandit chase, change dialogs

This commit is contained in:
Vladislav Khorev 2026-04-19 22:03:56 +03:00
parent 28a3ace187
commit ce8bc2d142
9 changed files with 441 additions and 244 deletions

BIN
resources/bandit.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/cashier.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -8,7 +8,7 @@
"id": "line_1",
"type": "Line",
"speaker": "Милиция",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/police.png",
"text": "Белый седан 256 остановитесь немедленно!",
"next": "end_1"
},
@ -18,6 +18,40 @@
}
]
},
{
"id": "dialogue_bandit1",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Думали, что сможете убежать от нас?",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Никто никогда не убежит от Нурланбая!",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Ваша песенка спета!",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "dialogue_gas1",
"start": "line_1",
@ -25,7 +59,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Первая колонка, полный бак пожалуйста.",
"next": "line_2"
@ -34,14 +68,14 @@
"id": "line_2",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "[Смотрит подозрительно]",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Что вы на меня так смотрите, со мной что-то не так?",
"next": "line_4"
@ -50,7 +84,7 @@
"id": "line_4",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "Нет-нет, все хорошо.",
"next": "line_5"
},
@ -58,14 +92,14 @@
"id": "line_5",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "Говорите, первая колонка, да?",
"next": "line_6"
},
{
"id": "line_6",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Да.",
"next": "line_7"
@ -74,7 +108,7 @@
"id": "line_7",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "Вот, пожалуйста. Приходите к нам еще!",
"next": "end_1"
},
@ -92,14 +126,14 @@
"id": "line_2",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "[Смотрит подозрительно]",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Что-то случилось?",
"next": "line_4"
@ -108,7 +142,7 @@
"id": "line_4",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "Поставьте машину чуть ближе к колонке пожалуйста.",
"next": "end_1"
},
@ -126,14 +160,14 @@
"id": "line_2",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "[Смотрит подозрительно]",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Что-то случилось?",
"next": "line_4"
@ -142,7 +176,7 @@
"id": "line_4",
"type": "Line",
"speaker": "Кассир",
"portrait": "resources/ghost_avatar.png",
"portrait": "resources/cashier.png",
"text": "У вас уже заправлен полный бак.",
"next": "end_1"
},
@ -159,7 +193,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Ну капец, мы застряли!",
"next": "line_2"
@ -167,7 +201,7 @@
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Теперь только пешком.",
"next": "end_1"
@ -185,7 +219,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Все, приехали! Машина в хлам!",
"next": "end_1"
@ -203,7 +237,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Все, приехали! Бензин закончился!",
"next": "end_1"
@ -221,8 +255,8 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алексей",
"portrait": "resources/girlfriend.png",
"text": "До Таласской области осталось ехать примерно 7 километров.",
"next": "end_1"
},
@ -239,8 +273,8 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алексей",
"portrait": "resources/girlfriend.png",
"text": "До Таласской области осталось ехать примерно 5 километров.",
"next": "end_1"
},
@ -257,8 +291,8 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "До Таласской области осталось ехать примерно 2 километра.",
"next": "end_1"
},
@ -275,31 +309,31 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Все, мы в Таласской области.",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Здесь должен быть сигнал, дай мне телефон.",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Я позвоню дяде.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Держи.",
"next": "line_5"
@ -307,47 +341,47 @@
{
"id": "line_5",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Ало, Акыл байке! Это Алтынай.",
"next": "line_6"
},{
"id": "line_6",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "У меня проблемы, меня преследуют бандиты.",
"next": "line_7"
},
{
"id": "line_7",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Я сейчас еду с другом в сторону Таласа.",
"next": "line_8"
},
{
"id": "line_8",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Пришли пожалуйста патруль мне на встречу.",
"next": "line_9"
},
{
"id": "line_9",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Белый седан, номер 256.",
"next": "line_10"
},
{
"id": "line_10",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Спасибо! Пока!",
"next": "end_1"
},
@ -364,7 +398,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "У нас бензин кончается.",
"next": "line_2"
@ -372,7 +406,7 @@
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Надо заправиться.",
"next": "line_3"
@ -380,16 +414,16 @@
{
"id": "line_3",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Хорошо, только давай быстро.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Мне как-то не по себе.",
"next": "end_1"
},
@ -406,15 +440,15 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Ты видел? Он так на меня смотрел, как будто узнал меня.",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Что-то мне стремно, давай поедем отсюда быстрее",
"next": "end_1"
@ -432,15 +466,15 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "[Телефон звонит]",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Да, слушаю.",
"next": "line_3"
@ -448,88 +482,88 @@
{
"id": "line_3",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Алексей, это Нурланбай на связи.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Мои ребята сообщили, что Алтынай видели на заправке с тобой.",
"next": "line_5"
},
{
"id": "line_5",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Как вы узнали мой номер?",
"next": "line_6"
}, {
"id": "line_6",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "О, это было нетрудно. У тебя слишком заметная машина.",
"next": "line_7"
}, {
"id": "line_7",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Мои ребята уже поехали за тобой.",
"next": "line_8"
}, {
"id": "line_8",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Предлагаю тебе не усложнять ничего.",
"next": "line_9"
}, {
"id": "line_9",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Остановись на трассе, отдай нам Алтынай.",
"next": "line_10"
}, {
"id": "line_10",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "И можешь ехать дальше спокойно.",
"next": "line_11"
}, {
"id": "line_11",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Никогда!",
"next": "line_12"
},{
"id": "line_12",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Какой ты смелый парень.",
"next": "line_13"
},{
"id": "line_13",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Ну ничего, скоро увидимся. Давай, бывай.",
"next": "line_14"
},
{
"id": "line_14",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "[Гудки]",
"next": "end_1"
},
@ -546,23 +580,23 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "Старший лейтенант Каримов, отдел милиции Чуйской области.",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "Предъявите ваши права.",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Вот, пожалуйста.",
"next": "line_4"
@ -570,23 +604,23 @@
{
"id": "line_4",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "Алексей Смирнов, да?",
"next": "line_5"
},
{
"id": "line_5",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "Когда в последний раз проходили техосмотр?",
"next": "line_6"
},
{
"id": "line_6",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "В прошлом году.",
"next": "line_7"
@ -594,15 +628,15 @@
{
"id": "line_7",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "Страховка у вас есть?",
"next": "line_8"
},
{
"id": "line_8",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Да, вот, до ноября.",
"next": "line_9"
@ -610,15 +644,15 @@
{
"id": "line_9",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "А огнетушитель в машине есть?",
"next": "line_10"
},
{
"id": "line_10",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Да он просто тянет время!*",
"next": "line_11"
@ -626,7 +660,7 @@
{
"id": "line_11",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Давайте напрямую, я задержан или нет?",
"next": "line_12"
@ -634,22 +668,22 @@
{
"id": "line_12",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": "Нет...",
"next": "line_13"
},{
"id": "line_13",
"type": "Line",
"speaker": "Hero",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Если не отпустите меня сейчас, я позвоню в прокуратуру.",
"next": "line_14"
},{
"id": "line_14",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/hero.png",
"speaker": "Милиция",
"portrait": "resources/police.png",
"text": ".. Счастливого пути!",
"next": "end_1"
},
@ -666,8 +700,8 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Попался красавчик.",
"next": "end_1"
},
@ -684,9 +718,9 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"text": "Эй, парень! Остановись и выйди!",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Эй, парень! Остановись!",
"next": "end_1"
},
{
@ -702,8 +736,8 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Попались воробушки.",
"next": "end_1"
},
@ -720,8 +754,8 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Бандит",
"portrait": "resources/bandit.png",
"text": "Ну все, вам конец!",
"next": "end_1"
},
@ -738,7 +772,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Алтынай ты тут?",
"next": "line_2"
@ -746,48 +780,48 @@
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Да, я тут!",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Где твоя машина припаркована?",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Прямо тут, недалеко.",
"text": "Здесь рядом.",
"next": "line_5"
},
{
"id": "line_5",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Давай отведи меня в машину, только тихо!",
"next": "line_6"
},
{
"id": "line_6",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Постарайся не попадаться на глаза бандитам!",
"next": "line_7"
},
{
"id": "line_7",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Я прыгаю!",
"next": "end_1"
},
@ -804,7 +838,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Моя подруга Алтынай пропала сегодня.*",
"next": "line_2"
@ -812,7 +846,7 @@
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*А потом я получил голосовое сообщение от нее.*",
"next": "line_3"
@ -820,63 +854,63 @@
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Если ты это слушаешь, то случилась беда.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Ко мне сватался Нурланбай, местный бизнесмен и авторитет.",
"next": "line_5"
},
{
"id": "line_5",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Он мне обещал, что похитит меня, и сегодня он сделал это.",
"next": "line_6"
},
{
"id": "line_6",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Я отправила тебе координаты дома, куда могут меня спрятать.",
"next": "line_7"
},
{
"id": "line_7",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Не обращайся в милицию, у него есть связи в МВД Чуйской области.",
"next": "line_8"
},
{
"id": "line_8",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Приезжай на своей машине и помоги мне сбежать оттуда!",
"next": "line_9"
},
{
"id": "line_9",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Телефон",
"portrait": "resources/phone.png",
"text": "Мне больше не к кому обращаться. Я жду тебя!",
"next": "line_10"
},
{
"id": "line_10",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Село где держат Алтынай, находится впереди по трассе.*",
"next": "line_11"
@ -884,7 +918,7 @@
{
"id": "line_11",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Пора садится в машину и отправляться в путь!*",
"next": "end_1"
@ -902,7 +936,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Вот этот дом, с охраной!*",
"next": "line_2"
@ -910,7 +944,7 @@
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Нужно держаться от этого бандита подальше!*",
"next": "line_3"
@ -918,7 +952,7 @@
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Если этот бандит меня заметит, он меня убьет!*",
"next": "line_4"
@ -926,7 +960,7 @@
{
"id": "line_4",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "*Может стоит прократься мимо него и осмотреть дом сзади?*",
"next": "end_1"
@ -944,23 +978,23 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Что сидишь, поехали!",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Дави по газам быстрее пока они нас не заметили!",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "Конечно, сейчас...",
"next": "line_4"
@ -968,39 +1002,39 @@
{
"id": "line_4",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Спасибо что помог мне!",
"next": "line_5"
},
{
"id": "line_5",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Этот Нурланбай сумасшедший!",
"next": "line_6"
},
{
"id": "line_6",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Он владелец сети заправок, а еще свою банду собрал.",
"next": "line_7"
},{
"id": "line_7",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "У него друг начальник милиции Чуйской области.",
"next": "line_8"
},
{
"id": "line_8",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Но я не выйду за него, пусть он сдохнет!",
"next": "end_1"
},
@ -1017,7 +1051,7 @@
{
"id": "line_1",
"type": "Line",
"speaker": "Игрок",
"speaker": "Алексей",
"portrait": "resources/hero.png",
"text": "А куда мы поедем?",
"next": "line_2"
@ -1025,32 +1059,32 @@
{
"id": "line_2",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Давай в Талас.",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Там у меня есть дядя в администрации области.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": у него спрячусь, и никакой Нурланбай нас там не достанет.",
"next": "line_5"
},
{
"id": "line_5",
"type": "Line",
"speaker": "Игрок",
"portrait": "resources/hero.png",
"speaker": "Алтынай",
"portrait": "resources/girlfriend.png",
"text": "Надо только доехать хотя бы до границы области.",
"next": "end_1"
},

BIN
resources/e/car_bandit001.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/girlfriend.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/police.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -153,14 +153,15 @@ namespace ZL
};
defaultLocation = std::make_shared<Location>(renderer, inventory, "default");
defaultLocation->setup();
defaultLocation->onLocationChangeRequest = [this](const std::string& locId) {
this->changeLocation(locId);
};
currentLocation = defaultLocation;
//currentLocation = forestLocation;
//currentLocation = defaultLocation;
currentLocation = forestLocation;
std::cout << "Load resurces step 5" << std::endl;

View File

@ -165,11 +165,34 @@ void Location::setup()
police->position = Vector3f{ 1000, -0, 10 };
police->setTarget(police->position);
auto banditTexture0 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/bandit_packed0_diffuse.png", CONST_ZIP_FILE));
auto banditTexture1 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/bandit_packed1_diffuse.png", CONST_ZIP_FILE));
auto banditTexture2 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/bandit_packed2_diffuse.png", CONST_ZIP_FILE));
bandit = std::make_unique<Character>();
bandit->loadBinaryAnimation(AnimationState::STAND, "resources/e/bandit_stand_idle003.anim2", CONST_ZIP_FILE);
bandit->loadBinaryAnimation(AnimationState::WALK, "resources/e/bandit_run003.anim2", CONST_ZIP_FILE);
bandit->setTexture("Body", banditTexture0);
bandit->setTexture("Bottoms", banditTexture2);
bandit->setTexture("Eyelashes", banditTexture0);
bandit->setTexture("Eyes", banditTexture0);
bandit->setTexture("Gloves", banditTexture1);
bandit->setTexture("Masks", banditTexture1);
bandit->setTexture("Shoes", banditTexture1);
bandit->setTexture("Tops", banditTexture1);
bandit->walkSpeed = 3.6f;
bandit->rotationSpeed = 8.0f;
bandit->modelScale = 0.01f;
bandit->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
// Parked far away — only spawned on screen via npcBanditCarSpawned.
bandit->position = Vector3f{ 1000, 0, 1000 };
bandit->setTarget(bandit->position);
std::cout << "[LOCATION] Setting up FOREST location (custom models only)" << std::endl;
carPosition ={ 7, 0, -7 + 300 };
npcCar.position = Vector3f(9, 0, -335) + Vector3f(1000,0,0);
npcBanditCar.position = Vector3f(9, 0, 0) + Vector3f(2000, 0, 0);
girlfriend->position = Vector3f{ 5, 0, 0.9 + 300 };
girlfriend->setTarget(girlfriend->position);
@ -402,6 +425,17 @@ void Location::setup()
//npcCar.position = carPosition + Eigen::Vector3f(0, 0.f, 14.f);//Eigen::Vector3f(-12.f, 0.f, 8.f);
npcCar.rotation = 0.f;
npcCar.mode = NpcCar::Mode::NONE;
// Bandit car: shares the same mesh as the player/police car but uses its own
// texture, is a touch faster, and tails the player at half the follow distance.
npcBanditCar.texture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/car_bandit001.png", CONST_ZIP_FILE));
npcBanditCar.rotation = 0.f;
npcBanditCar.mode = NpcCar::Mode::NONE;
npcBanditCar.maxSpeed = 26.0f;
npcBanditCar.maxReverseSpeed = 8.0f;
npcBanditCar.followMinDistance = 10.5f;
npcBanditCar.followMaxDistance = 12.5f;
npcBanditCar.position = Vector3f(-1000, 0, -1000);
/*npcCar.mode = NpcCar::Mode::FOLLOW_WAYPOINTS;
npcCar.waypoints = {
Eigen::Vector3f(-12.f, 0.f, 8.f),
@ -727,7 +761,8 @@ void Location::setup()
renderer.PopMatrix();
drawNpcCar();
drawNpcCar(npcCar);
drawNpcCar(npcBanditCar);
// Don't draw the player mesh when in first-person mode
if (player && !inCar && !firstPersonMode) player->draw(renderer);
@ -1016,9 +1051,9 @@ void Location::setup()
return std::abs(alongForward) <= carLength * 0.5f && std::abs(alongRight) <= carWidth * 0.5f;
}
void Location::pushOutOfNpcCarFootprint(Eigen::Vector3f& position) const
void Location::pushOutOfNpcCarFootprint(const NpcCar& car, Eigen::Vector3f& position) const
{
if (!npcCar.texture) return;
if (!car.texture) return;
constexpr float carLength = 7.3f;
constexpr float carWidth = 2.8f;
@ -1026,10 +1061,10 @@ void Location::setup()
constexpr float halfWidth = carWidth * 0.5f;
constexpr float skin = 0.05f;
const Eigen::Vector3f forward(-std::sin(npcCar.rotation), 0.f, -std::cos(npcCar.rotation));
const Eigen::Vector3f right(std::cos(npcCar.rotation), 0.f, -std::sin(npcCar.rotation));
const Eigen::Vector3f forward(-std::sin(car.rotation), 0.f, -std::cos(car.rotation));
const Eigen::Vector3f right(std::cos(car.rotation), 0.f, -std::sin(car.rotation));
Eigen::Vector3f delta = position - npcCar.position;
Eigen::Vector3f delta = position - car.position;
delta.y() = 0.f;
float alongForward = delta.dot(forward);
float alongRight = delta.dot(right);
@ -1050,20 +1085,20 @@ void Location::setup()
}
const float originalY = position.y();
Eigen::Vector3f resolved = npcCar.position + forward * alongForward + right * alongRight;
Eigen::Vector3f resolved = car.position + forward * alongForward + right * alongRight;
resolved.y() = originalY;
position = resolved;
}
bool Location::doesPlayerCarCollideWithNpcCar(const Eigen::Vector3f& center, float rotation) const
bool Location::doesPlayerCarCollideWithNpcCar(const NpcCar& car, const Eigen::Vector3f& center, float rotation) const
{
if (!npcCar.texture) return false;
if (!car.texture) return false;
constexpr float carLength = 7.3f;
constexpr float carWidth = 2.8f;
constexpr float sampleSpacing = 0.5f;
const Eigen::Vector3f delta = center - npcCar.position;
const Eigen::Vector3f delta = center - car.position;
const float approxRadius = std::sqrt(carLength * carLength + carWidth * carWidth);
if (delta.squaredNorm() > approxRadius * approxRadius) {
return false;
@ -1083,7 +1118,7 @@ void Location::setup()
for (int j = 0; j <= widthSteps; ++j) {
const float fw = (static_cast<float>(j) / static_cast<float>(widthSteps)) * 2.0f - 1.0f;
const Eigen::Vector3f sample = center + lineOffset + right * (fw * halfWidth);
if (isPointInCarFootprint(sample, npcCar.position, npcCar.rotation)) {
if (isPointInCarFootprint(sample, car.position, car.rotation)) {
return true;
}
}
@ -1202,14 +1237,19 @@ void Location::setup()
updateGirlfriendFollow();
girlfriend->update(delta);
if (!girlfriendInCar) {
pushOutOfNpcCarFootprint(girlfriend->position);
pushOutOfNpcCarFootprint(npcCar, girlfriend->position);
pushOutOfNpcCarFootprint(npcBanditCar, girlfriend->position);
}
}
if (salesperson) pushOutOfNpcCarFootprint(salesperson->position);
if (salesperson) {
pushOutOfNpcCarFootprint(npcCar, salesperson->position);
pushOutOfNpcCarFootprint(npcBanditCar, salesperson->position);
}
if (police) {
police->update(delta);
pushOutOfNpcCarFootprint(police->position);
pushOutOfNpcCarFootprint(npcCar, police->position);
pushOutOfNpcCarFootprint(npcBanditCar, police->position);
}
if (bandit)
{
@ -1217,12 +1257,14 @@ void Location::setup()
updateBanditFollow();
}
bandit->update(delta);
pushOutOfNpcCarFootprint(bandit->position);
pushOutOfNpcCarFootprint(npcCar, bandit->position);
pushOutOfNpcCarFootprint(npcBanditCar, bandit->position);
}
for (auto& npc : npcs) {
npc->update(delta);
pushOutOfNpcCarFootprint(npc->position);
pushOutOfNpcCarFootprint(npcCar, npc->position);
pushOutOfNpcCarFootprint(npcBanditCar, npc->position);
}
if (inCar) {
@ -1273,7 +1315,8 @@ void Location::setup()
if (navigation.isReady() && !isCarFootprintWalkable(carPosition, carRotation)) {
carRotation = oldRotation;
}
if (doesPlayerCarCollideWithNpcCar(carPosition, carRotation)) {
if (doesPlayerCarCollideWithNpcCar(npcCar, carPosition, carRotation)
|| doesPlayerCarCollideWithNpcCar(npcBanditCar, carPosition, carRotation)) {
carRotation = oldRotation;
}
@ -1294,7 +1337,8 @@ void Location::setup()
carVelocity = 0.f;
break;
}
if (doesPlayerCarCollideWithNpcCar(candidate, carRotation)) {
if (doesPlayerCarCollideWithNpcCar(npcCar, candidate, carRotation)
|| doesPlayerCarCollideWithNpcCar(npcBanditCar, candidate, carRotation)) {
carVelocity = 0.f;
if (!dialoguePlayedCrash && !dialogueSystem.isActive()) {
if (dialogueSystem.startDialogue("driving_dialogue_crash")) {
@ -1377,6 +1421,7 @@ void Location::setup()
if (navigation.isReady() && !navigation.isWalkable(p)) return true;
if (isPointInCarFootprint(p, carPosition, carRotation)) return true;
if (isPointInCarFootprint(p, npcCar.position, npcCar.rotation)) return true;
if (npcBanditCar.texture && isPointInCarFootprint(p, npcBanditCar.position, npcBanditCar.rotation)) return true;
return false;
};
if (blocked(player->position)) {
@ -1394,7 +1439,8 @@ void Location::setup()
}
}
updateNpcCar(delta);
updateNpcCar(npcCar, delta);
updateNpcCar(npcBanditCar, delta);
if (locationId == "forest")
{
@ -1454,6 +1500,10 @@ void Location::setup()
if (npcCar.mode == NpcCar::Mode::FOLLOW_PLAYER || npcCar.mode == NpcCar::Mode::NONE_STAY) {
npcCar.position += shift;
}
if (npcBanditCarSpawned &&
(npcBanditCar.mode == NpcCar::Mode::FOLLOW_PLAYER || npcBanditCar.mode == NpcCar::Mode::NONE_STAY)) {
npcBanditCar.position += shift;
}
}
}
@ -1580,6 +1630,89 @@ void Location::setup()
npcCarSpawnedAfterPhone = true;
}
}
// --- Bandit NPC car quest (forest only) ---
// Track how long the player has been on foot. Resets the moment they get
// back into the car so brief stops don't count toward the spawn timer.
if (!inCar) {
playerOnFootSeconds += static_cast<float>(delta) / 1000.0f;
}
else {
playerOnFootSeconds = 0.f;
}
if (!npcBanditCarSpawned && bandit && player && npcBanditCar.texture) {
bool shouldSpawn = false;
if (dialoguePlayedDrivingGasOut) {
shouldSpawn = true;
}
if (dialoguePlayedOffroad) {
shouldSpawn = true;
}
// Cases 1 & 2: phone dialogue done and player has been on foot >30s
// (the 60s case from the spec collapses into the same trigger — once
// the car is spawned the second threshold is moot).
if (dialoguePlayedPhone1 && !inCar && playerOnFootSeconds > 30.0f) {
shouldSpawn = true;
}
// Case 3: still driving, police chase wrapped up, and the goal
// distance is closing in.
if (inCar
&& policeEncounterStage == PoliceEncounterStage::Done
&& distanceRemaining < 1800.0f) {
shouldSpawn = true;
}
if (shouldSpawn) {
const Eigen::Vector3f anchor = inCar ? carPosition : player->position;
// 150 m behind the player along +Z (player drives toward -Z),
// snapped onto the road's right lane so the bandit appears on the
// road rather than the grass.
npcBanditCar.position = Eigen::Vector3f(9.0f, 0.0f, anchor.z() + 150.0f);
npcBanditCar.rotation = static_cast<float>(M_PI); // facing -Z, toward player
npcBanditCar.velocity = 0.f;
npcBanditCar.steeringAngle = 0.f;
npcBanditCar.mode = NpcCar::Mode::FOLLOW_PLAYER;
npcBanditCarSpawned = true;
}
}
// Once the bandit car is alongside the player and the player is on foot,
// the bandit hops out and the dialog plays. Fires exactly once.
if (npcBanditCarSpawned && !banditExitedNpcBanditCar && bandit && player && !inCar) {
Eigen::Vector3f toCar = npcBanditCar.position - player->position;
toCar.y() = 0.f;
const float toCarDist = toCar.norm();
if (toCarDist < 10.0f && !dialogueSystem.isActive()) {
// Park the bandit car and place the bandit on its left side, the
// same staging the police encounter uses.
npcBanditCar.mode = NpcCar::Mode::NONE_STAY;
npcBanditCar.velocity = 0.f;
const Eigen::Vector3f carLeft(-std::cos(npcBanditCar.rotation), 0.f, std::sin(npcBanditCar.rotation));
constexpr float carHalfWidth = 2.8f * 0.5f;
bandit->position = npcBanditCar.position + carLeft * (carHalfWidth + 1.5f);
bandit->position.y() = 0.f;
bandit->clearPath();
Eigen::Vector3f approachTarget = player->position;
if (toCarDist > 1e-4f) {
approachTarget = player->position + (toCar / toCarDist) * 1.5f;
}
approachTarget.y() = 0.f;
bandit->setTarget(approachTarget);
if (dialogueSystem.startDialogue("dialogue_bandit1")) {
dialoguePlayedBandit1 = true;
banditExitedNpcBanditCar = true;
playerFrozen = true;
}
}
}
}
if (locationId == "default")
@ -1693,42 +1826,44 @@ void Location::setup()
}
}
void Location::updateNpcCar(int64_t deltaMs)
void Location::updateNpcCar(NpcCar& car, int64_t deltaMs)
{
const float dt = static_cast<float>(deltaMs) / 1000.0f;
Eigen::Vector3f target = npcCar.position;
Eigen::Vector3f target = car.position;
float throttle = 0.f;
bool hasTarget = false;
if (npcCar.mode == NpcCar::Mode::FOLLOW_WAYPOINTS) {
if (!npcCar.waypoints.empty()) {
if (npcCar.currentWaypoint >= npcCar.waypoints.size()) {
npcCar.currentWaypoint = 0;
if (car.mode == NpcCar::Mode::FOLLOW_WAYPOINTS) {
if (!car.waypoints.empty()) {
if (car.currentWaypoint >= car.waypoints.size()) {
car.currentWaypoint = 0;
}
Eigen::Vector3f toTarget = npcCar.waypoints[npcCar.currentWaypoint] - npcCar.position;
Eigen::Vector3f toTarget = car.waypoints[car.currentWaypoint] - car.position;
toTarget.y() = 0.f;
if (toTarget.norm() < npcCar.waypointReachRadius) {
npcCar.currentWaypoint = (npcCar.currentWaypoint + 1) % npcCar.waypoints.size();
if (toTarget.norm() < car.waypointReachRadius) {
car.currentWaypoint = (car.currentWaypoint + 1) % car.waypoints.size();
}
target = npcCar.waypoints[npcCar.currentWaypoint];
target = car.waypoints[car.currentWaypoint];
throttle = 1.0f;
hasTarget = true;
}
}
else if (npcCar.mode == NpcCar::Mode::FOLLOW_PLAYER) {
else if (car.mode == NpcCar::Mode::FOLLOW_PLAYER) {
//if (x > 0.5)
{
target = carPosition;
Eigen::Vector3f toTarget = target - npcCar.position;
// Chase the actual player when they're on foot — otherwise an
// abandoned car would keep the chaser frozen at its parking spot.
target = (inCar || !player) ? carPosition : player->position;
Eigen::Vector3f toTarget = target - car.position;
toTarget.y() = 0.f;
const float dist = toTarget.norm();
const float targetDist = npcCar.followMinDistance;
const float targetDist = car.followMinDistance;
const float coastBuffer = 1.5f;
if (dist > npcCar.followMaxDistance) {
if (dist > car.followMaxDistance) {
throttle = 1.0f;
}
else if (dist > targetDist + coastBuffer) {
@ -1750,69 +1885,69 @@ void Location::setup()
throttle = 0.f;
}
float targetHeading = npcCar.rotation;
float targetHeading = car.rotation;
if (hasTarget) {
Eigen::Vector3f toTarget = target - npcCar.position;
Eigen::Vector3f toTarget = target - car.position;
toTarget.y() = 0.f;
if (toTarget.squaredNorm() > 1e-4f) {
targetHeading = std::atan2(-toTarget.x(), -toTarget.z());
}
}
float angleDiff = targetHeading - npcCar.rotation;
float angleDiff = targetHeading - car.rotation;
while (angleDiff > M_PI) angleDiff -= 2.0f * static_cast<float>(M_PI);
while (angleDiff < -M_PI) angleDiff += 2.0f * static_cast<float>(M_PI);
const float turnIntent = max(-1.0f, min(1.0f, angleDiff * 2.0f));
const float targetSteer = turnIntent * npcCar.maxSteerAngle;
const float targetSteer = turnIntent * car.maxSteerAngle;
const float steerLerp = min(1.f, dt * 8.f);
npcCar.steeringAngle += (targetSteer - npcCar.steeringAngle) * steerLerp;
car.steeringAngle += (targetSteer - car.steeringAngle) * steerLerp;
if (throttle > 0.f) {
npcCar.velocity += npcCar.acceleration * dt * throttle;
car.velocity += car.acceleration * dt * throttle;
}
else if (throttle < 0.f) {
const float brakeForce = npcCar.acceleration * dt * (-throttle);
if (npcCar.velocity > 0.f) {
npcCar.velocity = max(0.f, npcCar.velocity - brakeForce);
const float brakeForce = car.acceleration * dt * (-throttle);
if (car.velocity > 0.f) {
car.velocity = max(0.f, car.velocity - brakeForce);
}
else {
npcCar.velocity = min(0.f, npcCar.velocity + brakeForce);
car.velocity = min(0.f, car.velocity + brakeForce);
}
}
else {
const float resistance = npcCar.friction * dt;
if (npcCar.velocity > 0.f) {
npcCar.velocity = max(0.f, npcCar.velocity - resistance);
const float resistance = car.friction * dt;
if (car.velocity > 0.f) {
car.velocity = max(0.f, car.velocity - resistance);
}
else if (npcCar.velocity < 0.f) {
npcCar.velocity = min(0.f, npcCar.velocity + resistance);
else if (car.velocity < 0.f) {
car.velocity = min(0.f, car.velocity + resistance);
}
}
npcCar.velocity = max(-npcCar.maxReverseSpeed, min(npcCar.maxSpeed, npcCar.velocity));
car.velocity = max(-car.maxReverseSpeed, min(car.maxSpeed, car.velocity));
const float oldRotation = npcCar.rotation;
if (std::abs(npcCar.velocity) > 0.01f) {
const float speedFactor = npcCar.velocity / npcCar.maxSpeed;
npcCar.rotation += turnIntent * npcCar.turnRate * dt * speedFactor;
const float oldRotation = car.rotation;
if (std::abs(car.velocity) > 0.01f) {
const float speedFactor = car.velocity / car.maxSpeed;
car.rotation += turnIntent * car.turnRate * dt * speedFactor;
}
if (navigation.isReady() && !isCarFootprintWalkable(npcCar.position, npcCar.rotation)) {
npcCar.rotation = oldRotation;
if (navigation.isReady() && !isCarFootprintWalkable(car.position, car.rotation)) {
car.rotation = oldRotation;
}
const Eigen::Vector3f forward(-std::sin(npcCar.rotation), 0.f, -std::cos(npcCar.rotation));
const Eigen::Vector3f totalDelta = forward * npcCar.velocity * dt;
const Eigen::Vector3f forward(-std::sin(car.rotation), 0.f, -std::cos(car.rotation));
const Eigen::Vector3f totalDelta = forward * car.velocity * dt;
const float totalDist = totalDelta.norm();
const float maxSubstep = 0.2f;
const int substeps = max(1, static_cast<int>(std::ceil(totalDist / maxSubstep)));
const Eigen::Vector3f stepDelta = totalDelta / static_cast<float>(substeps);
for (int s = 0; s < substeps; ++s) {
Eigen::Vector3f candidate = npcCar.position + stepDelta;
if (navigation.isReady() && !isCarFootprintWalkable(candidate, npcCar.rotation)) {
npcCar.velocity = 0.f;
Eigen::Vector3f candidate = car.position + stepDelta;
if (navigation.isReady() && !isCarFootprintWalkable(candidate, car.rotation)) {
car.velocity = 0.f;
break;
}
npcCar.position = candidate;
car.position = candidate;
}
}
@ -1925,15 +2060,15 @@ void Location::setup()
}
}
void Location::drawNpcCar()
void Location::drawNpcCar(const NpcCar& car)
{
if (!npcCar.texture) return;
if (!car.texture) return;
renderer.PushMatrix();
renderer.TranslateMatrix(npcCar.position);
renderer.TranslateMatrix(car.position);
renderer.TranslateMatrix({ 0, 0.7f, 0 });
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(npcCar.rotation, Eigen::Vector3f::UnitY())).toRotationMatrix());
glBindTexture(GL_TEXTURE_2D, npcCar.texture->getTexID());
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(car.rotation, Eigen::Vector3f::UnitY())).toRotationMatrix());
glBindTexture(GL_TEXTURE_2D, car.texture->getTexID());
renderer.DrawVertexRenderStruct(carMesh);
if (carWheelTexture) {
@ -1953,7 +2088,7 @@ void Location::setup()
renderer.PushMatrix();
renderer.TranslateMatrix(wheelPositions[i]);
if (isFront[i]) {
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(npcCar.steeringAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(car.steeringAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
}
renderer.DrawVertexRenderStruct(carWheelMesh);
renderer.PopMatrix();
@ -2152,6 +2287,7 @@ void Location::setup()
roomTexture.reset();
npcCar.texture.reset();
npcBanditCar.texture.reset();
//dialogueSystem.dialogueDatabase.clear();
@ -2168,6 +2304,11 @@ void Location::setup()
dialoguePlayedOffroad = false;
dialoguePlayedCrash = false;
playerOnFootSeconds = 0.f;
npcBanditCarSpawned = false;
dialoguePlayedBandit1 = false;
banditExitedNpcBanditCar = false;
std::cout << "[LOCATION] Cleanup complete" << std::endl;
}

View File

@ -98,6 +98,7 @@ namespace ZL
float carMaxSteerAngle = 0.6f;
NpcCar npcCar;
NpcCar npcBanditCar;
bool keyForward = false;
bool keyBackward = false;
@ -144,6 +145,11 @@ namespace ZL
Eigen::Vector3f banditLastFollowTarget = Eigen::Vector3f::Zero();
bool banditLastFollowTargetValid = false;
float playerOnFootSeconds = 0.f;
bool npcBanditCarSpawned = false;
bool dialoguePlayedBandit1 = false;
bool banditExitedNpcBanditCar = false;
bool dialoguePlayedVillageRescue1 = false;
bool dialoguePlayedVillageIntro1 = false;
bool dialogueVillageIntro1Finished = false;
@ -185,10 +191,10 @@ namespace ZL
bool setNavigationAreaAvailable(const std::string& areaName, bool available);
void update(int64_t deltaMs);
void updateNpcCar(int64_t deltaMs);
void updateNpcCar(NpcCar& car, int64_t deltaMs);
void updateGirlfriendFollow();
void updateBanditFollow();
void drawNpcCar();
void drawNpcCar(const NpcCar& car);
void handleDown(int64_t fingerId, int eventX, int eventY, int mx, int my);
void handleUp(int64_t fingerId, int mx, int my);
@ -219,8 +225,8 @@ namespace ZL
bool isCarFootprintWalkable(const Eigen::Vector3f& center, float rotation) const;
bool isPointInCarFootprint(const Eigen::Vector3f& point, const Eigen::Vector3f& center, float rotation) const;
bool doesPlayerCarCollideWithNpcCar(const Eigen::Vector3f& center, float rotation) const;
void pushOutOfNpcCarFootprint(Eigen::Vector3f& position) const;
bool doesPlayerCarCollideWithNpcCar(const NpcCar& car, const Eigen::Vector3f& center, float rotation) const;
void pushOutOfNpcCarFootprint(const NpcCar& car, Eigen::Vector3f& position) const;
// --- FIRST PERSON BUILDING ZONE ---
bool firstPersonMode = false;