Partie 43: Vie et mort des champions
Téléchargements
Dégâts et mort
		void CCharacter::hitChampion(int num, int damages)
		{
			// déjà mort ou vide ?
			if (portrait == -1 || isDead() == true)
				return;
			displayedDamages = damages;
			damagesTimer.set(90, false);
			stats[eStatHealth].value -= damages;
			static CVec2    championPos[4][4] =
			{
				{{0, 0}, {1, 0}, {0, 1}, {1, 1}},   // up
				{{0, 1}, {0, 0}, {1, 1}, {1, 0}},   // left
				{{1, 1}, {0, 1}, {1, 0}, {0, 0}},   // down
				{{1, 0}, {1, 1}, {0, 0}, {0, 1}}    // right
			};
			// mort ?
			if (stats[eStatHealth].value <= 0)
			{
				stats[eStatHealth].value = 0;
				// jette tous les objet sur le sol
				CVec2   stackPos = player.pos * 2 + championPos[player.dir][num];
				CObjectStack*   stack = map.addObjectsStack(stackPos, eWallSideMax);
				for (int i = 0; i < eBodyPartCount; ++i)
				{
					CObject&    obj = bodyObjects[i];
					if (obj.getType() != 0)
					{
						stack->addObject(obj);
						obj.setType(0);
					}
				}
				// jette les os du champion
				CObject bones;
				bones.setType(OBJECT_TYPE_BONES);
				bones.setIntParam("Champion", num);
				stack->addObject(bones);
			}
		}
				
				On soustrait les dégâts à la santé du champion.
				
		<!-- OS DE # -->
		<item name="ITEM149">
			[...]
			<param type="int">Champion</param>
		</item>
				
				Parce qu'on doit connaître le nom du champion pour afficher le nom des os quand on les ramasse.
				
		void CInterface::drawObjectName(QImage* image)
		{
			int type = mouse.mObjectInHand.getType();
			if (type != 0)
			{
				std::string name;
				if (type == OBJECT_TYPE_BONES)
					name = setChampionNameInString(mouse.mObjectInHand.getIntParam("Champion"), "ITEM149");
				else
					name = objects.mObjectInfos[type].name;
				drawText(image, CVec2(233, 33), eFontStandard, name.c_str(), MAIN_INTERFACE_COLOR);
			}
		}
				
			
			
Se cogner contre les murs
				
		void CPlayer::moveIfPossible(EWallSide side)
		{
			[...]
			if (canMove == true)
			{
				[...]
			}
			else
			{
				if (game.characters[0].portrait != -1)
				{
					static const int championsHit[eWallSideMax][2] =
					{
						{0, 1}, // eWallSideUp
						{2, 3}, // eWallSideDown
						{0, 2}, // eWallSideLeft
						{1, 3}  // eWallSideRight
					};
					for (int i = 0; i < 2; ++i)
					{
						int champNum = championsHit[invWallSide(side)][i];
						game.characters[champNum].hitChampion(champNum, (RANDOM(4) == 0 ? 2 : 1));
					}
					sound->play(newPos, "sound/Party_Damaged.wav");
				}
			}
		}
				
				J'aurais probablement dû utiliser la fonction getChampionRow() de la partie précédente ici et prendre en compte le
Tomber dans un trou
				
		void CPlayer::fall()
		{
			[...]
			hitAllChampions(20);
		}
		//-----------------------------------------------------------------------------------------
		void CPlayer::hitAllChampions(int damages)
		{
			int rnd = damages / 8 + 1;
			sound->play(pos, "sound/Party_Damaged.wav");
			for (int i = 0; i < 4; ++i)
			{
				int dmg = damages - rnd + RANDOM(rnd * 2);
				dmg = MAX(1, dmg);
				game.characters[i].hitChampion(i, dmg);
			}
		}
				
			
			
L'autel Vi
				
		void CGame::update(SMouseArea* clickedArea)
		{
			[...]
			else if (clickedArea->type == eMouseAreaG_DropObject)
			{
				// récupère la position et le coté
				[...]
				// jette l'objet
				CObjectStack*   stack = map.addObjectsStack(pos, side);
				stack->addObject(mouse.mObjectInHand);
				// test si on ressuscite un champion
				if (mouse.mObjectInHand.getType() == OBJECT_TYPE_BONES &&
				    side != eWallSideMax)
				{
					CWall&  wall = map.getTile(pos)->mWalls[side];
					if (wall.getType() == eWallAlcove &&
					    wall.getEnumParam("Type") == 2)
					{
						// ressuscite
						sound->play(pos, "sound/Spell.wav");
						walls.resurrectWallPos = pos;
						walls.resurrectWallSide = side;
						walls.resurrectTimer.set(120, true);
					}
				}
				
				Le timer est utilisé pour jouer une animation d'éclair pendant 2 secondes.
		CWalls::COrnateData  alcoveLightning =
		{
			"",
			"gfx/3DView/missiles/Lightning_side.png",
			"",
			{82, 95},
			{0, 0}
		};
		//---------------------------------------------------------------------------------------------
		CRect CWalls::drawOrnate(QImage* image, CVec2 tablePos, EWallSide side, int ornate, int textLines)
		{
			if (ornate != 0)
			{
				int tableSide = walls.getTableSide(side, false);
				if (gWallsInfos[tablePos.y][tablePos.x][tableSide].size.x != 0)
				{
					COrnateData* ornateData = NULL;
					if (ornate == ORNATE_ALCOVE_LIGHTNING)
						ornateData = &alcoveLightning;
					else
						ornateData = &walls.ornatesDatas[ornate];
					[...]
					// dessine les décors à l'écran.
					bool    flipX = false;
					bool    flipY = false;
					if (ornate == ORNATE_ALCOVE_LIGHTNING)
					{
						int image = walls.resurrectTimer.get() / 30;
						flipX = image & 1;
						flipY = (image >> 1) & 1;
					}
					graph2D.drawImage(image, ornatePos, tempImage, 0, flipX, QRect(0, 33, MAINVIEW_WIDTH, MAINVIEW_HEIGHT), flipY);
				
			
			
Explosion
				
		void CExplosions::add(EExplosions type, CVec2 mapPos, int duration)
		{
			SExplosion  explo;
			explo.type = type;
			explo.mapPos = mapPos;
			explo.timer.set(duration, true);
			mExploList.push_back(explo);
			if (type == eExplo_Resurrect)
				sound->play(mapPos, "sound/Explosion.wav");
		}
				
				Une fonction update() gère les timers de toutes les explosions et les retire de la liste quand elles sont
		void CExplosions::update()
		{
			std::vector<SExplosion>::iterator   it = mExploList.begin();
			while(it != mExploList.end())
			{
				if (it->timer.update() == true)
					it = mExploList.erase(it);
				else
					it++;
			}
		}
				
				La fonction draw() est une version simplifiée de CWalls::drawOrnate()
				
		void CExplosions::draw(QImage* image, CVec2 mapPos, CVec2 tablePos)
		{
			for (size_t i = 0; i < mExploList.size(); ++i)
			{
				SExplosion& explo = mExploList[i];
				if (explo.mapPos == mapPos)
				{
					QImage  exploGfx;
					CVec2   pos;
					float   scale = 1.0;
					if (explo.type == eExplo_Resurrect)
					{
						exploGfx = fileCache.getImage("gfx/3DView/explosions/Fireball.png");
						pos = CVec2(57, 66);
						scale = 110.0 / 145.0;
					}
					const SWallInfos*   tabData = &gWallsInfos[tablePos.y][tablePos.x][eWallSideUp];
					if (tabData->size.x != 0)
					{
						const SWallInfos*   refWall = NULL;
						refWall = &gWallsInfos[3][2][eWallSideUp];
						// calcule la position et la taille et dessine l'explosion dans une image temporaire
						scale *= (float)tabData->size.y / 111.0f;
						QSize   scaledSize = exploGfx.size() * scale;
						pos = pos - refWall->pos;
						pos.x = pos.x * tabData->size.x / refWall->size.x;
						pos.y = pos.y * tabData->size.y / refWall->size.y;
						pos += tabData->pos;
						QImage  tempImage(scaledSize, QImage::Format_ARGB32);
						tempImage.fill(TRANSPARENT);
						graph2D.drawImageScaled(&tempImage, CVec2(), exploGfx, scale);
						// assombrit l'explosion en fonction de sa distance
						static const float shadowLevels[] = {0.0f, 0.2f, 0.4f};
						float shadow = shadowLevels[WALL_TABLE_HEIGHT - 1 - tablePos.y];
						graph2D.darken(&tempImage, shadow);
						// dessine l'explosion à l'écran.
						graph2D.drawImage(image, pos, tempImage, 0, false, QRect(0, 33, MAINVIEW_WIDTH, MAINVIEW_HEIGHT));
					}
				}
			}
		}
				
				Quand on crée cette explosion, le champion est aussi ressuscité et récupère la moitié de sa santé de départ.
				
		void CWalls::update()
		{
			// animation de l'autel vi
			if (resurrectTimer.update() == true)
			{
				// retrouve le numéro du champion
				CObjectStack*   stack = map.findObjectsStack(resurrectWallPos, resurrectWallSide);
				int         last = stack->getSize() - 1;
				CObject&    bones = stack->getObject(last);
				int         champNum = bones.getIntParam("Champion");
				// efface l'objet
				stack->removeObject(last);
				resurrectWallSide = eWallSideMax;
				// ressuscite le champion
				CCharacter::SStat&  health = game.characters[champNum].stats[CCharacter::eStatHealth];
				health.value = health.startValue / 2;
				// lance l'explosion
				explosions.add(eExplo_Resurrect, player.pos, 20);
			}
		}
				
				Je n'ai pas regardé le code du jeu d'origine pour voir si d'autres stats du champion changeaient.
			
			
Régénération de vie
		#define HEALTH_REGEN_TIMER        (30 * 60)
		#define HEALTH_REGEN_TIMER_SLEEP  90