Add explosions improvements (#29)
This commit is contained in:
parent
3ccb087d20
commit
5170948588
|
@ -316,8 +316,32 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b
|
||||||
sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED);
|
sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED);
|
||||||
animationRegisterPlaySoundEffect(a1, sfx_name, a10);
|
animationRegisterPlaySoundEffect(a1, sfx_name, a10);
|
||||||
|
|
||||||
|
// SFALL
|
||||||
|
if (explosionEmitsLight()) {
|
||||||
|
// 0xFFFF0002:
|
||||||
|
// - distance: 2
|
||||||
|
// - intensity: 65535
|
||||||
|
//
|
||||||
|
// NOTE: Change intensity to 65536 (which is on par with
|
||||||
|
// `anim_set_check_light_fix` Sfall's hack).
|
||||||
|
animationRegisterSetLightIntensity(a1, 2, 65536, 0);
|
||||||
|
}
|
||||||
|
|
||||||
animationRegisterAnimate(a1, anim, 0);
|
animationRegisterAnimate(a1, anim, 0);
|
||||||
|
|
||||||
|
// SFALL
|
||||||
|
if (explosionEmitsLight()) {
|
||||||
|
// 0x00010000:
|
||||||
|
// - distance: 0
|
||||||
|
// - intensity: 1
|
||||||
|
//
|
||||||
|
// NOTE: Change intensity to 0. I guess using 1 was a
|
||||||
|
// workaround for `anim_set_check_light_fix` hack which
|
||||||
|
// requires two upper bytes to be non-zero to override
|
||||||
|
// default behaviour.
|
||||||
|
animationRegisterSetLightIntensity(a1, 0, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
int randomDistance = randomBetween(2, 5);
|
int randomDistance = randomBetween(2, 5);
|
||||||
int randomRotation = randomBetween(0, 5);
|
int randomRotation = randomBetween(0, 5);
|
||||||
|
|
||||||
|
@ -692,7 +716,8 @@ int _action_ranged(Attack* attack, int anim)
|
||||||
|
|
||||||
bool isGrenade = false;
|
bool isGrenade = false;
|
||||||
if (anim == ANIM_THROW_ANIM) {
|
if (anim == ANIM_THROW_ANIM) {
|
||||||
if (damageType == DAMAGE_TYPE_EXPLOSION || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
// SFALL
|
||||||
|
if (damageType == explosionGetDamageType() || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
||||||
isGrenade = true;
|
isGrenade = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -750,7 +775,12 @@ int _action_ranged(Attack* attack, int anim)
|
||||||
|
|
||||||
objectHide(projectile, NULL);
|
objectHide(projectile, NULL);
|
||||||
|
|
||||||
objectSetLight(projectile, 9, projectile->lightIntensity, NULL);
|
// SFALL
|
||||||
|
if (explosionEmitsLight() && projectile->lightIntensity == 0) {
|
||||||
|
objectSetLight(projectile, projectileProto->item.lightDistance, projectileProto->item.lightIntensity, NULL);
|
||||||
|
} else {
|
||||||
|
objectSetLight(projectile, 9, projectile->lightIntensity, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int projectileOrigin = _combat_bullet_start(attack->attacker, attack->defender);
|
int projectileOrigin = _combat_bullet_start(attack->attacker, attack->defender);
|
||||||
objectSetLocation(projectile, projectileOrigin, attack->attacker->elevation, NULL);
|
objectSetLocation(projectile, projectileOrigin, attack->attacker->elevation, NULL);
|
||||||
|
@ -774,7 +804,8 @@ int _action_ranged(Attack* attack, int anim)
|
||||||
v24 = attack->tile;
|
v24 = attack->tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGrenade || damageType == DAMAGE_TYPE_EXPLOSION) {
|
// SFALL
|
||||||
|
if (isGrenade || damageType == explosionGetDamageType()) {
|
||||||
if ((attack->attackerFlags & DAM_DROP) == 0) {
|
if ((attack->attackerFlags & DAM_DROP) == 0) {
|
||||||
int explosionFrmId;
|
int explosionFrmId;
|
||||||
if (isGrenade) {
|
if (isGrenade) {
|
||||||
|
@ -793,6 +824,12 @@ int _action_ranged(Attack* attack, int anim)
|
||||||
explosionFrmId = 10;
|
explosionFrmId = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SFALL
|
||||||
|
int explosionFrmIdOverride = explosionGetFrm();
|
||||||
|
if (explosionFrmIdOverride != -1) {
|
||||||
|
explosionFrmId = explosionFrmIdOverride;
|
||||||
|
}
|
||||||
|
|
||||||
if (isGrenade) {
|
if (isGrenade) {
|
||||||
animationRegisterSetFid(projectile, weaponFid, -1);
|
animationRegisterSetFid(projectile, weaponFid, -1);
|
||||||
}
|
}
|
||||||
|
@ -803,9 +840,23 @@ int _action_ranged(Attack* attack, int anim)
|
||||||
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, weapon, attack->hitMode, attack->defender);
|
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, weapon, attack->hitMode, attack->defender);
|
||||||
animationRegisterPlaySoundEffect(projectile, sfx, 0);
|
animationRegisterPlaySoundEffect(projectile, sfx, 0);
|
||||||
|
|
||||||
animationRegisterAnimateAndHide(projectile, ANIM_STAND, 0);
|
// SFALL
|
||||||
|
if (explosionEmitsLight()) {
|
||||||
|
animationRegisterAnimate(projectile, ANIM_STAND, 0);
|
||||||
|
// 0xFFFF0008
|
||||||
|
// - distance: 8
|
||||||
|
// - intensity: 65535
|
||||||
|
animationRegisterSetLightIntensity(projectile, 8, 65536, 0);
|
||||||
|
} else {
|
||||||
|
animationRegisterAnimateAndHide(projectile, ANIM_STAND, 0);
|
||||||
|
}
|
||||||
|
|
||||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
// SFALL
|
||||||
|
int startRotation;
|
||||||
|
int endRotation;
|
||||||
|
explosionGetPattern(&startRotation, &endRotation);
|
||||||
|
|
||||||
|
for (int rotation = startRotation; rotation < endRotation; rotation++) {
|
||||||
if (objectCreateWithFidPid(&(neighboors[rotation]), explosionFid, -1) != -1) {
|
if (objectCreateWithFidPid(&(neighboors[rotation]), explosionFid, -1) != -1) {
|
||||||
objectHide(neighboors[rotation], NULL);
|
objectHide(neighboors[rotation], NULL);
|
||||||
|
|
||||||
|
@ -864,7 +915,8 @@ int _action_ranged(Attack* attack, int anim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectile != NULL && (isGrenade || damageType == DAMAGE_TYPE_EXPLOSION)) {
|
// SFALL
|
||||||
|
if (projectile != NULL && (isGrenade || damageType == explosionGetDamageType())) {
|
||||||
animationRegisterHideObjectForced(projectile);
|
animationRegisterHideObjectForced(projectile);
|
||||||
} else if (anim == ANIM_THROW_ANIM && projectile != NULL) {
|
} else if (anim == ANIM_THROW_ANIM && projectile != NULL) {
|
||||||
animationRegisterSetFid(projectile, weaponFid, -1);
|
animationRegisterSetFid(projectile, weaponFid, -1);
|
||||||
|
|
|
@ -64,6 +64,10 @@ typedef enum AnimationKind {
|
||||||
ANIM_KIND_26 = 26,
|
ANIM_KIND_26 = 26,
|
||||||
ANIM_KIND_27 = 27,
|
ANIM_KIND_27 = 27,
|
||||||
ANIM_KIND_NOOP = 28,
|
ANIM_KIND_NOOP = 28,
|
||||||
|
|
||||||
|
// New animation to update both light distance and intensity. Required to
|
||||||
|
// impement Sfall's explosion light effects without resorting to hackery.
|
||||||
|
ANIM_KIND_SET_LIGHT_INTENSITY,
|
||||||
} AnimationKind;
|
} AnimationKind;
|
||||||
|
|
||||||
typedef enum AnimationSequenceFlags {
|
typedef enum AnimationSequenceFlags {
|
||||||
|
@ -197,6 +201,9 @@ typedef struct AnimationDescription {
|
||||||
|
|
||||||
// ANIM_KIND_CALLBACK3
|
// ANIM_KIND_CALLBACK3
|
||||||
void* param3;
|
void* param3;
|
||||||
|
|
||||||
|
// ANIM_KIND_SET_LIGHT_INTENSITY
|
||||||
|
int lightIntensity;
|
||||||
};
|
};
|
||||||
CacheEntry* artCacheKey;
|
CacheEntry* artCacheKey;
|
||||||
} AnimationDescription;
|
} AnimationDescription;
|
||||||
|
@ -1527,6 +1534,11 @@ static int animationRunSequence(int animationSequenceIndex)
|
||||||
tileWindowRefreshRect(&rect, animationDescription->owner->elevation);
|
tileWindowRefreshRect(&rect, animationDescription->owner->elevation);
|
||||||
rc = _anim_set_continue(animationSequenceIndex, 0);
|
rc = _anim_set_continue(animationSequenceIndex, 0);
|
||||||
break;
|
break;
|
||||||
|
case ANIM_KIND_SET_LIGHT_INTENSITY:
|
||||||
|
objectSetLight(animationDescription->owner, animationDescription->lightDistance, animationDescription->lightIntensity, &rect);
|
||||||
|
tileWindowRefreshRect(&rect, animationDescription->owner->elevation);
|
||||||
|
rc = _anim_set_continue(animationSequenceIndex, 0);
|
||||||
|
break;
|
||||||
case ANIM_KIND_20:
|
case ANIM_KIND_20:
|
||||||
rc = _anim_move_on_stairs(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex);
|
rc = _anim_move_on_stairs(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex);
|
||||||
break;
|
break;
|
||||||
|
@ -3330,3 +3342,24 @@ static unsigned int animationComputeTicksPerFrame(Object* object, int fid)
|
||||||
|
|
||||||
return 1000 / fps;
|
return 1000 / fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int animationRegisterSetLightIntensity(Object* owner, int lightDistance, int lightIntensity, int delay)
|
||||||
|
{
|
||||||
|
if (_check_registry(owner) == -1) {
|
||||||
|
_anim_cleanup();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]);
|
||||||
|
AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]);
|
||||||
|
animationDescription->kind = ANIM_KIND_SET_LIGHT_INTENSITY;
|
||||||
|
animationDescription->artCacheKey = NULL;
|
||||||
|
animationDescription->owner = owner;
|
||||||
|
animationDescription->lightDistance = lightDistance;
|
||||||
|
animationDescription->lightIntensity = lightIntensity;
|
||||||
|
animationDescription->delay = delay;
|
||||||
|
|
||||||
|
gAnimationDescriptionCurrentIndex++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -154,4 +154,6 @@ void _dude_stand(Object* obj, int rotation, int fid);
|
||||||
void _dude_standup(Object* a1);
|
void _dude_standup(Object* a1);
|
||||||
void animationStop();
|
void animationStop();
|
||||||
|
|
||||||
|
int animationRegisterSetLightIntensity(Object* owner, int lightDistance, int lightIntensity, int delay);
|
||||||
|
|
||||||
#endif /* ANIMATION_H */
|
#endif /* ANIMATION_H */
|
||||||
|
|
|
@ -3430,6 +3430,9 @@ int _combat_attack(Object* a1, Object* a2, int hitMode, int hitLocation)
|
||||||
_critter_set_who_hit_me(a1, a2);
|
_critter_set_who_hit_me(a1, a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SFALL
|
||||||
|
explosionSettingsReset();
|
||||||
|
|
||||||
_combat_call_display = 1;
|
_combat_call_display = 1;
|
||||||
_combat_cleanup_enabled = 1;
|
_combat_cleanup_enabled = 1;
|
||||||
aiInfoSetLastTarget(a1, a2);
|
aiInfoSetLastTarget(a1, a2);
|
||||||
|
@ -3707,7 +3710,8 @@ static int attackCompute(Attack* attack)
|
||||||
|
|
||||||
bool isGrenade = false;
|
bool isGrenade = false;
|
||||||
int damageType = weaponGetDamageType(attack->attacker, attack->weapon);
|
int damageType = weaponGetDamageType(attack->attacker, attack->weapon);
|
||||||
if (anim == ANIM_THROW_ANIM && (damageType == DAMAGE_TYPE_EXPLOSION || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP)) {
|
// SFALL
|
||||||
|
if (anim == ANIM_THROW_ANIM && (damageType == explosionGetDamageType() || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP)) {
|
||||||
isGrenade = true;
|
isGrenade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3835,7 +3839,8 @@ static int attackCompute(Attack* attack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((damageType == DAMAGE_TYPE_EXPLOSION || isGrenade) && ((attack->attackerFlags & DAM_HIT) != 0 || (attack->attackerFlags & DAM_CRITICAL) == 0)) {
|
// SFALL
|
||||||
|
if ((damageType == explosionGetDamageType() || isGrenade) && ((attack->attackerFlags & DAM_HIT) != 0 || (attack->attackerFlags & DAM_CRITICAL) == 0)) {
|
||||||
_compute_explosion_on_extras(attack, 0, isGrenade, 0);
|
_compute_explosion_on_extras(attack, 0, isGrenade, 0);
|
||||||
} else {
|
} else {
|
||||||
if ((attack->attackerFlags & DAM_EXPLODE) != 0) {
|
if ((attack->attackerFlags & DAM_EXPLODE) != 0) {
|
||||||
|
@ -3882,7 +3887,10 @@ void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4
|
||||||
int rotation = 0;
|
int rotation = 0;
|
||||||
int v5 = -1;
|
int v5 = -1;
|
||||||
int v19 = tile;
|
int v19 = tile;
|
||||||
while (attack->extrasLength < 6) {
|
|
||||||
|
// SFALL
|
||||||
|
int maxTargets = explosionGetMaxTargets();
|
||||||
|
while (attack->extrasLength < maxTargets) {
|
||||||
if (v22 != 0 && (v5 == -1 || (v5 = tileGetTileInDirection(v5, rotation, 1)) != v19)) {
|
if (v22 != 0 && (v5 == -1 || (v5 = tileGetTileInDirection(v5, rotation, 1)) != v19)) {
|
||||||
v20++;
|
v20++;
|
||||||
if (v20 % v22 == 0) {
|
if (v20 % v22 == 0) {
|
||||||
|
|
|
@ -1399,7 +1399,10 @@ char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* ta
|
||||||
v6 = 1;
|
v6 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectTypeCode != 'H' || target == NULL || weaponIsGrenade(weapon)) {
|
int damageType = weaponGetDamageType(NULL, weapon);
|
||||||
|
|
||||||
|
// SFALL
|
||||||
|
if (effectTypeCode != 'H' || target == NULL || damageType == explosionGetDamageType() || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) {
|
||||||
materialCode = 'X';
|
materialCode = 'X';
|
||||||
} else {
|
} else {
|
||||||
const int type = FID_TYPE(target->fid);
|
const int type = FID_TYPE(target->fid);
|
||||||
|
|
|
@ -3277,7 +3277,7 @@ static void inventoryWindowOpenContextMenu(int keyCode, int inventoryWindowType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (item->pid == PROTO_ID_DYNAMITE_II || item->pid == PROTO_ID_PLASTIC_EXPLOSIVES_II) {
|
} else if (explosiveIsActiveExplosive(item->pid)) {
|
||||||
_dropped_explosive = 1;
|
_dropped_explosive = 1;
|
||||||
_obj_drop(v41, item);
|
_obj_drop(v41, item);
|
||||||
} else {
|
} else {
|
||||||
|
|
263
src/item.cc
263
src/item.cc
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define ADDICTION_COUNT (9)
|
#define ADDICTION_COUNT (9)
|
||||||
|
@ -62,6 +63,10 @@ static void booksInitCustom();
|
||||||
static void booksAdd(int bookPid, int messageId, int skill);
|
static void booksAdd(int bookPid, int messageId, int skill);
|
||||||
static void booksExit();
|
static void booksExit();
|
||||||
|
|
||||||
|
static void explosionsInit();
|
||||||
|
static void explosionsReset();
|
||||||
|
static void explosionsExit();
|
||||||
|
|
||||||
typedef struct DrugDescription {
|
typedef struct DrugDescription {
|
||||||
int drugPid;
|
int drugPid;
|
||||||
int gvar;
|
int gvar;
|
||||||
|
@ -74,6 +79,13 @@ typedef struct BookDescription {
|
||||||
int skill;
|
int skill;
|
||||||
} BookDescription;
|
} BookDescription;
|
||||||
|
|
||||||
|
typedef struct ExplosiveDescription {
|
||||||
|
int pid;
|
||||||
|
int activePid;
|
||||||
|
int minDamage;
|
||||||
|
int maxDamage;
|
||||||
|
} ExplosiveDescription;
|
||||||
|
|
||||||
// 0x509FFC
|
// 0x509FFC
|
||||||
static char _aItem_1[] = "<item>";
|
static char _aItem_1[] = "<item>";
|
||||||
|
|
||||||
|
@ -153,6 +165,20 @@ static Object* _wd_obj;
|
||||||
static int _wd_gvar;
|
static int _wd_gvar;
|
||||||
|
|
||||||
static std::vector<BookDescription> gBooks;
|
static std::vector<BookDescription> gBooks;
|
||||||
|
static bool gExplosionEmitsLight;
|
||||||
|
static int gGrenadeExplosionRadius;
|
||||||
|
static int gRocketExplosionRadius;
|
||||||
|
static int gDynamiteMinDamage;
|
||||||
|
static int gDynamiteMaxDamage;
|
||||||
|
static int gPlasticExplosiveMinDamage;
|
||||||
|
static int gPlasticExplosiveMaxDamage;
|
||||||
|
static std::vector<ExplosiveDescription> gExplosives;
|
||||||
|
static int gExplosionStartRotation;
|
||||||
|
static int gExplosionEndRotation;
|
||||||
|
static int gExplosionFrm;
|
||||||
|
static int gExplosionRadius;
|
||||||
|
static int gExplosionDamageType;
|
||||||
|
static int gExplosionMaxTargets;
|
||||||
|
|
||||||
// 0x4770E0
|
// 0x4770E0
|
||||||
int itemsInit()
|
int itemsInit()
|
||||||
|
@ -170,6 +196,7 @@ int itemsInit()
|
||||||
|
|
||||||
// SFALL
|
// SFALL
|
||||||
booksInit();
|
booksInit();
|
||||||
|
explosionsInit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +204,8 @@ int itemsInit()
|
||||||
// 0x477144
|
// 0x477144
|
||||||
void itemsReset()
|
void itemsReset()
|
||||||
{
|
{
|
||||||
return;
|
// SFALL
|
||||||
|
explosionsReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x477148
|
// 0x477148
|
||||||
|
@ -187,6 +215,7 @@ void itemsExit()
|
||||||
|
|
||||||
// SFALL
|
// SFALL
|
||||||
booksExit();
|
booksExit();
|
||||||
|
explosionsExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Collapsed.
|
// NOTE: Collapsed.
|
||||||
|
@ -2002,13 +2031,23 @@ int _item_w_area_damage_radius(Object* weapon, int hitMode)
|
||||||
// 0x479180
|
// 0x479180
|
||||||
int _item_w_grenade_dmg_radius(Object* weapon)
|
int _item_w_grenade_dmg_radius(Object* weapon)
|
||||||
{
|
{
|
||||||
return 2;
|
// SFALL
|
||||||
|
if (gExplosionRadius != -1) {
|
||||||
|
return gExplosionRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gGrenadeExplosionRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x479188
|
// 0x479188
|
||||||
int _item_w_rocket_dmg_radius(Object* weapon)
|
int _item_w_rocket_dmg_radius(Object* weapon)
|
||||||
{
|
{
|
||||||
return 3;
|
// SFALL
|
||||||
|
if (gExplosionRadius != -1) {
|
||||||
|
return gExplosionRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gRocketExplosionRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x479190
|
// 0x479190
|
||||||
|
@ -3353,3 +3392,221 @@ bool booksGetInfo(int bookPid, int* messageIdPtr, int* skillPtr)
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void explosionsInit()
|
||||||
|
{
|
||||||
|
gExplosionEmitsLight = false;
|
||||||
|
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_EXPLOSION_EMITS_LIGHT_KEY, &gExplosionEmitsLight);
|
||||||
|
|
||||||
|
explosionsReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void explosionsReset()
|
||||||
|
{
|
||||||
|
gGrenadeExplosionRadius = 2;
|
||||||
|
gRocketExplosionRadius = 3;
|
||||||
|
|
||||||
|
gDynamiteMinDamage = 30;
|
||||||
|
gDynamiteMaxDamage = 50;
|
||||||
|
gPlasticExplosiveMinDamage = 40;
|
||||||
|
gPlasticExplosiveMaxDamage = 80;
|
||||||
|
|
||||||
|
if (configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DYNAMITE_MAX_DAMAGE_KEY, &gDynamiteMaxDamage)) {
|
||||||
|
gDynamiteMaxDamage = std::clamp(gDynamiteMaxDamage, 0, 9999);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DYNAMITE_MIN_DAMAGE_KEY, &gDynamiteMinDamage)) {
|
||||||
|
gDynamiteMinDamage = std::clamp(gDynamiteMinDamage, 0, gDynamiteMaxDamage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PLASTIC_EXPLOSIVE_MAX_DAMAGE_KEY, &gPlasticExplosiveMaxDamage)) {
|
||||||
|
gPlasticExplosiveMaxDamage = std::clamp(gPlasticExplosiveMaxDamage, 0, 9999);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PLASTIC_EXPLOSIVE_MIN_DAMAGE_KEY, &gPlasticExplosiveMinDamage)) {
|
||||||
|
gPlasticExplosiveMinDamage = std::clamp(gPlasticExplosiveMinDamage, 0, gPlasticExplosiveMaxDamage);
|
||||||
|
}
|
||||||
|
|
||||||
|
gExplosives.clear();
|
||||||
|
|
||||||
|
explosionSettingsReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void explosionsExit()
|
||||||
|
{
|
||||||
|
gExplosives.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool explosionEmitsLight()
|
||||||
|
{
|
||||||
|
return gExplosionEmitsLight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void weaponSetGrenadeExplosionRadius(int value)
|
||||||
|
{
|
||||||
|
gGrenadeExplosionRadius = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void weaponSetRocketExplosionRadius(int value)
|
||||||
|
{
|
||||||
|
gRocketExplosionRadius = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosiveAdd(int pid, int activePid, int minDamage, int maxDamage)
|
||||||
|
{
|
||||||
|
ExplosiveDescription explosiveDescription;
|
||||||
|
explosiveDescription.pid = pid;
|
||||||
|
explosiveDescription.activePid = activePid;
|
||||||
|
explosiveDescription.minDamage = minDamage;
|
||||||
|
explosiveDescription.maxDamage = maxDamage;
|
||||||
|
gExplosives.push_back(std::move(explosiveDescription));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool explosiveIsExplosive(int pid)
|
||||||
|
{
|
||||||
|
if (pid == PROTO_ID_DYNAMITE_I) return true;
|
||||||
|
if (pid == PROTO_ID_PLASTIC_EXPLOSIVES_I) return true;
|
||||||
|
|
||||||
|
for (const auto& explosive : gExplosives) {
|
||||||
|
if (explosive.pid == pid) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool explosiveIsActiveExplosive(int pid)
|
||||||
|
{
|
||||||
|
if (pid == PROTO_ID_DYNAMITE_II) return true;
|
||||||
|
if (pid == PROTO_ID_PLASTIC_EXPLOSIVES_II) return true;
|
||||||
|
|
||||||
|
for (const auto& explosive : gExplosives) {
|
||||||
|
if (explosive.activePid == pid) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool explosiveActivate(int* pidPtr)
|
||||||
|
{
|
||||||
|
if (*pidPtr == PROTO_ID_DYNAMITE_I) {
|
||||||
|
*pidPtr = PROTO_ID_DYNAMITE_II;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pidPtr == PROTO_ID_PLASTIC_EXPLOSIVES_I) {
|
||||||
|
*pidPtr = PROTO_ID_PLASTIC_EXPLOSIVES_II;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& explosive : gExplosives) {
|
||||||
|
if (explosive.pid == *pidPtr) {
|
||||||
|
*pidPtr = explosive.activePid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool explosiveSetDamage(int pid, int minDamage, int maxDamage)
|
||||||
|
{
|
||||||
|
if (pid == PROTO_ID_DYNAMITE_I) {
|
||||||
|
gDynamiteMinDamage = minDamage;
|
||||||
|
gDynamiteMaxDamage = maxDamage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == PROTO_ID_PLASTIC_EXPLOSIVES_I) {
|
||||||
|
gPlasticExplosiveMinDamage = minDamage;
|
||||||
|
gPlasticExplosiveMaxDamage = maxDamage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: For unknown reason this function do not update custom explosives
|
||||||
|
// damage. Since we're after compatibility (at least at this time), the
|
||||||
|
// only way to follow this behaviour.
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool explosiveGetDamage(int pid, int* minDamagePtr, int* maxDamagePtr)
|
||||||
|
{
|
||||||
|
if (pid == PROTO_ID_DYNAMITE_I) {
|
||||||
|
*minDamagePtr = gDynamiteMinDamage;
|
||||||
|
*maxDamagePtr = gDynamiteMaxDamage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == PROTO_ID_PLASTIC_EXPLOSIVES_I) {
|
||||||
|
*minDamagePtr = gPlasticExplosiveMinDamage;
|
||||||
|
*maxDamagePtr = gPlasticExplosiveMaxDamage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& explosive : gExplosives) {
|
||||||
|
if (explosive.pid == pid) {
|
||||||
|
*minDamagePtr = explosive.minDamage;
|
||||||
|
*maxDamagePtr = explosive.maxDamage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionSettingsReset()
|
||||||
|
{
|
||||||
|
gExplosionStartRotation = 0;
|
||||||
|
gExplosionEndRotation = ROTATION_COUNT;
|
||||||
|
gExplosionFrm = -1;
|
||||||
|
gExplosionRadius = -1;
|
||||||
|
gExplosionDamageType = DAMAGE_TYPE_EXPLOSION;
|
||||||
|
gExplosionMaxTargets = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionGetPattern(int* startRotationPtr, int* endRotationPtr)
|
||||||
|
{
|
||||||
|
*startRotationPtr = gExplosionStartRotation;
|
||||||
|
*endRotationPtr = gExplosionEndRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionSetPattern(int startRotation, int endRotation)
|
||||||
|
{
|
||||||
|
gExplosionStartRotation = startRotation;
|
||||||
|
gExplosionEndRotation = endRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
int explosionGetFrm()
|
||||||
|
{
|
||||||
|
return gExplosionFrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionSetFrm(int frm)
|
||||||
|
{
|
||||||
|
gExplosionFrm = frm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionSetRadius(int radius)
|
||||||
|
{
|
||||||
|
gExplosionRadius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
int explosionGetDamageType()
|
||||||
|
{
|
||||||
|
return gExplosionDamageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionSetDamageType(int damageType)
|
||||||
|
{
|
||||||
|
gExplosionDamageType = damageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int explosionGetMaxTargets()
|
||||||
|
{
|
||||||
|
return gExplosionMaxTargets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void explosionSetMaxTargets(int maxTargets)
|
||||||
|
{
|
||||||
|
gExplosionMaxTargets = maxTargets;
|
||||||
|
}
|
||||||
|
|
19
src/item.h
19
src/item.h
|
@ -124,5 +124,24 @@ int itemGetMoney(Object* obj);
|
||||||
int itemSetMoney(Object* obj, int a2);
|
int itemSetMoney(Object* obj, int a2);
|
||||||
|
|
||||||
bool booksGetInfo(int bookPid, int* messageIdPtr, int* skillPtr);
|
bool booksGetInfo(int bookPid, int* messageIdPtr, int* skillPtr);
|
||||||
|
bool explosionEmitsLight();
|
||||||
|
void weaponSetGrenadeExplosionRadius(int value);
|
||||||
|
void weaponSetRocketExplosionRadius(int value);
|
||||||
|
void explosiveAdd(int pid, int activePid, int minDamage, int maxDamage);
|
||||||
|
bool explosiveIsExplosive(int pid);
|
||||||
|
bool explosiveIsActiveExplosive(int pid);
|
||||||
|
bool explosiveActivate(int* pidPtr);
|
||||||
|
bool explosiveSetDamage(int pid, int minDamage, int maxDamage);
|
||||||
|
bool explosiveGetDamage(int pid, int* minDamagePtr, int* maxDamagePtr);
|
||||||
|
void explosionSettingsReset();
|
||||||
|
void explosionGetPattern(int* startRotationPtr, int* endRotationPtr);
|
||||||
|
void explosionSetPattern(int startRotation, int endRotation);
|
||||||
|
int explosionGetFrm();
|
||||||
|
void explosionSetFrm(int frm);
|
||||||
|
void explosionSetRadius(int radius);
|
||||||
|
int explosionGetDamageType();
|
||||||
|
void explosionSetDamageType(int damageType);
|
||||||
|
int explosionGetMaxTargets();
|
||||||
|
void explosionSetMaxTargets(int maxTargets);
|
||||||
|
|
||||||
#endif /* ITEM_H */
|
#endif /* ITEM_H */
|
||||||
|
|
|
@ -2090,7 +2090,8 @@ int _obj_inven_free(Inventory* inventory)
|
||||||
bool _obj_action_can_use(Object* obj)
|
bool _obj_action_can_use(Object* obj)
|
||||||
{
|
{
|
||||||
int pid = obj->pid;
|
int pid = obj->pid;
|
||||||
if (pid != PROTO_ID_LIT_FLARE && pid != PROTO_ID_DYNAMITE_II && pid != PROTO_ID_PLASTIC_EXPLOSIVES_II) {
|
// SFALL
|
||||||
|
if (pid != PROTO_ID_LIT_FLARE && !explosiveIsActiveExplosive(pid)) {
|
||||||
return _proto_action_can_use(pid);
|
return _proto_action_can_use(pid);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -843,10 +843,8 @@ static int _obj_use_explosive(Object* explosive)
|
||||||
MessageListItem messageListItem;
|
MessageListItem messageListItem;
|
||||||
|
|
||||||
int pid = explosive->pid;
|
int pid = explosive->pid;
|
||||||
if (pid != PROTO_ID_DYNAMITE_I
|
// SFALL
|
||||||
&& pid != PROTO_ID_PLASTIC_EXPLOSIVES_I
|
if (!explosiveIsExplosive(pid)) {
|
||||||
&& pid != PROTO_ID_DYNAMITE_II
|
|
||||||
&& pid != PROTO_ID_PLASTIC_EXPLOSIVES_II) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,11 +863,8 @@ static int _obj_use_explosive(Object* explosive)
|
||||||
displayMonitorAddMessage(messageListItem.text);
|
displayMonitorAddMessage(messageListItem.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == PROTO_ID_DYNAMITE_I) {
|
// SFALL
|
||||||
explosive->pid = PROTO_ID_DYNAMITE_II;
|
explosiveActivate(&(explosive->pid));
|
||||||
} else if (pid == PROTO_ID_PLASTIC_EXPLOSIVES_I) {
|
|
||||||
explosive->pid = PROTO_ID_PLASTIC_EXPLOSIVES_II;
|
|
||||||
}
|
|
||||||
|
|
||||||
int delay = 10 * seconds;
|
int delay = 10 * seconds;
|
||||||
|
|
||||||
|
@ -1048,7 +1043,8 @@ int _protinst_use_item(Object* critter, Object* item)
|
||||||
// 0x49BFE8
|
// 0x49BFE8
|
||||||
static int _protinstTestDroppedExplosive(Object* a1)
|
static int _protinstTestDroppedExplosive(Object* a1)
|
||||||
{
|
{
|
||||||
if (a1->pid == PROTO_ID_DYNAMITE_II || a1->pid == PROTO_ID_PLASTIC_EXPLOSIVES_II) {
|
// SFALL
|
||||||
|
if (explosiveIsActiveExplosive(a1->pid)) {
|
||||||
Attack attack;
|
Attack attack;
|
||||||
attackInit(&attack, gDude, 0, HIT_MODE_PUNCH, HIT_LOCATION_TORSO);
|
attackInit(&attack, gDude, 0, HIT_MODE_PUNCH, HIT_LOCATION_TORSO);
|
||||||
attack.attackerFlags = DAM_HIT;
|
attack.attackerFlags = DAM_HIT;
|
||||||
|
|
12
src/queue.cc
12
src/queue.cc
|
@ -478,15 +478,9 @@ static int _queue_do_explosion_(Object* explosive, bool a2)
|
||||||
|
|
||||||
int maxDamage;
|
int maxDamage;
|
||||||
int minDamage;
|
int minDamage;
|
||||||
if (explosive->pid == PROTO_ID_DYNAMITE_I || explosive->pid == PROTO_ID_DYNAMITE_II) {
|
|
||||||
// Dynamite
|
// SFALL
|
||||||
minDamage = 30;
|
explosiveGetDamage(explosive->pid, &minDamage, &maxDamage);
|
||||||
maxDamage = 50;
|
|
||||||
} else {
|
|
||||||
// Plastic explosive
|
|
||||||
minDamage = 40;
|
|
||||||
maxDamage = 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: I guess this is a little bit wrong, dude can never be null, I
|
// FIXME: I guess this is a little bit wrong, dude can never be null, I
|
||||||
// guess it needs to check if owner is dude.
|
// guess it needs to check if owner is dude.
|
||||||
|
|
|
@ -35,6 +35,11 @@
|
||||||
#define SFALL_CONFIG_BURST_MOD_CENTER_DIVISOR_KEY "ComputeSpray_CenterDiv"
|
#define SFALL_CONFIG_BURST_MOD_CENTER_DIVISOR_KEY "ComputeSpray_CenterDiv"
|
||||||
#define SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY "ComputeSpray_TargetMult"
|
#define SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY "ComputeSpray_TargetMult"
|
||||||
#define SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY "ComputeSpray_TargetDiv"
|
#define SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY "ComputeSpray_TargetDiv"
|
||||||
|
#define SFALL_CONFIG_DYNAMITE_MIN_DAMAGE_KEY "Dynamite_DmgMin"
|
||||||
|
#define SFALL_CONFIG_DYNAMITE_MAX_DAMAGE_KEY "Dynamite_DmgMax"
|
||||||
|
#define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MIN_DAMAGE_KEY "PlasticExplosive_DmgMin"
|
||||||
|
#define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MAX_DAMAGE_KEY "PlasticExplosive_DmgMax"
|
||||||
|
#define SFALL_CONFIG_EXPLOSION_EMITS_LIGHT_KEY "ExplosionsEmitLight"
|
||||||
|
|
||||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
||||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
||||||
|
|
Loading…
Reference in New Issue