Add explosions improvements (#29)

This commit is contained in:
Alexander Batalov 2022-08-05 17:43:00 +03:00
parent 3ccb087d20
commit 5170948588
12 changed files with 404 additions and 34 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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) {

View File

@ -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);

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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