break;
}
}
- CurrentState()->HandleEvents(input);
+ if (CurrentState()) CurrentState()->HandleEvents(input);
}
void Application::UpdateWorld(Uint32 deltaT) {
}
-void BattleState::ClearAllAttacks() {
- activeHero = -1;
- for (int i(0); i < numHeroes; ++i) {
- attackChoices[i] = AttackChoice(this);
- }
-}
-
-
class OrderCompare {
public:
OrderCompare(BattleState *battle) : battle(battle) { }
BattleState *battle;
};
-void BattleState::WriteOrder(std::vector<Order> &order) {
- order.reserve(monsters.size() + NumHeroes());
+void BattleState::CalculateAttackOrder() {
+ attackOrder.reserve(monsters.size() + NumHeroes());
for (int i(0); i < numHeroes; ++i) {
- order.push_back(Order(i, false));
+ attackOrder.push_back(Order(i, false));
}
for (vector<Monster>::size_type i(0), end(monsters.size()); i < end; ++i) {
- order.push_back(Order(i, true));
+ attackOrder.push_back(Order(i, true));
+ }
+ std::sort(attackOrder.begin(), attackOrder.end(), OrderCompare(this));
+
+ monsterAttacks.resize(monsters.size(), AttackChoice(this));
+}
+
+void BattleState::NextAttack() {
+ ++attackCursor;
+ while (attackCursor < int(attackOrder.size())) {
+ if (attackOrder[attackCursor].isMonster) {
+ if (MonsterAt(attackOrder[attackCursor].index).Health() > 0) break;
+ } else {
+ if (HeroAt(attackOrder[attackCursor].index).Health() > 0) break;
+ }
+ ++attackCursor;
+ }
+}
+
+void BattleState::CalculateDamage() {
+ if (CurrentAttack().isMonster) {
+ // TODO: run monster's attack script
+ monsterAttacks[CurrentAttack().index].SetType(AttackChoice::SWORD);
+ monsterAttacks[CurrentAttack().index].Selection().SelectSingle();
+ monsterAttacks[CurrentAttack().index].Selection().SelectHeroes();
+ monsterAttacks[CurrentAttack().index].Selection().SetBad(0, 15);
+ } else {
+ TargetSelection &ts(AttackChoiceAt(CurrentAttack().index).Selection());
+ if (ts.TargetsEnemies()) {
+ for (int i(0); i < NumHeroes(); ++i) {
+ if (ts.IsSelected(i)) {
+ ts.SetBad(i, 15);
+ }
+ }
+ } else {
+ for (int i(0); i < MaxMonsters(); ++i) {
+ if (ts.IsSelected(i) && MonsterAt(i).Health() > 0) {
+ ts.SetBad(i, 15);
+ }
+ }
+ }
+ }
+}
+
+void BattleState::ClearAllAttacks() {
+ attackCursor = -1;
+ activeHero = -1;
+ for (int i(0); i < numHeroes; ++i) {
+ attackChoices[i] = AttackChoice(this);
}
- std::sort(order.begin(), order.end(), OrderCompare(this));
+ attackOrder.clear();
+ monsterAttacks.clear();
}
, moveMenu(res->moveIcons)
, numHeroes(0)
, activeHero(-1)
+ , attackCursor(-1)
, ranAway(false) { }
public:
bool HasChosenAttackType() const { return attackChoices[activeHero].GetType() != AttackChoice::UNDECIDED; }
AttackChoice &ActiveHeroAttackChoice() { return attackChoices[activeHero]; }
const AttackChoice &ActiveHeroAttackChoice() const { return attackChoices[activeHero]; }
+ AttackChoice &AttackChoiceAt(int index) { return attackChoices[index]; }
const AttackChoice &AttackChoiceAt(int index) const { return attackChoices[index]; }
bool AttackSelectionDone() const { return activeHero >= numHeroes; }
bool HeroPositionOccupied(int index) const { return index >= 0 && index < numHeroes; }
void SetRunaway() { ranAway = true; }
- void ClearAllAttacks();
struct Order {
Order(int index, bool isMonster)
bool isMonster;
};
- void WriteOrder(std::vector<Order> &);
+ void CalculateAttackOrder();
+ void NextAttack();
+ bool AttacksFinished() const { return attackCursor >= int(attackOrder.size()); }
+ void CalculateDamage();
+ const Order &CurrentAttack() const { return attackOrder[attackCursor]; };
+ void ClearAllAttacks();
public:
geometry::Vector<int> CalculateScreenOffset(SDL_Surface *screen) const {
std::vector<geometry::Point<int> > monsterPositions;
std::vector<geometry::Point<int> > heroesPositions;
std::vector<Monster> monsters;
+ std::vector<AttackChoice> monsterAttacks;
+ std::vector<Order> attackOrder;
Hero heroes[4];
graphics::Menu<const common::Spell *> spellMenus[4];
graphics::Menu<const common::Item *> itemMenu;
AttackChoice attackChoices[4];
int numHeroes;
int activeHero;
+ int attackCursor;
bool ranAway;
};
TargetSelection::TargetSelection(BattleState *battle, bool multiple, bool atEnemy)
: battle(battle)
-, selected(battle ? ((int)battle->MonsterPositions().size() > battle->NumHeroes() ? (int)battle->MonsterPositions().size() : battle->NumHeroes()) : 0, false)
+, selected(battle ? ((int)battle->MonsterPositions().size() > battle->NumHeroes() ? (int)battle->MonsterPositions().size() : battle->NumHeroes()) : 0, State())
, selection(-1)
, cursor(0)
, multiple(multiple)
public:
bool TargetsEnemies() const { return enemy; }
bool TargetsHeroes() const { return !TargetsEnemies(); }
- bool IsSelected(int index) const { return index >= 0 && index < int(selected.size()) && selected[index]; }
+ bool IsSelected(int index) const { return index >= 0 && index < int(selected.size()) && selected[index].type != State::IGNORE; }
bool HasSelected() const { return selection >= 0; }
int SingleSelection() const { return selection; }
void SelectEnemies();
void SelectHeroes();
- void Select(int index) { selected[index] = true; selection = index; }
- void Unselect(int index) { selected[index] = false; }
- void UnselectAll() { selected.assign(selected.size(), false); selection = -1; }
+ void Select(int index) { selected[index].type = State::SELECTED; selection = index; }
+ void Unselect(int index) { selected[index].type = State::IGNORE; }
+ void UnselectAll() { selected.assign(selected.size(), State()); selection = -1; }
void Reset();
- void Resize(int num) { selected.resize(num, false); }
+ void Resize(int num) { selected.resize(num); }
void MoveUp();
void MoveRight();
int Current() const { return cursor; }
bool CurrentIsSelected() { return IsSelected(cursor); }
+ void SetMiss(int index) { selected[index].type = State::MISS; }
+ void SetFull(int index) { selected[index].type = State::FULL; }
+ void SetGood(int index, int amount) { selected[index].type = State::GOOD; selected[index].number = amount; }
+ void SetBad(int index, int amount) { selected[index].type = State::BAD; selected[index].number = amount; }
+ int GetAmount(int index) const { return selected[index].number; }
+
private:
void FindNextEnemy();
private:
+ struct State {
+ enum Type {
+ IGNORE,
+ SELECTED,
+ MISS,
+ FULL,
+ GOOD,
+ BAD,
+ } type;
+ int number;
+ explicit State(Type type = IGNORE, int num = 0) : type(type), number(num) { }
+ };
BattleState *battle;
- std::vector<bool> selected;
+ std::vector<State> selected;
int selection;
int cursor;
bool multiple;
void PerformAttacks::EnterState(Application &c, SDL_Surface *screen) {
ctrl = &c;
- battle->WriteOrder(order);
+ battle->CalculateAttackOrder();
numberAnimation.reserve(battle->MaxMonsters() > battle->NumHeroes() + 1 ? battle->MaxMonsters() : battle->NumHeroes() + 1);
numberPosition.reserve(numberAnimation.size());
}
CheckAnimations();
if (HasAnimationsRunning()) return;
ResetAnimation();
- AdvanceCursor();
- if (Finished()) {
+ battle->NextAttack();
+ if (battle->AttacksFinished()) {
battle->ClearAllAttacks();
ctrl->PopState();
return;
}
- if (order[cursor].isMonster) {
- const Monster &monster(battle->MonsterAt(order[cursor].index));
+ battle->CalculateDamage();
+
+ if (battle->CurrentAttack().isMonster) {
+ const Monster &monster(battle->MonsterAt(battle->CurrentAttack().index));
titleBarText = monster.Name();
moveAnimation = 0;
} else {
- Hero &hero(battle->HeroAt(order[cursor].index));
- const AttackChoice &ac(battle->AttackChoiceAt(order[cursor].index));
+ Hero &hero(battle->HeroAt(battle->CurrentAttack().index));
+ const AttackChoice &ac(battle->AttackChoiceAt(battle->CurrentAttack().index));
switch (ac.GetType()) {
case AttackChoice::SWORD:
}
moveAnimation = hero.AttackAnimation();
- numberAnimation.push_back(NumberAnimation(15, battle->Res().numberAnimationPrototype, battle->Res().bigNumberSprite));
if (ac.Selection().TargetsEnemies()) {
- numberPosition.push_back(
- battle->MonsterPositions()[ac.Selection().SingleSelection()]);
+ for (int i(0); i < battle->MaxMonsters(); ++i) {
+ if (ac.Selection().IsSelected(i)) {
+ numberAnimation.push_back(NumberAnimation(ac.Selection().GetAmount(i), battle->Res().numberAnimationPrototype, battle->Res().bigNumberSprite));
+ numberPosition.push_back(
+ battle->MonsterPositions()[i]);
+ }
+ }
} else {
- numberPosition.push_back(
- battle->HeroesPositions()[ac.Selection().SingleSelection()]);
+ for (int i(0); i < battle->NumHeroes(); ++i) {
+ if (ac.Selection().IsSelected(i)) {
+ numberAnimation.push_back(NumberAnimation(ac.Selection().GetAmount(i), battle->Res().numberAnimationPrototype, battle->Res().bigNumberSprite));
+ numberPosition.push_back(
+ battle->HeroesPositions()[i]);
+ }
+ }
}
break;
case AttackChoice::MAGIC:
numberPosition.clear();
}
-void PerformAttacks::AdvanceCursor() {
- ++cursor;
- while (cursor < int(order.size())) {
- if (order[cursor].isMonster) {
- if (battle->MonsterAt(order[cursor].index).Health() > 0) break;
- } else {
- if (battle->HeroAt(order[cursor].index).Health() > 0) break;
- }
- ++cursor;
- }
-}
-
void PerformAttacks::UpdateWorld(float deltaT) {
void PerformAttacks::RenderTargetAnimation(SDL_Surface *screen, const geometry::Vector<int> &offset) const {
if (!targetAnimation || !targetAnimation->Running()) return;
- if (order[cursor].isMonster) return; // no monsters for now
- const TargetSelection &ts(battle->AttackChoiceAt(order[cursor].index).Selection());
+ if (battle->CurrentAttack().isMonster) return; // no monsters for now
+ const TargetSelection &ts(battle->AttackChoiceAt(battle->CurrentAttack().index).Selection());
const vector<Point<int> > &positions(ts.TargetsHeroes() ? battle->HeroesPositions() : battle->MonsterPositions());
for (vector<Point<int> >::size_type i(0), end(positions.size()); i < end; ++i) {
if (ts.IsSelected(i)) {
void CheckAnimations();
bool HasAnimationsRunning() const;
void ResetAnimation();
- void AdvanceCursor();
- bool Finished() const { return cursor >= int(order.size()); }
private:
void RenderTitleBar(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
const char *titleBarText;
app::Timer<Uint32> titleBarTimer;
app::Timer<Uint32> targetAnimationTimer;
- std::vector<BattleState::Order> order;
std::vector<NumberAnimation> numberAnimation;
std::vector<geometry::Point<int> > numberPosition;
int cursor;