diff --git a/C++ProjectTemplate b/C++ProjectTemplate index fa3af42..50e645f 100755 Binary files a/C++ProjectTemplate and b/C++ProjectTemplate differ diff --git a/battle.h b/battle.h index 7ea11a4..83f6e30 100644 --- a/battle.h +++ b/battle.h @@ -75,7 +75,7 @@ namespace Battle{ struct Move{ std::string name=""; std::string desc=""; - int grade=0; //If the name of a move name match, then the grade helps sort it into the same category on menus. + char grade=0; //If the name of a move name match, then the grade helps sort it into the same category on menus. int baseDmg=10; //The base damage of the attack. int randomDmg=5; //Additional random roll damage to add onto the base damage. int PPCost=0; @@ -89,6 +89,13 @@ namespace Battle{ std::vector> properties={}; //The int is used to determine the chance of something occurring. //Properties order is WET, DRY, COLD, HEAT bool overworld=false; //Whether or not a move can be used on the overworld. + std::string GetPowerName() { + if (grade!=0) { + return name+" "+grade; + } else { + return name; + } + } }; } #endif \ No newline at end of file diff --git a/main.cpp b/main.cpp index 6320ceb..c5789c2 100644 --- a/main.cpp +++ b/main.cpp @@ -158,6 +158,8 @@ public: int OVERWORLD_POWER_SELECTION_MEMBER=0; Battle::Move*OVERWORLD_SELECTED_POWER; int OVERWORLD_TARGET_SELECTION=0; + bool HEALING_OVERWORLD_MEMBERS=false; //When set to true, members will be healed as dialog boxes are closed using the HEALING_OVERWORLD_MEMBER variable. + int HEALING_OVERWORLD_MEMBER=0; bool MOUSE_PRESSED_DOWN=false,MOUSE_DOWN=false,MOUSE_RELEASED=false; //TODO Implement Mouse things. @@ -312,6 +314,29 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), GAME_STATE=GameState::GAME_WORLD; } CLOSE_OVERWORLD_WINDOW=false; + if (HEALING_OVERWORLD_MEMBERS) { + if (HEALING_OVERWORLD_MEMBER==0||HEALING_OVERWORLD_MEMBER==2) { + DisplayMessageBox(""); + } + Entity*castingMember=PARTY_MEMBER_STATS[PARTY_MEMBER_ID[OVERWORLD_POWER_SELECTION_MEMBER]]; + castingMember->selectedMove=OVERWORLD_SELECTED_POWER; + while (HEALING_OVERWORLD_MEMBERGetHP()>0) { + int healAmt = CalculateHealing(castingMember); + vi2d box = {(128-32*PARTY_MEMBER_COUNT)+HEALING_OVERWORLD_MEMBER*64+29,170}; + DAMAGE_NUMBERS.push_back(new DamageNumber(-healAmt,box+cameraPos)); + target->AddHP(healAmt); + targetText+=target->obj->name+" recovered "+std::to_string(healAmt)+" hitpoints.\n"; + messageBoxLoad=true; + messageBoxVisible=true; + HEALING_OVERWORLD_MEMBER++; + break; + } + HEALING_OVERWORLD_MEMBER++; + } + castingMember->selectedMove=nullptr; + } } } else { while (messageBoxMarkerLockAction(); } + HandleRollingCounters(); + HandleBattle(); HandleCutscenes(); @@ -429,25 +456,7 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), for (int i=0;iencounters.size();i++) { if (CURRENT_MAP->encounters[i]->IsEncounterAlive()&&CURRENT_MAP->encounters[i]->IsInRange(PARTY_MEMBER_OBJ[0]->GetPos())) { BATTLE_STATE=BattleState::MOVE_CAMERA; - for (int i=0;iGetHP()%10; - player_rollpp_display[i][j]=member->GetPP()%10; - }break; - case 1:{ - player_rollhp_display[i][j]=member->GetHP()/10%10; - player_rollpp_display[i][j]=member->GetPP()/10%10; - }break; - case 2:{ - player_rollhp_display[i][j]=member->GetHP()/100%10; - player_rollpp_display[i][j]=member->GetPP()/100%10; - }break; - } - } - } + SetupRollingHitpointCounters(); BATTLE_ENCOUNTER=CURRENT_MAP->encounters[i]; break; } @@ -1010,6 +1019,7 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), if (PlayerCanMove()&&ACTIONKEYPRESSED) { GAME_STATE=GameState::OVERWORLD_MENU; OVERWORLD_MENU_SELECTION=0; + SetupRollingHitpointCounters(); } }break; case GameState::OVERWORLD_MENU:{ @@ -1452,6 +1462,96 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), DrawTargetRangeGrid(BATTLE_ENCOUNTER->objs[SELECTED_TARGET]->obj->GetPosWithOrigin(),PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->range); } } + + + if (BATTLE_ENCOUNTER!=nullptr&&BATTLE_STATE!=BattleState::MOVE_CAMERA&&BATTLE_STATE!=BattleState::MOVE_CAMERA_BACK||OverworldMenuOpen()) { + SetDrawTarget(layer::INTERFACE); + vi2d screenShakeOffset = {0,0}; + if (BATTLE_ENCOUNTER!=nullptr) { + cameraPos = BATTLE_ENCOUNTER->pos; + if (BATTLE_HIT_SCREENSHAKE>0) { + BATTLE_HIT_SCREENSHAKE--; + if (BATTLE_HIT_SCREENSHAKE%2==0) { + screenShakeOffset = {0,2}; + } else { + screenShakeOffset = {0,-2}; + } + } + cameraPos+=screenShakeOffset; + } + for (int i=0;i attackedAllies; + + if (CURRENT_TURN>=0&&BATTLE_STATE==BattleState::WAIT_ANIMATION&&BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedTarget<0) { + attackedAllies=GetEntitiesInRange(BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedTarget,BATTLE_ENCOUNTER->objs[CURRENT_TURN]->channelPos,BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove); + } + for (int j=0;jobj==PARTY_MEMBER_OBJ[i]) { + underAttack=true; + break; + } + } + } + if (CURRENT_TURN>=0&&BATTLE_STATE==BattleState::WAIT_ANIMATION&&underAttack) { + drawCheckerboardBox(box,{59,59},Pixel(180,159,194),Pixel(200,179,214),{6,6},RED,DARK_RED); + } else { + drawCheckerboardBox(box,{59,59},Pixel(180,159,194),Pixel(200,179,214),{6,6}); + } + if (member->selectedMove==nullptr) { + DrawStringDecal({(float)(box.x+6),(float)(box.y+6)},obj->name,BLACK); + } else { + DrawStringDecal({(float)(box.x+6),(float)(box.y+4)},obj->name,BLACK,{1,0.8}); + } + if (BATTLE_ENCOUNTER!=nullptr) { + DrawPartialDecal({(float)(box.x+4),(float)(box.y+5+8+2)},SPRITES["atbbar_back.png"],{0,0},{static_cast(member->atb/1000.0*SPRITES["atbbar_back.png"]->sprite->width),static_cast(SPRITES["atbbar_back.png"]->sprite->height)}); + DrawDecal({(float)(box.x+4),(float)(box.y+5+8+2)},SPRITES["atbbar_front.png"]); + } + if (member->selectedMove!=nullptr) { + DrawPartialDecal({(float)(box.x+4),(float)(box.y+5+8+2)},SPRITES["atbbar_back.png"],{0,0},{(1-((float)member->channelTimeRemaining/member->selectedMove->channelTime))*SPRITES["atbbar_back.png"]->sprite->width,static_cast(SPRITES["atbbar_back.png"]->sprite->height)},{1,1},GREEN*0.7); + std::string label=member->selectedMove->name; + label+=" "; + if (member->selectedMove->grade!=0) { + label+=member->selectedMove->grade; + } + vd2d textOffset=GetTextSize(label)*0.6; + textOffset.y+=10; + vd2d barPos = {(float)(box.x+4),(float)(box.y+5+8+2)}; + DrawStringDecal(barPos-textOffset/2,label,BLACK,{std::min((float)54/GetTextSize(label).x,(float)1),0.6}); + } + const vi2d hpTextPos = {box.x+5,box.y+25}; + for (int x=-1;x<=1;x++) { + for (int y=-1;y<=1;y++) { + if (x!=0&&y!=0) { + DrawStringDecal({(float)(hpTextPos.x+x),(float)(hpTextPos.y+y)},"HP",olc::WHITE); + } + } + } + DrawStringDecal(hpTextPos,"HP",BLACK); + DrawRollingCounter(hpTextPos,member->GetHP(),player_rollhp_display[i],player_rollhp_counter[i]); + const vi2d mpTextPos = {box.x+5,hpTextPos.y+17}; + for (int x=-1;x<=1;x++) { + for (int y=-1;y<=1;y++) { + if (x!=0&&y!=0) { + DrawStringDecal({(float)(mpTextPos.x+x),(float)(mpTextPos.y+y)},"PP",olc::WHITE); + } + } + } + DrawStringDecal(mpTextPos,"PP",BLACK); + DrawRollingCounter(mpTextPos,member->GetPP(),player_rollpp_display[i],player_rollpp_counter[i]); + } + SetDrawTarget(layer::DYNAMIC); + } + + if (BATTLE_ENCOUNTER!=nullptr) { SetDrawTarget(layer::HIGH); if (BATTLE_STATE==BattleState::SELECT_ACTION||BATTLE_STATE==BattleState::POWER_SELECT||BATTLE_STATE==BattleState::GRADE_SELECT||BATTLE_STATE==BattleState::ITEM_SELECT) { @@ -1499,84 +1599,6 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), } if (BATTLE_STATE!=BattleState::MOVE_CAMERA&&BATTLE_STATE!=BattleState::MOVE_CAMERA_BACK) { SetDrawTarget(layer::INTERFACE); - vi2d screenShakeOffset = {0,0}; - cameraPos = BATTLE_ENCOUNTER->pos; - if (BATTLE_HIT_SCREENSHAKE>0) { - BATTLE_HIT_SCREENSHAKE--; - if (BATTLE_HIT_SCREENSHAKE%2==0) { - screenShakeOffset = {0,2}; - } else { - screenShakeOffset = {0,-2}; - } - } - cameraPos+=screenShakeOffset; - - std::vector attackedAllies; - - if (CURRENT_TURN>=0&&BATTLE_STATE==BattleState::WAIT_ANIMATION&&BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedTarget<0) { - attackedAllies=GetEntitiesInRange(BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedTarget,BATTLE_ENCOUNTER->objs[CURRENT_TURN]->channelPos,BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove); - } - - for (int i=0;iobj==PARTY_MEMBER_OBJ[i]) { - underAttack=true; - break; - } - } - if (CURRENT_TURN>=0&&BATTLE_STATE==BattleState::WAIT_ANIMATION&&underAttack) { - drawCheckerboardBox(box,{59,59},Pixel(180,159,194),Pixel(200,179,214),{6,6},RED,DARK_RED); - } else { - drawCheckerboardBox(box,{59,59},Pixel(180,159,194),Pixel(200,179,214),{6,6}); - } - if (member->selectedMove==nullptr) { - DrawStringDecal({(float)(box.x+6),(float)(box.y+6)},obj->name,BLACK); - } else { - DrawStringDecal({(float)(box.x+6),(float)(box.y+4)},obj->name,BLACK,{1,0.8}); - } - DrawPartialDecal({(float)(box.x+4),(float)(box.y+5+8+2)},SPRITES["atbbar_back.png"],{0,0},{static_cast(member->atb/1000.0*SPRITES["atbbar_back.png"]->sprite->width),static_cast(SPRITES["atbbar_back.png"]->sprite->height)}); - DrawDecal({(float)(box.x+4),(float)(box.y+5+8+2)},SPRITES["atbbar_front.png"]); - if (member->selectedMove!=nullptr) { - DrawPartialDecal({(float)(box.x+4),(float)(box.y+5+8+2)},SPRITES["atbbar_back.png"],{0,0},{(1-((float)member->channelTimeRemaining/member->selectedMove->channelTime))*SPRITES["atbbar_back.png"]->sprite->width,static_cast(SPRITES["atbbar_back.png"]->sprite->height)},{1,1},GREEN*0.7); - std::string label=member->selectedMove->name; - label+=" "; - if (member->selectedMove->grade!=0) { - label+=member->selectedMove->grade; - } - vd2d textOffset=GetTextSize(label)*0.6; - textOffset.y+=10; - vd2d barPos = {(float)(box.x+4),(float)(box.y+5+8+2)}; - DrawStringDecal(barPos-textOffset/2,label,BLACK,{std::min((float)54/GetTextSize(label).x,(float)1),0.6}); - } - const vi2d hpTextPos = {box.x+5,box.y+25}; - for (int x=-1;x<=1;x++) { - for (int y=-1;y<=1;y++) { - if (x!=0&&y!=0) { - DrawStringDecal({(float)(hpTextPos.x+x),(float)(hpTextPos.y+y)},"HP",olc::WHITE); - } - } - } - DrawStringDecal(hpTextPos,"HP",BLACK); - DrawRollingCounter(hpTextPos,member->GetHP(),player_rollhp_display[i],player_rollhp_counter[i]); - const vi2d mpTextPos = {box.x+5,hpTextPos.y+17}; - for (int x=-1;x<=1;x++) { - for (int y=-1;y<=1;y++) { - if (x!=0&&y!=0) { - DrawStringDecal({(float)(mpTextPos.x+x),(float)(mpTextPos.y+y)},"PP",olc::WHITE); - } - } - } - DrawStringDecal(mpTextPos,"PP",BLACK); - DrawRollingCounter(mpTextPos,member->GetPP(),player_rollpp_display[i],player_rollpp_counter[i]); - } for (int i=0;iobjs.size();i++) { Entity*obj = BATTLE_ENCOUNTER->objs[i]; if (obj->GetHP()>0&&obj->selectedMove!=nullptr) { @@ -2705,23 +2727,6 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), void HandleBattle() { if (BATTLE_ENCOUNTER!=nullptr) { - for (int i=0;i0) { - if (BATTLE_ROLLING_COUNTER_WAITTIME==0) { - player_rollwait_counter[i]=0; - } else { - player_rollwait_counter[i]--; - } - } - Entity*member=PARTY_MEMBER_STATS[PARTY_MEMBER_ID[i]]; - - HandleRollingCounters(i,player_rollhp_counter,player_rollhp_display,member,member->maxHP,member->GetHP(),member->GetTargetHP()); - HandleRollingCounters(i,player_rollpp_counter,player_rollpp_display,member,member->maxPP,member->GetPP(),member->GetTargetPP(),true); - - if (player_rollwait_counter[i]==0) { - player_rollwait_counter[i]=BATTLE_ROLLING_COUNTER_WAITTIME*13; - } - } switch (BATTLE_STATE) { case BattleState::MOVE_CAMERA:{ bool allDone=true; @@ -2923,9 +2928,7 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), if (PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->friendly) { if (PARTY_MEMBER_STATS[-PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedTarget-1]->GetHP()>0) { for (auto&ent:GetEntitiesInRange(PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedTarget,PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->channelPos,PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove)) { - int healAmt = PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->baseDmg+ - ((PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->randomDmg>0)?rand()%PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->randomDmg:0) - +PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->baseAtk; + int healAmt = CalculateHealing(PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]); if (ent->GetHP()>0) { std::cout << PARTY_MEMBER_OBJ[-CURRENT_TURN-1]->name << " uses " << PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->name << " " << PARTY_MEMBER_STATS[PARTY_MEMBER_ID[-CURRENT_TURN-1]]->selectedMove->grade << " on " << ent->obj->name << " recovering " << healAmt << " health.\n"; ent->AddHP(healAmt); @@ -2962,9 +2965,7 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), if (BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove->friendly) { if (BATTLE_ENCOUNTER->objs[BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedTarget]->GetHP()>0) { for (auto&ent:GetEntitiesInRange(BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedTarget,BATTLE_ENCOUNTER->objs[CURRENT_TURN]->channelPos,BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove)) { - int healAmt = BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove->baseDmg+ - ((rand()%BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove->randomDmg>0)?rand()%BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove->randomDmg:0) - +BATTLE_ENCOUNTER->objs[CURRENT_TURN]->baseAtk; + int healAmt = CalculateHealing(BATTLE_ENCOUNTER->objs[CURRENT_TURN]); if (ent->GetHP()>0) { std::cout << BATTLE_ENCOUNTER->objs[CURRENT_TURN]->obj->name << " uses " << BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove->name << " " << BATTLE_ENCOUNTER->objs[CURRENT_TURN]->selectedMove->grade << " on " << ent->obj->name << " recovering " << healAmt << " health.\n"; ent->AddHP(healAmt); @@ -3486,7 +3487,11 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), ITEM_SELECTION_CURSOR=std::clamp(ITEM_SELECTION_CURSOR,0,(int)PARTY_INVENTORY.size()-1); } - int CalculateDamage(Entity*attacker,Entity*defender) { + int CalculateHealing(Entity*user) { + return CalculateDamage(user,nullptr,false); + } + + int CalculateDamage(Entity*attacker,Entity*defender,bool includeDefenses=true) { int finalDamage = 0; int equipDamage = 0; for (int i=0;iequipment.size();i++) { @@ -3501,13 +3506,16 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), finalDamage += attackerDamage; int equipDefense = 0; - for (int i=0;iequipment.size();i++) { - if (defender->equipment[i]!=nullptr) { - equipDefense+=defender->equipment[i]->stats.defense; + if (includeDefenses) { + for (int i=0;iequipment.size();i++) { + if (defender->equipment[i]!=nullptr) { + equipDefense+=defender->equipment[i]->stats.defense; + } } } + finalDamage=std::max(1,finalDamage-equipDefense); - if (defender->selectedMove==MOVELIST[BattleMoveName::DEFEND]) { + if (includeDefenses&&defender->selectedMove==MOVELIST[BattleMoveName::DEFEND]) { finalDamage*=0.4; } return finalDamage; @@ -3681,7 +3689,7 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), label=label.replace(label.find("$USER"),5,ent->obj->name); } if (label.find("$POWER")!=std::string::npos) { - label=label.replace(label.find("$POWER"),6,ent->selectedMove->name+" "+((ent->selectedMove->grade!=0)?std::string(1,ent->selectedMove->grade):"")); + label=label.replace(label.find("$POWER"),6,ent->selectedMove->GetPowerName()); } if (label.find("$ITEM")!=std::string::npos) { label=label.replace(label.find("$ITEM"),5,EQUIP_$ITEM_DISPLAY); @@ -3857,15 +3865,74 @@ This is a test message that lets us trigger straight from a cutscene! Cool!)"), OVERWORLD_SELECTED_POWER=move; OVERWORLD_TARGET_SELECTION=0; if (move->name=="PK Lifeup") { + PARTY_MEMBER_STATS[PARTY_MEMBER_ID[partyMemberSlot]]->SubtractPP(move->PPCost); if (move->range==1) { GAME_STATE=GameState::OVERWORLD_TARGET_MENU; } else { - //DisplayMessageBox(PARTY_MEMBER_OBJ[partyMemberSlot]->name+" begins to cast "+move->name+" "+); - //DisplayMessageBox() + DisplayMessageBox(PARTY_MEMBER_OBJ[partyMemberSlot]->name+" begins to cast "+move->GetPowerName()+".\n"); + HEALING_OVERWORLD_MEMBERS=true; + HEALING_OVERWORLD_MEMBER=0; } } else { } } + + void HandleRollingCounters() { + if (BATTLE_ENCOUNTER!=nullptr||OverworldMenuOpen()) { + for (int i=0;i0) { + if (BATTLE_ROLLING_COUNTER_WAITTIME==0) { + player_rollwait_counter[i]=0; + } else { + player_rollwait_counter[i]--; + } + } + Entity*member=PARTY_MEMBER_STATS[PARTY_MEMBER_ID[i]]; + + HandleRollingCounters(i,player_rollhp_counter,player_rollhp_display,member,member->maxHP,member->GetHP(),member->GetTargetHP()); + HandleRollingCounters(i,player_rollpp_counter,player_rollpp_display,member,member->maxPP,member->GetPP(),member->GetTargetPP(),true); + + if (player_rollwait_counter[i]==0) { + player_rollwait_counter[i]=BATTLE_ROLLING_COUNTER_WAITTIME*13; + } + } + } + } + + bool OverworldMenuOpen() { + return GAME_STATE==GameState::OVERWORLD_MENU|| + GAME_STATE==GameState::OVERWORLD_POWER_MENU|| + GAME_STATE==GameState::OVERWORLD_GRADE_MENU|| + GAME_STATE==GameState::OVERWORLD_POWER_PLAYER_MENU|| + GAME_STATE==GameState::OVERWORLD_ITEMS_MENU|| + GAME_STATE==GameState::OVERWORLD_EQUIP_ITEM_MENU|| + GAME_STATE==GameState::OVERWORLD_EQUIP_MENU|| + GAME_STATE==GameState::OVERWORLD_EQUIP_PLAYER_MENU|| + GAME_STATE==GameState::OVERWORLD_STATUS_MENU|| + GAME_STATE==GameState::OVERWORLD_TARGET_MENU; + } + + void SetupRollingHitpointCounters() { + for (int i=0;iGetHP()%10; + player_rollpp_display[i][j]=member->GetPP()%10; + }break; + case 1:{ + player_rollhp_display[i][j]=member->GetHP()/10%10; + player_rollpp_display[i][j]=member->GetPP()/10%10; + }break; + case 2:{ + player_rollhp_display[i][j]=member->GetHP()/100%10; + player_rollpp_display[i][j]=member->GetPP()/100%10; + }break; + } + } + } + } }; int main()