/** * @brief Deals damage and causes wounds. * @param[in,out] target Pointer to the actor we want to damage. * @param[in] damage The value of the damage. * @param[in] impact Impact location @c nullptr for splash damage. */ void G_DamageActor (Edict* target, const int damage, const vec3_t impact) { assert(target->chr.teamDef); G_TakeDamage(target, damage); if (damage > 0 && target->HP > 0) { const teamDef_t* const teamDef = target->chr.teamDef; if (impact) { /* Direct hit */ const byte impactDirection = G_GetImpactDirection(target, impact); const float impactHeight = impact[2] / (target->absBox.mins[2] + target->absBox.maxs[2]); const int bodyPart = teamDef->bodyTemplate->getHitBodyPart(impactDirection, impactHeight); target->chr.wounds.woundLevel[bodyPart] += damage; } else { /* No direct hit (splash damage) */ for (int bodyPart = 0; bodyPart < teamDef->bodyTemplate->numBodyParts(); ++bodyPart) target->chr.wounds.woundLevel[bodyPart] += teamDef->bodyTemplate->getArea(bodyPart) * damage; } #if 0 if (!CHRSH_IsTeamDefRobot(target->chr.teamDef)) /* Knockback -- currently disabled, not planned in the specs, also there's no way to tell stunned and dead actors apart */ target->STUN = std::min(255.0f, target->STUN + std::max(0.0f, damage * crand() * 0.25f)); #endif G_SendWoundStats(target); } }
/** * @brief Write player stats to network buffer * @sa G_SendStats */ void G_SendPlayerStats (const Player& player) { Edict* ent = nullptr; while ((ent = G_EdictsGetNextActor(ent))) if (ent->team == player.getTeam()) { G_EventActorStats(*ent, G_PlayerToPM(player)); G_SendWoundStats(ent); } }
/** * @brief Heals a target and treats wounds. * @param[in,out] target Pointer to the actor who we want to treat. * @param[in] fd Pointer to the firedef used to heal the target. * @param[in] heal The value of the damage to heal. * @param[in] healerTeam The index of the team of the healer. */ void G_TreatActor (Actor* target, const fireDef_t* const fd, const int heal, const int healerTeam) { assert(target->chr.teamDef); /* Treat wounds */ if (fd->dmgweight == gi.csi->damNormal) { int mostWounded = 0; woundInfo_t* wounds = &target->chr.wounds; /* Find the worst not treated wound */ for (int bodyPart = 0; bodyPart < target->chr.teamDef->bodyTemplate->numBodyParts(); ++bodyPart) if (wounds->woundLevel[bodyPart] > wounds->woundLevel[mostWounded]) mostWounded = bodyPart; if (wounds->woundLevel[mostWounded] > 0) { const int woundsHealed = std::min(static_cast<int>(abs(heal) / target->chr.teamDef->bodyTemplate->bleedingFactor(mostWounded)), wounds->woundLevel[mostWounded]); G_TakeDamage(target, heal); wounds->woundLevel[mostWounded] -= woundsHealed; wounds->treatmentLevel[mostWounded] += woundsHealed; /* Update stats here to get info on how many HP the target received. */ if (target->chr.scoreMission) target->chr.scoreMission->heal += abs(heal); } } /* Treat stunned actors */ if (fd->dmgweight == gi.csi->damStunElectro && target->isStunned()) { if (CHRSH_IsTeamDefAlien(target->chr.teamDef) && target->getTeam() != healerTeam) /** @todo According to specs it should only be possible to use the medikit to keep an alien sedated when * 'live alien' is researched, is it possible to find if a tech is researched here? */ target->setStun(std::min(255, target->getStun() - heal)); else target->setStun(std::max(0, target->getStun() + heal)); G_ActorCheckRevitalise(target); } /* Increase morale */ if (fd->dmgweight == gi.csi->damShock) target->setMorale(std::min(GET_MORALE(target->chr.score.skills[ABILITY_MIND]), target->morale - heal)); G_SendWoundStats(target); }