Partie 37: Les attaques Partie 1
Téléchargements
Les attaques
				
		<text id="ATTACK01">FENDRE</text>
		<text id="ATTACK02">ENTAILLER</text>
		<text id="ATTACK03">SONNER FORT</text>
		<text id="ATTACK04">PILE OU FACE</text>
		<text id="ATTACK05">COGNER</text>
		<text id="ATTACK06">COUP DE PIED</text>
		<text id="ATTACK07">AMORT</text>
		<text id="ATTACK08">POIGNARDER</text>
		<text id="ATTACK09">DESCENDRE</text>
		<text id="ATTACK10">CONGELER</text>
		<text id="ATTACK11">FRAPPER</text>
		<text id="ATTACK12">TAILLADER</text>
		<text id="ATTACK13">PLONGER</text>
		<text id="ATTACK14">PIQUER</text>
		<text id="ATTACK15">PARER</text>
		<text id="ATTACK16">ABATTRE</text>
		<text id="ATTACK17">SE RUER SUR</text>
		<text id="ATTACK18">BOULE DE FEU</text>
		<text id="ATTACK19">CONJURER</text>
		<text id="ATTACK20">SUBJUGUER</text>
		<text id="ATTACK21">ECLAIR</text>
		<text id="ATTACK22">ENSORCELER</text>
		<text id="ATTACK23">MELEE</text>
		<text id="ATTACK24">INVOQUER</text>
		<text id="ATTACK25">TAILLADER</text>
		<text id="ATTACK26">POURFENDRE</text>
		<text id="ATTACK27">ASSOMMER</text>
		<text id="ATTACK28">ETOURDIR</text>
		<text id="ATTACK29">TIRER</text>
		<text id="ATTACK30">AURA MAGIQUE</text>
		<text id="ATTACK31">PARE-FEU</text>
		<text id="ATTACK32">CAGE</text>
		<text id="ATTACK33">GUERIR</text>
		<text id="ATTACK34">TRANQUILISER</text>
		<text id="ATTACK35">LUMIERE</text>
		<text id="ATTACK36">FENETRE</text>
		<text id="ATTACK37">CRACHER</text>
		<text id="ATTACK38">BRANDIR</text>
		<text id="ATTACK39">LANCER</text>
		<text id="ATTACK40">FUSIONNER</text>
				
				J'ai créé une nouvelle base de données "attacks.xml" qui contient quelques paramètres pour chacune d'entre-elles,
Combos
		<?xml version="1.0" encoding="utf-8"?>
		<combos>
			<!-- Combo 0 (inutilise) -->
			<combo>
				<attack type="0">
				</attack>
				<attack type="0">
				</attack>
				<attack type="0">
				</attack>
			</combo>
			<!-- Combo 1 Invoquer/Fusionner/Cage -->
			<combo>
				<attack type="24">
				</attack>
				<attack type="40">
				</attack>
				<attack type="32">
				</attack>
			</combo>
			<!-- Combo 2 Cogner/Coup de Pied/Amort -->
			<combo>
				<attack type="5">
				</attack>
				<attack type="6">
				</attack>
				<attack type="7">
				</attack>
			</combo>
			[...]
		</combos>
				
				Chaque combo contient 3 attaques qui ont seulement un type. A l'avenir ces attaques contiendront plus de paramètres.
		class CAttacks
		{
		public:
			[...]
			struct SComboAttack
			{
				uint8_t type;
			};
			struct SCombo
			{
				SComboAttack    attacks[3];
			};
			[...]
			void        readCombosDB();
			[...]
			SCombo&     getCombo(int num);
		private:
			[...]
			std::vector<SCombo> mCombos;
		};
				
			
			
Lier les combos aux armes
		<?xml version="1.0" encoding="utf-8"?>
		<items>
			<!-- MAIN NUE -->
			<item name="ITEM000">
				<category>Weapon</category>
				<image_file>Items6.png</image_file>
				<image_num>9</image_num>
				<weight>0</weight>
				<combo>2</combo>
			</item>
			<!-- ======================== Armes ======================== -->
			<!-- OEIL DU TEMPS -->
			<item name="ITEM001">
				<category>Weapon</category>
				<floor_image>00W_Ring.png</floor_image>
				<image_file>Items0.png</image_file>
				<image_num>17</image_num>
				<position>hBCP</position>
				<weight>1</weight>
				<combo>43</combo>
			</item>
			<!-- ROND D'ECLAIRS -->
			<item name="ITEM002">
				<category>Weapon</category>
				<floor_image>00W_Ring.png</floor_image>
				<image_file>Items0.png</image_file>
				<image_num>19</image_num>
				<position>hBCP</position>
				<weight>1</weight>
				<combo>7</combo>
			</item>
				
				Vous pouvez voir que j'ai ajouté un objet "main nue" parce que quand il n'y a pas d'arme dans la main du champion,
        CObjects::CObjectInfo&  infos = objects.mObjectInfos[objType - 1];
				
				Ca prêtait à confusion et ça pouvait créer des bugs. Alors maintenant, on n'a plus besoin du "-1".
				
		void    CInterface::drawWeapon(QImage* image, int num)
		{
			if (isWeaponEmpty(num) == false)
			{
				// dessine le rectangle de fond
				CRect   rect(CVec2(233 + 22 * num, 86),
							 CVec2(252 + 22 * num, 120));
				graph2D.rect(image, rect, MAIN_INTERFACE_COLOR, true);
				// dessine l'arme
				CVec2       pos = CVec2(235 + 22 * num, 96);
				CObject&    weapon = getWeapon(num);
				int         weaponType = weapon.getType();
				CObjects::CObjectInfo   weaponInfo = objects.mObjectInfos[weaponType];
				if (weaponInfo.combo != 0)
				{
					std::string imageFile;
					int         imageNum;
					CObjects::CObjectInfo  object = objects.mObjectInfos[weaponType];
					imageFile = object.imageFile.toLocal8Bit().constData();
					imageNum = object.imageNum;
					QImage  objImage = fileCache.getImage(imageFile);
					CRect   objRect = getItemRect(imageNum);
					graph2D.drawImageAtlas(image, pos, objImage, objRect, BLACK);
				}
				// griser ou zone souris
				if (isWeaponGreyed(num) == true)
					graph2D.patternRectangle(image, rect);
				else if (weaponInfo.combo != 0)
					mouse.addArea(eMouseArea_Weapon, rect, eCursor_Arrow, (void*)num);
			}
		}
				
				Bien entendu on utilise aussi les données de la combo pour trouver combien d'attaques a une arme et afficher leurs
		void    CInterface::drawAttacks(QImage* image, int num)
		{
			CObject&    weapon = getWeapon(num);
			int         weaponType = weapon.getType();
			CObjects::CObjectInfo   weaponInfo = objects.mObjectInfos[weaponType];
			CAttacks::SCombo&       combo = attacks.getCombo(weaponInfo.combo);
			// dessine l'image de fond
			QImage  attacksBg = fileCache.getImage("gfx/interface/WeaponsActions.png");
			CVec2   pos(233, 77);
			graph2D.drawImage(image, pos, attacksBg);
			// cache les slots inutiles
			for (int i = 0; i < 3; ++i)
			{
				if (combo.attacks[i].type == 0)
				{
					CRect   rect(CVec2(233, 86 + i * 12),
								 CVec2(319, 97 + i * 12));
					graph2D.rect(image, rect, BLACK, true);
				}
			}
			// écrit le nom du personnage
			CCharacter* c = &game.characters[num];
			drawText(image, CVec2(235, 79), eFontStandard, c->firstName.c_str(), BLACK);
			// écrit le nom des attaques
			for (int i = 0; i < 3; ++i)
			{
				if (combo.attacks[i].type != 0)
				{
					static char attackName[16];
					sprintf(attackName, "ATTACK%02d", combo.attacks[i].type);
					drawText(image, CVec2(241, 89 + i * 12), eFontStandard, getText(attackName).c_str(), MAIN_INTERFACE_COLOR);
					if (attackHighlightTime.isRunning() == true && currentAttack == i)
					{
						CRect   rect(CVec2(234, 86 + i * 12),
									 CVec2(318, 96 + i * 12));
						graph2D.Xor(image, rect, MAIN_INTERFACE_COLOR);
					}
				}
			}
			// zones souris
			if (isWeaponGreyed(num) == false && attackHighlightTime.isRunning() == false)
			{
				for (int i = 0; i < 3; ++i)
				{
					if (combo.attacks[i].type != 0)
					{
						CRect   rect(CVec2(234, 86 + i * 12),
									 CVec2(318, 96 + i * 12));
						mouse.addArea(eMouseArea_Attack, rect, eCursor_Arrow, (void*)i);
					}
				}
				CRect   rect(CVec2(290, 77), CVec2(314, 83));
				mouse.addArea(eMouseArea_CloseAttack, rect, eCursor_Arrow);
			}
		}
				
				Toutes les attaques d'une arme ne seront pas disponibles dès le départ. Certaines nécessiteront que le personnage
La base de données des attaques
		<?xml version="1.0" encoding="utf-8"?>
		<attacks>
			<!-- Rien -->
			<attack>
				<cooldown>0</cooldown>
				<hitprob>0</hitprob>
			</attack>
			<!-- FENDRE -->
			<attack>
				<cooldown>60</cooldown>
				<hitprob>22</hitprob>
			</attack>
			<!-- ENTAILLER -->
			<attack>
				<cooldown>80</cooldown>
				<hitprob>48</hitprob>
			</attack>
				
				Pour le moment il contient seulement le temps de cooldown en nombre de frames et la probabilité de toucher avec
		void CInterface::updateWeapons()
		{
			// surbrillance de l'attaque
			if (attackHighlightTime.update() == true)
			{
				CObject&    weapon = getWeapon(currentWeapon);
				int         weaponType = weapon.getType();
				CObjects::CObjectInfo   weaponInfo = objects.mObjectInfos[weaponType];
				CAttacks::SCombo&        combo = attacks.getCombo(weaponInfo.combo);
				int         attackType = combo.attacks[currentAttack].type;
				CAttacks::SAttack&       attack = attacks.getAttack(attackType);
				weaponCoolDown[currentWeapon].set(attack.cooldown, true);
				if (((rand() % 75) + 1) <= attack.hitProbability)
				{
					damages = rand() % 200 + 1;
					damagesDisplayTime.set(DAMAGES_DISPLAY_TIME, false);
					weaponsAreaState = eWeaponsAreaDamage;
				}
				else
				{
					weaponsAreaState = eWeaponsAreaWeapons;
				}
			}
			// timer des dégats
			if (damagesDisplayTime.update() == true)
				weaponsAreaState = eWeaponsAreaWeapons;
			// cooldowns des armes
			for (int i = 0; i < 4; ++i)
				weaponCoolDown[i].update();
		}
				
				Ce n'est pas la formule exacte utilisée dans le jeu d'origine, car la probabilité de toucher va varier avec les