/* Copyright © 2020 tyrolyean * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "game.h" #include "structures.h" #include "16550.h" #include #include #include char command_buffer[100]; uint8_t command_buffer_pointer = 0x00; uint8_t current_room = ROOM_LONELYROAD; uint8_t computer_state = 0; bool bear_shot = false; void routine_game(){ if(command_buffer_pointer >= sizeof(command_buffer)){ command_buffer_pointer = 0x00; memset(command_buffer, 0, sizeof(command_buffer)); println("\nToo much input!"); return; } if(command_buffer[command_buffer_pointer-1] == '\n' || command_buffer[command_buffer_pointer-1] == '\r'){ /* A command from the user has been received, we are ready to * do something!*/ int8_t action_id = -1; for(size_t i = 0; i < sizeof(action_table)/sizeof(const char*); i++){ if(strncasecmp(action_table[i], command_buffer, strlen(action_table[i])) == 0){ action_id = i; break; } } if(action_id < 0){ println(info_table[1]); }else{ perform_action(action_id); } command_buffer_pointer = 0x00; memset(command_buffer, 0, sizeof(command_buffer)); } return; } void ingest_user_char(char in){ if(in == 0x7F /* DELETE CHAR */){ command_buffer[command_buffer_pointer--] = 0x00; }else{ command_buffer[command_buffer_pointer++] = in; } return; } void perform_action(uint8_t action_id){ putchar_16550('\n', NULL); switch(action_id){ default: case ACTION_HELP: println("You can:"); for(size_t i = 0; i < NUM_ACTIONS; i++){ println(" %s",action_table[i]); } break; case ACTION_DESCRIBE: describe_room(current_room, false); break; case ACTION_NORTH: case ACTION_SOUTH: case ACTION_WEST: case ACTION_EAST: move_direction(action_id -1); break; case ACTION_INVENTORY: print_inventory(); break; case ACTION_SEARCH: print_room_item(); break; case ACTION_TAKE: consume_room_item(command_buffer+ strlen(action_table[ACTION_TAKE])+1); break; case ACTION_USE: use_item(command_buffer+ strlen(action_table[ACTION_USE])+1); break; }; println(info_table[3]); return; } void move_direction(uint8_t direction){ if(!room_map_table[current_room][direction]){ println(info_table[4]); return; } println("Moving towards %s",action_table[direction+1]); current_room = room_map_table[current_room][direction]; describe_room(current_room,true); current_track = room_track_map[current_room]; return; } void describe_room(uint8_t room, bool auto_desc){ println(room_table[room]); if(room_visited_table[room] && auto_desc){ room_visited_table[room] = true; return; } room_visited_table[room] = true; putchar_16550('\n', NULL); println(room_description_table[room]); return; } void print_inventory(){ bool found_item = false; for(size_t i = 0; i < NUM_ITEMS; i++){ if(inventory[i]){ found_item = true; break; } } if(found_item){ println("You have:"); for(size_t i = 0; i < NUM_ITEMS; i++){ if(inventory[i]){ println(" %s",item_table[i]); } } }else{ println("Your inventory is empty"); } return; } void print_room_item(){ if(item_room_map[current_room] < 0){ println(info_table[6]); }else{ println("You found a %s", item_table[item_room_map[current_room]]); } return; } void consume_room_item(const char* item_name){ if(item_room_map[current_room] < 0){ println(info_table[6]); }else{ for(int8_t i = 0; i < NUM_ITEMS; i++){ if(strncasecmp(item_table[i], item_name, strlen(item_table[i])) == 0){ if(item_room_map[current_room] != i){ break; } println("You took the %s", item_table[item_room_map[ current_room]]); inventory[item_room_map[current_room]] = true; item_room_map[current_room] = -1; return; } } println("That's not here..."); } return; } void use_item(const char* item_name){ for(size_t i = 0; i < NUM_ITEMS; i++){ if(strncasecmp(item_table[i], item_name, strlen(item_table[i])) == 0){ use_item_id(i); return; } } println(info_table[2]); return; } void use_item_id(uint8_t item_id){ if(!inventory[item_id]){ println(info_table[2]); return; } switch(item_id){ case ITEM_SAUSAGE: if(current_room == ROOM_SNDIRTROAD){ inventory[ITEM_SAUSAGE] = false; room_map_table[current_room][DIRECTION_NORTH] = ROOM_FIREPLACE; println(info_table[10]); return; } break; case ITEM_PISTOL: if(current_room == ROOM_SNDIRTROAD){ room_map_table[current_room][DIRECTION_NORTH] = ROOM_FIREPLACE; println(info_table[7]); bear_shot = true; return; } else if(current_room == ROOM_NOTHING){ /* The real end i guess. I won't put this in the * info table as it *SHOULD* only be displayed * once. */ println("You cry for help. It's no use. You " "attempt to shoot yourself. It's no " "use... You run out of bullets"); inventory[ITEM_PISTOL] = false; return; } break; case ITEM_KEY: if(current_room == ROOM_EWSTREET){ inventory[ITEM_KEY] = false; room_map_table[current_room][DIRECTION_NORTH] = ROOM_OLDHOUSE; println(info_table[13]); return; } break; case ITEM_FLOPPY: case ITEM_FLESH: case ITEM_SCREWDRIVER: case ITEM_KEYBOARD: if(current_room == ROOM_COMPUTER){ if(perform_computer_action(item_id)){ return; } } break; }; println(info_table[2]); return; } bool perform_computer_action(uint8_t item_id){ static bool fleshed = false; if(item_id == ITEM_KEYBOARD && computer_state == COMPUTER_STATE_NOTHING){ computer_state = COMPUTER_STATE_KEYBOARD; inventory[item_id] = false; println("You connected the keyboard"); return true; } if(item_id == ITEM_FLOPPY && computer_state == COMPUTER_STATE_KEYBOARD){ computer_state = COMPUTER_STATE_FLOPPY; inventory[item_id] = false; println("You inseted the floppy disk"); return true; } if(item_id == ITEM_FLESH && computer_state == COMPUTER_STATE_KEYBOARD){ computer_state = COMPUTER_STATE_FLOPPY; inventory[item_id] = false; println("You inserted the flesh into the floppy drive"); fleshed = true; return true; } if(item_id == ITEM_SCREWDRIVER && computer_state == COMPUTER_STATE_FLOPPY){ computer_state = COMPUTER_STATE_FLOPPY; inventory[item_id] = false; /* Perform a reset of the game */ println("You start the computer with the screwdriver, sit down" " and watch it boot into a textadventure:"); reset_game(fleshed); return true; } return false; } /* Resets the game into "original" state or the bear dead state or the FLESH * game state. FLESH is basically the end. You need to reset your computer * afterwards. */ void reset_game(bool fleshed){ /* clear inventory */ memset(inventory, 0, sizeof(inventory)); /* Reset rooms visited */ memset(room_visited_table, 0, sizeof(inventory)); /* Reset items in rooms */ for(size_t i = 0; i < NUM_ROOMS; i++){ item_room_map[i] = -1; } if(fleshed){ current_room = ROOM_NOTHING; inventory[ITEM_PISTOL] = true; }else if(bear_shot){ current_room = ROOM_LONELYROAD; room_description_table[ROOM_SNDIRTROAD] = sndirtroad_msg[1]; item_room_map[ROOM_SNDIRTROAD] = ITEM_FLESH; }else{ current_room = ROOM_LONELYROAD; room_map_table[ROOM_SNDIRTROAD][DIRECTION_NORTH] = 0x00; item_room_map[ROOM_SNDIRTROAD] = ITEM_SAUSAGE; item_room_map[ROOM_LONELYROAD] = ITEM_PISTOL; item_room_map[ROOM_BASEMENT] = ITEM_FLOPPY; } item_room_map[ROOM_EWSTREET] = ITEM_KEY; item_room_map[ROOM_OLDHOUSE] = ITEM_SCREWDRIVER; item_room_map[ROOM_ATTIC] = ITEM_KEYBOARD; computer_state = COMPUTER_STATE_NOTHING; room_map_table[ROOM_EWSTREET][DIRECTION_NORTH] = 0x00; current_track = room_track_map[current_room]; describe_room(current_room, false); return; } void init_game(){ room_description_table[ROOM_SNDIRTROAD] = sndirtroad_msg[0]; info_table[3] = user_action_req_msgs[0]; return; }