Improve code readability (#315)
This commit is contained in:
parent
c4c2806071
commit
ffe90eef49
|
@ -1711,6 +1711,7 @@ int _make_path(Object* object, int from, int to, unsigned char* rotations, int a
|
|||
return pathfinderFindPath(object, from, to, rotations, a5, _obj_blocking_at);
|
||||
}
|
||||
|
||||
// TODO: move pathfinding into another unit
|
||||
// 0x415EFC
|
||||
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback)
|
||||
{
|
||||
|
@ -1939,18 +1940,18 @@ static int _tile_idistance(int tile1, int tile2)
|
|||
}
|
||||
|
||||
// 0x4163AC
|
||||
int _make_straight_path(Object* a1, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6)
|
||||
int _make_straight_path(Object* obj, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6)
|
||||
{
|
||||
return _make_straight_path_func(a1, from, to, straightPathNodeList, obstaclePtr, a6, _obj_blocking_at);
|
||||
return _make_straight_path_func(obj, from, to, straightPathNodeList, obstaclePtr, a6, _obj_blocking_at);
|
||||
}
|
||||
|
||||
// TODO: Rather complex, but understandable, needs testing.
|
||||
//
|
||||
// 0x4163C8
|
||||
int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6, PathBuilderCallback* callback)
|
||||
int _make_straight_path_func(Object* obj, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6, PathBuilderCallback* callback)
|
||||
{
|
||||
if (obstaclePtr != NULL) {
|
||||
Object* obstacle = callback(a1, from, a1->elevation);
|
||||
Object* obstacle = callback(obj, from, obj->elevation);
|
||||
if (obstacle != NULL) {
|
||||
if (obstacle != *obstaclePtr && (a6 != 32 || (obstacle->flags & OBJECT_SHOOT_THRU) == 0)) {
|
||||
*obstaclePtr = obstacle;
|
||||
|
@ -1961,13 +1962,13 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
|
||||
int fromX;
|
||||
int fromY;
|
||||
tileToScreenXY(from, &fromX, &fromY, a1->elevation);
|
||||
tileToScreenXY(from, &fromX, &fromY, obj->elevation);
|
||||
fromX += 16;
|
||||
fromY += 8;
|
||||
|
||||
int toX;
|
||||
int toY;
|
||||
tileToScreenXY(to, &toX, &toY, a1->elevation);
|
||||
tileToScreenXY(to, &toX, &toY, obj->elevation);
|
||||
toX += 16;
|
||||
toY += 8;
|
||||
|
||||
|
@ -2005,7 +2006,7 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
if (ddx <= ddy) {
|
||||
int middle = ddx - ddy / 2;
|
||||
while (true) {
|
||||
tile = tileFromScreenXY(tileX, tileY, a1->elevation);
|
||||
tile = tileFromScreenXY(tileX, tileY, obj->elevation);
|
||||
|
||||
v22 += 1;
|
||||
if (v22 == a6) {
|
||||
|
@ -2016,9 +2017,9 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
if (straightPathNodeList != NULL) {
|
||||
StraightPathNode* pathNode = &(straightPathNodeList[pathNodeIndex]);
|
||||
pathNode->tile = tile;
|
||||
pathNode->elevation = a1->elevation;
|
||||
pathNode->elevation = obj->elevation;
|
||||
|
||||
tileToScreenXY(tile, &fromX, &fromY, a1->elevation);
|
||||
tileToScreenXY(tile, &fromX, &fromY, obj->elevation);
|
||||
pathNode->x = tileX - fromX - 16;
|
||||
pathNode->y = tileY - fromY - 8;
|
||||
}
|
||||
|
@ -2044,10 +2045,10 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
|
||||
if (tile != prevTile) {
|
||||
if (obstaclePtr != NULL) {
|
||||
Object* obj = callback(a1, tile, a1->elevation);
|
||||
if (obj != NULL) {
|
||||
if (obj != *obstaclePtr && (a6 != 32 || (obj->flags & OBJECT_SHOOT_THRU) == 0)) {
|
||||
*obstaclePtr = obj;
|
||||
Object* obstacle = callback(obj, tile, obj->elevation);
|
||||
if (obstacle != NULL) {
|
||||
if (obstacle != *obstaclePtr && (a6 != 32 || (obstacle->flags & OBJECT_SHOOT_THRU) == 0)) {
|
||||
*obstaclePtr = obstacle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2058,7 +2059,7 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
} else {
|
||||
int middle = ddy - ddx / 2;
|
||||
while (true) {
|
||||
tile = tileFromScreenXY(tileX, tileY, a1->elevation);
|
||||
tile = tileFromScreenXY(tileX, tileY, obj->elevation);
|
||||
|
||||
v22 += 1;
|
||||
if (v22 == a6) {
|
||||
|
@ -2069,9 +2070,9 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
if (straightPathNodeList != NULL) {
|
||||
StraightPathNode* pathNode = &(straightPathNodeList[pathNodeIndex]);
|
||||
pathNode->tile = tile;
|
||||
pathNode->elevation = a1->elevation;
|
||||
pathNode->elevation = obj->elevation;
|
||||
|
||||
tileToScreenXY(tile, &fromX, &fromY, a1->elevation);
|
||||
tileToScreenXY(tile, &fromX, &fromY, obj->elevation);
|
||||
pathNode->x = tileX - fromX - 16;
|
||||
pathNode->y = tileY - fromY - 8;
|
||||
}
|
||||
|
@ -2097,10 +2098,10 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
|
||||
if (tile != prevTile) {
|
||||
if (obstaclePtr != NULL) {
|
||||
Object* obj = callback(a1, tile, a1->elevation);
|
||||
if (obj != NULL) {
|
||||
if (obj != *obstaclePtr && (a6 != 32 || (obj->flags & OBJECT_SHOOT_THRU) == 0)) {
|
||||
*obstaclePtr = obj;
|
||||
Object* obstacle = callback(obj, tile, obj->elevation);
|
||||
if (obstacle != NULL) {
|
||||
if (obstacle != *obstaclePtr && (a6 != 32 || (obstacle->flags & OBJECT_SHOOT_THRU) == 0)) {
|
||||
*obstaclePtr = obstacle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2118,9 +2119,9 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
if (straightPathNodeList != NULL) {
|
||||
StraightPathNode* pathNode = &(straightPathNodeList[pathNodeIndex]);
|
||||
pathNode->tile = tile;
|
||||
pathNode->elevation = a1->elevation;
|
||||
pathNode->elevation = obj->elevation;
|
||||
|
||||
tileToScreenXY(tile, &fromX, &fromY, a1->elevation);
|
||||
tileToScreenXY(tile, &fromX, &fromY, obj->elevation);
|
||||
pathNode->x = tileX - fromX - 16;
|
||||
pathNode->y = tileY - fromY - 8;
|
||||
}
|
||||
|
@ -2128,7 +2129,7 @@ int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* str
|
|||
pathNodeIndex += 1;
|
||||
} else {
|
||||
if (pathNodeIndex > 0 && straightPathNodeList != NULL) {
|
||||
straightPathNodeList[pathNodeIndex - 1].elevation = a1->elevation;
|
||||
straightPathNodeList[pathNodeIndex - 1].elevation = obj->elevation;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,8 +145,8 @@ int animationRegisterAnimateForever(Object* owner, int anim, int delay);
|
|||
int animationRegisterPing(int flags, int delay);
|
||||
int _make_path(Object* object, int from, int to, unsigned char* a4, int a5);
|
||||
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback);
|
||||
int _make_straight_path(Object* a1, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6);
|
||||
int _make_straight_path_func(Object* a1, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6, PathBuilderCallback* callback);
|
||||
int _make_straight_path(Object* object, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6);
|
||||
int _make_straight_path_func(Object* object, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6, PathBuilderCallback* callback);
|
||||
void _object_animate();
|
||||
int _check_move(int* actionPointsPtr);
|
||||
int _dude_move(int actionPoints);
|
||||
|
|
259
src/combat.cc
259
src/combat.cc
|
@ -116,7 +116,7 @@ static int attackComputeCriticalHit(Attack* a1);
|
|||
static int _attackFindInvalidFlags(Object* a1, Object* a2);
|
||||
static int attackComputeCriticalFailure(Attack* attack);
|
||||
static void _do_random_cripple(int* flagsPtr);
|
||||
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, bool a6);
|
||||
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, bool useDistance);
|
||||
static void attackComputeDamage(Attack* attack, int ammoQuantity, int a3);
|
||||
static void _check_for_death(Object* a1, int a2, int* a3);
|
||||
static void _set_new_results(Object* a1, int a2);
|
||||
|
@ -3476,16 +3476,16 @@ void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode,
|
|||
}
|
||||
|
||||
// 0x422F3C
|
||||
int _combat_attack(Object* a1, Object* a2, int hitMode, int hitLocation)
|
||||
int _combat_attack(Object* attacker, Object* defender, int hitMode, int hitLocation)
|
||||
{
|
||||
if (a1 != gDude && hitMode == HIT_MODE_PUNCH && randomBetween(1, 4) == 1) {
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_KICK_LEG, (a1->fid & 0xF000) >> 12, (a1->fid & 0x70000000) >> 28);
|
||||
if (attacker != gDude && hitMode == HIT_MODE_PUNCH && randomBetween(1, 4) == 1) {
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, attacker->fid & 0xFFF, ANIM_KICK_LEG, (attacker->fid & 0xF000) >> 12, (attacker->fid & 0x70000000) >> 28);
|
||||
if (artExists(fid)) {
|
||||
hitMode = HIT_MODE_KICK;
|
||||
}
|
||||
}
|
||||
|
||||
attackInit(&_main_ctd, a1, a2, hitMode, hitLocation);
|
||||
attackInit(&_main_ctd, attacker, defender, hitMode, hitLocation);
|
||||
debugPrint("computing attack...\n");
|
||||
|
||||
if (attackCompute(&_main_ctd) == -1) {
|
||||
|
@ -3513,7 +3513,7 @@ int _combat_attack(Object* a1, Object* a2, int hitMode, int hitLocation)
|
|||
|
||||
bool aiming;
|
||||
if (_main_ctd.defenderHitLocation == HIT_LOCATION_TORSO || _main_ctd.defenderHitLocation == HIT_LOCATION_UNCALLED) {
|
||||
if (a1 == gDude) {
|
||||
if (attacker == gDude) {
|
||||
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
||||
} else {
|
||||
aiming = false;
|
||||
|
@ -3522,22 +3522,22 @@ int _combat_attack(Object* a1, Object* a2, int hitMode, int hitLocation)
|
|||
aiming = true;
|
||||
}
|
||||
|
||||
int actionPoints = weaponGetActionPointCost(a1, _main_ctd.hitMode, aiming);
|
||||
int actionPoints = weaponGetActionPointCost(attacker, _main_ctd.hitMode, aiming);
|
||||
debugPrint("sequencing attack...\n");
|
||||
|
||||
if (_action_attack(&_main_ctd) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (actionPoints > a1->data.critter.combat.ap) {
|
||||
a1->data.critter.combat.ap = 0;
|
||||
if (actionPoints > attacker->data.critter.combat.ap) {
|
||||
attacker->data.critter.combat.ap = 0;
|
||||
} else {
|
||||
a1->data.critter.combat.ap -= actionPoints;
|
||||
attacker->data.critter.combat.ap -= actionPoints;
|
||||
}
|
||||
|
||||
if (a1 == gDude) {
|
||||
interfaceRenderActionPoints(a1->data.critter.combat.ap, _combat_free_move);
|
||||
_critter_set_who_hit_me(a1, a2);
|
||||
if (attacker == gDude) {
|
||||
interfaceRenderActionPoints(attacker->data.critter.combat.ap, _combat_free_move);
|
||||
_critter_set_who_hit_me(attacker, defender);
|
||||
}
|
||||
|
||||
// SFALL
|
||||
|
@ -3545,19 +3545,19 @@ int _combat_attack(Object* a1, Object* a2, int hitMode, int hitLocation)
|
|||
|
||||
_combat_call_display = 1;
|
||||
_combat_cleanup_enabled = 1;
|
||||
aiInfoSetLastTarget(a1, a2);
|
||||
aiInfoSetLastTarget(attacker, defender);
|
||||
debugPrint("running attack...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns tile one step closer from [a1] to [a2]
|
||||
// Returns tile one step closer from [attacker] to [target]
|
||||
//
|
||||
// 0x423104
|
||||
int _combat_bullet_start(const Object* a1, const Object* a2)
|
||||
int _combat_bullet_start(const Object* attacker, const Object* target)
|
||||
{
|
||||
int rotation = tileGetRotationTo(a1->tile, a2->tile);
|
||||
return tileGetTileInDirection(a1->tile, rotation, 1);
|
||||
int rotation = tileGetRotationTo(attacker->tile, target->tile);
|
||||
return tileGetTileInDirection(attacker->tile, rotation, 1);
|
||||
}
|
||||
|
||||
// 0x423128
|
||||
|
@ -3942,17 +3942,17 @@ static int attackCompute(Attack* attack)
|
|||
|
||||
attack->tile = tile;
|
||||
|
||||
Object* v25 = attack->defender;
|
||||
_make_straight_path_func(v25, attack->defender->tile, attack->tile, NULL, &v25, 32, _obj_shoot_blocking_at);
|
||||
if (v25 != NULL && v25 != attack->defender) {
|
||||
attack->tile = v25->tile;
|
||||
Object* accidentalTarget = attack->defender;
|
||||
_make_straight_path_func(accidentalTarget, attack->defender->tile, attack->tile, NULL, &accidentalTarget, 32, _obj_shoot_blocking_at);
|
||||
if (accidentalTarget != NULL && accidentalTarget != attack->defender) {
|
||||
attack->tile = accidentalTarget->tile;
|
||||
} else {
|
||||
v25 = _obj_blocking_at(NULL, attack->tile, attack->defender->elevation);
|
||||
accidentalTarget = _obj_blocking_at(NULL, attack->tile, attack->defender->elevation);
|
||||
}
|
||||
|
||||
if (v25 != NULL && (v25->flags & OBJECT_SHOOT_THRU) == 0) {
|
||||
if (accidentalTarget != NULL && (accidentalTarget->flags & OBJECT_SHOOT_THRU) == 0) {
|
||||
attack->attackerFlags |= DAM_HIT;
|
||||
attack->defender = v25;
|
||||
attack->defender = accidentalTarget;
|
||||
attackComputeDamage(attack, 1, 2);
|
||||
}
|
||||
}
|
||||
|
@ -3974,75 +3974,75 @@ static int attackCompute(Attack* attack)
|
|||
|
||||
// compute_explosion_on_extras
|
||||
// 0x423C10
|
||||
void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4)
|
||||
void _compute_explosion_on_extras(Attack* attack, bool isFromAttacker, bool isGrenade, bool noDamage)
|
||||
{
|
||||
Object* attacker;
|
||||
Object* targetObj;
|
||||
|
||||
if (a2) {
|
||||
attacker = attack->attacker;
|
||||
if (isFromAttacker) {
|
||||
targetObj = attack->attacker;
|
||||
} else {
|
||||
if ((attack->attackerFlags & DAM_HIT) != 0) {
|
||||
attacker = attack->defender;
|
||||
targetObj = attack->defender;
|
||||
} else {
|
||||
attacker = NULL;
|
||||
targetObj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int tile;
|
||||
if (attacker != NULL) {
|
||||
tile = attacker->tile;
|
||||
int explosionTile;
|
||||
if (targetObj != NULL) {
|
||||
explosionTile = targetObj->tile;
|
||||
} else {
|
||||
tile = attack->tile;
|
||||
explosionTile = attack->tile;
|
||||
}
|
||||
|
||||
if (tile == -1) {
|
||||
if (explosionTile == -1) {
|
||||
debugPrint("\nError: compute_explosion_on_extras: Called with bad target/tileNum");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: The math in this loop is rather complex and hard to understand.
|
||||
int v20;
|
||||
int v22 = 0;
|
||||
int ringTileIdx;
|
||||
int radius = 0;
|
||||
int rotation = 0;
|
||||
int v5 = -1;
|
||||
int v19 = tile;
|
||||
int tile = -1;
|
||||
int ringFirstTile = explosionTile;
|
||||
|
||||
// SFALL
|
||||
int maxTargets = explosionGetMaxTargets();
|
||||
// Check adjacent tiles for possible targets, going ring-by-ring
|
||||
while (attack->extrasLength < maxTargets) {
|
||||
if (v22 != 0 && (v5 == -1 || (v5 = tileGetTileInDirection(v5, rotation, 1)) != v19)) {
|
||||
v20++;
|
||||
if (v20 % v22 == 0) {
|
||||
if (radius != 0 && (tile == -1 || (tile = tileGetTileInDirection(tile, rotation, 1)) != ringFirstTile)) {
|
||||
ringTileIdx++;
|
||||
if (ringTileIdx % radius == 0) { // the larger the radius, the slower we rotate
|
||||
rotation += 1;
|
||||
if (rotation == ROTATION_COUNT) {
|
||||
rotation = ROTATION_NE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v22++;
|
||||
if (isGrenade && weaponGetGrenadeExplosionRadius(attack->weapon) < v22) {
|
||||
v5 = -1;
|
||||
} else if (isGrenade || weaponGetRocketExplosionRadius(attack->weapon) >= v22) {
|
||||
v5 = tileGetTileInDirection(v19, ROTATION_NE, 1);
|
||||
radius++; // go to the next ring
|
||||
if (isGrenade && weaponGetGrenadeExplosionRadius(attack->weapon) < radius) {
|
||||
tile = -1;
|
||||
} else if (isGrenade || weaponGetRocketExplosionRadius(attack->weapon) >= radius) {
|
||||
tile = tileGetTileInDirection(ringFirstTile, ROTATION_NE, 1);
|
||||
} else {
|
||||
v5 = -1;
|
||||
tile = -1;
|
||||
}
|
||||
|
||||
v19 = v5;
|
||||
ringFirstTile = tile;
|
||||
rotation = ROTATION_SE;
|
||||
v20 = 0;
|
||||
ringTileIdx = 0;
|
||||
}
|
||||
|
||||
if (v5 == -1) {
|
||||
if (tile == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
Object* obstacle = _obj_blocking_at(attacker, v5, attack->attacker->elevation);
|
||||
Object* obstacle = _obj_blocking_at(targetObj, tile, attack->attacker->elevation);
|
||||
if (obstacle != NULL
|
||||
&& FID_TYPE(obstacle->fid) == OBJ_TYPE_CRITTER
|
||||
&& (obstacle->data.critter.combat.results & DAM_DEAD) == 0
|
||||
&& (obstacle->flags & OBJECT_SHOOT_THRU) == 0
|
||||
&& !_combat_is_shot_blocked(obstacle, obstacle->tile, tile, NULL, NULL)) {
|
||||
&& !_combat_is_shot_blocked(obstacle, obstacle->tile, explosionTile, NULL, NULL)) {
|
||||
if (obstacle == attack->attacker) {
|
||||
attack->attackerFlags &= ~DAM_HIT;
|
||||
attackComputeDamage(attack, 1, 2);
|
||||
|
@ -4060,7 +4060,7 @@ void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4
|
|||
attack->extrasHitLocation[index] = HIT_LOCATION_TORSO;
|
||||
attack->extras[index] = obstacle;
|
||||
attackInit(&_explosion_ctd, attack->attacker, obstacle, attack->hitMode, HIT_LOCATION_TORSO);
|
||||
if (!a4) {
|
||||
if (!noDamage) {
|
||||
_explosion_ctd.attackerFlags |= DAM_HIT;
|
||||
attackComputeDamage(&_explosion_ctd, 1, 2);
|
||||
}
|
||||
|
@ -4282,26 +4282,26 @@ static void _do_random_cripple(int* flagsPtr)
|
|||
}
|
||||
|
||||
// 0x42436C
|
||||
int _determine_to_hit(Object* a1, Object* a2, int hitLocation, int hitMode)
|
||||
int _determine_to_hit(Object* attacker, Object* defender, int hitLocation, int hitMode)
|
||||
{
|
||||
return attackDetermineToHit(a1, a1->tile, a2, hitLocation, hitMode, true);
|
||||
return attackDetermineToHit(attacker, attacker->tile, defender, hitLocation, hitMode, true);
|
||||
}
|
||||
|
||||
// 0x424380
|
||||
int _determine_to_hit_no_range(Object* a1, Object* a2, int hitLocation, int hitMode, unsigned char* a5)
|
||||
int _determine_to_hit_no_range(Object* attacker, Object* defender, int hitLocation, int hitMode, unsigned char* a5)
|
||||
{
|
||||
return attackDetermineToHit(a1, a1->tile, a2, hitLocation, hitMode, false);
|
||||
return attackDetermineToHit(attacker, attacker->tile, defender, hitLocation, hitMode, false);
|
||||
}
|
||||
|
||||
// 0x424394
|
||||
int _determine_to_hit_from_tile(Object* a1, int tile, Object* a3, int hitLocation, int hitMode)
|
||||
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode)
|
||||
{
|
||||
return attackDetermineToHit(a1, tile, a3, hitLocation, hitMode, true);
|
||||
return attackDetermineToHit(attacker, tile, defender, hitLocation, hitMode, true);
|
||||
}
|
||||
|
||||
// determine_to_hit
|
||||
// 0x4243A8
|
||||
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, bool a6)
|
||||
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, bool useDistance)
|
||||
{
|
||||
Object* weapon = critterGetWeaponForHitMode(attacker, hitMode);
|
||||
|
||||
|
@ -4311,32 +4311,30 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in
|
|||
|
||||
bool isRangedWeapon = false;
|
||||
|
||||
int accuracy;
|
||||
int toHit;
|
||||
if (weapon == NULL || isUnarmedHitMode(hitMode)) {
|
||||
accuracy = skillGetValue(attacker, SKILL_UNARMED);
|
||||
toHit = skillGetValue(attacker, SKILL_UNARMED);
|
||||
} else {
|
||||
accuracy = weaponGetSkillValue(attacker, hitMode);
|
||||
|
||||
int modifier = 0;
|
||||
toHit = weaponGetSkillValue(attacker, hitMode);
|
||||
|
||||
int attackType = weaponGetAttackTypeForHitMode(weapon, hitMode);
|
||||
if (attackType == ATTACK_TYPE_RANGED || attackType == ATTACK_TYPE_THROW) {
|
||||
isRangedWeapon = true;
|
||||
|
||||
int v29 = 0;
|
||||
int v25 = 0;
|
||||
int perceptionBonusMult = 0;
|
||||
int minEffectiveDist = 0;
|
||||
|
||||
int weaponPerk = weaponGetPerk(weapon);
|
||||
switch (weaponPerk) {
|
||||
case PERK_WEAPON_LONG_RANGE:
|
||||
v29 = 4;
|
||||
perceptionBonusMult = 4;
|
||||
break;
|
||||
case PERK_WEAPON_SCOPE_RANGE:
|
||||
v29 = 5;
|
||||
v25 = 8;
|
||||
perceptionBonusMult = 5;
|
||||
minEffectiveDist = 8;
|
||||
break;
|
||||
default:
|
||||
v29 = 2;
|
||||
perceptionBonusMult = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4347,71 +4345,72 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in
|
|||
perception += 2 * perkGetRank(gDude, PERK_SHARPSHOOTER);
|
||||
}
|
||||
|
||||
int distanceMod = 0;
|
||||
// SFALL: Fix for `determine_to_hit_func` function taking distance
|
||||
// into account when called from `determine_to_hit_no_range`.
|
||||
if (defender != NULL && a6) {
|
||||
modifier = objectGetDistanceBetweenTiles(attacker, tile, defender, defender->tile);
|
||||
if (defender != NULL && useDistance) {
|
||||
distanceMod = objectGetDistanceBetweenTiles(attacker, tile, defender, defender->tile);
|
||||
} else {
|
||||
modifier = 0;
|
||||
distanceMod = 0;
|
||||
}
|
||||
|
||||
if (modifier >= v25) {
|
||||
int penalty = attacker == gDude
|
||||
? v29 * (perception - 2)
|
||||
: v29 * perception;
|
||||
if (distanceMod >= minEffectiveDist) {
|
||||
int perceptionBonus = attacker == gDude
|
||||
? perceptionBonusMult * (perception - 2)
|
||||
: perceptionBonusMult * perception;
|
||||
|
||||
modifier -= penalty;
|
||||
distanceMod -= perceptionBonus;
|
||||
} else {
|
||||
modifier += v25;
|
||||
distanceMod += minEffectiveDist;
|
||||
}
|
||||
|
||||
if (-2 * perception > modifier) {
|
||||
modifier = -2 * perception;
|
||||
if (distanceMod < -2 * perception) {
|
||||
distanceMod = -2 * perception;
|
||||
}
|
||||
|
||||
if (modifier >= 0) {
|
||||
if (distanceMod >= 0) {
|
||||
if ((attacker->data.critter.combat.results & DAM_BLIND) != 0) {
|
||||
modifier *= -12;
|
||||
distanceMod *= -12;
|
||||
} else {
|
||||
modifier *= -4;
|
||||
distanceMod *= -4;
|
||||
}
|
||||
} else {
|
||||
modifier *= -4;
|
||||
distanceMod *= -4;
|
||||
}
|
||||
|
||||
if (a6 || modifier > 0) {
|
||||
accuracy += modifier;
|
||||
if (useDistance || distanceMod > 0) {
|
||||
toHit += distanceMod;
|
||||
}
|
||||
|
||||
modifier = 0;
|
||||
int numCrittersInLof = 0;
|
||||
|
||||
if (defender != NULL && a6) {
|
||||
_combat_is_shot_blocked(attacker, tile, defender->tile, defender, &modifier);
|
||||
if (defender != NULL && useDistance) {
|
||||
_combat_is_shot_blocked(attacker, tile, defender->tile, defender, &numCrittersInLof);
|
||||
}
|
||||
|
||||
accuracy -= 10 * modifier;
|
||||
toHit -= 10 * numCrittersInLof;
|
||||
}
|
||||
|
||||
if (attacker == gDude && traitIsSelected(TRAIT_ONE_HANDER)) {
|
||||
if (weaponIsTwoHanded(weapon)) {
|
||||
accuracy -= 40;
|
||||
toHit -= 40;
|
||||
} else {
|
||||
accuracy += 20;
|
||||
toHit += 20;
|
||||
}
|
||||
}
|
||||
|
||||
int minStrength = weaponGetMinStrengthRequired(weapon);
|
||||
modifier = minStrength - critterGetStat(attacker, STAT_STRENGTH);
|
||||
int minStrengthMod = minStrength - critterGetStat(attacker, STAT_STRENGTH);
|
||||
if (attacker == gDude && perkGetRank(gDude, PERK_WEAPON_HANDLING) != 0) {
|
||||
modifier -= 3;
|
||||
minStrengthMod -= 3;
|
||||
}
|
||||
|
||||
if (modifier > 0) {
|
||||
accuracy -= 20 * modifier;
|
||||
if (minStrengthMod > 0) {
|
||||
toHit -= 20 * minStrengthMod;
|
||||
}
|
||||
|
||||
if (weaponGetPerk(weapon) == PERK_WEAPON_ACCURATE) {
|
||||
accuracy += 20;
|
||||
toHit += 20;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4422,17 +4421,17 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in
|
|||
armorClass = 0;
|
||||
}
|
||||
|
||||
accuracy -= armorClass;
|
||||
toHit -= armorClass;
|
||||
}
|
||||
|
||||
if (isRangedWeapon) {
|
||||
accuracy += hit_location_penalty[hitLocation];
|
||||
toHit += hit_location_penalty[hitLocation];
|
||||
} else {
|
||||
accuracy += hit_location_penalty[hitLocation] / 2;
|
||||
toHit += hit_location_penalty[hitLocation] / 2;
|
||||
}
|
||||
|
||||
if (defender != NULL && (defender->flags & OBJECT_MULTIHEX) != 0) {
|
||||
accuracy += 15;
|
||||
toHit += 15;
|
||||
}
|
||||
|
||||
if (attacker == gDude) {
|
||||
|
@ -4447,45 +4446,45 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in
|
|||
}
|
||||
|
||||
if (lightIntensity <= 26214)
|
||||
accuracy -= 40;
|
||||
toHit -= 40;
|
||||
else if (lightIntensity <= 39321)
|
||||
accuracy -= 25;
|
||||
toHit -= 25;
|
||||
else if (lightIntensity <= 52428)
|
||||
accuracy -= 10;
|
||||
toHit -= 10;
|
||||
}
|
||||
|
||||
if (_gcsd != NULL) {
|
||||
accuracy += _gcsd->accuracyBonus;
|
||||
toHit += _gcsd->accuracyBonus;
|
||||
}
|
||||
|
||||
if ((attacker->data.critter.combat.results & DAM_BLIND) != 0) {
|
||||
accuracy -= 25;
|
||||
toHit -= 25;
|
||||
}
|
||||
|
||||
if (targetIsCritter && defender != NULL && (defender->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0) {
|
||||
accuracy += 40;
|
||||
toHit += 40;
|
||||
}
|
||||
|
||||
if (attacker->data.critter.combat.team != gDude->data.critter.combat.team) {
|
||||
switch (settings.preferences.combat_difficulty) {
|
||||
case 0:
|
||||
accuracy -= 20;
|
||||
toHit -= 20;
|
||||
break;
|
||||
case 2:
|
||||
accuracy += 20;
|
||||
toHit += 20;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (accuracy > 95) {
|
||||
accuracy = 95;
|
||||
if (toHit > 95) {
|
||||
toHit = 95;
|
||||
}
|
||||
|
||||
if (accuracy < -100) {
|
||||
if (toHit < -100) {
|
||||
debugPrint("Whoa! Bad skill value in determine_to_hit!\n");
|
||||
}
|
||||
|
||||
return accuracy;
|
||||
return toHit;
|
||||
}
|
||||
|
||||
// 0x4247B8
|
||||
|
@ -5880,39 +5879,35 @@ void _combat_highlight_change()
|
|||
_combat_highlight = targetHighlight;
|
||||
}
|
||||
|
||||
// Probably calculates line of sight or determines if object can see other object.
|
||||
// Checks if line of fire to the target object is blocked or not. Optionally calculate number of critters on the line of fire.
|
||||
//
|
||||
// 0x426CC4
|
||||
bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5)
|
||||
bool _combat_is_shot_blocked(Object* sourceObj, int from, int to, Object* targetObj, int* numCrittersOnLof)
|
||||
{
|
||||
if (a5 != NULL) {
|
||||
*a5 = 0;
|
||||
if (numCrittersOnLof != NULL) {
|
||||
*numCrittersOnLof = 0;
|
||||
}
|
||||
|
||||
Object* obstacle = a1;
|
||||
Object* obstacle = sourceObj;
|
||||
int current = from;
|
||||
while (obstacle != NULL && current != to) {
|
||||
_make_straight_path_func(a1, current, to, 0, &obstacle, 32, _obj_shoot_blocking_at);
|
||||
_make_straight_path_func(sourceObj, current, to, 0, &obstacle, 32, _obj_shoot_blocking_at);
|
||||
if (obstacle != NULL) {
|
||||
if (FID_TYPE(obstacle->fid) != OBJ_TYPE_CRITTER && obstacle != a4) {
|
||||
if (FID_TYPE(obstacle->fid) != OBJ_TYPE_CRITTER && obstacle != targetObj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a5 != NULL) {
|
||||
if (obstacle != a4) {
|
||||
if (a4 != NULL) {
|
||||
if (numCrittersOnLof != NULL && obstacle != targetObj && targetObj != NULL) {
|
||||
// SFALL: Fix for combat_is_shot_blocked_ engine
|
||||
// function not taking the flags of critters in the
|
||||
// line of fire into account when calculating the hit
|
||||
// chance penalty of ranged attacks in
|
||||
// determine_to_hit_func_ engine function.
|
||||
if ((obstacle->data.critter.combat.results & (DAM_DEAD | DAM_KNOCKED_DOWN | DAM_KNOCKED_OUT)) == 0) {
|
||||
*a5 += 1;
|
||||
*numCrittersOnLof += 1;
|
||||
|
||||
if ((obstacle->flags & OBJECT_MULTIHEX) != 0) {
|
||||
*a5 += 1;
|
||||
}
|
||||
}
|
||||
*numCrittersOnLof += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/combat.h
14
src/combat.h
|
@ -34,13 +34,13 @@ void _combat_over_from_load();
|
|||
void _combat_give_exps(int exp_points);
|
||||
void _combat_turn_run();
|
||||
void _combat(STRUCT_664980* attack);
|
||||
void attackInit(Attack* attack, Object* a2, Object* a3, int a4, int a5);
|
||||
int _combat_attack(Object* a1, Object* a2, int a3, int a4);
|
||||
int _combat_bullet_start(const Object* a1, const Object* a2);
|
||||
void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4);
|
||||
void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode, int hitLocation);
|
||||
int _combat_attack(Object* attacker, Object* defender, int hitMode, int hitLocation);
|
||||
int _combat_bullet_start(const Object* attacker, const Object* target);
|
||||
void _compute_explosion_on_extras(Attack* attack, bool isFromAttacker, bool isGrenade, bool noDamage);
|
||||
int _determine_to_hit(Object* a1, Object* a2, int hitLocation, int hitMode);
|
||||
int _determine_to_hit_no_range(Object* a1, Object* a2, int a3, int a4, unsigned char* a5);
|
||||
int _determine_to_hit_from_tile(Object* a1, int a2, Object* a3, int a4, int a5);
|
||||
int _determine_to_hit_no_range(Object* attacker, Object* defender, int hitLocation, int hitMode, unsigned char* a5);
|
||||
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode);
|
||||
void attackComputeDeathFlags(Attack* attack);
|
||||
void _apply_damage(Attack* attack, bool animated);
|
||||
void _combat_display(Attack* attack);
|
||||
|
@ -52,7 +52,7 @@ void _combat_attack_this(Object* a1);
|
|||
void _combat_outline_on();
|
||||
void _combat_outline_off();
|
||||
void _combat_highlight_change();
|
||||
bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5);
|
||||
bool _combat_is_shot_blocked(Object* sourceObj, int from, int to, Object* targetObj, int* numCrittersOnLof);
|
||||
int _combat_player_knocked_out_by();
|
||||
int _combat_explode_scenery(Object* a1, Object* a2);
|
||||
void _combat_delete_critter(Object* obj);
|
||||
|
|
183
src/combat_ai.cc
183
src/combat_ai.cc
|
@ -2327,61 +2327,61 @@ static int _ai_pick_hit_mode(Object* attacker, Object* weapon, Object* defender)
|
|||
}
|
||||
|
||||
// 0x429FC8
|
||||
static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, bool taunt)
|
||||
static int _ai_move_steps_closer(Object* critter, Object* target, int actionPoints, bool taunt)
|
||||
{
|
||||
if (actionPoints <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int distance = aiGetDistance(a1);
|
||||
int distance = aiGetDistance(critter);
|
||||
if (distance == DISTANCE_STAY) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (distance == DISTANCE_STAY_CLOSE) {
|
||||
if (a2 != gDude) {
|
||||
int currentDistance = objectGetDistanceBetween(a1, gDude);
|
||||
if (target != gDude) {
|
||||
int currentDistance = objectGetDistanceBetween(critter, gDude);
|
||||
if (currentDistance > 5
|
||||
&& objectGetDistanceBetween(a2, gDude) > 5
|
||||
&& objectGetDistanceBetween(target, gDude) > 5
|
||||
&& currentDistance + actionPoints > 5) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (objectGetDistanceBetween(a1, a2) <= 1) {
|
||||
if (objectGetDistanceBetween(critter, target) <= 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
|
||||
|
||||
if (taunt) {
|
||||
_combatai_msg(a1, NULL, AI_MESSAGE_TYPE_MOVE, 0);
|
||||
_combatai_msg(critter, NULL, AI_MESSAGE_TYPE_MOVE, 0);
|
||||
}
|
||||
|
||||
Object* v18 = a2;
|
||||
Object* initialTarget = target;
|
||||
|
||||
bool shouldUnhide;
|
||||
if ((a2->flags & OBJECT_MULTIHEX) != 0) {
|
||||
if ((target->flags & OBJECT_MULTIHEX) != 0) {
|
||||
shouldUnhide = true;
|
||||
a2->flags |= OBJECT_HIDDEN;
|
||||
target->flags |= OBJECT_HIDDEN;
|
||||
} else {
|
||||
shouldUnhide = false;
|
||||
}
|
||||
|
||||
if (pathfinderFindPath(a1, a1->tile, a2->tile, NULL, 0, _obj_blocking_at) == 0) {
|
||||
if (pathfinderFindPath(critter, critter->tile, target->tile, NULL, 0, _obj_blocking_at) == 0) {
|
||||
_moveBlockObj = NULL;
|
||||
if (pathfinderFindPath(a1, a1->tile, a2->tile, NULL, 0, _obj_ai_blocking_at) == 0
|
||||
if (pathfinderFindPath(critter, critter->tile, target->tile, NULL, 0, _obj_ai_blocking_at) == 0
|
||||
&& _moveBlockObj != NULL
|
||||
&& PID_TYPE(_moveBlockObj->pid) == OBJ_TYPE_CRITTER) {
|
||||
if (shouldUnhide) {
|
||||
a2->flags &= ~OBJECT_HIDDEN;
|
||||
target->flags &= ~OBJECT_HIDDEN;
|
||||
}
|
||||
|
||||
a2 = _moveBlockObj;
|
||||
if ((a2->flags & OBJECT_MULTIHEX) != 0) {
|
||||
target = _moveBlockObj;
|
||||
if ((target->flags & OBJECT_MULTIHEX) != 0) {
|
||||
shouldUnhide = true;
|
||||
a2->flags |= OBJECT_HIDDEN;
|
||||
target->flags |= OBJECT_HIDDEN;
|
||||
} else {
|
||||
shouldUnhide = false;
|
||||
}
|
||||
|
@ -2389,25 +2389,25 @@ static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, bool
|
|||
}
|
||||
|
||||
if (shouldUnhide) {
|
||||
a2->flags &= ~OBJECT_HIDDEN;
|
||||
target->flags &= ~OBJECT_HIDDEN;
|
||||
}
|
||||
|
||||
int tile = a2->tile;
|
||||
if (a2 == v18) {
|
||||
_cai_retargetTileFromFriendlyFire(a1, a2, &tile);
|
||||
int tile = target->tile;
|
||||
if (target == initialTarget) {
|
||||
_cai_retargetTileFromFriendlyFire(critter, target, &tile);
|
||||
}
|
||||
|
||||
if (actionPoints >= critterGetStat(a1, STAT_MAXIMUM_ACTION_POINTS) / 2 && artCritterFidShouldRun(a1->fid)) {
|
||||
if ((a2->flags & OBJECT_MULTIHEX) != 0) {
|
||||
animationRegisterRunToObject(a1, a2, actionPoints, 0);
|
||||
if (actionPoints >= critterGetStat(critter, STAT_MAXIMUM_ACTION_POINTS) / 2 && artCritterFidShouldRun(critter->fid)) {
|
||||
if ((target->flags & OBJECT_MULTIHEX) != 0) {
|
||||
animationRegisterRunToObject(critter, target, actionPoints, 0);
|
||||
} else {
|
||||
animationRegisterRunToTile(a1, tile, a1->elevation, actionPoints, 0);
|
||||
animationRegisterRunToTile(critter, tile, critter->elevation, actionPoints, 0);
|
||||
}
|
||||
} else {
|
||||
if ((a2->flags & OBJECT_MULTIHEX) != 0) {
|
||||
animationRegisterMoveToObject(a1, a2, actionPoints, 0);
|
||||
if ((target->flags & OBJECT_MULTIHEX) != 0) {
|
||||
animationRegisterMoveToObject(critter, target, actionPoints, 0);
|
||||
} else {
|
||||
animationRegisterMoveToTile(a1, tile, a1->elevation, actionPoints, 0);
|
||||
animationRegisterMoveToTile(critter, tile, critter->elevation, actionPoints, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2665,35 +2665,35 @@ static int _ai_attack(Object* attacker, Object* defender, int hitMode)
|
|||
}
|
||||
|
||||
// 0x42A7D8
|
||||
static int _ai_try_attack(Object* a1, Object* a2)
|
||||
static int _ai_try_attack(Object* attacker, Object* defender)
|
||||
{
|
||||
_critter_set_who_hit_me(a1, a2);
|
||||
_critter_set_who_hit_me(attacker, defender);
|
||||
|
||||
CritterCombatData* combatData = &(a1->data.critter.combat);
|
||||
CritterCombatData* combatData = &(attacker->data.critter.combat);
|
||||
bool taunt = true;
|
||||
|
||||
Object* weapon = critterGetItem2(a1);
|
||||
Object* weapon = critterGetItem2(attacker);
|
||||
if (weapon != NULL && itemGetType(weapon) != ITEM_TYPE_WEAPON) {
|
||||
weapon = NULL;
|
||||
}
|
||||
|
||||
int hitMode = _ai_pick_hit_mode(a1, weapon, a2);
|
||||
int minToHit = aiGetPacket(a1)->min_to_hit;
|
||||
int hitMode = _ai_pick_hit_mode(attacker, weapon, defender);
|
||||
int minToHit = aiGetPacket(attacker)->min_to_hit;
|
||||
|
||||
int actionPoints = a1->data.critter.combat.ap;
|
||||
int actionPoints = attacker->data.critter.combat.ap;
|
||||
int safeDistance = 0;
|
||||
int v42 = 0;
|
||||
int actionPointsToUse = 0;
|
||||
if (weapon != NULL
|
||||
|| (critterGetBodyType(a2) == BODY_TYPE_BIPED
|
||||
&& ((a2->fid & 0xF000) >> 12 == 0)
|
||||
&& artExists(buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_THROW_PUNCH, 0, a1->rotation + 1)))) {
|
||||
|| (critterGetBodyType(defender) == BODY_TYPE_BIPED
|
||||
&& ((defender->fid & 0xF000) >> 12 == 0)
|
||||
&& artExists(buildFid(OBJ_TYPE_CRITTER, attacker->fid & 0xFFF, ANIM_THROW_PUNCH, 0, attacker->rotation + 1)))) {
|
||||
// SFALL: Check the safety of weapons based on the selected attack mode
|
||||
// instead of always the primary weapon hit mode.
|
||||
if (_combat_safety_invalidate_weapon(a1, weapon, hitMode, a2, &safeDistance)) {
|
||||
_ai_switch_weapons(a1, &hitMode, &weapon, a2);
|
||||
if (_combat_safety_invalidate_weapon(attacker, weapon, hitMode, defender, &safeDistance)) {
|
||||
_ai_switch_weapons(attacker, &hitMode, &weapon, defender);
|
||||
}
|
||||
} else {
|
||||
_ai_switch_weapons(a1, &hitMode, &weapon, a2);
|
||||
_ai_switch_weapons(attacker, &hitMode, &weapon, defender);
|
||||
}
|
||||
|
||||
unsigned char rotations[800];
|
||||
|
@ -2704,37 +2704,37 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
|||
break;
|
||||
}
|
||||
|
||||
int reason = _combat_check_bad_shot(a1, a2, hitMode, false);
|
||||
int reason = _combat_check_bad_shot(attacker, defender, hitMode, false);
|
||||
if (reason == COMBAT_BAD_SHOT_NO_AMMO) {
|
||||
// out of ammo
|
||||
if (aiHaveAmmo(a1, weapon, &ammo)) {
|
||||
if (aiHaveAmmo(attacker, weapon, &ammo)) {
|
||||
int remainingAmmoQuantity = weaponReload(weapon, ammo);
|
||||
if (remainingAmmoQuantity == 0 && ammo != NULL) {
|
||||
_obj_destroy(ammo);
|
||||
}
|
||||
|
||||
if (remainingAmmoQuantity != -1) {
|
||||
int volume = _gsound_compute_relative_volume(a1);
|
||||
int volume = _gsound_compute_relative_volume(attacker);
|
||||
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon, hitMode, NULL);
|
||||
_gsound_play_sfx_file_volume(sfx, volume);
|
||||
_ai_magic_hands(a1, weapon, 5002);
|
||||
_ai_magic_hands(attacker, weapon, 5002);
|
||||
|
||||
// SFALL: Fix incorrect AP cost when AI reloads a weapon.
|
||||
// CE: There is a commented out code which checks
|
||||
// available action points before performing reload. Not
|
||||
// sure why it was commented, probably needs additional
|
||||
// testing.
|
||||
int actionPointsRequired = weaponGetActionPointCost(a1, HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
||||
if (a1->data.critter.combat.ap >= actionPointsRequired) {
|
||||
a1->data.critter.combat.ap -= actionPointsRequired;
|
||||
int actionPointsRequired = weaponGetActionPointCost(attacker, HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
||||
if (attacker->data.critter.combat.ap >= actionPointsRequired) {
|
||||
attacker->data.critter.combat.ap -= actionPointsRequired;
|
||||
} else {
|
||||
a1->data.critter.combat.ap = 0;
|
||||
attacker->data.critter.combat.ap = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ammo = _ai_search_environ(a1, ITEM_TYPE_AMMO);
|
||||
ammo = _ai_search_environ(attacker, ITEM_TYPE_AMMO);
|
||||
if (ammo != NULL) {
|
||||
ammo = _ai_retrieve_object(a1, ammo);
|
||||
ammo = _ai_retrieve_object(attacker, ammo);
|
||||
if (ammo != NULL) {
|
||||
int remainingAmmoQuantity = weaponReload(weapon, ammo);
|
||||
if (remainingAmmoQuantity == 0) {
|
||||
|
@ -2742,62 +2742,63 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
|||
}
|
||||
|
||||
if (remainingAmmoQuantity != -1) {
|
||||
int volume = _gsound_compute_relative_volume(a1);
|
||||
int volume = _gsound_compute_relative_volume(attacker);
|
||||
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon, hitMode, NULL);
|
||||
_gsound_play_sfx_file_volume(sfx, volume);
|
||||
_ai_magic_hands(a1, weapon, 5002);
|
||||
_ai_magic_hands(attacker, weapon, 5002);
|
||||
|
||||
// SFALL: Fix incorrect AP cost when AI reloads a
|
||||
// weapon.
|
||||
// CE: See note above, probably need to check
|
||||
// available action points before performing
|
||||
// reload.
|
||||
int actionPointsRequired = weaponGetActionPointCost(a1, HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
||||
if (a1->data.critter.combat.ap >= actionPointsRequired) {
|
||||
a1->data.critter.combat.ap -= actionPointsRequired;
|
||||
int actionPointsRequired = weaponGetActionPointCost(attacker, HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
||||
if (attacker->data.critter.combat.ap >= actionPointsRequired) {
|
||||
attacker->data.critter.combat.ap -= actionPointsRequired;
|
||||
} else {
|
||||
a1->data.critter.combat.ap = 0;
|
||||
attacker->data.critter.combat.ap = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int volume = _gsound_compute_relative_volume(a1);
|
||||
int volume = _gsound_compute_relative_volume(attacker);
|
||||
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_OUT_OF_AMMO, weapon, hitMode, NULL);
|
||||
_gsound_play_sfx_file_volume(sfx, volume);
|
||||
_ai_magic_hands(a1, weapon, 5001);
|
||||
_ai_magic_hands(attacker, weapon, 5001);
|
||||
|
||||
if (_inven_unwield(a1, 1) == 0) {
|
||||
if (_inven_unwield(attacker, 1) == 0) {
|
||||
_combat_turn_run();
|
||||
}
|
||||
|
||||
_ai_switch_weapons(a1, &hitMode, &weapon, a2);
|
||||
_ai_switch_weapons(attacker, &hitMode, &weapon, defender);
|
||||
}
|
||||
}
|
||||
} else if (reason == COMBAT_BAD_SHOT_NOT_ENOUGH_AP || reason == COMBAT_BAD_SHOT_ARM_CRIPPLED || reason == COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED) {
|
||||
// 3 - not enough action points
|
||||
// 6 - crippled one arm for two-handed weapon
|
||||
// 7 - both hands crippled
|
||||
if (_ai_switch_weapons(a1, &hitMode, &weapon, a2) == -1) {
|
||||
if (_ai_switch_weapons(attacker, &hitMode, &weapon, defender) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else if (reason == COMBAT_BAD_SHOT_OUT_OF_RANGE) {
|
||||
// target out of range
|
||||
int accuracy = _determine_to_hit_no_range(a1, a2, HIT_LOCATION_UNCALLED, hitMode, rotations);
|
||||
if (accuracy < minToHit) {
|
||||
debugPrint("%s: FLEEING: Can't possibly Hit Target!", critterGetName(a1));
|
||||
_ai_run_away(a1, a2);
|
||||
int toHitNoRange = _determine_to_hit_no_range(attacker, defender, HIT_LOCATION_UNCALLED, hitMode, rotations);
|
||||
if (toHitNoRange < minToHit) {
|
||||
// hit chance is too low even at point blank range (not taking range into account)
|
||||
debugPrint("%s: FLEEING: Can't possibly Hit Target!", critterGetName(attacker));
|
||||
_ai_run_away(attacker, defender);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (weapon != NULL) {
|
||||
if (_ai_move_steps_closer(a1, a2, actionPoints, taunt) == -1) {
|
||||
if (_ai_move_steps_closer(attacker, defender, actionPoints, taunt) == -1) {
|
||||
return -1;
|
||||
}
|
||||
taunt = false;
|
||||
} else {
|
||||
if (_ai_switch_weapons(a1, &hitMode, &weapon, a2) == -1 || weapon == NULL) {
|
||||
if (_ai_switch_weapons(attacker, &hitMode, &weapon, defender) == -1 || weapon == NULL) {
|
||||
// NOTE: Uninline.
|
||||
if (_ai_move_closer(a1, a2, taunt) == -1) {
|
||||
if (_ai_move_closer(attacker, defender, taunt) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -2805,66 +2806,66 @@ static int _ai_try_attack(Object* a1, Object* a2)
|
|||
}
|
||||
} else if (reason == COMBAT_BAD_SHOT_AIM_BLOCKED) {
|
||||
// aim is blocked
|
||||
if (_ai_move_steps_closer(a1, a2, a1->data.critter.combat.ap, taunt) == -1) {
|
||||
if (_ai_move_steps_closer(attacker, defender, attacker->data.critter.combat.ap, taunt) == -1) {
|
||||
return -1;
|
||||
}
|
||||
taunt = false;
|
||||
} else if (reason == COMBAT_BAD_SHOT_OK) {
|
||||
int accuracy = _determine_to_hit(a1, a2, HIT_LOCATION_UNCALLED, hitMode);
|
||||
int accuracy = _determine_to_hit(attacker, defender, HIT_LOCATION_UNCALLED, hitMode);
|
||||
if (safeDistance != 0) {
|
||||
if (_ai_move_away(a1, a2, safeDistance) == -1) {
|
||||
if (_ai_move_away(attacker, defender, safeDistance) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (accuracy < minToHit) {
|
||||
int accuracyNoRange = _determine_to_hit_no_range(a1, a2, HIT_LOCATION_UNCALLED, hitMode, rotations);
|
||||
if (accuracyNoRange < minToHit) {
|
||||
debugPrint("%s: FLEEING: Can't possibly Hit Target!", critterGetName(a1));
|
||||
_ai_run_away(a1, a2);
|
||||
int toHitNoRange = _determine_to_hit_no_range(attacker, defender, HIT_LOCATION_UNCALLED, hitMode, rotations);
|
||||
if (toHitNoRange < minToHit) {
|
||||
debugPrint("%s: FLEEING: Can't possibly Hit Target!", critterGetName(attacker));
|
||||
_ai_run_away(attacker, defender);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (actionPoints > 0) {
|
||||
int v24 = pathfinderFindPath(a1, a1->tile, a2->tile, rotations, 0, _obj_blocking_at);
|
||||
if (v24 == 0) {
|
||||
v42 = actionPoints;
|
||||
int pathLength = pathfinderFindPath(attacker, attacker->tile, defender->tile, rotations, 0, _obj_blocking_at);
|
||||
if (pathLength == 0) {
|
||||
actionPointsToUse = actionPoints;
|
||||
} else {
|
||||
if (v24 < actionPoints) {
|
||||
actionPoints = v24;
|
||||
if (pathLength < actionPoints) {
|
||||
actionPoints = pathLength;
|
||||
}
|
||||
|
||||
int tile = a1->tile;
|
||||
int tile = attacker->tile;
|
||||
int index;
|
||||
for (index = 0; index < actionPoints; index++) {
|
||||
tile = tileGetTileInDirection(tile, rotations[index], 1);
|
||||
|
||||
v42++;
|
||||
actionPointsToUse++;
|
||||
|
||||
int v27 = _determine_to_hit_from_tile(a1, tile, a2, HIT_LOCATION_UNCALLED, hitMode);
|
||||
if (v27 >= minToHit) {
|
||||
int toHit = _determine_to_hit_from_tile(attacker, tile, defender, HIT_LOCATION_UNCALLED, hitMode);
|
||||
if (toHit >= minToHit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == actionPoints) {
|
||||
v42 = actionPoints;
|
||||
actionPointsToUse = actionPoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_ai_move_steps_closer(a1, a2, v42, taunt) == -1) {
|
||||
debugPrint("%s: FLEEING: Can't possibly get closer to Target!", critterGetName(a1));
|
||||
_ai_run_away(a1, a2);
|
||||
if (_ai_move_steps_closer(attacker, defender, actionPointsToUse, taunt) == -1) {
|
||||
debugPrint("%s: FLEEING: Can't possibly get closer to Target!", critterGetName(attacker));
|
||||
_ai_run_away(attacker, defender);
|
||||
return 0;
|
||||
}
|
||||
|
||||
taunt = false;
|
||||
if (_ai_attack(a1, a2, hitMode) == -1 || weaponGetActionPointCost(a1, hitMode, 0) > a1->data.critter.combat.ap) {
|
||||
if (_ai_attack(attacker, defender, hitMode) == -1 || weaponGetActionPointCost(attacker, hitMode, 0) > attacker->data.critter.combat.ap) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (_ai_attack(a1, a2, hitMode) == -1 || weaponGetActionPointCost(a1, hitMode, 0) > a1->data.critter.combat.ap) {
|
||||
if (_ai_attack(attacker, defender, hitMode) == -1 || weaponGetActionPointCost(attacker, hitMode, 0) > attacker->data.critter.combat.ap) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1370,7 +1370,7 @@ char* gameSoundBuildInterfaceName(const char* a1)
|
|||
// 0x451760
|
||||
char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* target)
|
||||
{
|
||||
int v6;
|
||||
int soundVariant;
|
||||
char weaponSoundCode;
|
||||
char effectTypeCode;
|
||||
char materialCode;
|
||||
|
@ -1384,12 +1384,12 @@ char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* ta
|
|||
if (hitMode != HIT_MODE_LEFT_WEAPON_PRIMARY
|
||||
&& hitMode != HIT_MODE_RIGHT_WEAPON_PRIMARY
|
||||
&& hitMode != HIT_MODE_PUNCH) {
|
||||
v6 = 2;
|
||||
soundVariant = 2;
|
||||
} else {
|
||||
v6 = 1;
|
||||
soundVariant = 1;
|
||||
}
|
||||
} else {
|
||||
v6 = 1;
|
||||
soundVariant = 1;
|
||||
}
|
||||
|
||||
int damageType = weaponGetDamageType(NULL, weapon);
|
||||
|
@ -1438,7 +1438,7 @@ char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* ta
|
|||
}
|
||||
}
|
||||
|
||||
snprintf(_sfx_file_name, sizeof(_sfx_file_name), "W%c%c%1d%cXX%1d", effectTypeCode, weaponSoundCode, v6, materialCode, 1);
|
||||
snprintf(_sfx_file_name, sizeof(_sfx_file_name), "W%c%c%1d%cXX%1d", effectTypeCode, weaponSoundCode, soundVariant, materialCode, 1);
|
||||
compat_strupr(_sfx_file_name);
|
||||
return _sfx_file_name;
|
||||
}
|
||||
|
|
|
@ -31,13 +31,13 @@ static int _outputStr(char* a1);
|
|||
static int _checkWait(Program* program);
|
||||
static char* programGetCurrentProcedureName(Program* s);
|
||||
static opcode_t stackReadInt16(unsigned char* data, int pos);
|
||||
static int stackReadInt32(unsigned char* a1, int a2);
|
||||
static void stackWriteInt16(int value, unsigned char* a2, int a3);
|
||||
static void stackWriteInt32(int value, unsigned char* stack, int pos);
|
||||
static void stackPushInt16(unsigned char* a1, int* a2, int value);
|
||||
static void stackPushInt32(unsigned char* a1, int* a2, int value);
|
||||
static int stackPopInt32(unsigned char* a1, int* a2);
|
||||
static opcode_t stackPopInt16(unsigned char* a1, int* a2);
|
||||
static int stackReadInt32(unsigned char* data, int pos);
|
||||
static void stackWriteInt16(int value, unsigned char* data, int pos);
|
||||
static void stackWriteInt32(int value, unsigned char* data, int pos);
|
||||
static void stackPushInt16(unsigned char* data, int* pointer, int value);
|
||||
static void stackPushInt32(unsigned char* data, int* pointer, int value);
|
||||
static int stackPopInt32(unsigned char* data, int* pointer);
|
||||
static opcode_t stackPopInt16(unsigned char* data, int* pointer);
|
||||
static void _interpretIncStringRef(Program* program, opcode_t opcode, int value);
|
||||
static void programReturnStackPushInt16(Program* program, int value);
|
||||
static opcode_t programReturnStackPopInt16(Program* program);
|
||||
|
@ -51,7 +51,7 @@ static void opPush(Program* program);
|
|||
static void opPushBase(Program* program);
|
||||
static void opPopBase(Program* program);
|
||||
static void opPopToBase(Program* program);
|
||||
static void op802C(Program* program);
|
||||
static void opSetGlobal(Program* program);
|
||||
static void opDump(Program* program);
|
||||
static void opDelayedCall(Program* program);
|
||||
static void opConditionalCall(Program* program);
|
||||
|
@ -230,17 +230,17 @@ static char* programGetCurrentProcedureName(Program* program)
|
|||
int procedureCount = stackReadInt32(program->procedures, 0);
|
||||
unsigned char* ptr = program->procedures + 4;
|
||||
|
||||
int procedureOffset = stackReadInt32(ptr, 16);
|
||||
int identifierOffset = stackReadInt32(ptr, 0);
|
||||
int procedureOffset = stackReadInt32(ptr, offsetof(Procedure, bodyOffset));
|
||||
int identifierOffset = stackReadInt32(ptr, offsetof(Procedure, nameOffset));
|
||||
|
||||
for (int index = 0; index < procedureCount; index++) {
|
||||
int nextProcedureOffset = stackReadInt32(ptr + 24, 16);
|
||||
int nextProcedureOffset = stackReadInt32(ptr + 24, offsetof(Procedure, bodyOffset));
|
||||
if (program->instructionPointer >= procedureOffset && program->instructionPointer < nextProcedureOffset) {
|
||||
return (char*)(program->identifiers + identifierOffset);
|
||||
}
|
||||
|
||||
ptr += 24;
|
||||
identifierOffset = stackReadInt32(ptr, 0);
|
||||
identifierOffset = stackReadInt32(ptr, offsetof(Procedure, nameOffset));
|
||||
}
|
||||
|
||||
return _aCouldnTFindPro;
|
||||
|
@ -712,7 +712,7 @@ static void opPopToBase(Program* program)
|
|||
}
|
||||
|
||||
// 0x467DE0
|
||||
static void op802C(Program* program)
|
||||
static void opSetGlobal(Program* program)
|
||||
{
|
||||
program->basePointer = program->stackValues->size();
|
||||
}
|
||||
|
@ -745,10 +745,10 @@ static void opDelayedCall(Program* program)
|
|||
delay += 1000 * _timerFunc() / _timerTick;
|
||||
}
|
||||
|
||||
int flags = stackReadInt32(procedure_ptr, 4);
|
||||
int flags = stackReadInt32(procedure_ptr, offsetof(Procedure, flags));
|
||||
|
||||
stackWriteInt32(delay, procedure_ptr, 8);
|
||||
stackWriteInt32(flags | PROCEDURE_FLAG_TIMED, procedure_ptr, 4);
|
||||
stackWriteInt32(delay, procedure_ptr, offsetof(Procedure, time));
|
||||
stackWriteInt32(flags | PROCEDURE_FLAG_TIMED, procedure_ptr, offsetof(Procedure, flags));
|
||||
}
|
||||
|
||||
// 0x468034
|
||||
|
@ -761,10 +761,10 @@ static void opConditionalCall(Program* program)
|
|||
}
|
||||
|
||||
unsigned char* procedure_ptr = program->procedures + 4 + 24 * data[0];
|
||||
int flags = stackReadInt32(procedure_ptr, 4);
|
||||
int flags = stackReadInt32(procedure_ptr, offsetof(Procedure, flags));
|
||||
|
||||
stackWriteInt32(flags | PROCEDURE_FLAG_CONDITIONAL, procedure_ptr, 4);
|
||||
stackWriteInt32(data[1], procedure_ptr, 12);
|
||||
stackWriteInt32(flags | PROCEDURE_FLAG_CONDITIONAL, procedure_ptr, offsetof(Procedure, flags));
|
||||
stackWriteInt32(data[1], procedure_ptr, offsetof(Procedure, conditionOffset));
|
||||
}
|
||||
|
||||
// 0x46817C
|
||||
|
@ -788,9 +788,9 @@ static void opCancel(Program* program)
|
|||
}
|
||||
|
||||
Procedure* proc = (Procedure*)(program->procedures + 4 + data * sizeof(*proc));
|
||||
proc->field_4 = 0;
|
||||
proc->field_8 = 0;
|
||||
proc->field_C = 0;
|
||||
proc->flags = 0;
|
||||
proc->time = 0;
|
||||
proc->conditionOffset = 0;
|
||||
}
|
||||
|
||||
// 0x468330
|
||||
|
@ -802,9 +802,9 @@ static void opCancelAll(Program* program)
|
|||
// TODO: Original code uses different approach, check.
|
||||
Procedure* proc = (Procedure*)(program->procedures + 4 + index * sizeof(*proc));
|
||||
|
||||
proc->field_4 = 0;
|
||||
proc->field_8 = 0;
|
||||
proc->field_C = 0;
|
||||
proc->flags = 0;
|
||||
proc->time = 0;
|
||||
proc->conditionOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2030,12 +2030,12 @@ static void opCall(Program* program)
|
|||
|
||||
unsigned char* ptr = program->procedures + 4 + 24 * value;
|
||||
|
||||
int flags = stackReadInt32(ptr, 4);
|
||||
if ((flags & 4) != 0) {
|
||||
int flags = stackReadInt32(ptr, offsetof(Procedure, flags));
|
||||
if ((flags & PROCEDURE_FLAG_IMPORTED) != 0) {
|
||||
// TODO: Incomplete.
|
||||
} else {
|
||||
program->instructionPointer = stackReadInt32(ptr, 16);
|
||||
if ((flags & 0x10) != 0) {
|
||||
program->instructionPointer = stackReadInt32(ptr, offsetof(Procedure, bodyOffset));
|
||||
if ((flags & PROCEDURE_FLAG_CRITICAL) != 0) {
|
||||
program->flags |= PROGRAM_FLAG_CRITICAL_SECTION;
|
||||
}
|
||||
}
|
||||
|
@ -2238,7 +2238,7 @@ static void opFetchProcedureAddress(Program* program)
|
|||
{
|
||||
int procedureIndex = programStackPopInteger(program);
|
||||
|
||||
int address = stackReadInt32(program->procedures + 4 + sizeof(Procedure) * procedureIndex, 16);
|
||||
int address = stackReadInt32(program->procedures + 4 + sizeof(Procedure) * procedureIndex, offsetof(Procedure, bodyOffset));
|
||||
programStackPushInteger(program, address);
|
||||
}
|
||||
|
||||
|
@ -2298,8 +2298,8 @@ static void opExportProcedure(Program* program)
|
|||
|
||||
unsigned char* proc_ptr = program->procedures + 4 + sizeof(Procedure) * procedureIndex;
|
||||
|
||||
char* procedureName = programGetIdentifier(program, stackReadInt32(proc_ptr, 0));
|
||||
int procedureAddress = stackReadInt32(proc_ptr, 16);
|
||||
char* procedureName = programGetIdentifier(program, stackReadInt32(proc_ptr, offsetof(Procedure, nameOffset)));
|
||||
int procedureAddress = stackReadInt32(proc_ptr, offsetof(Procedure, bodyOffset));
|
||||
|
||||
if (externalProcedureCreate(program, procedureName, procedureAddress, argumentCount) != 0) {
|
||||
char err[256];
|
||||
|
@ -2468,9 +2468,9 @@ static void opCheckProcedureArgumentCount(Program* program)
|
|||
int expectedArgumentCount = programStackPopInteger(program);
|
||||
int procedureIndex = programStackPopInteger(program);
|
||||
|
||||
int actualArgumentCount = stackReadInt32(program->procedures + 4 + 24 * procedureIndex, 20);
|
||||
int actualArgumentCount = stackReadInt32(program->procedures + 4 + 24 * procedureIndex, offsetof(Procedure, argCount));
|
||||
if (actualArgumentCount != expectedArgumentCount) {
|
||||
const char* identifier = programGetIdentifier(program, stackReadInt32(program->procedures + 4 + 24 * procedureIndex, 0));
|
||||
const char* identifier = programGetIdentifier(program, stackReadInt32(program->procedures + 4 + 24 * procedureIndex, offsetof(Procedure, nameOffset)));
|
||||
char err[260];
|
||||
snprintf(err, sizeof(err), "Wrong number of args to procedure %s\n", identifier);
|
||||
programFatalError(err);
|
||||
|
@ -2491,7 +2491,7 @@ static void opLookupStringProc(Program* program)
|
|||
// Start with 1 since we've skipped main procedure, which is always at
|
||||
// index 0.
|
||||
for (int index = 1; index < procedureCount; index++) {
|
||||
int offset = stackReadInt32(procedurePtr, 0);
|
||||
int offset = stackReadInt32(procedurePtr, offsetof(Procedure, nameOffset));
|
||||
const char* procedureName = programGetIdentifier(program, offset);
|
||||
if (compat_stricmp(procedureName, procedureNameToLookup) == 0) {
|
||||
programStackPushInteger(program, index);
|
||||
|
@ -2556,7 +2556,7 @@ void interpreterRegisterOpcodeHandlers()
|
|||
interpreterRegisterOpcode(OPCODE_POP_BASE, opPopBase);
|
||||
interpreterRegisterOpcode(OPCODE_POP_TO_BASE, opPopToBase);
|
||||
interpreterRegisterOpcode(OPCODE_PUSH_BASE, opPushBase);
|
||||
interpreterRegisterOpcode(OPCODE_SET_GLOBAL, op802C);
|
||||
interpreterRegisterOpcode(OPCODE_SET_GLOBAL, opSetGlobal);
|
||||
interpreterRegisterOpcode(OPCODE_FETCH_PROCEDURE_ADDRESS, opFetchProcedureAddress);
|
||||
interpreterRegisterOpcode(OPCODE_DUMP, opDump);
|
||||
interpreterRegisterOpcode(OPCODE_IF, opIf);
|
||||
|
@ -2776,9 +2776,9 @@ void _executeProc(Program* program, int procedureIndex)
|
|||
char err[256];
|
||||
|
||||
procedurePtr = program->procedures + 4 + sizeof(Procedure) * procedureIndex;
|
||||
procedureFlags = stackReadInt32(procedurePtr, 4);
|
||||
procedureFlags = stackReadInt32(procedurePtr, offsetof(Procedure, flags));
|
||||
if ((procedureFlags & PROCEDURE_FLAG_IMPORTED) != 0) {
|
||||
procedureIdentifier = programGetIdentifier(program, stackReadInt32(procedurePtr, 0));
|
||||
procedureIdentifier = programGetIdentifier(program, stackReadInt32(procedurePtr, offsetof(Procedure, nameOffset)));
|
||||
externalProgram = externalProcedureGetProgram(procedureIdentifier, &externalProcedureAddress, &externalProcedureArgumentCount);
|
||||
if (externalProgram != NULL) {
|
||||
if (externalProcedureArgumentCount == 0) {
|
||||
|
@ -2795,7 +2795,7 @@ void _executeProc(Program* program, int procedureIndex)
|
|||
_setupExternalCall(program, externalProgram, externalProcedureAddress, 28);
|
||||
|
||||
procedurePtr = externalProgram->procedures + 4 + sizeof(Procedure) * procedureIndex;
|
||||
procedureFlags = stackReadInt32(procedurePtr, 4);
|
||||
procedureFlags = stackReadInt32(procedurePtr, offsetof(Procedure, flags));
|
||||
|
||||
if ((procedureFlags & PROCEDURE_FLAG_CRITICAL) != 0) {
|
||||
// NOTE: Uninline.
|
||||
|
@ -2803,7 +2803,7 @@ void _executeProc(Program* program, int procedureIndex)
|
|||
_interpret(externalProgram, 0);
|
||||
}
|
||||
} else {
|
||||
procedureAddress = stackReadInt32(procedurePtr, 16);
|
||||
procedureAddress = stackReadInt32(procedurePtr, offsetof(Procedure, bodyOffset));
|
||||
|
||||
// NOTE: Uninline.
|
||||
_setupCall(program, procedureAddress, 20);
|
||||
|
@ -2826,7 +2826,7 @@ int programFindProcedure(Program* program, const char* name)
|
|||
|
||||
unsigned char* ptr = program->procedures + 4;
|
||||
for (int index = 0; index < procedureCount; index++) {
|
||||
int identifierOffset = stackReadInt32(ptr, offsetof(Procedure, field_0));
|
||||
int identifierOffset = stackReadInt32(ptr, offsetof(Procedure, nameOffset));
|
||||
if (compat_stricmp((char*)(program->identifiers + identifierOffset), name) == 0) {
|
||||
return index;
|
||||
}
|
||||
|
@ -2851,10 +2851,10 @@ void _executeProcedure(Program* program, int procedureIndex)
|
|||
jmp_buf env;
|
||||
|
||||
procedurePtr = program->procedures + 4 + sizeof(Procedure) * procedureIndex;
|
||||
procedureFlags = stackReadInt32(procedurePtr, 4);
|
||||
procedureFlags = stackReadInt32(procedurePtr, offsetof(Procedure, flags));
|
||||
|
||||
if ((procedureFlags & PROCEDURE_FLAG_IMPORTED) != 0) {
|
||||
procedureIdentifier = programGetIdentifier(program, stackReadInt32(procedurePtr, 0));
|
||||
procedureIdentifier = programGetIdentifier(program, stackReadInt32(procedurePtr, offsetof(Procedure, nameOffset)));
|
||||
externalProgram = externalProcedureGetProgram(procedureIdentifier, &externalProcedureAddress, &externalProcedureArgumentCount);
|
||||
if (externalProgram != NULL) {
|
||||
if (externalProcedureArgumentCount == 0) {
|
||||
|
@ -2872,7 +2872,7 @@ void _executeProcedure(Program* program, int procedureIndex)
|
|||
_interpretOutput(err);
|
||||
}
|
||||
} else {
|
||||
procedureAddress = stackReadInt32(procedurePtr, 16);
|
||||
procedureAddress = stackReadInt32(procedurePtr, offsetof(Procedure, bodyOffset));
|
||||
|
||||
// NOTE: Uninline.
|
||||
_setupCall(program, procedureAddress, 24);
|
||||
|
@ -2908,14 +2908,14 @@ static void _doEvents()
|
|||
|
||||
procedurePtr = programListNode->program->procedures + 4;
|
||||
for (procedureIndex = 0; procedureIndex < procedureCount; procedureIndex++) {
|
||||
procedureFlags = stackReadInt32(procedurePtr, 4);
|
||||
procedureFlags = stackReadInt32(procedurePtr, offsetof(Procedure, flags));
|
||||
if ((procedureFlags & PROCEDURE_FLAG_CONDITIONAL) != 0) {
|
||||
memcpy(env, programListNode->program, sizeof(env));
|
||||
oldProgramFlags = programListNode->program->flags;
|
||||
oldInstructionPointer = programListNode->program->instructionPointer;
|
||||
|
||||
programListNode->program->flags = 0;
|
||||
programListNode->program->instructionPointer = stackReadInt32(procedurePtr, 12);
|
||||
programListNode->program->instructionPointer = stackReadInt32(procedurePtr, offsetof(Procedure, conditionOffset));
|
||||
_interpret(programListNode->program, -1);
|
||||
|
||||
if ((programListNode->program->flags & PROGRAM_FLAG_0x04) == 0) {
|
||||
|
@ -2926,16 +2926,16 @@ static void _doEvents()
|
|||
|
||||
if (data != 0) {
|
||||
// NOTE: Uninline.
|
||||
stackWriteInt32(0, procedurePtr, 4);
|
||||
stackWriteInt32(0, procedurePtr, offsetof(Procedure, flags));
|
||||
_executeProc(programListNode->program, procedureIndex);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(programListNode->program, env, sizeof(env));
|
||||
} else if ((procedureFlags & PROCEDURE_FLAG_TIMED) != 0) {
|
||||
if ((unsigned int)stackReadInt32(procedurePtr, 8) < time) {
|
||||
if ((unsigned int)stackReadInt32(procedurePtr, offsetof(Procedure, time)) < time) {
|
||||
// NOTE: Uninline.
|
||||
stackWriteInt32(0, procedurePtr, 4);
|
||||
stackWriteInt32(0, procedurePtr, offsetof(Procedure, flags));
|
||||
_executeProc(programListNode->program, procedureIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,12 +133,12 @@ enum RawValueType {
|
|||
typedef unsigned short opcode_t;
|
||||
|
||||
typedef struct Procedure {
|
||||
int field_0;
|
||||
int field_4;
|
||||
int field_8;
|
||||
int field_C;
|
||||
int field_10;
|
||||
int field_14;
|
||||
int nameOffset;
|
||||
int flags;
|
||||
int time;
|
||||
int conditionOffset;
|
||||
int bodyOffset;
|
||||
int argCount;
|
||||
} Procedure;
|
||||
|
||||
class ProgramValue {
|
||||
|
|
|
@ -2375,10 +2375,10 @@ bool _obj_occupied(int tile, int elevation)
|
|||
}
|
||||
|
||||
// 0x48B848
|
||||
Object* _obj_blocking_at(Object* a1, int tile, int elev)
|
||||
Object* _obj_blocking_at(Object* excludeObj, int tile, int elev)
|
||||
{
|
||||
ObjectListNode* objectListNode;
|
||||
Object* v7;
|
||||
Object* obj;
|
||||
int type;
|
||||
|
||||
if (!hexGridTileIsValid(tile)) {
|
||||
|
@ -2387,14 +2387,14 @@ Object* _obj_blocking_at(Object* a1, int tile, int elev)
|
|||
|
||||
objectListNode = gObjectListHeadByTile[tile];
|
||||
while (objectListNode != NULL) {
|
||||
v7 = objectListNode->obj;
|
||||
if (v7->elevation == elev) {
|
||||
if ((v7->flags & OBJECT_HIDDEN) == 0 && (v7->flags & OBJECT_NO_BLOCK) == 0 && v7 != a1) {
|
||||
type = FID_TYPE(v7->fid);
|
||||
obj = objectListNode->obj;
|
||||
if (obj->elevation == elev) {
|
||||
if ((obj->flags & OBJECT_HIDDEN) == 0 && (obj->flags & OBJECT_NO_BLOCK) == 0 && obj != excludeObj) {
|
||||
type = FID_TYPE(obj->fid);
|
||||
if (type == OBJ_TYPE_CRITTER
|
||||
|| type == OBJ_TYPE_SCENERY
|
||||
|| type == OBJ_TYPE_WALL) {
|
||||
return v7;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2406,15 +2406,15 @@ Object* _obj_blocking_at(Object* a1, int tile, int elev)
|
|||
if (hexGridTileIsValid(neighboor)) {
|
||||
objectListNode = gObjectListHeadByTile[neighboor];
|
||||
while (objectListNode != NULL) {
|
||||
v7 = objectListNode->obj;
|
||||
if ((v7->flags & OBJECT_MULTIHEX) != 0) {
|
||||
if (v7->elevation == elev) {
|
||||
if ((v7->flags & OBJECT_HIDDEN) == 0 && (v7->flags & OBJECT_NO_BLOCK) == 0 && v7 != a1) {
|
||||
type = FID_TYPE(v7->fid);
|
||||
obj = objectListNode->obj;
|
||||
if ((obj->flags & OBJECT_MULTIHEX) != 0) {
|
||||
if (obj->elevation == elev) {
|
||||
if ((obj->flags & OBJECT_HIDDEN) == 0 && (obj->flags & OBJECT_NO_BLOCK) == 0 && obj != excludeObj) {
|
||||
type = FID_TYPE(obj->fid);
|
||||
if (type == OBJ_TYPE_CRITTER
|
||||
|| type == OBJ_TYPE_SCENERY
|
||||
|| type == OBJ_TYPE_WALL) {
|
||||
return v7;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2428,7 +2428,7 @@ Object* _obj_blocking_at(Object* a1, int tile, int elev)
|
|||
}
|
||||
|
||||
// 0x48B930
|
||||
Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev)
|
||||
Object* _obj_shoot_blocking_at(Object* excludeObj, int tile, int elev)
|
||||
{
|
||||
if (!hexGridTileIsValid(tile)) {
|
||||
return NULL;
|
||||
|
@ -2439,7 +2439,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev)
|
|||
Object* candidate = objectListItem->obj;
|
||||
if (candidate->elevation == elev) {
|
||||
unsigned int flags = candidate->flags;
|
||||
if ((flags & OBJECT_HIDDEN) == 0 && ((flags & OBJECT_NO_BLOCK) == 0 || (flags & OBJECT_SHOOT_THRU) == 0) && candidate != obj) {
|
||||
if ((flags & OBJECT_HIDDEN) == 0 && ((flags & OBJECT_NO_BLOCK) == 0 || (flags & OBJECT_SHOOT_THRU) == 0) && candidate != excludeObj) {
|
||||
int type = FID_TYPE(candidate->fid);
|
||||
// SFALL: Fix to prevent corpses from blocking line of fire.
|
||||
if ((type == OBJ_TYPE_CRITTER && !critterIsDead(candidate))
|
||||
|
@ -2464,7 +2464,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev)
|
|||
unsigned int flags = candidate->flags;
|
||||
if ((flags & OBJECT_MULTIHEX) != 0) {
|
||||
if (candidate->elevation == elev) {
|
||||
if ((flags & OBJECT_HIDDEN) == 0 && (flags & OBJECT_NO_BLOCK) == 0 && candidate != obj) {
|
||||
if ((flags & OBJECT_HIDDEN) == 0 && (flags & OBJECT_NO_BLOCK) == 0 && candidate != excludeObj) {
|
||||
int type = FID_TYPE(candidate->fid);
|
||||
// SFALL: Fix to prevent corpses from blocking line of
|
||||
// fire.
|
||||
|
@ -2484,7 +2484,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev)
|
|||
}
|
||||
|
||||
// 0x48BA20
|
||||
Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation)
|
||||
Object* _obj_ai_blocking_at(Object* excludeObj, int tile, int elevation)
|
||||
{
|
||||
if (!hexGridTileIsValid(tile)) {
|
||||
return NULL;
|
||||
|
@ -2496,7 +2496,7 @@ Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation)
|
|||
if (object->elevation == elevation) {
|
||||
if ((object->flags & OBJECT_HIDDEN) == 0
|
||||
&& (object->flags & OBJECT_NO_BLOCK) == 0
|
||||
&& object != a1) {
|
||||
&& object != excludeObj) {
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
if (objectType == OBJ_TYPE_CRITTER
|
||||
|| objectType == OBJ_TYPE_SCENERY
|
||||
|
@ -2525,7 +2525,7 @@ Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation)
|
|||
if (object->elevation == elevation) {
|
||||
if ((object->flags & OBJECT_HIDDEN) == 0
|
||||
&& (object->flags & OBJECT_NO_BLOCK) == 0
|
||||
&& object != a1) {
|
||||
&& object != excludeObj) {
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
if (objectType == OBJ_TYPE_CRITTER
|
||||
|| objectType == OBJ_TYPE_SCENERY
|
||||
|
@ -2571,7 +2571,7 @@ int _obj_scroll_blocking_at(int tile, int elev)
|
|||
}
|
||||
|
||||
// 0x48BB88
|
||||
Object* _obj_sight_blocking_at(Object* a1, int tile, int elevation)
|
||||
Object* _obj_sight_blocking_at(Object* excludeObj, int tile, int elevation)
|
||||
{
|
||||
ObjectListNode* objectListNode = gObjectListHeadByTile[tile];
|
||||
while (objectListNode != NULL) {
|
||||
|
@ -2579,7 +2579,7 @@ Object* _obj_sight_blocking_at(Object* a1, int tile, int elevation)
|
|||
if (object->elevation == elevation
|
||||
&& (object->flags & OBJECT_HIDDEN) == 0
|
||||
&& (object->flags & OBJECT_LIGHT_THRU) == 0
|
||||
&& object != a1) {
|
||||
&& object != excludeObj) {
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
if (objectType == OBJ_TYPE_SCENERY || objectType == OBJ_TYPE_WALL) {
|
||||
return object;
|
||||
|
|
|
@ -71,11 +71,11 @@ Object* objectFindFirstAtLocation(int elevation, int tile);
|
|||
Object* objectFindNextAtLocation();
|
||||
void objectGetRect(Object* obj, Rect* rect);
|
||||
bool _obj_occupied(int tile_num, int elev);
|
||||
Object* _obj_blocking_at(Object* a1, int tile_num, int elev);
|
||||
Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev);
|
||||
Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation);
|
||||
Object* _obj_blocking_at(Object* excludeObj, int tile_num, int elev);
|
||||
Object* _obj_shoot_blocking_at(Object* excludeObj, int tile, int elev);
|
||||
Object* _obj_ai_blocking_at(Object* excludeObj, int tile, int elevation);
|
||||
int _obj_scroll_blocking_at(int tile_num, int elev);
|
||||
Object* _obj_sight_blocking_at(Object* a1, int tile_num, int elev);
|
||||
Object* _obj_sight_blocking_at(Object* excludeObj, int tile_num, int elev);
|
||||
int objectGetDistanceBetween(Object* object1, Object* object2);
|
||||
int objectGetDistanceBetweenTiles(Object* object1, int tile1, Object* object2, int tile2);
|
||||
int objectListCreate(int tile, int elevation, int objectType, Object*** objectsPtr);
|
||||
|
|
|
@ -344,18 +344,19 @@ bool queueHasEvent(Object* owner, int eventType)
|
|||
int queueProcessEvents()
|
||||
{
|
||||
unsigned int time = gameTimeGetTime();
|
||||
int v1 = 0;
|
||||
// TODO: this is 0 or 1, but in some cases -1. Probably needs to be bool.
|
||||
int stopProcess = 0;
|
||||
|
||||
while (gQueueListHead != NULL) {
|
||||
QueueListNode* queueListNode = gQueueListHead;
|
||||
if (time < queueListNode->time || v1 != 0) {
|
||||
if (time < queueListNode->time || stopProcess != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
gQueueListHead = queueListNode->next;
|
||||
|
||||
EventTypeDescription* eventTypeDescription = &(gEventTypeDescriptions[queueListNode->type]);
|
||||
v1 = eventTypeDescription->handlerProc(queueListNode->owner, queueListNode->data);
|
||||
stopProcess = eventTypeDescription->handlerProc(queueListNode->owner, queueListNode->data);
|
||||
|
||||
if (eventTypeDescription->freeProc != NULL) {
|
||||
eventTypeDescription->freeProc(queueListNode->data);
|
||||
|
@ -364,7 +365,7 @@ int queueProcessEvents()
|
|||
internal_free(queueListNode);
|
||||
}
|
||||
|
||||
return v1;
|
||||
return stopProcess;
|
||||
}
|
||||
|
||||
// 0x4A2748
|
||||
|
|
|
@ -405,7 +405,7 @@ int gameTimeScheduleUpdateEvent()
|
|||
int gameTimeEventProcess(Object* obj, void* data)
|
||||
{
|
||||
int movie_index;
|
||||
int v4;
|
||||
int stopProcess;
|
||||
|
||||
movie_index = -1;
|
||||
|
||||
|
@ -421,17 +421,17 @@ int gameTimeEventProcess(Object* obj, void* data)
|
|||
_scriptsCheckGameEvents(&movie_index, -1);
|
||||
}
|
||||
|
||||
v4 = _critter_check_rads(gDude);
|
||||
stopProcess = _critter_check_rads(gDude);
|
||||
|
||||
_queue_clear_type(4, 0);
|
||||
|
||||
gameTimeScheduleUpdateEvent();
|
||||
|
||||
if (movie_index != -1) {
|
||||
v4 = 1;
|
||||
stopProcess = 1;
|
||||
}
|
||||
|
||||
return v4;
|
||||
return stopProcess;
|
||||
}
|
||||
|
||||
// 0x4A3690
|
||||
|
|
Loading…
Reference in New Issue