From fb5a98b72ab79949d1da7f75a3d6150c2906ef40 Mon Sep 17 00:00:00 2001 From: jacopograndi Date: Mon, 30 Aug 2021 14:48:06 +0200 Subject: gui: tech representation, menu, tile & unit info, attack info --- graphics/graphics.cpp | 411 +++++++++++++++++++++++++++++++++++++++++++++++++- graphics/graphics.h | 1 + 2 files changed, 409 insertions(+), 3 deletions(-) (limited to 'graphics') diff --git a/graphics/graphics.cpp b/graphics/graphics.cpp index 9658605..3b943a4 100644 --- a/graphics/graphics.cpp +++ b/graphics/graphics.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include "graphics.h" #include "../game/menu.h" #include "../game/tile.h" @@ -53,7 +55,13 @@ void render_menu (Graphics *graphics, Gst &gst, Menu &menu) { ); float acc = 0; for (Option opt : menu.options) { - graphics->backend.txt.render_text(opt.name, menu.pos + vec2 {10, 10 + acc}); + int r=0, g=0, b=0; + if (opt.id == menu.over) { + Player &player = gst.players[gst.turn]; + r = player.r; g = player.g; b = player.b; + } + graphics->backend.txt.render_text( + opt.name, menu.pos + vec2 {10, 10 + acc}, r, g, b); float width = graphics->backend.txt.get_width(opt.name); if (opt.cost.size() > 0) { graphics->backend.txt.render_text( @@ -68,6 +76,343 @@ void render_menu (Graphics *graphics, Gst &gst, Menu &menu) { } } +void render_menu_tech (Graphics *graphics, Gst &gst, View &view) { + vec2 res { (float)graphics->resx, (float)graphics->resy }; + if (view.menu_tech.active) { + vec2 pos { res }; + float height = view.menu_tech.options.size() * 20; + vec2 size { 120, height+10 }; + pos *= 0.5f; + pos -= size/2; + graphics->backend.render_rect( + 255,255,255,255, + view.menu_tech.pos.x,view.menu_tech.pos.y, + view.menu_tech.size.x,view.menu_tech.size.y + ); + + float x = 0, y = 0; + for (auto v : view.menu_tech.tech_opt_ordered) { + for (auto opt : v) { + int r=0, g=0, b=0; + Player &player = gst.players[gst.turn]; + if (opt.tech->id == view.menu_tech.over) { + r = player.r; g = player.g; b = player.b; + } + if (opt.tech->level > player.level) { + r = 100; g = 100; b = 100; + } + if (opt.tech->cost[0] > player.res[0] + || opt.tech->cost[1] > player.res[1] ) + { + r = 100; g = 100; b = 100; + } + bool req_id = false; + for (auto &ent : gst.entities) { + if (ent.owner == gst.turn + && ent.info->id == opt.tech->req_id + && ent.building == 0) + { + req_id = true; + } + } + if (!req_id) { + r = 100; g = 100; b = 100; + } + graphics->backend.txt.render_text(opt.name, + view.menu_tech.pos + vec2 {10 + x, 10 + y}, r, g, b); + float width = graphics->backend.txt.get_width(opt.name); + /* + if (opt.tech->cost.size() > 0) { + graphics->backend.txt.render_text( + std::to_string (opt.tech->cost[0]) + "f", + view.menu_tech.pos + vec2 { width + 20 + x, 10 + y }); + graphics->backend.txt.render_text( + std::to_string (opt.tech->cost[1]) + "g", + view.menu_tech.pos + vec2 { width + 50 + x, 10 + y }); + }*/ + y += 10; + } + x += 150; y = 0; + } + } +} + + +int get_entity_info_height (Entity &ent) { + return 155+10*ent.info->abilities.size(); +} + +void render_entity_info (Graphics *graphics, Gst &gst, vec2 pos, int i) { + Entity &ent = gst.entities[i]; + int w = 200, h = get_entity_info_height(ent); + + graphics->backend.render_rect (0,0,0,255, + (int)pos.x,(int)pos.y,w,h); + graphics->backend.render_rect (255,255,255,255, + (int)pos.x+1,(int)pos.y+1,w-2,h-2); + + graphics->backend.render_rect ( + 0,0,0,255, (int)pos.x+w-32-10-1, (int)pos.y+10-1,34,34); + graphics->backend.render_rect ( + 255,255,255,255, (int)pos.x+w-32-10, (int)pos.y+10,32,32); + + graphics->backend.render_sprite ( + (int)gst.entities[i].info->spritebounds.x, + (int)gst.entities[i].info->spritebounds.y, 16, 16, + (int)pos.x + w-32-10, + (int)pos.y + 10, 32, 32 + ); + + graphics->backend.txt.render_text(ent.info->name, pos + vec2 { 10, 10 }); + graphics->backend.txt.render_text("Attack", pos + vec2 { 10, 30 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(ent.info->attack)), pos + vec2 { 90, 30 }); + graphics->backend.txt.render_text("Defence", pos + vec2 { 10, 45 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(ent.info->defence)), pos + vec2 { 90, 45 }); + graphics->backend.txt.render_text("Move", pos + vec2 { 10, 60 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(ent.info->move)), pos + vec2 { 90, 60 }); + graphics->backend.txt.render_text("Range", pos + vec2 { 10, 75 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(ent.info->range)), pos + vec2 { 90, 75 }); + graphics->backend.txt.render_text("Sight", pos + vec2 { 10, 90 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(ent.info->sight)), pos + vec2 { 90, 90 }); + graphics->backend.txt.render_text("Health", pos + vec2 { 10, 105 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(ent.hp)), pos + vec2 { 90, 105 }); + graphics->backend.txt.render_text("Class", pos + vec2 { 10, 120 }); + std::string ent_class = ""; + switch (ent.info->ent_class) { + case EntityInfo::Class::inf: ent_class = "Infantry"; break; + case EntityInfo::Class::cav: ent_class = "Cavalry"; break; + case EntityInfo::Class::ran: ent_class = "Ranged"; break; + case EntityInfo::Class::sie: ent_class = "Siege"; break; + case EntityInfo::Class::bld: ent_class = "Building"; break; + } + graphics->backend.txt.render_text(ent_class, pos + vec2 { 90, 120 }); + graphics->backend.txt.render_text("Abilities", pos + vec2 { 10, 135 }); + std::string abname; + for (int s=0; sabilities.size(); s++) { + abname = gst.abilities[ent.info->abilities[s]].name; + graphics->backend.txt.render_text(abname, + pos + vec2 { 90, 135+s*10.0f }); + } +} + +void render_tile_info (Graphics *graphics, Gst &gst, vec2 pos, int i) { + int x = i % gst.ground.sizex; + int y = i / gst.ground.sizex; + Tile &tile = gst.tiles[gst.ground.tiles[gst.ground.at(x,y)]]; + + int w = 200, h = 95; + graphics->backend.render_rect ( + 0,0,0,255, + (int)pos.x,(int)pos.y,w,h + ); + graphics->backend.render_rect ( + 255,255,255,255, + (int)pos.x+1,(int)pos.y+1,w-2,h-2 + ); + + graphics->backend.render_sprite ( + (int)tile.spritebounds.x, + (int)tile.spritebounds.y-16, 16, 32, + (int)pos.x + w-32-10, + (int)pos.y + 10-32, 32, 64 + ); + + graphics->backend.txt.render_text(tile.name, pos + vec2 { 10, 10 }); + graphics->backend.txt.render_text("Move", pos + vec2 { 10, 30 }); + graphics->backend.txt.render_text( + std::to_string(tile.move_cost), pos + vec2 { 90, 30 }); + graphics->backend.txt.render_text("Sight", pos + vec2 { 10, 45 }); + graphics->backend.txt.render_text( + std::to_string(tile.sight_cost), pos + vec2 { 90, 45 }); + graphics->backend.txt.render_text("Defence Bonus", pos + vec2 { 10, 60 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(tile.defence_bonus*100))+"%", pos + vec2 { 90, 60 }); + graphics->backend.txt.render_text("Range Bonus", pos + vec2 { 10, 75 }); + graphics->backend.txt.render_text( + std::to_string(tile.range_bonus), pos + vec2 { 90, 75 }); +} + +int render_attack_info_bonus (Graphics *graphics, Gst &gst, vec2 pos, + Entity &atk, Entity &def, bool attack, int rtl) +{ + std::vector bonuses; + if (attack) { bonuses = gst.get_bonuses(atk, def); } + else { bonuses = gst.get_bonuses(def, atk); } + + float value = attack ? atk.info->attack : atk.info->defence; + + { + std::string nlabel = attack ? "Attack" : "Defence"; + float labw = graphics->backend.txt.get_width(nlabel); + graphics->backend.txt.render_text(nlabel, + pos + vec2 { -labw*rtl, 0 }); + } { + std::string nlabel = std::to_string((int)roundf(value)); + float labw = graphics->backend.txt.get_width(nlabel); + graphics->backend.txt.render_text(nlabel, + pos + vec2 { 50*(1-rtl*2)-labw*rtl, 0 }); + } + + int bonusnum = 0; float atk_mod = 1; + for (int s=0; sbackend.txt.get_width(b.id_string()); + graphics->backend.txt.render_text( + b.id_string(), pos + vec2 { -idw*rtl, 10.0f+bonusnum*10 }); + std::string amt; + if (b.amt > 0) amt += "+"; + amt += std::to_string((int)roundf(b.amt*100)) + "%"; + float labw = graphics->backend.txt.get_width(amt); + graphics->backend.txt.render_text( + amt, pos + vec2 { 50*(1-rtl*2)-labw*rtl, 10.0f+bonusnum*10 }); + atk_mod += b.amt; + bonusnum ++; + } + } + + if (bonusnum > 0) { + { + std::string label = attack ? "->" : "<-"; + float labw = graphics->backend.txt.get_width(label); + graphics->backend.txt.render_text(label, + pos + vec2 { 70*(1-rtl*2)-labw*rtl, 0 }); + } + { + std::string label = std::to_string((int)roundf(value * atk_mod)); + float labw = graphics->backend.txt.get_width(label); + graphics->backend.txt.render_text(label, + pos + vec2 { 83*(1-rtl*2)-labw*rtl, 0 }); + } + } + + return bonusnum*10; +} + + +void render_attack_info (Graphics *graphics, Gst &gst, vec2 pos, int i, int j) { + Entity &atk = gst.entities[i]; + Entity &def = gst.entities[j]; + int w = 300, h = 250; + + graphics->backend.render_rect (0,0,0,255, + (int)pos.x,(int)pos.y,w,h); + graphics->backend.render_rect (255,255,255,255, + (int)pos.x+1,(int)pos.y+1,w-2,h-2); + + graphics->backend.render_rect ( + 0,0,0,255, (int)pos.x+10-1, (int)pos.y+35-1,34,34); + graphics->backend.render_rect ( + 255,255,255,255, (int)pos.x+10, (int)pos.y+35,32,32); + graphics->backend.render_sprite ( + (int)atk.info->spritebounds.x, + (int)atk.info->spritebounds.y, 16, 16, + (int)pos.x + 10, + (int)pos.y + 35, 32, 32 + ); + { + Tile &tile = gst.tiles[gst.ground.tiles[gst.ground.at(atk.x,atk.y)]]; + graphics->backend.render_sprite ( + (int)tile.spritebounds.x, + (int)tile.spritebounds.y-16, 16, 32, + (int)pos.x + 52, + (int)pos.y + 35-32, 32, 64 + ); + } + + graphics->backend.render_rect ( + 0,0,0,255, (int)pos.x+w-42-1, (int)pos.y+35-1,34,34); + graphics->backend.render_rect ( + 255,255,255,255, (int)pos.x+w-42, (int)pos.y+35,32,32); + graphics->backend.render_sprite ( + (int)def.info->spritebounds.x, + (int)def.info->spritebounds.y, 16, 16, + (int)pos.x + w-42, + (int)pos.y + 35, 32, 32 + ); + { + Tile &tile = gst.tiles[gst.ground.tiles[gst.ground.at(def.x,def.y)]]; + graphics->backend.render_sprite ( + (int)tile.spritebounds.x, + (int)tile.spritebounds.y-16, 16, 32, + (int)pos.x + w-84, + (int)pos.y + 35-32, 32, 64 + ); + } + + graphics->backend.txt.render_text(atk.info->name, pos + vec2 { 10, 10 }); + { + int txtwidth = graphics->backend.txt.get_width(def.info->name); + graphics->backend.txt.render_text(def.info->name, + pos + vec2 { w-10.0f-txtwidth, 10 }); + } + + BattleResult result = gst.battle_res(atk, def); + std::vector sres = { "++", "+", "=", "-", "--" }; + float atk_loss = atk.hp-result.atk_hp; + float def_loss = def.hp-result.def_hp; + float est_atk = def_loss - atk_loss; + float est_def = atk_loss - def_loss; + int atk_res = 2; + int def_res = 2; + if (est_atk > 40) { atk_res = 0; } + else if (est_atk > 5) { atk_res = 1; } + if (est_atk < -40) { atk_res = 4; } + else if (est_atk < -5) { atk_res = 3; } + if (est_def > 40) { def_res = 0; } + else if (est_def > 5) { def_res = 1; } + if (est_def < -40) { def_res = 4; } + else if (est_def < -5) { def_res = 3; } + + graphics->backend.txt.render_text("Health", pos + vec2 { 10, 80 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(atk.hp)), pos + vec2 { 60, 80 }); + graphics->backend.txt.render_text("->", pos + vec2 { 80, 80 }); + graphics->backend.txt.render_text( + std::to_string((int)roundf(result.atk_hp)), pos + vec2 { 93, 80 }); + graphics->backend.txt.render_text(sres[atk_res], pos + vec2 { 115, 80 }); + { + int txtwidth = graphics->backend.txt.get_width("Health"); + graphics->backend.txt.render_text("Health", + pos + vec2 { w-10.0f-txtwidth, 80 }); + std::string label = std::to_string((int)roundf(def.hp)); + int txtwidthlabel = graphics->backend.txt.get_width(label); + graphics->backend.txt.render_text(label, + pos + vec2 { w-60.0f-txtwidthlabel, 80 }); + } { + int txtwidth = graphics->backend.txt.get_width("<-"); + graphics->backend.txt.render_text("<-", + pos + vec2 { w-80.0f-txtwidth, 80 }); + } { + std::string label = std::to_string((int)roundf(result.def_hp)); + int txtwidth = graphics->backend.txt.get_width(label); + graphics->backend.txt.render_text(label, + pos + vec2 { w-93.0f-txtwidth, 80 }); + } { + int txtwidth = graphics->backend.txt.get_width(sres[def_res]); + graphics->backend.txt.render_text(sres[def_res], + pos + vec2 { w-115.0f-txtwidth, 80 }); + } + + { + int batkh = render_attack_info_bonus(graphics, gst, + pos + vec2 { 10, 95 }, atk, def, true, 0); + int bdefh = render_attack_info_bonus(graphics, gst, + pos + vec2 { 10, 95 + batkh + 15.0f }, atk, def, false, 0); + } { + int batkh = render_attack_info_bonus(graphics, gst, + pos + vec2 { w-10.0f, 95 }, def, atk, true, 1); + int bdefh = render_attack_info_bonus(graphics, gst, + pos + vec2 { w-10.0f, 95 + batkh + 15.0f }, def, atk, false, 1); + } +} + void Graphics::render (Gst &gst, View &view) { Ground &gr = gst.ground; @@ -154,6 +499,7 @@ void Graphics::render (Gst &gst, View &view) render_menu(this, gst, view.menu_day); render_menu(this, gst, view.menu_build); render_menu(this, gst, view.menu_train); + render_menu_tech(this, gst, view); if (view.moves.size() > 0) { for (int m : view.moves) { @@ -202,6 +548,59 @@ void Graphics::render (Gst &gst, View &view) 255,255,255,255, 0,(int)res.y-30,(int)res.x, 30 ); + + // info stack box + int info_ground = -1; + if (view.hover_ground != -1) { info_ground = view.hover_ground; } + if (view.selected_entity != -1) { + int i = view.selected_entity; + info_ground = gst.ground.at(entities[i].x, entities[i].y); + } + if (view.selected_ground != -1) { info_ground = view.selected_ground; } + + if (info_ground != -1) { + int unit = -1; + int bld = -1; + int x = info_ground % gr.sizex; + int y = info_ground / gr.sizex; + for (int i=0; i < gst.entities.size(); i++) { + Entity &ent = gst.entities[i]; + if (ent.x == x && ent.y == y) { + if (ent.info->unit) { unit = i; } + else { bld = i; } + } + } + + float hoff = -95; + if (bld != -1) hoff -= get_entity_info_height(gst.entities[bld]); + if (unit != -1) hoff -= get_entity_info_height(gst.entities[unit]); + + if (unit != -1) { + render_entity_info(this, gst, vec2 { 0, res.y-30+hoff }, unit); + hoff += get_entity_info_height(gst.entities[unit]); + } + if (bld != -1) { + render_entity_info(this, gst, vec2 { 0, res.y-30+hoff }, bld); + hoff += get_entity_info_height(gst.entities[bld]); + } + render_tile_info(this, gst, vec2 { 0, res.y-30+hoff }, info_ground); + } + + if (view.attacks.size() > 0 && view.hover_ground != -1) { + int def = -1; + int x = view.hover_ground % gr.sizex; + int y = view.hover_ground / gr.sizex; + for (int i=0; i < gst.entities.size(); i++) { + Entity &ent = gst.entities[i]; + if (ent.x == x && ent.y == y && ent.owner != gst.turn) { + def = i; break; + } + } + if (def != -1) { + render_attack_info(this, gst, vec2 { res.x/2-175, res.y/2-125 }, + view.selected_entity, def); + } + } } @@ -293,7 +692,7 @@ Graphics_sdl_text::Graphics_sdl_text () { char_width['('] = 2; char_width[')'] = 2; char_width['['] = 2; char_width[']'] = 2; char_width['{'] = 3; char_width['}'] = 3; - char_width[','] = 1; char_width['-'] = 3; char_width['.'] = 1; + char_width[','] = 1; char_width['-'] = 5; char_width['.'] = 1; char_width['/'] = 4; char_width['!'] = 1; char_width[':'] = 1; char_width[';'] = 1; char_width['%'] = 4; @@ -313,7 +712,13 @@ int Graphics_sdl_text::get_width (std::string str) { } void Graphics_sdl_text::render_text (std::string str, vec2 off) { - SDL_SetTextureColorMod(tex, 0, 0, 0); + render_text(str, off, 0, 0, 0); +} + +void Graphics_sdl_text::render_text (std::string str, vec2 off, + int r, int g, int b) +{ + SDL_SetTextureColorMod(tex, r, g, b); int width = 0; for (int i=0; str[i]!='\0'; i++) { int char_i = str[i]; diff --git a/graphics/graphics.h b/graphics/graphics.h index dd7e51a..af8630a 100644 --- a/graphics/graphics.h +++ b/graphics/graphics.h @@ -19,6 +19,7 @@ class Graphics_sdl_text { Graphics_sdl_text(); int get_width (std::string str); void render_text (std::string str, vec2 off); + void render_text (std::string str, vec2 off, int r, int g, int b); SDL_Renderer* gRenderer; SDL_Texture *tex; int char_width[128]; -- cgit v1.2.3-54-g00ecf