diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index 385a18bf..15c3cff3 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -176,8 +176,8 @@ struct xy { enum class stat { str, con, wis, dex }; -constexpr stat allstats[] = { stat::str, stat::con, stat::wis, stat::dex }; constexpr int qstat = 4; +constexpr array allstats = { stat::str, stat::con, stat::wis, stat::dex }; template struct statarray : array { statarray() {}; @@ -309,6 +309,7 @@ struct man : public entity { int last_action; int experience; + stat profession; statarray base_stats; statdata current, next; diff --git a/rogueviz/ru/ru.cpp b/rogueviz/ru/ru.cpp index a0085162..be07f73e 100644 --- a/rogueviz/ru/ru.cpp +++ b/rogueviz/ru/ru.cpp @@ -481,7 +481,15 @@ void add_platf_hooks() { pushScreen(run); } +void start_new_game() { + enable(); + randomize_stats(); + cmode = mode::menu; + pushScreen(initial_stats); + } + auto chk = arg::add3("-ru", enable) + + arg::add3("-ru-start", start_new_game) + arg::add3("-ru-cheat", [] { arg::shift(); load_cheat(arg::args()); }) + addHook(mapstream::hooks_loadmap, 100, [] (hstream& f, int id) { if(id == 67) { diff --git a/rogueviz/ru/stats.cpp b/rogueviz/ru/stats.cpp index 45a495b2..a2c72374 100644 --- a/rogueviz/ru/stats.cpp +++ b/rogueviz/ru/stats.cpp @@ -1,5 +1,29 @@ namespace rogue_unlike { +// -1 to downgrade +int stat_upgrade_cost(stat s, int bonus = 0) { + return 10 * (m.base_stats[s] + bonus); + } + +void randomize_stats() { + for(auto s: allstats) while(m.base_stats[s] > 1) { + m.base_stats[s]--; m.experience += stat_upgrade_cost(s); + } + auto mainstat = stat::str; + for(int i=0; i<500; i++) { + auto s = hrand_elt(allstats); + auto uc = stat_upgrade_cost(s); + if(uc <= m.experience) { + m.experience -= uc; + m.base_stats[s]++; + if(m.base_stats[s] > m.base_stats[mainstat]) mainstat = s; + } + } + m.profession = mainstat; + for(auto s: allstats) + m.current.stats[s] = m.base_stats[s]; + } + struct statinfo { char key; string name; @@ -15,17 +39,53 @@ string prettystat(ld cur) { return format("%.lf", cur); } -void draw_stats() { +struct profinfo { + char key; + string name; + string desc; + }; + +statarray profdata; + +vector professions = { "Warrior", "Morpher", "Sorcerer", "Rogue" }; + +void stat_screen(bool editable) { statdata[stat::str] = {'s', "Strength", "Affects the strength of your physical attacks."}; statdata[stat::con] = {'t', "Toughness", "Affects the amount of hitpoints you have."}; statdata[stat::wis] = {'w', "Wisdom", "Affects the power of your alchemy."}; statdata[stat::dex] = {'d', "Dexterity", "Improves your 'chill time' power."}; + profdata[stat::str] = {'w', "Warrior", "Warriors start with a powerful axe."}; + profdata[stat::con] = {'m', "Morpher", "Morpher start with an ability to transform into small animals."}; + profdata[stat::wis] = {'s', "Sorcerer", "Sorcerers start with an ability to cast fire spells."}; + profdata[stat::dex] = {'r', "Rogue", "Rogues start with an ability to detect hidden passages and traps."}; + render_the_map(); draw_inventory_frame(); dialog::init("the Alchemist", 0xC000C0); + dialog::addSelItem("class", profdata[m.profession].name, 'c'); + dialog::add_action_push([editable] { + dialog::init("the Alchemist: class", 0xC000C0); + dialog::addHelp( + "During their apprenticeship, Alchemists focus on one of multiple specializations.\n\n" + "Game-wise, this affects the abilities you start with, which also affects what things you can do close to the start of the game. " + "You should be able to find the basic abilities of other classes early. However, you will also find the basic ability of your " + "own class, making it more powerful, so it will always be the strongest." + ); + dialog::addBreak(100); + for(auto st: allstats) { + if(!editable && st != m.profession) continue; + dialog::addBoolItem(profdata[st].name, st == m.profession, profdata[st].key); + dialog::add_action([st] { m.profession = st; }); + dialog::addBreak(50); + dialog::addHelp(profdata[st].desc); + } + dialog::addBack(); + dialog::display(); + }); + dialog::addSelItem("free experience", its(m.experience), 'x'); for(auto st: allstats) { @@ -34,7 +94,7 @@ void draw_stats() { string s = its(bas); if(cur != bas) s += " (" + prettystat(cur) + ")"; dialog::addSelItem(statdata[st].name, s, statdata[st].key); - dialog::add_action_push([st] { + dialog::add_action_push([st, editable] { render_the_map(); draw_inventory_frame(); dialog::init(statdata[st].name, 0xC000C0); @@ -43,13 +103,59 @@ void draw_stats() { dialog::addSelItem("base value", its(m.base_stats[st]), 0); dialog::addSelItem("current value", prettystat(m.current.stats[st]), 0); dialog::addBreak(100); + int uc = stat_upgrade_cost(st); + dialog::addSelItem("upgrade", its(uc) + " XP", 'u'); + dialog::add_action([uc, st] { + if(m.experience < uc) { addMessage("Not enough XP!"); return; } + m.base_stats[st]++; m.current.stats[st]++; m.experience -= uc; + }); + if(editable) { + uc = stat_upgrade_cost(st, -1); + dialog::addSelItem("downgrade", its(uc) + " XP", 'd'); + dialog::add_action([uc, st] { + if(m.base_stats[st] <= 1) { addMessage("Impossible to go lower!"); return; } + m.base_stats[st]--; m.current.stats[st]--; m.experience += uc; + }); + } + dialog::addBreak(100); dialog::addBack(); dialog::display(); }); } - dialog::addBack(); + if(!editable) dialog::addBack(); + if(editable) { + // need to delete the handler so that we cannot exit this dialog + keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); }; + dialog::addItem("start the game!", 'z'); + dialog::add_action([] { + popScreen(); + cmode = mode::playing; + switch(m.profession) { + case stat::str: + find_power("dagger").gain(1, 1); // no axe yet + break; + case stat::con: + find_power("polymorph").gain(1, 1).flags |= IDENTIFIED | PARTIAL; + break; + case stat::dex: + find_power("the thief").gain(1, 1).flags |= IDENTIFIED | PARTIAL; + break; + case stat::wis: + find_power("fire").gain(1, 1).flags |= IDENTIFIED | PARTIAL; + break; + } + }); + + dialog::addItem("reroll", 'r'); + dialog::add_action(randomize_stats); + } + dialog::display(); } +void initial_stats() { stat_screen(true); } + +void draw_stats() { stat_screen(false); } + }