318 lines
9.7 KiB
Plaintext
318 lines
9.7 KiB
Plaintext
#include "include/bgt_compat.nvgt"
|
|
#include "include/sound_pool.nvgt"
|
|
#include "include/virtual_dialogs.nvgt"
|
|
|
|
// Audio
|
|
sound_pool p(100);
|
|
|
|
#include "src/constants.nvgt"
|
|
#include "src/player.nvgt"
|
|
#include "src/world_state.nvgt"
|
|
#include "src/inventory.nvgt"
|
|
#include "src/environment.nvgt"
|
|
#include "src/combat.nvgt"
|
|
#include "src/save_system.nvgt"
|
|
#include "src/time_system.nvgt"
|
|
#include "src/audio_utils.nvgt"
|
|
#include "src/notify.nvgt"
|
|
|
|
int run_main_menu() {
|
|
screen_reader_speak("Draugnorak. Main menu.", true);
|
|
|
|
int selection = 0;
|
|
string load_label = has_save_game() ? "Load Game" : "Load Game (no save found)";
|
|
string[] options = {"New Game", load_label, "Exit"};
|
|
|
|
screen_reader_speak(options[selection], true);
|
|
|
|
while(true) {
|
|
wait(5);
|
|
|
|
if (key_pressed(KEY_DOWN)) {
|
|
selection++;
|
|
if (selection >= options.length()) selection = 0;
|
|
screen_reader_speak(options[selection], true);
|
|
}
|
|
|
|
if (key_pressed(KEY_UP)) {
|
|
selection--;
|
|
if (selection < 0) selection = options.length() - 1;
|
|
screen_reader_speak(options[selection], true);
|
|
}
|
|
|
|
if (key_pressed(KEY_RETURN)) {
|
|
return selection;
|
|
}
|
|
|
|
if (key_pressed(KEY_ESCAPE)) {
|
|
return 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
void main()
|
|
{
|
|
show_window("Draugnorak");
|
|
|
|
bool game_started = false;
|
|
while (!game_started) {
|
|
int selection = run_main_menu();
|
|
|
|
if (selection == 0) {
|
|
start_new_game();
|
|
screen_reader_speak("New game started.", true);
|
|
game_started = true;
|
|
} else if (selection == 1) {
|
|
if (load_game_state()) {
|
|
screen_reader_speak("Game loaded.", true);
|
|
game_started = true;
|
|
} else {
|
|
if (has_save_game()) {
|
|
screen_reader_speak("Unable to load save.", true);
|
|
} else {
|
|
screen_reader_speak("No save found.", true);
|
|
}
|
|
}
|
|
} else {
|
|
exit();
|
|
}
|
|
}
|
|
|
|
while(true)
|
|
{
|
|
wait(5);
|
|
|
|
if(key_pressed(KEY_ESCAPE))
|
|
{
|
|
int really_exit = virtual_question("Draugnorak", "Really exit?");
|
|
if (really_exit == 1) {
|
|
exit();
|
|
}
|
|
// Restore focus to the game window
|
|
show_window("Draugnorak");
|
|
}
|
|
|
|
// Time & Environment updates
|
|
update_time();
|
|
update_environment();
|
|
update_snares();
|
|
update_streams();
|
|
update_fires();
|
|
update_zombies();
|
|
update_bandits();
|
|
|
|
// Fire damage check (only if not jumping)
|
|
WorldFire@ fire_on_tile = get_fire_at(x);
|
|
if (fire_on_tile != null && !jumping && fire_damage_timer.elapsed > 1000) {
|
|
player_health--;
|
|
fire_damage_timer.restart();
|
|
screen_reader_speak("Burning! " + player_health + " health remaining.", true);
|
|
}
|
|
|
|
// Healing in base area
|
|
if (x <= BASE_END && player_health < max_health) {
|
|
WorldHerbGarden@ herb_garden = get_herb_garden_at_base();
|
|
int heal_interval = (herb_garden != null) ? 30000 : 150000; // 30 seconds with garden, 2.5 minutes without
|
|
|
|
if (healing_timer.elapsed > heal_interval) {
|
|
player_health++;
|
|
healing_timer.restart();
|
|
screen_reader_speak(player_health + " health.", true);
|
|
}
|
|
}
|
|
|
|
// Death check
|
|
if (player_health <= 0) {
|
|
screen_reader_speak("You have died.", true);
|
|
wait(2000);
|
|
exit();
|
|
}
|
|
|
|
// Inventory & Actions
|
|
check_inventory_keys(x);
|
|
check_action_menu(x);
|
|
check_crafting_menu(x, BASE_END);
|
|
check_equipment_menu();
|
|
check_time_input();
|
|
check_notification_keys();
|
|
|
|
// Health Key
|
|
if (key_pressed(KEY_H)) {
|
|
screen_reader_speak(player_health + " health of " + max_health, true);
|
|
}
|
|
|
|
// Coordinates Key
|
|
if (key_pressed(KEY_X)) {
|
|
string direction_label = (facing == 1) ? "east" : "west";
|
|
screen_reader_speak(direction_label + ", x " + x + ", y " + y, true);
|
|
}
|
|
|
|
// Barricade Key (base only)
|
|
if (key_pressed(KEY_B)) {
|
|
if (x <= BASE_END) {
|
|
screen_reader_speak("Barricade health " + barricade_health + " of " + BARRICADE_MAX_HEALTH, true);
|
|
} else {
|
|
screen_reader_speak("You are not in the base.", true);
|
|
}
|
|
}
|
|
|
|
// Climbing and Falling Updates
|
|
update_climbing();
|
|
update_falling();
|
|
|
|
// Down arrow to climb down from tree
|
|
if (key_pressed(KEY_DOWN)) {
|
|
Tree@ tree = get_tree_at(x);
|
|
if (tree != null && !tree.is_chopped && y > 0 && !jumping && !climbing && !falling) {
|
|
climb_down_tree();
|
|
}
|
|
}
|
|
|
|
// Jumping Logic
|
|
if(key_pressed(KEY_UP))
|
|
{
|
|
if(!jumping && !climbing && !falling)
|
|
{
|
|
// Check if on tree tile
|
|
Tree@ tree = get_tree_at(x);
|
|
if (tree != null && !tree.is_chopped && y == 0) {
|
|
// Start climbing the tree
|
|
start_climbing_tree(x);
|
|
} else if (y == 0) {
|
|
// Normal jump
|
|
p.play_stationary("sounds/jump.ogg", false);
|
|
jumping = true;
|
|
jumptimer.restart();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(jumping && jumptimer.elapsed > 850)
|
|
{
|
|
jumping = false;
|
|
y = 0; // Reset y after jump
|
|
play_land_sound(x, BASE_END, GRASS_END);
|
|
// Check for snare on landing?
|
|
check_snare_collision(x);
|
|
}
|
|
|
|
// Set y to 3 during jump
|
|
if(jumping && y == 0) {
|
|
y = 3;
|
|
}
|
|
|
|
movetime = jumping ? jump_speed : walk_speed;
|
|
|
|
// Movement Logic
|
|
if (key_pressed(KEY_LEFT) && facing != 0 && !climbing && !falling) {
|
|
facing = 0;
|
|
screen_reader_speak("west", true);
|
|
walktimer.restart();
|
|
}
|
|
if (key_pressed(KEY_RIGHT) && facing != 1 && !climbing && !falling) {
|
|
facing = 1;
|
|
screen_reader_speak("east", true);
|
|
walktimer.restart();
|
|
}
|
|
|
|
if(walktimer.elapsed > movetime)
|
|
{
|
|
int old_x = x;
|
|
|
|
// Check if trying to move left/right while in tree
|
|
if((key_down(KEY_LEFT) || key_down(KEY_RIGHT)) && y > 0 && !jumping && !falling) {
|
|
// Fall out of tree
|
|
climbing = false;
|
|
start_falling();
|
|
}
|
|
|
|
if(key_down(KEY_LEFT) && x > 0 && !climbing && !falling)
|
|
{
|
|
facing = 0;
|
|
x--;
|
|
walktimer.restart();
|
|
if(!jumping) {
|
|
play_footstep(x, BASE_END, GRASS_END);
|
|
check_snare_collision(x); // Check when moving onto a tile
|
|
}
|
|
}
|
|
else if(key_down(KEY_RIGHT) && x < MAP_SIZE - 1 && !climbing && !falling)
|
|
{
|
|
facing = 1;
|
|
x++;
|
|
walktimer.restart();
|
|
if(!jumping) {
|
|
play_footstep(x, BASE_END, GRASS_END);
|
|
check_snare_collision(x); // Check when moving onto a tile
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset search timer if shift is used with other keys
|
|
if((key_down(KEY_LSHIFT) || key_down(KEY_RSHIFT))) {
|
|
if(key_pressed(KEY_COMMA) || key_pressed(KEY_PERIOD)) {
|
|
searching = false;
|
|
search_delay_timer.restart();
|
|
}
|
|
}
|
|
|
|
// Searching Logic
|
|
if((key_down(KEY_LSHIFT) || key_down(KEY_RSHIFT)) && search_timer.elapsed > 2000 && !searching)
|
|
{
|
|
searching = true;
|
|
search_delay_timer.restart();
|
|
}
|
|
|
|
// Complete search after delay
|
|
if(searching && search_delay_timer.elapsed >= 1000)
|
|
{
|
|
searching = false;
|
|
search_timer.restart();
|
|
perform_search(x);
|
|
}
|
|
|
|
// Sling charge detection
|
|
if (sling_equipped && (key_down(KEY_LCONTROL) || key_down(KEY_RCONTROL)) && !sling_charging) {
|
|
if (inv_stones > 0) {
|
|
sling_charging = true;
|
|
sling_charge_timer.restart();
|
|
sling_sound_handle = p.play_stationary("sounds/weapons/sling_swing.ogg", true);
|
|
last_sling_stage = -1;
|
|
} else {
|
|
screen_reader_speak("No stones.", true);
|
|
}
|
|
}
|
|
|
|
// Update sling charge state while holding
|
|
if (sling_charging && (key_down(KEY_LCONTROL) || key_down(KEY_RCONTROL))) {
|
|
update_sling_charge();
|
|
}
|
|
|
|
// Sling release detection
|
|
if (sling_charging && (!key_down(KEY_LCONTROL) && !key_down(KEY_RCONTROL))) {
|
|
release_sling_attack(x);
|
|
sling_charging = false;
|
|
if (sling_sound_handle != -1) {
|
|
p.destroy_sound(sling_sound_handle);
|
|
sling_sound_handle = -1;
|
|
}
|
|
}
|
|
|
|
// Non-sling weapon attacks (existing pattern)
|
|
if (!sling_equipped && !sling_charging) {
|
|
int attack_cooldown = 1000;
|
|
if (spear_equipped) attack_cooldown = 800;
|
|
if (axe_equipped) attack_cooldown = 1600;
|
|
|
|
if((key_down(KEY_LCONTROL) || key_down(KEY_RCONTROL)) && attack_timer.elapsed > attack_cooldown)
|
|
{
|
|
attack_timer.restart();
|
|
perform_attack(x);
|
|
}
|
|
}
|
|
|
|
// Audio Listener Update
|
|
p.update_listener_1d(x);
|
|
}
|
|
}
|