diff --git a/Adventures in Lestoria/Ability.cpp b/Adventures in Lestoria/Ability.cpp index e8e821a5..00f11817 100644 --- a/Adventures in Lestoria/Ability.cpp +++ b/Adventures in Lestoria/Ability.cpp @@ -126,6 +126,7 @@ const std::string Ability::GetDescriptionWithPlayerModifiers()const{ std::string separatorVal{variableName.substr(separatorMarker+1)}; if(!specialPrefixes.count(separatorKey))ERR(std::format("Could not find translation function for key {} inside special prefixes map!",separatorKey)) else { + if(!data.HasProperty(separatorVal))return false; //Could not be found in this section, will need to seek in another location. finalText+=specialValCol.toHTMLColorCode()+specialPrefixes[separatorKey](data,separatorVal)+WHITE.toHTMLColorCode(); bracesFound=false; return true; @@ -176,6 +177,7 @@ const std::string Ability::GetDescriptionWithPlayerModifiers()const{ std::string separatorVal{variableName.substr(separatorMarker+1)}; if(!specialPrefixes.count(separatorKey))ERR(std::format("Could not find translation function for key {} inside special prefixes map!",separatorKey)) else { + if(!data.HasProperty(separatorVal))return false; //Could not be found in this section, will need to seek in another location. finalText+=specialValCol.toHTMLColorCode()+specialPrefixes[separatorKey](data,separatorVal)+WHITE.toHTMLColorCode(); bracesFound=false; return true; diff --git a/Adventures in Lestoria/Ability.h b/Adventures in Lestoria/Ability.h index 5852cfbb..ec3a848b 100644 --- a/Adventures in Lestoria/Ability.h +++ b/Adventures in Lestoria/Ability.h @@ -78,7 +78,7 @@ struct Ability{ PrecastData precastInfo; bool canCancelCast=false; InputGroup*input; - std::string icon; + std::string icon{"pixel.png"}; //If set to true, this ability is tied to using an item. bool itemAbility=false; //If set to true, this ability instead activates immediately when a cast occurs. When the cast finishes, nothing happens instead. diff --git a/Adventures in Lestoria/CharacterMenuWindow.cpp b/Adventures in Lestoria/CharacterMenuWindow.cpp index 2143eaf9..d8430c31 100644 --- a/Adventures in Lestoria/CharacterMenuWindow.cpp +++ b/Adventures in Lestoria/CharacterMenuWindow.cpp @@ -343,26 +343,30 @@ void Menu::InitializeCharacterMenuWindow(){ auto abilityDescriptionLabel{characterMenuWindow->ADD("Ability Description Text",MenuLabel)(geom2d::rect{{125,30+16},{116,windowSize.y-39-16}},"",1.f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END}; #pragma region Skill Selection Boxes - std::array abilityBoxes{ - std::pair,AbilitySlot>{game->GetPlayer()->GetAbility1(),AbilitySlot::ABILITY1}, - std::pair,AbilitySlot>{game->GetPlayer()->GetAbility2(),AbilitySlot::ABILITY2}, - std::pair,AbilitySlot>{game->GetPlayer()->GetAbility3(),AbilitySlot::ABILITY3}, - std::pair,AbilitySlot>{game->GetPlayer()->GetAbility4(),AbilitySlot::ABILITY4}, - std::pair,AbilitySlot>{game->GetPlayer()->GetRightClickAbility(),AbilitySlot::DEFENSIVE}, - }; - for(size_t i{0};auto&[ability,slot]:abilityBoxes){ - float x=0; - float y=24+i*28; - float labelX=31; - float labelY=24+i*28+36; - auto skillBox{characterMenuWindow->ADD(std::format("Skill Icon Label {}",i),MenuIconButton)(geom2d::rect{{x,y+28},{24,24}},GFX[ability.get().icon].Decal(),DO_NOTHING)END}; - auto skillNameLabel{characterMenuWindow->ADD(std::format("Skill Name Label {}",i),MenuLabel)(geom2d::rect{{labelX,labelY},{96,24}},ability.get().GetNameWithPlayerModifiers())END}; - skillBox->SetHoverFunc([&abilityNameLabel,&abilityDescriptionLabel,&ability](MenuFuncData data){ - abilityNameLabel->SetLabel(ability.get().GetNameWithPlayerModifiers()); - abilityDescriptionLabel->SetLabel(ability.get().GetDescriptionWithPlayerModifiers()); - return true; - }); - i++; + { + const std::array abilityBoxes{ + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility1(),AbilitySlot::ABILITY1}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility2(),AbilitySlot::ABILITY2}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility3(),AbilitySlot::ABILITY3}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility4(),AbilitySlot::ABILITY4}, + std::pair,AbilitySlot>{game->GetPlayer()->GetRightClickAbility(),AbilitySlot::DEFENSIVE}, + }; + for(size_t i{0};auto&[ability,slot]:abilityBoxes){ + float x=4; + float y=4+i*28; + float labelX=28; + float labelY=24+i*28+36; + auto skillBox{characterMenuWindow->ADD(std::format("Skill Icon Label {}",i),MenuIconButton)(geom2d::rect{{x,y+28},{24,24}},GFX[ability.get().icon].Decal(),DO_NOTHING)END}; + auto skillNameLabel{characterMenuWindow->ADD(std::format("Skill Name Label {}",i),MenuLabel)(geom2d::rect{{labelX,labelY},{96,24}},ability.get().GetNameWithPlayerModifiers())END}; + skillBox->SetHoverFunc([slot](MenuFuncData data){ + const auto&ability{game->GetPlayer()->GetAbility(slot)}; + Component(data.menu.GetType(),"Ability Name Text")->SetLabel(ability.GetNameWithPlayerModifiers()); + Component(data.menu.GetType(),"Ability Description Text")->SetLabel(ability.GetDescriptionWithPlayerModifiers()); + return true; + }); + skillBox->Disable(); //Hide these by default. + i++; + } } #pragma endregion @@ -372,17 +376,29 @@ void Menu::InitializeCharacterMenuWindow(){ }; //Used in conjunction with the onClick events of MenuComponents tab. - auto OnTabClick=[&abilityBoxes,&abilityNameLabel,&abilityDescriptionLabel](const ClickedTab tabClicked,const MenuFuncData&data){ + auto OnTabClick=[](const ClickedTab tabClicked,const MenuFuncData&data){ using enum ClickedTab; + auto abilityNameLabel{Component(data.menu.GetType(),"Ability Name Text")}; + auto abilityDescriptionLabel{Component(data.menu.GetType(),"Ability Description Text")}; for(int i=0;i<8;i++){ - auto slot{Component(data.menu.GetType(),CharacterMenuWindow::slotNames[i])}; + auto slot{Component(data.menu.GetType(),std::format("Equip Slot {}",CharacterMenuWindow::slotNames[i]))}; if(tabClicked==EQUIPMENT)slot->Enable(); else slot->Disable(); } + const std::array abilityBoxes{ + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility1(),AbilitySlot::ABILITY1}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility2(),AbilitySlot::ABILITY2}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility3(),AbilitySlot::ABILITY3}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility4(),AbilitySlot::ABILITY4}, + std::pair,AbilitySlot>{game->GetPlayer()->GetRightClickAbility(),AbilitySlot::DEFENSIVE}, + }; for(int i=0;i(data.menu.GetType(),std::format("Skill Icon Label {}",i))}; - if(tabClicked==SKILLS)slot->Enable(); - else slot->Disable(); + auto&[ability,slot]{abilityBoxes[i]}; + Component(data.menu.GetType(),std::format("Skill Icon Label {}",i))->SetIcon(GFX[ability.get().icon].Decal()); + Component(data.menu.GetType(),std::format("Skill Name Label {}",i))->SetLabel(ability.get().GetNameWithPlayerModifiers()); + auto abilityLabel{Component(data.menu.GetType(),std::format("Skill Icon Label {}",i))}; + if(tabClicked==SKILLS)abilityLabel->Enable(); + else abilityLabel->Disable(); } Component(data.menu.GetType(),"Equipment Tab")->SetSelected(tabClicked==EQUIPMENT); Component(data.menu.GetType(),"Skills Tab")->SetSelected(tabClicked==SKILLS); diff --git a/Adventures in Lestoria/GameEvent.cpp b/Adventures in Lestoria/GameEvent.cpp index cc9cabaf..e66b73d1 100644 --- a/Adventures in Lestoria/GameEvent.cpp +++ b/Adventures in Lestoria/GameEvent.cpp @@ -37,7 +37,7 @@ All rights reserved. #pragma endregion #include "GameEvent.h" -#include +#include std::vector>GameEvent::events; diff --git a/Adventures in Lestoria/HubPauseMenu.cpp b/Adventures in Lestoria/HubPauseMenu.cpp index 4384b018..5b0b73a9 100644 --- a/Adventures in Lestoria/HubPauseMenu.cpp +++ b/Adventures in Lestoria/HubPauseMenu.cpp @@ -44,6 +44,7 @@ All rights reserved. #include "CharacterRotatingDisplay.h" #include "ClassInfo.h" #include "Unlock.h" +#include "MenuIconButton.h" INCLUDE_game INCLUDE_GFX @@ -59,6 +60,22 @@ void Menu::InitializeHubPauseWindow(){ hubPauseWindow->ADD("Character Button",MenuComponent)(geom2d::rect{{6.f,28.f},{84.f,24.f}},"Character",[](MenuFuncData data){ Component(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal()); Component(CHARACTER_MENU,"Equip Selection Select Button")->Click(); + std::array abilityBoxes{ + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility1(),AbilitySlot::ABILITY1}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility2(),AbilitySlot::ABILITY2}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility3(),AbilitySlot::ABILITY3}, + std::pair,AbilitySlot>{game->GetPlayer()->GetAbility4(),AbilitySlot::ABILITY4}, + std::pair,AbilitySlot>{game->GetPlayer()->GetRightClickAbility(),AbilitySlot::DEFENSIVE}, + }; + for(size_t i{0};auto&[ability,slot]:abilityBoxes){ + //Attempt to update icons in case the abilities have changed at some point. + //Attempt to update labels in case they have changed. + auto skillBox{Component(CHARACTER_MENU,std::format("Skill Icon Label {}",i))}; + auto skillNameLabel{Component(CHARACTER_MENU,std::format("Skill Name Label {}",i))}; + skillBox->SetIcon(GFX[ability.get().icon].Decal()); + skillNameLabel->SetLabel(ability.get().GetNameWithPlayerModifiers()); + i++; + } Menu::OpenMenu(CHARACTER_MENU); return true; },ButtonAttr::FIT_TO_LABEL)END; diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index 48fc6e40..df308dae 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -2326,4 +2326,17 @@ const vf2d&Player::GetPreviousPos()const{ const std::unordered_set&Player::GetEnchants()const{ return enchantList; +} + +const Ability&Player::GetAbility(AbilitySlot slot){ + using enum AbilitySlot; + switch(slot){ + case ABILITY1:return GetAbility1(); + case ABILITY2:return GetAbility2(); + case ABILITY3:return GetAbility3(); + case ABILITY4:return GetAbility4(); + case DEFENSIVE:return GetRightClickAbility(); + } + ERR(std::format("WARNING! Unknown ability slot {} specified when attempting to retrieve Ability! THIS SHOULD NOT BE HAPPENING!",int(slot))); + return GetAbility1(); //THIS SHOULD NEVER BE HIT!!! } \ No newline at end of file diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h index 61f38443..e58d4b44 100644 --- a/Adventures in Lestoria/Player.h +++ b/Adventures in Lestoria/Player.h @@ -230,6 +230,7 @@ public: virtual Ability&GetAbility2()=0; virtual Ability&GetAbility3()=0; virtual Ability&GetAbility4()=0; + const Ability&GetAbility(AbilitySlot slot); virtual void SetAbility4(const Ability&originalAbility)=0; //NOTE: Make sure to provide the original ability and not a current ability! virtual std::string&GetWalkNAnimation()=0; virtual std::string&GetWalkEAnimation()=0; diff --git a/Adventures in Lestoria/Ranger.cpp b/Adventures in Lestoria/Ranger.cpp index 107932c8..5db0fbf4 100644 --- a/Adventures in Lestoria/Ranger.cpp +++ b/Adventures in Lestoria/Ranger.cpp @@ -151,8 +151,16 @@ void Ranger::InitializeClassAbilities(){ float shootingDist=pointTowardsCursor.length(); vf2d shootingDirMiddle=pointTowardsCursor.vector(); float shootingAngle=atan2(shootingDirMiddle.y,shootingDirMiddle.x); - int arrowCount="Ranger.Ability 3.ArrowCount"_I%2==0?"Ranger.Ability 3.ArrowCount"_I+1:"Ranger.Ability 3.ArrowCount"_I; - for(int i=0;iGetAttack())}; + const int perArrowDamage{std::max(1,int(p->GetAttack()*("Ranger.Ability 3.DamageMult"_F/"Ranger.Ability 3.ArrowCount"_I)))}; + const int totalArrowDamage{perArrowDamage*"Ranger.Ability 3.ArrowCount"_I}; + const int leftoverArrowDamage{intendedTotalDamage-totalArrowDamage}; //Compared to intended damage, the amount dealt may not be completely evenly divisible. Account for the remainder here to pour into the last arrow. + int totalDamageCalculated{0}; + for(int i=0;iGetPos(),p->GetPos()+vf2d{cos(newAngle),sin(newAngle)}*shootingDist); vf2d extendedLine=pointTowardsCursor.upoint(1.1f); - BULLET_LIST.push_back(std::make_unique(Arrow(p->GetPos(),extendedLine,vf2d{cos(newAngle)*"Ranger.Ability 3.ArrowSpd"_F,float(sin(newAngle)*"Ranger.Ability 3.ArrowSpd"_F-PI/8*"Ranger.Ability 3.ArrowSpd"_F)}+p->movementVelocity,12*"Ranger.Ability 3.ArrowRadius"_F/100,int(p->GetAttack()*"Ranger.Ability 3.DamageMult"_F),p->OnUpperLevel(),true))); + int finalArrowDamage{perArrowDamage}; + if(i==algorithmArrowCount-1)finalArrowDamage+=leftoverArrowDamage; + BULLET_LIST.emplace_back(std::make_unique(Arrow(p->GetPos(),extendedLine,vf2d{cos(newAngle)*"Ranger.Ability 3.ArrowSpd"_F,float(sin(newAngle)*"Ranger.Ability 3.ArrowSpd"_F-PI/8*"Ranger.Ability 3.ArrowSpd"_F)}+p->movementVelocity,12*"Ranger.Ability 3.ArrowRadius"_F/100,finalArrowDamage,p->OnUpperLevel(),true))); + totalDamageCalculated+=finalArrowDamage; } + if(totalDamageCalculated!=intendedTotalDamage)ERR(std::format("WARNING! Multi-shot expected a total damage calculation of {} but added up to {} instead!",intendedTotalDamage,totalDamageCalculated)); p->rangerShootAnimationTimer=0.3f; p->SetState(State::SHOOT_ARROW); p->SetAnimationBasedOnTargetingDirection("SHOOT",shootingAngle); diff --git a/Adventures in Lestoria/assets/config/classes/Ranger.txt b/Adventures in Lestoria/assets/config/classes/Ranger.txt index 63d283a9..daf0c6fb 100644 --- a/Adventures in Lestoria/assets/config/classes/Ranger.txt +++ b/Adventures in Lestoria/assets/config/classes/Ranger.txt @@ -138,7 +138,7 @@ Ranger # Whether or not this ability cancels casts. CancelCast = 0 - Description = Prepares and fires a fan of {ArrowCount} packed arrows. Total Damage: {DamageMult:TotalDamageMult}. + Description = Prepares and fires a fan of {ArrowCount} packed arrows. Total Damage: {DamageMult:DamageMult}. #RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown. Cooldown Bar Color 1 = 64, 0, 0, 192 @@ -148,11 +148,10 @@ Ranger Casting Range = 0 Casting Size = 0 - # Damage multiplier per shot - DamageMult = 1.0 + # Total Damage multiplier of all shots combined. + DamageMult = 6.0 # Number of arrows in the shot spread. ArrowCount = 6 - TotalDamageMult = 6.0 # How far the shot spread in one angle is. For example, if the value here is set to 18.375, then Multishot divides the arrows evenly from a span of -18.375 degrees to the left to 18.375 degrees to the right of the player. MultiShotSpread = 18.375 # Speed of arrows that Rapid Fire shoots out.