#include "state_playing.hpp" #include "inventory/weapon.hpp" #include "map/map.hpp" #include "building/research.hpp" #include "building/craft.hpp" #include "game/game.hpp" #include "defaults/ui.hpp" #include "character/message.hpp" #include "defaults/shuffle_texture.hpp" StatePlaying::StatePlaying() { std::cout << "CREATE STATE_PLAYING " << this << std::endl; } StatePlaying::~StatePlaying() { std::cout << "STATEPL DTOR " << this << std::endl; } StatePlaying::StatePlaying(StatePlaying&&) { std::cout << "[StatePlaying] Move constructor called!" << std::endl; } bool StatePlaying::Init(Game* game) { std::cout << "Call init state_game\n"; Default::now = SDL_GetPerformanceCounter(); Default::last = 0; Default::delta_time = 0.0; cursor = game->cursor; cursor->set_State(CursorState::HIDDEN); // INIT Bird Bird::Init(game->renderer); player = std::make_unique(); player->Init(game->renderer); std::cout << "PLAYER:: " << this << " " << player << std::endl; // INIT Weapons Weapon::Init(game->renderer); // INIT Building BuildingData::Init(game->renderer); // INIT Enemy Enemy::init_All(game->renderer); Map::tile_map = Map::load_MapTiles(Map::save_path); if (Map::tile_map.size() == 0) Map::Init(); Map::load_TileCollision(Map::save_collission_path); if (Map::tile_collission_map.size() == 0) Map::init_Collider(); Map::offset = {0, 0}; Default::game_scale = 4.0; // START CHEAT if (game->is_cheating) { player->inventory->add_Resource(ResourceType::WOOD, 120, player->messages.get()); player->inventory->add_Resource(ResourceType::STONE, 120, player->messages.get()); player->inventory->add_Resource(ResourceType::CLAY, 120, player->messages.get()); player->inventory->add_Resource(ResourceType::IRON, 120, player->messages.get()); player->set_ResourceDiscovery(ResourceType::WOOD); player->set_ResourceDiscovery(ResourceType::STONE); player->set_ResourceDiscovery(ResourceType::CLAY); player->set_ResourceDiscovery(ResourceType::IRON); player->researched_items[static_cast(ItemType::SWORD_WOOD)] = true; player->researched_items[static_cast(ItemType::WOODAXE_STONE)] = true; player->researched_items[static_cast(ItemType::CULTIVATOR)] = true; player->researched_buildings[static_cast(BuildingType::CRAFTING_WOOD_1)] = true; player->set_BuildingDiscovery(); player->inventory->add_Item(ItemType::SWORD_WOOD, player->messages.get()); player->inventory->add_Item(ItemType::WOODAXE_STONE, player->messages.get()); player->inventory->add_Item(ItemType::BUILDING_TOOL, player->messages.get()); player->inventory->add_Item(ItemType::CULTIVATOR, player->messages.get()); player->inventory->add_Vegetable(VegetableData::Type::CARROT, 4, player->messages.get()); player->inventory->add_Vegetable(VegetableData::Type::CABBAGE, 4, player->messages.get()); player->is_attackable = true; } // END CHEAT // Enemy Enemy::enemies.clear(); Enemy::enemies_to_spawn.clear(); /* */ Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {850, 480}, {16,16,2,false,false,0,1.2}); Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {450, 480}, {16,16,2,false,false,0,1.2}); Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 480}, {16,16,2,false,false,0,1.2}); /* Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {140, 100}, {6,6,1,false,false,0,1.2}); Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {100, 10}, {6,6,1,false,false,0,1.2}); Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {100, 130}, {6,6,1,false,false,0,1.2}); Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {200, 100}, {6,6,1,false,false,0,1.2}); Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {600,100}, {6,6,1,false,false,0,1.2}); Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {600,100}, {6,6,1,false,false,0,1.2}); */ //Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 100}, {6,6,1,false,false,0,1.2}); //for (int i = 0; i < 12; i++) Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {600,100}, {6,6,1,false,false,0,1.2}); return true; } inline void setActiveMenu(CharacterMenuType& active_menu, const CharacterMenuType& new_menu, AnimatedCursor* cursor) { switch (active_menu) { case CharacterMenuType::NONE: active_menu = new_menu; cursor->set_State(CursorState::ANIMATED); break; default: active_menu = CharacterMenuType::NONE; cursor->set_State(CursorState::HIDDEN); break; } } void StatePlaying::handle_Events(SDL_Event& event, Game* game) { if (game->input.cursor_over_tileset) { game->input.mouse_game_offset = {(int)Tile::tileset_offset.x, (int)Tile::tileset_offset.y }; } game->input.clicked_on_map = false; //std::cout << "ET: " << (int)event.type << std::endl; switch (event.type) { case SDL_EVENT_KEY_DOWN: { if (event.key.scancode >= SDL_SCANCODE_1 && event.key.scancode <= SDL_SCANCODE_6) { player->inventory->selected_hotbar_last = player->inventory->selected_hotbar; player->inventory->selected_hotbar = (int)(event.key.scancode - SDL_SCANCODE_1) + 1; } if (event.key.scancode == SDL_SCANCODE_0) { Default::game_scale = 4.0; } break; } case SDL_EVENT_KEY_UP: switch (event.key.scancode) { case SDL_SCANCODE_B: { InventoryItem *sel_item = nullptr; if (player->selected_item->object_type == InventoryObjectType::ITEM) { sel_item = static_cast(player->selected_item); if (sel_item->type == ItemType::BUILDING_TOOL) setActiveMenu(player->active_menu, CharacterMenuType::BUILDING, cursor); else player->messages->Add(MessageKey::BUILDING_TOOL_REQUIRED); } else player->messages->Add(MessageKey::BUILDING_TOOL_REQUIRED); break; } case SDL_SCANCODE_R: Inventory::selected_hotbar = !Inventory::selected_hotbar ? Inventory::selected_hotbar_last : 0; break; case SDL_SCANCODE_E: setActiveMenu(player->active_menu, CharacterMenuType::INVENTORY, cursor); Inventory::draw_menu = !Inventory::draw_menu; break; case SDL_SCANCODE_K: { Building::construction_mode = Building::construction_mode == BuildingStatus::DECONSTRUCT ? BuildingStatus::CONSTRUCTING: BuildingStatus::DECONSTRUCT; InventoryItem *it = static_cast(player->selected_item); if (it && it->type == ItemType::CULTIVATOR) player->cultivation_logic.is_removing = !player->cultivation_logic.is_removing; break; } case SDL_SCANCODE_F5: player->health_Reduce(100000000); break; case SDL_SCANCODE_F11: // FOR TESTING Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 100}, {16,16,2,false,false,0,1.2}); return; default: break; } break; case SDL_EVENT_MOUSE_BUTTON_UP: if (!game->input.pressed_ctrl && !game->input.pressed_shift) game->input.clicked_on_map = true; break; default: break; } } void update_CameraOffset( const SDL_FPoint& player_world, const SDL_Rect& win_size ) { const float inv_scale = 1.0f / Default::game_scale; const float logical_w = win_size.w * inv_scale; const float logical_h = win_size.h * inv_scale; const float margin_x = logical_w * 0.4f; const float margin_y = logical_h * 0.4f; const float player_screen_x = player_world.x + Map::offset.x; const float player_screen_y = player_world.y + Map::offset.y; float target_offset_x = Map::offset.x; float target_offset_y = Map::offset.y; // Horizontal deadzone if (player_screen_x < margin_x) { target_offset_x = margin_x - player_world.x; } else if (player_screen_x > logical_w - margin_x) { target_offset_x = (logical_w - margin_x) - player_world.x; } // Vertical deadzone if (player_screen_y < margin_y) { target_offset_y = margin_y - player_world.y; } else if (player_screen_y > logical_h - margin_y) { target_offset_y = (logical_h - margin_y) - player_world.y; } // --- Smooth interpolation --- const float follow_speed = 10.0f; // higher = snappier const float t = 1.0f - std::exp(-follow_speed * Default::delta_time); Map::offset.x += (target_offset_x - Map::offset.x) * t; Map::offset.y += (target_offset_y - Map::offset.y) * t; } void StatePlaying::Update(Game* game) { // SET Map offset Map::set_Offset(game->input); // VEGETABLES for (Vegetable* veg : VegetableData::all_vegetables) { veg->Grow(Default::get_TimeSinceStartInSec()); } // CHARACTER player->handle_Input(game->input, game->win_size); player->Update(); if (player->status == CharacterStatus::DEAD && player->death_shuffler == nullptr) { player->death_shuffler = new PixelShuffler(game->renderer, player->active_anim->surface); player->shuffle_timer = 0.0f; Animation::audio->Play("character.dead"); return; } // MESSAGES player->messages->Update(); // START ENEMY HANDLING // spawn for (size_t i = 0; i < Enemy::enemies_to_spawn.size(); ) { SpawnParams &sp = Enemy::enemies_to_spawn[i]; if (Enemy::spawn_Enemy(sp)) Enemy::enemies_to_spawn.erase(Enemy::enemies_to_spawn.begin() + static_cast(i)); else ++i; } // get moves Enemy::run_GetMovesThreads(); // update moves for (Enemy* enemy : Enemy::enemies) enemy->Update(*player); // clear dead Enemy::remove_Dead(); // END ENEMY HANDLING // CAMERA update_CameraOffset({player->x+player->tile_size/2, player->y+player->tile_size/2}, game->win_size); } void StatePlaying::Render(Game* game) { if (!game->renderer) std::cerr << "ERROR in StatePlayin::Render\n"; player->messages->render_InventoryMessages(game, player->inventory.get()); switch (player->active_menu) { case CharacterMenuType::NONE: break; case CharacterMenuType::BUILDING: BuildingData::draw_WorkbenchMenu(game->renderer, game->win_size, player->discovered_buildings); break; case CharacterMenuType::INVENTORY: player->inventory->draw_Menu( game->renderer, game->win_size, Ui::font_menu, player->researched_items, Inventory::cursor_OverCraftButton(game->input.mouse_state_raw)); break; case CharacterMenuType::RESEARCH: Research::draw_ReserachMenu(game->renderer, game->win_size, Building::selected_building_type, player->researched_buildings, player->researched_items, Research::cursor_OverResearchButton(game->input.mouse_state_raw)); break; case CharacterMenuType::WORKBENCH: Craft::draw_CraftMenu(game, Building::selected_building_type, Craft::cursor_OverCraftButton(game->input.mouse_state_raw)); break; } player->inventory->draw_Hotbar(game->renderer, Ui::font_menu); //player->messages->render_ResourceMessages(game, player->inventory->resources); Ui::draw_BottomLeftBars(game->renderer, game->win_size, *player); } void StatePlaying::Load(SDL_Renderer* renderer, std::string path) { Map::tile_map = Map::load_MapTiles(path + "/map"); std::cout << "STATE LOAD\n"; Map::load_TileCollision(path + "/collisions"); if (!renderer) std::cerr << "FUCK NO RENDERER..\n"; Enemy::load_All(path+"/enemies"); for (size_t i = 0; i < Enemy::enemies_to_spawn.size(); ) { SpawnParams &sp = Enemy::enemies_to_spawn[i]; if (Enemy::spawn_Enemy(sp)) Enemy::enemies_to_spawn.erase(Enemy::enemies_to_spawn.begin() + static_cast(i)); else ++i; } player->Load(path); } void StatePlaying::Save(std::string path) { Map::save_MapTiles(Map::tile_map, path + "/map"); Map::save_TileCollision(path + "/collisions"); Enemy::save_All(path+"/enemies"); player->Save(path); }