From: Stan_Lewry <stanley.jml@gmail.com>
Date: Tue, 27 Aug 2024 17:42:23 +0000 (+0100)
Subject: first basic attacking implementation done
X-Git-Url: https://stanlewry.com/index.cgi?a=commitdiff_plain;h=f7fcb353dd9cb1b23e2111d8be2c0986330db888;p=dragonsurvivors.git

first basic attacking implementation done
---

diff --git a/combat.cpp b/combat.cpp
index 529c159..c2611d6 100644
--- a/combat.cpp
+++ b/combat.cpp
@@ -16,7 +16,7 @@ struct Character {
 	int maxHP;
 	int currentMP;
 	int maxMP;
-	
+	int attack;
 	float agility; // to determine move order
 	float moveDist;
 
@@ -31,13 +31,15 @@ struct Character {
 
 	bool canMove = true;
 	bool canAttack = true;
+
+	bool alive = true;
 };
 
 std::vector<Character> combatants;
 int currentCombatantIndex = -1;
 Character* activeCombatant;
 
-std::vector<Character> targets;
+std::vector<Character*> targets;
 int currentTargetIdx = 0;
 
 enum CombatState {
@@ -45,20 +47,24 @@ enum CombatState {
 	ACTION_SELECT,
 	PLAYER_MOVE,
 	SELECT_TARGET,
+	DO_ATTACK,
 	ENEMY_MOVE,
 	MOVE_TO_POSITION,
 };
 
 CombatState currentCombatState = TURN_ORDER;
 
+enum Spell {
+	BASIC_ATTACK
+};
+
+Spell currentSpell = BASIC_ATTACK;
 
 static double frameTimer = 0;
 static const double frameTime = 1.0f / 60.0f;
 
-
 //bool playerTurn = true;
 
-
 SDL_Texture* arrowSprite = nullptr;
 SDL_Texture* indicatorSprite = nullptr;
 SDL_Texture* indicatorRedSprite = nullptr;
@@ -99,6 +105,7 @@ void enemyMoveActionState(double delta);
 void movingCharacterState(double delta);
 void determineNextTurnState(double delta);
 void selectAttackTarget(double delta);
+void doAttack(double delta); // plays attack animation, resolves and applies damage.
 
 void runStateFunction(CombatState state, double delta) {
 	switch (state) {
@@ -108,6 +115,7 @@ void runStateFunction(CombatState state, double delta) {
 	case SELECT_TARGET: selectAttackTarget(delta);		break;
 	case ENEMY_MOVE: enemyMoveActionState(delta);		break;
 	case MOVE_TO_POSITION: movingCharacterState(delta);	break;
+	case DO_ATTACK: doAttack(delta);					break;
 	default: assert(false); break;
 	}
 }
@@ -163,15 +171,21 @@ void renderStatsPanel() {
 
 	renderString(portraitX + portraitWidth + innerPad, portraitY, "HP:");
 	int valPad = 100;
-	renderString(portraitX + portraitWidth + innerPad + valPad, portraitY, "50/100");
+	char hpStr[10];
+	sprintf(hpStr, "%d/%d", activeCombatant->currentHP, activeCombatant->maxHP);
+	renderString(portraitX + portraitWidth + innerPad + valPad, portraitY, hpStr);
 
-	renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad, panelWidth - (innerPad * 3) - portraitWidth, 20, 0.5, hpColour, 2);
+	float hpLvl = (float)activeCombatant->currentHP / (float)activeCombatant->maxHP;
+	renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad, panelWidth - (innerPad * 3) - portraitWidth, 20, hpLvl, hpColour, 2);
 
 	renderString(portraitX + portraitWidth + innerPad, portraitY + innerPad + 22, "MP:");
 
-	renderString(portraitX + portraitWidth + innerPad + valPad, portraitY + innerPad + 22, "50/100");
+	char mpStr[10];
+	sprintf(mpStr, "%d/%d", activeCombatant->currentMP, activeCombatant->maxMP);
+	renderString(portraitX + portraitWidth + innerPad + valPad, portraitY + innerPad + 22, mpStr);
 	
-	renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad + 42, panelWidth - (innerPad * 3) - portraitWidth, 20, 0.5, mpColour, 2);
+	float mpLvl = (float)activeCombatant->currentMP / (float)activeCombatant->maxMP;
+	renderMeter(portraitX + portraitWidth + innerPad, portraitY + innerPad + 42, panelWidth - (innerPad * 3) - portraitWidth, 20, mpLvl, mpColour, 2);
 	
 }
 
@@ -219,37 +233,41 @@ void renderCombat() {
 void renderCombatants() {
 
 	for (Character c : combatants) {
-		S2DE::Vec2<float> pos = c.position;
-		S2DE::Rect charDRect = S2DE::worldToScreenRect(&combatCam, &pos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
-		S2DE::Rect charSRect = { 0, 0, 32, 32 };
-
-		// disabled for now
-		//if (c.allied) {
-		//	// do the looking logic only for allied characters
-		//	int playerFrame = 1;
-		//	int playerDir = 0;
-
-		//	Character enemy = combatants.at(1);
-
-		//	int lookDeltaX = (enemy.position.x + 0.5) - (c.position.x + 0.5);
-		//	int lookDeltaY = (enemy.position.y + 0.5) - (c.position.y + 0.5);
-
-		//	if (abs(lookDeltaX) > abs(lookDeltaY)) {
-		//		if (lookDeltaX > 0) playerDir = 2;
-		//		else playerDir = 6;
-		//	}
-		//	else {
-		//		if (lookDeltaY > 0) playerDir = 4;
-		//		else playerDir = 0;
-		//	}
-
-		//	charSRect = { playerFrame * 32, playerDir * 32, 32, 32 };
-		//}
-
-		SDL_Texture* texture = c.texture;
-		S2DE::renderTexture(&renderer, &texture, &charSRect, &charDRect);
-		
-		renderMeter(charDRect.x + 6, charDRect.y - 6, charDRect.w - 12, 6, 0.5, hpColour, 1);
+
+		if (c.alive) {
+			S2DE::Vec2<float> pos = c.position;
+			S2DE::Rect charDRect = S2DE::worldToScreenRect(&combatCam, &pos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
+			S2DE::Rect charSRect = { 0, 0, 32, 32 };
+
+			// disabled for now
+			//if (c.allied) {
+			//	// do the looking logic only for allied characters
+			//	int playerFrame = 1;
+			//	int playerDir = 0;
+
+			//	Character enemy = combatants.at(1);
+
+			//	int lookDeltaX = (enemy.position.x + 0.5) - (c.position.x + 0.5);
+			//	int lookDeltaY = (enemy.position.y + 0.5) - (c.position.y + 0.5);
+
+			//	if (abs(lookDeltaX) > abs(lookDeltaY)) {
+			//		if (lookDeltaX > 0) playerDir = 2;
+			//		else playerDir = 6;
+			//	}
+			//	else {
+			//		if (lookDeltaY > 0) playerDir = 4;
+			//		else playerDir = 0;
+			//	}
+
+			//	charSRect = { playerFrame * 32, playerDir * 32, 32, 32 };
+			//}
+
+			SDL_Texture* texture = c.texture;
+			S2DE::renderTexture(&renderer, &texture, &charSRect, &charDRect);
+
+			float hpLvl = (float)c.currentHP / (float)c.maxHP;
+			renderMeter(charDRect.x + 6, charDRect.y - 6, charDRect.w - 12, 6, hpLvl, hpColour, 1);
+		}
 	}
 
 	// render the little arrow
@@ -288,6 +306,8 @@ void initCombatScene()
 	player.moveDist = 3.0f;
 	player.texture = player_forward_texture;
 	player.position = { arenaCenter.x, arenaCenter.y + 2 };
+	player.attack = 5;
+
 
 	Character monica;
 	monica.allied = true;
@@ -300,18 +320,20 @@ void initCombatScene()
 	monica.moveDist = 6.0f;
 	monica.texture = monica_texture;
 	monica.position = { player.position.x - 2, player.position.y };
+	monica.attack = 6;
 
 	Character enemy;
 	enemy.allied = false;
 	enemy.name = "Bird";
 	enemy.maxHP = 25;
-	enemy.currentHP = player.maxHP;
+	enemy.currentHP = enemy.maxHP;
 	enemy.maxMP = 10;
-	enemy.currentMP = player.maxMP;
+	enemy.currentMP = enemy.maxMP;
 	enemy.agility = 5.0f;
 	enemy.moveDist = 1.5f;
 	enemy.texture = bird;
 	enemy.position = { arenaCenter.x, arenaCenter.y - 2 };
+	enemy.attack = 2;
 
 	Character frog;
 	frog.allied = false;
@@ -322,6 +344,7 @@ void initCombatScene()
 	frog.moveDist = 2.0f;
 	frog.texture = frog_texture;
 	frog.position = { arenaCenter.x - 1, arenaCenter.y - 2 };
+	frog.attack = 2;
 
 	combatants.push_back(player);
 	combatants.push_back(monica);
@@ -389,17 +412,15 @@ void actionSelectState(double delta) {
 			if (activeCombatant->canAttack) {
 				// filter the targets
 				targets.clear();
-				//float range = activeCombatant->basicAttackRange;
-				std::copy_if(combatants.begin(), combatants.end(), std::back_inserter(targets),
-					[](const Character& c) {
-						if (!c.allied) {
-							float dist = distance(activeCombatant->position, c.position);
-							if (dist <= activeCombatant->basicAttackRange) {
-								return true;
-							}
+				for (auto& c : combatants) {
+					if (!c.allied && c.alive) {
+						float dist = distance(activeCombatant->position, c.position);
+						if (dist <= activeCombatant->basicAttackRange) {
+							targets.push_back(&c);
 						}
-						return false;
-					});
+					}
+				}
+
 				currentCombatState = SELECT_TARGET;
 			}
 			break;
@@ -506,7 +527,14 @@ void selectAttackTarget(double delta) {
 		frameTimer = 0;
 		if (inputState.rtrn) {
 			inputState.rtrn = false;
-			currentCombatState = ACTION_SELECT;
+			if (targets.size() > 0) {
+				currentSpell = BASIC_ATTACK;
+				currentCombatState = DO_ATTACK;
+			}
+			else {
+				currentCombatState = ACTION_SELECT;
+			}
+
 		}
 
 		if (inputState.right) {
@@ -542,7 +570,7 @@ void selectAttackTarget(double delta) {
 	// render the little red arrow above all valid targets
 	//for (auto target : targets) {
 	if (targets.size() > 0) {
-		S2DE::Vec2<float> arrowPos = targets.at(currentTargetIdx).position;
+		S2DE::Vec2<float> arrowPos = targets.at(currentTargetIdx)->position;
 
 		arrowPos.y -= 0.7;
 		S2DE::Rect arrowDRect = S2DE::worldToScreenRect(&combatCam, &arrowPos, 2, WINDOW_WIDTH, WINDOW_HEIGHT, 32, 32);
@@ -573,6 +601,31 @@ void selectAttackTarget(double delta) {
 
 }
 
+void doAttack(double delta) {
+	// for now just subtract the combatants' dmg from the targets hp and move on
+	
+
+	if (currentTargetIdx == -1) {
+		// AOE, apply to all targets in range ?
+	}
+	else {
+		Character* target = targets.at(currentTargetIdx);
+		target->currentHP -= activeCombatant->attack;
+
+		if (target->currentHP <= 0) {
+			target->alive = false;
+			target->currentHP = 0;
+		}
+	}
+
+
+
+	targets.clear();
+	currentCombatState = ACTION_SELECT;
+	activeCombatant->canAttack = false;
+}
+
+
 void enemyMoveActionState(double delta) {
 	S2DE::updateInputState(&inputState);
 
@@ -641,15 +694,17 @@ void determineNextTurnState(double delta) {
 
 	activeCombatant = &combatants.at(currentCombatantIndex);
 
-	if (activeCombatant->allied) {
-		// reset combatants actions
-		activeCombatant->canAttack = true;
-		activeCombatant->canMove = true;
-		currentAction = 0;
-		currentCombatState = ACTION_SELECT;
-	}
-	else {
-		currentCombatState = ENEMY_MOVE;
+	if (activeCombatant->alive) { // skip dead characters
+		if (activeCombatant->allied) {
+			// reset combatants actions
+			activeCombatant->canAttack = true;
+			activeCombatant->canMove = true;
+			currentAction = 0;
+			currentCombatState = ACTION_SELECT;
+		}
+		else {
+			currentCombatState = ENEMY_MOVE;
+		}
 	}
 
 }