diff --git a/CMakeLists.txt b/CMakeLists.txt index d722207..47070a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC "src/palette.h" "src/party_member.cc" "src/party_member.h" + "src/pcx.cc" + "src/pcx.h" "src/perk_defs.h" "src/perk.cc" "src/perk.h" diff --git a/src/actions.cc b/src/actions.cc index f32e467..1da504f 100644 --- a/src/actions.cc +++ b/src/actions.cc @@ -86,12 +86,12 @@ static int _compute_dmg_damage(int min, int max, Object* obj, int* a4, int damag // 0x410468 int actionKnockdown(Object* obj, int* anim, int maxDistance, int rotation, int delay) { - if (_critter_flag_check(obj->pid, 0x4000)) { + if (_critter_flag_check(obj->pid, CRITTER_FLAG_0x4000)) { return -1; } if (*anim == ANIM_FALL_FRONT) { - int fid = buildFid(1, obj->fid & 0xFFF, *anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, *anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); if (!artExists(fid)) { *anim = ANIM_FALL_BACK; } @@ -113,17 +113,17 @@ int actionKnockdown(Object* obj, int* anim, int maxDistance, int rotation, int d } const char* soundEffectName = sfxBuildCharName(obj, *anim, CHARACTER_SOUND_EFFECT_KNOCKDOWN); - reg_anim_play_sfx(obj, soundEffectName, delay); + animationRegisterPlaySoundEffect(obj, soundEffectName, delay); // TODO: Check, probably step back because we've started with 1? distance--; if (distance <= 0) { tile = obj->tile; - reg_anim_animate(obj, *anim, 0); + animationRegisterAnimate(obj, *anim, 0); } else { tile = tileGetTileInDirection(obj->tile, rotation, distance); - reg_anim_knockdown(obj, tile, obj->elevation, *anim, 0); + animationRegisterMoveToTileStraightAndWaitForComplete(obj, tile, obj->elevation, *anim, 0); } return tile; @@ -148,9 +148,9 @@ int _action_blood(Object* obj, int anim, int delay) return anim; } - int fid = buildFid(1, obj->fid & 0xFFF, bloodyAnim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, bloodyAnim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); if (artExists(fid)) { - reg_anim_animate(obj, bloodyAnim, delay); + animationRegisterAnimate(obj, bloodyAnim, delay); } else { bloodyAnim = anim; } @@ -186,7 +186,7 @@ int _pick_death(Object* attacker, Object* defender, Object* weapon, int damage, int violenceLevel = VIOLENCE_LEVEL_MAXIMUM_BLOOD; configGetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, &violenceLevel); - if (_critter_flag_check(defender->pid, 0x1000)) { + if (_critter_flag_check(defender->pid, CRITTER_FLAG_0x1000)) { return _check_death(defender, ANIM_EXPLODED_TO_NOTHING, VIOLENCE_LEVEL_NORMAL, isFallingBack); } @@ -244,7 +244,7 @@ int _check_death(Object* obj, int anim, int minViolenceLevel, bool isFallingBack int violenceLevel = VIOLENCE_LEVEL_MAXIMUM_BLOOD; configGetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, &violenceLevel); if (violenceLevel >= minViolenceLevel) { - fid = buildFid(1, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); if (artExists(fid)) { return anim; } @@ -254,7 +254,7 @@ int _check_death(Object* obj, int anim, int minViolenceLevel, bool isFallingBack return ANIM_FALL_BACK; } - fid = buildFid(1, obj->fid & 0xFFF, ANIM_FALL_FRONT, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, ANIM_FALL_FRONT, (obj->fid & 0xF000) >> 12, obj->rotation + 1); if (artExists(fid)) { return ANIM_FALL_BACK; } @@ -277,14 +277,14 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b int fid; const char* sfx_name; - if (_critter_flag_check(a1->pid, 0x4000)) { + if (_critter_flag_check(a1->pid, CRITTER_FLAG_0x4000)) { knockbackDistance = 0; } - anim = (a1->fid & 0xFF0000) >> 16; + anim = FID_ANIM_TYPE(a1->fid); if (!_critter_is_prone(a1)) { if ((flags & DAM_DEAD) != 0) { - fid = buildFid(5, 10, 0, 0, 0); + fid = buildFid(OBJ_TYPE_MISC, 10, 0, 0, 0); if (fid == a9->fid) { anim = _check_death(a1, ANIM_EXPLODED_TO_NOTHING, VIOLENCE_LEVEL_MAXIMUM_BLOOD, isFallingBack); } else if (a9->pid == PROTO_ID_0x20001EB) { @@ -301,22 +301,22 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b anim = _action_blood(a1, anim, -1); } else { sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_DIE); - reg_anim_play_sfx(a1, sfx_name, a10); + animationRegisterPlaySoundEffect(a1, sfx_name, a10); anim = _pick_fall(a1, anim); - reg_anim_animate(a1, anim, 0); + animationRegisterAnimate(a1, anim, 0); if (anim == ANIM_FALL_FRONT || anim == ANIM_FALL_BACK) { anim = _action_blood(a1, anim, -1); } } } else { - fid = buildFid(1, a1->fid & 0xFFF, ANIM_FIRE_DANCE, (a1->fid & 0xF000) >> 12, a1->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_FIRE_DANCE, (a1->fid & 0xF000) >> 12, a1->rotation + 1); if (artExists(fid)) { sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx_name, a10); + animationRegisterPlaySoundEffect(a1, sfx_name, a10); - reg_anim_animate(a1, anim, 0); + animationRegisterAnimate(a1, anim, 0); int randomDistance = randomBetween(2, 5); int randomRotation = randomBetween(0, 5); @@ -326,8 +326,8 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b Object* v35 = NULL; _make_straight_path(a1, a1->tile, tile, NULL, &v35, 4); if (v35 == NULL) { - reg_anim_set_rotation_to_tile(a1, tile); - reg_anim_2(a1, tile, a1->elevation, anim, 0); + animationRegisterRotateToTile(a1, tile); + animationRegisterMoveToTileStraight(a1, tile, a1->elevation, anim, 0); break; } randomDistance--; @@ -336,45 +336,45 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b anim = ANIM_BURNED_TO_NOTHING; sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx_name, -1); - reg_anim_animate(a1, anim, 0); + animationRegisterPlaySoundEffect(a1, sfx_name, -1); + animationRegisterAnimate(a1, anim, 0); } } else { if ((flags & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0) { anim = isFallingBack ? ANIM_FALL_BACK : ANIM_FALL_FRONT; sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx_name, a10); + animationRegisterPlaySoundEffect(a1, sfx_name, a10); if (knockbackDistance != 0) { actionKnockdown(a1, &anim, knockbackDistance, knockbackRotation, 0); } else { anim = _pick_fall(a1, anim); - reg_anim_animate(a1, anim, 0); + animationRegisterAnimate(a1, anim, 0); } - } else if ((flags & DAM_ON_FIRE) != 0 && artExists(buildFid(1, a1->fid & 0xFFF, ANIM_FIRE_DANCE, (a1->fid & 0xF000) >> 12, a1->rotation + 1))) { - reg_anim_animate(a1, ANIM_FIRE_DANCE, a10); + } else if ((flags & DAM_ON_FIRE) != 0 && artExists(buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_FIRE_DANCE, (a1->fid & 0xF000) >> 12, a1->rotation + 1))) { + animationRegisterAnimate(a1, ANIM_FIRE_DANCE, a10); - fid = buildFid(1, a1->fid & 0xFFF, ANIM_STAND, (a1->fid & 0xF000) >> 12, a1->rotation + 1); - reg_anim_17(a1, fid, -1); + fid = buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_STAND, (a1->fid & 0xF000) >> 12, a1->rotation + 1); + animationRegisterSetFid(a1, fid, -1); } else { if (knockbackDistance != 0) { anim = isFallingBack ? ANIM_FALL_BACK : ANIM_FALL_FRONT; actionKnockdown(a1, &anim, knockbackDistance, knockbackRotation, a10); if (anim == ANIM_FALL_BACK) { - reg_anim_animate(a1, ANIM_BACK_TO_STANDING, -1); + animationRegisterAnimate(a1, ANIM_BACK_TO_STANDING, -1); } else { - reg_anim_animate(a1, ANIM_PRONE_TO_STANDING, -1); + animationRegisterAnimate(a1, ANIM_PRONE_TO_STANDING, -1); } } else { - if (isFallingBack || !artExists(buildFid(1, a1->fid & 0xFFF, ANIM_HIT_FROM_BACK, (a1->fid & 0xF000) >> 12, a1->rotation + 1))) { + if (isFallingBack || !artExists(buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_HIT_FROM_BACK, (a1->fid & 0xF000) >> 12, a1->rotation + 1))) { anim = ANIM_HIT_FROM_FRONT; } else { anim = ANIM_HIT_FROM_BACK; } sfx_name = sfxBuildCharName(a1, anim, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx_name, a10); + animationRegisterPlaySoundEffect(a1, sfx_name, a10); - reg_anim_animate(a1, anim, 0); + animationRegisterAnimate(a1, anim, 0); } } } @@ -388,25 +388,25 @@ void _show_damage_to_object(Object* a1, int damage, int flags, Object* weapon, b if (weapon != NULL) { if ((flags & DAM_EXPLODE) != 0) { - reg_anim_11_1(a1, weapon, _obj_drop, -1); - fid = buildFid(5, 10, 0, 0, 0); - reg_anim_17(weapon, fid, 0); - reg_anim_6(weapon, ANIM_STAND, 0); + animationRegisterCallbackForced(a1, weapon, (AnimationCallback*)_obj_drop, -1); + fid = buildFid(OBJ_TYPE_MISC, 10, 0, 0, 0); + animationRegisterSetFid(weapon, fid, 0); + animationRegisterAnimateAndHide(weapon, ANIM_STAND, 0); sfx_name = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, a1); - reg_anim_play_sfx(weapon, sfx_name, 0); + animationRegisterPlaySoundEffect(weapon, sfx_name, 0); - reg_anim_hide(weapon); + animationRegisterHideObjectForced(weapon); } else if ((flags & DAM_DESTROY) != 0) { - reg_anim_11_1(a1, weapon, _internal_destroy, -1); + animationRegisterCallbackForced(a1, weapon, (AnimationCallback*)_internal_destroy, -1); } else if ((flags & DAM_DROP) != 0) { - reg_anim_11_1(a1, weapon, _obj_drop, -1); + animationRegisterCallbackForced(a1, weapon, (AnimationCallback*)_obj_drop, -1); } } if ((flags & DAM_DEAD) != 0) { // TODO: Get rid of casts. - reg_anim_11_1(a1, (Object*)anim, (AnimationProc*)_show_death, -1); + animationRegisterCallbackForced(a1, (void*)anim, (AnimationCallback*)_show_death, -1); } } @@ -419,7 +419,7 @@ int _show_death(Object* obj, int anim) objectGetRect(obj, &v8); if (anim < 48 && anim > 63) { - fid = buildFid(1, obj->fid & 0xFFF, anim + 28, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, anim + 28, (obj->fid & 0xF000) >> 12, obj->rotation + 1); if (objectSetFid(obj, fid, &v7) == 0) { rectUnion(&v8, &v7, &v8); } @@ -429,7 +429,7 @@ int _show_death(Object* obj, int anim) } } - if (_critter_flag_check(obj->pid, 2048) == 0) { + if (_critter_flag_check(obj->pid, CRITTER_FLAG_0x800) == 0) { obj->flags |= OBJECT_NO_BLOCK; if (_obj_toggle_flat(obj, &v7) == 0) { rectUnion(&v8, &v7, &v8); @@ -440,7 +440,7 @@ int _show_death(Object* obj, int anim) rectUnion(&v8, &v7, &v8); } - if (anim >= 30 && anim <= 31 && _critter_flag_check(obj->pid, 4096) == 0 && _critter_flag_check(obj->pid, 64) == 0) { + if (anim >= 30 && anim <= 31 && _critter_flag_check(obj->pid, CRITTER_FLAG_0x1000) == 0 && _critter_flag_check(obj->pid, CRITTER_FLAG_0x40) == 0) { _item_drop_all(obj, obj->tile); } @@ -458,14 +458,14 @@ int _show_damage_extras(Attack* attack) for (int index = 0; index < attack->extrasLength; index++) { Object* obj = attack->extras[index]; - if ((obj->fid & 0xF000000) >> 24 == 1) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_CRITTER) { int delta = attack->attacker->rotation - obj->rotation; if (delta < 0) { delta = -delta; } v6 = delta != 0 && delta != 1 && delta != 5; - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); _register_priority(1); v8 = critterGetAnimationForHitMode(attack->attacker, attack->hitMode); v9 = tileGetRotationTo(attack->attacker->tile, obj->tile); @@ -488,7 +488,7 @@ void _show_damage(Attack* attack, int a2, int a3) v5 = a3; for (int index = 0; index < attack->extrasLength; index++) { Object* object = attack->extras[index]; - if ((object->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(object->fid) == OBJ_TYPE_CRITTER) { reg_anim_26(2, v5); v5 = 0; } @@ -510,7 +510,7 @@ void _show_damage(Attack* attack, int a2, int a3) v15 = delta != 0 && delta != 1 && delta != 5; - if ((attack->defender->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(attack->defender->fid) == OBJ_TYPE_CRITTER) { if (attack->attacker->fid == 33554933) { v14 = tileGetRotationTo(attack->attacker->tile, attack->defender->tile); _show_damage_to_object(attack->defender, attack->defenderDamage, attack->defenderFlags, attack->weapon, v15, attack->defenderKnockback, v14, a2, attack->attacker, a3); @@ -569,10 +569,10 @@ int _action_melee(Attack* attack, int anim) const char* sfx_name; char sfx_name_temp[16]; - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); _register_priority(1); - fid = buildFid(1, attack->attacker->fid & 0xFFF, anim, (attack->attacker->fid & 0xF000) >> 12, attack->attacker->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, attack->attacker->fid & 0xFFF, anim, (attack->attacker->fid & 0xF000) >> 12, attack->attacker->rotation + 1); art = artLock(fid, &cache_entry); if (art != NULL) { v17 = artGetActionFrame(art); @@ -582,7 +582,7 @@ int _action_melee(Attack* attack, int anim) artUnlock(cache_entry); tileGetTileInDirection(attack->attacker->tile, attack->attacker->rotation, 1); - reg_anim_set_rotation_to_tile(attack->attacker, attack->defender->tile); + animationRegisterRotateToTile(attack->attacker, attack->defender->tile); delta = attack->attacker->rotation - attack->defender->rotation; if (delta < 0) { @@ -601,7 +601,7 @@ int _action_melee(Attack* attack, int anim) _combatai_msg(attack->attacker, attack, AI_MESSAGE_TYPE_ATTACK, 0); if (attack->attackerFlags & 0x0300) { - reg_anim_play_sfx(attack->attacker, sfx_name_temp, 0); + animationRegisterPlaySoundEffect(attack->attacker, sfx_name_temp, 0); if (anim != ANIM_THROW_PUNCH && anim != ANIM_KICK_LEG) { sfx_name = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, attack->weapon, attack->hitMode, attack->defender); } else { @@ -610,33 +610,33 @@ int _action_melee(Attack* attack, int anim) strcpy(sfx_name_temp, sfx_name); - reg_anim_animate(attack->attacker, anim, 0); - reg_anim_play_sfx(attack->attacker, sfx_name_temp, v17); + animationRegisterAnimate(attack->attacker, anim, 0); + animationRegisterPlaySoundEffect(attack->attacker, sfx_name_temp, v17); _show_damage(attack, anim, 0); } else { if (attack->defender->data.critter.combat.results & 0x03) { - reg_anim_play_sfx(attack->attacker, sfx_name_temp, -1); - reg_anim_animate(attack->attacker, anim, 0); + animationRegisterPlaySoundEffect(attack->attacker, sfx_name_temp, -1); + animationRegisterAnimate(attack->attacker, anim, 0); } else { - fid = buildFid(1, attack->defender->fid & 0xFFF, ANIM_DODGE_ANIM, (attack->defender->fid & 0xF000) >> 12, attack->defender->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, attack->defender->fid & 0xFFF, ANIM_DODGE_ANIM, (attack->defender->fid & 0xF000) >> 12, attack->defender->rotation + 1); art = artLock(fid, &cache_entry); if (art != NULL) { v18 = artGetActionFrame(art); artUnlock(cache_entry); if (v18 <= v17) { - reg_anim_play_sfx(attack->attacker, sfx_name_temp, -1); - reg_anim_animate(attack->attacker, anim, 0); + animationRegisterPlaySoundEffect(attack->attacker, sfx_name_temp, -1); + animationRegisterAnimate(attack->attacker, anim, 0); sfx_name = sfxBuildCharName(attack->defender, ANIM_DODGE_ANIM, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(attack->defender, sfx_name, v17 - v18); - reg_anim_animate(attack->defender, 13, 0); + animationRegisterPlaySoundEffect(attack->defender, sfx_name, v17 - v18); + animationRegisterAnimate(attack->defender, ANIM_DODGE_ANIM, 0); } else { sfx_name = sfxBuildCharName(attack->defender, ANIM_DODGE_ANIM, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(attack->defender, sfx_name, -1); - reg_anim_animate(attack->defender, 13, 0); - reg_anim_play_sfx(attack->attacker, sfx_name_temp, v18 - v17); - reg_anim_animate(attack->attacker, anim, 0); + animationRegisterPlaySoundEffect(attack->defender, sfx_name, -1); + animationRegisterAnimate(attack->defender, ANIM_DODGE_ANIM, 0); + animationRegisterPlaySoundEffect(attack->attacker, sfx_name_temp, v18 - v17); + animationRegisterAnimate(attack->attacker, anim, 0); } } } @@ -665,7 +665,7 @@ int _action_ranged(Attack* attack, int anim) Object* neighboors[6]; memset(neighboors, 0, sizeof(neighboors)); - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); _register_priority(1); Object* projectile = NULL; @@ -676,7 +676,7 @@ int _action_ranged(Attack* attack, int anim) Object* weapon = attack->weapon; protoGetProto(weapon->pid, &weaponProto); - int fid = buildFid(1, attack->attacker->fid & 0xFFF, anim, (attack->attacker->fid & 0xF000) >> 12, attack->attacker->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, attack->attacker->fid & 0xFFF, anim, (attack->attacker->fid & 0xF000) >> 12, attack->attacker->rotation + 1); CacheEntry* artHandle; Art* art = artLock(fid, &artHandle); int actionFrame = (art != NULL) ? artGetActionFrame(art) : 0; @@ -688,7 +688,7 @@ int _action_ranged(Attack* attack, int anim) tileGetTileInDirection(attack->attacker->tile, attack->attacker->rotation, 1); - reg_anim_set_rotation_to_tile(attack->attacker, attack->defender->tile); + animationRegisterRotateToTile(attack->attacker, attack->defender->tile); bool isGrenade = false; if (anim == ANIM_THROW_ANIM) { @@ -696,7 +696,7 @@ int _action_ranged(Attack* attack, int anim) isGrenade = true; } } else { - reg_anim_animate(attack->attacker, ANIM_POINT, -1); + animationRegisterAnimate(attack->attacker, ANIM_POINT, -1); } _combatai_msg(attack->attacker, attack, AI_MESSAGE_TYPE_ATTACK, 0); @@ -707,9 +707,9 @@ int _action_ranged(Attack* attack, int anim) } else { sfx = sfxBuildCharName(attack->attacker, anim, CHARACTER_SOUND_EFFECT_UNUSED); } - reg_anim_play_sfx(attack->attacker, sfx, -1); + animationRegisterPlaySoundEffect(attack->attacker, sfx, -1); - reg_anim_animate(attack->attacker, anim, 0); + animationRegisterAnimate(attack->attacker, anim, 0); if (anim != ANIM_FIRE_CONTINUOUS) { if ((attack->attackerFlags & DAM_HIT) != 0 || (attack->attackerFlags & DAM_CRITICAL) == 0) { @@ -758,18 +758,18 @@ int _action_ranged(Attack* attack, int anim) int projectileRotation = tileGetRotationTo(attack->attacker->tile, attack->defender->tile); objectSetRotation(projectile, projectileRotation, NULL); - reg_anim_15(projectile, 1, actionFrame); + animationRegisterUnsetFlag(projectile, OBJECT_HIDDEN, actionFrame); const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_AMMO_FLYING, weapon, attack->hitMode, attack->defender); - reg_anim_play_sfx(projectile, sfx, 0); + animationRegisterPlaySoundEffect(projectile, sfx, 0); int v24; if ((attack->attackerFlags & DAM_HIT) != 0) { - reg_anim_2(projectile, attack->defender->tile, attack->defender->elevation, ANIM_WALK, 0); + animationRegisterMoveToTileStraight(projectile, attack->defender->tile, attack->defender->elevation, ANIM_WALK, 0); actionFrame = _make_straight_path(projectile, projectileOrigin, attack->defender->tile, NULL, NULL, 32) - 1; v24 = attack->defender->tile; } else { - reg_anim_2(projectile, attack->tile, attack->defender->elevation, ANIM_WALK, 0); + animationRegisterMoveToTileStraight(projectile, attack->tile, attack->defender->elevation, ANIM_WALK, 0); actionFrame = 0; v24 = attack->tile; } @@ -794,16 +794,16 @@ int _action_ranged(Attack* attack, int anim) } if (isGrenade) { - reg_anim_17(projectile, weaponFid, -1); + animationRegisterSetFid(projectile, weaponFid, -1); } - int explosionFid = buildFid(5, explosionFrmId, 0, 0, 0); - reg_anim_17(projectile, explosionFid, -1); + int explosionFid = buildFid(OBJ_TYPE_MISC, explosionFrmId, 0, 0, 0); + animationRegisterSetFid(projectile, explosionFid, -1); const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, weapon, attack->hitMode, attack->defender); - reg_anim_play_sfx(projectile, sfx, 0); + animationRegisterPlaySoundEffect(projectile, sfx, 0); - reg_anim_6(projectile, ANIM_STAND, 0); + animationRegisterAnimateAndHide(projectile, ANIM_STAND, 0); for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) { if (objectCreateWithFidPid(&(neighboors[rotation]), explosionFid, -1) != -1) { @@ -823,8 +823,8 @@ int _action_ranged(Attack* attack, int anim) } } - reg_anim_15(neighboors[rotation], 1, delay); - reg_anim_6(neighboors[rotation], ANIM_STAND, 0); + animationRegisterUnsetFlag(neighboors[rotation], OBJECT_HIDDEN, delay); + animationRegisterAnimateAndHide(neighboors[rotation], ANIM_STAND, 0); } } @@ -832,13 +832,13 @@ int _action_ranged(Attack* attack, int anim) } } else { if (anim != ANIM_THROW_ANIM) { - reg_anim_hide(projectile); + animationRegisterHideObjectForced(projectile); } } if (!l56) { const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_HIT, weapon, attack->hitMode, attack->defender); - reg_anim_play_sfx(weapon, sfx, actionFrame); + animationRegisterPlaySoundEffect(weapon, sfx, actionFrame); } actionFrame = 0; @@ -846,7 +846,7 @@ int _action_ranged(Attack* attack, int anim) if ((attack->attackerFlags & DAM_HIT) == 0) { Object* defender = attack->defender; if ((defender->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) == 0) { - reg_anim_animate(defender, ANIM_DODGE_ANIM, actionFrame); + animationRegisterAnimate(defender, ANIM_DODGE_ANIM, actionFrame); l56 = true; } } @@ -865,14 +865,14 @@ int _action_ranged(Attack* attack, int anim) } if (projectile != NULL && (isGrenade || damageType == DAMAGE_TYPE_EXPLOSION)) { - reg_anim_hide(projectile); + animationRegisterHideObjectForced(projectile); } else if (anim == ANIM_THROW_ANIM && projectile != NULL) { - reg_anim_17(projectile, weaponFid, -1); + animationRegisterSetFid(projectile, weaponFid, -1); } for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) { if (neighboors[rotation] != NULL) { - reg_anim_hide(neighboors[rotation]); + animationRegisterHideObjectForced(neighboors[rotation]); } } @@ -882,17 +882,17 @@ int _action_ranged(Attack* attack, int anim) if (v50 != NULL) { int v38 = weaponGetAnimationCode(v50); if (v38 != 0) { - reg_anim_18(attack->attacker, v38, -1); + animationRegisterTakeOutWeapon(attack->attacker, v38, -1); l9 = true; } } if (!l9) { - int fid = buildFid(1, attack->attacker->fid & 0xFFF, ANIM_STAND, 0, attack->attacker->rotation + 1); - reg_anim_17(attack->attacker, fid, -1); + int fid = buildFid(OBJ_TYPE_CRITTER, attack->attacker->fid & 0xFFF, ANIM_STAND, 0, attack->attacker->rotation + 1); + animationRegisterSetFid(attack->attacker, fid, -1); } } else { - reg_anim_animate(attack->attacker, ANIM_UNPOINT, -1); + animationRegisterAnimate(attack->attacker, ANIM_UNPOINT, -1); } } @@ -937,60 +937,55 @@ int _is_next_to(Object* a1, Object* a2) // 0x411DB4 int _action_climb_ladder(Object* a1, Object* a2) { - int anim; - int v5; - int v6; - int tile_num; - int v11; - const char* sfx_name; - if (a1 == gDude) { - anim = (gDude->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(gDude->fid); if (anim == ANIM_WALK || anim == ANIM_RUNNING) { reg_anim_clear(gDude); } } + int animationRequestOptions; + int actionPoints; if (isInCombat()) { - v5 = 2; - v6 = a1->data.critter.combat.ap; + animationRequestOptions = ANIMATION_REQUEST_RESERVED; + actionPoints = a1->data.critter.combat.ap; } else { - v5 = 1; - v6 = -1; + animationRequestOptions = ANIMATION_REQUEST_UNRESERVED; + actionPoints = -1; } if (a1 == gDude) { - v5 = 2; + animationRequestOptions = ANIMATION_REQUEST_RESERVED; } - v5 |= 4; - reg_anim_begin(v5); + animationRequestOptions |= ANIMATION_REQUEST_NO_STAND; + reg_anim_begin(animationRequestOptions); - tile_num = tileGetTileInDirection(a2->tile, 2, 1); - if (v6 != -1 || objectGetDistanceBetween(a1, a2) < 5) { - reg_anim_obj_move_to_tile(a1, tile_num, a2->elevation, v6, 0); + int tile = tileGetTileInDirection(a2->tile, ROTATION_SE, 1); + if (actionPoints != -1 || objectGetDistanceBetween(a1, a2) < 5) { + animationRegisterMoveToTile(a1, tile, a2->elevation, actionPoints, 0); } else { - reg_anim_obj_run_to_tile(a1, tile_num, a2->elevation, v6, 0); + animationRegisterRunToTile(a1, tile, a2->elevation, actionPoints, 0); } - reg_anim_11_1(a1, a2, _is_next_to, -1); - reg_anim_set_rotation_to_tile(a1, a2->tile); - reg_anim_11_1(a1, a2, _check_scenery_ap_cost, -1); + animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_is_next_to, -1); + animationRegisterRotateToTile(a1, a2->tile); + animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_check_scenery_ap_cost, -1); - v11 = (a1->fid & 0xF000) >> 12; - if (v11 != 0) { - sfx_name = sfxBuildCharName(a1, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx_name, -1); - reg_anim_animate(a1, 39, 0); + int weaponAnimationCode = (a1->fid & 0xF000) >> 12; + if (weaponAnimationCode != 0) { + const char* puttingAwaySfx = sfxBuildCharName(a1, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); + animationRegisterPlaySoundEffect(a1, puttingAwaySfx, -1); + animationRegisterAnimate(a1, ANIM_PUT_AWAY, 0); } - sfx_name = sfxBuildCharName(a1, ANIM_CLIMB_LADDER, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx_name, -1); - reg_anim_animate(a1, 4, 0); - reg_anim_11_0(a1, a2, _obj_use, -1); + const char* climbingSfx = sfxBuildCharName(a1, ANIM_CLIMB_LADDER, CHARACTER_SOUND_EFFECT_UNUSED); + animationRegisterPlaySoundEffect(a1, climbingSfx, -1); + animationRegisterAnimate(a1, ANIM_CLIMB_LADDER, 0); + animationRegisterCallback(a1, a2, (AnimationCallback*)_obj_use, -1); - if (v11 != 0) { - reg_anim_18(a1, v11, -1); + if (weaponAnimationCode != 0) { + animationRegisterTakeOutWeapon(a1, weaponAnimationCode, -1); } return reg_anim_end(); @@ -1000,7 +995,7 @@ int _action_climb_ladder(Object* a1, Object* a2) int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3) { Proto* proto = NULL; - int type = (a2->fid & 0xF000000) >> 24; + int type = FID_TYPE(a2->fid); int sceneryType = -1; if (type == OBJ_TYPE_SCENERY) { if (protoGetProto(a2->pid, &proto) == -1) { @@ -1012,70 +1007,70 @@ int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3) if (sceneryType != SCENERY_TYPE_LADDER_UP || a3 != NULL) { if (a1 == gDude) { - int anim = (gDude->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(gDude->fid); if (anim == ANIM_WALK || anim == ANIM_RUNNING) { reg_anim_clear(gDude); } } - int v9; + int animationRequestOptions; int actionPoints; if (isInCombat()) { - v9 = 2; + animationRequestOptions = ANIMATION_REQUEST_RESERVED; actionPoints = a1->data.critter.combat.ap; } else { - v9 = 1; + animationRequestOptions = ANIMATION_REQUEST_UNRESERVED; actionPoints = -1; } if (a1 == gDude) { - v9 = 2; + animationRequestOptions = ANIMATION_REQUEST_RESERVED; } - reg_anim_begin(v9); + reg_anim_begin(animationRequestOptions); if (actionPoints != -1 || objectGetDistanceBetween(a1, a2) < 5) { - reg_anim_obj_move_to_obj(a1, a2, actionPoints, 0); + animationRegisterMoveToObject(a1, a2, actionPoints, 0); } else { - reg_anim_obj_run_to_obj(a1, a2, -1, 0); + animationRegisterRunToObject(a1, a2, -1, 0); } - reg_anim_11_1(a1, a2, _is_next_to, -1); + animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_is_next_to, -1); if (a3 == NULL) { - reg_anim_11_0(a1, a2, _check_scenery_ap_cost, -1); + animationRegisterCallback(a1, a2, (AnimationCallback*)_check_scenery_ap_cost, -1); } int a2a = (a1->fid & 0xF000) >> 12; if (a2a != 0) { const char* sfx = sfxBuildCharName(a1, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(a1, sfx, -1); - reg_anim_animate(a1, ANIM_PUT_AWAY, 0); + animationRegisterPlaySoundEffect(a1, sfx, -1); + animationRegisterAnimate(a1, ANIM_PUT_AWAY, 0); } - int v13; - int v12 = (a2->fid & 0xF000000) >> 24; - if (v12 == OBJ_TYPE_CRITTER && _critter_is_prone(a2)) { - v13 = ANIM_MAGIC_HANDS_GROUND; - } else if (v12 == OBJ_TYPE_SCENERY && (proto->scenery.extendedFlags & 0x01) != 0) { - v13 = ANIM_MAGIC_HANDS_GROUND; + int anim; + int objectType = FID_TYPE(a2->fid); + if (objectType == OBJ_TYPE_CRITTER && _critter_is_prone(a2)) { + anim = ANIM_MAGIC_HANDS_GROUND; + } else if (objectType == OBJ_TYPE_SCENERY && (proto->scenery.extendedFlags & 0x01) != 0) { + anim = ANIM_MAGIC_HANDS_GROUND; } else { - v13 = ANIM_MAGIC_HANDS_MIDDLE; + anim = ANIM_MAGIC_HANDS_MIDDLE; } if (sceneryType != SCENERY_TYPE_STAIRS && a3 == NULL) { - reg_anim_animate(a1, v13, -1); + animationRegisterAnimate(a1, anim, -1); } if (a3 != NULL) { // TODO: Get rid of cast. - reg_anim_12(a1, a2, a3, (AnimationProc2*)_obj_use_item_on, -1); + animationRegisterCallback3(a1, a2, a3, (AnimationCallback3*)_obj_use_item_on, -1); } else { - reg_anim_11_0(a1, a2, _obj_use, -1); + animationRegisterCallback(a1, a2, (AnimationCallback*)_obj_use, -1); } if (a2a != 0) { - reg_anim_18(a1, a2a, -1); + animationRegisterTakeOutWeapon(a1, a2a, -1); } return reg_anim_end(); @@ -1093,40 +1088,39 @@ int _action_use_an_object(Object* a1, Object* a2) // 0x412134 int actionPickUp(Object* critter, Object* item) { - if (((item->fid & 0xF000000) >> 24) != OBJ_TYPE_ITEM) { + if (FID_TYPE(item->fid) != OBJ_TYPE_ITEM) { return -1; } if (critter == gDude) { - int animationCode = (gDude->fid & 0xFF0000) >> 16; + int animationCode = FID_ANIM_TYPE(gDude->fid); if (animationCode == ANIM_WALK || animationCode == ANIM_RUNNING) { reg_anim_clear(gDude); } } if (isInCombat()) { - reg_anim_begin(2); - reg_anim_obj_move_to_obj(critter, item, critter->data.critter.combat.ap, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterMoveToObject(critter, item, critter->data.critter.combat.ap, 0); } else { - int flags = (critter == gDude) ? 2 : 1; - reg_anim_begin(flags); + reg_anim_begin(critter == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED); if (objectGetDistanceBetween(critter, item) >= 5) { - reg_anim_obj_run_to_obj(critter, item, -1, 0); + animationRegisterRunToObject(critter, item, -1, 0); } else { - reg_anim_obj_move_to_obj(critter, item, -1, 0); + animationRegisterMoveToObject(critter, item, -1, 0); } } - reg_anim_11_1(critter, item, _is_next_to, -1); - reg_anim_11_0(critter, item, _check_scenery_ap_cost, -1); + animationRegisterCallbackForced(critter, item, (AnimationCallback*)_is_next_to, -1); + animationRegisterCallback(critter, item, (AnimationCallback*)_check_scenery_ap_cost, -1); Proto* itemProto; protoGetProto(item->pid, &itemProto); if (itemProto->item.type != ITEM_TYPE_CONTAINER || _proto_action_can_pickup(item->pid)) { - reg_anim_animate(critter, ANIM_MAGIC_HANDS_GROUND, 0); + animationRegisterAnimate(critter, ANIM_MAGIC_HANDS_GROUND, 0); - int fid = buildFid(1, critter->fid & 0xFFF, ANIM_MAGIC_HANDS_GROUND, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_MAGIC_HANDS_GROUND, (critter->fid & 0xF000) >> 12, critter->rotation + 1); int actionFrame; CacheEntry* cacheEntry; @@ -1138,25 +1132,27 @@ int actionPickUp(Object* critter, Object* item) } char sfx[16]; - if (artCopyFileName((item->fid & 0xF000000) >> 24, item->fid & 0xFFF, sfx) == 0) { + if (artCopyFileName(FID_TYPE(item->fid), item->fid & 0xFFF, sfx) == 0) { // NOTE: looks like they copy sfx one more time, what for? - reg_anim_play_sfx(item, sfx, actionFrame); + animationRegisterPlaySoundEffect(item, sfx, actionFrame); } - reg_anim_11_0(critter, item, _obj_pickup, actionFrame); + animationRegisterCallback(critter, item, (AnimationCallback*)_obj_pickup, actionFrame); } else { - int v27 = (critter->fid & 0xF000) >> 12; - if (v27 != 0) { + int weaponAnimationCode = (critter->fid & 0xF000) >> 12; + if (weaponAnimationCode != 0) { const char* sfx = sfxBuildCharName(critter, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(critter, sfx, -1); - reg_anim_animate(critter, ANIM_PUT_AWAY, -1); + animationRegisterPlaySoundEffect(critter, sfx, -1); + animationRegisterAnimate(critter, ANIM_PUT_AWAY, -1); } // ground vs middle animation - int animationCode = 10 + ((itemProto->item.data.container.openFlags & 0x01) == 0); - reg_anim_animate(critter, animationCode, 0); + int anim = (itemProto->item.data.container.openFlags & 0x01) == 0 + ? ANIM_MAGIC_HANDS_MIDDLE + : ANIM_MAGIC_HANDS_GROUND; + animationRegisterAnimate(critter, anim, 0); - int fid = buildFid(1, critter->fid & 0xFFF, animationCode, 0, critter->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, anim, 0, critter->rotation + 1); int actionFrame; CacheEntry* cacheEntry; @@ -1169,15 +1165,15 @@ int actionPickUp(Object* critter, Object* item) } if (item->frame != 1) { - reg_anim_11_0(critter, item, _obj_use_container, actionFrame); + animationRegisterCallback(critter, item, (AnimationCallback*)_obj_use_container, actionFrame); } - if (v27 != 0) { - reg_anim_18(critter, v27, -1); + if (weaponAnimationCode != 0) { + animationRegisterTakeOutWeapon(critter, weaponAnimationCode, -1); } if (item->frame == 0 || item->frame == 1) { - reg_anim_11_0(critter, item, scriptsRequestLooting, -1); + animationRegisterCallback(critter, item, (AnimationCallback*)scriptsRequestLooting, -1); } } @@ -1192,33 +1188,33 @@ int actionPickUp(Object* critter, Object* item) // 0x4123E8 int _action_loot_container(Object* critter, Object* container) { - if ((container->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(container->fid) != OBJ_TYPE_CRITTER) { return -1; } if (critter == gDude) { - int anim = (gDude->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(gDude->fid); if (anim == ANIM_WALK || anim == ANIM_RUNNING) { reg_anim_clear(gDude); } } if (isInCombat()) { - reg_anim_begin(2); - reg_anim_obj_move_to_obj(critter, container, critter->data.critter.combat.ap, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterMoveToObject(critter, container, critter->data.critter.combat.ap, 0); } else { - reg_anim_begin(critter == gDude ? 2 : 1); + reg_anim_begin(critter == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED); if (objectGetDistanceBetween(critter, container) < 5) { - reg_anim_obj_move_to_obj(critter, container, -1, 0); + animationRegisterMoveToObject(critter, container, -1, 0); } else { - reg_anim_obj_run_to_obj(critter, container, -1, 0); + animationRegisterRunToObject(critter, container, -1, 0); } } - reg_anim_11_1(critter, container, _is_next_to, -1); - reg_anim_11_0(critter, container, _check_scenery_ap_cost, -1); - reg_anim_11_0(critter, container, scriptsRequestLooting, -1); + animationRegisterCallbackForced(critter, container, (AnimationCallback*)_is_next_to, -1); + animationRegisterCallback(critter, container, (AnimationCallback*)_check_scenery_ap_cost, -1); + animationRegisterCallback(critter, container, (AnimationCallback*)scriptsRequestLooting, -1); return reg_anim_end(); } @@ -1253,7 +1249,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) return -1; } - if ((a2->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) { return -1; } break; @@ -1268,7 +1264,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) return -1; } - if ((a2->pid >> 24) != OBJ_TYPE_ITEM && (a2->pid >> 24) != OBJ_TYPE_SCENERY) { + if (PID_TYPE(a2->pid) != OBJ_TYPE_ITEM && PID_TYPE(a2->pid) != OBJ_TYPE_SCENERY) { return -1; } @@ -1284,7 +1280,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) return -1; } - if ((a2->pid >> 24) != OBJ_TYPE_ITEM && (a2->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(a2->pid) != OBJ_TYPE_ITEM && PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) { return -1; } @@ -1304,7 +1300,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) return -1; } - if ((a2->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(a2->pid) == OBJ_TYPE_CRITTER) { return -1; } @@ -1321,7 +1317,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) return -1; } - if ((a2->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) { break; } @@ -1366,7 +1362,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) if (partyMember != NULL) { performer = partyMember; - int anim = (partyMember->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(partyMember->fid); if (anim != ANIM_WALK && anim != ANIM_RUNNING) { if (anim != ANIM_STAND) { performer = gDude; @@ -1397,7 +1393,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill) } if (partyMember == NULL) { - int anim = (performer->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(performer->fid); if (anim == ANIM_WALK || anim == ANIM_RUNNING) { reg_anim_clear(performer); } @@ -1405,23 +1401,23 @@ int actionUseSkill(Object* a1, Object* a2, int skill) } if (isInCombat()) { - reg_anim_begin(2); - reg_anim_obj_move_to_obj(performer, a2, performer->data.critter.combat.ap, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterMoveToObject(performer, a2, performer->data.critter.combat.ap, 0); } else { - reg_anim_begin(a1 == gDude ? 2 : 1); + reg_anim_begin(a1 == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED); if (a2 != gDude) { if (objectGetDistanceBetween(performer, a2) >= 5) { - reg_anim_obj_run_to_obj(performer, a2, -1, 0); + animationRegisterRunToObject(performer, a2, -1, 0); } else { - reg_anim_obj_move_to_obj(performer, a2, -1, 0); + animationRegisterMoveToObject(performer, a2, -1, 0); } } } - reg_anim_11_1(performer, a2, _is_next_to, -1); + animationRegisterCallbackForced(performer, a2, (AnimationCallback*)_is_next_to, -1); - int anim = (((a2->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER && _critter_is_prone(a2)) ? ANIM_MAGIC_HANDS_GROUND : ANIM_MAGIC_HANDS_MIDDLE; - int fid = buildFid(1, performer->fid & 0xFFF, anim, 0, performer->rotation + 1); + int anim = (FID_TYPE(a2->fid) == OBJ_TYPE_CRITTER && _critter_is_prone(a2)) ? ANIM_MAGIC_HANDS_GROUND : ANIM_MAGIC_HANDS_MIDDLE; + int fid = buildFid(OBJ_TYPE_CRITTER, performer->fid & 0xFFF, anim, 0, performer->rotation + 1); CacheEntry* artHandle; Art* art = artLock(fid, &artHandle); @@ -1430,9 +1426,9 @@ int actionUseSkill(Object* a1, Object* a2, int skill) artUnlock(artHandle); } - reg_anim_animate(performer, anim, -1); + animationRegisterAnimate(performer, anim, -1); // TODO: Get rid of casts. - reg_anim_12(performer, a2, (void*)skill, (AnimationProc2*)_obj_use_skill_on, -1); + animationRegisterCallback3(performer, a2, (void*)skill, (AnimationCallback3*)_obj_use_skill_on, -1); return reg_anim_end(); } @@ -1490,7 +1486,7 @@ int _pick_fall(Object* obj, int anim) } if (anim == ANIM_FALL_FRONT) { - fid = buildFid(1, obj->fid & 0xFFF, ANIM_FALL_FRONT, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, ANIM_FALL_FRONT, (obj->fid & 0xF000) >> 12, obj->rotation + 1); if (!artExists(fid)) { anim = ANIM_FALL_BACK; } @@ -1519,7 +1515,7 @@ int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* } Object* explosion; - int fid = buildFid(5, 10, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_MISC, 10, 0, 0, 0); if (objectCreateWithFidPid(&explosion, fid, -1) == -1) { internal_free(attack); return -1; @@ -1532,7 +1528,7 @@ int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* Object* adjacentExplosions[ROTATION_COUNT]; for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) { - int fid = buildFid(5, 10, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_MISC, 10, 0, 0, 0); if (objectCreateWithFidPid(&(adjacentExplosions[rotation]), fid, -1) == -1) { while (--rotation >= 0) { objectDestroy(adjacentExplosions[rotation], NULL); @@ -1552,7 +1548,7 @@ int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* Object* critter = _obj_blocking_at(NULL, tile, elevation); if (critter != NULL) { - if ((critter->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER || (critter->data.critter.combat.results & DAM_DEAD) != 0) { + if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER || (critter->data.critter.combat.results & DAM_DEAD) != 0) { critter = NULL; } } @@ -1587,28 +1583,27 @@ int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* if (a6) { _action_in_explode = 1; - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); _register_priority(1); - reg_anim_play_sfx(explosion, "whn1xxx1", 0); - reg_anim_15(explosion, 1, 0); - reg_anim_6(explosion, ANIM_STAND, 0); + animationRegisterPlaySoundEffect(explosion, "whn1xxx1", 0); + animationRegisterUnsetFlag(explosion, OBJECT_HIDDEN, 0); + animationRegisterAnimateAndHide(explosion, ANIM_STAND, 0); _show_damage(attack, 0, 1); for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) { - reg_anim_15(adjacentExplosions[rotation], 1, 0); - reg_anim_6(adjacentExplosions[rotation], ANIM_STAND, 0); + animationRegisterUnsetFlag(adjacentExplosions[rotation], OBJECT_HIDDEN, 0); + animationRegisterAnimateAndHide(adjacentExplosions[rotation], ANIM_STAND, 0); } - reg_anim_11_1(explosion, 0, _combat_explode_scenery, -1); - reg_anim_hide(explosion); + animationRegisterCallbackForced(explosion, 0, (AnimationCallback*)_combat_explode_scenery, -1); + animationRegisterHideObjectForced(explosion); for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) { - reg_anim_hide(adjacentExplosions[rotation]); + animationRegisterHideObjectForced(adjacentExplosions[rotation]); } - // TODO: Get rid of casts. - reg_anim_11_1((Object*)attack, a5, (AnimationProc*)_report_explosion, -1); - reg_anim_11_1(NULL, NULL, _finished_explosion, -1); + animationRegisterCallbackForced(attack, a5, (AnimationCallback*)_report_explosion, -1); + animationRegisterCallbackForced(NULL, NULL, (AnimationCallback*)_finished_explosion, -1); if (reg_anim_end() == -1) { _action_in_explode = 0; @@ -1765,28 +1760,28 @@ int actionTalk(Object* a1, Object* a2) return -1; } - if ((a2->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) { return -1; } - int anim = (gDude->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(gDude->fid); if (anim == ANIM_WALK || anim == ANIM_RUNNING) { reg_anim_clear(gDude); } if (isInCombat()) { - reg_anim_begin(2); - reg_anim_obj_move_to_obj(a1, a2, a1->data.critter.combat.ap, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterMoveToObject(a1, a2, a1->data.critter.combat.ap, 0); } else { - reg_anim_begin((a1 == gDude) ? 2 : 1); + reg_anim_begin(a1 == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED); if (objectGetDistanceBetween(a1, a2) >= 9 || _combat_is_shot_blocked(a1, a1->tile, a2->tile, a2, NULL)) { - reg_anim_obj_run_to_obj(a1, a2, -1, 0); + animationRegisterRunToObject(a1, a2, -1, 0); } } - reg_anim_11_1(a1, a2, _can_talk_to, -1); - reg_anim_11_0(a1, a2, _talk_to, -1); + animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_can_talk_to, -1); + animationRegisterCallback(a1, a2, (AnimationCallback*)_talk_to, -1); return reg_anim_end(); } @@ -1817,39 +1812,39 @@ int _talk_to(Object* a1, Object* a2) } // 0x413494 -void _action_dmg(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor) +void actionDamage(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor) { Attack* attack = (Attack*)internal_malloc(sizeof(*attack)); if (attack == NULL) { return; } - Object* obj; - if (objectCreateWithFidPid(&obj, FID_0x20001F5, -1) == -1) { + Object* attacker; + if (objectCreateWithFidPid(&attacker, FID_0x20001F5, -1) == -1) { internal_free(attack); return; } - objectHide(obj, NULL); + objectHide(attacker, NULL); - obj->flags |= OBJECT_TEMPORARY; + attacker->flags |= OBJECT_TEMPORARY; - objectSetLocation(obj, tile, elevation, NULL); + objectSetLocation(attacker, tile, elevation, NULL); - Object* v9 = _obj_blocking_at(NULL, tile, elevation); - attackInit(attack, obj, v9, HIT_MODE_PUNCH, HIT_LOCATION_TORSO); + Object* defender = _obj_blocking_at(NULL, tile, elevation); + attackInit(attack, attacker, defender, HIT_MODE_PUNCH, HIT_LOCATION_TORSO); attack->tile = tile; attack->attackerFlags = DAM_HIT; gameUiDisable(1); - if (v9 != NULL) { - reg_anim_clear(v9); + if (defender != NULL) { + reg_anim_clear(defender); int damage; if (bypassArmor) { damage = maxDamage; } else { - damage = _compute_dmg_damage(minDamage, maxDamage, v9, &(attack->defenderKnockback), damageType); + damage = _compute_dmg_damage(minDamage, maxDamage, defender, &(attack->defenderKnockback), damageType); } attack->defenderDamage = damage; @@ -1858,30 +1853,28 @@ void _action_dmg(int tile, int elevation, int minDamage, int maxDamage, int dama attackComputeDeathFlags(attack); if (animated) { - reg_anim_begin(2); - reg_anim_play_sfx(obj, "whc1xxx1", 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterPlaySoundEffect(attacker, "whc1xxx1", 0); _show_damage(attack, gMaximumBloodDeathAnimations[damageType], 0); - // TODO: Get rid of casts. - reg_anim_11_1((Object*)attack, NULL, (AnimationProc*)_report_dmg, 0); - reg_anim_hide(obj); + animationRegisterCallbackForced(attack, NULL, (AnimationCallback*)_report_dmg, 0); + animationRegisterHideObjectForced(attacker); if (reg_anim_end() == -1) { - objectDestroy(obj, NULL); + objectDestroy(attacker, NULL); internal_free(attack); return; } } else { - if (v9 != NULL) { + if (defender != NULL) { if ((attack->defenderFlags & DAM_DEAD) != 0) { - critterKill(v9, -1, 1); + critterKill(defender, -1, 1); } } - _combat_display(attack); - _apply_damage(attack, false); - internal_free(attack); - gameUiEnable(); - objectDestroy(obj, NULL); + // NOTE: Uninline. + _report_dmg(attack, NULL); + + objectDestroy(attacker, NULL); } gameUiEnable(); @@ -1902,7 +1895,7 @@ int _report_dmg(Attack* attack, Object* a2) // 0x413660 int _compute_dmg_damage(int min, int max, Object* obj, int* a4, int damageType) { - if (!_critter_flag_check(obj->pid, 0x4000)) { + if (!_critter_flag_check(obj->pid, CRITTER_FLAG_0x4000)) { a4 = NULL; } @@ -1929,7 +1922,7 @@ int _compute_dmg_damage(int min, int max, Object* obj, int* a4, int damageType) bool actionCheckPush(Object* a1, Object* a2) { // Cannot push anything but critters. - if ((a2->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) { return false; } @@ -2036,9 +2029,9 @@ int actionPush(Object* a1, Object* a2) actionPoints = -1; } - reg_anim_begin(2); - reg_anim_set_rotation_to_tile(a2, tile); - reg_anim_obj_move_to_tile(a2, tile, a2->elevation, actionPoints, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterRotateToTile(a2, tile); + animationRegisterMoveToTile(a2, tile, a2->elevation, actionPoints, 0); return reg_anim_end(); } diff --git a/src/actions.h b/src/actions.h index 339e5eb..521840a 100644 --- a/src/actions.h +++ b/src/actions.h @@ -16,7 +16,7 @@ bool _can_see(Object* a1, Object* a2); bool _action_explode_running(); int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* a5, bool a6); int actionTalk(Object* a1, Object* a2); -void _action_dmg(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor); +void actionDamage(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor); bool actionCheckPush(Object* a1, Object* a2); int actionPush(Object* a1, Object* a2); int _action_can_talk_to(Object* a1, Object* a2); diff --git a/src/animation.cc b/src/animation.cc index aaa9906..2176856 100644 --- a/src/animation.cc +++ b/src/animation.cc @@ -35,34 +35,170 @@ #define ANIMATION_DESCRIPTION_LIST_CAPACITY 55 #define ANIMATION_SAD_LIST_CAPACITY 24 +#define ANIMATION_SEQUENCE_FORCED 0x01 + +typedef enum AnimationKind { + ANIM_KIND_MOVE_TO_OBJECT = 0, + ANIM_KIND_MOVE_TO_TILE = 1, + ANIM_KIND_MOVE_TO_TILE_STRAIGHT = 2, + ANIM_KIND_MOVE_TO_TILE_STRAIGHT_AND_WAIT_FOR_COMPLETE = 3, + ANIM_KIND_ANIMATE = 4, + ANIM_KIND_ANIMATE_REVERSED = 5, + ANIM_KIND_ANIMATE_AND_HIDE = 6, + ANIM_KIND_ROTATE_TO_TILE = 7, + ANIM_KIND_ROTATE_CLOCKWISE = 8, + ANIM_KIND_ROTATE_COUNTER_CLOCKWISE = 9, + ANIM_KIND_HIDE = 10, + ANIM_KIND_CALLBACK = 11, + ANIM_KIND_CALLBACK3 = 12, + ANIM_KIND_SET_FLAG = 14, + ANIM_KIND_UNSET_FLAG = 15, + ANIM_KIND_TOGGLE_FLAT = 16, + ANIM_KIND_SET_FID = 17, + ANIM_KIND_TAKE_OUT_WEAPON = 18, + ANIM_KIND_SET_LIGHT_DISTANCE = 19, + ANIM_KIND_20 = 20, + ANIM_KIND_23 = 23, + ANIM_KIND_TOGGLE_OUTLINE = 24, + ANIM_KIND_ANIMATE_FOREVER = 25, + ANIM_KIND_26 = 26, + ANIM_KIND_27 = 27, + ANIM_KIND_NOOP = 28, +} AnimationKind; + +typedef enum AnimationSequenceFlags { + // Specifies that the animation sequence has high priority, it cannot be + // cleared. + ANIM_SEQ_PRIORITIZED = 0x01, + + // Specifies that the animation sequence started combat animation mode and + // therefore should balance it with appropriate finish call. + ANIM_SEQ_COMBAT_ANIM_STARTED = 0x02, + + // Specifies that the animation sequence is reserved (TODO: explain what it + // actually means). + ANIM_SEQ_RESERVED = 0x04, + + // Specifies that the animation sequence is in the process of adding actions + // to it (that is in the middle of begin/end calls). + ANIM_SEQ_ACCUMULATING = 0x08, + + // TODO: Add description. + ANIM_SEQ_0x10 = 0x10, + + // TODO: Add description. + ANIM_SEQ_0x20 = 0x20, + + // Specifies that the animation sequence is negligible and will be end + // immediately when a new animation sequence is requested for the same + // object. + ANIM_SEQ_INSIGNIFICANT = 0x40, + + // Specifies that the animation sequence should not return to ANIM_STAND + // when it's completed. + ANIM_SEQ_NO_STAND = 0x80, +} AnimationSequenceFlags; + +typedef enum AnimationSadFlags { + // Specifies that the animation should play from end to start. + ANIM_SAD_REVERSE = 0x01, + + // Specifies that the animation should use straight movement mode (as + // opposed to normal movement mode). + ANIM_SAD_STRAIGHT = 0x02, + + // Specifies that no frame change should occur during animation. + ANIM_SAD_NO_ANIM = 0x04, + + // Specifies that the animation should be played fully from start to finish. + // + // NOTE: This flag is only used together with straight movement mode to + // implement knockdown. Without this flag when the knockdown distance is + // short, say 1 or 2 tiles, knockdown animation might not be completed by + // the time critter reached it's destination. With this flag set animation + // will be played to it's final frame. + ANIM_SAD_WAIT_FOR_COMPLETION = 0x10, + + // Unknown, set once, never read. + ANIM_SAD_0x20 = 0x20, + + // Specifies that the owner of the animation should be hidden when animation + // is completed. + ANIM_SAD_HIDE_ON_END = 0x40, + + // Specifies that the animation should never end. + ANIM_SAD_FOREVER = 0x80, +} AnimationSadFlags; + typedef struct AnimationDescription { - int type; - Object* owner; + int kind; union { - Object* destinationObj; - Sound* sound; + Object* owner; + + // - ANIM_KIND_CALLBACK + // - ANIM_KIND_CALLBACK3 + void* param2; + }; + + union { + // - ANIM_KIND_MOVE_TO_OBJECT + Object* destination; + + // - ANIM_KIND_CALLBACK + void* param1; }; union { - int tile; - int fid; // for type == 17 - int weaponAnimationCode; // for type == 18 - int lightDistance; // for type == 19 + // - ANIM_KIND_MOVE_TO_TILE + // - ANIM_KIND_ANIMATE_AND_MOVE_TO_TILE_STRAIGHT + // - ANIM_KIND_MOVE_TO_TILE_STRAIGHT + struct { + int tile; + int elevation; + }; + + // ANIM_KIND_SET_FID + int fid; + + // ANIM_KIND_TAKE_OUT_WEAPON + int weaponAnimationCode; + + // ANIM_KIND_SET_LIGHT_DISTANCE + int lightDistance; + + // ANIM_KIND_TOGGLE_OUTLINE + bool outline; }; - int elevation; - int anim; // anim - int delay; // delay + int anim; + int delay; + + // ANIM_KIND_CALLBACK + AnimationCallback* callback; + + // ANIM_KIND_CALLBACK3 + AnimationCallback3* callback3; + union { - AnimationProc* proc; - AnimationSoundProc* soundProc; + // - ANIM_KIND_SET_FLAG + // - ANIM_KIND_UNSET_FLAG + unsigned int objectFlag; + + // - ANIM_KIND_HIDE + // - ANIM_KIND_CALLBACK + unsigned int extendedFlags; }; - AnimationProc2* field_20; // func - int field_24; + union { - int field_28; // actionPoints - Object* field_28_obj; // obj in type == 12 - void* field_28_void; + // - ANIM_KIND_MOVE_TO_TILE + // - ANIM_KIND_MOVE_TO_OBJECT + int actionPoints; + + // ANIM_KIND_26 + int animationSequenceIndex; + + // ANIM_KIND_CALLBACK3 + void* param3; }; - CacheEntry* field_2C; + CacheEntry* artCacheKey; } AnimationDescription; typedef struct AnimationSequence { @@ -72,7 +208,7 @@ typedef struct AnimationSequence { int animationIndex; // Number of scheduled animations in [animations] array. int length; - int flags; + unsigned int flags; AnimationDescription animations[ANIMATION_DESCRIPTION_LIST_CAPACITY]; } AnimationSequence; @@ -88,7 +224,7 @@ typedef struct PathNode { // TODO: I don't know what `sad` means, but it's definitely better than // `STRUCT_530014`. Find a better name. typedef struct AnimationSad { - int flags; // flags + unsigned int flags; Object* obj; int fid; // fid int anim; @@ -122,7 +258,7 @@ static int _tile_idistance(int tile1, int tile2); static int animateMoveObjectToObject(Object* from, Object* to, int a3, int anim, int animationSequenceIndex); static int animateMoveObjectToTile(Object* obj, int tile_num, int elev, int a4, int anim, int animationSequenceIndex); static int _anim_move(Object* obj, int tile, int elev, int a3, int anim, int a5, int animationSequenceIndex); -static int _anim_move_straight_to_tile(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex, int flags); +static int animateMoveObjectToTileStraight(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex, int flags); static int _anim_move_on_stairs(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex); static int _check_for_falling(Object* obj, int anim, int a3); static void _object_move(int index); @@ -213,7 +349,7 @@ void animationExit() } // 0x413AF4 -int reg_anim_begin(int flags) +int reg_anim_begin(int requestOptions) { if (gAnimationSequenceCurrentIndex != -1) { return -1; @@ -223,24 +359,24 @@ int reg_anim_begin(int flags) return -1; } - int v1 = _anim_free_slot(flags); + int v1 = _anim_free_slot(requestOptions); if (v1 == -1) { return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[v1]); - animationSequence->flags |= 0x08; + animationSequence->flags |= ANIM_SEQ_ACCUMULATING; - if (flags & 0x02) { - animationSequence->flags |= 0x04; + if ((requestOptions & ANIMATION_REQUEST_RESERVED) != 0) { + animationSequence->flags |= ANIM_SEQ_RESERVED; } - if (flags & 0x0200) { - animationSequence->flags |= 0x40; + if ((requestOptions & ANIMATION_REQUEST_INSIGNIFICANT) != 0) { + animationSequence->flags |= ANIM_SEQ_INSIGNIFICANT; } - if (flags & 0x04) { - animationSequence->flags |= 0x80; + if ((requestOptions & ANIMATION_REQUEST_NO_STAND) != 0) { + animationSequence->flags |= ANIM_SEQ_NO_STAND; } gAnimationSequenceCurrentIndex = v1; @@ -251,28 +387,28 @@ int reg_anim_begin(int flags) } // 0x413B80 -static int _anim_free_slot(int flags) +static int _anim_free_slot(int requestOptions) { int v1 = -1; int v2 = 0; for (int index = 0; index < ANIMATION_SEQUENCE_LIST_CAPACITY; index++) { - // TODO: Check. - if (gAnimationSequences[index].field_0 != -1000 || gAnimationSequences[index].flags & 8 || gAnimationSequences[index].flags & 0x20) { - if (!(gAnimationSequences[index].flags & 4)) { + AnimationSequence* animationSequence = &(gAnimationSequences[index]); + if (animationSequence->field_0 != -1000 || (animationSequence->flags & ANIM_SEQ_ACCUMULATING) != 0 || (animationSequence->flags & ANIM_SEQ_0x20) != 0) { + if (!(animationSequence->flags & ANIM_SEQ_RESERVED)) { v2++; } - } else if (v1 == -1 && (!((flags >> 8) & 1) || !(gAnimationSequences[index].flags & 0x10))) { + } else if (v1 == -1 && ((requestOptions & ANIMATION_REQUEST_0x100) == 0 || (animationSequence->flags & ANIM_SEQ_0x10) == 0)) { v1 = index; } } if (v1 == -1) { - if (flags & 0x02) { + if ((requestOptions & ANIMATION_REQUEST_RESERVED) != 0) { debugPrint("Unable to begin reserved animation!\n"); } return -1; - } else if (flags & 0x02 || v2 < 20) { + } else if ((requestOptions & ANIMATION_REQUEST_RESERVED) != 0 || v2 < 20) { return v1; } @@ -290,7 +426,7 @@ int _register_priority(int a1) return -1; } - gAnimationSequences[gAnimationSequenceCurrentIndex].flags |= 0x01; + gAnimationSequences[gAnimationSequenceCurrentIndex].flags |= ANIM_SEQ_PRIORITIZED; return 0; } @@ -299,24 +435,26 @@ int _register_priority(int a1) int reg_anim_clear(Object* a1) { for (int animationSequenceIndex = 0; animationSequenceIndex < ANIMATION_SEQUENCE_LIST_CAPACITY; animationSequenceIndex++) { - if (gAnimationSequences[animationSequenceIndex].field_0 == -1000) { + AnimationSequence* animationSequence = &(gAnimationSequences[animationSequenceIndex]); + if (animationSequence->field_0 == -1000) { continue; } int animationDescriptionIndex; - for (animationDescriptionIndex = 0; animationDescriptionIndex < gAnimationSequences[animationSequenceIndex].length; animationDescriptionIndex++) { - if (a1 != gAnimationSequences[animationSequenceIndex].animations[animationDescriptionIndex].owner || gAnimationSequences[animationSequenceIndex].animations[animationDescriptionIndex].type == 11) { + for (animationDescriptionIndex = 0; animationDescriptionIndex < animationSequence->length; animationDescriptionIndex++) { + AnimationDescription* animationDescription = &(animationSequence->animations[animationDescriptionIndex]); + if (a1 != animationDescription->owner || animationDescription->kind == 11) { continue; } break; } - if (animationDescriptionIndex == gAnimationSequences[animationSequenceIndex].length) { + if (animationDescriptionIndex == animationSequence->length) { continue; } - if (gAnimationSequences[animationSequenceIndex].flags & 0x01) { + if ((animationSequence->flags & ANIM_SEQ_PRIORITIZED) != 0) { return -2; } @@ -339,17 +477,17 @@ int reg_anim_end() animationSequence->field_0 = 0; animationSequence->length = gAnimationDescriptionCurrentIndex; animationSequence->animationIndex = -1; - animationSequence->flags &= ~0x08; + animationSequence->flags &= ~ANIM_SEQ_ACCUMULATING; animationSequence->animations[0].delay = 0; if (isInCombat()) { _combat_anim_begin(); - animationSequence->flags |= 0x02; + animationSequence->flags |= ANIM_SEQ_COMBAT_ANIM_STARTED; } int v1 = gAnimationSequenceCurrentIndex; gAnimationSequenceCurrentIndex = -1; - if (!(animationSequence->flags & 0x10)) { + if (!(animationSequence->flags & ANIM_SEQ_0x10)) { _anim_set_continue(v1, 1); } @@ -364,18 +502,18 @@ static void _anim_cleanup() } for (int index = 0; index < ANIMATION_SEQUENCE_LIST_CAPACITY; index++) { - gAnimationSequences[index].flags &= ~0x18; + gAnimationSequences[index].flags &= ~(ANIM_SEQ_ACCUMULATING | ANIM_SEQ_0x10); } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); for (int index = 0; index < gAnimationDescriptionCurrentIndex; index++) { AnimationDescription* animationDescription = &(animationSequence->animations[index]); - if (animationDescription->field_2C != NULL) { - artUnlock(animationDescription->field_2C); + if (animationDescription->artCacheKey != NULL) { + artUnlock(animationDescription->artCacheKey); } - if (animationDescription->type == ANIM_KIND_EXEC && animationDescription->soundProc == _gsnd_anim_sound) { - soundEffectDelete(animationDescription->sound); + if (animationDescription->kind == ANIM_KIND_CALLBACK && animationDescription->callback == (AnimationCallback*)_gsnd_anim_sound) { + soundEffectDelete((Sound*)animationDescription->param1); } } @@ -389,7 +527,7 @@ static int _check_registry(Object* obj) return -1; } - if (gAnimationDescriptionCurrentIndex >= 55) { + if (gAnimationDescriptionCurrentIndex >= ANIMATION_DESCRIPTION_LIST_CAPACITY) { return -1; } @@ -403,8 +541,8 @@ static int _check_registry(Object* obj) if (animationSequenceIndex != gAnimationSequenceCurrentIndex && animationSequence->field_0 != -1000) { for (int animationDescriptionIndex = 0; animationDescriptionIndex < animationSequence->length; animationDescriptionIndex++) { AnimationDescription* animationDescription = &(animationSequence->animations[animationDescriptionIndex]); - if (obj == animationDescription->owner && animationDescription->type != 11) { - if (!(animationSequence->flags & 0x40)) { + if (obj == animationDescription->owner && animationDescription->kind != 11) { + if ((animationSequence->flags & ANIM_SEQ_INSIGNIFICANT) == 0) { return -1; } @@ -435,7 +573,7 @@ int animationIsBusy(Object* a1) continue; } - if (animationDescription->type == ANIM_KIND_EXEC) { + if (animationDescription->kind == ANIM_KIND_CALLBACK) { continue; } @@ -452,48 +590,43 @@ int animationIsBusy(Object* a1) } // 0x413F5C -int reg_anim_obj_move_to_obj(Object* a1, Object* a2, int actionPoints, int delay) +int animationRegisterMoveToObject(Object* owner, Object* destination, int actionPoints, int delay) { - if (_check_registry(a1) == -1 || actionPoints == 0) { + if (_check_registry(owner) == -1 || actionPoints == 0) { _anim_cleanup(); return -1; } - if (a1->tile == a2->tile && a1->elevation == a2->elevation) { + if (owner->tile == destination->tile && owner->elevation == destination->elevation) { return 0; } AnimationDescription* animationDescription = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_OBJ_MOVE_TO_OBJ; + animationDescription->kind = ANIM_KIND_MOVE_TO_OBJECT; animationDescription->anim = ANIM_WALK; - animationDescription->owner = a1; - animationDescription->destinationObj = a2; - animationDescription->field_28 = actionPoints; + animationDescription->owner = owner; + animationDescription->destination = destination; + animationDescription->actionPoints = actionPoints; animationDescription->delay = delay; - int fid = buildFid((a1->fid & 0xF000000) >> 24, a1->fid & 0xFFF, animationDescription->anim, (a1->fid & 0xF000) >> 12, a1->rotation + 1); + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; - return reg_anim_set_rotation_to_tile(a1, a2->tile); + return animationRegisterRotateToTile(owner, destination->tile); } // 0x41405C -int reg_anim_obj_run_to_obj(Object* owner, Object* destination, int actionPoints, int delay) +int animationRegisterRunToObject(Object* owner, Object* destination, int actionPoints, int delay) { - MessageListItem msg; - const char* text; - const char* name; - char formatted_text[90]; // TODO: Size is probably wrong. - if (_check_registry(owner) == -1 || actionPoints == 0) { _anim_cleanup(); return -1; @@ -505,85 +638,84 @@ int reg_anim_obj_run_to_obj(Object* owner, Object* destination, int actionPoints if (critterIsEncumbered(owner)) { if (objectIsPartyMember(owner)) { + char formattedText[92]; + MessageListItem messageListItem; + if (owner == gDude) { // You are overloaded. - text = getmsg(&gMiscMessageList, &msg, 8000); - strcpy(formatted_text, text); + strcpy(formattedText, getmsg(&gMiscMessageList, &messageListItem, 8000)); } else { // %s is overloaded. - name = critterGetName(owner); - text = getmsg(&gMiscMessageList, &msg, 8001); - sprintf(formatted_text, text, name); + sprintf(formattedText, + getmsg(&gMiscMessageList, &messageListItem, 8001), + critterGetName(owner)); } - displayMonitorAddMessage(formatted_text); + displayMonitorAddMessage(formattedText); } - return reg_anim_obj_move_to_obj(owner, destination, actionPoints, delay); + return animationRegisterMoveToObject(owner, destination, actionPoints, delay); } AnimationDescription* animationDescription = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_OBJ_MOVE_TO_OBJ; + animationDescription->kind = ANIM_KIND_MOVE_TO_OBJECT; animationDescription->owner = owner; - animationDescription->destinationObj = destination; + animationDescription->destination = destination; - if ((owner->fid & 0xF000000) >> 24 == 1 && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) + if (FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) || owner == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING) - || !artExists(buildFid((owner->fid & 0xF000000) >> 24, owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) { + || !artExists(buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) { animationDescription->anim = ANIM_WALK; } else { animationDescription->anim = ANIM_RUNNING; } - animationDescription->field_28 = actionPoints; + animationDescription->actionPoints = actionPoints; animationDescription->delay = delay; - int fid = buildFid((owner->fid & 0xF000000) >> 24, owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); - animationDescription->field_2C = NULL; - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + animationDescription->artCacheKey = NULL; + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; - return reg_anim_set_rotation_to_tile(owner, destination->tile); + return animationRegisterRotateToTile(owner, destination->tile); } // 0x414294 -int reg_anim_obj_move_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay) +int animationRegisterMoveToTile(Object* owner, int tile, int elevation, int actionPoints, int delay) { - AnimationDescription* ptr; - int fid; - - if (_check_registry(obj) == -1 || actionPoints == 0) { + if (_check_registry(owner) == -1 || actionPoints == 0) { _anim_cleanup(); return -1; } - if (tile_num == obj->tile && elev == obj->elevation) { + if (tile == owner->tile && elevation == owner->elevation) { return 0; } - ptr = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); - ptr->type = ANIM_KIND_OBJ_MOVE_TO_TILE; - ptr->anim = ANIM_WALK; - ptr->owner = obj; - ptr->tile = tile_num; - ptr->elevation = elev; - ptr->field_28 = actionPoints; - ptr->delay = delay; + AnimationDescription* animationDescription = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_MOVE_TO_TILE; + animationDescription->anim = ANIM_WALK; + animationDescription->owner = owner; + animationDescription->tile = tile; + animationDescription->elevation = elevation; + animationDescription->actionPoints = actionPoints; + animationDescription->delay = delay; + animationDescription->artCacheKey = NULL; - ptr->field_2C = NULL; - fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ptr->anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(ptr->field_2C)) == NULL) { + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(ptr->field_2C); - ptr->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -591,76 +723,65 @@ int reg_anim_obj_move_to_tile(Object* obj, int tile_num, int elev, int actionPoi } // 0x414394 -int reg_anim_obj_run_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay) +int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actionPoints, int delay) { - MessageListItem msg; - const char* text; - const char* name; - char str[72]; // TODO: Size is probably wrong. - AnimationDescription* animationDescription; - int fid; - - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1 || actionPoints == 0) { _anim_cleanup(); return -1; } - if (actionPoints == 0) { - _anim_cleanup(); - return -1; - } - - if (tile_num == obj->tile && elev == obj->elevation) { + if (tile == owner->tile && elevation == owner->elevation) { return 0; } - if (critterIsEncumbered(obj)) { - if (objectIsPartyMember(obj)) { - if (obj == gDude) { + if (critterIsEncumbered(owner)) { + if (objectIsPartyMember(owner)) { + MessageListItem messageListItem; + char formattedText[72]; + + if (owner == gDude) { // You are overloaded. - text = getmsg(&gMiscMessageList, &msg, 8000); - strcpy(str, text); + strcpy(formattedText, getmsg(&gMiscMessageList, &messageListItem, 8000)); } else { // %s is overloaded. - name = critterGetName(obj); - text = getmsg(&gMiscMessageList, &msg, 8001); - sprintf(str, text, name); + sprintf(formattedText, + getmsg(&gMiscMessageList, &messageListItem, 8001), + critterGetName(owner)); } - displayMonitorAddMessage(str); + displayMonitorAddMessage(formattedText); } - return reg_anim_obj_move_to_tile(obj, tile_num, elev, actionPoints, delay); + return animationRegisterMoveToTile(owner, tile, elevation, actionPoints, delay); } - animationDescription = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_OBJ_MOVE_TO_TILE; - animationDescription->owner = obj; - animationDescription->tile = tile_num; - animationDescription->elevation = elev; + AnimationDescription* animationDescription = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_MOVE_TO_TILE; + animationDescription->owner = owner; + animationDescription->tile = tile; + animationDescription->elevation = elevation; - // TODO: Check. - if ((obj->fid & 0xF000000) >> 24 == 1 && (obj->data.critter.combat.results & DAM_CRIP_LEG_ANY) - || obj == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING) - || !artExists(buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_RUNNING, 0, obj->rotation + 1))) { + if (FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) + || owner == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING) + || !artExists(buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) { animationDescription->anim = ANIM_WALK; } else { animationDescription->anim = ANIM_RUNNING; } - animationDescription->field_28 = actionPoints; + animationDescription->actionPoints = actionPoints; animationDescription->delay = delay; - fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, animationDescription->anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); - animationDescription->field_2C = NULL; - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + animationDescription->artCacheKey = NULL; + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -668,36 +789,36 @@ int reg_anim_obj_run_to_tile(Object* obj, int tile_num, int elev, int actionPoin } // 0x4145D0 -int reg_anim_2(Object* obj, int tile_num, int elev, int anim, int delay) +int animationRegisterMoveToTileStraight(Object* object, int tile, int elevation, int anim, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(object) == -1) { _anim_cleanup(); return -1; } - if (tile_num == obj->tile && elev == obj->elevation) { + if (tile == object->tile && elevation == object->elevation) { return 0; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_2; - animationDescription->owner = obj; - animationDescription->tile = tile_num; - animationDescription->elevation = elev; + animationDescription->kind = ANIM_KIND_MOVE_TO_TILE_STRAIGHT; + animationDescription->owner = object; + animationDescription->tile = tile; + animationDescription->elevation = elevation; animationDescription->anim = anim; animationDescription->delay = delay; - animationDescription->field_2C = NULL; + animationDescription->artCacheKey = NULL; - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, animationDescription->anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + int fid = buildFid(FID_TYPE(object->fid), object->fid & 0xFFF, animationDescription->anim, (object->fid & 0xF000) >> 12, object->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -705,35 +826,35 @@ int reg_anim_2(Object* obj, int tile_num, int elev, int anim, int delay) } // 0x4146C4 -int reg_anim_knockdown(Object* obj, int tile, int elev, int anim, int delay) +int animationRegisterMoveToTileStraightAndWaitForComplete(Object* owner, int tile, int elevation, int anim, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } - if (tile == obj->tile && elev == obj->elevation) { + if (tile == owner->tile && elevation == owner->elevation) { return 0; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_KNOCKDOWN; - animationDescription->owner = obj; + animationDescription->kind = ANIM_KIND_MOVE_TO_TILE_STRAIGHT_AND_WAIT_FOR_COMPLETE; + animationDescription->owner = owner; animationDescription->tile = tile; - animationDescription->elevation = elev; + animationDescription->elevation = elevation; animationDescription->anim = anim; animationDescription->delay = delay; - animationDescription->field_2C = NULL; + animationDescription->artCacheKey = NULL; - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, animationDescription->anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -741,97 +862,7 @@ int reg_anim_knockdown(Object* obj, int tile, int elev, int anim, int delay) } // 0x4149D0 -int reg_anim_animate(Object* obj, int anim, int delay) -{ - if (_check_registry(obj) == -1) { - _anim_cleanup(); - return -1; - } - - AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); - AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_ANIMATE; - animationDescription->owner = obj; - animationDescription->anim = anim; - animationDescription->delay = delay; - animationDescription->field_2C = NULL; - - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, animationDescription->anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { - _anim_cleanup(); - return -1; - } - - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; - - gAnimationDescriptionCurrentIndex++; - - return 0; -} - -// 0x414AA8 -int reg_anim_animate_reverse(Object* obj, int anim, int delay) -{ - if (_check_registry(obj) == -1) { - _anim_cleanup(); - return -1; - } - - AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); - AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_ANIMATE_REVERSE; - animationDescription->owner = obj; - animationDescription->anim = anim; - animationDescription->delay = delay; - animationDescription->field_2C = NULL; - - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, animationDescription->anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { - _anim_cleanup(); - return -1; - } - - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; - - gAnimationDescriptionCurrentIndex++; - - return 0; -} - -// 0x414B7C -int reg_anim_6(Object* obj, int anim, int delay) -{ - if (_check_registry(obj) == -1) { - _anim_cleanup(); - return -1; - } - - AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); - AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_6; - animationDescription->owner = obj; - animationDescription->anim = anim; - animationDescription->delay = delay; - animationDescription->field_2C = NULL; - - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { - _anim_cleanup(); - return -1; - } - - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; - - gAnimationDescriptionCurrentIndex++; - - return 0; -} - -// 0x414C50 -int reg_anim_set_rotation_to_tile(Object* owner, int tile) +int animationRegisterAnimate(Object* owner, int anim, int delay) { if (_check_registry(owner) == -1) { _anim_cleanup(); @@ -840,76 +871,191 @@ int reg_anim_set_rotation_to_tile(Object* owner, int tile) AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_SET_ROTATION_TO_TILE; + animationDescription->kind = ANIM_KIND_ANIMATE; + animationDescription->owner = owner; + animationDescription->anim = anim; + animationDescription->delay = delay; + animationDescription->artCacheKey = NULL; + + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { + _anim_cleanup(); + return -1; + } + + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; + + gAnimationDescriptionCurrentIndex++; + + return 0; +} + +// 0x414AA8 +int animationRegisterAnimateReversed(Object* owner, int anim, int delay) +{ + if (_check_registry(owner) == -1) { + _anim_cleanup(); + return -1; + } + + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_ANIMATE_REVERSED; + animationDescription->owner = owner; + animationDescription->anim = anim; + animationDescription->delay = delay; + animationDescription->artCacheKey = NULL; + + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, animationDescription->anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { + _anim_cleanup(); + return -1; + } + + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; + + gAnimationDescriptionCurrentIndex++; + + return 0; +} + +// 0x414B7C +int animationRegisterAnimateAndHide(Object* owner, int anim, int delay) +{ + if (_check_registry(owner) == -1) { + _anim_cleanup(); + return -1; + } + + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_ANIMATE_AND_HIDE; + animationDescription->owner = owner; + animationDescription->anim = anim; + animationDescription->delay = delay; + animationDescription->artCacheKey = NULL; + + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { + _anim_cleanup(); + return -1; + } + + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; + + gAnimationDescriptionCurrentIndex++; + + return 0; +} + +// 0x414C50 +int animationRegisterRotateToTile(Object* owner, int tile) +{ + if (_check_registry(owner) == -1) { + _anim_cleanup(); + return -1; + } + + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_ROTATE_TO_TILE; animationDescription->delay = -1; - animationDescription->field_2C = NULL; + animationDescription->artCacheKey = NULL; animationDescription->owner = owner; animationDescription->tile = tile; + gAnimationDescriptionCurrentIndex++; return 0; } // 0x414CC8 -int reg_anim_rotate_clockwise(Object* obj) +int animationRegisterRotateClockwise(Object* owner) { - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_ROTATE_CLOCKWISE; + animationDescription->kind = ANIM_KIND_ROTATE_CLOCKWISE; animationDescription->delay = -1; - animationDescription->field_2C = NULL; - animationDescription->owner = obj; + animationDescription->artCacheKey = NULL; + animationDescription->owner = owner; + gAnimationDescriptionCurrentIndex++; return 0; } // 0x414D38 -int reg_anim_rotate_counter_clockwise(Object* obj) +int animationRegisterRotateCounterClockwise(Object* owner) { - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_ROTATE_COUNTER_CLOCKWISE; + animationDescription->kind = ANIM_KIND_ROTATE_COUNTER_CLOCKWISE; animationDescription->delay = -1; - animationDescription->field_2C = NULL; - animationDescription->owner = obj; + animationDescription->artCacheKey = NULL; + animationDescription->owner = owner; + + gAnimationDescriptionCurrentIndex++; + + return 0; +} + +// NOTE: Unused. +// +// 0x414DA8 +int animationRegisterHideObject(Object* object) +{ + if (_check_registry(object) == -1) { + _anim_cleanup(); + return -1; + } + + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_HIDE; + animationDescription->delay = -1; + animationDescription->artCacheKey = NULL; + animationDescription->extendedFlags = 0; + animationDescription->owner = object; gAnimationDescriptionCurrentIndex++; return 0; } // 0x414E20 -int reg_anim_hide(Object* obj) +int animationRegisterHideObjectForced(Object* object) { - if (_check_registry(obj) == -1) { + if (_check_registry(object) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_HIDE; + animationDescription->kind = ANIM_KIND_HIDE; animationDescription->delay = -1; - animationDescription->field_2C = NULL; - animationDescription->field_24 = 1; - animationDescription->owner = obj; + animationDescription->artCacheKey = NULL; + animationDescription->extendedFlags = ANIMATION_SEQUENCE_FORCED; + animationDescription->owner = object; gAnimationDescriptionCurrentIndex++; return 0; } // 0x414E98 -int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay) +int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int delay) { if (_check_registry(NULL) == -1 || proc == NULL) { _anim_cleanup(); @@ -918,12 +1064,12 @@ int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay) AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_EXEC; - animationDescription->field_24 = 0; - animationDescription->field_2C = NULL; - animationDescription->owner = a2; - animationDescription->destinationObj = a1; - animationDescription->proc = proc; + animationDescription->kind = ANIM_KIND_CALLBACK; + animationDescription->extendedFlags = 0; + animationDescription->artCacheKey = NULL; + animationDescription->param2 = a2; + animationDescription->param1 = a1; + animationDescription->callback = proc; animationDescription->delay = delay; gAnimationDescriptionCurrentIndex++; @@ -931,23 +1077,25 @@ int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay) return 0; } +// Same as `animationRegisterCallback` but accepting 3 parameters. +// // 0x414F20 -int reg_anim_12(Object* a1, Object* a2, void* a3, AnimationProc2* proc, int delay) +int animationRegisterCallback3(void* a1, void* a2, void* a3, AnimationCallback3* proc, int delay) { - if (_check_registry(NULL) == -1 || !proc) { + if (_check_registry(NULL) == -1 || proc == NULL) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_EXEC_2; - animationDescription->field_24 = 0; - animationDescription->field_2C = NULL; - animationDescription->owner = a2; - animationDescription->destinationObj = a1; - animationDescription->field_20 = proc; - animationDescription->field_28_void = a3; + animationDescription->kind = ANIM_KIND_CALLBACK3; + animationDescription->extendedFlags = 0; + animationDescription->artCacheKey = NULL; + animationDescription->param2 = a2; + animationDescription->param1 = a1; + animationDescription->callback3 = proc; + animationDescription->param3 = a3; animationDescription->delay = delay; gAnimationDescriptionCurrentIndex++; @@ -956,7 +1104,7 @@ int reg_anim_12(Object* a1, Object* a2, void* a3, AnimationProc2* proc, int dela } // 0x414FAC -int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay) +int animationRegisterCallbackForced(void* a1, void* a2, AnimationCallback* proc, int delay) { if (_check_registry(NULL) == -1 || proc == NULL) { _anim_cleanup(); @@ -965,12 +1113,12 @@ int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay) AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_EXEC; - animationDescription->field_24 = 1; - animationDescription->field_2C = NULL; - animationDescription->owner = a2; - animationDescription->destinationObj = a1; - animationDescription->proc = proc; + animationDescription->kind = ANIM_KIND_CALLBACK; + animationDescription->extendedFlags = ANIMATION_SEQUENCE_FORCED; + animationDescription->artCacheKey = NULL; + animationDescription->param2 = a2; + animationDescription->param1 = a1; + animationDescription->callback = proc; animationDescription->delay = delay; gAnimationDescriptionCurrentIndex++; @@ -978,20 +1126,51 @@ int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay) return 0; } -// 0x4150A8 -int reg_anim_15(Object* obj, int a2, int delay) +// NOTE: Unused. +// +// The [flag] parameter should be one of OBJECT_* flags. The way it's handled +// down the road implies it should not be a group of flags (joined with bitwise +// OR), but a one particular flag. +// +// 0x415034 +int animationRegisterSetFlag(Object* object, int flag, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(object) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_15; - animationDescription->field_2C = NULL; - animationDescription->owner = obj; - animationDescription->field_24 = a2; + animationDescription->kind = ANIM_KIND_SET_FLAG; + animationDescription->artCacheKey = NULL; + animationDescription->owner = object; + animationDescription->objectFlag = flag; + animationDescription->delay = delay; + + gAnimationDescriptionCurrentIndex++; + + return 0; +} + +// The [flag] parameter should be one of OBJECT_* flags. The way it's handled +// down the road implies it should not be a group of flags (joined with bitwise +// OR), but a one particular flag. +// +// 0x4150A8 +int animationRegisterUnsetFlag(Object* object, int flag, int delay) +{ + if (_check_registry(object) == -1) { + _anim_cleanup(); + return -1; + } + + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_UNSET_FLAG; + animationDescription->artCacheKey = NULL; + animationDescription->owner = object; + animationDescription->objectFlag = flag; animationDescription->delay = delay; gAnimationDescriptionCurrentIndex++; @@ -1000,28 +1179,28 @@ int reg_anim_15(Object* obj, int a2, int delay) } // 0x41518C -int reg_anim_17(Object* obj, int fid, int delay) +int animationRegisterSetFid(Object* owner, int fid, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_17; - animationDescription->owner = obj; + animationDescription->kind = ANIM_KIND_SET_FID; + animationDescription->owner = owner; animationDescription->fid = fid; animationDescription->delay = delay; - animationDescription->field_2C = NULL; + animationDescription->artCacheKey = NULL; - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -1029,34 +1208,34 @@ int reg_anim_17(Object* obj, int fid, int delay) } // 0x415238 -int reg_anim_18(Object* obj, int weaponAnimationCode, int delay) +int animationRegisterTakeOutWeapon(Object* owner, int weaponAnimationCode, int delay) { - const char* sfx = sfxBuildCharName(obj, ANIM_TAKE_OUT, weaponAnimationCode); - if (reg_anim_play_sfx(obj, sfx, delay) == -1) { + const char* sfx = sfxBuildCharName(owner, ANIM_TAKE_OUT, weaponAnimationCode); + if (animationRegisterPlaySoundEffect(owner, sfx, delay) == -1) { return -1; } - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_18; + animationDescription->kind = ANIM_KIND_TAKE_OUT_WEAPON; animationDescription->anim = ANIM_TAKE_OUT; animationDescription->delay = 0; - animationDescription->owner = obj; + animationDescription->owner = owner; animationDescription->weaponAnimationCode = weaponAnimationCode; - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_TAKE_OUT, weaponAnimationCode, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_TAKE_OUT, weaponAnimationCode, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -1064,18 +1243,18 @@ int reg_anim_18(Object* obj, int weaponAnimationCode, int delay) } // 0x415334 -int reg_anim_update_light(Object* obj, int lightDistance, int delay) +int animationRegisterSetLightDistance(Object* owner, int lightDistance, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_19; - animationDescription->field_2C = NULL; - animationDescription->owner = obj; + animationDescription->kind = ANIM_KIND_SET_LIGHT_DISTANCE; + animationDescription->artCacheKey = NULL; + animationDescription->owner = owner; animationDescription->lightDistance = lightDistance; animationDescription->delay = delay; @@ -1084,31 +1263,54 @@ int reg_anim_update_light(Object* obj, int lightDistance, int delay) return 0; } -// 0x41541C -int reg_anim_play_sfx(Object* obj, const char* soundEffectName, int delay) +// NOTE: Unused. +// +// 0x4153A8 +int animationRegisterToggleOutline(Object* object, bool outline, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(object) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_EXEC; - animationDescription->owner = obj; - if (soundEffectName != NULL) { - int volume = _gsound_compute_relative_volume(obj); - animationDescription->sound = soundEffectLoadWithVolume(soundEffectName, obj, volume); - if (animationDescription->sound != NULL) { - animationDescription->soundProc = _gsnd_anim_sound; - } else { - animationDescription->type = ANIM_KIND_28; - } - } else { - animationDescription->type = ANIM_KIND_28; + animationDescription->kind = ANIM_KIND_TOGGLE_OUTLINE; + animationDescription->artCacheKey = NULL; + animationDescription->owner = object; + animationDescription->outline = outline; + animationDescription->delay = delay; + + gAnimationDescriptionCurrentIndex++; + + return 0; +} + +// 0x41541C +int animationRegisterPlaySoundEffect(Object* owner, const char* soundEffectName, int delay) +{ + if (_check_registry(owner) == -1) { + _anim_cleanup(); + return -1; } - animationDescription->field_2C = NULL; + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->kind = ANIM_KIND_CALLBACK; + animationDescription->owner = owner; + if (soundEffectName != NULL) { + int volume = _gsound_compute_relative_volume(owner); + animationDescription->param1 = soundEffectLoadWithVolume(soundEffectName, owner, volume); + if (animationDescription->param1 != NULL) { + animationDescription->callback = (AnimationCallback*)_gsnd_anim_sound; + } else { + animationDescription->kind = ANIM_KIND_NOOP; + } + } else { + animationDescription->kind = ANIM_KIND_NOOP; + } + + animationDescription->artCacheKey = NULL; animationDescription->delay = delay; gAnimationDescriptionCurrentIndex++; @@ -1117,29 +1319,29 @@ int reg_anim_play_sfx(Object* obj, const char* soundEffectName, int delay) } // 0x4154C4 -int reg_anim_animate_forever(Object* obj, int anim, int delay) +int animationRegisterAnimateForever(Object* owner, int anim, int delay) { - if (_check_registry(obj) == -1) { + if (_check_registry(owner) == -1) { _anim_cleanup(); return -1; } AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); - animationDescription->type = ANIM_KIND_ANIMATE_FOREVER; - animationDescription->owner = obj; + animationDescription->kind = ANIM_KIND_ANIMATE_FOREVER; + animationDescription->owner = owner; animationDescription->anim = anim; animationDescription->delay = delay; - animationDescription->field_2C = NULL; + animationDescription->artCacheKey = NULL; - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); - if (artLock(fid, &(animationDescription->field_2C)) == NULL) { + int fid = buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, anim, (owner->fid & 0xF000) >> 12, owner->rotation + 1); + if (artLock(fid, &(animationDescription->artCacheKey)) == NULL) { _anim_cleanup(); return -1; } - artUnlock(animationDescription->field_2C); - animationDescription->field_2C = NULL; + artUnlock(animationDescription->artCacheKey); + animationDescription->artCacheKey = NULL; gAnimationDescriptionCurrentIndex++; @@ -1149,27 +1351,25 @@ int reg_anim_animate_forever(Object* obj, int anim, int delay) // 0x415598 int reg_anim_26(int a1, int delay) { - AnimationDescription* ptr; - int v5; - if (_check_registry(NULL) == -1) { _anim_cleanup(); return -1; } - v5 = _anim_free_slot(a1 | 0x0100); - if (v5 == -1) { + int animationSequenceIndex = _anim_free_slot(a1 | ANIMATION_REQUEST_0x100); + if (animationSequenceIndex == -1) { return -1; } - gAnimationSequences[v5].flags = 16; + gAnimationSequences[animationSequenceIndex].flags = ANIM_SEQ_0x10; - ptr = &(gAnimationSequences[gAnimationSequenceCurrentIndex].animations[gAnimationDescriptionCurrentIndex]); - ptr->owner = NULL; - ptr->type = ANIM_KIND_26; - ptr->field_2C = NULL; - ptr->field_28 = v5; - ptr->delay = delay; + AnimationSequence* animationSequence = &(gAnimationSequences[gAnimationSequenceCurrentIndex]); + AnimationDescription* animationDescription = &(animationSequence->animations[gAnimationDescriptionCurrentIndex]); + animationDescription->owner = NULL; + animationDescription->kind = ANIM_KIND_26; + animationDescription->artCacheKey = NULL; + animationDescription->animationSequenceIndex = animationSequenceIndex; + animationDescription->delay = delay; gAnimationDescriptionCurrentIndex++; @@ -1209,27 +1409,27 @@ static int animationRunSequence(int animationSequenceIndex) int rc; Rect rect; - switch (animationDescription->type) { - case ANIM_KIND_OBJ_MOVE_TO_OBJ: - rc = animateMoveObjectToObject(animationDescription->owner, animationDescription->destinationObj, animationDescription->field_28, animationDescription->anim, animationSequenceIndex); + switch (animationDescription->kind) { + case ANIM_KIND_MOVE_TO_OBJECT: + rc = animateMoveObjectToObject(animationDescription->owner, animationDescription->destination, animationDescription->actionPoints, animationDescription->anim, animationSequenceIndex); break; - case ANIM_KIND_OBJ_MOVE_TO_TILE: - rc = animateMoveObjectToTile(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->field_28, animationDescription->anim, animationSequenceIndex); + case ANIM_KIND_MOVE_TO_TILE: + rc = animateMoveObjectToTile(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->actionPoints, animationDescription->anim, animationSequenceIndex); break; - case ANIM_KIND_2: - rc = _anim_move_straight_to_tile(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex, 0x00); + case ANIM_KIND_MOVE_TO_TILE_STRAIGHT: + rc = animateMoveObjectToTileStraight(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex, 0); break; - case ANIM_KIND_KNOCKDOWN: - rc = _anim_move_straight_to_tile(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex, 0x10); + case ANIM_KIND_MOVE_TO_TILE_STRAIGHT_AND_WAIT_FOR_COMPLETE: + rc = animateMoveObjectToTileStraight(animationDescription->owner, animationDescription->tile, animationDescription->elevation, animationDescription->anim, animationSequenceIndex, ANIM_SAD_WAIT_FOR_COMPLETION); break; case ANIM_KIND_ANIMATE: rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, 0); break; - case ANIM_KIND_ANIMATE_REVERSE: - rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, 0x01); + case ANIM_KIND_ANIMATE_REVERSED: + rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, ANIM_SAD_REVERSE); break; - case ANIM_KIND_6: - rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, 0x40); + case ANIM_KIND_ANIMATE_AND_HIDE: + rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, ANIM_SAD_HIDE_ON_END); if (rc == -1) { Rect rect; if (objectHide(animationDescription->owner, &rect) == 0) { @@ -1243,9 +1443,9 @@ static int animationRunSequence(int animationSequenceIndex) } break; case ANIM_KIND_ANIMATE_FOREVER: - rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, 0x80); + rc = _anim_animate(animationDescription->owner, animationDescription->anim, animationSequenceIndex, ANIM_SAD_FOREVER); break; - case ANIM_KIND_SET_ROTATION_TO_TILE: + case ANIM_KIND_ROTATE_TO_TILE: if (!_critter_is_prone(animationDescription->owner)) { int rotation = tileGetRotationTo(animationDescription->owner->tile, animationDescription->tile); _dude_stand(animationDescription->owner, rotation, -1); @@ -1268,61 +1468,61 @@ static int animationRunSequence(int animationSequenceIndex) } rc = 0; break; - case ANIM_KIND_EXEC: - rc = animationDescription->proc(animationDescription->destinationObj, animationDescription->owner); + case ANIM_KIND_CALLBACK: + rc = animationDescription->callback(animationDescription->param1, animationDescription->param2); if (rc == 0) { rc = _anim_set_continue(animationSequenceIndex, 0); } break; - case ANIM_KIND_EXEC_2: - rc = animationDescription->field_20(animationDescription->destinationObj, animationDescription->owner, animationDescription->field_28_obj); + case ANIM_KIND_CALLBACK3: + rc = animationDescription->callback3(animationDescription->param1, animationDescription->param2, animationDescription->param3); if (rc == 0) { rc = _anim_set_continue(animationSequenceIndex, 0); } break; - case ANIM_KIND_14: - if (animationDescription->field_24 == 32) { + case ANIM_KIND_SET_FLAG: + if (animationDescription->objectFlag == OBJECT_LIGHTING) { if (_obj_turn_on_light(animationDescription->owner, &rect) == 0) { tileWindowRefreshRect(&rect, animationDescription->owner->elevation); } - } else if (animationDescription->field_24 == 1) { + } else if (animationDescription->objectFlag == OBJECT_HIDDEN) { if (objectHide(animationDescription->owner, &rect) == 0) { tileWindowRefreshRect(&rect, animationDescription->owner->elevation); } } else { - animationDescription->owner->flags |= animationDescription->field_24; + animationDescription->owner->flags |= animationDescription->objectFlag; } rc = _anim_set_continue(animationSequenceIndex, 0); break; - case ANIM_KIND_15: - if (animationDescription->field_24 == 32) { + case ANIM_KIND_UNSET_FLAG: + if (animationDescription->objectFlag == OBJECT_LIGHTING) { if (_obj_turn_off_light(animationDescription->owner, &rect) == 0) { tileWindowRefreshRect(&rect, animationDescription->owner->elevation); } - } else if (animationDescription->field_24 == 1) { + } else if (animationDescription->objectFlag == OBJECT_HIDDEN) { if (objectShow(animationDescription->owner, &rect) == 0) { tileWindowRefreshRect(&rect, animationDescription->owner->elevation); } } else { - animationDescription->owner->flags &= ~animationDescription->field_24; + animationDescription->owner->flags &= ~animationDescription->objectFlag; } rc = _anim_set_continue(animationSequenceIndex, 0); break; - case ANIM_KIND_16: + case ANIM_KIND_TOGGLE_FLAT: if (_obj_toggle_flat(animationDescription->owner, &rect) == 0) { tileWindowRefreshRect(&rect, animationDescription->owner->elevation); } rc = _anim_set_continue(animationSequenceIndex, 0); break; - case ANIM_KIND_17: + case ANIM_KIND_SET_FID: rc = _anim_change_fid(animationDescription->owner, animationSequenceIndex, animationDescription->fid); break; - case ANIM_KIND_18: + case ANIM_KIND_TAKE_OUT_WEAPON: rc = _anim_animate(animationDescription->owner, ANIM_TAKE_OUT, animationSequenceIndex, animationDescription->tile); break; - case ANIM_KIND_19: + case ANIM_KIND_SET_LIGHT_DISTANCE: objectSetLight(animationDescription->owner, animationDescription->lightDistance, animationDescription->owner->lightIntensity, &rect); tileWindowRefreshRect(&rect, animationDescription->owner->elevation); rc = _anim_set_continue(animationSequenceIndex, 0); @@ -1333,8 +1533,8 @@ static int animationRunSequence(int animationSequenceIndex) case ANIM_KIND_23: rc = _check_for_falling(animationDescription->owner, animationDescription->anim, animationSequenceIndex); break; - case ANIM_KIND_24: - if (animationDescription->tile) { + case ANIM_KIND_TOGGLE_OUTLINE: + if (animationDescription->outline) { if (objectEnableOutline(animationDescription->owner, &rect) == 0) { tileWindowRefreshRect(&rect, animationDescription->owner->elevation); } @@ -1346,13 +1546,13 @@ static int animationRunSequence(int animationSequenceIndex) rc = _anim_set_continue(animationSequenceIndex, 0); break; case ANIM_KIND_26: - gAnimationSequences[animationDescription->field_28].flags &= ~0x10; - rc = _anim_set_continue(animationDescription->field_28, 1); + gAnimationSequences[animationDescription->animationSequenceIndex].flags &= ~ANIM_SEQ_0x10; + rc = _anim_set_continue(animationDescription->animationSequenceIndex, 1); if (rc != -1) { rc = _anim_set_continue(animationSequenceIndex, 0); } break; - case ANIM_KIND_28: + case ANIM_KIND_NOOP: rc = _anim_set_continue(animationSequenceIndex, 0); break; default: @@ -1420,7 +1620,7 @@ static int _anim_set_end(int animationSequenceIndex) for (i = 0; i < animationSequence->length; i++) { animationDescription = &(animationSequence->animations[i]); - if (animationDescription->type == ANIM_KIND_HIDE && ((i < animationSequence->animationIndex) || (animationDescription->field_24 & 0x01))) { + if (animationDescription->kind == ANIM_KIND_HIDE && ((i < animationSequence->animationIndex) || (animationDescription->extendedFlags & ANIMATION_SEQUENCE_FORCED))) { objectDestroy(animationDescription->owner, &v27); tileWindowRefreshRect(&v27, animationDescription->owner->elevation); } @@ -1428,20 +1628,20 @@ static int _anim_set_end(int animationSequenceIndex) for (i = 0; i < animationSequence->length; i++) { animationDescription = &(animationSequence->animations[i]); - if (animationDescription->field_2C) { - artUnlock(animationDescription->field_2C); + if (animationDescription->artCacheKey) { + artUnlock(animationDescription->artCacheKey); } - if (animationDescription->type != 11 && animationDescription->type != 12) { + if (animationDescription->kind != 11 && animationDescription->kind != 12) { // TODO: Check. - if (animationDescription->type != ANIM_KIND_26) { + if (animationDescription->kind != ANIM_KIND_26) { Object* owner = animationDescription->owner; - if (((owner->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { + if (FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER) { int j = 0; for (; j < i; j++) { AnimationDescription* ad = &(animationSequence->animations[j]); if (owner == ad->owner) { - if (ad->type != 11 && ad->type != 12) { + if (ad->kind != ANIM_KIND_CALLBACK && ad->kind != ANIM_KIND_CALLBACK3) { break; } } @@ -1451,7 +1651,7 @@ static int _anim_set_end(int animationSequenceIndex) int k = 0; for (; k < animationSequence->animationIndex; k++) { AnimationDescription* ad = &(animationSequence->animations[k]); - if (ad->type == 10 && ad->owner == owner) { + if (ad->kind == ANIM_KIND_HIDE && ad->owner == owner) { break; } } @@ -1464,7 +1664,7 @@ static int _anim_set_end(int animationSequenceIndex) } } - if ((animationSequence->flags & 0x80) == 0 && !_critter_is_prone(owner)) { + if ((animationSequence->flags & ANIM_SEQ_NO_STAND) == 0 && !_critter_is_prone(owner)) { _dude_stand(owner, owner->rotation, -1); } } @@ -1472,11 +1672,11 @@ static int _anim_set_end(int animationSequenceIndex) } } } else if (i >= animationSequence->field_0) { - if (animationDescription->field_24 & 0x01) { - animationDescription->proc(animationDescription->destinationObj, animationDescription->owner); + if (animationDescription->extendedFlags & ANIMATION_SEQUENCE_FORCED) { + animationDescription->callback(animationDescription->param1, animationDescription->param2); } else { - if (animationDescription->type == ANIM_KIND_EXEC && animationDescription->soundProc == _gsnd_anim_sound) { - soundEffectDelete(animationDescription->sound); + if (animationDescription->kind == ANIM_KIND_CALLBACK && animationDescription->callback == (AnimationCallback*)_gsnd_anim_sound) { + soundEffectDelete((Sound*)animationDescription->param1); } } } @@ -1484,12 +1684,12 @@ static int _anim_set_end(int animationSequenceIndex) animationSequence->animationIndex = -1; animationSequence->field_0 = -1000; - if ((animationSequence->flags & 0x02) != 0) { + if ((animationSequence->flags & ANIM_SEQ_COMBAT_ANIM_STARTED) != 0) { _combat_anim_finished(); } if (_anim_in_bk) { - animationSequence->flags = 0x20; + animationSequence->flags = ANIM_SEQ_0x20; } else { animationSequence->flags = 0; } @@ -1506,11 +1706,11 @@ static bool canUseDoor(Object* critter, Object* door) } } - if ((critter->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) { return false; } - if ((door->fid & 0xF000000) >> 24 != OBJ_TYPE_SCENERY) { + if (FID_TYPE(door->fid) != OBJ_TYPE_SCENERY) { return false; } @@ -1556,7 +1756,7 @@ int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotation bool isCritter = false; int kt = 0; - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { isCritter = true; kt = critterGetKillType(object); } @@ -2007,6 +2207,185 @@ static int animateMoveObjectToObject(Object* from, Object* to, int a3, int anim, return 0; } +// 0x41695C +int _make_stair_path(Object* object, int from, int fromElevation, int to, int toElevation, STRUCT_530014_28* a6, Object** obstaclePtr) +{ + int elevation = fromElevation; + if (elevation > toElevation) { + elevation = toElevation; + } + + int fromX; + int fromY; + tileToScreenXY(from, &fromX, &fromY, fromElevation); + fromX += 16; + fromY += 8; + + int toX; + int toY; + tileToScreenXY(to, &toX, &toY, toElevation); + toX += 16; + toY += 8; + + if (obstaclePtr != NULL) { + *obstaclePtr = NULL; + } + + int ddx = 2 * abs(toX - fromX); + + int stepX; + int deltaX = toX - fromX; + if (deltaX > 0) { + stepX = 1; + } else if (deltaX < 0) { + stepX = -1; + } else { + stepX = 0; + } + + int ddy = 2 * abs(toY - fromY); + + int stepY; + int deltaY = toY - fromY; + if (deltaY > 0) { + stepY = 1; + } else if (deltaY < 0) { + stepY = -1; + } else { + stepY = 0; + } + + int tileX = fromX; + int tileY = fromY; + + int pathNodeIndex = 0; + int prevTile = from; + int iteration = 0; + int tile; + + if (ddx > ddy) { + int middle = ddy - ddx / 2; + while (true) { + tile = tileFromScreenXY(tileX, tileY, elevation); + + iteration += 1; + if (iteration == 16) { + if (pathNodeIndex >= 200) { + return 0; + } + + if (a6 != NULL) { + STRUCT_530014_28* pathNode = &(a6[pathNodeIndex]); + pathNode->tile = tile; + pathNode->elevation = elevation; + + tileToScreenXY(tile, &fromX, &fromY, elevation); + pathNode->x = tileX - fromX - 16; + pathNode->y = tileY - fromY - 8; + } + + iteration = 0; + pathNodeIndex++; + } + + if (tileX == toX) { + break; + } + + if (middle >= 0) { + tileY += stepY; + middle -= ddx; + } + + tileX += stepX; + middle += ddy; + + if (tile != prevTile) { + if (obstaclePtr != NULL) { + *obstaclePtr = _obj_blocking_at(object, tile, object->elevation); + if (*obstaclePtr != NULL) { + break; + } + } + prevTile = tile; + } + } + } else { + int middle = ddx - ddy / 2; + while (true) { + tile = tileFromScreenXY(tileX, tileY, elevation); + + iteration += 1; + if (iteration == 16) { + if (pathNodeIndex >= 200) { + return 0; + } + + if (a6 != NULL) { + STRUCT_530014_28* pathNode = &(a6[pathNodeIndex]); + pathNode->tile = tile; + pathNode->elevation = elevation; + + tileToScreenXY(tile, &fromX, &fromY, elevation); + pathNode->x = tileX - fromX - 16; + pathNode->y = tileY - fromY - 8; + } + + iteration = 0; + pathNodeIndex++; + } + + if (tileY == toY) { + break; + } + + if (middle >= 0) { + tileX += stepX; + middle -= ddy; + } + + tileY += stepY; + middle += ddx; + + if (tile != prevTile) { + if (obstaclePtr != NULL) { + *obstaclePtr = _obj_blocking_at(object, tile, object->elevation); + if (*obstaclePtr != NULL) { + break; + } + } + prevTile = tile; + } + } + } + + if (iteration != 0) { + if (pathNodeIndex >= 200) { + return 0; + } + + if (a6 != NULL) { + STRUCT_530014_28* pathNode = &(a6[pathNodeIndex]); + pathNode->tile = tile; + pathNode->elevation = elevation; + + tileToScreenXY(tile, &fromX, &fromY, elevation); + pathNode->x = tileX - fromX - 16; + pathNode->y = tileY - fromY - 8; + } + + pathNodeIndex++; + } else { + if (pathNodeIndex > 0) { + if (a6 != NULL) { + a6[pathNodeIndex - 1].elevation = toElevation; + } + } + } + + return pathNodeIndex; +} + // 0x416CFC static int animateMoveObjectToTile(Object* obj, int tile, int elev, int a4, int anim, int animationSequenceIndex) { @@ -2045,13 +2424,13 @@ static int _anim_move(Object* obj, int tile, int elev, int a3, int anim, int a5, sad->obj = obj; if (a5) { - sad->flags = 0x20; + sad->flags = ANIM_SAD_0x20; } else { sad->flags = 0; } sad->field_20 = -2000; - sad->fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + sad->fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); sad->animationTimestamp = 0; sad->ticksPerFrame = animationComputeTicksPerFrame(obj, sad->fid); sad->field_24 = tile; @@ -2072,7 +2451,7 @@ static int _anim_move(Object* obj, int tile, int elev, int a3, int anim, int a5, } // 0x416F54 -static int _anim_move_straight_to_tile(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex, int flags) +static int animateMoveObjectToTileStraight(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex, int flags) { if (gAnimationCurrentSad == ANIMATION_SAD_LIST_CAPACITY) { return -1; @@ -2080,12 +2459,12 @@ static int _anim_move_straight_to_tile(Object* obj, int tile, int elevation, int AnimationSad* sad = &(gAnimationSads[gAnimationCurrentSad]); sad->obj = obj; - sad->flags = flags | 0x02; + sad->flags = flags | ANIM_SAD_STRAIGHT; if (anim == -1) { sad->fid = obj->fid; - sad->flags |= 0x04; + sad->flags |= ANIM_SAD_NO_ANIM; } else { - sad->fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + sad->fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); } sad->field_20 = -2000; sad->animationTimestamp = 0; @@ -2093,8 +2472,8 @@ static int _anim_move_straight_to_tile(Object* obj, int tile, int elevation, int sad->animationSequenceIndex = animationSequenceIndex; int v15; - if (((obj->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { - if (((obj->fid & 0xFF0000) >> 16) == ANIM_JUMP_BEGIN) + if (FID_TYPE(obj->fid) == OBJ_TYPE_CRITTER) { + if (FID_ANIM_TYPE(obj->fid) == ANIM_JUMP_BEGIN) v15 = 16; else v15 = 4; @@ -2121,20 +2500,19 @@ static int _anim_move_on_stairs(Object* obj, int tile, int elevation, int anim, } AnimationSad* sad = &(gAnimationSads[gAnimationCurrentSad]); - sad->flags = 0x02; + sad->flags = ANIM_SAD_STRAIGHT; sad->obj = obj; if (anim == -1) { sad->fid = obj->fid; - sad->flags |= 0x04; + sad->flags |= ANIM_SAD_NO_ANIM; } else { - sad->fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + sad->fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); } sad->field_20 = -2000; sad->animationTimestamp = 0; sad->ticksPerFrame = animationComputeTicksPerFrame(obj, sad->fid); sad->animationSequenceIndex = animationSequenceIndex; - // TODO: Incomplete. - // ptr->field_1C = _make_stair_path(obj, obj->tile_index, obj->elevation, tile, elevation, ptr->field_28, 0); + sad->field_1C = _make_stair_path(obj, obj->tile, obj->elevation, tile, elevation, sad->field_28, NULL); if (sad->field_1C == 0) { sad->field_20 = -1000; return -1; @@ -2157,13 +2535,13 @@ static int _check_for_falling(Object* obj, int anim, int a3) } AnimationSad* sad = &(gAnimationSads[gAnimationCurrentSad]); - sad->flags = 0x02; + sad->flags = ANIM_SAD_STRAIGHT; sad->obj = obj; if (anim == -1) { sad->fid = obj->fid; - sad->flags |= 0x04; + sad->flags |= ANIM_SAD_NO_ANIM; } else { - sad->fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + sad->fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); } sad->field_20 = -2000; sad->animationTimestamp = 0; @@ -2198,7 +2576,7 @@ static void _object_move(int index) objectSetRotation(object, sad->rotations[0], &temp); rectUnion(&dirty, &temp, &dirty); - int fid = buildFid((object->fid & 0xF000000) >> 24, object->fid & 0xFFF, sad->anim, (object->fid & 0xF000) >> 12, object->rotation + 1); + int fid = buildFid(FID_TYPE(object->fid), object->fid & 0xFFF, sad->anim, (object->fid & 0xF000) >> 12, object->rotation + 1); objectSetFid(object, fid, &temp); rectUnion(&dirty, &temp, &dirty); @@ -2260,7 +2638,7 @@ static void _object_move(int index) rectUnion(&dirty, &temp, &dirty); int v17 = 0; - if (isInCombat() && ((object->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { + if (isInCombat() && FID_TYPE(object->fid) == OBJ_TYPE_CRITTER) { int v18 = critterGetMovementPointCostAdjustedForCrippledLegs(object, 1); if (_combat_free_move < v18) { int ap = object->data.critter.combat.ap; @@ -2324,9 +2702,11 @@ static void _object_straight_move(int index) int lastFrame = artGetFrameCount(art) - 1; artUnlock(cacheHandle); - if ((sad->flags & 0x04) == 0 && ((sad->flags & 0x10) == 0 || lastFrame > object->frame)) { - objectSetNextFrame(object, &temp); - rectUnion(&dirtyRect, &temp, &dirtyRect); + if ((sad->flags & ANIM_SAD_NO_ANIM) == 0) { + if ((sad->flags & ANIM_SAD_WAIT_FOR_COMPLETION) == 0 || object->frame < lastFrame) { + objectSetNextFrame(object, &temp); + rectUnion(&dirtyRect, &temp, &dirtyRect); + } } if (sad->field_20 < sad->field_1C) { @@ -2341,8 +2721,10 @@ static void _object_straight_move(int index) sad->field_20++; } - if (sad->field_20 == sad->field_1C && ((sad->flags & 0x10) == 0 || object->frame == lastFrame)) { - sad->field_20 = -1000; + if (sad->field_20 == sad->field_1C) { + if ((sad->flags & ANIM_SAD_WAIT_FOR_COMPLETION) == 0 || object->frame == lastFrame) { + sad->field_20 = -1000; + } } tileWindowRefreshRect(&dirtyRect, sad->obj->elevation); @@ -2365,10 +2747,10 @@ static int _anim_animate(Object* obj, int anim, int animationSequenceIndex, int int fid; if (anim == ANIM_TAKE_OUT) { sad->flags = 0; - fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_TAKE_OUT, flags, obj->rotation + 1); + fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_TAKE_OUT, flags, obj->rotation + 1); } else { sad->flags = flags; - fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); } if (!artExists(fid)) { @@ -2417,7 +2799,7 @@ void _object_animate() } if (sad->field_1C > 0) { - if ((sad->flags & 0x02) != 0) { + if ((sad->flags & ANIM_SAD_STRAIGHT) != 0) { _object_straight_move(index); } else { int savedTile = object->tile; @@ -2446,16 +2828,18 @@ void _object_animate() objectGetRect(object, &dirtyRect); if (object->fid == sad->fid) { - if ((sad->flags & 0x01) == 0) { + if ((sad->flags & ANIM_SAD_REVERSE) == 0) { CacheEntry* cacheHandle; Art* art = artLock(object->fid, &cacheHandle); if (art != NULL) { - if ((sad->flags & 0x80) == 0 && object->frame == artGetFrameCount(art) - 1) { + if ((sad->flags & ANIM_SAD_FOREVER) == 0 && object->frame == artGetFrameCount(art) - 1) { sad->field_20 = -1000; artUnlock(cacheHandle); - if ((sad->flags & 0x40) != 0 && objectHide(object, &tempRect) == 0) { - tileWindowRefreshRect(&tempRect, object->elevation); + if ((sad->flags & ANIM_SAD_HIDE_ON_END) != 0) { + if (objectHide(object, &tempRect) == 0) { + tileWindowRefreshRect(&tempRect, object->elevation); + } } _anim_set_continue(sad->animationSequenceIndex, 1); @@ -2480,7 +2864,7 @@ void _object_animate() continue; } - if ((sad->flags & 0x80) != 0 || object->frame != 0) { + if ((sad->flags & ANIM_SAD_FOREVER) != 0 || object->frame != 0) { int x; int y; @@ -2524,7 +2908,7 @@ void _object_animate() art = artLock(object->fid, &cacheHandle); if (art != NULL) { int frame; - if ((sad->flags & 0x01) != 0) { + if ((sad->flags & ANIM_SAD_REVERSE) != 0) { frame = artGetFrameCount(art) - 1; } else { frame = 0; @@ -2561,7 +2945,7 @@ static void _object_anim_compact() { for (int index = 0; index < ANIMATION_SEQUENCE_LIST_CAPACITY; index++) { AnimationSequence* animationSequence = &(gAnimationSequences[index]); - if ((animationSequence->flags & 0x20) != 0) { + if ((animationSequence->flags & ANIM_SEQ_0x20) != 0) { animationSequence->flags = 0; } } @@ -2642,9 +3026,9 @@ int _dude_move(int a1) _lastDestination = tile; - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); - reg_anim_obj_move_to_tile(gDude, tile, gDude->elevation, a1, 0); + animationRegisterMoveToTile(gDude, tile, gDude->elevation, a1, 0); return reg_anim_end(); } @@ -2665,9 +3049,9 @@ int _dude_run(int a1) dudeDisableState(0); } - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); - reg_anim_obj_run_to_tile(gDude, tile_num, gDude->elevation, a4, 0); + animationRegisterRunToTile(gDude, tile_num, gDude->elevation, a4, 0); return reg_anim_end(); } @@ -2683,7 +3067,7 @@ void _dude_fidget() return; } - if (_vcr_status() != 2) { + if (vcrGetState() != VCR_STATE_TURNED_OFF) { return; } @@ -2705,7 +3089,7 @@ void _dude_fidget() break; } - if ((object->flags & OBJECT_HIDDEN) == 0 && ((object->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER && ((object->fid & 0xFF0000) >> 16) == 0 && !critterIsDead(object)) { + if ((object->flags & OBJECT_HIDDEN) == 0 && FID_TYPE(object->fid) == OBJ_TYPE_CRITTER && FID_ANIM_TYPE(object->fid) == ANIM_STAND && !critterIsDead(object)) { Rect rect; objectGetRect(object, &rect); @@ -2723,7 +3107,7 @@ void _dude_fidget() int r = randomBetween(0, v5 - 1); Object* object = dword_56C7E0[r]; - reg_anim_begin(0x201); + reg_anim_begin(ANIMATION_REQUEST_UNRESERVED | ANIMATION_REQUEST_INSIGNIFICANT); bool v8 = false; if (object == gDude) { @@ -2741,10 +3125,10 @@ void _dude_fidget() if (v8) { const char* sfx = sfxBuildCharName(object, ANIM_STAND, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(object, sfx, 0); + animationRegisterPlaySoundEffect(object, sfx, 0); } - reg_anim_animate(object, 0, 0); + animationRegisterAnimate(object, ANIM_STAND, 0); reg_anim_end(); v13 = 20 / v5; @@ -2771,10 +3155,10 @@ void _dude_stand(Object* obj, int rotation, int fid) int x = 0; int y = 0; - int v4 = (obj->fid & 0xF000) >> 12; - if (v4 != 0) { + int weaponAnimationCode = (obj->fid & 0xF000) >> 12; + if (weaponAnimationCode != 0) { if (fid == -1) { - int takeOutFid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_TAKE_OUT, v4, obj->rotation + 1); + int takeOutFid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_TAKE_OUT, weaponAnimationCode, obj->rotation + 1); CacheEntry* takeOutFrmHandle; Art* takeOutFrm = artLock(takeOutFid, &takeOutFrmHandle); if (takeOutFrm != NULL) { @@ -2789,7 +3173,7 @@ void _dude_stand(Object* obj, int rotation, int fid) artUnlock(takeOutFrmHandle); CacheEntry* standFrmHandle; - int standFid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_STAND, 0, obj->rotation + 1); + int standFid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_STAND, 0, obj->rotation + 1); Art* standFrm = artLock(standFid, &standFrmHandle); if (standFrm != NULL) { int offsetX; @@ -2806,12 +3190,12 @@ void _dude_stand(Object* obj, int rotation, int fid) if (fid == -1) { int anim; - if (((obj->fid & 0xFF0000) >> 16) == ANIM_FIRE_DANCE) { + if (FID_ANIM_TYPE(obj->fid) == ANIM_FIRE_DANCE) { anim = ANIM_FIRE_DANCE; } else { anim = ANIM_STAND; } - fid = buildFid((obj->fid & 0xF000000) >> 24, (obj->fid & 0xFFF), anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + fid = buildFid(FID_TYPE(obj->fid), (obj->fid & 0xFFF), anim, (obj->fid & 0xF000) >> 12, obj->rotation + 1); } Rect temp; @@ -2833,16 +3217,16 @@ void _dude_stand(Object* obj, int rotation, int fid) // 0x418574 void _dude_standup(Object* a1) { - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); int anim; - if ((a1->fid & 0xFF0000) >> 16 == ANIM_FALL_BACK) { + if (FID_ANIM_TYPE(a1->fid) == ANIM_FALL_BACK) { anim = ANIM_BACK_TO_STANDING; } else { anim = ANIM_PRONE_TO_STANDING; } - reg_anim_animate(a1, anim, 0); + animationRegisterAnimate(a1, anim, 0); reg_anim_end(); a1->data.critter.combat.results &= ~DAM_KNOCKED_DOWN; } @@ -2872,7 +3256,7 @@ static int _anim_change_fid(Object* obj, int animationSequenceIndex, int fid) Rect rect; Rect v7; - if ((fid & 0xFF0000) >> 16) { + if (FID_ANIM_TYPE(fid)) { objectSetFid(obj, fid, &rect); objectSetFrame(obj, 0, &v7); rectUnion(&rect, &v7, &rect); @@ -2909,8 +3293,8 @@ static int _check_gravity(int tile, int elevation) tileToScreenXY(tile, &x, &y, elevation); int squareTile = squareTileFromScreenXY(x + 2, y + 8, elevation); - int fid = buildFid(4, _square[elevation]->field_0[squareTile] & 0xFFF, 0, 0, 0); - if (fid != buildFid(4, 1, 0, 0, 0)) { + int fid = buildFid(OBJ_TYPE_TILE, _square[elevation]->field_0[squareTile] & 0xFFF, 0, 0, 0); + if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { break; } } @@ -2932,7 +3316,7 @@ static unsigned int animationComputeTicksPerFrame(Object* object, int fid) } if (isInCombat()) { - if (((fid & 0xFF0000) >> 16) == 1) { + if (FID_ANIM_TYPE(fid) == ANIM_WALK) { int playerSpeedup = 0; configGetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_PLAYER_SPEEDUP_KEY, &playerSpeedup); diff --git a/src/animation.h b/src/animation.h index 0fec9f4..e9296c3 100644 --- a/src/animation.h +++ b/src/animation.h @@ -3,36 +3,14 @@ #include "combat_defs.h" #include "obj_types.h" -#include "sound.h" -typedef enum AnimKind { - ANIM_KIND_OBJ_MOVE_TO_OBJ = 0, - ANIM_KIND_OBJ_MOVE_TO_TILE = 1, - ANIM_KIND_2 = 2, - ANIM_KIND_KNOCKDOWN = 3, - ANIM_KIND_ANIMATE = 4, - ANIM_KIND_ANIMATE_REVERSE = 5, - ANIM_KIND_6 = 6, - ANIM_KIND_SET_ROTATION_TO_TILE = 7, - ANIM_KIND_ROTATE_CLOCKWISE = 8, - ANIM_KIND_ROTATE_COUNTER_CLOCKWISE = 9, - ANIM_KIND_HIDE = 10, - ANIM_KIND_EXEC = 11, - ANIM_KIND_EXEC_2 = 12, - ANIM_KIND_14 = 14, - ANIM_KIND_15 = 15, - ANIM_KIND_16 = 16, - ANIM_KIND_17 = 17, - ANIM_KIND_18 = 18, - ANIM_KIND_19 = 19, - ANIM_KIND_20 = 20, - ANIM_KIND_23 = 23, - ANIM_KIND_24 = 24, - ANIM_KIND_ANIMATE_FOREVER = 25, - ANIM_KIND_26 = 26, - ANIM_KIND_27 = 27, - ANIM_KIND_28 = 28, -} AnimKind; +typedef enum AnimationRequestOptions { + ANIMATION_REQUEST_UNRESERVED = 0x01, + ANIMATION_REQUEST_RESERVED = 0x02, + ANIMATION_REQUEST_NO_STAND = 0x04, + ANIMATION_REQUEST_0x100 = 0x100, + ANIMATION_REQUEST_INSIGNIFICANT = 0x200, +} AnimationRequestOptions; // Basic animations: 0-19 // Knockdown and death: 20-35 @@ -112,9 +90,13 @@ typedef enum AnimationType { LAST_SF_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD_SF, } AnimationType; -typedef int AnimationProc(Object*, Object*); -typedef int AnimationSoundProc(Sound*); -typedef int AnimationProc2(Object*, Object*, void*); +#define FID_ANIM_TYPE(value) ((value) & 0xFF0000) >> 16 + +// Signature of animation callback accepting 2 parameters. +typedef int(AnimationCallback)(void* a1, void* a2); + +// Signature of animation callback accepting 3 parameters. +typedef int(AnimationCallback3)(void* a1, void* a2, void* a3); typedef struct STRUCT_530014_28 { int tile; @@ -133,28 +115,31 @@ int _register_priority(int a1); int reg_anim_clear(Object* a1); int reg_anim_end(); int animationIsBusy(Object* a1); -int reg_anim_obj_move_to_obj(Object* a1, Object* a2, int actionPoints, int delay); -int reg_anim_obj_run_to_obj(Object* owner, Object* destination, int actionPoints, int delay); -int reg_anim_obj_move_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay); -int reg_anim_obj_run_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay); -int reg_anim_2(Object* obj, int tile_num, int elev, int a4, int a5); -int reg_anim_knockdown(Object* obj, int tile, int elev, int anim, int delay); -int reg_anim_animate(Object* obj, int anim, int delay); -int reg_anim_animate_reverse(Object* obj, int anim, int delay); -int reg_anim_6(Object* obj, int anim, int delay); -int reg_anim_set_rotation_to_tile(Object* owner, int tile); -int reg_anim_rotate_clockwise(Object* obj); -int reg_anim_rotate_counter_clockwise(Object* obj); -int reg_anim_hide(Object* obj); -int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay); -int reg_anim_12(Object* a1, Object* a2, void* a3, AnimationProc2* proc, int delay); -int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay); -int reg_anim_15(Object* obj, int a2, int a3); -int reg_anim_17(Object* obj, int fid, int a3); -int reg_anim_18(Object* obj, int a2, int a3); -int reg_anim_update_light(Object* obj, int fid, int a3); -int reg_anim_play_sfx(Object* obj, const char* a2, int a3); -int reg_anim_animate_forever(Object* obj, int a2, int a3); +int animationRegisterMoveToObject(Object* owner, Object* destination, int actionPoints, int delay); +int animationRegisterRunToObject(Object* owner, Object* destination, int actionPoints, int delay); +int animationRegisterMoveToTile(Object* owner, int tile, int elevation, int actionPoints, int delay); +int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actionPoints, int delay); +int animationRegisterMoveToTileStraight(Object* object, int tile, int elevation, int anim, int delay); +int animationRegisterMoveToTileStraightAndWaitForComplete(Object* owner, int tile, int elev, int anim, int delay); +int animationRegisterAnimate(Object* owner, int anim, int delay); +int animationRegisterAnimateReversed(Object* owner, int anim, int delay); +int animationRegisterAnimateAndHide(Object* owner, int anim, int delay); +int animationRegisterRotateToTile(Object* owner, int tile); +int animationRegisterRotateClockwise(Object* owner); +int animationRegisterRotateCounterClockwise(Object* owner); +int animationRegisterHideObject(Object* object); +int animationRegisterHideObjectForced(Object* object); +int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int delay); +int animationRegisterCallback3(void* a1, void* a2, void* a3, AnimationCallback3* proc, int delay); +int animationRegisterCallbackForced(void* a1, void* a2, AnimationCallback* proc, int delay); +int animationRegisterSetFlag(Object* object, int flag, int delay); +int animationRegisterUnsetFlag(Object* object, int flag, int delay); +int animationRegisterSetFid(Object* owner, int fid, int delay); +int animationRegisterTakeOutWeapon(Object* owner, int weaponAnimationCode, int delay); +int animationRegisterSetLightDistance(Object* owner, int lightDistance, int delay); +int animationRegisterToggleOutline(Object* object, bool outline, int delay); +int animationRegisterPlaySoundEffect(Object* owner, const char* soundEffectName, int delay); +int animationRegisterAnimateForever(Object* owner, int anim, int delay); int reg_anim_26(int a1, int a2); 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); diff --git a/src/art.cc b/src/art.cc index eddb575..fab0165 100644 --- a/src/art.cc +++ b/src/art.cc @@ -3,6 +3,7 @@ #include "animation.h" #include "debug.h" #include "draw.h" +#include "game.h" #include "game_config.h" #include "memory.h" #include "object.h" @@ -126,10 +127,8 @@ static int* gArtCritterFidShoudRunData; int artInit() { char path[COMPAT_MAX_PATH]; - int i; File* stream; - char str[200]; - char *ptr, *curr; + char string[200]; int cacheSize; if (!configGetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_ART_CACHE_SIZE_KEY, &cacheSize)) { @@ -147,20 +146,20 @@ int artInit() gArtLanguageInitialized = true; } - for (i = 0; i < 11; i++) { - gArtListDescriptions[i].flags = 0; - sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[i].name, gArtListDescriptions[i].name); + for (int objectType = 0; objectType < OBJ_TYPE_COUNT; objectType++) { + gArtListDescriptions[objectType].flags = 0; + sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[objectType].name, gArtListDescriptions[objectType].name); - if (artReadList(path, &(gArtListDescriptions[i].fileNames), &(gArtListDescriptions[i].fileNamesLength)) != 0) { + if (artReadList(path, &(gArtListDescriptions[objectType].fileNames), &(gArtListDescriptions[objectType].fileNamesLength)) != 0) { debugPrint("art_read_lst failed in art_init\n"); cacheFree(&gArtCache); return -1; } } - _anon_alias = (int*)internal_malloc(sizeof(*_anon_alias) * gArtListDescriptions[1].fileNamesLength); + _anon_alias = (int*)internal_malloc(sizeof(*_anon_alias) * gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength); if (_anon_alias == NULL) { - gArtListDescriptions[1].fileNamesLength = 0; + gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength = 0; debugPrint("Out of memory for anon_alias in art_init\n"); cacheFree(&gArtCache); return -1; @@ -168,17 +167,17 @@ int artInit() gArtCritterFidShoudRunData = (int*)internal_malloc(sizeof(*gArtCritterFidShoudRunData) * gArtListDescriptions[1].fileNamesLength); if (gArtCritterFidShoudRunData == NULL) { - gArtListDescriptions[1].fileNamesLength = 0; + gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength = 0; debugPrint("Out of memory for artCritterFidShouldRunData in art_init\n"); cacheFree(&gArtCache); return -1; } - for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) { - gArtCritterFidShoudRunData[i] = 0; + for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) { + gArtCritterFidShoudRunData[critterIndex] = 0; } - sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[1].name, gArtListDescriptions[1].name); + sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[OBJ_TYPE_CRITTER].name, gArtListDescriptions[OBJ_TYPE_CRITTER].name); stream = fileOpen(path, "rt"); if (stream == NULL) { @@ -206,75 +205,70 @@ int artInit() tribalMaleFileName = gDefaultTribalMaleFileName; } - char *tribalFemaleFileName = NULL; + char* tribalFemaleFileName = NULL; configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, &tribalFemaleFileName); if (tribalFemaleFileName == NULL || tribalFemaleFileName[0] == '\0') { tribalFemaleFileName = gDefaultTribalFemaleFileName; } - ptr = gArtListDescriptions[1].fileNames; - for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) { - if (compat_stricmp(ptr, jumpsuitMaleFileName) == 0) { - _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE] = i; - } else if (compat_stricmp(ptr, jumpsuitFemaleFileName) == 0) { - _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE] = i; + char* critterFileNames = gArtListDescriptions[OBJ_TYPE_CRITTER].fileNames; + for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) { + if (compat_stricmp(critterFileNames, "hmjmps") == 0) { + _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE] = critterIndex; + } else if (compat_stricmp(critterFileNames, "hfjmps") == 0) { + _art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE] = critterIndex; } - if (compat_stricmp(ptr, tribalMaleFileName) == 0) { - _art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = i; - _art_vault_guy_num = i; - } else if (compat_stricmp(ptr, tribalFemaleFileName) == 0) { - _art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = i; + if (compat_stricmp(critterFileNames, "hmwarr") == 0) { + _art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = critterIndex; + _art_vault_guy_num = critterIndex; + } else if (compat_stricmp(critterFileNames, "hfprim") == 0) { + _art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = critterIndex; } - ptr += 13; + critterFileNames += 13; } - for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) { - if (!fileReadString(str, sizeof(str), stream)) { + for (int critterIndex = 0; critterIndex < gArtListDescriptions[OBJ_TYPE_CRITTER].fileNamesLength; critterIndex++) { + if (!fileReadString(string, sizeof(string), stream)) { break; } - ptr = str; - curr = ptr; - while (*curr != '\0' && *curr != ',') { - curr++; - } + char* sep1 = strchr(string, ','); + if (sep1 != NULL) { + _anon_alias[critterIndex] = atoi(sep1 + 1); - if (*curr != '\0') { - _anon_alias[i] = atoi(curr + 1); - - ptr = curr + 1; - curr = ptr; - while (*curr != '\0' && *curr != ',') { - curr++; + char* sep2 = strchr(sep1 + 1, ','); + if (sep2 != NULL) { + gArtCritterFidShoudRunData[critterIndex] = atoi(sep2 + 1); + } else { + gArtCritterFidShoudRunData[critterIndex] = 0; } - - gArtCritterFidShoudRunData[i] = *curr != '\0' ? atoi(ptr) : 0; } else { - _anon_alias[i] = _art_vault_guy_num; - gArtCritterFidShoudRunData[i] = 1; + _anon_alias[critterIndex] = _art_vault_guy_num; + gArtCritterFidShoudRunData[critterIndex] = 1; } } fileClose(stream); - ptr = gArtListDescriptions[4].fileNames; - for (i = 0; i < gArtListDescriptions[4].fileNamesLength; i++) { - if (compat_stricmp(ptr, "grid001.frm") == 0) { - _art_mapper_blank_tile = i; + char* tileFileNames = gArtListDescriptions[OBJ_TYPE_TILE].fileNames; + for (int tileIndex = 0; tileIndex < gArtListDescriptions[OBJ_TYPE_TILE].fileNamesLength; tileIndex++) { + if (compat_stricmp(tileFileNames, "grid001.frm") == 0) { + _art_mapper_blank_tile = tileIndex; } + tileFileNames += 13; } - gHeadDescriptions = (HeadDescription*)internal_malloc(sizeof(HeadDescription) * gArtListDescriptions[8].fileNamesLength); + gHeadDescriptions = (HeadDescription*)internal_malloc(sizeof(*gHeadDescriptions) * gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength); if (gHeadDescriptions == NULL) { - gArtListDescriptions[8].fileNamesLength = 0; + gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength = 0; debugPrint("Out of memory for head_info in art_init\n"); cacheFree(&gArtCache); return -1; } - sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[8].name, gArtListDescriptions[8].name); + sprintf(path, "%s%s%s\\%s.lst", _cd_path_base, "art\\", gArtListDescriptions[OBJ_TYPE_HEAD].name, gArtListDescriptions[OBJ_TYPE_HEAD].name); stream = fileOpen(path, "rt"); if (stream == NULL) { @@ -283,46 +277,42 @@ int artInit() return -1; } - for (i = 0; i < gArtListDescriptions[8].fileNamesLength; i++) { - if (!fileReadString(str, sizeof(str), stream)) { + for (int headIndex = 0; headIndex < gArtListDescriptions[OBJ_TYPE_HEAD].fileNamesLength; headIndex++) { + if (!fileReadString(string, sizeof(string), stream)) { break; } - ptr = str; - curr = ptr; - while (*curr != '\0' && *curr != ',') { - curr++; + char* sep1 = strchr(string, ','); + if (sep1 != NULL) { + *sep1 = '\0'; + } else { + sep1 = string; } - if (*curr != '\0') { - ptr = curr + 1; - curr = ptr; - while (*curr != '\0' && *curr != ',') { - curr++; - } - - if (*curr != '\0') { - gHeadDescriptions[i].goodFidgetCount = atoi(ptr); - - ptr = curr + 1; - curr = ptr; - while (*curr != '\0' && *curr != ',') { - curr++; - } - - if (*curr != '\0') { - gHeadDescriptions[i].neutralFidgetCount = atoi(ptr); - - ptr = curr + 1; - curr = strpbrk(ptr, " ,;\t\n"); - if (curr != NULL) { - *curr = '\0'; - } - - gHeadDescriptions[i].badFidgetCount = atoi(ptr); - } - } + char* sep2 = strchr(sep1, ','); + if (sep2 != NULL) { + *sep2 = '\0'; + } else { + sep2 = sep1; } + + gHeadDescriptions[headIndex].goodFidgetCount = atoi(sep1 + 1); + + char* sep3 = strchr(sep2, ','); + if (sep3 != NULL) { + *sep3 = '\0'; + } else { + sep3 = sep2; + } + + gHeadDescriptions[headIndex].neutralFidgetCount = atoi(sep2 + 1); + + char* sep4 = strpbrk(sep3 + 1, " ,;\t\n"); + if (sep4 != NULL) { + *sep4 = '\0'; + } + + gHeadDescriptions[headIndex].badFidgetCount = atoi(sep3 + 1); } fileClose(stream); @@ -357,19 +347,19 @@ void artExit() // 0x418F1C char* artGetObjectTypeName(int objectType) { - return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].name : NULL; + return objectType >= OBJ_TYPE_ITEM && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].name : NULL; } // 0x418F34 int artIsObjectTypeHidden(int objectType) { - return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0; + return objectType >= OBJ_TYPE_ITEM && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0; } // 0x418F7C int artGetFidgetCount(int headFid) { - if ((headFid & 0xF000000) >> 24 != OBJ_TYPE_HEAD) { + if (FID_TYPE(headFid) != OBJ_TYPE_HEAD) { return 0; } @@ -522,15 +512,15 @@ int artCacheFlush() } // 0x4192B0 -int artCopyFileName(int type, int id, char* dest) +int artCopyFileName(int objectType, int id, char* dest) { ArtListDescription* ptr; - if (type < 0 && type >= 11) { + if (objectType < OBJ_TYPE_ITEM && objectType >= OBJ_TYPE_COUNT) { return -1; } - ptr = &(gArtListDescriptions[type]); + ptr = &(gArtListDescriptions[objectType]); if (id >= ptr->fileNamesLength) { return -1; @@ -622,7 +612,7 @@ char* artBuildFilePath(int fid) v10 = (fid & 0x70000000) >> 28; - v1 = _art_alias_fid(fid); + v1 = artAliasFid(fid); if (v1 != -1) { v2 = v1; } @@ -630,15 +620,15 @@ char* artBuildFilePath(int fid) *_art_name = '\0'; v3 = v2 & 0xFFF; - v4 = (v2 & 0xFF0000) >> 16; + v4 = FID_ANIM_TYPE(v2); v5 = (v2 & 0xF000) >> 12; - type = (v2 & 0xF000000) >> 24; + type = FID_TYPE(v2); if (v3 >= gArtListDescriptions[type].fileNamesLength) { return NULL; } - if (type < 0 || type >= 11) { + if (type < OBJ_TYPE_ITEM || type >= OBJ_TYPE_COUNT) { return NULL; } @@ -669,44 +659,40 @@ char* artBuildFilePath(int fid) // art_read_lst // 0x419664 -static int artReadList(const char* path, char** out_arr, int* out_count) +static int artReadList(const char* path, char** artListPtr, int* artListSizePtr) { - File* stream; - char str[200]; - char* arr; - int count; - char* brk; - - stream = fileOpen(path, "rt"); + File* stream = fileOpen(path, "rt"); if (stream == NULL) { return -1; } - count = 0; - while (fileReadString(str, sizeof(str), stream)) { + int count = 0; + char string[200]; + while (fileReadString(string, sizeof(string), stream)) { count++; } fileSeek(stream, 0, SEEK_SET); - *out_count = count; + *artListSizePtr = count; - arr = (char*)internal_malloc(13 * count); - *out_arr = arr; - if (arr == NULL) { - goto err; + char* artList = (char*)internal_malloc(13 * count); + *artListPtr = artList; + if (artList == NULL) { + fileClose(stream); + return -1; } - while (fileReadString(str, sizeof(str), stream)) { - brk = strpbrk(str, " ,;\r\t\n"); + while (fileReadString(string, sizeof(string), stream)) { + char* brk = strpbrk(string, " ,;\r\t\n"); if (brk != NULL) { *brk = '\0'; } - strncpy(arr, str, 12); - arr[12] = '\0'; + strncpy(artList, string, 12); + artList[12] = '\0'; - arr += 13; + artList += 13; } fileClose(stream); @@ -864,34 +850,24 @@ ArtFrame* artGetFrame(Art* art, int frame, int rotation) // 0x4198C8 bool artExists(int fid) { - int v3; - bool result; + bool result = false; + int oldDb = -1; - v3 = -1; - result = false; - - if ((fid & 0xF000000) >> 24 == 1) { - v3 = _db_current(1); - // _db_current(_critter_db_handle); - _db_current(0); + if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) { + oldDb = _db_current(1); + _db_current(_critter_db_handle); } char* filePath = artBuildFilePath(fid); - if (filePath == NULL) { - goto out; + if (filePath != NULL) { + int fileSize; + if (dbGetFileSize(filePath, &fileSize) != -1) { + result = true; + } } - int fileSize; - if (dbGetFileSize(filePath, &fileSize) == -1) { - goto out; - } - - result = true; - -out: - - if (v3 != -1) { - _db_current(v3); + if (oldDb != -1) { + _db_current(oldDb); } return result; @@ -923,7 +899,7 @@ int _art_alias_num(int index) // 0x4199AC int artCritterFidShouldRun(int fid) { - if ((fid & 0xF000000) >> 24 == 1) { + if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) { return gArtCritterFidShoudRunData[fid & 0xFFF]; } @@ -931,64 +907,61 @@ int artCritterFidShouldRun(int fid) } // 0x4199D4 -int _art_alias_fid(int fid) +int artAliasFid(int fid) { - int v2; - int v3; - int result; + int type = FID_TYPE(fid); + int anim = FID_ANIM_TYPE(fid); + if (type == OBJ_TYPE_CRITTER) { + if (anim == ANIM_ELECTRIFY + || anim == ANIM_BURNED_TO_NOTHING + || anim == ANIM_ELECTRIFIED_TO_NOTHING + || anim == ANIM_ELECTRIFY_SF + || anim == ANIM_BURNED_TO_NOTHING_SF + || anim == ANIM_ELECTRIFIED_TO_NOTHING_SF + || anim == ANIM_FIRE_DANCE + || anim == ANIM_CALLED_SHOT_PIC) { + // NOTE: Original code is slightly different. It uses many mutually + // mirrored bitwise operators. Probably result of some macros for + // getting/setting individual bits on fid. + return (fid & 0x70000000) | ((anim << 16) & 0xFF0000) | 0x1000000 | (fid & 0xF000) | (_anon_alias[fid & 0xFFF] & 0xFFF); + } + } - v2 = (fid & 0xF000000) >> 24; - v3 = (fid & 0xFF0000) >> 16; - - if (v2 != 1 || v3 != 27 && v3 != 29 && v3 != 30 && v3 != 55 && v3 != 57 && v3 != 58 && v3 != 33 && v3 != 64) - result = -1; - else - result = ((fid & 0x70000000) >> 28 << 28) & 0x70000000 | (v3 << 16) & 0xFF0000 | 0x1000000 | (((fid & 0xF000) >> 12) << 12) & 0xF000 | _anon_alias[fid & 0xFFF] & 0xFFF; - - return result; + return -1; } // 0x419A78 static int artCacheGetFileSizeImpl(int fid, int* sizePtr) { - int v4; - char* str; - char* ptr; - int result; - char path[COMPAT_MAX_PATH]; - bool loaded; - int fileSize; + int oldDb = -1; + int result = -1; - v4 = -1; - result = -1; - - if ((fid & 0xF000000) >> 24 == 1) { - v4 = _db_current(1); - // _db_current(_critter_db_handle); - _db_current(0); + if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) { + oldDb = _db_current(1); + _db_current(_critter_db_handle); } - str = artBuildFilePath(fid); - if (str != NULL) { - loaded = false; + char* artFilePath = artBuildFilePath(fid); + if (artFilePath != NULL) { + int fileSize; + bool loaded = false; + if (gArtLanguageInitialized) { - ptr = str; - while (*ptr != '\0' && *ptr != '\\') { - ptr++; + char* pch = strchr(artFilePath, '\\'); + if (pch == NULL) { + pch = artFilePath; } - if (*ptr == '\0') { - ptr = str; - } + char localizedPath[COMPAT_MAX_PATH]; + sprintf(localizedPath, "art\\%s\\%s", gArtLanguage, pch); - sprintf(path, "art\\%s\\%s", gArtLanguage, ptr); - if (dbGetFileSize(path, &fileSize) == 0) { + if (dbGetFileSize(localizedPath, &fileSize) == 0) { loaded = true; } } if (!loaded) { - if (dbGetFileSize(str, &fileSize) == 0) { + if (dbGetFileSize(artFilePath, &fileSize) == 0) { loaded = true; } } @@ -999,8 +972,8 @@ static int artCacheGetFileSizeImpl(int fid, int* sizePtr) } } - if (v4 != -1) { - _db_current(v4); + if (oldDb != -1) { + _db_current(oldDb); } return result; @@ -1009,43 +982,33 @@ static int artCacheGetFileSizeImpl(int fid, int* sizePtr) // 0x419B78 static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data) { - int v4; - char* str; - char* ptr; - int result; - char path[COMPAT_MAX_PATH]; - bool loaded; + int oldDb = -1; + int result = -1; - v4 = -1; - result = -1; - - if ((fid & 0xF000000) >> 24 == 1) { - v4 = _db_current(1); - // _db_current(_critter_db_handle); - _db_current(0); + if (FID_TYPE(fid) == OBJ_TYPE_CRITTER) { + oldDb = _db_current(1); + _db_current(_critter_db_handle); } - str = artBuildFilePath(fid); - if (str != NULL) { - loaded = false; + char* artFileName = artBuildFilePath(fid); + if (artFileName != NULL) { + bool loaded = false; if (gArtLanguageInitialized) { - ptr = str; - while (*ptr != '\0' && *ptr != '\\') { - ptr++; + char* pch = strchr(artFileName, '\\'); + if (pch == NULL) { + pch = artFileName; } - if (*ptr == '\0') { - ptr = str; - } + char localizedPath[COMPAT_MAX_PATH]; + sprintf(localizedPath, "art\\%s\\%s", gArtLanguage, pch); - sprintf(path, "art\\%s\\%s", gArtLanguage, ptr); - if (artRead(str, data) == 0) { + if (artRead(localizedPath, data) == 0) { loaded = true; } } if (!loaded) { - if (artRead(str, data) == 0) { + if (artRead(artFileName, data) == 0) { loaded = true; } } @@ -1057,8 +1020,8 @@ static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data) } } - if (v4 != -1) { - _db_current(v4); + if (oldDb != -1) { + _db_current(oldDb); } return result; @@ -1071,7 +1034,7 @@ static void artCacheFreeImpl(void* ptr) } // 0x419C88 -int buildFid(int objectType, int a2, int anim, int a3, int rotation) +int buildFid(int objectType, int frmId, int animType, int a3, int rotation) { int v7, v8, v9, v10; @@ -1081,13 +1044,13 @@ int buildFid(int objectType, int a2, int anim, int a3, int rotation) goto zero; } - if (anim == 33 || anim < 20 || anim > 35) { + if (animType == ANIM_FIRE_DANCE || animType < ANIM_FALL_BACK || animType > ANIM_FALL_FRONT_BLOOD) { goto zero; } - v7 = ((a3 << 12) & 0xF000) | (anim << 16) & 0xFF0000 | 0x1000000; + v7 = ((a3 << 12) & 0xF000) | (animType << 16) & 0xFF0000 | 0x1000000; v8 = (rotation << 28) & 0x70000000 | v7; - v9 = a2 & 0xFFF; + v9 = frmId & 0xFFF; if (artExists(v9 | v8) != 0) { goto out; @@ -1108,7 +1071,7 @@ zero: out: - return (v10 << 28) & 0x70000000 | (objectType << 24) | (anim << 16) & 0xFF0000 | (a3 << 12) & 0xF000 | a2 & 0xFFF; + return (v10 << 28) & 0x70000000 | (objectType << 24) | (animType << 16) & 0xFF0000 | (a3 << 12) & 0xF000 | frmId & 0xFFF; } // 0x419D60 @@ -1172,3 +1135,75 @@ int artRead(const char* path, unsigned char* data) fileClose(stream); return 0; } + +// NOTE: Unused. +// +// 0x41A070 +int artWriteFrameData(unsigned char* data, File* stream, int count) +{ + unsigned char* ptr = data; + for (int index = 0; index < count; index++) { + ArtFrame* frame = (ArtFrame*)ptr; + + if (fileWriteInt16(stream, frame->width) == -1) return -1; + if (fileWriteInt16(stream, frame->height) == -1) return -1; + if (fileWriteInt32(stream, frame->size) == -1) return -1; + if (fileWriteInt16(stream, frame->x) == -1) return -1; + if (fileWriteInt16(stream, frame->y) == -1) return -1; + if (fileWrite(ptr + sizeof(ArtFrame), frame->size, 1, stream) != 1) return -1; + + ptr += sizeof(ArtFrame) + frame->size; + } + + return 0; +} + +// NOTE: Unused. +// +// 0x41A138 +int artWriteHeader(Art* art, File* stream) +{ + if (fileWriteInt32(stream, art->field_0) == -1) return -1; + if (fileWriteInt16(stream, art->framesPerSecond) == -1) return -1; + if (fileWriteInt16(stream, art->actionFrame) == -1) return -1; + if (fileWriteInt16(stream, art->frameCount) == -1) return -1; + if (fileWriteInt16List(stream, art->xOffsets, ROTATION_COUNT) == -1) return -1; + if (fileWriteInt16List(stream, art->yOffsets, ROTATION_COUNT) == -1) return -1; + if (fileWriteInt32List(stream, art->dataOffsets, ROTATION_COUNT) == -1) return -1; + if (fileWriteInt32(stream, art->field_3A) == -1) return -1; + + return 0; +} + +// NOTE: Unused. +// +// 0x41A1E8 +int artWrite(const char* path, unsigned char* data) +{ + if (data == NULL) { + return -1; + } + + File* stream = fileOpen(path, "wb"); + if (stream == NULL) { + return -1; + } + + Art* art = (Art*)data; + if (artWriteHeader(art, stream) == -1) { + fileClose(stream); + return -1; + } + + for (int index = 0; index < ROTATION_COUNT; index++) { + if (index == 0 || art->dataOffsets[index - 1] != art->dataOffsets[index]) { + if (artWriteFrameData(data + sizeof(Art) + art->dataOffsets[index], stream, art->frameCount) != 0) { + fileClose(stream); + return -1; + } + } + } + + fileClose(stream); + return 0; +} diff --git a/src/art.h b/src/art.h index 79dcc90..2bf1af7 100644 --- a/src/art.h +++ b/src/art.h @@ -127,7 +127,7 @@ unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr); int artUnlock(CacheEntry* cache_entry); int artCacheFlush(); -int artCopyFileName(int a1, int a2, char* a3); +int artCopyFileName(int objectType, int a2, char* a3); int _art_get_code(int a1, int a2, char* a3, char* a4); char* artBuildFilePath(int a1); int artGetFramesPerSecond(Art* art); @@ -144,8 +144,9 @@ bool artExists(int fid); bool _art_fid_valid(int fid); int _art_alias_num(int a1); int artCritterFidShouldRun(int a1); -int _art_alias_fid(int a1); -int buildFid(int a1, int a2, int a3, int a4, int a5); +int artAliasFid(int fid); +int buildFid(int objectType, int frmId, int animType, int a4, int rotation); int artRead(const char* path, unsigned char* data); +int artWrite(const char* path, unsigned char* data); #endif diff --git a/src/automap.cc b/src/automap.cc index 98502c7..b622b34 100644 --- a/src/automap.cc +++ b/src/automap.cc @@ -302,7 +302,7 @@ void automapShow(bool isInGame, bool isUsingScanner) unsigned char* frmData[AUTOMAP_FRM_COUNT]; CacheEntry* frmHandle[AUTOMAP_FRM_COUNT]; for (int index = 0; index < AUTOMAP_FRM_COUNT; index++) { - int fid = buildFid(6, frmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, frmIds[index], 0, 0, 0); frmData[index] = artLockFrameData(fid, 0, 0, &(frmHandle[index])); if (frmData[index] == NULL) { while (--index >= 0) { @@ -482,7 +482,7 @@ static void automapRenderInMapWindow(int window, int elevation, unsigned char* b continue; } - int objectType = (object->fid & 0xF000000) >> 24; + int objectType = FID_TYPE(object->fid); unsigned char objectColor; if ((flags & AUTOMAP_IN_GAME) != 0) { @@ -1048,7 +1048,7 @@ static void _decode_map_data(int elevation) if (object->tile != -1 && (object->flags & OBJECT_SEEN) != 0) { int contentType; - int objectType = (object->fid & 0xF000000) >> 24; + int objectType = FID_TYPE(object->fid); if (objectType == OBJ_TYPE_SCENERY && object->pid != PROTO_ID_0x2000158) { contentType = 2; } else if (objectType == OBJ_TYPE_WALL) { diff --git a/src/cache.cc b/src/cache.cc index c2fe137..959e624 100644 --- a/src/cache.cc +++ b/src/cache.cc @@ -5,8 +5,8 @@ #include "sound.h" #include -#include #include +#include #include // The initial number of cache entries in new cache. diff --git a/src/character_editor.cc b/src/character_editor.cc index 8a9c187..1a25805 100644 --- a/src/character_editor.cc +++ b/src/character_editor.cc @@ -1275,7 +1275,7 @@ static int characterEditorWindowInit() return -1; } - fid = buildFid(6, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0); gCharacterEditorWindowBackgroundBuffer = artLockFrameDataReturningSize(fid, &gCharacterEditorWindowBackgroundHandle, &(gCharacterEditorFrmSize[0].width), &(gCharacterEditorFrmSize[0].height)); if (gCharacterEditorWindowBackgroundBuffer == NULL) { messageListFree(&gCharacterEditorMessageList); @@ -1296,7 +1296,7 @@ static int characterEditorWindowInit() soundContinueAll(); for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) { - fid = buildFid(6, gCharacterEditorFrmIds[i], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, gCharacterEditorFrmIds[i], 0, 0, 0); gCharacterEditorFrmData[i] = artLockFrameDataReturningSize(fid, &(gCharacterEditorFrmHandle[i]), &(gCharacterEditorFrmSize[i].width), &(gCharacterEditorFrmSize[i].height)); if (gCharacterEditorFrmData[i] == NULL) { break; @@ -4892,7 +4892,7 @@ static int characterEditorDrawCardWithOptions(int graphicId, const char* name, c short beginnings[WORD_WRAP_MAX_COUNT]; short beginningsCount; - fid = buildFid(10, graphicId, 0, 0, 0); + fid = buildFid(OBJ_TYPE_SKILLDEX, graphicId, 0, 0, 0); buf = artLockFrameDataReturningSize(fid, &graphicHandle, &(size.width), &(size.height)); if (buf == NULL) { return -1; @@ -5744,7 +5744,7 @@ static int perkDialogShow() CacheEntry* backgroundFrmHandle; int backgroundWidth; int backgroundHeight; - int fid = buildFid(6, 86, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 86, 0, 0, 0); gPerkDialogBackgroundBuffer = artLockFrameDataReturningSize(fid, &backgroundFrmHandle, &backgroundWidth, &backgroundHeight); if (gPerkDialogBackgroundBuffer == NULL) { debugPrint("\n *** Error running perks dialog window ***\n"); @@ -5956,7 +5956,7 @@ static int perkDialogHandleInput(int count, void (*refreshProc)()) soundPlayFile("ib1p1xx1"); rc = 1; } else if (keyCode == 501) { - mouseGetPositionInWindow(gPerkDialogWindow , &gCharacterEditorMouseX, &gCharacterEditorMouseY); + mouseGetPositionInWindow(gPerkDialogWindow, &gCharacterEditorMouseX, &gCharacterEditorMouseY); gPerkDialogCurrentLine = (gCharacterEditorMouseY - PERK_WINDOW_LIST_Y) / v16; if (gPerkDialogCurrentLine >= 0) { if (count - 1 < gPerkDialogCurrentLine) @@ -6526,7 +6526,7 @@ static int perkDialogOptionCompare(const void* a1, const void* a2) // 0x43DB54 static int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description) { - int fid = buildFid(10, frmId, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_SKILLDEX, frmId, 0, 0, 0); CacheEntry* handle; int width; @@ -6611,7 +6611,7 @@ static int perkDialogDrawCard(int frmId, const char* name, const char* rank, cha strcpy(gPerkDialogCardTitle, name); gPerkDialogCardFrmId = frmId; gPerkDialogCardDrawn = true; - + artUnlock(handle); return 0; diff --git a/src/character_selector.cc b/src/character_selector.cc index 681abe7..771773c 100644 --- a/src/character_selector.cc +++ b/src/character_selector.cc @@ -299,7 +299,7 @@ static bool characterSelectorWindowInit() } CacheEntry* backgroundFrmHandle; - backgroundFid = buildFid(6, 174, 0, 0, 0); + backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 174, 0, 0, 0); backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData == NULL) { goto err; @@ -328,13 +328,13 @@ static bool characterSelectorWindowInit() int fid; // Setup "Previous" button. - fid = buildFid(6, 122, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 122, 0, 0, 0); gCharacterSelectorWindowPreviousButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonUpFrmHandle); if (gCharacterSelectorWindowPreviousButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 123, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 123, 0, 0, 0); gCharacterSelectorWindowPreviousButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonDownFrmHandle); if (gCharacterSelectorWindowPreviousButtonDownFrmData == NULL) { goto err; @@ -360,13 +360,13 @@ static bool characterSelectorWindowInit() buttonSetCallbacks(gCharacterSelectorWindowPreviousButton, _gsound_med_butt_press, _gsound_med_butt_release); // Setup "Next" button. - fid = buildFid(6, 124, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 124, 0, 0, 0); gCharacterSelectorWindowNextButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonUpFrmHandle); if (gCharacterSelectorWindowNextButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 125, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 125, 0, 0, 0); gCharacterSelectorWindowNextButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonDownFrmHandle); if (gCharacterSelectorWindowNextButtonDownFrmData == NULL) { goto err; @@ -392,13 +392,13 @@ static bool characterSelectorWindowInit() buttonSetCallbacks(gCharacterSelectorWindowNextButton, _gsound_med_butt_press, _gsound_med_butt_release); // Setup "Take" button. - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); gCharacterSelectorWindowTakeButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonUpFrmHandle); if (gCharacterSelectorWindowTakeButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); gCharacterSelectorWindowTakeButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonDownFrmHandle); if (gCharacterSelectorWindowTakeButtonDownFrmData == NULL) { goto err; @@ -424,12 +424,12 @@ static bool characterSelectorWindowInit() buttonSetCallbacks(gCharacterSelectorWindowTakeButton, _gsound_red_butt_press, _gsound_red_butt_release); // Setup "Modify" button. - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); gCharacterSelectorWindowModifyButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonUpFrmHandle); if (gCharacterSelectorWindowModifyButtonUpFrmData == NULL) goto err; - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); gCharacterSelectorWindowModifyButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonDownFrmHandle); if (gCharacterSelectorWindowModifyButtonDownFrmData == NULL) { goto err; @@ -455,13 +455,13 @@ static bool characterSelectorWindowInit() buttonSetCallbacks(gCharacterSelectorWindowModifyButton, _gsound_red_butt_press, _gsound_red_butt_release); // Setup "Create" button. - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); gCharacterSelectorWindowCreateButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonUpFrmHandle); if (gCharacterSelectorWindowCreateButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); gCharacterSelectorWindowCreateButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonDownFrmHandle); if (gCharacterSelectorWindowCreateButtonDownFrmData == NULL) { goto err; @@ -487,13 +487,13 @@ static bool characterSelectorWindowInit() buttonSetCallbacks(gCharacterSelectorWindowCreateButton, _gsound_red_butt_press, _gsound_red_butt_release); // Setup "Back" button. - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); gCharacterSelectorWindowBackButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonUpFrmHandle); if (gCharacterSelectorWindowBackButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); gCharacterSelectorWindowBackButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonDownFrmHandle); if (gCharacterSelectorWindowBackButtonDownFrmData == NULL) { goto err; @@ -688,7 +688,7 @@ static bool characterSelectorWindowRenderFace() bool success = false; CacheEntry* faceFrmHandle; - int faceFid = buildFid(6, gPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0); + int faceFid = buildFid(OBJ_TYPE_INTERFACE, gPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0); Art* frm = artLock(faceFid, &faceFrmHandle); if (frm != NULL) { unsigned char* data = artGetFrameData(frm, 0, 0); diff --git a/src/color.cc b/src/color.cc index 6676720..614cee1 100644 --- a/src/color.cc +++ b/src/color.cc @@ -2,11 +2,19 @@ #include "core.h" -#include #include +#include #include +#define COLOR_PALETTE_STACK_CAPACITY 16 + +typedef struct ColorPaletteStackEntry { + unsigned char mappedColors[256]; + unsigned char cmap[768]; + unsigned char colorTable[32768]; +} ColorPaletteStackEntry; + static int colorPaletteFileOpen(const char* filePath, int flags); static int colorPaletteFileRead(int fd, void* buffer, size_t size); static int colorPaletteFileClose(int fd); @@ -25,6 +33,12 @@ static char _aColor_cNoError[] = "color.c: No errors\n"; // 0x50F95C static char _aColor_cColorTa[] = "color.c: color table not found\n"; +// 0x50F984 +static char _aColor_cColorpa[] = "color.c: colorpalettestack overflow"; + +// 0x50F9AC +static char aColor_cColor_0[] = "color.c: colorpalettestack underflow"; + // 0x51DF10 static char* _errorStr = _aColor_cNoError; @@ -54,6 +68,9 @@ unsigned char _cmap[768] = { 0x3F, 0x3F, 0x3F }; +// 0x673050 +static ColorPaletteStackEntry* gColorPaletteStack[COLOR_PALETTE_STACK_CAPACITY]; + // 0x673090 unsigned char _systemCmap[256 * 3]; @@ -78,6 +95,9 @@ unsigned char _colorMixMulTable[65536]; // 0x6A38D0 unsigned char _colorTable[32768]; +// 0x6AB8D0 +static int gColorPaletteStackSize; + // 0x6AB928 static ColorPaletteFileReadProc* gColorPaletteFileReadProc; @@ -572,6 +592,60 @@ void colorSetBrightness(double value) _setSystemPalette(_systemCmap); } +// NOTE: Unused. +// +// 0x4C8828 +bool colorPushColorPalette() +{ + if (gColorPaletteStackSize >= COLOR_PALETTE_STACK_CAPACITY) { + _errorStr = _aColor_cColorpa; + return false; + } + + ColorPaletteStackEntry* entry = (ColorPaletteStackEntry*)malloc(sizeof(*entry)); + gColorPaletteStack[gColorPaletteStackSize] = entry; + + memcpy(entry->mappedColors, _mappedColor, sizeof(_mappedColor)); + memcpy(entry->cmap, _cmap, sizeof(_cmap)); + memcpy(entry->colorTable, _colorTable, sizeof(_colorTable)); + + gColorPaletteStackSize++; + + return true; +} + +// NOTE: Unused. +// +// 0x4C88E0 +bool colorPopColorPalette() +{ + if (gColorPaletteStackSize == 0) { + _errorStr = aColor_cColor_0; + return false; + } + + gColorPaletteStackSize--; + + ColorPaletteStackEntry* entry = gColorPaletteStack[gColorPaletteStackSize]; + + memcpy(_mappedColor, entry->mappedColors, sizeof(_mappedColor)); + memcpy(_cmap, entry->cmap, sizeof(_cmap)); + memcpy(_colorTable, entry->colorTable, sizeof(_colorTable)); + + free(entry); + gColorPaletteStack[gColorPaletteStackSize] = NULL; + + _setIntensityTables(); + + for (int index = 0; index < 256; index++) { + _setMixTableColor(index); + } + + _rebuildColorBlendTables(); + + return true; +} + // 0x4C89CC bool _initColors() { @@ -599,5 +673,9 @@ void _colorsClose() _freeColorBlendTable(index); } - // TODO: Incomplete. + for (int index = 0; index < gColorPaletteStackSize; index++) { + free(gColorPaletteStack[index]); + } + + gColorPaletteStackSize = 0; } diff --git a/src/color.h b/src/color.h index 1a4fe04..3976115 100644 --- a/src/color.h +++ b/src/color.h @@ -35,6 +35,8 @@ unsigned char* _getColorBlendTable(int ch); void _freeColorBlendTable(int a1); void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc); void colorSetBrightness(double value); +bool colorPushColorPalette(); +bool colorPopColorPalette(); bool _initColors(); void _colorsClose(); diff --git a/src/combat.cc b/src/combat.cc index 02a6670..4c6740e 100644 --- a/src/combat.cc +++ b/src/combat.cc @@ -96,7 +96,7 @@ int _combatNumTurns = 0; unsigned int gCombatState = COMBAT_STATE_0x02; // 0x510948 -static STRUCT_510948* _aiInfoList = NULL; +static CombatAIInfo* _aiInfoList = NULL; // 0x51094C static STRUCT_664980* _gcsd = NULL; @@ -1989,7 +1989,7 @@ int _find_cid(int a1, int cid, Object** critterList, int critterListLength) int combatLoad(File* stream) { int v14; - STRUCT_510948* ptr; + CombatAIInfo* ptr; int a2; Object* obj; int v24; @@ -2001,7 +2001,7 @@ int combatLoad(File* stream) if (!isInCombat()) { obj = objectFindFirst(); while (obj != NULL) { - if (obj->pid >> 24 == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { if (obj->data.critter.combat.whoHitMeCid == -1) { obj->data.critter.combat.whoHitMe = NULL; } @@ -2071,7 +2071,7 @@ int combatLoad(File* stream) internal_free(_aiInfoList); } - _aiInfoList = (STRUCT_510948*)internal_malloc(sizeof(*_aiInfoList) * _list_total); + _aiInfoList = (CombatAIInfo*)internal_malloc(sizeof(*_aiInfoList) * _list_total); if (_aiInfoList == NULL) { return -1; } @@ -2082,31 +2082,31 @@ int combatLoad(File* stream) if (fileReadInt32(stream, &a2) == -1) return -1; if (a2 == -1) { - ptr->field_0 = 0; + ptr->friendlyDead = NULL; } else { - ptr->field_0 = objectFindById(a2); - if (ptr->field_0 == NULL) return -1; + ptr->friendlyDead = objectFindById(a2); + if (ptr->friendlyDead == NULL) return -1; } if (fileReadInt32(stream, &a2) == -1) return -1; if (a2 == -1) { - ptr->field_4 = 0; + ptr->lastTarget = NULL; } else { - ptr->field_4 = objectFindById(a2); - if (ptr->field_4 == NULL) return -1; + ptr->lastTarget = objectFindById(a2); + if (ptr->lastTarget == NULL) return -1; } if (fileReadInt32(stream, &a2) == -1) return -1; if (a2 == -1) { - ptr->field_8 = 0; + ptr->lastItem = NULL; } else { - ptr->field_8 = objectFindById(a2); - if (ptr->field_8 == NULL) return -1; + ptr->lastItem = objectFindById(a2); + if (ptr->lastItem == NULL) return -1; } - if (fileReadInt32(stream, &(ptr->field_C)) == -1) return -1; + if (fileReadInt32(stream, &(ptr->lastMove)) == -1) return -1; } _combat_begin_extra(gDude); @@ -2138,12 +2138,12 @@ int combatSave(File* stream) } for (int index = 0; index < _list_total; index++) { - STRUCT_510948* ptr = &(_aiInfoList[index]); + CombatAIInfo* ptr = &(_aiInfoList[index]); - if (fileWriteInt32(stream, ptr->field_0 != NULL ? ptr->field_0->id : -1) == -1) return -1; - if (fileWriteInt32(stream, ptr->field_4 != NULL ? ptr->field_4->id : -1) == -1) return -1; - if (fileWriteInt32(stream, ptr->field_8 != NULL ? ptr->field_8->id : -1) == -1) return -1; - if (fileWriteInt32(stream, ptr->field_C) == -1) return -1; + if (fileWriteInt32(stream, ptr->friendlyDead != NULL ? ptr->friendlyDead->id : -1) == -1) return -1; + if (fileWriteInt32(stream, ptr->lastTarget != NULL ? ptr->lastTarget->id : -1) == -1) return -1; + if (fileWriteInt32(stream, ptr->lastItem != NULL ? ptr->lastItem->id : -1) == -1) return -1; + if (fileWriteInt32(stream, ptr->lastMove) == -1) return -1; } return 0; @@ -2285,16 +2285,16 @@ void _combat_data_init(Object* obj) // 0x421850 static int _combatCopyAIInfo(int a1, int a2) { - STRUCT_510948* v3; - STRUCT_510948* v4; + CombatAIInfo* v3; + CombatAIInfo* v4; v3 = &_aiInfoList[a1]; v4 = &_aiInfoList[a2]; - v4->field_0 = v3->field_0; - v4->field_4 = v3->field_4; - v4->field_8 = v3->field_8; - v4->field_C = v3->field_C; + v4->friendlyDead = v3->friendlyDead; + v4->lastTarget = v3->lastTarget; + v4->lastItem = v3->lastItem; + v4->lastMove = v3->lastMove; return 0; } @@ -2314,7 +2314,7 @@ Object* _combatAIInfoGetFriendlyDead(Object* obj) return NULL; } - return _aiInfoList[obj->cid].field_0; + return _aiInfoList[obj->cid].friendlyDead; } // 0x4218AC @@ -2336,7 +2336,7 @@ int _combatAIInfoSetFriendlyDead(Object* a1, Object* a2) return -1; } - _aiInfoList[a1->cid].field_0 = a2; + _aiInfoList[a1->cid].friendlyDead = a2; return 0; } @@ -2356,7 +2356,7 @@ Object* _combatAIInfoGetLastTarget(Object* obj) return NULL; } - return _aiInfoList[obj->cid].field_4; + return _aiInfoList[obj->cid].lastTarget; } // 0x421918 @@ -2382,7 +2382,7 @@ int _combatAIInfoSetLastTarget(Object* a1, Object* a2) a2 = NULL; } - _aiInfoList[a1->cid].field_4 = a2; + _aiInfoList[a1->cid].lastTarget = a2; return 0; } @@ -2405,7 +2405,7 @@ Object* _combatAIInfoGetLastItem(Object* obj) return NULL; } - return _aiInfoList[v1].field_8; + return _aiInfoList[v1].lastItem; } // 0x421998 @@ -2426,7 +2426,7 @@ int _combatAIInfoSetLastItem(Object* obj, Object* a2) return -1; } - _aiInfoList[v2].field_8 = NULL; + _aiInfoList[v2].lastItem = NULL; return 0; } @@ -2446,24 +2446,24 @@ static void _combat_begin(Object* a1) _list_total = objectListCreate(-1, _combat_elev, OBJ_TYPE_CRITTER, &_combat_list); _list_noncom = _list_total; _list_com = 0; - _aiInfoList = (STRUCT_510948*)internal_malloc(sizeof(*_aiInfoList) * _list_total); + _aiInfoList = (CombatAIInfo*)internal_malloc(sizeof(*_aiInfoList) * _list_total); if (_aiInfoList == NULL) { return; } for (int index = 0; index < _list_total; index++) { - STRUCT_510948* ptr = &(_aiInfoList[index]); - ptr->field_0 = NULL; - ptr->field_4 = NULL; - ptr->field_8 = NULL; - ptr->field_C = 0; + CombatAIInfo* ptr = &(_aiInfoList[index]); + ptr->friendlyDead = NULL; + ptr->lastTarget = NULL; + ptr->lastItem = NULL; + ptr->lastMove = 0; } Object* v1 = NULL; for (int index = 0; index < _list_total; index++) { Object* critter = _combat_list[index]; CritterCombatData* combatData = &(critter->data.critter.combat); - combatData->maneuver &= 0x01; + combatData->maneuver &= CRITTER_MANEUVER_0x01; combatData->damageLastTurn = 0; combatData->whoHitMe = NULL; combatData->ap = 0; @@ -2471,7 +2471,7 @@ static void _combat_begin(Object* a1) // NOTE: Not sure about this code, field_C is already reset. if (isInCombat() && critter != NULL && index != -1) { - _aiInfoList[index].field_C = 0; + _aiInfoList[index].lastMove = 0; } scriptSetObjects(critter->sid, NULL, NULL); @@ -2495,16 +2495,16 @@ static void _combat_begin(Object* a1) _gmouse_enable_scrolling(); if (v1 != NULL && !_isLoadingGame()) { - int fid = buildFid((v1->fid & 0xF000000) >> 24, + int fid = buildFid(FID_TYPE(v1->fid), 100, - (v1->fid & 0xFF0000) >> 16, + FID_ANIM_TYPE(v1->fid), (v1->fid & 0xF000) >> 12, (v1->fid & 0x70000000) >> 28); reg_anim_clear(v1); - reg_anim_begin(2); - reg_anim_animate(v1, 6, -1); - reg_anim_17(v1, fid, -1); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterAnimate(v1, ANIM_UP_STAIRS_RIGHT, -1); + animationRegisterSetFid(v1, fid, -1); reg_anim_end(); while (animationIsBusy(v1)) { @@ -2536,7 +2536,7 @@ static void _combat_begin_extra(Object* a1) // 0x421D50 void _combat_update_critter_outline_for_los(Object* critter, bool a2) { - if (critter->pid >> 24 != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return; } @@ -2636,7 +2636,7 @@ static void _combat_over() for (int index = 0; index < _list_noncom + _list_com; index++) { Object* critter = _combat_list[index]; critter->data.critter.combat.damageLastTurn = 0; - critter->data.critter.combat.maneuver = 0; + critter->data.critter.combat.maneuver = CRITTER_MANEUVER_NONE; } for (int index = 0; index < _list_total; index++) { @@ -2649,15 +2649,15 @@ static void _combat_over() scriptSetFixedParam(critter->sid, 0); if (critter->pid == 0x1000098 && !critterIsDead(critter) && !_isLoadingGame()) { - int fid = buildFid((critter->fid & 0xF000000) >> 24, + int fid = buildFid(FID_TYPE(critter->fid), 99, - (critter->fid & 0xFF0000) >> 16, + FID_ANIM_TYPE(critter->fid), (critter->fid & 0xF000) >> 12, (critter->fid & 0x70000000) >> 28); reg_anim_clear(critter); - reg_anim_begin(2); - reg_anim_animate(critter, 6, -1); - reg_anim_17(critter, fid, -1); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterAnimate(critter, ANIM_UP_STAIRS_RIGHT, -1); + animationRegisterSetFid(critter, fid, -1); reg_anim_end(); while (animationIsBusy(critter)) { @@ -2766,7 +2766,7 @@ static void _combat_add_noncoms() for (int index = _list_com; index < _list_com + _list_noncom; index++) { Object* obj = _combat_list[index]; if (_combatai_want_to_join(obj)) { - obj->data.critter.combat.maneuver = 0; + obj->data.critter.combat.maneuver = CRITTER_MANEUVER_NONE; Object** objectPtr1 = &(_combat_list[index]); Object** objectPtr2 = &(_combat_list[_list_com]); @@ -3056,7 +3056,7 @@ static void _combat_set_move_all() if (isInCombat()) { if (object->cid != -1) { - _aiInfoList[object->cid].field_C = 0; + _aiInfoList[object->cid].lastMove = 0; } } } @@ -3330,7 +3330,7 @@ void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode, int _combat_attack(Object* a1, Object* a2, int hitMode, int hitLocation) { if (a1 != gDude && hitMode == HIT_MODE_PUNCH && randomBetween(1, 4) == 1) { - int fid = buildFid(1, a1->fid & 0xFFF, ANIM_KICK_LEG, (a1->fid & 0xF000) >> 12, (a1->fid & 0x70000000) >> 28); + int fid = buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_KICK_LEG, (a1->fid & 0xF000) >> 12, (a1->fid & 0x70000000) >> 28); if (artExists(fid)) { hitMode = HIT_MODE_KICK; } @@ -3422,7 +3422,7 @@ static bool _check_ranged_miss(Attack* attack) _make_straight_path_func(attack->attacker, curr, to, NULL, &critter, 32, _obj_shoot_blocking_at); if (critter != NULL) { if ((critter->flags & OBJECT_SHOOT_THRU) == 0) { - if ((critter->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) { roll = ROLL_SUCCESS; break; } @@ -3479,7 +3479,7 @@ static int _shoot_along_path(Attack* attack, int a2, int a3, int anim) _make_straight_path_func(attack->attacker, v7, a2, NULL, &critter, 32, _obj_shoot_blocking_at); if (critter != NULL) { - if (((critter->fid & 0xF000000) >> 24) != OBJ_TYPE_CRITTER) { + if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) { break; } @@ -3809,7 +3809,7 @@ static int attackCompute(Attack* attack) // compute_explosion_on_extras // 0x423C10 -void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4) +void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4) { Object* attacker; @@ -3852,9 +3852,9 @@ void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4) } } else { v22++; - if (a3 && _item_w_grenade_dmg_radius(attack->weapon) < v22) { + if (isGrenade && _item_w_grenade_dmg_radius(attack->weapon) < v22) { v5 = -1; - } else if (a3 || _item_w_rocket_dmg_radius(attack->weapon) >= v22) { + } else if (isGrenade || _item_w_rocket_dmg_radius(attack->weapon) >= v22) { v5 = tileGetTileInDirection(v19, ROTATION_NE, 1); } else { v5 = -1; @@ -3869,13 +3869,13 @@ void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4) break; } - Object* v11 = _obj_blocking_at(attacker, v5, attack->attacker->elevation); - if (v11 != NULL - && (v11->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER - && (v11->data.critter.combat.results & DAM_DEAD) == 0 - && (v11->flags & OBJECT_SHOOT_THRU) == 0 - && !_combat_is_shot_blocked(v11, v11->tile, tile, NULL, NULL)) { - if (v11 == attack->attacker) { + Object* obstacle = _obj_blocking_at(attacker, v5, 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)) { + if (obstacle == attack->attacker) { attack->attackerFlags &= ~DAM_HIT; attackComputeDamage(attack, 1, 2); attack->attackerFlags |= DAM_HIT; @@ -3883,15 +3883,15 @@ void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4) } else { int index; for (index = 0; index < attack->extrasLength; index++) { - if (attack->extras[index] == v11) { + if (attack->extras[index] == obstacle) { break; } } if (index == attack->extrasLength) { attack->extrasHitLocation[index] = HIT_LOCATION_TORSO; - attack->extras[index] = v11; - attackInit(&_explosion_ctd, attack->attacker, v11, attack->hitMode, HIT_LOCATION_TORSO); + attack->extras[index] = obstacle; + attackInit(&_explosion_ctd, attack->attacker, obstacle, attack->hitMode, HIT_LOCATION_TORSO); if (!a4) { _explosion_ctd.attackerFlags |= DAM_HIT; attackComputeDamage(&_explosion_ctd, 1, 2); @@ -3911,11 +3911,11 @@ void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4) static int attackComputeCriticalHit(Attack* attack) { Object* defender = attack->defender; - if (defender != NULL && _critter_flag_check(defender->pid, 1024)) { + if (defender != NULL && _critter_flag_check(defender->pid, CRITTER_FLAG_0x400)) { return 2; } - if (defender != NULL && (defender->pid >> 24) != OBJ_TYPE_CRITTER) { + if (defender != NULL && PID_TYPE(defender->pid) != OBJ_TYPE_CRITTER) { return 2; } @@ -3999,7 +3999,7 @@ static int _attackFindInvalidFlags(Object* critter, Object* item) { int flags = 0; - if (critter != NULL && (critter->pid >> 24) == OBJ_TYPE_CRITTER && _critter_flag_check(critter->pid, 64)) { + if (critter != NULL && PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER && _critter_flag_check(critter->pid, CRITTER_FLAG_0x40)) { flags |= DAM_DROP; } @@ -4015,7 +4015,7 @@ static int attackComputeCriticalFailure(Attack* attack) { attack->attackerFlags |= DAM_HIT; - if (attack->attacker != NULL && _critter_flag_check(attack->attacker->pid, 1024)) { + if (attack->attacker != NULL && _critter_flag_check(attack->attacker->pid, CRITTER_FLAG_0x400)) { return 0; } @@ -4141,7 +4141,7 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in Object* weapon = critterGetWeaponForHitMode(attacker, hitMode); bool targetIsCritter = defender != NULL - ? ((defender->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER + ? FID_TYPE(defender->fid) == OBJ_TYPE_CRITTER : false; bool isRangedWeapon = false; @@ -4323,7 +4323,7 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in } // 0x4247B8 -static void attackComputeDamage(Attack* attack, int ammoQuantity, int a3) +static void attackComputeDamage(Attack* attack, int ammoQuantity, int bonusDamageMultiplier) { int* damagePtr; Object* critter; @@ -4344,7 +4344,7 @@ static void attackComputeDamage(Attack* attack, int ammoQuantity, int a3) *damagePtr = 0; - if ((critter->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) { return; } @@ -4398,7 +4398,7 @@ static void attackComputeDamage(Attack* attack, int ammoQuantity, int a3) damageResistance = 0; } - int damageMultiplier = a3 * weaponGetAmmoDamageMultiplier(attack->weapon); + int damageMultiplier = bonusDamageMultiplier * weaponGetAmmoDamageMultiplier(attack->weapon); int damageDivisor = weaponGetAmmoDamageDivisor(attack->weapon); for (int index = 0; index < ammoQuantity; index++) { @@ -4447,8 +4447,8 @@ static void attackComputeDamage(Attack* attack, int ammoQuantity, int a3) if (knockbackDistancePtr != NULL && (critter->flags & OBJECT_MULTIHEX) == 0 && (damageType == DAMAGE_TYPE_EXPLOSION || attack->weapon == NULL || weaponGetAttackTypeForHitMode(attack->weapon, attack->hitMode) == ATTACK_TYPE_MELEE) - && (critter->pid >> 24) == OBJ_TYPE_CRITTER - && _critter_flag_check(critter->pid, 0x4000) == 0) { + && PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER + && _critter_flag_check(critter->pid, CRITTER_FLAG_0x4000) == 0) { bool shouldKnockback = true; bool hasStonewall = false; if (critter == gDude) { @@ -4488,7 +4488,7 @@ void attackComputeDeathFlags(Attack* attack) void _apply_damage(Attack* attack, bool animated) { Object* attacker = attack->attacker; - bool attackerIsCritter = attacker != NULL && (attacker->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER; + bool attackerIsCritter = attacker != NULL && FID_TYPE(attacker->fid) == OBJ_TYPE_CRITTER; bool v5 = attack->defender != attack->oops; if (attackerIsCritter && (attacker->data.critter.combat.results & DAM_DEAD) != 0) { @@ -4503,7 +4503,7 @@ void _apply_damage(Attack* attack, bool animated) } Object* defender = attack->defender; - bool defenderIsCritter = defender != NULL && (defender->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER; + bool defenderIsCritter = defender != NULL && FID_TYPE(defender->fid) == OBJ_TYPE_CRITTER; if (!defenderIsCritter && !v5) { bool v9 = objectIsPartyMember(attack->defender) && objectIsPartyMember(attack->attacker) ? false : true; @@ -4549,7 +4549,7 @@ void _apply_damage(Attack* attack, bool animated) for (int index = 0; index < attack->extrasLength; index++) { Object* obj = attack->extras[index]; - if ((obj->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER && (obj->data.critter.combat.results & DAM_DEAD) == 0) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_CRITTER && (obj->data.critter.combat.results & DAM_DEAD) == 0) { _set_new_results(obj, attack->extrasFlags[index]); if (defenderIsCritter) { @@ -4579,8 +4579,8 @@ void _apply_damage(Attack* attack, bool animated) // 0x424EE8 static void _check_for_death(Object* object, int damage, int* flags) { - if (object == NULL || !_critter_flag_check(object->pid, 0x0400)) { - if (object == NULL || (object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (object == NULL || !_critter_flag_check(object->pid, CRITTER_FLAG_0x400)) { + if (object == NULL || PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { if (damage > 0) { if (critterGetHitPoints(object) - damage <= 0) { *flags |= DAM_DEAD; @@ -4597,15 +4597,15 @@ static void _set_new_results(Object* critter, int flags) return; } - if (((critter->fid & 0xF000000) >> 24) != OBJ_TYPE_CRITTER) { + if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) { return; } - if (_critter_flag_check(critter->pid, 0x0400)) { + if (_critter_flag_check(critter->pid, CRITTER_FLAG_0x400)) { return; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return; } @@ -4635,11 +4635,11 @@ static void _damage_object(Object* a1, int damage, bool animated, int a4, Object return; } - if ((a1->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(a1->fid) != OBJ_TYPE_CRITTER) { return; } - if (_critter_flag_check(a1->pid, 1024)) { + if (_critter_flag_check(a1->pid, CRITTER_FLAG_0x400)) { return; } @@ -4764,7 +4764,7 @@ void _combat_display(Attack* attack) && attack->oops != NULL && attack->defender != attack->oops && (attack->attackerFlags & DAM_HIT) != 0) { - if ((attack->defender->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(attack->defender->fid) == OBJ_TYPE_CRITTER) { if (attack->oops == gDude) { // 608 (male) - Oops! %s was hit instead of you! // 708 (female) - Oops! %s was hit instead of you! @@ -4820,7 +4820,7 @@ void _combat_display(Attack* attack) if (v21 != NULL && (v21->data.critter.combat.results & DAM_DEAD) == 0) { text[0] = '\0'; - if ((v21->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(v21->fid) == OBJ_TYPE_CRITTER) { if (attack->defenderHitLocation == HIT_LOCATION_TORSO) { if ((attack->attackerFlags & DAM_CRITICAL) != 0) { switch (attack->defenderDamage) { @@ -5233,7 +5233,7 @@ static void _combat_standup(Object* a1) static void _print_tohit(unsigned char* dest, int destPitch, int accuracy) { CacheEntry* numbersFrmHandle; - int numbersFrmFid = buildFid(6, 82, 0, 0, 0); + int numbersFrmFid = buildFid(OBJ_TYPE_INTERFACE, 82, 0, 0, 0); unsigned char* numbersFrmData = artLockFrameData(numbersFrmFid, 0, 0, &numbersFrmHandle); if (numbersFrmData == NULL) { return; @@ -5325,7 +5325,7 @@ static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hi unsigned char* windowBuffer = windowGetBuffer(gCalledShotWindow); - fid = buildFid(6, 118, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 118, 0, 0, 0); data = artLockFrameData(fid, 0, 0, &handle); if (data == NULL) { windowDestroy(gCalledShotWindow); @@ -5335,14 +5335,14 @@ static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hi blitBufferToBuffer(data, CALLED_SHOT_WINDOW_WIDTH, CALLED_SHOT_WINDOW_HEIGHT, CALLED_SHOT_WINDOW_WIDTH, windowBuffer, CALLED_SHOT_WINDOW_WIDTH); artUnlock(handle); - fid = buildFid(1, critter->fid & 0xFFF, ANIM_CALLED_SHOT_PIC, 0, 0); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_CALLED_SHOT_PIC, 0, 0); data = artLockFrameData(fid, 0, 0, &handle); if (data != NULL) { blitBufferToBuffer(data, 170, 225, 170, windowBuffer + CALLED_SHOT_WINDOW_WIDTH * 31 + 168, CALLED_SHOT_WINDOW_WIDTH); artUnlock(handle); } - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); CacheEntry* upHandle; unsigned char* up = artLockFrameData(fid, 0, 0, &upHandle); @@ -5351,7 +5351,7 @@ static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hi return -1; } - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); CacheEntry* downHandle; unsigned char* down = artLockFrameData(fid, 0, 0, &downHandle); @@ -5710,7 +5710,7 @@ bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5) while (obstacle != NULL && current != to) { _make_straight_path_func(a1, current, to, 0, &obstacle, 32, _obj_shoot_blocking_at); if (obstacle != NULL) { - if ((obstacle->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER && obstacle != a4) { + if (FID_TYPE(obstacle->fid) != OBJ_TYPE_CRITTER && obstacle != a4) { return true; } diff --git a/src/combat.h b/src/combat.h index 285587d..7eab9fe 100644 --- a/src/combat.h +++ b/src/combat.h @@ -1,8 +1,8 @@ #ifndef COMBAT_H #define COMBAT_H -#include "db.h" #include "combat_defs.h" +#include "db.h" #include "obj_types.h" #include "proto_types.h" @@ -35,7 +35,7 @@ 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, int a3, int a4); +void _compute_explosion_on_extras(Attack* attack, int a2, bool isGrenade, int a4); 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); diff --git a/src/combat_ai.cc b/src/combat_ai.cc index ede87ad..f33ecc1 100644 --- a/src/combat_ai.cc +++ b/src/combat_ai.cc @@ -568,7 +568,7 @@ int aiLoad(File* stream) { for (int index = 0; index < gPartyMemberDescriptionsLength; index++) { int pid = gPartyMemberPids[index]; - if (pid != -1 && (pid >> 24) == OBJ_TYPE_CRITTER) { + if (pid != -1 && PID_TYPE(pid) == OBJ_TYPE_CRITTER) { Proto* proto; if (protoGetProto(pid, &proto) == -1) { return -1; @@ -589,7 +589,7 @@ int aiSave(File* stream) { for (int index = 0; index < gPartyMemberDescriptionsLength; index++) { int pid = gPartyMemberPids[index]; - if (pid != -1 && (pid >> 24) == OBJ_TYPE_CRITTER) { + if (pid != -1 && PID_TYPE(pid) == OBJ_TYPE_CRITTER) { Proto* proto; if (protoGetProto(pid, &proto) == -1) { return -1; @@ -897,9 +897,9 @@ int aiSetDisposition(Object* obj, int disposition) // 0x428398 static int _ai_magic_hands(Object* critter, Object* item, int num) { - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); - reg_anim_animate(critter, ANIM_MAGIC_HANDS_MIDDLE, 0); + animationRegisterAnimate(critter, ANIM_MAGIC_HANDS_MIDDLE, 0); if (reg_anim_end() == 0) { if (isInCombat()) { @@ -1128,9 +1128,9 @@ static void _ai_run_away(Object* a1, Object* a2) } if (actionPoints > 0) { - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); _combatai_msg(a1, NULL, AI_MESSAGE_TYPE_RUN, 0); - reg_anim_obj_run_to_tile(a1, destination, a1->elevation, combatData->ap, 0); + animationRegisterRunToTile(a1, destination, a1->elevation, combatData->ap, 0); if (reg_anim_end() == 0) { _combat_turn_run(); } @@ -1175,8 +1175,8 @@ static int _ai_move_away(Object* a1, Object* a2, int a3) } if (actionPoints > 0) { - reg_anim_begin(2); - reg_anim_obj_move_to_tile(a1, destination, a1->elevation, actionPoints, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterMoveToTile(a1, destination, a1->elevation, actionPoints, 0); if (reg_anim_end() == 0) { _combat_turn_run(); } @@ -1560,8 +1560,8 @@ int _caiSetupTeamCombat(Object* a1, Object* a2) obj = objectFindFirstAtElevation(a1->elevation); while (obj != NULL) { - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER && obj != gDude) { - obj->data.critter.combat.maneuver |= 0x01; + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER && obj != gDude) { + obj->data.critter.combat.maneuver |= CRITTER_MANEUVER_0x01; } obj = objectFindNextAtElevation(); } @@ -1719,7 +1719,7 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon avgDamage1 = (maxDamage - minDamage) / 2; if (_item_w_area_damage_radius(weapon1, HIT_MODE_RIGHT_WEAPON_PRIMARY) > 0 && defender != NULL) { attack.weapon = weapon1; - _compute_explosion_on_extras(&attack, 0, _item_w_is_grenade(weapon1), 1); + _compute_explosion_on_extras(&attack, 0, weaponIsGrenade(weapon1), 1); avgDamage1 *= attack.extrasLength + 1; } @@ -1763,7 +1763,7 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon avgDamage2 = (maxDamage - minDamage) / 2; if (_item_w_area_damage_radius(weapon2, HIT_MODE_RIGHT_WEAPON_PRIMARY) > 0 && defender != NULL) { attack.weapon = weapon2; - _compute_explosion_on_extras(&attack, 0, _item_w_is_grenade(weapon2), 1); + _compute_explosion_on_extras(&attack, 0, weaponIsGrenade(weapon2), 1); avgDamage2 *= attack.extrasLength + 1; } @@ -1842,7 +1842,7 @@ static bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode) int rotation = critter->rotation + 1; int animationCode = weaponGetAnimationCode(weapon); int v9 = weaponGetAnimationForHitMode(weapon, hitMode); - int fid = buildFid(1, critter->fid & 0xFFF, v9, animationCode, rotation); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, v9, animationCode, rotation); if (!artExists(fid)) { return false; } @@ -2194,7 +2194,7 @@ static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a return -1; } - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); if (a4) { _combatai_msg(a1, NULL, AI_MESSAGE_TYPE_MOVE, 0); @@ -2214,7 +2214,7 @@ static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a _moveBlockObj = NULL; if (pathfinderFindPath(a1, a1->tile, a2->tile, NULL, 0, _obj_ai_blocking_at) == 0 && _moveBlockObj != NULL - && (_moveBlockObj->pid >> 24) == OBJ_TYPE_CRITTER) { + && PID_TYPE(_moveBlockObj->pid) == OBJ_TYPE_CRITTER) { if (shouldUnhide) { a2->flags &= ~OBJECT_HIDDEN; } @@ -2240,15 +2240,15 @@ static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a if (actionPoints >= critterGetStat(a1, STAT_MAXIMUM_ACTION_POINTS) / 2 && artCritterFidShouldRun(a1->fid)) { if ((a2->flags & OBJECT_MULTIHEX) != 0) { - reg_anim_obj_run_to_obj(a1, a2, actionPoints, 0); + animationRegisterRunToObject(a1, a2, actionPoints, 0); } else { - reg_anim_obj_run_to_tile(a1, tile, a1->elevation, actionPoints, 0); + animationRegisterRunToTile(a1, tile, a1->elevation, actionPoints, 0); } } else { if ((a2->flags & OBJECT_MULTIHEX) != 0) { - reg_anim_obj_move_to_obj(a1, a2, actionPoints, 0); + animationRegisterMoveToObject(a1, a2, actionPoints, 0); } else { - reg_anim_obj_move_to_tile(a1, tile, a1->elevation, actionPoints, 0); + animationRegisterMoveToTile(a1, tile, a1->elevation, actionPoints, 0); } } @@ -2490,8 +2490,8 @@ static int _ai_attack(Object* a1, Object* a2, int a3) return -1; } - reg_anim_begin(2); - reg_anim_set_rotation_to_tile(a1, a2->tile); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterRotateToTile(a1, a2->tile); reg_anim_end(); _combat_turn_run(); @@ -2527,7 +2527,7 @@ static int _ai_try_attack(Object* a1, Object* a2) if (weapon == NULL) { if (critterGetBodyType(a2) != BODY_TYPE_BIPED || ((a2->fid & 0xF000) >> 12 != 0) - || !artExists(buildFid(1, a1->fid & 0xFFF, ANIM_THROW_PUNCH, 0, a1->rotation + 1)) + || !artExists(buildFid(OBJ_TYPE_CRITTER, a1->fid & 0xFFF, ANIM_THROW_PUNCH, 0, a1->rotation + 1)) || _combat_safety_invalidate_weapon(a1, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, a2, &v31)) { _ai_switch_weapons(a1, &hitMode, &weapon, a2); } @@ -2813,8 +2813,8 @@ int _cai_perform_distance_prefs(Object* a1, Object* a2) int tile = a1->tile; if (_cai_retargetTileFromFriendlyFire(a1, a2, &tile) == 0 && tile != a1->tile) { - reg_anim_begin(2); - reg_anim_obj_move_to_tile(a1, tile, a1->elevation, a1->data.critter.combat.ap, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterMoveToTile(a1, tile, a1->elevation, a1->data.critter.combat.ap, 0); if (reg_anim_end() != 0) { return -1; } @@ -3017,7 +3017,7 @@ bool _combatai_want_to_stop(Object* a1) // 0x42B504 int critterSetTeam(Object* obj, int team) { - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { return 0; } @@ -3065,7 +3065,7 @@ int critterSetTeam(Object* obj, int team) // 0x42B5D4 int critterSetAiPacket(Object* object, int aiPacket) { - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return -1; } @@ -3087,7 +3087,7 @@ int critterSetAiPacket(Object* object, int aiPacket) // 0x42B634 int _combatai_msg(Object* a1, Attack* attack, int type, int delay) { - if ((a1->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(a1->pid) != OBJ_TYPE_CRITTER) { return -1; } @@ -3162,7 +3162,7 @@ int _combatai_msg(Object* a1, Attack* attack, int type, int delay) strncpy(string, messageListItem.text, 259); // TODO: Get rid of casts. - return reg_anim_11_0(a1, (Object*)type, (AnimationProc*)_ai_print_msg, delay); + return animationRegisterCallback(a1, (void*)type, (AnimationCallback*)_ai_print_msg, delay); } // 0x42B80C @@ -3245,7 +3245,7 @@ static int _combatai_rating(Object* obj) return 0; } - if ((obj->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) { + if (FID_TYPE(obj->fid) != OBJ_TYPE_CRITTER) { return 0; } diff --git a/src/combat_defs.h b/src/combat_defs.h index b29816b..ec56184 100644 --- a/src/combat_defs.h +++ b/src/combat_defs.h @@ -84,12 +84,12 @@ typedef enum HitLocation { HIT_LOCATION_SPECIFIC_COUNT = HIT_LOCATION_COUNT - 1, } HitLocation; -typedef struct STRUCT_510948 { - Object* field_0; - Object* field_4; - Object* field_8; - int field_C; -} STRUCT_510948; +typedef struct CombatAIInfo { + Object* friendlyDead; + Object* lastTarget; + Object* lastItem; + int lastMove; +} CombatAIInfo; typedef struct STRUCT_664980 { Object* attacker; diff --git a/src/config.cc b/src/config.cc index 99aea57..96b23a7 100644 --- a/src/config.cc +++ b/src/config.cc @@ -81,25 +81,20 @@ bool configParseCommandLineArguments(Config* config, int argc, char** argv) } for (int arg = 0; arg < argc; arg++) { - char* pch = argv[arg]; + char* pch; + char* string = argv[arg]; // Find opening bracket. - while (*pch != '\0' && *pch != '[') { - pch++; - } - - if (*pch == '\0') { + pch = strchr(string, '['); + if (pch == NULL) { continue; } char* sectionKey = pch + 1; // Find closing bracket. - while (*pch != '\0' && *pch != ']') { - pch++; - } - - if (*pch == '\0') { + pch = strchr(sectionKey, ']'); + if (pch == NULL) { continue; } @@ -189,7 +184,7 @@ bool configSetString(Config* config, const char* sectionKey, const char* key, co } // 0x42C05C -bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */ ) +bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */) { if (valuePtr == NULL) { return false; @@ -233,36 +228,30 @@ bool configGetIntList(Config* config, const char* sectionKey, const char* key, i } char temp[CONFIG_FILE_MAX_LINE_LENGTH]; - strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1); + string = strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1); - char* beginning = temp; - char* pch = beginning; - while (*pch != '\0') { - if (*pch == ',') { - *pch = '\0'; - - *arr++ = atoi(beginning); - - *pch = ','; - - pch++; - beginning = pch; - - count--; - - if (count < 0) { - break; - } + while (1) { + char* pch = strchr(string, ','); + if (pch == NULL) { + break; } - pch++; + count--; + if (count == 0) { + break; + } + + *pch = '\0'; + *arr++ = atoi(string); + string = pch + 1; } if (count <= 1) { - *arr = atoi(beginning); + *arr = atoi(string); + return true; } - return true; + return false; } // 0x42C160 @@ -383,30 +372,19 @@ static bool configParseLine(Config* config, char* string) char* pch; // Find comment marker and truncate the string. - pch = string; - while (*pch != '\0' && *pch != ';') { - pch++; - } - - if (*pch != '\0') { + pch = strchr(string, ';'); + if (pch != NULL) { *pch = '\0'; } // Find opening bracket. - pch = string; - while (*pch != '\0' && *pch != '[') { - pch++; - } - - if (*pch == '[') { + pch = strchr(string, '['); + if (pch != NULL) { char* sectionKey = pch + 1; // Find closing bracket. - while (*pch != '\0' && *pch != ']') { - pch++; - } - - if (*pch == ']') { + pch = strchr(sectionKey, ']'); + if (pch != NULL) { *pch = '\0'; strcpy(gConfigLastSectionKey, sectionKey); return configTrimString(gConfigLastSectionKey); @@ -435,12 +413,8 @@ static bool configParseKeyValue(char* string, char* key, char* value) } // Find equals character. - char* pch = string; - while (*pch != '\0' && *pch != '=') { - pch++; - } - - if (*pch == '\0') { + char* pch = strchr(string, '='); + if (pch == NULL) { return false; } diff --git a/src/core.cc b/src/core.cc index 802797b..274c141 100644 --- a/src/core.cc +++ b/src/core.cc @@ -1,8 +1,8 @@ #include "core.h" #include "audio_engine.h" -#include "config.h" #include "color.h" +#include "config.h" #include "dinput.h" #include "draw.h" #include "interface.h" @@ -13,9 +13,9 @@ #include "window_manager.h" #include "window_manager_private.h" +#include #include #include -#include // NOT USED. void (*_idle_func)() = NULL; @@ -116,39 +116,48 @@ int gModifierKeysState = 0; int (*_kb_scan_to_ascii)() = keyboardDequeueLogicalKeyCode; // 0x51E2F0 -STRUCT_51E2F0* _vcr_buffer = NULL; +VcrEntry* _vcr_buffer = NULL; // number of entries in _vcr_buffer // 0x51E2F4 int _vcr_buffer_index = 0; // 0x51E2F8 -int _vcr_state = 2; +unsigned int gVcrState = VCR_STATE_TURNED_OFF; // 0x51E2FC -int _vcr_time = 0; +unsigned int _vcr_time = 0; // 0x51E300 -int _vcr_counter = 0; +unsigned int _vcr_counter = 0; // 0x51E304 -int _vcr_terminate_flags = 0; +unsigned int gVcrTerminateFlags = 0; // 0x51E308 -int _vcr_terminated_condition = 0; +int gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_NONE; // 0x51E30C -int _vcr_start_time = 0; +unsigned int _vcr_start_time = 0; // 0x51E310 int _vcr_registered_atexit = 0; // 0x51E314 -File* _vcr_file = NULL; +File* gVcrFile = NULL; // 0x51E318 int _vcr_buffer_end = 0; +// 0x51E31C +VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback = NULL; + +// 0x51E320 +unsigned int gVcrRequestedTerminationFlags = 0; + +// 0x51E324 +int gVcrOldKeyboardLayout = 0; + // A map of SDL_SCANCODE_* constants normalized for QWERTY keyboard. // // 0x6ABC70 @@ -355,6 +364,9 @@ int gKeyboardLayout; // 0x6AD93C unsigned char gPressedPhysicalKeysCount; +// 0x6AD940 +VcrEntry stru_6AD940; + SDL_Window* gSdlWindow = NULL; SDL_Surface* gSdlSurface = NULL; SDL_Renderer* gSdlRenderer = NULL; @@ -446,7 +458,7 @@ void _process_bk() tickersExecute(); - if (_vcr_update() != 3) { + if (vcrUpdate() != 3) { _mouse_info(); } @@ -629,31 +641,37 @@ void pauseGame() // 0x4C8E38 int pauseHandlerDefaultImpl() { - int len; - int v1; - int v2; - int win; - unsigned char* buf; - int v6; - int v7; + int windowWidth = fontGetStringWidth("Paused") + 32; + int windowHeight = 3 * fontGetLineHeight() + 16; - len = fontGetStringWidth("Paused") + 32; - v1 = fontGetLineHeight(); - v2 = 3 * v1 + 16; - - win = windowCreate((_scr_size.right - _scr_size.left + 1 - len) / 2, (_scr_size.bottom - _scr_size.top + 1 - v2) / 2, len, v2, 256, 20); + int win = windowCreate((rectGetWidth(&_scr_size) - windowWidth) / 2, + (rectGetHeight(&_scr_size) - windowHeight) / 2, + windowWidth, + windowHeight, + 256, + WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); if (win == -1) { return -1; } windowDrawBorder(win); - buf = windowGetBuffer(win); - fontDrawText(buf + 8 * len + 16, "Paused", len, len, _colorTable[31744]); - v6 = v2 - 8 - v1; - v7 = fontGetStringWidth("Done"); - // TODO: Incomplete. - // _win_register_text_button(win, (len - v7 - 16) / 2, v6 - 6, -1, -1, -1, 27, "Done", 0); + unsigned char* windowBuffer = windowGetBuffer(win); + fontDrawText(windowBuffer + 8 * windowWidth + 16, + "Paused", + windowWidth, + windowWidth, + _colorTable[31744]); + + _win_register_text_button(win, + (windowWidth - fontGetStringWidth("Done") - 16) / 2, + windowHeight - 8 - fontGetLineHeight() - 6, + -1, + -1, + -1, + KEY_ESCAPE, + "Done", + 0); windowRefresh(win); @@ -720,7 +738,7 @@ int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, uns for (index = 0; index < 100000; index++) { sprintf(fileName, "scr%.5d.bmp", index); - + stream = compat_fopen(fileName, "rb"); if (stream == NULL) { break; @@ -784,7 +802,7 @@ int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, uns // biCompression intValue = 0; fwrite(&intValue, sizeof(intValue), 1, stream); - + // biSizeImage intValue = 0; fwrite(&intValue, sizeof(intValue), 1, stream); @@ -1324,10 +1342,10 @@ void _GNW95_process_key(KeyboardData* data) { data->key = gNormalizedQwertyKeys[data->key]; - if (_vcr_state == 1) { - if (_vcr_terminate_flags & 1) { - _vcr_terminated_condition = 2; - _vcr_stop(); + if (gVcrState == VCR_STATE_PLAYING) { + if ((gVcrTerminateFlags & VCR_TERMINATE_ON_KEY_PRESS) != 0) { + gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED; + vcrStop(); } } else { STRUCT_6ABF50* ptr = &(_GNW95_key_time_stamps[data->key]); @@ -1643,10 +1661,11 @@ void _mouse_info() x = (int)(x * gMouseSensitivity); y = (int)(y * gMouseSensitivity); - if (_vcr_state == 1) { - if (((_vcr_terminate_flags & 4) && buttons) || ((_vcr_terminate_flags & 2) && (x || y))) { - _vcr_terminated_condition = 2; - _vcr_stop(); + if (gVcrState == VCR_STATE_PLAYING) { + if (((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_PRESS) != 0 && buttons != 0) + || ((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_MOVE) != 0 && (x != 0 || y != 0))) { + gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED; + vcrStop(); return; } x = 0; @@ -1665,18 +1684,18 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons) } if (delta_x || delta_y || buttons != gMouseButtonsState) { - if (_vcr_state == 0) { - if (_vcr_buffer_index == 4095) { - _vcr_dump_buffer(); + if (gVcrState == 0) { + if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) { + vcrDump(); } - STRUCT_51E2F0* ptr = &(_vcr_buffer[_vcr_buffer_index]); - ptr->type = 3; - ptr->field_4 = _vcr_time; - ptr->field_8 = _vcr_counter; - ptr->dx = delta_x; - ptr->dy = delta_y; - ptr->buttons = buttons; + VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]); + vcrEntry->type = VCR_ENTRY_TYPE_MOUSE_EVENT; + vcrEntry->time = _vcr_time; + vcrEntry->counter = _vcr_counter; + vcrEntry->mouseEvent.dx = delta_x; + vcrEntry->mouseEvent.dy = delta_y; + vcrEntry->mouseEvent.buttons = buttons; _vcr_buffer_index++; } @@ -1996,10 +2015,10 @@ int _GNW95_init_mode_ex(int width, int height, int bpp) _zero_mem = _GNW95_zero_vid_mem; _mouse_blit = _GNW95_ShowRect; } else { - _zero_mem = NULL; - _mouse_blit = _GNW95_MouseShowRect16; - _mouse_blit_trans = _GNW95_MouseShowTransRect16; - _scr_blit = _GNW95_ShowRect16; + _zero_mem = NULL; + _mouse_blit = _GNW95_MouseShowRect16; + _mouse_blit_trans = _GNW95_MouseShowTransRect16; + _scr_blit = _GNW95_ShowRect16; } return 0; @@ -2036,7 +2055,7 @@ int _GNW95_init_window(int width, int height, bool fullscreen) if (gSdlRenderer == NULL) { goto err; } - + if (SDL_RenderSetLogicalSize(gSdlRenderer, width, height) != 0) { goto err; } @@ -2214,7 +2233,7 @@ void directDrawSetPaletteInRange(unsigned char* palette, int start, int count) void directDrawSetPalette(unsigned char* palette) { if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) { - SDL_Color colors[256]; + SDL_Color colors[256]; for (int index = 0; index < 256; index++) { colors[index].r = palette[index * 3] << 2; @@ -2251,7 +2270,6 @@ void directDrawSetPalette(unsigned char* palette) windowRefreshAll(&_scr_size); } - if (_update_palette_func != NULL) { _update_palette_func(); } @@ -2555,13 +2573,14 @@ int keyboardGetLayout() // TODO: Key type is likely short. void _kb_simulate_key(KeyboardData* data) { - if (_vcr_state == 0) { - if (_vcr_buffer_index != 4095) { - STRUCT_51E2F0* ptr = &(_vcr_buffer[_vcr_buffer_index]); - ptr->type = 2; - ptr->type_2_field_C = data->key & 0xFFFF; - ptr->field_4 = _vcr_time; - ptr->field_8 = _vcr_counter; + if (gVcrState == 0) { + if (_vcr_buffer_index != VCR_BUFFER_CAPACITY - 1) { + VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]); + vcrEntry->type = VCR_ENTRY_TYPE_KEYBOARD_EVENT; + vcrEntry->keyboardEvent.key = data->key & 0xFFFF; + vcrEntry->time = _vcr_time; + vcrEntry->counter = _vcr_counter; + _vcr_buffer_index++; } } @@ -4359,9 +4378,9 @@ int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr) } // 0x4D2680 -bool _vcr_record(const char* fileName) +bool vcrRecord(const char* fileName) { - if (_vcr_state != 2) { + if (gVcrState != VCR_STATE_TURNED_OFF) { return false; } @@ -4369,77 +4388,260 @@ bool _vcr_record(const char* fileName) return false; } - if (_vcr_buffer != NULL) { + // NOTE: Uninline. + if (!vcrInitBuffer()) { return false; } - _vcr_buffer = (STRUCT_51E2F0*)internal_malloc(sizeof(*_vcr_buffer) * 4096); - if (_vcr_buffer == NULL) { - return false; - } - - _vcr_clear_buffer(); - - _vcr_file = fileOpen(fileName, "wb"); - if (_vcr_file == NULL) { - if (_vcr_buffer != NULL) { - _vcr_clear_buffer(); - internal_free(_vcr_buffer); - _vcr_buffer = NULL; - } + gVcrFile = fileOpen(fileName, "wb"); + if (gVcrFile == NULL) { + // NOTE: Uninline. + vcrFreeBuffer(); return false; } if (_vcr_registered_atexit == 0) { - _vcr_registered_atexit = atexit(_vcr_stop); + _vcr_registered_atexit = atexit(vcrStop); } - STRUCT_51E2F0* entry = &(_vcr_buffer[_vcr_buffer_index]); - entry->type = 1; - entry->field_4 = 0; - entry->field_8 = 0; - entry->type_1_field_14 = keyboardGetLayout(); + VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]); + vcrEntry->type = VCR_ENTRY_TYPE_INITIAL_STATE; + vcrEntry->time = 0; + vcrEntry->counter = 0; + vcrEntry->initial.keyboardLayout = keyboardGetLayout(); while (mouseGetEvent() != 0) { _mouse_info(); } - mouseGetPosition(&(entry->type_1_field_C), &(entry->type_1_field_10)); + mouseGetPosition(&(vcrEntry->initial.mouseX), &(vcrEntry->initial.mouseY)); _vcr_counter = 1; _vcr_buffer_index++; _vcr_start_time = _get_time(); keyboardReset(); - _vcr_state = 0; - + gVcrState = VCR_STATE_RECORDING; + + return true; +} + +// 0x4D27EC +bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback) +{ + if (gVcrState != VCR_STATE_TURNED_OFF) { + return false; + } + + if (fileName == NULL) { + return false; + } + + // NOTE: Uninline. + if (!vcrInitBuffer()) { + return false; + } + + gVcrFile = fileOpen(fileName, "rb"); + if (gVcrFile == NULL) { + // NOTE: Uninline. + vcrFreeBuffer(); + return false; + } + + if (!vcrLoad()) { + fileClose(gVcrFile); + // NOTE: Uninline. + vcrFreeBuffer(); + return false; + } + + while (mouseGetEvent() != 0) { + _mouse_info(); + } + + keyboardReset(); + + gVcrRequestedTerminationFlags = terminationFlags; + gVcrPlaybackCompletionCallback = callback; + gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_COMPLETED; + gVcrTerminateFlags = 0; + _vcr_counter = 0; + _vcr_time = 0; + _vcr_start_time = _get_time(); + gVcrState = VCR_STATE_PLAYING; + stru_6AD940.time = 0; + stru_6AD940.counter = 0; + return true; } // 0x4D28F4 -void _vcr_stop() +void vcrStop() { - if (_vcr_state == 0 || _vcr_state == 1) { - _vcr_state |= 0x80000000; + if (gVcrState == VCR_STATE_RECORDING || gVcrState == VCR_STATE_PLAYING) { + gVcrState |= VCR_STATE_STOP_REQUESTED; } keyboardReset(); } // 0x4D2918 -int _vcr_status() +int vcrGetState() { - return _vcr_state; + return gVcrState; } // 0x4D2930 -int _vcr_update() +int vcrUpdate() { - // TODO: Incomplete. + if ((gVcrState & VCR_STATE_STOP_REQUESTED) != 0) { + gVcrState &= ~VCR_STATE_STOP_REQUESTED; + + switch (gVcrState) { + case VCR_STATE_RECORDING: + vcrDump(); + + fileClose(gVcrFile); + gVcrFile = NULL; + + // NOTE: Uninline. + vcrFreeBuffer(); + + break; + case VCR_STATE_PLAYING: + fileClose(gVcrFile); + gVcrFile = NULL; + + // NOTE: Uninline. + vcrFreeBuffer(); + + keyboardSetLayout(gVcrOldKeyboardLayout); + + if (gVcrPlaybackCompletionCallback != NULL) { + gVcrPlaybackCompletionCallback(gVcrPlaybackCompletionReason); + } + break; + } + + gVcrState = VCR_STATE_TURNED_OFF; + } + + switch (gVcrState) { + case VCR_STATE_RECORDING: + _vcr_counter++; + _vcr_time = getTicksSince(_vcr_start_time); + if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) { + vcrDump(); + } + break; + case VCR_STATE_PLAYING: + if (_vcr_buffer_index < _vcr_buffer_end || vcrLoad()) { + VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]); + if (stru_6AD940.counter < vcrEntry->counter) { + if (vcrEntry->time > stru_6AD940.time) { + unsigned int delay = stru_6AD940.time; + delay += (_vcr_counter - stru_6AD940.counter) + * (vcrEntry->time - stru_6AD940.time) + / (vcrEntry->counter - stru_6AD940.counter); + + while (getTicksSince(_vcr_start_time) < delay) { + } + } + } + + _vcr_counter++; + + int rc = 0; + while (_vcr_counter >= _vcr_buffer[_vcr_buffer_index].counter) { + _vcr_time = getTicksSince(_vcr_start_time); + if (_vcr_time > _vcr_buffer[_vcr_buffer_index].time + 5 + || _vcr_time < _vcr_buffer[_vcr_buffer_index].time - 5) { + _vcr_start_time += _vcr_time - _vcr_buffer[_vcr_buffer_index].time; + } + + switch (_vcr_buffer[_vcr_buffer_index].type) { + case VCR_ENTRY_TYPE_INITIAL_STATE: + gVcrState = VCR_STATE_TURNED_OFF; + gVcrOldKeyboardLayout = keyboardGetLayout(); + keyboardSetLayout(_vcr_buffer[_vcr_buffer_index].initial.keyboardLayout); + while (mouseGetEvent() != 0) { + _mouse_info(); + } + gVcrState = VCR_ENTRY_TYPE_INITIAL_STATE; + mouseHideCursor(); + _mouse_set_position(_vcr_buffer[_vcr_buffer_index].initial.mouseX, _vcr_buffer[_vcr_buffer_index].initial.mouseY); + mouseShowCursor(); + keyboardReset(); + gVcrTerminateFlags = gVcrRequestedTerminationFlags; + _vcr_start_time = _get_time(); + _vcr_counter = 0; + break; + case VCR_ENTRY_TYPE_KEYBOARD_EVENT: + if (1) { + KeyboardData keyboardData; + keyboardData.key = _vcr_buffer[_vcr_buffer_index].keyboardEvent.key; + _kb_simulate_key(&keyboardData); + } + break; + case VCR_ENTRY_TYPE_MOUSE_EVENT: + rc = 3; + _mouse_simulate_input(_vcr_buffer[_vcr_buffer_index].mouseEvent.dx, _vcr_buffer[_vcr_buffer_index].mouseEvent.dy, _vcr_buffer[_vcr_buffer_index].mouseEvent.buttons); + break; + } + + memcpy(&stru_6AD940, &(_vcr_buffer[_vcr_buffer_index]), sizeof(stru_6AD940)); + _vcr_buffer_index++; + } + + return rc; + } else { + // NOTE: Uninline. + vcrStop(); + } + break; + } + return 0; } +// NOTE: Inlined. +// +// 0x4D2C64 +bool vcrInitBuffer() +{ + if (_vcr_buffer == NULL) { + _vcr_buffer = (VcrEntry*)internal_malloc(sizeof(*_vcr_buffer) * VCR_BUFFER_CAPACITY); + if (_vcr_buffer == NULL) { + return false; + } + } + + // NOTE: Uninline. + vcrClear(); + + return true; +} + +// NOTE: Inlined. +// +// 0x4D2C98 +bool vcrFreeBuffer() +{ + if (_vcr_buffer == NULL) { + return false; + } + + // NOTE: Uninline. + vcrClear(); + + internal_free(_vcr_buffer); + _vcr_buffer = NULL; + + return true; +} + // 0x4D2CD0 -bool _vcr_clear_buffer() +bool vcrClear() { if (_vcr_buffer == NULL) { return false; @@ -4451,81 +4653,104 @@ bool _vcr_clear_buffer() } // 0x4D2CF0 -int _vcr_dump_buffer() +bool vcrDump() { - if (!_vcr_buffer || !_vcr_file) { - return 0; + if (_vcr_buffer == NULL) { + return false; + } + + if (gVcrFile == NULL) { + return false; } for (int index = 0; index < _vcr_buffer_index; index++) { - if (_vcr_save_record(&(_vcr_buffer[index]), _vcr_file)) { - _vcr_buffer_index = 0; - return 1; + if (!vcrWriteEntry(&(_vcr_buffer[index]), gVcrFile)) { + return false; } } - return 0; + // NOTE: Uninline. + if (!vcrClear()) { + return false; + } + + return true; +} + +// 0x4D2D74 +bool vcrLoad() +{ + if (gVcrFile == NULL) { + return false; + } + + // NOTE: Uninline. + if (!vcrClear()) { + return false; + } + + for (_vcr_buffer_end = 0; _vcr_buffer_end < VCR_BUFFER_CAPACITY; _vcr_buffer_end++) { + if (!vcrReadEntry(&(_vcr_buffer[_vcr_buffer_end]), gVcrFile)) { + break; + } + } + + if (_vcr_buffer_end == 0) { + return false; + } + + return true; } // 0x4D2E00 -bool _vcr_save_record(STRUCT_51E2F0* ptr, File* stream) +bool vcrWriteEntry(VcrEntry* vcrEntry, File* stream) { - if (_db_fwriteLong(stream, ptr->type) == -1) goto err; - if (_db_fwriteLong(stream, ptr->field_4) == -1) goto err; - if (_db_fwriteLong(stream, ptr->field_8) == -1) goto err; - - switch (ptr->type) { - case 1: - if (_db_fwriteLong(stream, ptr->type_1_field_C) == -1) goto err; - if (_db_fwriteLong(stream, ptr->type_1_field_10) == -1) goto err; - if (_db_fwriteLong(stream, ptr->type_1_field_14) == -1) goto err; + if (fileWriteUInt32(stream, vcrEntry->type) == -1) return false; + if (fileWriteUInt32(stream, vcrEntry->time) == -1) return false; + if (fileWriteUInt32(stream, vcrEntry->counter) == -1) return false; + switch (vcrEntry->type) { + case VCR_ENTRY_TYPE_INITIAL_STATE: + if (fileWriteInt32(stream, vcrEntry->initial.mouseX) == -1) return false; + if (fileWriteInt32(stream, vcrEntry->initial.mouseY) == -1) return false; + if (fileWriteInt32(stream, vcrEntry->initial.keyboardLayout) == -1) return false; return true; - case 2: - if (fileWriteInt16(stream, ptr->type_2_field_C) == -1) goto err; - + case VCR_ENTRY_TYPE_KEYBOARD_EVENT: + if (fileWriteInt16(stream, vcrEntry->keyboardEvent.key) == -1) return false; return true; - case 3: - if (_db_fwriteLong(stream, ptr->dx) == -1) goto err; - if (_db_fwriteLong(stream, ptr->dy) == -1) goto err; - if (_db_fwriteLong(stream, ptr->buttons) == -1) goto err; - + case VCR_ENTRY_TYPE_MOUSE_EVENT: + if (fileWriteInt32(stream, vcrEntry->mouseEvent.dx) == -1) return false; + if (fileWriteInt32(stream, vcrEntry->mouseEvent.dy) == -1) return false; + if (fileWriteInt32(stream, vcrEntry->mouseEvent.buttons) == -1) return false; return true; } -err: - return false; } // 0x4D2EE4 -bool _vcr_load_record(STRUCT_51E2F0* ptr, File* stream) +bool vcrReadEntry(VcrEntry* vcrEntry, File* stream) { - if (_db_freadInt(stream, &(ptr->type)) == -1) goto err; - if (_db_freadInt(stream, &(ptr->field_4)) == -1) goto err; - if (_db_freadInt(stream, &(ptr->field_8)) == -1) goto err; - - switch (ptr->type) { - case 1: - if (_db_freadInt(stream, &(ptr->type_1_field_C)) == -1) goto err; - if (_db_freadInt(stream, &(ptr->type_1_field_10)) == -1) goto err; - if (_db_freadInt(stream, &(ptr->type_1_field_14)) == -1) goto err; + if (fileReadUInt32(stream, &(vcrEntry->type)) == -1) return false; + if (fileReadUInt32(stream, &(vcrEntry->time)) == -1) return false; + if (fileReadUInt32(stream, &(vcrEntry->counter)) == -1) return false; + switch (vcrEntry->type) { + case VCR_ENTRY_TYPE_INITIAL_STATE: + if (fileReadInt32(stream, &(vcrEntry->initial.mouseX)) == -1) return false; + if (fileReadInt32(stream, &(vcrEntry->initial.mouseY)) == -1) return false; + if (fileReadInt32(stream, &(vcrEntry->initial.keyboardLayout)) == -1) return false; return true; - case 2: - if (fileReadInt16(stream, &(ptr->type_2_field_C)) == -1) goto err; - + case VCR_ENTRY_TYPE_KEYBOARD_EVENT: + if (fileReadInt16(stream, &(vcrEntry->keyboardEvent.key)) == -1) return false; return true; - case 3: - if (_db_freadInt(stream, &(ptr->dx)) == -1) goto err; - if (_db_freadInt(stream, &(ptr->dy)) == -1) goto err; - if (_db_freadInt(stream, &(ptr->buttons)) == -1) goto err; - + case VCR_ENTRY_TYPE_MOUSE_EVENT: + if (fileReadInt32(stream, &(vcrEntry->mouseEvent.dx)) == -1) return false; + if (fileReadInt32(stream, &(vcrEntry->mouseEvent.dy)) == -1) return false; + if (fileReadInt32(stream, &(vcrEntry->mouseEvent.buttons)) == -1) return false; return true; } -err: - return false; } diff --git a/src/core.h b/src/core.h index b046821..cf0a736 100644 --- a/src/core.h +++ b/src/core.h @@ -360,6 +360,44 @@ typedef enum KeyboardLayout { KEYBOARD_LAYOUT_SPANISH, } KeyboardLayout; +#define VCR_BUFFER_CAPACITY 4096 + +typedef enum VcrState { + VCR_STATE_RECORDING, + VCR_STATE_PLAYING, + VCR_STATE_TURNED_OFF, +} VcrState; + +#define VCR_STATE_STOP_REQUESTED 0x80000000 + +typedef enum VcrTerminationFlags { + // Specifies that VCR playback should stop if any key is pressed. + VCR_TERMINATE_ON_KEY_PRESS = 0x01, + + // Specifies that VCR playback should stop if mouse is mouved. + VCR_TERMINATE_ON_MOUSE_MOVE = 0x02, + + // Specifies that VCR playback should stop if any mouse button is pressed. + VCR_TERMINATE_ON_MOUSE_PRESS = 0x04, +} VcrTerminationFlags; + +typedef enum VcrPlaybackCompletionReason { + VCR_PLAYBACK_COMPLETION_REASON_NONE = 0, + + // Indicates that VCR playback completed normally. + VCR_PLAYBACK_COMPLETION_REASON_COMPLETED = 1, + + // Indicates that VCR playback terminated according to termination flags. + VCR_PLAYBACK_COMPLETION_REASON_TERMINATED = 2, +} VcrPlaybackCompletionReason; + +typedef enum VcrEntryType { + VCR_ENTRY_TYPE_NONE = 0, + VCR_ENTRY_TYPE_INITIAL_STATE = 1, + VCR_ENTRY_TYPE_KEYBOARD_EVENT = 2, + VCR_ENTRY_TYPE_MOUSE_EVENT = 3, +} VcrEntryType; + typedef struct STRUCT_6ABF50 { // Time when appropriate key was pressed down or -1 if it's up. int tick; @@ -383,26 +421,26 @@ typedef struct TickerListNode { struct TickerListNode* next; } TickerListNode; -typedef struct STRUCT_51E2F0 { - int type; - int field_4; - int field_8; +typedef struct VcrEntry { + unsigned int type; + unsigned int time; + unsigned int counter; union { struct { - int type_1_field_C; // mouse x - int type_1_field_10; // mouse y - int type_1_field_14; // keyboard layout - }; + int mouseX; + int mouseY; + int keyboardLayout; + } initial; struct { - short type_2_field_C; - }; + short key; + } keyboardEvent; struct { int dx; int dy; int buttons; - }; + } mouseEvent; }; -} STRUCT_51E2F0; +} VcrEntry; typedef struct LogicalKeyEntry { short field_0; @@ -420,6 +458,7 @@ typedef struct KeyboardEvent { typedef int(PauseHandler)(); typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette); +typedef void(VcrPlaybackCompletionCallback)(int reason); extern void (*_idle_func)(); extern void (*_focus_func)(int); @@ -448,17 +487,20 @@ extern int gKeyboardEventQueueReadIndex; extern short word_51E2E8; extern int gModifierKeysState; extern int (*_kb_scan_to_ascii)(); -extern STRUCT_51E2F0* _vcr_buffer; +extern VcrEntry* _vcr_buffer; extern int _vcr_buffer_index; -extern int _vcr_state; -extern int _vcr_time; -extern int _vcr_counter; -extern int _vcr_terminate_flags; -extern int _vcr_terminated_condition; -extern int _vcr_start_time; +extern unsigned int gVcrState; +extern unsigned int _vcr_time; +extern unsigned int _vcr_counter; +extern unsigned int gVcrTerminateFlags; +extern int gVcrPlaybackCompletionReason; +extern unsigned int _vcr_start_time; extern int _vcr_registered_atexit; -extern File* _vcr_file; +extern File* gVcrFile; extern int _vcr_buffer_end; +extern VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback; +extern unsigned int gVcrRequestedTerminationFlags; +extern int gVcrOldKeyboardLayout; extern int gNormalizedQwertyKeys[SDL_NUM_SCANCODES]; extern InputEvent gInputEventQueue[40]; @@ -520,6 +562,7 @@ extern unsigned int _kb_idle_start_time; extern KeyboardEvent gLastKeyboardEvent; extern int gKeyboardLayout; extern unsigned char gPressedPhysicalKeysCount; +extern VcrEntry stru_6AD940; extern SDL_Window* gSdlWindow; extern SDL_Surface* gSdlSurface; @@ -621,14 +664,18 @@ void keyboardBuildItalianConfiguration(); void keyboardBuildSpanishConfiguration(); void _kb_init_lock_status(); int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr); -bool _vcr_record(const char* fileName); -void _vcr_stop(); -int _vcr_status(); -int _vcr_update(); -bool _vcr_clear_buffer(); -int _vcr_dump_buffer(); -bool _vcr_save_record(STRUCT_51E2F0* ptr, File* stream); -bool _vcr_load_record(STRUCT_51E2F0* ptr, File* stream); +bool vcrRecord(const char* fileName); +bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback); +void vcrStop(); +int vcrGetState(); +int vcrUpdate(); +bool vcrInitBuffer(); +bool vcrFreeBuffer(); +bool vcrClear(); +bool vcrDump(); +bool vcrLoad(); +bool vcrWriteEntry(VcrEntry* ptr, File* stream); +bool vcrReadEntry(VcrEntry* ptr, File* stream); int screenGetWidth(); int screenGetHeight(); diff --git a/src/critter.cc b/src/critter.cc index 7a357b6..92910da 100644 --- a/src/critter.cc +++ b/src/critter.cc @@ -276,18 +276,18 @@ void dudeResetName() // 0x42D18C int critterGetHitPoints(Object* critter) { - return (critter->pid >> 24) == OBJ_TYPE_CRITTER ? critter->data.critter.hp : 0; + return PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER ? critter->data.critter.hp : 0; } // 0x42D1A4 -int critterAdjustHitPoints(Object* critter, int a2) +int critterAdjustHitPoints(Object* critter, int hp) { - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return 0; } int maximumHp = critterGetStat(critter, STAT_MAXIMUM_HIT_POINTS); - int newHp = critter->data.critter.hp + a2; + int newHp = critter->data.critter.hp + hp; critter->data.critter.hp = newHp; if (maximumHp >= newHp) { @@ -304,7 +304,7 @@ int critterAdjustHitPoints(Object* critter, int a2) // 0x42D1F8 int critterGetPoison(Object* critter) { - return (critter->pid >> 24) == OBJ_TYPE_CRITTER ? critter->data.critter.poison : 0; + return PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER ? critter->data.critter.poison : 0; } // Adjust critter's current poison by specified amount. @@ -396,7 +396,7 @@ int poisonEventProcess(Object* obj, void* data) // 0x42D38C int critterGetRadiation(Object* obj) { - return (obj->pid >> 24) == OBJ_TYPE_CRITTER ? obj->data.critter.radiation : 0; + return PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER ? obj->data.critter.radiation : 0; } // 0x42D3A4 @@ -416,7 +416,7 @@ int critterAdjustRadiation(Object* obj, int amount) } if (amount > 0) { - proto->critter.data.flags |= 0x02; + proto->critter.data.flags |= CRITTER_FLAG_0x2; } if (amount > 0) { @@ -483,7 +483,7 @@ int _critter_check_rads(Object* obj) Proto* proto; protoGetProto(obj->pid, &proto); - if ((proto->critter.data.flags & 0x02) == 0) { + if ((proto->critter.data.flags & CRITTER_FLAG_0x2) == 0) { return 0; } @@ -521,10 +521,10 @@ int _critter_check_rads(Object* obj) radiationEvent->radiationLevel = radiationLevel; radiationEvent->isHealing = 0; - queueAddEvent(36000 * randomBetween(4, 18), obj, radiationEvent, EVENT_TYPE_RADIATION); + queueAddEvent(GAME_TIME_TICKS_PER_HOUR * randomBetween(4, 18), obj, radiationEvent, EVENT_TYPE_RADIATION); } - proto->critter.data.flags &= ~(0x02); + proto->critter.data.flags &= ~(CRITTER_FLAG_0x2); return 0; } @@ -657,7 +657,7 @@ int radiationEventWrite(File* stream, void* data) // 0x42D82C int critterGetDamageType(Object* obj) { - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { return 0; } @@ -723,7 +723,7 @@ int critterGetKillType(Object* obj) return KILL_TYPE_MAN; } - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { return -1; } @@ -766,7 +766,7 @@ char* killTypeGetDescription(int killType) // 0x42D9F4 int _critter_heal_hours(Object* critter, int a2) { - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return -1; } @@ -788,7 +788,7 @@ static int _critterClearObjDrugs(Object* obj, void* data) // 0x42DA64 void critterKill(Object* critter, int anim, bool a3) { - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return; } @@ -800,20 +800,20 @@ void critterKill(Object* critter, int anim, bool a3) bool shouldChangeFid = false; int fid; if (_critter_is_prone(critter)) { - int current = (critter->fid & 0xFF0000) >> 16; + int current = FID_ANIM_TYPE(critter->fid); if (current == ANIM_FALL_BACK || current == ANIM_FALL_FRONT) { bool back = false; if (current == ANIM_FALL_BACK) { back = true; } else { - fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_FRONT_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_FRONT_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1); if (!artExists(fid)) { back = true; } } if (back) { - fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_BACK_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_BACK_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1); } shouldChangeFid = true; @@ -828,12 +828,12 @@ void critterKill(Object* critter, int anim, bool a3) anim = LAST_SF_DEATH_ANIM; } - fid = buildFid(1, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1); _obj_fix_violence_settings(&fid); if (!artExists(fid)) { debugPrint("\nError: Critter Kill: Can't match fid!"); - fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_BACK_BLOOD_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_BACK_BLOOD_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1); _obj_fix_violence_settings(&fid); } @@ -850,7 +850,7 @@ void critterKill(Object* critter, int anim, bool a3) rectUnion(&updatedRect, &tempRect, &updatedRect); } - if (!_critter_flag_check(critter->pid, 2048)) { + if (!_critter_flag_check(critter->pid, CRITTER_FLAG_0x800)) { critter->flags |= OBJECT_NO_BLOCK; _obj_toggle_flat(critter, &tempRect); } @@ -902,7 +902,7 @@ bool critterIsActive(Object* critter) return false; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -924,7 +924,7 @@ bool critterIsDead(Object* critter) return false; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -946,7 +946,7 @@ bool critterIsCrippled(Object* critter) return false; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -960,11 +960,11 @@ bool _critter_is_prone(Object* critter) return false; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return false; } - int anim = (critter->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(critter->fid); return (critter->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0 || anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM @@ -980,7 +980,7 @@ int critterGetBodyType(Object* critter) return 0; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return 0; } @@ -1236,7 +1236,7 @@ int knockoutEventProcess(Object* obj, void* data) // 0x42E460 int _critter_wake_clear(Object* obj, void* data) { - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { return 0; } @@ -1246,7 +1246,7 @@ int _critter_wake_clear(Object* obj, void* data) obj->data.critter.combat.results &= ~(DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN); - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_STAND, (obj->fid & 0xF000) >> 12, obj->rotation + 1); + int fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_STAND, (obj->fid & 0xF000) >> 12, obj->rotation + 1); objectSetFid(obj, fid, 0); return 0; @@ -1259,11 +1259,11 @@ int _critter_set_who_hit_me(Object* a1, Object* a2) return -1; } - if (a2 != NULL && ((a2->fid & 0xF000000) >> 24) != OBJ_TYPE_CRITTER) { + if (a2 != NULL && FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) { return -1; } - if ((a1->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(a1->pid) == OBJ_TYPE_CRITTER) { if (a2 == NULL || a1->data.critter.combat.team != a2->data.critter.combat.team || statRoll(a1, STAT_INTELLIGENCE, -1, NULL) < 2 && (!objectIsPartyMember(a1) || !objectIsPartyMember(a2))) { a1->data.critter.combat.whoHitMe = a2; if (a2 == gDude) { @@ -1319,7 +1319,7 @@ bool _critter_can_obj_dude_rest() // 0x42E62C int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int actionPoints) { - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return 0; } @@ -1358,7 +1358,7 @@ bool _critter_flag_check(int pid, int flag) return false; } - if ((pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(pid) != OBJ_TYPE_CRITTER) { return false; } diff --git a/src/critter.h b/src/critter.h index 0fc492f..78ef891 100644 --- a/src/critter.h +++ b/src/critter.h @@ -21,7 +21,7 @@ void critterProtoDataCopy(CritterProtoData* dest, CritterProtoData* src); int dudeSetName(const char* name); void dudeResetName(); int critterGetHitPoints(Object* critter); -int critterAdjustHitPoints(Object* critter, int amount); +int critterAdjustHitPoints(Object* critter, int hp); int critterGetPoison(Object* critter); int critterAdjustPoison(Object* obj, int amount); int poisonEventProcess(Object* obj, void* data); diff --git a/src/datafile.cc b/src/datafile.cc index c4ff41f..bccd470 100644 --- a/src/datafile.cc +++ b/src/datafile.cc @@ -1,10 +1,195 @@ #include "datafile.h" +#include + +#include "color.h" +#include "db.h" +#include "memory_manager.h" +#include "pcx.h" +#include "platform_compat.h" + +// 0x5184AC +DatafileLoader* gDatafileLoader = NULL; + +// 0x5184B0 +DatafileNameMangler* gDatafileNameMangler = datafileDefaultNameManglerImpl; + // 0x56D7E0 -unsigned char _pal[768]; +unsigned char gDatafilePalette[768]; + +// 0x42EE70 +char* datafileDefaultNameManglerImpl(char* path) +{ + return path; +} + +// NOTE: Unused. +// +// 0x42EE74 +void datafileSetNameMangler(DatafileNameMangler* mangler) +{ + gDatafileNameMangler = mangler; +} + +// NOTE: Unused. +// +// 0x42EE7C +void datafileSetLoader(DatafileLoader* loader) +{ + gDatafileLoader = loader; +} + +// 0x42EE84 +void sub_42EE84(unsigned char* data, unsigned char* palette, int width, int height) +{ + unsigned char indexedPalette[256]; + + indexedPalette[0] = 0; + for (int index = 1; index < 256; index++) { + // TODO: Check. + int r = palette[index * 3 + 2] >> 3; + int g = palette[index * 3 + 1] >> 3; + int b = palette[index * 3] >> 3; + int colorTableIndex = (r << 10) | (g << 5) | b; + indexedPalette[index] = _colorTable[colorTableIndex]; + } + + int size = width * height; + for (int index = 0; index < size; index++) { + data[index] = indexedPalette[data[index]]; + } +} + +// NOTE: Unused. +// +// 0x42EEF8 +void sub_42EEF8(unsigned char* data, unsigned char* palette, int width, int height) +{ + unsigned char indexedPalette[256]; + + indexedPalette[0] = 0; + for (int index = 1; index < 256; index++) { + // TODO: Check. + int r = palette[index * 3 + 2] >> 1; + int g = palette[index * 3 + 1] >> 1; + int b = palette[index * 3] >> 1; + int colorTableIndex = (r << 10) | (g << 5) | b; + indexedPalette[index] = _colorTable[colorTableIndex]; + } + + int size = width * height; + for (int index = 0; index < size; index++) { + data[index] = indexedPalette[data[index]]; + } +} + +// 0x42EF60 +unsigned char* datafileReadRaw(char* path, int* widthPtr, int* heightPtr) +{ + char* mangledPath = gDatafileNameMangler(path); + char* dot = strrchr(mangledPath, '.'); + if (dot != NULL) { + if (compat_stricmp(dot + 1, "pcx")) { + return pcxRead(mangledPath, widthPtr, heightPtr, gDatafilePalette); + } + } + + if (gDatafileLoader != NULL) { + return gDatafileLoader(mangledPath, gDatafilePalette, widthPtr, heightPtr); + } + + return NULL; +} + +// 0x42EFCC +unsigned char* datafileRead(char* path, int* widthPtr, int* heightPtr) +{ + unsigned char* v1 = datafileReadRaw(path, widthPtr, heightPtr); + if (v1 != NULL) { + sub_42EE84(v1, gDatafilePalette, *widthPtr, *heightPtr); + } + return v1; +} + +// NOTE: Unused +// +// 0x42EFF4 +unsigned char* sub_42EFF4(char* path) +{ + int width; + int height; + unsigned char* v3 = datafileReadRaw(path, &width, &height); + if (v3 != NULL) { + internal_free_safe(v3, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 148 + return gDatafilePalette; + } + + return NULL; +} + +// NOTE: Unused. +// +// 0x42F024 +void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr) +{ + int width = *widthPtr; + int height = *heightPtr; + unsigned char* temp = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 157 + + // NOTE: Original code does not initialize `x`. + int y = 0; + int x = 0; + unsigned char* src1 = data; + + for (y = 0; y < height; y++) { + if (*src1 == 0) { + break; + } + + unsigned char* src2 = src1; + for (x = 0; x < width; x++) { + if (*src2 == 0) { + break; + } + + *temp++ = *src2++; + } + + src1 += width; + } + + memcpy(data, temp, x * y); + internal_free_safe(temp, __FILE__, __LINE__); // // "..\\int\\DATAFILE.C", 171 +} // 0x42F0E4 -unsigned char* _datafileGetPalette() +unsigned char* datafileGetPalette() { - return _pal; + return gDatafilePalette; +} + +// NOTE: Unused. +// +// 0x42F0EC +unsigned char* datafileLoad(char* path, int* sizePtr) +{ + const char* mangledPath = gDatafileNameMangler(path); + File* stream = fileOpen(mangledPath, "rb"); + if (stream == NULL) { + return NULL; + } + + int size = fileGetSize(stream); + unsigned char* data = (unsigned char*)internal_malloc_safe(size, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 185 + if (data == NULL) { + // NOTE: This code is unreachable, internal_malloc_safe never fails. + // Otherwise it leaks stream. + *sizePtr = 0; + return NULL; + } + + fileRead(data, 1, size, stream); + fileClose(stream); + *sizePtr = size; + return data; } diff --git a/src/datafile.h b/src/datafile.h index ee7704b..bee2d39 100644 --- a/src/datafile.h +++ b/src/datafile.h @@ -1,8 +1,24 @@ #ifndef DATAFILE_H #define DATAFILE_H -extern unsigned char _pal[768]; +typedef unsigned char*(DatafileLoader)(char* path, unsigned char* palette, int* widthPtr, int* heightPtr); +typedef char*(DatafileNameMangler)(char* path); -unsigned char* _datafileGetPalette(); +extern DatafileLoader* gDatafileLoader; +extern DatafileNameMangler* gDatafileNameMangler; + +extern unsigned char gDatafilePalette[768]; + +char* datafileDefaultNameManglerImpl(char* path); +void datafileSetNameMangler(DatafileNameMangler* mangler); +void datafileSetLoader(DatafileLoader* loader); +void sub_42EE84(unsigned char* data, unsigned char* palette, int width, int height); +void sub_42EEF8(unsigned char* data, unsigned char* palette, int width, int height); +unsigned char* datafileReadRaw(char* path, int* widthPtr, int* heightPtr); +unsigned char* datafileRead(char* path, int* widthPtr, int* heightPtr); +unsigned char* sub_42EFF4(char* path); +void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr); +unsigned char* datafileGetPalette(); +unsigned char* datafileLoad(char* path, int* sizePtr); #endif /* DATAFILE_H */ diff --git a/src/db.cc b/src/db.cc index b419d07..b0399b0 100644 --- a/src/db.cc +++ b/src/db.cc @@ -638,7 +638,7 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a } } - bool v1 = *pattern == '*'; + bool isWildcard = *pattern == '*'; for (int index = 0; index < fileNamesLength; index += 1) { const char* name = xlist->fileNames[index]; @@ -647,16 +647,7 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a char extension[COMPAT_MAX_EXT]; compat_splitpath(name, NULL, dir, fileName, extension); - bool v2 = false; - if (v1) { - char* pch = dir; - while (*pch != '\0' && *pch != '\\') { - pch++; - } - v2 = *pch != '\0'; - } - - if (!v2) { + if (!isWildcard || *dir == '\0' || strchr(dir, '\\') == NULL) { // NOTE: Quick and dirty fix to buffer overflow. See RE to // understand the problem. char path[COMPAT_MAX_PATH]; diff --git a/src/dbox.cc b/src/dbox.cc index f862833..271611e 100644 --- a/src/dbox.cc +++ b/src/dbox.cc @@ -196,7 +196,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i CacheEntry* backgroundHandle; int backgroundWidth; int backgroundHeight; - int fid = buildFid(6, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gDialogBoxBackgroundFrmIds[dialogType], 0, 0, 0); unsigned char* background = artLockFrameDataReturningSize(fid, &backgroundHandle, &backgroundWidth, &backgroundHeight); if (background == NULL) { fontSetCurrent(savedFont); @@ -230,7 +230,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i unsigned char* upButton = NULL; if ((flags & DIALOG_BOX_0x20) == 0) { - int doneBoxFid = buildFid(6, 209, 0, 0, 0); + int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0); doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight); if (doneBox == NULL) { artUnlock(backgroundHandle); @@ -239,7 +239,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i return -1; } - int downButtonFid = buildFid(6, 9, 0, 0, 0); + int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight); if (downButton == NULL) { artUnlock(doneBoxHandle); @@ -249,7 +249,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i return -1; } - int upButtonFid = buildFid(6, 8, 0, 0, 0); + int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle); if (upButton == NULL) { artUnlock(downButtonHandle); @@ -331,7 +331,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release); } } else { - int doneBoxFid = buildFid(6, 209, 0, 0, 0); + int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0); unsigned char* doneBox = artLockFrameDataReturningSize(doneBoxFid, &doneBoxHandle, &doneBoxWidth, &doneBoxHeight); if (doneBox == NULL) { artUnlock(backgroundHandle); @@ -340,7 +340,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i return -1; } - int downButtonFid = buildFid(6, 9, 0, 0, 0); + int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); unsigned char* downButton = artLockFrameDataReturningSize(downButtonFid, &downButtonHandle, &downButtonWidth, &downButtonHeight); if (downButton == NULL) { artUnlock(doneBoxHandle); @@ -350,7 +350,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i return -1; } - int upButtonFid = buildFid(6, 8, 0, 0, 0); + int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); unsigned char* upButton = artLockFrameData(upButtonFid, 0, 0, &upButtonHandle); if (upButton == NULL) { artUnlock(downButtonHandle); @@ -517,7 +517,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i } // 0x41DE90 -int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLength, int x, int y, int flags) +int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags) { int oldFont = fontGetCurrent(); @@ -541,7 +541,7 @@ int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLen Size frmSizes[FILE_DIALOG_FRM_COUNT]; for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { - int fid = buildFid(6, gLoadFileDialogFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gLoadFileDialogFrmIds[index], 0, 0, 0); frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height)); if (frmBuffers[index] == NULL) { while (--index >= 0) { @@ -551,7 +551,6 @@ int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLen } } - int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width; int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height; @@ -922,7 +921,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen Size frmSizes[FILE_DIALOG_FRM_COUNT]; for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { - int fid = buildFid(6, gSaveFileDialogFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gSaveFileDialogFrmIds[index], 0, 0, 0); frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height)); if (frmBuffers[index] == NULL) { while (--index >= 0) { @@ -1090,7 +1089,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen char fileNameCopy[32]; strncpy(fileNameCopy, dest, 32); - + int fileNameCopyLength = strlen(fileNameCopy); fileNameCopy[fileNameCopyLength + 1] = '\0'; fileNameCopy[fileNameCopyLength] = ' '; diff --git a/src/dialog.cc b/src/dialog.cc index db4a0cd..dc5d666 100644 --- a/src/dialog.cc +++ b/src/dialog.cc @@ -76,7 +76,7 @@ int dword_56DB6C; int dword_56DB70; // 0x56DB74 -int _rand2plus; +char* off_56DB74; // 0x56DB7C int dword_56DB7C; @@ -91,7 +91,7 @@ int dword_56DB84; int dword_56DB88; // 0x56DB8C -int dword_56DB8C; +char* off_56DB8C; // 0x56DB90 int _replyPlaying; @@ -127,16 +127,16 @@ int dword_56DBB8; int dword_56DBBC; // 0x56DBC0 -void* off_56DBC0; +char* off_56DBC0; // 0x56DBC4 -void* off_56DBC4; +char* off_56DBC4; // 0x56DBC8 -void* off_56DBC8; +char* off_56DBC8; // 0x56DBCC -void* off_56DBCC; +char* off_56DBCC; // 0x56DBD0 char* gDialogReplyTitle; @@ -151,16 +151,16 @@ int dword_56DBD8; int dword_56DBDC; // 0x56DBE0 -void* off_56DBE0; +char* off_56DBE0; // 0x56DBE4 -void* off_56DBE4; +char* off_56DBE4; // 0x56DBE8 -void* off_56DBE8; +char* off_56DBE8; // 0x56DBEC -void* off_56DBEC; +char* off_56DBEC; // 0x42F434 STRUCT_56DAE0_FIELD_4* _getReply() @@ -191,7 +191,7 @@ void _replyAddOption(const char* a1, const char* a2, int a3) v18 = _getReply(); v17 = v18->field_14 - 1; - v18->field_C[v17].field_8 = 2; + v18->field_C[v17].kind = 2; if (a1 != NULL) { v14 = (char*)internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 805 @@ -204,9 +204,9 @@ void _replyAddOption(const char* a1, const char* a2, int a3) if (a2 != NULL) { v15 = (char*)internal_malloc_safe(strlen(a2) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 810 strcpy(v15, a2); - v18->field_C[v17].field_4 = v15; + v18->field_C[v17].string = v15; } else { - v18->field_C[v17].field_4 = NULL; + v18->field_C[v17].string = NULL; } v18->field_C[v17].field_18 = widgetGetFont(); @@ -215,7 +215,7 @@ void _replyAddOption(const char* a1, const char* a2, int a3) } // 0x42F624 -void _replyAddOptionProc(const char* a1, const char* a2, int a3) +void _replyAddOptionProc(const char* a1, int a2, int a3) { STRUCT_56DAE0_FIELD_4* v5; int v13; @@ -224,7 +224,7 @@ void _replyAddOptionProc(const char* a1, const char* a2, int a3) v5 = _getReply(); v13 = v5->field_14 - 1; - v5->field_C[v13].field_8 = 1; + v5->field_C[v13].kind = 1; if (a1 != NULL) { v11 = (char*)internal_malloc_safe(strlen(a1) + 1, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 830 @@ -234,7 +234,7 @@ void _replyAddOptionProc(const char* a1, const char* a2, int a3) v5->field_C[v13].field_0 = NULL; } - v5->field_C[v13].field_4 = (char*)a2; + v5->field_C[v13].proc = a2; v5->field_C[v13].field_18 = widgetGetFont(); v5->field_C[v13].field_1A = word_56DB60; @@ -248,9 +248,9 @@ void _optionFree(STRUCT_56DAE0_FIELD_4_FIELD_C* a1) internal_free_safe(a1->field_0, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 844 } - if (a1->field_8 == 2) { - if (a1->field_4 != NULL) { - internal_free_safe(a1->field_4, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 846 + if (a1->kind == 2) { + if (a1->string != NULL) { + internal_free_safe(a1->string, __FILE__, __LINE__); // "..\\int\\DIALOG.C", 846 } } } @@ -503,7 +503,7 @@ int _dialogOption(const char* a1, const char* a2) } // 0x430F38 -int _dialogOptionProc(const char* a1, const char* a2) +int _dialogOptionProc(const char* a1, int a2) { if (_dialog[_tods].field_C == -1) { return 1; @@ -514,6 +514,20 @@ int _dialogOptionProc(const char* a1, const char* a2) return 0; } +// 0x430FD4 +int sub_430FD4(const char* a1, const char* a2, int timeout) +{ + // TODO: Incomplete. + return -1; +} + +// 0x431088 +int sub_431088(int a1) +{ + // TODO: Incomplete. + return -1; +} + // 0x431184 int _dialogGetExitPoint() { @@ -533,24 +547,24 @@ int _dialogQuit() } // 0x4311B8 -int dialogSetOptionWindow(int a1, int a2, int a3, int a4, int a5) +int dialogSetOptionWindow(int a1, int a2, int a3, int a4, char* a5) { dword_56DB6C = a1; dword_56DB70 = a2; dword_56DB64 = a3; dword_56DB68 = a4; - _rand2plus = a5; + off_56DB74 = a5; return 0; } // 0x4311E0 -int dialogSetReplyWindow(int a1, int a2, int a3, int a4, int a5) +int dialogSetReplyWindow(int a1, int a2, int a3, int a4, char* a5) { dword_56DB84 = a1; dword_56DB88 = a2; dword_56DB7C = a3; dword_56DB80 = a4; - dword_56DB8C = a5; + off_56DB8C = a5; return 0; } @@ -565,7 +579,7 @@ int dialogSetBorder(int a1, int a2) } // 0x431218 -int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7) +int _dialogSetScrollUp(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7) { _upButton = a1; dword_56DBD8 = a2; @@ -596,7 +610,7 @@ int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, i } // 0x4312C0 -int _dialogSetScrollDown(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7) +int _dialogSetScrollDown(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7) { _downButton = a1; dword_56DBB8 = a2; @@ -666,6 +680,11 @@ int _dialogSetOptionFlags(int flags) return 1; } +// 0x431430 +void dialogInit() +{ +} + // 0x431434 void _dialogClose() { diff --git a/src/dialog.h b/src/dialog.h index 0d2d367..7545591 100644 --- a/src/dialog.h +++ b/src/dialog.h @@ -8,8 +8,11 @@ typedef void DialogFunc2(int win); typedef struct STRUCT_56DAE0_FIELD_4_FIELD_C { char* field_0; - char* field_4; - int field_8; + union { + int proc; + char* string; + }; + int kind; int field_C; int field_10; int field_14; @@ -60,12 +63,12 @@ extern int dword_56DB64; extern int dword_56DB68; extern int dword_56DB6C; extern int dword_56DB70; -extern int _rand2plus; +extern char* off_56DB74; extern int dword_56DB7C; extern int dword_56DB80; extern int dword_56DB84; extern int dword_56DB88; -extern int dword_56DB8C; +extern char* off_56DB8C; extern int _replyPlaying; extern int _replyWin; extern int gDialogReplyColorG; @@ -77,22 +80,22 @@ extern int gDialogOptionColorR; extern int _downButton; extern int dword_56DBB8; extern int dword_56DBBC; -extern void* off_56DBC0; -extern void* off_56DBC4; -extern void* off_56DBC8; -extern void* off_56DBCC; +extern char* off_56DBC0; +extern char* off_56DBC4; +extern char* off_56DBC8; +extern char* off_56DBCC; extern char* gDialogReplyTitle; extern int _upButton; extern int dword_56DBD8; extern int dword_56DBDC; -extern void* off_56DBE0; -extern void* off_56DBE4; -extern void* off_56DBE8; -extern void* off_56DBEC; +extern char* off_56DBE0; +extern char* off_56DBE4; +extern char* off_56DBE8; +extern char* off_56DBEC; STRUCT_56DAE0_FIELD_4* _getReply(); void _replyAddOption(const char* a1, const char* a2, int a3); -void _replyAddOptionProc(const char* a1, const char* a2, int a3); +void _replyAddOptionProc(const char* a1, int a2, int a3); void _optionFree(STRUCT_56DAE0_FIELD_4_FIELD_C* a1); void _replyFree(); int _endDialog(); @@ -107,18 +110,21 @@ int _dialogGotoReply(const char* a1); int dialogSetReplyTitle(const char* a1); int _dialogReply(const char* a1, const char* a2); int _dialogOption(const char* a1, const char* a2); -int _dialogOptionProc(const char* a1, const char* a2); +int _dialogOptionProc(const char* a1, int a2); +int sub_430FD4(const char* a1, const char* a2, int timeout); +int sub_431088(int a1); int _dialogGetExitPoint(); int _dialogQuit(); -int dialogSetOptionWindow(int a1, int a2, int a3, int a4, int a5); -int dialogSetReplyWindow(int a1, int a2, int a3, int a4, int a5); +int dialogSetOptionWindow(int a1, int a2, int a3, int a4, char* a5); +int dialogSetReplyWindow(int a1, int a2, int a3, int a4, char* a5); int dialogSetBorder(int a1, int a2); -int _dialogSetScrollUp(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7); -int _dialogSetScrollDown(int a1, int a2, void* a3, void* a4, void* a5, void* a6, int a7); +int _dialogSetScrollUp(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7); +int _dialogSetScrollDown(int a1, int a2, char* a3, char* a4, char* a5, char* a6, int a7); int dialogSetOptionSpacing(int value); int dialogSetOptionColor(float a1, float a2, float a3); int dialogSetReplyColor(float a1, float a2, float a3); int _dialogSetOptionFlags(int flags); +void dialogInit(); void _dialogClose(); int _dialogGetDialogDepth(); void _dialogRegisterWinDrawCallbacks(DialogFunc1* a1, DialogFunc2* a2); diff --git a/src/dictionary.cc b/src/dictionary.cc index b7ef061..4801289 100644 --- a/src/dictionary.cc +++ b/src/dictionary.cc @@ -44,24 +44,19 @@ static void dictionaryFreeDefaultImpl(void* ptr) } // 0x4D9BA8 -int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, void* a4) +int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io) { dictionary->entriesCapacity = initialCapacity; dictionary->valueSize = valueSize; dictionary->entriesLength = 0; - if (a4 != NULL) { - // NOTE: There is some structure pointed by [a4] with 5 fields. They are - // either memcopied or assigned one by one into field_10 - field_20 - // respectively. This parameter is always NULL, so I doubt it's possible - // to understand it's meaning. There are some hints in the unused - // functions though. - assert(false && "Not implemented"); + if (io != NULL) { + memcpy(&(dictionary->io), io, sizeof(*io)); } else { - dictionary->field_10 = 0; - dictionary->field_14 = 0; - dictionary->field_18 = 0; - dictionary->field_1C = 0; + dictionary->io.readProc = NULL; + dictionary->io.writeProc = NULL; + dictionary->io.field_8 = 0; + dictionary->io.field_C = 0; } int rc = 0; @@ -302,6 +297,248 @@ int dictionaryRemoveValue(Dictionary* dictionary, const char* key) return 0; } +// NOTE: Unused. +// +// 0x4D9F84 +int dictionaryCopy(Dictionary* dest, Dictionary* src) +{ + if (src->marker != DICTIONARY_MARKER) { + return -1; + } + + if (dictionaryInit(dest, src->entriesCapacity, src->valueSize, &(src->io)) != 0) { + // FIXME: Should return -1, as we were unable to initialize dictionary. + return 0; + } + + for (int index = 0; index < src->entriesLength; index++) { + DictionaryEntry* entry = &(src->entries[index]); + if (dictionaryAddValue(dest, entry->key, entry->value) == -1) { + return -1; + } + } + + return 0; +} + +// NOTE: Unused. +// +// 0x4DA090 +int dictionaryReadInt(FILE* stream, int* valuePtr) +{ + int ch; + int value; + + ch = fgetc(stream); + if (ch == -1) { + return -1; + } + + value = (ch & 0xFF); + + ch = fgetc(stream); + if (ch == -1) { + return -1; + } + + value = (value << 8) | (ch & 0xFF); + + ch = fgetc(stream); + if (ch == -1) { + return -1; + } + + value = (value << 8) | (ch & 0xFF); + + ch = fgetc(stream); + if (ch == -1) { + return -1; + } + + value = (value << 8) | (ch & 0xFF); + + *valuePtr = value; + + return 0; +} + +// NOTE: Unused. +// +// 0x4DA0F4 +int dictionaryReadHeader(FILE* stream, Dictionary* dictionary) +{ + int value; + + if (dictionaryReadInt(stream, &value) != 0) return -1; + dictionary->entriesLength = value; + + if (dictionaryReadInt(stream, &value) != 0) return -1; + dictionary->entriesCapacity = value; + + if (dictionaryReadInt(stream, &value) != 0) return -1; + dictionary->valueSize = value; + + // NOTE: Originally reads `values` pointer. + if (dictionaryReadInt(stream, &value) != 0) return -1; + + return 0; +} + +// NOTE: Unused. +// +// 0x4DA158 +int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3) +{ + if (dictionary->marker != DICTIONARY_MARKER) { + return -1; + } + + for (int index = 0; index < dictionary->entriesLength; index++) { + DictionaryEntry* entry = &(dictionary->entries[index]); + if (entry->key != NULL) { + gDictionaryFreeProc(entry->key); + } + + if (entry->value != NULL) { + gDictionaryFreeProc(entry->value); + } + } + + if (dictionary->entries != NULL) { + gDictionaryFreeProc(dictionary->entries); + } + + if (dictionaryReadHeader(stream, dictionary) != 0) { + return -1; + } + + dictionary->entries = NULL; + + if (dictionary->entriesCapacity <= 0) { + return 0; + } + + dictionary->entries = (DictionaryEntry*)gDictionaryMallocProc(sizeof(*dictionary->entries) * dictionary->entriesCapacity); + if (dictionary->entries == NULL) { + return -1; + } + + for (int index = 0; index < dictionary->entriesLength; index++) { + DictionaryEntry* entry = &(dictionary->entries[index]); + entry->key = NULL; + entry->value = NULL; + } + + if (dictionary->entriesLength <= 0) { + return 0; + } + + for (int index = 0; index < dictionary->entriesLength; index++) { + DictionaryEntry* entry = &(dictionary->entries[index]); + int keyLength = fgetc(stream); + if (keyLength == -1) { + return -1; + } + + entry->key = (char*)gDictionaryMallocProc(keyLength + 1); + if (entry->key == NULL) { + return -1; + } + + if (fgets(entry->key, keyLength, stream) == NULL) { + return -1; + } + + if (dictionary->valueSize != 0) { + entry->value = gDictionaryMallocProc(dictionary->valueSize); + if (entry->value == NULL) { + return -1; + } + + if (dictionary->io.readProc != NULL) { + if (dictionary->io.readProc(stream, entry->value, dictionary->valueSize, a3) != 0) { + return -1; + } + } else { + if (fread(entry->value, dictionary->valueSize, 1, stream) != 1) { + return -1; + } + } + } + } + + return 0; +} + +// NOTE: Unused. +// +// 0x4DA2EC +int dictionaryWriteInt(FILE* stream, int value) +{ + if (fputc((value >> 24) & 0xFF, stream) == -1) return -1; + if (fputc((value >> 16) & 0xFF, stream) == -1) return -1; + if (fputc((value >> 8) & 0xFF, stream) == -1) return -1; + if (fputc(value & 0xFF, stream) == -1) return -1; + + return 0; +} + +// NOTE: Unused. +// +// 0x4DA360 +int dictionaryWriteHeader(FILE* stream, Dictionary* dictionary) +{ + if (dictionaryWriteInt(stream, dictionary->entriesLength) != 0) return -1; + if (dictionaryWriteInt(stream, dictionary->entriesCapacity) != 0) return -1; + if (dictionaryWriteInt(stream, dictionary->valueSize) != 0) return -1; + // NOTE: Originally writes `entries` pointer. + if (dictionaryWriteInt(stream, 0) != 0) return -1; + + return 0; +} + +// NOTE: Unused. +// +// 0x4DA3A4 +int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3) +{ + if (dictionary->marker != DICTIONARY_MARKER) { + return -1; + } + + if (dictionaryWriteHeader(stream, dictionary) != 0) { + return -1; + } + + for (int index = 0; index < dictionary->entriesLength; index++) { + DictionaryEntry* entry = &(dictionary->entries[index]); + int keyLength = strlen(entry->key); + if (fputc(keyLength, stream) == -1) { + return -1; + } + + if (fputs(entry->key, stream) == -1) { + return -1; + } + + if (dictionary->io.writeProc != NULL) { + if (dictionary->valueSize != 0) { + if (dictionary->io.writeProc(stream, entry->value, dictionary->valueSize, a3) != 0) { + return -1; + } + } + } else { + if (dictionary->valueSize != 0) { + if (fwrite(entry->value, dictionary->valueSize, 1, stream) != 1) { + return -1; + } + } + } + } + + return 0; +} + // 0x4DA498 void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc) { diff --git a/src/dictionary.h b/src/dictionary.h index b3e35ad..5e093d4 100644 --- a/src/dictionary.h +++ b/src/dictionary.h @@ -3,6 +3,20 @@ #include "memory_defs.h" +#include + +typedef int(DictionaryReadProc)(FILE* stream, void* buffer, unsigned int size, int a4); +typedef int(DictionaryWriteProc)(FILE* stream, void* buffer, unsigned int size, int a4); + +// NOTE: Last unnamed fields are likely seek, tell, and filelength. +typedef struct DictionaryIO { + DictionaryReadProc* readProc; + DictionaryWriteProc* writeProc; + int field_8; + int field_C; + int field_10; +} DictionaryIO; + // A tuple containing individual key-value pair of a dictionary. typedef struct DictionaryEntry { char* key; @@ -27,22 +41,26 @@ typedef struct Dictionary { // The size of the dictionary values in bytes. size_t valueSize; - int field_10; - int field_14; - int field_18; - int field_1C; - int field_20; + // IO callbacks. + DictionaryIO io; // The array of key-value pairs. DictionaryEntry* entries; } Dictionary; -int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, void* a4); +int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io); int dictionarySetCapacity(Dictionary* dictionary, int newCapacity); int dictionaryFree(Dictionary* dictionary); int dictionaryGetIndexByKey(Dictionary* dictionary, const char* key); int dictionaryAddValue(Dictionary* dictionary, const char* key, const void* value); int dictionaryRemoveValue(Dictionary* dictionary, const char* key); +int dictionaryCopy(Dictionary* dest, Dictionary* src); +int dictionaryReadInt(FILE* stream, int* valuePtr); +int dictionaryReadHeader(FILE* stream, Dictionary* dictionary); +int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3); +int dictionaryWriteInt(FILE* stream, int value); +int dictionaryWriteHeader(FILE* stream, Dictionary* dictionary); +int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3); void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc); #endif /* DICTIONARY_H */ diff --git a/src/display_monitor.cc b/src/display_monitor.cc index c0aeee5..2077740 100644 --- a/src/display_monitor.cc +++ b/src/display_monitor.cc @@ -105,7 +105,7 @@ int displayMonitorInit() } CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 16, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 16, 0, 0, 0); Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle); if (backgroundFrm == NULL) { internal_free(gDisplayMonitorBackgroundFrmData); diff --git a/src/draw.h b/src/draw.h index 7adcac0..2679315 100644 --- a/src/draw.h +++ b/src/draw.h @@ -1,7 +1,7 @@ #ifndef DRAW_H #define DRAW_H -void bufferDrawLine(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int color); +void bufferDrawLine(unsigned char* buf, int pitch, int left, int top, int right, int bottom, int color); void bufferDrawRect(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7); void bufferDrawRectShadowed(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7, int a8); void blitBufferToBufferStretch(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* dest, int destWidth, int destHeight, int destPitch); diff --git a/src/elevator.cc b/src/elevator.cc index 89bf558..e7e49a4 100644 --- a/src/elevator.cc +++ b/src/elevator.cc @@ -503,7 +503,7 @@ static int elevatorWindowInit(int elevator) int index; for (index = 0; index < ELEVATOR_FRM_COUNT; index++) { - int fid = buildFid(6, gElevatorFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gElevatorFrmIds[index], 0, 0, 0); gElevatorFrmData[index] = artLockFrameDataReturningSize(fid, &(gElevatorFrmHandles[index]), &(gElevatorFrmSizes[index].width), &(gElevatorFrmSizes[index].height)); if (gElevatorFrmData[index] == NULL) { break; @@ -530,11 +530,11 @@ static int elevatorWindowInit(int elevator) const ElevatorBackground* elevatorBackground = &(gElevatorBackgrounds[elevator]); bool backgroundsLoaded = true; - int backgroundFid = buildFid(6, elevatorBackground->backgroundFrmId, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, elevatorBackground->backgroundFrmId, 0, 0, 0); gElevatorBackgroundFrmData = artLockFrameDataReturningSize(backgroundFid, &gElevatorBackgroundFrmHandle, &gElevatorBackgroundFrmWidth, &gElevatorBackgroundFrmHeight); if (gElevatorBackgroundFrmData != NULL) { if (elevatorBackground->panelFrmId != -1) { - int panelFid = buildFid(6, elevatorBackground->panelFrmId, 0, 0, 0); + int panelFid = buildFid(OBJ_TYPE_INTERFACE, elevatorBackground->panelFrmId, 0, 0, 0); gElevatorPanelFrmData = artLockFrameDataReturningSize(panelFid, &gElevatorPanelFrmHandle, &gElevatorPanelFrmWidth, &gElevatorPanelFrmHeight); if (gElevatorPanelFrmData == NULL) { gElevatorPanelFrmData = ELEVATOR_BACKGROUND_NULL; diff --git a/src/endgame.cc b/src/endgame.cc index e5a5df2..d49a2fe 100644 --- a/src/endgame.cc +++ b/src/endgame.cc @@ -217,7 +217,7 @@ void endgamePlaySlideshow() if (ending->art_num == 327) { endgameEndingRenderPanningScene(ending->direction, ending->voiceOverBaseName); } else { - int fid = buildFid(6, ending->art_num, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, ending->art_num, 0, 0, 0); endgameEndingRenderStaticScene(fid, ending->voiceOverBaseName); } } @@ -309,7 +309,7 @@ static int endgameEndingHandleContinuePlaying() // 0x43FBDC static void endgameEndingRenderPanningScene(int direction, const char* narratorFileName) { - int fid = buildFid(6, 327, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 327, 0, 0, 0); CacheEntry* backgroundHandle; Art* background = artLock(fid, &backgroundHandle); @@ -441,7 +441,7 @@ static void endgameEndingRenderStaticScene(int fid, const char* narratorFileName blitBufferToBuffer(backgroundData, ENDGAME_ENDING_WINDOW_WIDTH, ENDGAME_ENDING_WINDOW_HEIGHT, ENDGAME_ENDING_WINDOW_WIDTH, gEndgameEndingSlideshowWindowBuffer, ENDGAME_ENDING_WINDOW_WIDTH); windowRefresh(gEndgameEndingSlideshowWindow); - endgameEndingLoadPalette((fid & 0xF000000) >> 24, fid & 0xFFF); + endgameEndingLoadPalette(FID_TYPE(fid), fid & 0xFFF); endgameEndingVoiceOverInit(narratorFileName); @@ -746,23 +746,15 @@ static int endgameEndingSubtitlesLoad(const char* filePath) char* pch; // Find and clamp string at EOL. - pch = string; - while (*pch != '\0' && *pch != '\n') { - pch++; - } - - if (*pch != '\0') { + pch = strchr(string, '\n'); + if (pch != NULL) { *pch = '\0'; } // Find separator. The value before separator is ignored (as opposed to // movie subtitles, where the value before separator is a timing). - pch = string; - while (*pch != '\0' && *pch != ':') { - pch++; - } - - if (*pch != '\0') { + pch = strchr(string, ':'); + if (pch != NULL) { if (gEndgameEndingSubtitlesLength < ENDGAME_ENDING_MAX_SUBTITLES) { gEndgameEndingSubtitles[gEndgameEndingSubtitlesLength] = internal_strdup(pch + 1); gEndgameEndingSubtitlesLength++; diff --git a/src/export.cc b/src/export.cc index 28e0444..4a12c7a 100644 --- a/src/export.cc +++ b/src/export.cc @@ -176,12 +176,11 @@ int externalVariableSetValue(Program* program, const char* name, ProgramValue& p return 1; } - - if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 169 } - if ((programValue.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((programValue.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { if (program != NULL) { const char* stringValue = programGetString(program, programValue.opcode, programValue.integerValue); exportedVariable->value.opcode = VALUE_TYPE_DYNAMIC_STRING; @@ -204,7 +203,7 @@ int externalVariableGetValue(Program* program, const char* name, ProgramValue& v return 1; } - if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { value.opcode = exportedVariable->value.opcode; value.integerValue = programPushString(program, exportedVariable->stringValue); } else { @@ -225,7 +224,7 @@ int externalVariableCreate(Program* program, const char* identifier) return 1; } - if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 234 } } else { @@ -261,7 +260,7 @@ void _removeProgramReferences(Program* program) // 0x44152C void _initExport() { - _interpretRegisterProgramDeleteCallback(_removeProgramReferences); + intLibRegisterProgramDeleteCallback(_removeProgramReferences); } // 0x441538 @@ -328,7 +327,7 @@ void _exportClearAllVariables() for (int index = 0; index < 1013; index++) { ExternalVariable* exportedVariable = &(gExternalVariables[index]); if (exportedVariable->name[0] != '\0') { - if ((exportedVariable->value.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((exportedVariable->value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { if (exportedVariable->stringValue != NULL) { internal_free_safe(exportedVariable->stringValue, __FILE__, __LINE__); // "..\\int\\EXPORT.C", 387 } diff --git a/src/game.cc b/src/game.cc index e7c1c01..0bdb947 100644 --- a/src/game.cc +++ b/src/game.cc @@ -720,14 +720,14 @@ int gameHandleKey(int eventCode, bool isInCombatMode) case KEY_COMMA: case KEY_LESS: if (reg_anim_begin(0) == 0) { - reg_anim_rotate_counter_clockwise(gDude); + animationRegisterRotateCounterClockwise(gDude); reg_anim_end(); } break; case KEY_DOT: case KEY_GREATER: if (reg_anim_begin(0) == 0) { - reg_anim_rotate_clockwise(gDude); + animationRegisterRotateClockwise(gDude); reg_anim_end(); } break; @@ -930,68 +930,56 @@ static int gameLoadGlobalVars() } // 0x443CE8 -int globalVarsRead(const char* path, const char* section, int* out_vars_num, int** out_vars) +int globalVarsRead(const char* path, const char* section, int* variablesListLengthPtr, int** variablesListPtr) { - File* stream; - char str[258]; - char* ch; - _inven_reset_dude(); - stream = fileOpen(path, "rt"); + File* stream = fileOpen(path, "rt"); if (stream == NULL) { return -1; } - if (*out_vars_num != 0) { - internal_free(*out_vars); - *out_vars = NULL; - *out_vars_num = 0; + if (*variablesListLengthPtr != 0) { + internal_free(*variablesListPtr); + *variablesListPtr = NULL; + *variablesListLengthPtr = 0; } + char string[260]; if (section != NULL) { - while (fileReadString(str, sizeof(str), stream)) { - if (strncmp(str, section, 16) == 0) { + while (fileReadString(string, 258, stream)) { + if (strncmp(string, section, 16) == 0) { break; } } } - while (fileReadString(str, sizeof(str), stream)) { - if (str[0] == '\n') { + while (fileReadString(string, 258, stream)) { + if (string[0] == '\n') { continue; } - if (str[0] == '/' && str[1] == '/') { + if (string[0] == '/' && string[1] == '/') { continue; } - ch = str; - - while (*ch != '\0' && *ch != ';') { - ch++; + char* semicolon = strchr(string, ';'); + if (semicolon != NULL) { + *semicolon = '\0'; } - if (*ch != '\0') { - *ch = '\0'; - } + *variablesListLengthPtr = *variablesListLengthPtr + 1; + *variablesListPtr = (int*)internal_realloc(*variablesListPtr, sizeof(int) * *variablesListLengthPtr); - *out_vars_num = *out_vars_num + 1; - *out_vars = (int*)internal_realloc(*out_vars, sizeof(int) * *out_vars_num); - - if (*out_vars == NULL) { + if (*variablesListPtr == NULL) { exit(1); } - ch = str; - while (*ch != '\0' && *ch != '=') { - ch++; - } - - if (*ch != '\0') { - sscanf(ch + 1, "%d", *out_vars + *out_vars_num - 1); + char* equals = strchr(string, '='); + if (equals != NULL) { + sscanf(equals + 1, "%d", *variablesListPtr + *variablesListLengthPtr - 1); } else { - *out_vars[*out_vars_num - 1] = 0; + *variablesListPtr[*variablesListLengthPtr - 1] = 0; } } @@ -1098,7 +1086,7 @@ static void showHelp() if (win != -1) { unsigned char* windowBuffer = windowGetBuffer(win); if (windowBuffer != NULL) { - int backgroundFid = buildFid(6, 297, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 297, 0, 0, 0); CacheEntry* backgroundHandle; unsigned char* backgroundData = artLockFrameData(backgroundFid, 0, 0, &backgroundHandle); if (backgroundData != NULL) { diff --git a/src/game.h b/src/game.h index 23737ea..e4301d8 100644 --- a/src/game.h +++ b/src/game.h @@ -22,7 +22,7 @@ void gameUiEnable(); bool gameUiIsDisabled(); int gameGetGlobalVar(int var); int gameSetGlobalVar(int var, int value); -int globalVarsRead(const char* path, const char* section, int* out_vars_num, int** out_vars); +int globalVarsRead(const char* path, const char* section, int* variablesListLengthPtr, int** variablesListPtr); int _game_state(); int _game_state_request(int a1); void _game_state_update(); diff --git a/src/game_dialog.cc b/src/game_dialog.cc index 9f7a35f..8b59547 100644 --- a/src/game_dialog.cc +++ b/src/game_dialog.cc @@ -717,7 +717,7 @@ void gameDialogEnter(Object* a1, int a2) return; } - if ((a1->pid >> 24) != OBJ_TYPE_ITEM && (a1->sid >> 24) != SCRIPT_TYPE_SPATIAL) { + if (PID_TYPE(a1->pid) != OBJ_TYPE_ITEM && SID_TYPE(a1->sid) != SCRIPT_TYPE_SPATIAL) { MessageListItem messageListItem; int rc = _action_can_talk_to(gDude, a1); @@ -915,9 +915,9 @@ int _gdialogInitFromScript(int headFid, int reaction) gGameDialogSpeakerIsPartyMember = objectIsPartyMember(gGameDialogSpeaker); _oldFont = fontGetCurrent(); fontSetCurrent(101); - dialogSetReplyWindow(135, 225, 379, 58, 0); + dialogSetReplyWindow(135, 225, 379, 58, NULL); dialogSetReplyColor(0.3f, 0.3f, 0.3f); - dialogSetOptionWindow(127, 335, 393, 117, 0); + dialogSetOptionWindow(127, 335, 393, 117, NULL); dialogSetOptionColor(0.2f, 0.2f, 0.2f); dialogSetReplyTitle(NULL); _dialogRegisterWinDrawCallbacks(_demo_copy_title, _demo_copy_options); @@ -930,7 +930,7 @@ int _gdialogInitFromScript(int headFid, int reaction) gameMouseSetCursor(MOUSE_CURSOR_ARROW); textObjectsReset(); - if ((gGameDialogSpeaker->pid >> 24) != OBJ_TYPE_ITEM) { + if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_ITEM) { _tile_scroll_to(gGameDialogSpeaker->tile, 2); } @@ -970,7 +970,7 @@ int _gdialogExitFromScript() dialogReviewEntriesClear(); tickersRemove(gameDialogTicker); - if (gGameDialogSpeaker->pid >> 24 != OBJ_TYPE_ITEM) { + if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_ITEM) { if (gGameDialogOldDudeTile != gDude->tile) { gGameDialogOldCenterTile = gDude->tile; } @@ -1298,7 +1298,7 @@ int gameDialogReviewWindowInit(int* win) return -1; } - int fid = buildFid(6, 102, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 102, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &_reviewBackKey); if (backgroundFrmData == NULL) { windowDestroy(*win); @@ -1318,10 +1318,10 @@ int gameDialogReviewWindowInit(int* win) _reviewBackKey = INVALID_CACHE_ENTRY; unsigned char* buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT]; - + int index; for (index = 0; index < GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_COUNT; index++) { - int fid = buildFid(6, gGameDialogReviewWindowButtonFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gGameDialogReviewWindowButtonFrmIds[index], 0, 0, 0); buttonFrmData[index] = artLockFrameData(fid, 0, 0, &(gGameDialogReviewWindowButtonFrmHandles[index])); if (buttonFrmData[index] == NULL) { break; @@ -1360,11 +1360,11 @@ int gameDialogReviewWindowInit(int* win) gGameDialogReviewWindowButtonHeights[GAME_DIALOG_REVIEW_WINDOW_BUTTON_SCROLL_DOWN], -1, -1, - -1, + -1, KEY_ARROW_DOWN, buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_NORMAL], - buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_PRESSED], - NULL, + buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_ARROW_DOWN_PRESSED], + NULL, BUTTON_FLAG_TRANSPARENT); if (downBtn == -1) { gameDialogReviewWindowFree(win); @@ -1373,18 +1373,18 @@ int gameDialogReviewWindowInit(int* win) buttonSetCallbacks(downBtn, _gsound_med_butt_press, _gsound_med_butt_release); - int doneBtn = buttonCreate(*win, - 499, - 398, - gGameDialogReviewWindowButtonWidths[GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE], + int doneBtn = buttonCreate(*win, + 499, + 398, + gGameDialogReviewWindowButtonWidths[GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE], gGameDialogReviewWindowButtonHeights[GAME_DIALOG_REVIEW_WINDOW_BUTTON_DONE], - -1, -1, - -1, - KEY_ESCAPE, - buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_NORMAL], + -1, + -1, + KEY_ESCAPE, + buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_NORMAL], buttonFrmData[GAME_DIALOG_REVIEW_WINDOW_BUTTON_FRM_DONE_PRESSED], - NULL, + NULL, BUTTON_FLAG_TRANSPARENT); if (doneBtn == -1) { gameDialogReviewWindowFree(win); @@ -1399,7 +1399,7 @@ int gameDialogReviewWindowInit(int* win) tickersRemove(gameDialogTicker); - int backgroundFid = buildFid(6, 102, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 102, 0, 0, 0); gGameDialogReviewWindowBackgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &gGameDialogReviewWindowBackgroundFrmHandle); if (gGameDialogReviewWindowBackgroundFrmData == NULL) { gameDialogReviewWindowFree(win); @@ -1691,7 +1691,7 @@ int gameDialogSetReviewOptionText(const char* string) // 0x446288 int _gdProcessInit() { - int upBtn; + int upBtn; int downBtn; int optionsWindowX; int optionsWindowY; @@ -1735,14 +1735,14 @@ int _gdProcessInit() } // di_rdbt2.frm - dialog red button down - fid = buildFid(6, 96, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 96, 0, 0, 0); gGameDialogRedButtonUpFrmData = artLockFrameData(fid, 0, 0, &gGameDialogRedButtonUpFrmHandle); if (gGameDialogRedButtonUpFrmData == NULL) { goto err_3; } // di_rdbt1.frm - dialog red button up - fid = buildFid(6, 95, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 95, 0, 0, 0); gGameDialogRedButtonDownFrmData = artLockFrameData(fid, 0, 0, &gGameDialogRedButtonDownFrmHandle); if (gGameDialogRedButtonDownFrmData == NULL) { goto err_3; @@ -3010,7 +3010,7 @@ int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4, } } } - + if (*end == ' ') { *end = '\0'; } @@ -3127,7 +3127,7 @@ int _gdialog_barter_create_win() frmId = 111; } - int backgroundFid = buildFid(6, frmId, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0); CacheEntry* backgroundHandle; Art* backgroundFrm = artLock(backgroundFid, &backgroundHandle); if (backgroundFrm == NULL) { @@ -3236,7 +3236,7 @@ void _gdialog_barter_destroy_win() } CacheEntry* backgroundFrmHandle; - int fid = buildFid(6, frmId, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData != NULL) { unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow); @@ -3287,7 +3287,7 @@ void _gdialog_barter_cleanup_tables() int partyMemberControlWindowInit() { CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 390, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0); Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle); if (backgroundFrm == NULL) { return -1; @@ -3359,7 +3359,7 @@ int partyMemberControlWindowInit() GameDialogButtonData* buttonData = &(gGameDialogDispositionButtonsData[index]); int fid; - fid = buildFid(6, buttonData->upFrmId, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, buttonData->upFrmId, 0, 0, 0); Art* upButtonFrm = artLock(fid, &(buttonData->upFrmHandle)); if (upButtonFrm == NULL) { partyMemberControlWindowFree(); @@ -3370,7 +3370,7 @@ int partyMemberControlWindowInit() int height = artGetHeight(upButtonFrm, 0, 0); unsigned char* upButtonFrmData = artGetFrameData(upButtonFrm, 0, 0); - fid = buildFid(6, buttonData->downFrmId, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, buttonData->downFrmId, 0, 0, 0); Art* downButtonFrm = artLock(fid, &(buttonData->downFrmHandle)); if (downButtonFrm == NULL) { partyMemberControlWindowFree(); @@ -3379,7 +3379,7 @@ int partyMemberControlWindowInit() unsigned char* downButtonFrmData = artGetFrameData(downButtonFrm, 0, 0); - fid = buildFid(6, buttonData->disabledFrmId, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, buttonData->disabledFrmId, 0, 0, 0); Art* disabledButtonFrm = artLock(fid, &(buttonData->disabledFrmHandle)); if (disabledButtonFrm == NULL) { partyMemberControlWindowFree(); @@ -3394,14 +3394,14 @@ int partyMemberControlWindowInit() buttonData->x, buttonData->y, width, - height, + height, -1, - -1, - buttonData->keyCode, - -1, - upButtonFrmData, + -1, + buttonData->keyCode, + -1, + upButtonFrmData, downButtonFrmData, - NULL, + NULL, BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x04 | BUTTON_FLAG_0x01); if (_gdialog_buttons[v21] == -1) { partyMemberControlWindowFree(); @@ -3463,7 +3463,7 @@ void partyMemberControlWindowFree() // control.frm - party member control interface CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 390, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData != NULL) { _gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmData, windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len, 0); @@ -3484,7 +3484,7 @@ void partyMemberControlWindowUpdate() int windowWidth = windowGetWidth(gGameDialogWindow); CacheEntry* backgroundHandle; - int backgroundFid = buildFid(6, 390, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0); Art* background = artLock(backgroundFid, &backgroundHandle); if (background != NULL) { int width = artGetWidth(background, 0, 0); @@ -3523,7 +3523,7 @@ void partyMemberControlWindowUpdate() // Render preview. CacheEntry* previewHandle; - int previewFid = buildFid((gGameDialogSpeaker->fid & 0xF000000) >> 24, gGameDialogSpeaker->fid & 0xFFF, ANIM_STAND, (gGameDialogSpeaker->fid & 0xF000) >> 12, ROTATION_SW); + int previewFid = buildFid(FID_TYPE(gGameDialogSpeaker->fid), gGameDialogSpeaker->fid & 0xFFF, ANIM_STAND, (gGameDialogSpeaker->fid & 0xF000) >> 12, ROTATION_SW); Art* preview = artLock(previewFid, &previewHandle); if (preview != NULL) { int width = artGetWidth(preview, 0, ROTATION_SW); @@ -3603,7 +3603,7 @@ int _gdPickAIUpdateMsg(Object* critter) // 0x449330 int _gdCanBarter() { - if ((gGameDialogSpeaker->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_CRITTER) { return 1; } @@ -3612,7 +3612,7 @@ int _gdCanBarter() return 1; } - if (proto->critter.data.flags & 0x02) { + if (proto->critter.data.flags & CRITTER_FLAG_0x2) { return 1; } @@ -3724,7 +3724,7 @@ int partyMemberCustomizationWindowInit() } CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 391, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0); Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle); if (backgroundFrm == NULL) { return -1; @@ -3778,7 +3778,7 @@ int partyMemberCustomizationWindowInit() for (int index = 0; index < PARTY_MEMBER_CUSTOMIZATION_OPTION_COUNT; index++) { GameDialogButtonData* buttonData = &(_custom_button_info[index]); - int upButtonFid = buildFid(6, buttonData->upFrmId, 0, 0, 0); + int upButtonFid = buildFid(OBJ_TYPE_INTERFACE, buttonData->upFrmId, 0, 0, 0); Art* upButtonFrm = artLock(upButtonFid, &(buttonData->upFrmHandle)); if (upButtonFrm == NULL) { partyMemberCustomizationWindowFree(); @@ -3789,7 +3789,7 @@ int partyMemberCustomizationWindowInit() int height = artGetHeight(upButtonFrm, 0, 0); unsigned char* upButtonFrmData = artGetFrameData(upButtonFrm, 0, 0); - int downButtonFid = buildFid(6, buttonData->downFrmId, 0, 0, 0); + int downButtonFid = buildFid(OBJ_TYPE_INTERFACE, buttonData->downFrmId, 0, 0, 0); Art* downButtonFrm = artLock(downButtonFid, &(buttonData->downFrmHandle)); if (downButtonFrm == NULL) { partyMemberCustomizationWindowFree(); @@ -3867,7 +3867,7 @@ void partyMemberCustomizationWindowFree() CacheEntry* backgroundFrmHandle; // custom.frm - party member control interface - int fid = buildFid(6, 391, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData != NULL) { _gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmData, windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len, 0); @@ -3917,7 +3917,7 @@ void partyMemberCustomizationWindowUpdate() int windowWidth = windowGetWidth(gGameDialogWindow); CacheEntry* backgroundHandle; - int backgroundFid = buildFid(6, 391, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0); Art* background = artLock(backgroundFid, &backgroundHandle); if (background == NULL) { return; @@ -4025,7 +4025,7 @@ int _gdCustomSelect(int a1) int oldFont = fontGetCurrent(); CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 419, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 419, 0, 0, 0); Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle); if (backgroundFrm == NULL) { return -1; @@ -4208,7 +4208,7 @@ void _gdCustomUpdateSetting(int option, int value) // 0x44A52C void gameDialogBarterButtonUpMouseUp(int btn, int keyCode) { - if ((gGameDialogSpeaker->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(gGameDialogSpeaker->pid) != OBJ_TYPE_CRITTER) { return; } @@ -4219,7 +4219,7 @@ void gameDialogBarterButtonUpMouseUp(int btn, int keyCode) Proto* proto; protoGetProto(gGameDialogSpeaker->pid, &proto); - if (proto->critter.data.flags & 2) { + if (proto->critter.data.flags & CRITTER_FLAG_0x2) { if (gGameDialogLipSyncStarted) { if (soundIsPlaying(gLipsData.sound)) { gameDialogEndLips(); @@ -4269,7 +4269,7 @@ int _gdialog_window_create() CacheEntry* backgroundFrmHandle; // 389 - di_talkp.frm - dialog screen subwindow (party members) // 99 - di_talk.frm - dialog screen subwindow (NPC's) - int backgroundFid = buildFid(6, gGameDialogSpeakerIsPartyMember ? 389 : 99, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, gGameDialogSpeakerIsPartyMember ? 389 : 99, 0, 0, 0); Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle); if (backgroundFrm == NULL) { return -1; @@ -4306,11 +4306,11 @@ int _gdialog_window_create() buttonSetCallbacks(_gdialog_buttons[0], _gsound_med_butt_press, _gsound_med_butt_release); // di_rest1.frm - dialog rest button up - int upFid = buildFid(6, 97, 0, 0, 0); + int upFid = buildFid(OBJ_TYPE_INTERFACE, 97, 0, 0, 0); unsigned char* reviewButtonUpData = artLockFrameData(upFid, 0, 0, &gGameDialogReviewButtonUpFrmHandle); if (reviewButtonUpData != NULL) { // di_rest2.frm - dialog rest button down - int downFid = buildFid(6, 98, 0, 0, 0); + int downFid = buildFid(OBJ_TYPE_INTERFACE, 98, 0, 0, 0); unsigned char* reivewButtonDownData = artLockFrameData(downFid, 0, 0, &gGameDialogReviewButtonDownFrmHandle); if (reivewButtonDownData != NULL) { // REVIEW @@ -4386,7 +4386,7 @@ void _gdialog_window_destroy() } CacheEntry* backgroundFrmHandle; - int fid = buildFid(6, frmId, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData != NULL) { unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow); @@ -4403,7 +4403,7 @@ int gameDialogWindowRenderBackground() { CacheEntry* backgroundFrmHandle; // alltlk.frm - dialog screen background - int fid = buildFid(6, 103, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 103, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData == NULL) { return -1; @@ -4434,7 +4434,7 @@ int _talkToRefreshDialogWindowRect(Rect* rect) } CacheEntry* backgroundFrmHandle; - int fid = buildFid(6, frmId, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData == NULL) { return -1; @@ -4550,7 +4550,7 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame) unsigned char* src = windowGetBuffer(gIsoWindow); // Usually rendering functions use `screenGetWidth`/`screenGetHeight` to - // determine rendering position. However in this case `windowGetHeight` + // determine rendering position. However in this case `windowGetHeight` // is a must because isometric window's height can either include // interface bar or not. Offset is updated accordingly (332 -> 232, the // missing 100 is interface bar height, which is already accounted for @@ -4612,13 +4612,13 @@ void gameDialogPrepareHighlights() _dark_BlendTable = _getColorBlendTable(_colorTable[22187]); // hilight1.frm - dialogue upper hilight - int upperHighlightFid = buildFid(6, 115, 0, 0, 0); + int upperHighlightFid = buildFid(OBJ_TYPE_INTERFACE, 115, 0, 0, 0); gGameDialogUpperHighlightFrm = artLock(upperHighlightFid, &gGameDialogUpperHighlightFrmHandle); gGameDialogUpperHighlightFrmWidth = artGetWidth(gGameDialogUpperHighlightFrm, 0, 0); gGameDialogUpperHighlightFrmHeight = artGetHeight(gGameDialogUpperHighlightFrm, 0, 0); // hilight2.frm - dialogue lower hilight - int lowerHighlightFid = buildFid(6, 116, 0, 0, 0); + int lowerHighlightFid = buildFid(OBJ_TYPE_INTERFACE, 116, 0, 0, 0); gGameDialogLowerHighlightFrm = artLock(lowerHighlightFid, &gGameDialogLowerHighlightFrmHandle); gGameDialogLowerHighlightFrmWidth = artGetWidth(gGameDialogLowerHighlightFrm, 0, 0); gGameDialogLowerHighlightFrmHeight = artGetHeight(gGameDialogLowerHighlightFrm, 0, 0); diff --git a/src/game_mouse.cc b/src/game_mouse.cc index d808615..caecddd 100644 --- a/src/game_mouse.cc +++ b/src/game_mouse.cc @@ -648,7 +648,7 @@ void gameMouseRefresh() if (pointedObject != NULL) { int primaryAction = -1; - switch ((pointedObject->fid & 0xF000000) >> 24) { + switch (FID_TYPE(pointedObject->fid)) { case OBJ_TYPE_ITEM: primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_USE; if (gGameMouseItemHighlightEnabled) { @@ -670,7 +670,7 @@ void gameMouseRefresh() primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_TALK; } } else { - if (_critter_flag_check(pointedObject->pid, 32)) { + if (_critter_flag_check(pointedObject->pid, CRITTER_FLAG_0x20)) { primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_LOOK; } else { primaryAction = GAME_MOUSE_ACTION_MENU_ITEM_USE; @@ -693,7 +693,7 @@ void gameMouseRefresh() if (primaryAction != -1) { if (gameMouseRenderPrimaryAction(mouseX, mouseY, primaryAction, _scr_size.right - _scr_size.left + 1, _scr_size.bottom - _scr_size.top - 99) == 0) { Rect tmp; - int fid = buildFid(6, 282, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 282, 0, 0, 0); if (objectSetFid(gGameMouseHexCursor, fid, &tmp) == 0) { tileWindowRefreshRect(&tmp, gElevation); } @@ -715,7 +715,7 @@ void gameMouseRefresh() } if (pointedObject != NULL) { - bool pointedObjectIsCritter = (pointedObject->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER; + bool pointedObjectIsCritter = FID_TYPE(pointedObject->fid) == OBJ_TYPE_CRITTER; int combatLooks = 0; configGetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_COMBAT_LOOKS_KEY, &combatLooks); @@ -756,7 +756,7 @@ void gameMouseRefresh() if (gameMouseRenderAccuracy(formattedAccuracy, color) == 0) { Rect tmp; - int fid = buildFid(6, 284, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 284, 0, 0, 0); if (objectSetFid(gGameMouseHexCursor, fid, &tmp) == 0) { tileWindowRefreshRect(&tmp, gElevation); } @@ -825,7 +825,7 @@ void gameMouseRefresh() gGameMouseLastY = mouseY; if (!_gmouse_mapper_mode) { - int fid = buildFid(6, 0, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0); gameMouseSetBouncingCursorFid(fid); } @@ -936,13 +936,13 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState) if (gGameMouseMode == GAME_MOUSE_MODE_ARROW) { Object* v5 = gameMouseGetObjectUnderCursor(-1, true, gElevation); if (v5 != NULL) { - switch ((v5->fid & 0xF000000) >> 24) { + switch (FID_TYPE(v5->fid)) { case OBJ_TYPE_ITEM: actionPickUp(gDude, v5); break; case OBJ_TYPE_CRITTER: if (v5 == gDude) { - if (((gDude->fid & 0xFF0000) >> 16) == ANIM_STAND) { + if (FID_ANIM_TYPE(gDude->fid) == ANIM_STAND) { Rect a1; if (objectRotateClockwise(v5, &a1) == 0) { tileWindowRefreshRect(&a1, v5->elevation); @@ -1053,7 +1053,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState) if (v16 != NULL) { int actionMenuItemsCount = 0; int actionMenuItems[6]; - switch ((v16->fid & 0xF000000) >> 24) { + switch (FID_TYPE(v16->fid)) { case OBJ_TYPE_ITEM: actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE; actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_LOOK; @@ -1072,7 +1072,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState) actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_TALK; } } else { - if (!_critter_flag_check(v16->pid, 32)) { + if (!_critter_flag_check(v16->pid, CRITTER_FLAG_0x20)) { actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE; } } @@ -1108,7 +1108,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState) if (gameMouseRenderActionMenuItems(mouseX, mouseY, actionMenuItems, actionMenuItemsCount, _scr_size.right - _scr_size.left + 1, _scr_size.bottom - _scr_size.top - 99) == 0) { Rect v43; - int fid = buildFid(6, 283, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 283, 0, 0, 0); if (objectSetFid(gGameMouseHexCursor, fid, &v43) == 0 && _gmouse_3d_move_to(mouseX, mouseY, gElevation, &v43) == 0) { tileWindowRefreshRect(&v43, gElevation); isoDisable(); @@ -1171,7 +1171,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState) actionTalk(gDude, v16); break; case GAME_MOUSE_ACTION_MENU_ITEM_USE: - switch ((v16->fid & 0xF000000) >> 24) { + switch (FID_TYPE(v16->fid)) { case OBJ_TYPE_SCENERY: _action_use_an_object(gDude, v16); break; @@ -1242,7 +1242,7 @@ int gameMouseSetCursor(int cursor) } CacheEntry* mouseCursorFrmHandle; - int fid = buildFid(6, gGameMouseCursorFrmIds[cursor], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseCursorFrmIds[cursor], 0, 0, 0); Art* mouseCursorFrm = artLock(fid, &mouseCursorFrmHandle); if (mouseCursorFrm == NULL) { return -1; @@ -1327,10 +1327,10 @@ void gameMouseSetMode(int mode) return; } - int fid = buildFid(6, 0, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0); gameMouseSetBouncingCursorFid(fid); - fid = buildFid(6, gGameMouseModeFrmIds[mode], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[mode], 0, 0, 0); Rect rect; if (objectSetFid(gGameMouseHexCursor, fid, &rect) == -1) { @@ -1472,7 +1472,7 @@ int gameMouseSetBouncingCursorFid(int fid) // 0x44CD0C void gameMouseResetBouncingCursorFid() { - int fid = buildFid(6, 0, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0); gameMouseSetBouncingCursorFid(fid); } @@ -1601,7 +1601,7 @@ Object* gameMouseGetObjectUnderCursor(int objectType, bool a2, int elevation) v4 = ptr->object; if ((ptr->flags & 0x01) != 0) { if ((ptr->flags & 0x04) == 0) { - if ((ptr->object->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER || (ptr->object->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_DEAD)) == 0) { + if (FID_TYPE(ptr->object->fid) != OBJ_TYPE_CRITTER || (ptr->object->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_DEAD)) == 0) { break; } } @@ -1620,14 +1620,14 @@ Object* gameMouseGetObjectUnderCursor(int objectType, bool a2, int elevation) int gameMouseRenderPrimaryAction(int x, int y, int menuItem, int width, int height) { CacheEntry* menuItemFrmHandle; - int menuItemFid = buildFid(6, gGameMouseActionMenuItemFrmIds[menuItem], 0, 0, 0); + int menuItemFid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseActionMenuItemFrmIds[menuItem], 0, 0, 0); Art* menuItemFrm = artLock(menuItemFid, &menuItemFrmHandle); if (menuItemFrm == NULL) { return -1; } CacheEntry* arrowFrmHandle; - int arrowFid = buildFid(6, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0); + int arrowFid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0); Art* arrowFrm = artLock(arrowFid, &arrowFrmHandle); if (arrowFrm == NULL) { artUnlock(menuItemFrmHandle); @@ -1666,7 +1666,7 @@ int gameMouseRenderPrimaryAction(int x, int y, int menuItem, int width, int heig } else { artUnlock(arrowFrmHandle); - arrowFid = buildFid(6, 285, 0, 0, 0); + arrowFid = buildFid(OBJ_TYPE_INTERFACE, 285, 0, 0, 0); arrowFrm = artLock(arrowFid, &arrowFrmHandle); arrowFrmData = artGetFrameData(arrowFrm, 0, 0); arrowFrmDest += menuItemFrmWidth; @@ -1725,7 +1725,7 @@ int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuI frmId -= 1; } - int fid = buildFid(6, frmId, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0); menuItemFrms[index] = artLock(fid, &(menuItemFrmHandles[index])); if (menuItemFrms[index] == NULL) { @@ -1736,7 +1736,7 @@ int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuI } } - int fid = buildFid(6, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[GAME_MOUSE_MODE_ARROW], 0, 0, 0); CacheEntry* arrowFrmHandle; Art* arrowFrm = artLock(fid, &arrowFrmHandle); if (arrowFrm == NULL) { @@ -1772,7 +1772,7 @@ int gameMouseRenderActionMenuItems(int x, int y, const int* menuItems, int menuI } } else { // Mirrored arrow (from left to right). - fid = buildFid(6, 285, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 285, 0, 0, 0); arrowFrm = artLock(fid, &arrowFrmHandle); arrowData = artGetFrameData(arrowFrm, 0, 0); gGameMouseActionMenuFrm->xOffsets[0] = -gGameMouseActionMenuFrm->xOffsets[0]; @@ -1820,7 +1820,7 @@ int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex) } CacheEntry* handle; - int fid = buildFid(6, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[gGameMouseActionMenuHighlightedItemIndex]], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[gGameMouseActionMenuHighlightedItemIndex]], 0, 0, 0); Art* art = artLock(fid, &handle); if (art == NULL) { return -1; @@ -1832,7 +1832,7 @@ int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex) blitBufferToBuffer(data, width, height, width, _gmouse_3d_menu_actions_start + gGameMouseActionMenuFrmWidth * height * gGameMouseActionMenuHighlightedItemIndex, gGameMouseActionMenuFrmWidth); artUnlock(handle); - fid = buildFid(6, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[menuItemIndex]] - 1, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseActionMenuItemFrmIds[gGameMouseActionMenuItems[menuItemIndex]] - 1, 0, 0, 0); art = artLock(fid, &handle); if (art == NULL) { return -1; @@ -1851,7 +1851,7 @@ int gameMouseHighlightActionMenuItemAtIndex(int menuItemIndex) int gameMouseRenderAccuracy(const char* string, int color) { CacheEntry* crosshairFrmHandle; - int fid = buildFid(6, gGameMouseModeFrmIds[GAME_MOUSE_MODE_CROSSHAIR], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[GAME_MOUSE_MODE_CROSSHAIR], 0, 0, 0); Art* crosshairFrm = artLock(fid, &crosshairFrmHandle); if (crosshairFrm == NULL) { return -1; @@ -1910,7 +1910,7 @@ int gameMouseRenderActionPoints(const char* string, int color) fontSetCurrent(oldFont); - int fid = buildFid(6, 1, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 1, 0, 0, 0); gameMouseSetBouncingCursorFid(fid); return 0; @@ -1934,12 +1934,12 @@ int gameMouseObjectsInit() return -1; } - fid = buildFid(6, 0, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0); if (objectCreateWithFidPid(&gGameMouseBouncingCursor, fid, -1) != 0) { return -1; } - fid = buildFid(6, 1, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 1, 0, 0, 0); if (objectCreateWithFidPid(&gGameMouseHexCursor, fid, -1) != 0) { return -1; } @@ -2031,35 +2031,35 @@ int gameMouseActionMenuInit() int fid; // actmenu.frm - action menu - fid = buildFid(6, 283, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 283, 0, 0, 0); gGameMouseActionMenuFrm = artLock(fid, &gGameMouseActionMenuFrmHandle); if (gGameMouseActionMenuFrm == NULL) { goto err; } // actpick.frm - action pick - fid = buildFid(6, 282, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 282, 0, 0, 0); gGameMouseActionPickFrm = artLock(fid, &gGameMouseActionPickFrmHandle); if (gGameMouseActionPickFrm == NULL) { goto err; } // acttohit.frm - action to hit - fid = buildFid(6, 284, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 284, 0, 0, 0); gGameMouseActionHitFrm = artLock(fid, &gGameMouseActionHitFrmHandle); if (gGameMouseActionHitFrm == NULL) { goto err; } // blank.frm - used be mset000.frm for top of bouncing mouse cursor - fid = buildFid(6, 0, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 0, 0, 0, 0); gGameMouseBouncingCursorFrm = artLock(fid, &gGameMouseBouncingCursorFrmHandle); if (gGameMouseBouncingCursorFrm == NULL) { goto err; } // msef000.frm - hex mouse cursor - fid = buildFid(6, 1, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 1, 0, 0, 0); gGameMouseHexCursorFrm = artLock(fid, &gGameMouseHexCursorFrmHandle); if (gGameMouseHexCursorFrm == NULL) { goto err; @@ -2145,7 +2145,7 @@ void gameMouseActionMenuFree() // 0x44DF40 int gameMouseUpdateHexCursorFid(Rect* rect) { - int fid = buildFid(6, gGameMouseModeFrmIds[gGameMouseMode], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gGameMouseModeFrmIds[gGameMouseMode], 0, 0, 0); if (gGameMouseHexCursor->fid == fid) { return -1; } @@ -2210,7 +2210,7 @@ int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4) int y1 = 0; int fid = gGameMouseBouncingCursor->fid; - if ((fid & 0xF000000) >> 24 == OBJ_TYPE_TILE) { + if (FID_TYPE(fid) == OBJ_TYPE_TILE) { int squareTile = squareTileFromScreenXY(x, y, elevation); if (squareTile == -1) { tile = HEX_GRID_WIDTH * (2 * (squareTile / SQUARE_GRID_WIDTH) + 1) + 2 * (squareTile % SQUARE_GRID_WIDTH) + 1; @@ -2398,7 +2398,7 @@ int objectIsDoor(Object* object) return false; } - if ((object->pid >> 24) != OBJ_TYPE_SCENERY) { + if (PID_TYPE(object->pid) != OBJ_TYPE_SCENERY) { return false; } diff --git a/src/game_movie.cc b/src/game_movie.cc index 4e5ffac..91b2f1e 100644 --- a/src/game_movie.cc +++ b/src/game_movie.cc @@ -176,7 +176,7 @@ int gameMoviePlay(int movie, int flags) int gameMovieWindowY = (screenGetHeight() - GAME_MOVIE_WINDOW_HEIGHT) / 2; int win = windowCreate(gameMovieWindowX, gameMovieWindowY, - GAME_MOVIE_WINDOW_WIDTH, + GAME_MOVIE_WINDOW_WIDTH, GAME_MOVIE_WINDOW_HEIGHT, 0, WINDOW_FLAG_0x10); diff --git a/src/game_sound.cc b/src/game_sound.cc index deb60ee..2ce4157 100644 --- a/src/game_sound.cc +++ b/src/game_sound.cc @@ -1118,7 +1118,7 @@ Sound* soundEffectLoad(const char* name, Object* object) } if (object != NULL) { - if ((object->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER && (name[0] == 'H' || name[0] == 'N')) { + if (FID_TYPE(object->fid) == OBJ_TYPE_CRITTER && (name[0] == 'H' || name[0] == 'N')) { char v9 = name[1]; if (v9 == 'A' || v9 == 'F' || v9 == 'M') { if (v9 == 'A') { @@ -1230,7 +1230,7 @@ void soundEffectDelete(Sound* sound) } // 0x4514F0 -int _gsnd_anim_sound(Sound* sound) +int _gsnd_anim_sound(Sound* sound, void* a2) { if (!gGameSoundInitialized) { return 0; @@ -1287,7 +1287,7 @@ int _gsound_compute_relative_volume(Object* obj) v3 = 0x7FFF; if (obj) { - type = (obj->fid & 0xF000000) >> 24; + type = FID_TYPE(obj->fid); if (type == 0 || type == 1 || type == 2) { v7 = objectGetOwner(obj); if (!v7) { @@ -1325,7 +1325,7 @@ char* sfxBuildCharName(Object* a1, int anim, int extra) char v8; char v9; - if (artCopyFileName((a1->fid & 0xF000000) >> 24, a1->fid & 0xFFF, v7) == -1) { + if (artCopyFileName(FID_TYPE(a1->fid), a1->fid & 0xFFF, v7) == -1) { return NULL; } @@ -1399,12 +1399,10 @@ char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* ta v6 = 1; } - int damageType = weaponGetDamageType(NULL, weapon); - // TODO: Check damageType conditions. - if (effectTypeCode != 'H' || target == NULL || damageType == DAMAGE_TYPE_EXPLOSION || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP) { + if (effectTypeCode != 'H' || target == NULL || weaponIsGrenade(weapon)) { materialCode = 'X'; } else { - const int type = (target->fid & 0xF000000) >> 24; + const int type = FID_TYPE(target->fid); int material; switch (type) { case OBJ_TYPE_ITEM: @@ -1466,7 +1464,7 @@ char* sfxBuildSceneryName(int actionType, int action, const char* name) // 0x4518D char* sfxBuildOpenName(Object* object, int action) { - if ((object->fid & 0xF000000) >> 24 == OBJ_TYPE_SCENERY) { + if (FID_TYPE(object->fid) == OBJ_TYPE_SCENERY) { char scenerySoundId; Proto* proto; if (protoGetProto(object->pid, &proto) != -1) { diff --git a/src/game_sound.h b/src/game_sound.h index 1df3550..87209d1 100644 --- a/src/game_sound.h +++ b/src/game_sound.h @@ -63,7 +63,7 @@ int _gsound_play_sfx_file_volume(const char* a1, int a2); Sound* soundEffectLoad(const char* name, Object* a2); Sound* soundEffectLoadWithVolume(const char* a1, Object* a2, int a3); void soundEffectDelete(Sound* a1); -int _gsnd_anim_sound(Sound* a1); +int _gsnd_anim_sound(Sound* sound, void* a2); int soundEffectPlay(Sound* a1); int _gsound_compute_relative_volume(Object* obj); char* sfxBuildCharName(Object* a1, int anim, int extra); diff --git a/src/interface.cc b/src/interface.cc index 0e914d4..954c4da 100644 --- a/src/interface.cc +++ b/src/interface.cc @@ -438,7 +438,7 @@ int interfaceInit() goto err; } - fid = buildFid(6, 16, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 16, 0, 0, 0); backgroundFrmData = artLockFrameData(fid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData == NULL) { goto err; @@ -447,13 +447,13 @@ int interfaceInit() blitBufferToBuffer(backgroundFrmData, INTERFACE_BAR_WIDTH, INTERFACE_BAR_HEIGHT - 1, INTERFACE_BAR_WIDTH, gInterfaceWindowBuffer, 640); artUnlock(backgroundFrmHandle); - fid = buildFid(6, 47, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 47, 0, 0, 0); gInventoryButtonUpFrmData = artLockFrameData(fid, 0, 0, &gInventoryButtonUpFrmHandle); if (gInventoryButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 46, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 46, 0, 0, 0); gInventoryButtonDownFrmData = artLockFrameData(fid, 0, 0, &gInventoryButtonDownFrmHandle); if (gInventoryButtonDownFrmData == NULL) { goto err; @@ -466,13 +466,13 @@ int interfaceInit() buttonSetCallbacks(gInventoryButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 18, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 18, 0, 0, 0); gOptionsButtonUpFrmData = artLockFrameData(fid, 0, 0, &gOptionsButtonUpFrmHandle); if (gOptionsButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 17, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 17, 0, 0, 0); gOptionsButtonDownFrmData = artLockFrameData(fid, 0, 0, &gOptionsButtonDownFrmHandle); if (gOptionsButtonDownFrmData == NULL) { goto err; @@ -485,19 +485,19 @@ int interfaceInit() buttonSetCallbacks(gOptionsButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 6, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0); gSkilldexButtonUpFrmData = artLockFrameData(fid, 0, 0, &gSkilldexButtonUpFrmHandle); if (gSkilldexButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 7, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 7, 0, 0, 0); gSkilldexButtonDownFrmData = artLockFrameData(fid, 0, 0, &gSkilldexButtonDownFrmHandle); if (gSkilldexButtonDownFrmData == NULL) { goto err; } - fid = buildFid(6, 6, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0); gSkilldexButtonMaskFrmData = artLockFrameData(fid, 0, 0, &gSkilldexButtonMaskFrmHandle); if (gSkilldexButtonMaskFrmData == NULL) { goto err; @@ -511,19 +511,19 @@ int interfaceInit() buttonSetMask(gSkilldexButton, gSkilldexButtonMaskFrmData); buttonSetCallbacks(gSkilldexButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 13, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 13, 0, 0, 0); gMapButtonUpFrmData = artLockFrameData(fid, 0, 0, &gMapButtonUpFrmHandle); if (gMapButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 10, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 10, 0, 0, 0); gMapButtonDownFrmData = artLockFrameData(fid, 0, 0, &gMapButtonDownFrmHandle); if (gMapButtonDownFrmData == NULL) { goto err; } - fid = buildFid(6, 13, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 13, 0, 0, 0); gMapButtonMaskFrmData = artLockFrameData(fid, 0, 0, &gMapButtonMaskFrmHandle); if (gMapButtonMaskFrmData == NULL) { goto err; @@ -537,13 +537,13 @@ int interfaceInit() buttonSetMask(gMapButton, gMapButtonMaskFrmData); buttonSetCallbacks(gMapButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 59, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 59, 0, 0, 0); gPipboyButtonUpFrmData = artLockFrameData(fid, 0, 0, &gPipboyButtonUpFrmHandle); if (gPipboyButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 58, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 58, 0, 0, 0); gPipboyButtonDownFrmData = artLockFrameData(fid, 0, 0, &gPipboyButtonDownFrmHandle); if (gPipboyButtonDownFrmData == NULL) { goto err; @@ -557,13 +557,13 @@ int interfaceInit() buttonSetMask(gPipboyButton, gMapButtonMaskFrmData); buttonSetCallbacks(gPipboyButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 57, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 57, 0, 0, 0); gCharacterButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterButtonUpFrmHandle); if (gCharacterButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 56, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 56, 0, 0, 0); gCharacterButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterButtonDownFrmHandle); if (gCharacterButtonDownFrmData == NULL) { goto err; @@ -577,19 +577,19 @@ int interfaceInit() buttonSetMask(gCharacterButton, gMapButtonMaskFrmData); buttonSetCallbacks(gCharacterButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 32, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 32, 0, 0, 0); gSingleAttackButtonUpData = artLockFrameData(fid, 0, 0, &gSingleAttackButtonUpHandle); if (gSingleAttackButtonUpData == NULL) { goto err; } - fid = buildFid(6, 31, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 31, 0, 0, 0); gSingleAttackButtonDownData = artLockFrameData(fid, 0, 0, &gSingleAttackButtonDownHandle); if (gSingleAttackButtonDownData == NULL) { goto err; } - fid = buildFid(6, 73, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 73, 0, 0, 0); _itemButtonDisabled = artLockFrameData(fid, 0, 0, &_itemButtonDisabledKey); if (_itemButtonDisabled == NULL) { goto err; @@ -606,19 +606,19 @@ int interfaceInit() buttonSetRightMouseCallbacks(gSingleAttackButton, -1, KEY_LOWERCASE_N, NULL, NULL); buttonSetCallbacks(gSingleAttackButton, _gsound_lrg_butt_press, _gsound_lrg_butt_release); - fid = buildFid(6, 6, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0); gChangeHandsButtonUpFrmData = artLockFrameData(fid, 0, 0, &gChangeHandsButtonUpFrmHandle); if (gChangeHandsButtonUpFrmData == NULL) { goto err; } - fid = buildFid(6, 7, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 7, 0, 0, 0); gChangeHandsButtonDownFrmData = artLockFrameData(fid, 0, 0, &gChangeHandsButtonDownFrmHandle); if (gChangeHandsButtonDownFrmData == NULL) { goto err; } - fid = buildFid(6, 6, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0); gChangeHandsButtonMaskFrmData = artLockFrameData(fid, 0, 0, &gChangeHandsButtonMaskFrmHandle); if (gChangeHandsButtonMaskFrmData == NULL) { goto err; @@ -633,25 +633,25 @@ int interfaceInit() buttonSetMask(gChangeHandsButton, gChangeHandsButtonMaskFrmData); buttonSetCallbacks(gChangeHandsButton, _gsound_med_butt_press, _gsound_med_butt_release); - fid = buildFid(6, 82, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 82, 0, 0, 0); gNumbersFrmData = artLockFrameData(fid, 0, 0, &gNumbersFrmHandle); if (gNumbersFrmData == NULL) { goto err; } - fid = buildFid(6, 83, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 83, 0, 0, 0); gGreenLightFrmData = artLockFrameData(fid, 0, 0, &gGreenLightFrmHandle); if (gGreenLightFrmData == NULL) { goto err; } - fid = buildFid(6, 84, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 84, 0, 0, 0); gYellowLightFrmData = artLockFrameData(fid, 0, 0, &gYellowLightFrmHandle); if (gYellowLightFrmData == NULL) { goto err; } - fid = buildFid(6, 85, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 85, 0, 0, 0); gRedLightFrmData = artLockFrameData(fid, 0, 0, &gRedLightFrmHandle); if (gRedLightFrmData == NULL) { goto err; @@ -1592,7 +1592,7 @@ void interfaceBarEndButtonsShow(bool animated) return; } - int fid = buildFid(6, 104, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 104, 0, 0, 0); CacheEntry* handle; Art* art = artLock(fid, &handle); if (art == NULL) { @@ -1644,7 +1644,7 @@ void interfaceBarEndButtonsHide(bool animated) return; } - int fid = buildFid(6, 104, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 104, 0, 0, 0); CacheEntry* handle; Art* art = artLock(fid, &handle); if (art == NULL) { @@ -1693,7 +1693,7 @@ void interfaceBarEndButtonsRenderGreenLights() buttonEnable(gEndCombatButton); // endltgrn.frm - green lights around end turn/combat window - int lightsFid = buildFid(6, 109, 0, 0, 0); + int lightsFid = buildFid(OBJ_TYPE_INTERFACE, 109, 0, 0, 0); CacheEntry* lightsFrmHandle; unsigned char* lightsFrmData = artLockFrameData(lightsFid, 0, 0, &lightsFrmHandle); if (lightsFrmData == NULL) { @@ -1717,7 +1717,7 @@ void interfaceBarEndButtonsRenderRedLights() CacheEntry* lightsFrmHandle; // endltred.frm - red lights around end turn/combat window - int lightsFid = buildFid(6, 110, 0, 0, 0); + int lightsFid = buildFid(OBJ_TYPE_INTERFACE, 110, 0, 0, 0); unsigned char* lightsFrmData = artLockFrameData(lightsFid, 0, 0, &lightsFrmHandle); if (lightsFrmData == NULL) { return; @@ -1751,10 +1751,10 @@ static int interfaceBarRefreshMainAction() int fid; if (_proto_action_can_use_on(itemState->item->pid)) { // USE ON - fid = buildFid(6, 294, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 294, 0, 0, 0); } else if (_obj_action_can_use(itemState->item)) { // USE - fid = buildFid(6, 292, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 292, 0, 0, 0); } else { fid = -1; } @@ -1782,20 +1782,20 @@ static int interfaceBarRefreshMainAction() // jump table. switch (itemState->action) { case INTERFACE_ITEM_ACTION_PRIMARY_AIMING: - bullseyeFid = buildFid(6, 288, 0, 0, 0); + bullseyeFid = buildFid(OBJ_TYPE_INTERFACE, 288, 0, 0, 0); // FALLTHROUGH case INTERFACE_ITEM_ACTION_PRIMARY: hitMode = itemState->primaryHitMode; break; case INTERFACE_ITEM_ACTION_SECONDARY_AIMING: - bullseyeFid = buildFid(6, 288, 0, 0, 0); + bullseyeFid = buildFid(OBJ_TYPE_INTERFACE, 288, 0, 0, 0); // FALLTHROUGH case INTERFACE_ITEM_ACTION_SECONDARY: hitMode = itemState->secondaryHitMode; break; case INTERFACE_ITEM_ACTION_RELOAD: actionPoints = _item_mp_cost(gDude, gInterfaceCurrentHand == HAND_LEFT ? HIT_MODE_LEFT_WEAPON_RELOAD : HIT_MODE_RIGHT_WEAPON_RELOAD, false); - primaryFid = buildFid(6, 291, 0, 0, 0); + primaryFid = buildFid(OBJ_TYPE_INTERFACE, 291, 0, 0, 0); break; } @@ -1893,7 +1893,7 @@ static int interfaceBarRefreshMainAction() break; } - primaryFid = buildFid(6, id, 0, 0, 0); + primaryFid = buildFid(OBJ_TYPE_INTERFACE, id, 0, 0, 0); } if (primaryFid != -1) { @@ -1913,7 +1913,7 @@ static int interfaceBarRefreshMainAction() if (actionPoints >= 0 && actionPoints < 10) { // movement point text - int fid = buildFid(6, 289, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 289, 0, 0, 0); CacheEntry* handle; Art* art = artLock(fid, &handle); @@ -1936,7 +1936,7 @@ static int interfaceBarRefreshMainAction() int offset = width + 7; // movement point numbers - ten numbers 0 to 9, each 10 pixels wide. - fid = buildFid(6, 290, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 290, 0, 0, 0); art = artLock(fid, &handle); if (art != NULL) { width = artGetWidth(art, 0, 0); @@ -2018,30 +2018,32 @@ static void interfaceBarSwapHandsAnimatePutAwayTakeOutSequence(int previousWeapo gInterfaceBarSwapHandsInProgress = true; reg_anim_clear(gDude); - reg_anim_begin(2); - reg_anim_update_light(gDude, 4, 0); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); + animationRegisterSetLightDistance(gDude, 4, 0); if (previousWeaponAnimationCode != 0) { const char* sfx = sfxBuildCharName(gDude, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(gDude, sfx, 0); - reg_anim_animate(gDude, ANIM_PUT_AWAY, 0); + animationRegisterPlaySoundEffect(gDude, sfx, 0); + animationRegisterAnimate(gDude, ANIM_PUT_AWAY, 0); } - reg_anim_11_1(NULL, NULL, _intface_redraw_items_callback, -1); + // TODO: Get rid of cast. + animationRegisterCallbackForced(NULL, NULL, (AnimationCallback*)_intface_redraw_items_callback, -1); Object* item = gInterfaceItemStates[gInterfaceCurrentHand].item; if (item != NULL && item->lightDistance > 4) { - reg_anim_update_light(gDude, item->lightDistance, 0); + animationRegisterSetLightDistance(gDude, item->lightDistance, 0); } if (weaponAnimationCode != 0) { - reg_anim_18(gDude, weaponAnimationCode, -1); + animationRegisterTakeOutWeapon(gDude, weaponAnimationCode, -1); } else { - int fid = buildFid(1, gDude->fid & 0xFFF, ANIM_STAND, 0, gDude->rotation + 1); - reg_anim_17(gDude, fid, -1); + int fid = buildFid(OBJ_TYPE_CRITTER, gDude->fid & 0xFFF, ANIM_STAND, 0, gDude->rotation + 1); + animationRegisterSetFid(gDude, fid, -1); } - reg_anim_11_1(NULL, NULL, _intface_change_fid_callback, -1); + // TODO: Get rid of cast. + animationRegisterCallbackForced(NULL, NULL, (AnimationCallback*)_intface_change_fid_callback, -1); if (reg_anim_end() == -1) { return; @@ -2084,13 +2086,13 @@ static int endTurnButtonInit() return -1; } - fid = buildFid(6, 105, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 105, 0, 0, 0); gEndTurnButtonUpFrmData = artLockFrameData(fid, 0, 0, &gEndTurnButtonUpFrmHandle); if (gEndTurnButtonUpFrmData == NULL) { return -1; } - fid = buildFid(6, 106, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 106, 0, 0, 0); gEndTurnButtonDownFrmData = artLockFrameData(fid, 0, 0, &gEndTurnButtonDownFrmHandle); if (gEndTurnButtonDownFrmData == NULL) { return -1; @@ -2147,13 +2149,13 @@ static int endCombatButtonInit() return -1; } - fid = buildFid(6, 107, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 107, 0, 0, 0); gEndCombatButtonUpFrmData = artLockFrameData(fid, 0, 0, &gEndCombatButtonUpFrmHandle); if (gEndCombatButtonUpFrmData == NULL) { return -1; } - fid = buildFid(6, 108, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 108, 0, 0, 0); gEndCombatButtonDownFrmData = artLockFrameData(fid, 0, 0, &gEndCombatButtonDownFrmHandle); if (gEndCombatButtonDownFrmData == NULL) { return -1; @@ -2412,7 +2414,7 @@ static int indicatorBarInit() CacheEntry* indicatorBoxFrmHandle; int width; int height; - int indicatorBoxFid = buildFid(6, 126, 0, 0, 0); + int indicatorBoxFid = buildFid(OBJ_TYPE_INTERFACE, 126, 0, 0, 0); unsigned char* indicatorBoxFrmData = artLockFrameDataReturningSize(indicatorBoxFid, &indicatorBoxFrmHandle, &width, &height); if (indicatorBoxFrmData == NULL) { debugPrint("\nINTRFACE: Error initializing indicator box graphics! **\n"); diff --git a/src/interpreter.cc b/src/interpreter.cc index 6277ea5..f4105dc 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -398,7 +398,7 @@ static void _detachProgram(Program* program) static void _purgeProgram(Program* program) { if (!program->exited) { - _removeProgramReferences_(program); + intLibRemoveProgramReferences(program); program->exited = true; } } @@ -781,7 +781,7 @@ static void opCancelAll(Program* program) static void opIf(Program* program) { ProgramValue value = programStackPopValue(program); - + if (!value.isEmpty()) { programStackPopValue(program); } else { @@ -1963,7 +1963,7 @@ static void opCall(Program* program) // 0x46B590 static void op801F(Program* program) { - program->field_84 = programStackPopInteger(program); + program->windowId = programStackPopInteger(program); program->field_7C = (int (*)(Program*))programStackPopPointer(program); program->flags = programStackPopInteger(program) & 0xFFFF; } @@ -2216,7 +2216,7 @@ static void opExportProcedure(Program* program) unsigned char* proc_ptr = program->procedures + 4 + sizeof(Procedure) * procedureIndex; - char *procedureName = programGetIdentifier(program, stackReadInt32(proc_ptr, 0)); + char* procedureName = programGetIdentifier(program, stackReadInt32(proc_ptr, 0)); int procedureAddress = stackReadInt32(proc_ptr, 16); if (externalProcedureCreate(program, procedureName, procedureAddress, argumentCount) != 0) { @@ -2253,7 +2253,7 @@ static void opExit(Program* program) } if (!program->exited) { - _removeProgramReferences_(program); + intLibRemoveProgramReferences(program); program->exited = true; } } @@ -2297,7 +2297,7 @@ static void opCallStart(Program* program) _interpret(program->child, 24); program->child->parent = program; - program->child->field_84 = program->field_84; + program->child->windowId = program->windowId; } // spawn @@ -2323,7 +2323,7 @@ static void opSpawn(Program* program) _interpret(program->child, 24); program->child->parent = program; - program->child->field_84 = program->field_84; + program->child->windowId = program->windowId; if ((program->flags & PROGRAM_FLAG_CRITICAL_SECTION) != 0) { program->child->flags |= PROGRAM_FLAG_CRITICAL_SECTION; @@ -2349,7 +2349,7 @@ static Program* forkProgram(Program* program) _interpret(forked, 24); - forked->field_84 = program->field_84; + forked->windowId = program->windowId; return forked; } @@ -2516,7 +2516,7 @@ void interpreterRegisterOpcodeHandlers() interpreterRegisterOpcode(OPCODE_START_CRITICAL, opEnterCriticalSection); interpreterRegisterOpcode(OPCODE_END_CRITICAL, opLeaveCriticalSection); - _initIntlib(); + intLibInit(); _initExport(); } @@ -2524,7 +2524,7 @@ void interpreterRegisterOpcodeHandlers() void _interpretClose() { externalVariablesClear(); - _intlibClose(); + intLibExit(); } // 0x46CCA4 @@ -2641,7 +2641,7 @@ static void _setupCallWithReturnVal(Program* program, int address, int returnAdd programStackPushPointer(program, (void*)program->field_7C); - programStackPushInteger(program, program->field_84); + programStackPushInteger(program, program->windowId); program->flags &= ~0xFFFF; program->instructionPointer = address; @@ -2664,11 +2664,11 @@ static void _setupExternalCallWithReturnVal(Program* program1, Program* program2 programStackPushPointer(program2, (void*)program2->field_7C); - programStackPushInteger(program2, program2->field_84); + programStackPushInteger(program2, program2->windowId); program2->flags &= ~0xFFFF; program2->instructionPointer = address; - program2->field_84 = program1->field_84; + program2->windowId = program1->windowId; program1->flags |= PROGRAM_FLAG_0x20; } @@ -2683,9 +2683,9 @@ void _executeProc(Program* program, int procedure_index) unsigned char* procedure_ptr; int flags; char err[256]; - Program* v12; + Program* context; - procedure_ptr = program->procedures + 4 + 24 * procedure_index; + procedure_ptr = program->procedures + 4 + sizeof(Procedure) * procedure_index; flags = stackReadInt32(procedure_ptr, 4); if (!(flags & PROCEDURE_FLAG_IMPORTED)) { address = stackReadInt32(procedure_ptr, 16); @@ -2699,7 +2699,7 @@ void _executeProc(Program* program, int procedure_index) } program->flags |= PROGRAM_FLAG_CRITICAL_SECTION; - v12 = program; + context = program; } else { identifier = programGetIdentifier(program, stackReadInt32(procedure_ptr, 0)); external_program = externalProcedureGetProgram(identifier, &address, &arguments_count); @@ -2721,7 +2721,7 @@ void _executeProc(Program* program, int procedure_index) programStackPushInteger(external_program, 0); - procedure_ptr = external_program->procedures + 4 + 24 * procedure_index; + procedure_ptr = external_program->procedures + 4 + sizeof(Procedure) * procedure_index; flags = stackReadInt32(procedure_ptr, 4); if (!(flags & PROCEDURE_FLAG_CRITICAL)) { @@ -2729,10 +2729,10 @@ void _executeProc(Program* program, int procedure_index) } external_program->flags |= PROGRAM_FLAG_CRITICAL_SECTION; - v12 = external_program; + context = external_program; } - _interpret(v12, 0); + _interpret(context, 0); } // Returns index of the procedure with specified name or -1 if no such @@ -2769,10 +2769,10 @@ void _executeProcedure(Program* program, int procedure_index) jmp_buf jmp_buf; Program* v13; - procedure_ptr = program->procedures + 4 + 24 * procedure_index; + procedure_ptr = program->procedures + 4 + sizeof(Procedure) * procedure_index; flags = stackReadInt32(procedure_ptr, 4); - if (flags & 0x04) { + if (flags & PROCEDURE_FLAG_IMPORTED) { identifier = programGetIdentifier(program, stackReadInt32(procedure_ptr, 0)); external_program = externalProcedureGetProgram(identifier, &address, &arguments_count); if (external_program == NULL) { @@ -2875,7 +2875,7 @@ void _updatePrograms() curr = next; } _doEvents(); - _updateIntLib(); + intLibUpdate(); } // 0x46E238 diff --git a/src/interpreter.h b/src/interpreter.h index 87f7c74..e52e966 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -167,7 +167,7 @@ typedef struct Program { int field_78; // time when program begin execution (for the first time)?, -1 - program never executed int (*field_7C)(struct Program* s); // proc to check timer int flags; // flags - int field_84; + int windowId; bool exited; ProgramStack* stackValues; ProgramStack* returnStackValues; diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index b5820ed..7316376 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -19,7 +19,6 @@ #include "game_sound.h" #include "geometry.h" #include "interface.h" -#include "interpreter.h" #include "item.h" #include "light.h" #include "loadsave.h" @@ -300,8 +299,8 @@ static void opObjectClose(Program* program); static void opGameUiDisable(Program* program); static void opGameUiEnable(Program* program); static void opGameUiIsDisabled(Program* program); -static void opFadeOut(Program* program); -static void opFadeIn(Program* program); +static void opGameFadeOut(Program* program); +static void opGameFadeIn(Program* program); static void opItemCapsTotal(Program* program); static void opItemCapsAdjust(Program* program); static void _op_anim_action_frame(Program* program); @@ -496,11 +495,11 @@ static int _correctFidForRemovedItem(Object* a1, Object* a2, int flags) } if (v8 == 0) { - newFid = buildFid((fid & 0xF000000) >> 24, fid & 0xFFF, (fid & 0xFF0000) >> 16, 0, (fid & 0x70000000) >> 28); + newFid = buildFid(FID_TYPE(fid), fid & 0xFFF, FID_ANIM_TYPE(fid), 0, (fid & 0x70000000) >> 28); } } else { if (a1 == gDude) { - newFid = buildFid((fid & 0xF000000) >> 24, _art_vault_guy_num, (fid & 0xFF0000) >> 16, v8, (fid & 0x70000000) >> 28); + newFid = buildFid(FID_TYPE(fid), _art_vault_guy_num, FID_ANIM_TYPE(fid), v8, (fid & 0x70000000) >> 28); } _adjust_ac(a1, a2, NULL); @@ -557,7 +556,7 @@ static void opSetMapStart(Program* program) int elevation = programStackPopInteger(program); int y = programStackPopInteger(program); int x = programStackPopInteger(program); - + if (mapSetElevation(elevation) != 0) { scriptError("\nScript Error: %s: op_set_map_start: map_set_elevation failed", program->name); return; @@ -619,7 +618,7 @@ static void opHasSkill(Program* program) int result = 0; if (object != NULL) { - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { result = skillGetValue(object, skill); } } else { @@ -658,7 +657,7 @@ static void opRollVsSkill(Program* program) int roll = ROLL_CRITICAL_FAILURE; if (object != NULL) { - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { int sid = scriptGetSid(program); Script* script; @@ -835,7 +834,7 @@ static void opRandom(Program* program) } int result; - if (_vcr_status() == 2) { + if (vcrGetState() == VCR_STATE_TURNED_OFF) { result = randomBetween(data[1], data[0]); } else { result = (data[0] - data[1]) / 2; @@ -899,7 +898,7 @@ static void opMoveTo(Program* program) Rect before; objectGetRect(object, &before); - if (object->elevation != elevation && (object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (object->elevation != elevation && PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { _combat_delete_critter(object); } @@ -964,7 +963,7 @@ static void opCreateObject(Program* program) if (sid != -1) { int scriptType = 0; - switch (object->pid >> 24) { + switch (PID_TYPE(object->pid)) { case OBJ_TYPE_CRITTER: scriptType = SCRIPT_TYPE_CRITTER; break; @@ -991,7 +990,7 @@ static void opCreateObject(Program* program) script->field_14 = sid - 1; if (scriptType == SCRIPT_TYPE_SPATIAL) { - script->sp.built_tile = ((object->elevation << 29) & 0xE0000000) | object->tile; + script->sp.built_tile = builtTileCreate(object->tile, object->elevation); script->sp.radius = 3; } @@ -1020,7 +1019,7 @@ static void opDestroyObject(Program* program) return; } - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { if (_isLoadingGame()) { debugPrint("\nError: attempt to destroy critter in load/save-game: %s!", program->name); program->flags &= ~PROGRAM_FLAG_0x20; @@ -1030,7 +1029,7 @@ static void opDestroyObject(Program* program) bool isSelf = object == scriptGetSelf(program); - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { _combat_delete_critter(object); } @@ -1311,7 +1310,7 @@ static void opGetObjectType(Program* program) int objectType = -1; if (object != NULL) { - objectType = (object->fid & 0xF000000) >> 24; + objectType = FID_TYPE(object->fid); } programStackPushInteger(program, objectType); @@ -1325,7 +1324,7 @@ static void opGetItemType(Program* program) int itemType = -1; if (obj != NULL) { - if ((obj->pid >> 24) == OBJ_TYPE_ITEM) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_ITEM) { Proto* proto; if (protoGetProto(obj->pid, &proto) != -1) { itemType = itemGetType(obj); @@ -1400,8 +1399,8 @@ static void opAnimateStand(Program* program) } if (!isInCombat()) { - reg_anim_begin(1); - reg_anim_animate(object, ANIM_STAND, 0); + reg_anim_begin(ANIMATION_REQUEST_UNRESERVED); + animationRegisterAnimate(object, ANIM_STAND, 0); reg_anim_end(); } } @@ -1424,8 +1423,8 @@ static void opAnimateStandReverse(Program* program) } if (!isInCombat()) { - reg_anim_begin(0x01); - reg_anim_animate_reverse(object, ANIM_STAND, 0); + reg_anim_begin(ANIMATION_REQUEST_UNRESERVED); + animationRegisterAnimateReversed(object, ANIM_STAND, 0); reg_anim_end(); } } @@ -1468,12 +1467,12 @@ static void opAnimateMoveObjectToTile(Program* program) flags &= ~0x10; } - reg_anim_begin(1); + reg_anim_begin(ANIMATION_REQUEST_UNRESERVED); if (flags == 0) { - reg_anim_obj_move_to_tile(object, tile, object->elevation, -1, 0); + animationRegisterMoveToTile(object, tile, object->elevation, -1, 0); } else { - reg_anim_obj_run_to_tile(object, tile, object->elevation, -1, 0); + animationRegisterRunToTile(object, tile, object->elevation, -1, 0); } reg_anim_end(); @@ -1739,7 +1738,7 @@ static void opWieldItem(Program* program) return; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { scriptPredefinedError(program, "wield_obj_critter", SCRIPT_ERROR_FOLLOWS); debugPrint(" Only works for critters! ERROR ERROR ERROR!"); return; @@ -1805,7 +1804,7 @@ static void opUseObject(Program* program) } Object* self = scriptGetSelf(program); - if ((self->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) { _action_use_an_object(script->target, object); } else { _obj_use(self, object); @@ -1946,7 +1945,7 @@ static void opStartGameDialog(Program* program) } gGameDialogHeadFid = -1; - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { Proto* proto; if (protoGetProto(obj->pid, &proto) == -1) { return; @@ -2009,7 +2008,7 @@ static void opMetarule3(Program* program) ProgramValue param2 = programStackPopValue(program); ProgramValue param1 = programStackPopValue(program); int rule = programStackPopInteger(program); - + ProgramValue result; result.opcode = VALUE_TYPE_INT; result.integerValue = 0; @@ -2048,7 +2047,7 @@ static void opMetarule3(Program* program) Object* object = objectFindFirstAtLocation(elevation, tile); while (object != NULL) { - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { if (critterFound) { result.opcode = VALUE_TYPE_PTR; result.pointerValue = object; @@ -2069,9 +2068,9 @@ static void opMetarule3(Program* program) Object* obj = static_cast(param1.pointerValue); int frmId = param2.integerValue; - int fid = buildFid((obj->fid & 0xF000000) >> 24, + int fid = buildFid(FID_TYPE(obj->fid), frmId, - (obj->fid & 0xFF0000) >> 16, + FID_ANIM_TYPE(obj->fid), (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 28); @@ -2139,7 +2138,7 @@ static void opSetObjectVisibility(Program* program) Rect rect; if (objectHide(obj, &rect) != -1) { - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { obj->flags |= OBJECT_NO_BLOCK; } @@ -2148,7 +2147,7 @@ static void opSetObjectVisibility(Program* program) } } else { if ((obj->flags & OBJECT_HIDDEN) != 0) { - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { obj->flags &= ~OBJECT_NO_BLOCK; } @@ -2364,7 +2363,7 @@ static int _correctDeath(Object* critter, int anim, bool forceBack) if (violenceLevel < VIOLENCE_LEVEL_MAXIMUM_BLOOD) { useStandardDeath = true; } else { - int fid = buildFid(1, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1); if (!artExists(fid)) { useStandardDeath = true; } @@ -2374,7 +2373,7 @@ static int _correctDeath(Object* critter, int anim, bool forceBack) if (forceBack) { anim = ANIM_FALL_BACK; } else { - int fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_FRONT, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_FRONT, (critter->fid & 0xF000) >> 12, critter->rotation + 1); if (artExists(fid)) { anim = ANIM_FALL_FRONT; } else { @@ -2407,7 +2406,7 @@ static void opKillCritterType(Program* program) Object* obj = objectFindFirst(); while (obj != NULL) { - if (((obj->fid & 0xFF0000) >> 16) >= ANIM_FALL_BACK_SF) { + if (FID_ANIM_TYPE(obj->fid) >= ANIM_FALL_BACK_SF) { obj = objectFindNext(); continue; } @@ -2447,7 +2446,7 @@ static void opKillCritterType(Program* program) objectFindFirst(); - gMapHeader.field_38 = gameTimeGetTime(); + gMapHeader.lastVisitTime = gameTimeGetTime(); } obj = objectFindNext(); @@ -2471,7 +2470,7 @@ static void opCritterDamage(Program* program) return; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { scriptPredefinedError(program, "critter_damage", SCRIPT_ERROR_FOLLOWS); debugPrint(" Can't call on non-critters!"); return; @@ -2485,7 +2484,7 @@ static void opCritterDamage(Program* program) bool animate = (damageTypeWithFlags & 0x200) == 0; bool bypassArmor = (damageTypeWithFlags & 0x100) != 0; int damageType = damageTypeWithFlags & ~(0x100 | 0x200); - _action_dmg(object->tile, object->elevation, amount, amount, damageType, animate, bypassArmor); + actionDamage(object->tile, object->elevation, amount, amount, damageType, animate, bypassArmor); program->flags &= ~PROGRAM_FLAG_0x20; @@ -2567,12 +2566,12 @@ static void opHasTrait(Program* program) case CRITTER_TRAIT_OBJECT: switch (param) { case CRITTER_TRAIT_OBJECT_AI_PACKET: - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { result = object->data.critter.combat.aiPacket; } break; case CRITTER_TRAIT_OBJECT_TEAM: - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { result = object->data.critter.combat.team; } break; @@ -2681,7 +2680,7 @@ static void opGameDialogSystemEnter(Program* program) } Object* self = scriptGetSelf(program); - if ((self->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) { if (!critterIsActive(self)) { return; } @@ -2723,11 +2722,11 @@ static void opGetCritterState(Program* program) Object* critter = static_cast(programStackPopPointer(program)); int state = CRITTER_STATE_DEAD; - if (critter != NULL && (critter->pid >> 24) == OBJ_TYPE_CRITTER) { + if (critter != NULL && PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER) { if (critterIsActive(critter)) { state = CRITTER_STATE_NORMAL; - int anim = (critter->fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(critter->fid); if (anim >= ANIM_FALL_BACK_SF && anim <= ANIM_FALL_FRONT_SF) { state = CRITTER_STATE_PRONE; } @@ -2809,7 +2808,7 @@ static void opCritterAttemptPlacement(Program* program) return; } - if (elevation != critter->elevation && critter->pid >> 24 == OBJ_TYPE_CRITTER) { + if (elevation != critter->elevation && PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER) { _combat_delete_critter(critter); } @@ -2853,7 +2852,7 @@ static void opCritterAddTrait(Program* program) Object* object = static_cast(programStackPopPointer(program)); if (object != NULL) { - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { switch (kind) { case CRITTER_TRAIT_PERK: if (1) { @@ -2928,7 +2927,7 @@ static void opCritterRemoveTrait(Program* program) return; } - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { switch (kind) { case CRITTER_TRAIT_PERK: while (perkGetRank(object, param) > 0) { @@ -2997,7 +2996,7 @@ static void opCritterGetInventoryObject(Program* program) int type = programStackPopInteger(program); Object* critter = static_cast(programStackPopPointer(program)); - if ((critter->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER) { switch (type) { case INVEN_TYPE_WORN: programStackPushPointer(program, critterGetArmor(critter)); @@ -3280,13 +3279,13 @@ static void opMetarule(Program* program) case METARULE_WEAPON_DAMAGE_TYPE: if (1) { Object* object = static_cast(param.pointerValue); - if ((object->pid >> 24) == OBJ_TYPE_ITEM) { + if (PID_TYPE(object->pid) == OBJ_TYPE_ITEM) { if (itemGetType(object) == ITEM_TYPE_WEAPON) { result = weaponGetDamageType(NULL, object); break; } } else { - if (buildFid(5, 10, 0, 0, 0) == object->fid) { + if (buildFid(OBJ_TYPE_MISC, 10, 0, 0, 0) == object->fid) { result = DAMAGE_TYPE_EXPLOSION; break; } @@ -3299,10 +3298,10 @@ static void opMetarule(Program* program) case METARULE_CRITTER_BARTERS: if (1) { Object* object = static_cast(param.pointerValue); - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { Proto* proto; protoGetProto(object->pid, &proto); - if ((proto->critter.data.flags & 0x02) != 0) { + if ((proto->critter.data.flags & CRITTER_FLAG_0x2) != 0) { result = 1; } } @@ -3348,40 +3347,40 @@ static void opAnim(Program* program) if (anim < ANIM_COUNT) { CritterCombatData* combatData = NULL; - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { combatData = &(obj->data.critter.combat); } anim = _correctDeath(obj, anim, true); - reg_anim_begin(1); + reg_anim_begin(ANIMATION_REQUEST_UNRESERVED); // TODO: Not sure about the purpose, why it handles knock down flag? if (frame == 0) { - reg_anim_animate(obj, anim, 0); + animationRegisterAnimate(obj, anim, 0); if (anim >= ANIM_FALL_BACK && anim <= ANIM_FALL_FRONT_BLOOD) { - int fid = buildFid(1, obj->fid & 0xFFF, anim + 28, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 28); - reg_anim_17(obj, fid, -1); + int fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, anim + 28, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 28); + animationRegisterSetFid(obj, fid, -1); } if (combatData != NULL) { combatData->results &= DAM_KNOCKED_DOWN; } } else { - int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 24); - reg_anim_animate_reverse(obj, anim, 0); + int fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, anim, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 24); + animationRegisterAnimateReversed(obj, anim, 0); if (anim == ANIM_PRONE_TO_STANDING) { - fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_FALL_FRONT_SF, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 24); + fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_FALL_FRONT_SF, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 24); } else if (anim == ANIM_BACK_TO_STANDING) { - fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_FALL_BACK_SF, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 24); + fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_FALL_BACK_SF, (obj->fid & 0xF000) >> 12, (obj->fid & 0x70000000) >> 24); } if (combatData != NULL) { combatData->results |= DAM_KNOCKED_DOWN; } - reg_anim_17(obj, fid, -1); + animationRegisterSetFid(obj, fid, -1); } reg_anim_end(); @@ -3451,7 +3450,7 @@ static void opRegAnimAnimate(Program* program) int violenceLevel = VIOLENCE_LEVEL_NONE; if (anim != 20 || object == NULL || object->pid != 0x100002F || (configGetInt(&gGameConfig, GAME_CONFIG_PREFERENCES_KEY, GAME_CONFIG_VIOLENCE_LEVEL_KEY, &violenceLevel) && violenceLevel >= 2)) { if (object != NULL) { - reg_anim_animate(object, anim, delay); + animationRegisterAnimate(object, anim, delay); } else { scriptPredefinedError(program, "reg_anim_animate", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -3469,7 +3468,7 @@ static void opRegAnimAnimateReverse(Program* program) if (!isInCombat()) { if (object != NULL) { - reg_anim_animate_reverse(object, anim, delay); + animationRegisterAnimateReversed(object, anim, delay); } else { scriptPredefinedError(program, "reg_anim_animate_reverse", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -3486,7 +3485,7 @@ static void opRegAnimObjectMoveToObject(Program* program) if (!isInCombat()) { if (object != NULL) { - reg_anim_obj_move_to_obj(object, dest, -1, delay); + animationRegisterMoveToObject(object, dest, -1, delay); } else { scriptPredefinedError(program, "reg_anim_obj_move_to_obj", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -3503,7 +3502,7 @@ static void opRegAnimObjectRunToObject(Program* program) if (!isInCombat()) { if (object != NULL) { - reg_anim_obj_run_to_obj(object, dest, -1, delay); + animationRegisterRunToObject(object, dest, -1, delay); } else { scriptPredefinedError(program, "reg_anim_obj_run_to_obj", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -3520,7 +3519,7 @@ static void opRegAnimObjectMoveToTile(Program* program) if (!isInCombat()) { if (object != NULL) { - reg_anim_obj_move_to_tile(object, tile, object->elevation, -1, delay); + animationRegisterMoveToTile(object, tile, object->elevation, -1, delay); } else { scriptPredefinedError(program, "reg_anim_obj_move_to_tile", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -3537,7 +3536,7 @@ static void opRegAnimObjectRunToTile(Program* program) if (!isInCombat()) { if (object != NULL) { - reg_anim_obj_run_to_tile(object, tile, object->elevation, -1, delay); + animationRegisterRunToTile(object, tile, object->elevation, -1, delay); } else { scriptPredefinedError(program, "reg_anim_obj_run_to_tile", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -3674,8 +3673,8 @@ static void opGetDaysSinceLastVisit(Program* program) { int days; - if (gMapHeader.field_38 != 0) { - days = (gameTimeGetTime() - gMapHeader.field_38) / GAME_TIME_TICKS_PER_DAY; + if (gMapHeader.lastVisitTime != 0) { + days = (gameTimeGetTime() - gMapHeader.lastVisitTime) / GAME_TIME_TICKS_PER_DAY; } else { days = -1; } @@ -3759,7 +3758,6 @@ static void _op_gsay_option(Program* program) } } else { programFatalError("Invalid arg 3 to sayOption"); - } program->flags &= ~PROGRAM_FLAG_0x20; @@ -3868,7 +3866,7 @@ static void opGetPoison(Program* program) int poison = 0; if (obj != NULL) { - if (obj->pid >> 24 == 1) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { poison = critterGetPoison(obj); } else { debugPrint("\nScript Error: get_poison: who is not a critter!"); @@ -3915,7 +3913,7 @@ static void opRegAnimAnimateForever(Program* program) if (!isInCombat()) { if (obj != NULL) { - reg_anim_animate_forever(obj, anim, -1); + animationRegisterAnimateForever(obj, anim, -1); } else { scriptPredefinedError(program, "reg_anim_animate_forever", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -4119,7 +4117,7 @@ static void opGameUiIsDisabled(Program* program) // gfade_out // 0x45B404 -static void opFadeOut(Program* program) +static void opGameFadeOut(Program* program) { int data = programStackPopInteger(program); @@ -4132,7 +4130,7 @@ static void opFadeOut(Program* program) // gfade_in // 0x45B47C -static void opFadeIn(Program* program) +static void opGameFadeIn(Program* program) { int data = programStackPopInteger(program); @@ -4186,7 +4184,7 @@ static void _op_anim_action_frame(Program* program) int actionFrame = 0; if (object != NULL) { - int fid = buildFid((object->fid & 0xF000000) >> 24, object->fid & 0xFFF, anim, 0, object->rotation); + int fid = buildFid(FID_TYPE(object->fid), object->fid & 0xFFF, anim, 0, object->rotation); CacheEntry* frmHandle; Art* frm = artLock(fid, &frmHandle); if (frm != NULL) { @@ -4214,7 +4212,7 @@ static void opRegAnimPlaySfx(Program* program) } if (obj != NULL) { - reg_anim_play_sfx(obj, soundEffectName, delay); + animationRegisterPlaySoundEffect(obj, soundEffectName, delay); } else { scriptPredefinedError(program, "reg_anim_play_sfx", SCRIPT_ERROR_OBJECT_IS_NULL); } @@ -4229,7 +4227,7 @@ static void opCritterModifySkill(Program* program) Object* critter = static_cast(programStackPopPointer(program)); if (critter != NULL && points != 0) { - if (critter->pid >> 24 == OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER) { if (critter == gDude) { int normalizedPoints = abs(points); if (skillIsTagged(skill)) { @@ -4430,7 +4428,7 @@ static void opDestroyMultipleObjects(Program* program) int result = 0; - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { _combat_delete_critter(object); } @@ -4502,7 +4500,7 @@ static void opUseObjectOnObject(Program* program) } Object* self = scriptGetSelf(program); - if ((self->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) { _action_use_an_item_on_object(self, target, item); } else { _obj_use_item_on(self, target, item); @@ -4723,7 +4721,7 @@ static void opTerminateCombat(Program* program) _game_user_wants_to_quit = 1; Object* self = scriptGetSelf(program); if (self != NULL) { - if ((self->pid >> 24) == 1) { + if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) { self->data.critter.combat.maneuver |= CRITTER_MANEUVER_STOP_ATTACKING; self->data.critter.combat.whoHitMe = NULL; _combatAIInfoSetLastTarget(self, NULL); @@ -4967,8 +4965,8 @@ void _initIntExtra() interpreterRegisterOpcode(0x8133, opGameUiDisable); // op_game_ui_disable interpreterRegisterOpcode(0x8134, opGameUiEnable); // op_game_ui_enable interpreterRegisterOpcode(0x8135, opGameUiIsDisabled); // op_game_ui_is_disabled - interpreterRegisterOpcode(0x8136, opFadeOut); // op_gfade_out - interpreterRegisterOpcode(0x8137, opFadeIn); // op_gfade_in + interpreterRegisterOpcode(0x8136, opGameFadeOut); // op_gfade_out + interpreterRegisterOpcode(0x8137, opGameFadeIn); // op_gfade_in interpreterRegisterOpcode(0x8138, opItemCapsTotal); // op_item_caps_total interpreterRegisterOpcode(0x8139, opItemCapsAdjust); // op_item_caps_adjust interpreterRegisterOpcode(0x813A, _op_anim_action_frame); // op_anim_action_frame @@ -5001,7 +4999,16 @@ void _initIntExtra() interpreterRegisterOpcode(0x8155, opCritterStopAttacking); // op_critter_stop_attacking } +// NOTE: Uncollapsed 0x45D878. +// // 0x45D878 -void _intExtraRemoveProgramReferences_() +void intExtraUpdate() +{ +} + +// NOTE: Uncollapsed 0x45D878. +// +// 0x45D878 +void intExtraRemoveProgramReferences(Program* program) { } diff --git a/src/interpreter_extra.h b/src/interpreter_extra.h index 0816adb..b884185 100644 --- a/src/interpreter_extra.h +++ b/src/interpreter_extra.h @@ -1,8 +1,11 @@ #ifndef INTERPRETER_EXTRA_H #define INTERPRETER_EXTRA_H +#include "interpreter.h" + void _intExtraClose_(); void _initIntExtra(); -void _intExtraRemoveProgramReferences_(); +void intExtraUpdate(); +void intExtraRemoveProgramReferences(Program* program); #endif /* INTERPRETER_EXTRA_H */ diff --git a/src/interpreter_lib.cc b/src/interpreter_lib.cc index d33797b..5a37925 100644 --- a/src/interpreter_lib.cc +++ b/src/interpreter_lib.cc @@ -2,47 +2,83 @@ #include "color.h" #include "core.h" +#include "datafile.h" #include "debug.h" #include "dialog.h" #include "interpreter_extra.h" #include "memory_manager.h" +#include "mouse_manager.h" #include "nevs.h" +#include "select_file_list.h" #include "sound.h" +#include "text_font.h" #include "widget.h" +#include "window.h" +#include "window_manager_private.h" -#define INTERPRETER_SOUNDS_LENGTH (32) -#define INTERPRETER_KEY_HANDLER_ENTRIES_LENGTH (256) +#define INT_LIB_SOUNDS_CAPACITY (32) +#define INT_LIB_KEY_HANDLERS_CAPACITY (256) -typedef struct InterpreterKeyHandlerEntry { +typedef struct IntLibKeyHandlerEntry { Program* program; int proc; -} InterpreterKeyHandlerEntry; +} IntLibKeyHandlerEntry; +static void opFillWin3x3(Program* program); static void opFormat(Program* program); static void opPrint(Program* program); +static void opSelectFileList(Program* program); +static void opTokenize(Program* program); static void opPrintRect(Program* program); +static void opSelect(Program* program); +static void opDisplay(Program* program); +static void opDisplayRaw(Program* program); +static void sub_46222C(unsigned char* a1, unsigned char* a2, int a3, float a4, int a5); +static void opFadeIn(Program* program); +static void opFadeOut(Program* program); +static int intLibCheckMovie(Program* program); static void opSetMovieFlags(Program* program); +static void opPlayMovie(Program* program); static void opStopMovie(Program* program); static void opAddRegionProc(Program* program); static void opAddRegionRightProc(Program* program); +static void opCreateWin(Program* program); +static void opResizeWin(Program* program); +static void opScaleWin(Program* program); +static void opDeleteWin(Program* program); static void opSayStart(Program* program); static void opDeleteRegion(Program* program); +static void opActivateRegion(Program* program); static void opCheckRegion(Program* program); +static void opAddRegion(Program* program); static void opSayStartPos(Program* program); static void opSayReplyTitle(Program* program); static void opSayGoToReply(Program* program); +static void opSayReply(Program* program); +static void opSayOption(Program* program); +static int intLibCheckDialog(Program* program); +static void opSayEnd(Program* program); static void opSayGetLastPos(Program* program); static void opSayQuit(Program* program); static void opSayMessageTimeout(Program* program); +static void opSayMessage(Program* program); +static void opGotoXY(Program* program); static void opAddButtonFlag(Program* program); static void opAddRegionFlag(Program* program); +static void opAddButton(Program* program); +static void opAddButtonText(Program* program); +static void opAddButtonGfx(Program* program); static void opAddButtonProc(Program* program); static void opAddButtonRightProc(Program* program); static void opShowWin(Program* program); static void opDeleteButton(Program* program); +static void opFillWin(Program* program); +static void opFillRect(Program* program); static void opHideMouse(Program* program); static void opShowMouse(Program* program); +static void opMouseShape(Program* program); static void opSetGlobalMouseFunc(Program* Program); +static void opDisplayGfx(Program* program); static void opLoadPaletteTable(Program* program); static void opAddNamedEvent(Program* program); static void opAddNamedHandler(Program* program); @@ -50,23 +86,28 @@ static void opClearNamed(Program* program); static void opSignalNamed(Program* program); static void opAddKey(Program* program); static void opDeleteKey(Program* program); +static void opRefreshMouse(Program* program); static void opSetFont(Program* program); static void opSetTextFlags(Program* program); static void opSetTextColor(Program* program); static void opSayOptionColor(Program* program); static void opSayReplyColor(Program* program); static void opSetHighlightColor(Program* program); +static void opSayReplyWindow(Program* program); static void opSayReplyFlags(Program* program); static void opSayOptionFlags(Program* program); +static void opSayOptionWindow(Program* program); static void opSayBorder(Program* program); +static void opSayScrollUp(Program* program); +static void opSayScrollDown(Program* program); static void opSaySetSpacing(Program* program); static void opSayRestart(Program* program); -static void interpreterSoundCallback(void* userData, int a2); -static int interpreterSoundDelete(int a1); -static int interpreterSoundPlay(char* fileName, int mode); -static int interpreterSoundPause(int value); -static int interpreterSoundRewind(int value); -static int interpreterSoundResume(int value); +static void intLibSoundCallback(void* userData, int a2); +static int intLibSoundDelete(int value); +static int intLibSoundPlay(char* fileName, int mode); +static int intLibSoundPause(int value); +static int intLibSoundRewind(int value); +static int intLibSoundResume(int value); static void opSoundPlay(Program* program); static void opSoundPause(Program* program); static void opSoundResume(Program* program); @@ -74,30 +115,69 @@ static void opSoundStop(Program* program); static void opSoundRewind(Program* program); static void opSoundDelete(Program* program); static void opSetOneOptPause(Program* program); -static bool _intLibDoInput(int key); +static bool intLibDoInput(int key); // 0x59D5D0 -static Sound* gInterpreterSounds[INTERPRETER_SOUNDS_LENGTH]; +static Sound* gIntLibSounds[INT_LIB_SOUNDS_CAPACITY]; + +// 0x59D650 +static unsigned char gIntLibFadePalette[256 * 3]; // 0x59D950 -static InterpreterKeyHandlerEntry gInterpreterKeyHandlerEntries[INTERPRETER_KEY_HANDLER_ENTRIES_LENGTH]; +static IntLibKeyHandlerEntry gIntLibKeyHandlerEntries[INT_LIB_KEY_HANDLERS_CAPACITY]; + +// 0x59E150 +static bool gIntLibIsPaletteFaded; // 0x59E154 -static int gIntepreterAnyKeyHandlerProc; +static int gIntLibGenericKeyHandlerProc; -// Number of entries in _callbacks. -// // 0x59E158 -static int _numCallbacks; +static int gIntLibProgramDeleteCallbacksLength; // 0x59E15C -static Program* gInterpreterAnyKeyHandlerProgram; +static Program* gIntLibGenericKeyHandlerProgram; // 0x59E160 -static OFF_59E160* _callbacks; +static IntLibProgramDeleteCallback** gIntLibProgramDeleteCallbacks; // 0x59E164 -static int _sayStartingPosition; +static int gIntLibSayStartingPosition; + +// 0x59E168 +static char gIntLibPlayMovieFileName[100]; + +// 0x59E1CC +static char gIntLibPlayMovieRectFileName[100]; + +// fillwin3x3 +// 0x461780 +void opFillWin3x3(Program* program) +{ + char* fileName = programStackPopString(program); + char* mangledFileName = _interpretMangleName(fileName); + + int imageWidth; + int imageHeight; + unsigned char* imageData = datafileRead(mangledFileName, &imageWidth, &imageHeight); + if (imageData == NULL) { + programFatalError("cannot load 3x3 file '%s'", mangledFileName); + } + + _selectWindowID(program->windowId); + + int windowHeight = _windowHeight(); + int windowWidth = _windowWidth(); + unsigned char* windowBuffer = _windowGetBuffer(); + _fillBuf3x3(imageData, + imageWidth, + imageHeight, + windowBuffer, + windowWidth, + windowHeight); + + internal_free_safe(imageData, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 94 +} // format // 0x461850 @@ -119,11 +199,11 @@ static void opFormat(Program* program) // 0x461A5C static void opPrint(Program* program) { - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); ProgramValue value = programStackPopValue(program); - switch (value.opcode & 0xF7FF) { + switch (value.opcode & VALUE_TYPE_MASK) { case VALUE_TYPE_STRING: _interpretOutput("%s", programGetString(program, value.opcode, value.integerValue)); break; @@ -136,11 +216,112 @@ static void opPrint(Program* program) } } +// selectfilelist +// 0x461B10 +void opSelectFileList(Program* program) +{ + program->flags |= PROGRAM_FLAG_0x20; + + char* pattern = programStackPopString(program); + char* title = programStackPopString(program); + + int fileListLength; + char** fileList = _getFileList(_interpretMangleName(pattern), &fileListLength); + if (fileList != NULL && fileListLength != 0) { + int selectedIndex = _win_list_select(title, + fileList, + fileListLength, + NULL, + 320 - fontGetStringWidth(title) / 2, + 200, + _colorTable[0x7FFF] | 0x10000); + + if (selectedIndex != -1) { + programStackPushString(program, fileList[selectedIndex]); + } else { + programStackPushInteger(program, 0); + } + + _freeFileList(fileList); + } else { + programStackPushInteger(program, 0); + } + + program->flags &= ~PROGRAM_FLAG_0x20; +} + +// tokenize +// 0x461CA0 +void opTokenize(Program* program) +{ + int ch = programStackPopInteger(program); + + ProgramValue prevValue = programStackPopValue(program); + + char* prev = NULL; + if ((prevValue.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (prevValue.integerValue != 0) { + programFatalError("Error, invalid arg 2 to tokenize. (only accept 0 for int value)"); + } + } else if ((prevValue.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + prev = programGetString(program, prevValue.opcode, prevValue.integerValue); + } else { + programFatalError("Error, invalid arg 2 to tokenize. (string)"); + } + + char* string = programStackPopString(program); + char* temp = NULL; + + if (prev != NULL) { + char* start = strstr(string, prev); + if (start != NULL) { + start += strlen(prev); + while (*start != ch && *start != '\0') { + start++; + } + } + + if (*start == ch) { + int length = 0; + char* end = start + 1; + while (*end != ch && *end != '\0') { + end++; + length++; + } + + temp = (char*)internal_calloc_safe(1, length + 1, __FILE__, __LINE__); // "..\\int\\INTLIB.C, 230 + strncpy(temp, start, length); + programStackPushString(program, temp); + } else { + programStackPushInteger(program, 0); + } + } else { + int length = 0; + char* end = string; + while (*end != ch && *end != '\0') { + end++; + length++; + } + + if (string != NULL) { + temp = (char*)internal_calloc_safe(1, length + 1, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 248 + strncpy(temp, string, length); + programStackPushString(program, temp); + } else { + programStackPushInteger(program, 0); + } + } + + if (temp != NULL) { + internal_free_safe(temp, __FILE__, __LINE__); // "..\\int\\INTLIB.C" , 260 + } +} + // printrect // 0x461F1C static void opPrintRect(Program* program) { - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); int v1 = programStackPopInteger(program); if (v1 > 2) { @@ -151,7 +332,7 @@ static void opPrintRect(Program* program) ProgramValue value = programStackPopValue(program); char string[80]; - switch (value.opcode & 0xF7FF) { + switch (value.opcode & VALUE_TYPE_MASK) { case VALUE_TYPE_STRING: sprintf(string, "%s", programGetString(program, value.opcode, value.integerValue)); break; @@ -168,6 +349,98 @@ static void opPrintRect(Program* program) } } +// 0x46209C +void opSelect(Program* program) +{ + const char* windowName = programStackPopString(program); + int win = _pushWindow(windowName); + if (win == -1) { + programFatalError("Error selecing window %s\n", windowName); + } + + program->windowId = win; + + _interpretOutputFunc(_windowOutput); +} + +// display +// 0x46213C +void opDisplay(Program* program) +{ + char* fileName = programStackPopString(program); + + _selectWindowID(program->windowId); + + char* mangledFileName = _interpretMangleName(fileName); + _displayFile(mangledFileName); +} + +// displayraw +// 0x4621B4 +void opDisplayRaw(Program* program) +{ + char* fileName = programStackPopString(program); + + _selectWindowID(program->windowId); + + char* mangledFileName = _interpretMangleName(fileName); + _displayFileRaw(mangledFileName); +} + +// 0x46222C +void sub_46222C(unsigned char* a1, unsigned char* a2, int a3, float a4, int a5) +{ + // TODO: Incomplete. +} + +// fadein +// 0x462400 +void opFadeIn(Program* program) +{ + int data = programStackPopInteger(program); + + program->flags |= PROGRAM_FLAG_0x20; + + _setSystemPalette(gIntLibFadePalette); + + sub_46222C(gIntLibFadePalette, _cmap, 64, (float)data, 1); + gIntLibIsPaletteFaded = true; + + program->flags &= ~PROGRAM_FLAG_0x20; +} + +// fadeout +// 0x4624B4 +void opFadeOut(Program* program) +{ + int data = programStackPopInteger(program); + + program->flags |= PROGRAM_FLAG_0x20; + + bool cursorWasHidden = cursorIsHidden(); + mouseHideCursor(); + + sub_46222C(_getSystemPalette(), gIntLibFadePalette, 64, (float)data, 1); + + if (!cursorWasHidden) { + mouseShowCursor(); + } + + gIntLibIsPaletteFaded = false; + + program->flags &= ~PROGRAM_FLAG_0x20; +} + +// 0x462570 +int intLibCheckMovie(Program* program) +{ + if (_dialogGetDialogDepth() > 0) { + return 1; + } + + return _windowMoviePlaying(); +} + // movieflags // 0x462584 static void opSetMovieFlags(Program* program) @@ -179,6 +452,56 @@ static void opSetMovieFlags(Program* program) } } +// playmovie +// 0x4625D0 +void opPlayMovie(Program* program) +{ + char* movieFileName = programStackPopString(program); + + strcpy(gIntLibPlayMovieFileName, movieFileName); + + if (strrchr(gIntLibPlayMovieFileName, '.') == NULL) { + strcat(gIntLibPlayMovieFileName, ".mve"); + } + + _selectWindowID(program->windowId); + + program->flags |= PROGRAM_FLAG_0x10; + program->field_7C = intLibCheckMovie; + + char* mangledFileName = _interpretMangleName(gIntLibPlayMovieFileName); + if (!_windowPlayMovie(mangledFileName)) { + programFatalError("Error playing movie"); + } +} + +// playmovierect +// 0x4626C4 +void opPlayMovieRect(Program* program) +{ + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + char* movieFileName = programStackPopString(program); + + strcpy(gIntLibPlayMovieRectFileName, movieFileName); + + if (strrchr(gIntLibPlayMovieRectFileName, '.') == NULL) { + strcat(gIntLibPlayMovieRectFileName, ".mve"); + } + + _selectWindowID(program->windowId); + + program->field_7C = intLibCheckMovie; + program->flags |= PROGRAM_FLAG_0x10; + + char* mangledFileName = _interpretMangleName(gIntLibPlayMovieRectFileName); + if (!_windowPlayMovieRect(mangledFileName, x, y, width, height)) { + programFatalError("Error playing movie"); + } +} + // stopmovie // 0x46287C static void opStopMovie(Program* program) @@ -205,12 +528,22 @@ static void opDeleteRegion(Program* program) programFatalError("Invalid type given to deleteregion"); } - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); const char* regionName = value.integerValue != -1 ? programGetString(program, value.opcode, value.integerValue) : NULL; _windowDeleteRegion(regionName); } +// activateregion +// 0x462924 +void opActivateRegion(Program* program) +{ + int v1 = programStackPopInteger(program); + char* regionName = programStackPopString(program); + + _windowActivateRegion(regionName, v1); +} + // checkregion // 0x4629A0 static void opCheckRegion(Program* program) @@ -221,6 +554,41 @@ static void opCheckRegion(Program* program) programStackPushInteger(program, regionExists); } +// addregion +// 0x462A1C +void opAddRegion(Program* program) +{ + int args = programStackPopInteger(program); + + if (args < 2) { + programFatalError("addregion call without enough points!"); + } + + _selectWindowID(program->windowId); + + _windowStartRegion(args / 2); + + while (args >= 2) { + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + y = (y * _windowGetYres() + 479) / 480; + x = (x * _windowGetXres() + 639) / 640; + args -= 2; + + _windowAddRegionPoint(x, y, true); + } + + if (args == 0) { + programFatalError("Unnamed regions not allowed\n"); + _windowEndRegion(); + } else { + const char* regionName = programStackPopString(program); + _windowAddRegionName(regionName); + _windowEndRegion(); + } +} + // addregionproc // 0x462C10 static void opAddRegionProc(Program* program) @@ -229,8 +597,9 @@ static void opAddRegionProc(Program* program) int v2 = programStackPopInteger(program); int v3 = programStackPopInteger(program); int v4 = programStackPopInteger(program); - const char* regionName = programStackPopString(program);; - _selectWindowID(program->field_84); + const char* regionName = programStackPopString(program); + + _selectWindowID(program->windowId); if (!_windowAddRegionProc(regionName, program, v4, v3, v2, v1)) { programFatalError("Error setting procedures to region %s\n", regionName); @@ -244,18 +613,91 @@ static void opAddRegionRightProc(Program* program) int v1 = programStackPopInteger(program); int v2 = programStackPopInteger(program); const char* regionName = programStackPopString(program); - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); if (!_windowAddRegionRightProc(regionName, program, v2, v1)) { programFatalError("ErrorError setting right button procedures to region %s\n", regionName); } } +// createwin +// 0x462F08 +void opCreateWin(Program* program) +{ + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + char* windowName = programStackPopString(program); + + x = (x * _windowGetXres() + 639) / 640; + y = (y * _windowGetYres() + 479) / 480; + width = (width * _windowGetXres() + 639) / 640; + height = (height * _windowGetYres() + 479) / 480; + + if (_createWindow(windowName, x, y, width, height, _colorTable[0], 0) == -1) { + programFatalError("Couldn't create window."); + } +} + +// resizewin +// 0x46308C +void opResizeWin(Program* program) +{ + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + char* windowName = programStackPopString(program); + + x = (x * _windowGetXres() + 639) / 640; + y = (y * _windowGetYres() + 479) / 480; + width = (width * _windowGetXres() + 639) / 640; + height = (height * _windowGetYres() + 479) / 480; + + if (sub_4B7AC4(windowName, x, y, width, height) == -1) { + programFatalError("Couldn't resize window."); + } +} + +// scalewin +// 0x463204 +void opScaleWin(Program* program) +{ + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + char* windowName = programStackPopString(program); + + x = (x * _windowGetXres() + 639) / 640; + y = (y * _windowGetYres() + 479) / 480; + width = (width * _windowGetXres() + 639) / 640; + height = (height * _windowGetYres() + 479) / 480; + + if (sub_4B7E7C(windowName, x, y, width, height) == -1) { + programFatalError("Couldn't scale window."); + } +} + +// deletewin +// 0x46337C +void opDeleteWin(Program* program) +{ + char* windowName = programStackPopString(program); + + if (!_deleteWindow(windowName)) { + programFatalError("Error deleting window %s\n", windowName); + } + + program->windowId = _popWindow(); +} + // saystart // 0x4633E4 static void opSayStart(Program* program) { - _sayStartingPosition = 0; + gIntLibSayStartingPosition = 0; program->flags |= PROGRAM_FLAG_0x20; int rc = _dialogStart(program); @@ -270,7 +712,7 @@ static void opSayStart(Program* program) // 0x463430 static void opSayStartPos(Program* program) { - _sayStartingPosition = programStackPopInteger(program); + gIntLibSayStartingPosition = programStackPopInteger(program); program->flags |= PROGRAM_FLAG_0x20; int rc = _dialogStart(program); @@ -288,7 +730,7 @@ static void opSayReplyTitle(Program* program) ProgramValue value = programStackPopValue(program); char* string = NULL; - if ((value.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { string = programGetString(program, value.opcode, value.integerValue); } @@ -304,7 +746,7 @@ static void opSayGoToReply(Program* program) ProgramValue value = programStackPopValue(program); char* string = NULL; - if ((value.opcode & 0xF7FF) == VALUE_TYPE_STRING) { + if ((value.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { string = programGetString(program, value.opcode, value.integerValue); } @@ -313,6 +755,90 @@ static void opSayGoToReply(Program* program) } } +// sayreply +// 0x463584 +void opSayReply(Program* program) +{ + program->flags |= PROGRAM_FLAG_0x20; + + ProgramValue v3 = programStackPopValue(program); + ProgramValue v2 = programStackPopValue(program); + + const char* v1; + if ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v2.opcode, v2.integerValue); + } else { + v1 = NULL; + } + + if ((v3.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + const char* v2 = programGetString(program, v3.opcode, v3.integerValue); + if (_dialogOption(v1, v2) != 0) { + program->flags &= ~PROGRAM_FLAG_0x20; + programFatalError("Error setting option."); + } + } else if ((v3.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (_dialogOptionProc(v1, v3.integerValue) != 0) { + program->flags &= ~PROGRAM_FLAG_0x20; + programFatalError("Error setting option."); + } + } else { + programFatalError("Invalid arg 2 to sayOption"); + } + + program->flags &= ~PROGRAM_FLAG_0x20; +} + +// sayoption +void opSayOption(Program* program) +{ + program->flags |= PROGRAM_FLAG_0x20; + + ProgramValue v3 = programStackPopValue(program); + ProgramValue v4 = programStackPopValue(program); + + const char* v1; + if ((v4.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v4.opcode, v4.integerValue); + } else { + v1 = NULL; + } + + const char* v2; + if ((v3.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v2 = programGetString(program, v3.opcode, v3.integerValue); + } else { + v2 = NULL; + } + + if (_dialogReply(v1, v2) != 0) { + program->flags &= ~PROGRAM_FLAG_0x20; + programFatalError("Error setting option."); + } + + program->flags &= ~PROGRAM_FLAG_0x20; +} + +// 0x46378C +int intLibCheckDialog(Program* program) +{ + program->flags |= PROGRAM_FLAG_0x40; + return _dialogGetDialogDepth() != -1; +} + +// 0x4637A4 +void opSayEnd(Program* program) +{ + program->flags |= PROGRAM_FLAG_0x20; + int rc = sub_431088(gIntLibSayStartingPosition); + program->flags &= ~PROGRAM_FLAG_0x20; + + if (rc == -2) { + program->field_7C = intLibCheckDialog; + program->flags |= PROGRAM_FLAG_0x10; + } +} + // saygetlastpos // 0x4637EC static void opSayGetLastPos(Program* program) @@ -337,13 +863,56 @@ static void opSayMessageTimeout(Program* program) ProgramValue value = programStackPopValue(program); // TODO: What the hell is this? - if ((value.opcode & 0xF7FF) == 0x4000) { + if ((value.opcode & VALUE_TYPE_MASK) == 0x4000) { programFatalError("sayMsgTimeout: invalid var type passed."); } _TimeOut = value.integerValue; } +// saymessage +// 0x463890 +void opSayMessage(Program* program) +{ + program->flags |= PROGRAM_FLAG_0x20; + + ProgramValue v3 = programStackPopValue(program); + ProgramValue v4 = programStackPopValue(program); + + const char* v1; + if ((v4.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v4.opcode, v4.integerValue); + } else { + v1 = NULL; + } + + const char* v2; + if ((v3.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v2 = programGetString(program, v3.opcode, v3.integerValue); + } else { + v2 = NULL; + } + + if (sub_430FD4(v1, v2, _TimeOut) != 0) { + program->flags &= ~PROGRAM_FLAG_0x20; + programFatalError("Error setting option."); + } + + program->flags &= ~PROGRAM_FLAG_0x20; +} + +// gotoxy +// 0x463980 +void opGotoXY(Program* program) +{ + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + _selectWindowID(program->windowId); + + _windowGotoXY(x, y); +} + // addbuttonflag // 0x463A38 static void opAddButtonFlag(Program* program) @@ -370,6 +939,64 @@ static void opAddRegionFlag(Program* program) } } +// addbutton +// 0x463BE8 +void opAddButton(Program* program) +{ + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + char* buttonName = programStackPopString(program); + + _selectWindowID(program->windowId); + + height = (height * _windowGetYres() + 479) / 480; + width = (width * _windowGetXres() + 639) / 640; + y = (y * _windowGetYres() + 479) / 480; + x = (x * _windowGetXres() + 639) / 640; + + _windowAddButton(buttonName, x, y, width, height, 0); +} + +// addbuttontext +// 0x463DF4 +void opAddButtonText(Program* program) +{ + const char* text = programStackPopString(program); + const char* buttonName = programStackPopString(program); + + if (!_windowAddButtonText(buttonName, text)) { + programFatalError("Error setting text to button %s\n", buttonName); + } +} + +// addbuttongfx +// 0x463EEC +void opAddButtonGfx(Program* program) +{ + ProgramValue v1 = programStackPopValue(program); + ProgramValue v2 = programStackPopValue(program); + ProgramValue v3 = programStackPopValue(program); + char* buttonName = programStackPopString(program); + + if (((v3.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING || ((v3.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v3.integerValue == 0)) + || ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING || ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v2.integerValue == 0)) + || ((v1.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING || ((v1.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v1.integerValue == 0))) { + char* pressedFileName = _interpretMangleName(programGetString(program, v3.opcode, v3.integerValue)); + char* normalFileName = _interpretMangleName(programGetString(program, v2.opcode, v2.integerValue)); + char* hoverFileName = _interpretMangleName(programGetString(program, v1.opcode, v1.integerValue)); + + _selectWindowID(program->windowId); + + if (!_windowAddButtonGfx(buttonName, pressedFileName, normalFileName, hoverFileName)) { + programFatalError("Error setting graphics to button %s\n", buttonName); + } + } else { + programFatalError("Invalid filename given to addbuttongfx"); + } +} + // addbuttonproc // 0x4640DC static void opAddButtonProc(Program* program) @@ -379,7 +1006,7 @@ static void opAddButtonProc(Program* program) int v3 = programStackPopInteger(program); int v4 = programStackPopInteger(program); const char* buttonName = programStackPopString(program); - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); if (!_windowAddButtonProc(buttonName, program, v4, v3, v2, v1)) { programFatalError("Error setting procedures to button %s\n", buttonName); @@ -393,7 +1020,7 @@ static void opAddButtonRightProc(Program* program) int v1 = programStackPopInteger(program); int v2 = programStackPopInteger(program); const char* regionName = programStackPopString(program); - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); if (!_windowAddRegionRightProc(regionName, program, v2, v1)) { programFatalError("Error setting right button procedures to button %s\n", regionName); @@ -404,7 +1031,7 @@ static void opAddButtonRightProc(Program* program) // 0x4643D4 static void opShowWin(Program* program) { - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); _windowDraw(); } @@ -414,7 +1041,7 @@ static void opDeleteButton(Program* program) { ProgramValue value = programStackPopValue(program); - switch (value.opcode & 0xF7FF) { + switch (value.opcode & VALUE_TYPE_MASK) { case VALUE_TYPE_STRING: break; case VALUE_TYPE_INT: @@ -426,7 +1053,7 @@ static void opDeleteButton(Program* program) programFatalError("Invalid type given to delete button"); } - _selectWindowID(program->field_84); + _selectWindowID(program->windowId); if ((value.opcode & 0xF7FF) == VALUE_TYPE_INT) { if (_windowDeleteButton(NULL)) { @@ -438,10 +1065,100 @@ static void opDeleteButton(Program* program) return; } } - + programFatalError("Error deleting button"); } +// fillwin +// 0x46449C +void opFillWin(Program* program) +{ + ProgramValue b = programStackPopValue(program); + ProgramValue g = programStackPopValue(program); + ProgramValue r = programStackPopValue(program); + + if ((r.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT) { + if ((r.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (r.integerValue == 1) { + r.floatValue = 1.0; + } else if (r.integerValue != 0) { + programFatalError("Invalid red value given to fillwin"); + } + } + } + + if ((g.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT) { + if ((g.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (g.integerValue == 1) { + g.floatValue = 1.0; + } else if (g.integerValue != 0) { + programFatalError("Invalid green value given to fillwin"); + } + } + } + + if ((b.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT) { + if ((b.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (b.integerValue == 1) { + b.floatValue = 1.0; + } else if (b.integerValue != 0) { + programFatalError("Invalid blue value given to fillwin"); + } + } + } + + _selectWindowID(program->windowId); + + _windowFill(r.floatValue, g.floatValue, b.floatValue); +} + +// fillrect +// 0x4645FC +void opFillRect(Program* program) +{ + ProgramValue b = programStackPopValue(program); + ProgramValue g = programStackPopValue(program); + ProgramValue r = programStackPopValue(program); + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + if ((r.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT) { + if ((r.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (r.integerValue == 1) { + r.floatValue = 1.0; + } else if (r.integerValue != 0) { + programFatalError("Invalid red value given to fillwin"); + } + } + } + + if ((g.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT) { + if ((g.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (g.integerValue == 1) { + g.floatValue = 1.0; + } else if (g.integerValue != 0) { + programFatalError("Invalid green value given to fillwin"); + } + } + } + + if ((b.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT) { + if ((b.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (b.integerValue == 1) { + b.floatValue = 1.0; + } else if (b.integerValue != 0) { + programFatalError("Invalid blue value given to fillwin"); + } + } + } + + _selectWindowID(program->windowId); + + _windowFillRect(x, y, width, height, r.floatValue, g.floatValue, b.floatValue); +} + // hidemouse // 0x46489C static void opHideMouse(Program* program) @@ -456,6 +1173,19 @@ static void opShowMouse(Program* program) mouseShowCursor(); } +// mouseshape +// 0x4648AC +void opMouseShape(Program* program) +{ + int v1 = programStackPopInteger(program); + int v2 = programStackPopInteger(program); + char* fileName = programStackPopString(program); + + if (!mouseManagerSetMouseShape(fileName, v2, v1)) { + programFatalError("Error loading mouse shape."); + } +} + // setglobalmousefunc // 0x4649C4 static void opSetGlobalMouseFunc(Program* Program) @@ -463,6 +1193,20 @@ static void opSetGlobalMouseFunc(Program* Program) programFatalError("setglobalmousefunc not defined"); } +// displaygfx +// 0x4649D4 +void opDisplayGfx(Program* program) +{ + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + char* fileName = programStackPopString(program); + + char* mangledFileName = _interpretMangleName(fileName); + _windowDisplay(mangledFileName, x, y, width, height); +} + // loadpalettetable // 0x464ADC static void opLoadPaletteTable(Program* program) @@ -515,15 +1259,15 @@ static void opAddKey(Program* program) int key = programStackPopInteger(program); if (key == -1) { - gIntepreterAnyKeyHandlerProc = proc; - gInterpreterAnyKeyHandlerProgram = program; + gIntLibGenericKeyHandlerProc = proc; + gIntLibGenericKeyHandlerProgram = program; } else { - if (key > INTERPRETER_KEY_HANDLER_ENTRIES_LENGTH - 1) { + if (key > INT_LIB_KEY_HANDLERS_CAPACITY - 1) { programFatalError("Key out of range"); } - gInterpreterKeyHandlerEntries[key].program = program; - gInterpreterKeyHandlerEntries[key].proc = proc; + gIntLibKeyHandlerEntries[key].program = program; + gIntLibKeyHandlerEntries[key].proc = proc; } } @@ -534,15 +1278,26 @@ static void opDeleteKey(Program* program) int key = programStackPopInteger(program); if (key == -1) { - gIntepreterAnyKeyHandlerProc = 0; - gInterpreterAnyKeyHandlerProgram = NULL; + gIntLibGenericKeyHandlerProc = 0; + gIntLibGenericKeyHandlerProgram = NULL; } else { - if (key > INTERPRETER_KEY_HANDLER_ENTRIES_LENGTH - 1) { + if (key > INT_LIB_KEY_HANDLERS_CAPACITY - 1) { programFatalError("Key out of range"); } - gInterpreterKeyHandlerEntries[key].program = NULL; - gInterpreterKeyHandlerEntries[key].proc = 0; + gIntLibKeyHandlerEntries[key].program = NULL; + gIntLibKeyHandlerEntries[key].proc = 0; + } +} + +// refreshmouse +// 0x464EB0 +void opRefreshMouse(Program* program) +{ + int data = programStackPopInteger(program); + + if (!_windowRefreshRegions()) { + _executeProc(program, data); } } @@ -580,7 +1335,7 @@ static void opSetTextColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & 0xF7FF) != VALUE_TYPE_FLOAT && (value[arg].opcode & 0xF7FF) != VALUE_TYPE_INT) + if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) || value[arg].floatValue == 0.0) { programFatalError("Invalid type given to settextcolor"); } @@ -607,7 +1362,7 @@ static void opSayOptionColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & 0xF7FF) != VALUE_TYPE_FLOAT && (value[arg].opcode & 0xF7FF) != VALUE_TYPE_INT) + if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) || value[arg].floatValue == 0.0) { programFatalError("Invalid type given to sayoptioncolor"); } @@ -634,7 +1389,7 @@ static void opSayReplyColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & 0xF7FF) != VALUE_TYPE_FLOAT && (value[arg].opcode & 0xF7FF) != VALUE_TYPE_INT) + if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) || value[arg].floatValue == 0.0) { programFatalError("Invalid type given to sayreplycolor"); } @@ -661,7 +1416,7 @@ static void opSetHighlightColor(Program* program) } for (int arg = 0; arg < 3; arg++) { - if (((value[arg].opcode & 0xF7FF) != VALUE_TYPE_FLOAT && (value[arg].opcode & 0xF7FF) != VALUE_TYPE_INT) + if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT) || value[arg].floatValue == 0.0) { programFatalError("Invalid type given to sayreplycolor"); } @@ -676,6 +1431,32 @@ static void opSetHighlightColor(Program* program) } } +// sayreplywindow +// 0x465530 +void opSayReplyWindow(Program* program) +{ + ProgramValue v2 = programStackPopValue(program); + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + char* v1; + if ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v2.opcode, v2.integerValue); + v1 = _interpretMangleName(v1); + v1 = strdup_safe(v1, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1510 + } else if ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v2.integerValue == 0) { + v1 = NULL; + } else { + programFatalError("Invalid arg 5 given to sayreplywindow"); + } + + if (dialogSetReplyWindow(x, y, width, height, v1) != 0) { + programFatalError("Error setting reply window"); + } +} + // sayreplyflags // 0x465688 static void opSayReplyFlags(Program* program) @@ -698,6 +1479,32 @@ static void opSayOptionFlags(Program* program) } } +// sayoptionwindow +// 0x465760 +void opSayOptionWindow(Program* program) +{ + ProgramValue v2 = programStackPopValue(program); + int height = programStackPopInteger(program); + int width = programStackPopInteger(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + char* v1; + if ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v2.opcode, v2.integerValue); + v1 = _interpretMangleName(v1); + v1 = strdup_safe(v1, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1556 + } else if ((v2.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v2.integerValue == 0) { + v1 = NULL; + } else { + programFatalError("Invalid arg 5 given to sayoptionwindow"); + } + + if (dialogSetOptionWindow(x, y, width, height, v1) != 0) { + programFatalError("Error setting option window"); + } +} + // sayborder // 0x4658B8 static void opSayBorder(Program* program) @@ -710,6 +1517,152 @@ static void opSayBorder(Program* program) } } +// sayscrollup +// 0x465978 +void opSayScrollUp(Program* program) +{ + ProgramValue v6 = programStackPopValue(program); + ProgramValue v7 = programStackPopValue(program); + ProgramValue v8 = programStackPopValue(program); + ProgramValue v9 = programStackPopValue(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + char* v1 = NULL; + char* v2 = NULL; + char* v3 = NULL; + char* v4 = NULL; + int v5 = 0; + + if ((v6.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (v6.integerValue != -1 && v6.integerValue != 0) { + programFatalError("Invalid arg 4 given to sayscrollup"); + } + + if (v6.integerValue == -1) { + v5 = 1; + } + } else { + if ((v6.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING) { + programFatalError("Invalid arg 4 given to sayscrollup"); + } + } + + if ((v7.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING && (v7.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v7.integerValue != 0) { + programFatalError("Invalid arg 3 given to sayscrollup"); + } + + if ((v8.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING && (v8.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v8.integerValue != 0) { + programFatalError("Invalid arg 2 given to sayscrollup"); + } + + if ((v9.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING && (v9.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v9.integerValue != 0) { + programFatalError("Invalid arg 1 given to sayscrollup"); + } + + if ((v9.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v9.opcode, v9.integerValue); + v1 = _interpretMangleName(v1); + v1 = strdup_safe(v1, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1611 + } + + if ((v8.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v2 = programGetString(program, v8.opcode, v8.integerValue); + v2 = _interpretMangleName(v2); + v2 = strdup_safe(v2, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1613 + } + + if ((v7.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v3 = programGetString(program, v7.opcode, v7.integerValue); + v3 = _interpretMangleName(v3); + v3 = strdup_safe(v3, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1615 + } + + if ((v6.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v4 = programGetString(program, v6.opcode, v6.integerValue); + v4 = _interpretMangleName(v4); + v4 = strdup_safe(v4, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1617 + } + + if (_dialogSetScrollUp(x, y, v1, v2, v3, v4, v5) != 0) { + programFatalError("Error setting scroll up"); + } +} + +// sayscrolldown +// 0x465CAC +void opSayScrollDown(Program* program) +{ + ProgramValue v6 = programStackPopValue(program); + ProgramValue v7 = programStackPopValue(program); + ProgramValue v8 = programStackPopValue(program); + ProgramValue v9 = programStackPopValue(program); + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + + char* v1 = NULL; + char* v2 = NULL; + char* v3 = NULL; + char* v4 = NULL; + int v5 = 0; + + if ((v6.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT) { + if (v6.integerValue != -1 && v6.integerValue != 0) { + // FIXME: Wrong function name, should be sayscrolldown. + programFatalError("Invalid arg 4 given to sayscrollup"); + } + + if (v6.integerValue == -1) { + v5 = 1; + } + } else { + if ((v6.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING) { + // FIXME: Wrong function name, should be sayscrolldown. + programFatalError("Invalid arg 4 given to sayscrollup"); + } + } + + if ((v7.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING && (v7.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v7.integerValue != 0) { + programFatalError("Invalid arg 3 given to sayscrolldown"); + } + + if ((v8.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING && (v8.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v8.integerValue != 0) { + programFatalError("Invalid arg 2 given to sayscrolldown"); + } + + if ((v9.opcode & VALUE_TYPE_MASK) != VALUE_TYPE_STRING && (v9.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT && v9.integerValue != 0) { + programFatalError("Invalid arg 1 given to sayscrolldown"); + } + + if ((v9.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v1 = programGetString(program, v9.opcode, v9.integerValue); + v1 = _interpretMangleName(v1); + v1 = strdup_safe(v1, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1652 + } + + if ((v8.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v2 = programGetString(program, v8.opcode, v8.integerValue); + v2 = _interpretMangleName(v2); + v2 = strdup_safe(v2, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1654 + } + + if ((v7.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v3 = programGetString(program, v7.opcode, v7.integerValue); + v3 = _interpretMangleName(v3); + v3 = strdup_safe(v3, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1656 + } + + if ((v6.opcode & VALUE_TYPE_MASK) == VALUE_TYPE_STRING) { + v4 = programGetString(program, v6.opcode, v6.integerValue); + v4 = _interpretMangleName(v4); + v4 = strdup_safe(v4, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1658 + } + + if (_dialogSetScrollDown(x, y, v1, v2, v3, v4, v5) != 0) { + programFatalError("Error setting scroll down"); + } +} + // saysetspacing // 0x465FE0 static void opSaySetSpacing(Program* program) @@ -731,7 +1684,7 @@ static void opSayRestart(Program* program) } // 0x466064 -static void interpreterSoundCallback(void* userData, int a2) +static void intLibSoundCallback(void* userData, int a2) { if (a2 == 1) { Sound** sound = (Sound**)userData; @@ -740,7 +1693,7 @@ static void interpreterSoundCallback(void* userData, int a2) } // 0x466070 -static int interpreterSoundDelete(int value) +static int intLibSoundDelete(int value) { if (value == -1) { return 1; @@ -751,7 +1704,7 @@ static int interpreterSoundDelete(int value) } int index = value & ~0xA0000000; - Sound* sound = gInterpreterSounds[index]; + Sound* sound = gIntLibSounds[index]; if (sound == NULL) { return 0; } @@ -762,13 +1715,13 @@ static int interpreterSoundDelete(int value) soundDelete(sound); - gInterpreterSounds[index] = NULL; + gIntLibSounds[index] = NULL; return 1; } // 0x466110 -static int interpreterSoundPlay(char* fileName, int mode) +static int intLibSoundPlay(char* fileName, int mode) { int v3 = 1; int v5 = 0; @@ -799,22 +1752,22 @@ static int interpreterSoundPlay(char* fileName, int mode) } int index; - for (index = 0; index < INTERPRETER_SOUNDS_LENGTH; index++) { - if (gInterpreterSounds[index] == NULL) { + for (index = 0; index < INT_LIB_SOUNDS_CAPACITY; index++) { + if (gIntLibSounds[index] == NULL) { break; } } - if (index == INTERPRETER_SOUNDS_LENGTH) { + if (index == INT_LIB_SOUNDS_CAPACITY) { return -1; } - Sound* sound = gInterpreterSounds[index] = soundAllocate(v3, v5); + Sound* sound = gIntLibSounds[index] = soundAllocate(v3, v5); if (sound == NULL) { return -1; } - soundSetCallback(sound, interpreterSoundCallback, &(gInterpreterSounds[index])); + soundSetCallback(sound, intLibSoundCallback, &(gIntLibSounds[index])); if (mode & 0x01) { soundSetLooping(sound, 0xFFFF); @@ -885,12 +1838,12 @@ static int interpreterSoundPlay(char* fileName, int mode) err: soundDelete(sound); - gInterpreterSounds[index] = NULL; + gIntLibSounds[index] = NULL; return -1; } // 0x46655C -static int interpreterSoundPause(int value) +static int intLibSoundPause(int value) { if (value == -1) { return 1; @@ -901,7 +1854,7 @@ static int interpreterSoundPause(int value) } int index = value & ~0xA0000000; - Sound* sound = gInterpreterSounds[index]; + Sound* sound = gIntLibSounds[index]; if (sound == NULL) { return 0; } @@ -916,7 +1869,7 @@ static int interpreterSoundPause(int value) } // 0x4665C8 -static int interpreterSoundRewind(int value) +static int intLibSoundRewind(int value) { if (value == -1) { return 1; @@ -927,7 +1880,7 @@ static int interpreterSoundRewind(int value) } int index = value & ~0xA0000000; - Sound* sound = gInterpreterSounds[index]; + Sound* sound = gIntLibSounds[index]; if (sound == NULL) { return 0; } @@ -942,7 +1895,7 @@ static int interpreterSoundRewind(int value) } // 0x46662C -static int interpreterSoundResume(int value) +static int intLibSoundResume(int value) { if (value == -1) { return 1; @@ -953,7 +1906,7 @@ static int interpreterSoundResume(int value) } int index = value & ~0xA0000000; - Sound* sound = gInterpreterSounds[index]; + Sound* sound = gIntLibSounds[index]; if (sound == NULL) { return 0; } @@ -971,7 +1924,13 @@ static int interpreterSoundResume(int value) // 0x466698 static void opSoundPlay(Program* program) { - // TODO: Incomplete. + int flags = programStackPopInteger(program); + char* fileName = programStackPopString(program); + + char* mangledFileName = _interpretMangleName(fileName); + int rc = intLibSoundPlay(mangledFileName, flags); + + programStackPushInteger(program, rc); } // soundpause @@ -979,7 +1938,7 @@ static void opSoundPlay(Program* program) static void opSoundPause(Program* program) { int data = programStackPopInteger(program); - interpreterSoundPause(data); + intLibSoundPause(data); } // soundresume @@ -987,7 +1946,7 @@ static void opSoundPause(Program* program) static void opSoundResume(Program* program) { int data = programStackPopInteger(program); - interpreterSoundResume(data); + intLibSoundResume(data); } // soundstop @@ -995,7 +1954,7 @@ static void opSoundResume(Program* program) static void opSoundStop(Program* program) { int data = programStackPopInteger(program); - interpreterSoundPause(data); + intLibSoundPause(data); } // soundrewind @@ -1003,7 +1962,7 @@ static void opSoundStop(Program* program) static void opSoundRewind(Program* program) { int data = programStackPopInteger(program); - interpreterSoundRewind(data); + intLibSoundRewind(data); } // sounddelete @@ -1011,7 +1970,7 @@ static void opSoundRewind(Program* program) static void opSoundDelete(Program* program) { int data = programStackPopInteger(program); - interpreterSoundDelete(data); + intLibSoundDelete(data); } // SetOneOptPause @@ -1034,48 +1993,48 @@ static void opSetOneOptPause(Program* program) } // 0x466994 -void _updateIntLib() +void intLibUpdate() { _nevs_update(); - _intExtraRemoveProgramReferences_(); + intExtraUpdate(); } // 0x4669A0 -void _intlibClose() +void intLibExit() { _dialogClose(); _intExtraClose_(); - for (int index = 0; index < INTERPRETER_SOUNDS_LENGTH; index++) { - if (gInterpreterSounds[index] != NULL) { - interpreterSoundDelete(index | 0xA0000000); + for (int index = 0; index < INT_LIB_SOUNDS_CAPACITY; index++) { + if (gIntLibSounds[index] != NULL) { + intLibSoundDelete(index | 0xA0000000); } } _nevs_close(); - if (_callbacks != NULL) { - internal_free_safe(_callbacks, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1976 - _callbacks = NULL; - _numCallbacks = 0; + if (gIntLibProgramDeleteCallbacks != NULL) { + internal_free_safe(gIntLibProgramDeleteCallbacks, __FILE__, __LINE__); // "..\\int\\INTLIB.C", 1976 + gIntLibProgramDeleteCallbacks = NULL; + gIntLibProgramDeleteCallbacksLength = 0; } } // 0x466A04 -static bool _intLibDoInput(int key) +static bool intLibDoInput(int key) { - if (key < 0 || key >= INTERPRETER_KEY_HANDLER_ENTRIES_LENGTH) { + if (key < 0 || key >= INT_LIB_KEY_HANDLERS_CAPACITY) { return false; } - if (gInterpreterAnyKeyHandlerProgram != NULL) { - if (gIntepreterAnyKeyHandlerProc != 0) { - _executeProc(gInterpreterAnyKeyHandlerProgram, gIntepreterAnyKeyHandlerProc); + if (gIntLibGenericKeyHandlerProgram != NULL) { + if (gIntLibGenericKeyHandlerProc != 0) { + _executeProc(gIntLibGenericKeyHandlerProgram, gIntLibGenericKeyHandlerProc); } return true; } - InterpreterKeyHandlerEntry* entry = &(gInterpreterKeyHandlerEntries[key]); + IntLibKeyHandlerEntry* entry = &(gIntLibKeyHandlerEntries[key]); if (entry->program == NULL) { return false; } @@ -1088,50 +2047,136 @@ static bool _intLibDoInput(int key) } // 0x466A70 -void _initIntlib() +void intLibInit() { - // TODO: Incomplete. + _windowAddInputFunc(intLibDoInput); + + interpreterRegisterOpcode(0x806A, opFillWin3x3); + interpreterRegisterOpcode(0x808C, opDeleteButton); + interpreterRegisterOpcode(0x8086, opAddButton); + interpreterRegisterOpcode(0x8088, opAddButtonFlag); + interpreterRegisterOpcode(0x8087, opAddButtonText); + interpreterRegisterOpcode(0x8089, opAddButtonGfx); + interpreterRegisterOpcode(0x808A, opAddButtonProc); + interpreterRegisterOpcode(0x808B, opAddButtonRightProc); + interpreterRegisterOpcode(0x8067, opShowWin); + interpreterRegisterOpcode(0x8068, opFillWin); + interpreterRegisterOpcode(0x8069, opFillRect); + interpreterRegisterOpcode(0x8072, opPrint); + interpreterRegisterOpcode(0x8073, opFormat); + interpreterRegisterOpcode(0x8074, opPrintRect); + interpreterRegisterOpcode(0x8075, opSetFont); + interpreterRegisterOpcode(0x8076, opSetTextFlags); + interpreterRegisterOpcode(0x8077, opSetTextColor); + interpreterRegisterOpcode(0x8078, opSetHighlightColor); + interpreterRegisterOpcode(0x8064, opSelect); + interpreterRegisterOpcode(0x806B, opDisplay); + interpreterRegisterOpcode(0x806D, opDisplayRaw); + interpreterRegisterOpcode(0x806C, opDisplayGfx); + interpreterRegisterOpcode(0x806F, opFadeIn); + interpreterRegisterOpcode(0x8070, opFadeOut); + interpreterRegisterOpcode(0x807A, opPlayMovie); + interpreterRegisterOpcode(0x807B, opSetMovieFlags); + interpreterRegisterOpcode(0x807C, opPlayMovieRect); + interpreterRegisterOpcode(0x8079, opStopMovie); + interpreterRegisterOpcode(0x807F, opAddRegion); + interpreterRegisterOpcode(0x8080, opAddRegionFlag); + interpreterRegisterOpcode(0x8081, opAddRegionProc); + interpreterRegisterOpcode(0x8082, opAddRegionRightProc); + interpreterRegisterOpcode(0x8083, opDeleteRegion); + interpreterRegisterOpcode(0x8084, opActivateRegion); + interpreterRegisterOpcode(0x8085, opCheckRegion); + interpreterRegisterOpcode(0x8062, opCreateWin); + interpreterRegisterOpcode(0x8063, opDeleteWin); + interpreterRegisterOpcode(0x8065, opResizeWin); + interpreterRegisterOpcode(0x8066, opScaleWin); + interpreterRegisterOpcode(0x804E, opSayStart); + interpreterRegisterOpcode(0x804F, opSayStartPos); + interpreterRegisterOpcode(0x8050, opSayReplyTitle); + interpreterRegisterOpcode(0x8051, opSayGoToReply); + interpreterRegisterOpcode(0x8053, opSayReply); + interpreterRegisterOpcode(0x8052, opSayOption); + interpreterRegisterOpcode(0x804D, opSayEnd); + interpreterRegisterOpcode(0x804C, opSayQuit); + interpreterRegisterOpcode(0x8054, opSayMessage); + interpreterRegisterOpcode(0x8055, opSayReplyWindow); + interpreterRegisterOpcode(0x8056, opSayOptionWindow); + interpreterRegisterOpcode(0x805F, opSayReplyFlags); + interpreterRegisterOpcode(0x8060, opSayOptionFlags); + interpreterRegisterOpcode(0x8057, opSayBorder); + interpreterRegisterOpcode(0x8058, opSayScrollUp); + interpreterRegisterOpcode(0x8059, opSayScrollDown); + interpreterRegisterOpcode(0x805A, opSaySetSpacing); + interpreterRegisterOpcode(0x805B, opSayOptionColor); + interpreterRegisterOpcode(0x805C, opSayReplyColor); + interpreterRegisterOpcode(0x805D, opSayRestart); + interpreterRegisterOpcode(0x805E, opSayGetLastPos); + interpreterRegisterOpcode(0x8061, opSayMessageTimeout); + interpreterRegisterOpcode(0x8071, opGotoXY); + interpreterRegisterOpcode(0x808D, opHideMouse); + interpreterRegisterOpcode(0x808E, opShowMouse); + interpreterRegisterOpcode(0x8090, opRefreshMouse); + interpreterRegisterOpcode(0x808F, opMouseShape); + interpreterRegisterOpcode(0x8091, opSetGlobalMouseFunc); + interpreterRegisterOpcode(0x806E, opLoadPaletteTable); + interpreterRegisterOpcode(0x8092, opAddNamedEvent); + interpreterRegisterOpcode(0x8093, opAddNamedHandler); + interpreterRegisterOpcode(0x8094, opClearNamed); + interpreterRegisterOpcode(0x8095, opSignalNamed); + interpreterRegisterOpcode(0x8096, opAddKey); + interpreterRegisterOpcode(0x8097, opDeleteKey); + interpreterRegisterOpcode(0x8098, opSoundPlay); + interpreterRegisterOpcode(0x8099, opSoundPause); + interpreterRegisterOpcode(0x809A, opSoundResume); + interpreterRegisterOpcode(0x809B, opSoundStop); + interpreterRegisterOpcode(0x809C, opSoundRewind); + interpreterRegisterOpcode(0x809D, opSoundDelete); + interpreterRegisterOpcode(0x809E, opSetOneOptPause); + interpreterRegisterOpcode(0x809F, opSelectFileList); + interpreterRegisterOpcode(0x80A0, opTokenize); + _nevs_initonce(); _initIntExtra(); + dialogInit(); } // 0x466F6C -void _interpretRegisterProgramDeleteCallback(OFF_59E160 fn) +void intLibRegisterProgramDeleteCallback(IntLibProgramDeleteCallback* callback) { int index; - for (index = 0; index < _numCallbacks; index++) { - if (_callbacks[index] == NULL) { + for (index = 0; index < gIntLibProgramDeleteCallbacksLength; index++) { + if (gIntLibProgramDeleteCallbacks[index] == NULL) { break; } } - if (index == _numCallbacks) { - if (_callbacks != NULL) { - _callbacks = (OFF_59E160*)internal_realloc_safe(_callbacks, sizeof(*_callbacks) * (_numCallbacks + 1), __FILE__, __LINE__); // ..\\int\\INTLIB.C, 2110 + if (index == gIntLibProgramDeleteCallbacksLength) { + if (gIntLibProgramDeleteCallbacks != NULL) { + gIntLibProgramDeleteCallbacks = (IntLibProgramDeleteCallback**)internal_realloc_safe(gIntLibProgramDeleteCallbacks, sizeof(*gIntLibProgramDeleteCallbacks) * (gIntLibProgramDeleteCallbacksLength + 1), __FILE__, __LINE__); // ..\\int\\INTLIB.C, 2110 } else { - _callbacks = (OFF_59E160*)internal_malloc_safe(sizeof(*_callbacks), __FILE__, __LINE__); // ..\\int\\INTLIB.C, 2112 + gIntLibProgramDeleteCallbacks = (IntLibProgramDeleteCallback**)internal_malloc_safe(sizeof(*gIntLibProgramDeleteCallbacks), __FILE__, __LINE__); // ..\\int\\INTLIB.C, 2112 } - _numCallbacks++; + gIntLibProgramDeleteCallbacksLength++; } - _callbacks[index] = fn; + gIntLibProgramDeleteCallbacks[index] = callback; } // 0x467040 -void _removeProgramReferences_(Program* program) +void intLibRemoveProgramReferences(Program* program) { - for (int index = 0; index < INTERPRETER_KEY_HANDLER_ENTRIES_LENGTH; index++) { - if (program == gInterpreterKeyHandlerEntries[index].program) { - gInterpreterKeyHandlerEntries[index].program = NULL; + for (int index = 0; index < INT_LIB_KEY_HANDLERS_CAPACITY; index++) { + if (program == gIntLibKeyHandlerEntries[index].program) { + gIntLibKeyHandlerEntries[index].program = NULL; } } - _intExtraRemoveProgramReferences_(); + intExtraRemoveProgramReferences(program); - for (int index = 0; index < _numCallbacks; index++) { - OFF_59E160 fn = _callbacks[index]; - if (fn != NULL) { - fn(program); + for (int index = 0; index < gIntLibProgramDeleteCallbacksLength; index++) { + IntLibProgramDeleteCallback* callback = gIntLibProgramDeleteCallbacks[index]; + if (callback != NULL) { + callback(program); } } } diff --git a/src/interpreter_lib.h b/src/interpreter_lib.h index 2d840e3..2b22e8d 100644 --- a/src/interpreter_lib.h +++ b/src/interpreter_lib.h @@ -3,12 +3,12 @@ #include "interpreter.h" -typedef void (*OFF_59E160)(Program*); +typedef void(IntLibProgramDeleteCallback)(Program*); -void _updateIntLib(); -void _intlibClose(); -void _initIntlib(); -void _interpretRegisterProgramDeleteCallback(OFF_59E160 fn); -void _removeProgramReferences_(Program* program); +void intLibUpdate(); +void intLibExit(); +void intLibInit(); +void intLibRegisterProgramDeleteCallback(IntLibProgramDeleteCallback* callback); +void intLibRemoveProgramReferences(Program* program); #endif /* INTERPRETER_LIB_H */ diff --git a/src/inventory.cc b/src/inventory.cc index fbbaa95..74c5b04 100644 --- a/src/inventory.cc +++ b/src/inventory.cc @@ -675,7 +675,7 @@ static bool _setup_inventory(int inventoryWindowType) gInventoryWindowMaxY = windowDescription->height + inventoryWindowY; unsigned char* dest = windowGetBuffer(gInventoryWindow); - int backgroundFid = buildFid(6, windowDescription->field_0, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, windowDescription->field_0, 0, 0, 0); CacheEntry* backgroundFrmHandle; unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); @@ -821,10 +821,10 @@ static bool _setup_inventory(int inventoryWindowType) unsigned char* buttonDownData; unsigned char* buttonDisabledData; - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[0])); - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[1])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -853,13 +853,13 @@ static bool _setup_inventory(int inventoryWindowType) // TODO: Figure out why it building fid in chain. // Large arrow up (normal). - fid = buildFid(6, 100, 0, 0, 0); - fid = buildFid(6, fid, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 100, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, fid, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[2])); // Large arrow up (pressed). - fid = buildFid(6, 101, 0, 0, 0); - fid = buildFid(6, fid, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 101, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, fid, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[3])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -877,15 +877,15 @@ static bool _setup_inventory(int inventoryWindowType) } } else { // Large up arrow (normal). - fid = buildFid(6, 49, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 49, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[2])); // Large up arrow (pressed). - fid = buildFid(6, 50, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 50, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[3])); // Large up arrow (disabled). - fid = buildFid(6, 53, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 53, 0, 0, 0); buttonDisabledData = artLockFrameData(fid, 0, 0, &(_ikey[4])); if (buttonUpData != NULL && buttonDownData != NULL && buttonDisabledData != NULL) { @@ -913,13 +913,13 @@ static bool _setup_inventory(int inventoryWindowType) if (inventoryWindowType == INVENTORY_WINDOW_TYPE_TRADE) { // Large dialog down button (normal) - fid = buildFid(6, 93, 0, 0, 0); - fid = buildFid(6, fid, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 93, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, fid, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[5])); // Dialog down button (pressed) - fid = buildFid(6, 94, 0, 0, 0); - fid = buildFid(6, fid, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 94, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, fid, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[6])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -943,15 +943,15 @@ static bool _setup_inventory(int inventoryWindowType) } } else { // Large arrow down (normal). - fid = buildFid(6, 51, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 51, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[5])); // Large arrow down (pressed). - fid = buildFid(6, 52, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 52, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[6])); // Large arrow down (disabled). - fid = buildFid(6, 54, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 54, 0, 0, 0); buttonDisabledData = artLockFrameData(fid, 0, 0, &(_ikey[7])); if (buttonUpData != NULL && buttonDownData != NULL && buttonDisabledData != NULL) { @@ -986,11 +986,11 @@ static bool _setup_inventory(int inventoryWindowType) if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT) { if (!_gIsSteal) { // Take all button (normal) - fid = buildFid(6, 436, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 436, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[8])); // Take all button (pressed) - fid = buildFid(6, 437, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 437, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[9])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -1004,11 +1004,11 @@ static bool _setup_inventory(int inventoryWindowType) } } else { // Inventory button up (normal) - fid = buildFid(6, 49, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 49, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[8])); // Inventory button up (pressed) - fid = buildFid(6, 50, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 50, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[9])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -1026,11 +1026,11 @@ static bool _setup_inventory(int inventoryWindowType) } // Inventory button down (normal) - fid = buildFid(6, 51, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 51, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_ikey[8])); // Inventory button down (pressed). - fid = buildFid(6, 52, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 52, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_ikey[9])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -1178,7 +1178,7 @@ static void _display_inventory(int a1, int a2, int inventoryWindowType) if (inventoryWindowType == INVENTORY_WINDOW_TYPE_NORMAL) { pitch = 499; - int backgroundFid = buildFid(6, 48, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0); CacheEntry* backgroundFrmHandle; unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); @@ -1191,7 +1191,7 @@ static void _display_inventory(int a1, int a2, int inventoryWindowType) if (gInventoryLeftHandItem != NULL && gInventoryLeftHandItem == gInventoryRightHandItem) { // Clear item1. - int itemBackgroundFid = buildFid(6, 32, 0, 0, 0); + int itemBackgroundFid = buildFid(OBJ_TYPE_INTERFACE, 32, 0, 0, 0); CacheEntry* itemBackgroundFrmHandle; Art* itemBackgroundFrm = artLock(itemBackgroundFid, &itemBackgroundFrmHandle); @@ -1212,7 +1212,7 @@ static void _display_inventory(int a1, int a2, int inventoryWindowType) } else if (inventoryWindowType == INVENTORY_WINDOW_TYPE_USE_ITEM_ON) { pitch = 292; - int backgroundFid = buildFid(6, 113, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 113, 0, 0, 0); CacheEntry* backgroundFrmHandle; unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); @@ -1224,7 +1224,7 @@ static void _display_inventory(int a1, int a2, int inventoryWindowType) } else if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT) { pitch = 537; - int backgroundFid = buildFid(6, 114, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 114, 0, 0, 0); CacheEntry* backgroundFrmHandle; unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); @@ -1333,7 +1333,7 @@ static void _display_target_inventory(int a1, int a2, Inventory* inventory, int if (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT) { pitch = 537; - int fid = buildFid(6, 114, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 114, 0, 0, 0); CacheEntry* handle; unsigned char* data = artLockFrameData(fid, 0, 0, &handle); @@ -1521,7 +1521,7 @@ static void _display_body(int fid, int inventoryWindowType) rect.bottom = rect.top + INVENTORY_BODY_VIEW_HEIGHT - 1; int frmId = gGameDialogSpeakerIsPartyMember ? 420 : 111; - int backgroundFid = buildFid(6, frmId, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0); unsigned char* src = artLockFrameData(backgroundFid, 0, 0, &backrgroundFrmHandle); if (src != NULL) { @@ -1563,7 +1563,7 @@ static void _display_body(int fid, int inventoryWindowType) rect.right = rect.left + INVENTORY_BODY_VIEW_WIDTH - 1; rect.bottom = rect.top + INVENTORY_BODY_VIEW_HEIGHT - 1; - int backgroundFid = buildFid(6, 114, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 114, 0, 0, 0); unsigned char* src = artLockFrameData(backgroundFid, 0, 0, &backrgroundFrmHandle); if (src != NULL) { blitBufferToBuffer(src + 537 * rect.top + rect.left, @@ -1610,7 +1610,7 @@ static int inventoryCommonInit() for (index = 0; index < INVENTORY_WINDOW_CURSOR_COUNT; index++) { InventoryCursorData* cursorData = &(gInventoryCursorData[index]); - int fid = buildFid(6, gInventoryWindowCursorFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gInventoryWindowCursorFrmIds[index], 0, 0, 0); Art* frm = artLock(fid, &(cursorData->frmHandle)); if (frm == NULL) { break; @@ -1792,7 +1792,7 @@ static void _inven_pickup(int keyCode, int a2) } CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 48, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData != NULL) { blitBufferToBuffer(backgroundFrmData + 499 * rect.top + rect.left, width, height, 499, windowBuffer + 499 * rect.top + rect.left, 499); @@ -1803,7 +1803,7 @@ static void _inven_pickup(int keyCode, int a2) rect.bottom = rect.top + height - 1; } else { CacheEntry* backgroundFrmHandle; - int backgroundFid = buildFid(6, 48, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0); unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); if (backgroundFrmData != NULL) { blitBufferToBuffer(backgroundFrmData + 499 * 286 + 154, 180, 61, 499, windowBuffer + 499 * 286 + 154, 499); @@ -2043,7 +2043,7 @@ void _adjust_ac(Object* critter, Object* oldArmor, Object* newArmor) static void _adjust_fid() { int fid; - if ((_inven_dude->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(_inven_dude->fid) == OBJ_TYPE_CRITTER) { Proto* proto; int v0 = _art_vault_guy_num; @@ -2082,7 +2082,7 @@ static void _adjust_fid() } } - fid = buildFid(1, v0, 0, animationCode, 0); + fid = buildFid(OBJ_TYPE_CRITTER, v0, 0, animationCode, 0); } else { fid = _inven_dude->fid; } @@ -2325,7 +2325,7 @@ static void inventoryRenderSummary() unsigned char* windowBuffer = windowGetBuffer(gInventoryWindow); - int fid = buildFid(6, 48, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0); CacheEntry* backgroundHandle; unsigned char* backgroundData = artLockFrameData(fid, 0, 0, &backgroundHandle); @@ -2515,7 +2515,7 @@ static void inventoryRenderSummary() // Total wt: messageListItem.num = 20; if (messageListGetItem(&gInventoryMessageList, &messageListItem)) { - if (_stack[0]->pid >> 24 == OBJ_TYPE_CRITTER) { + if (PID_TYPE(_stack[0]->pid) == OBJ_TYPE_CRITTER) { int carryWeight = critterGetStat(_stack[0], STAT_CARRY_WEIGHT); int inventoryWeight = objectGetInventoryWeight(_stack[0]); sprintf(formattedText, "%s %d/%d", messageListItem.text, inventoryWeight, carryWeight); @@ -2623,7 +2623,7 @@ int _invenWieldFunc(Object* critter, Object* item, int a3, bool a4) { if (a4) { if (!isoIsDisabled()) { - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); } } @@ -2649,8 +2649,8 @@ int _invenWieldFunc(Object* critter, Object* item, int a3, bool a4) if (critter == gDude) { if (!isoIsDisabled()) { - int fid = buildFid(1, baseFrmId, 0, (critter->fid & 0xF000) >> 12, critter->rotation + 1); - reg_anim_17(critter, fid, 0); + int fid = buildFid(OBJ_TYPE_CRITTER, baseFrmId, 0, (critter->fid & 0xF000) >> 12, critter->rotation + 1); + animationRegisterSetFid(critter, fid, 0); } } else { _adjust_ac(critter, armor, item); @@ -2665,7 +2665,7 @@ int _invenWieldFunc(Object* critter, Object* item, int a3, bool a4) int weaponAnimationCode = weaponGetAnimationCode(item); int hitModeAnimationCode = weaponGetAnimationForHitMode(item, HIT_MODE_RIGHT_WEAPON_PRIMARY); - int fid = buildFid(1, critter->fid & 0xFFF, hitModeAnimationCode, weaponAnimationCode, critter->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, hitModeAnimationCode, weaponAnimationCode, critter->rotation + 1); if (!artExists(fid)) { debugPrint("\ninven_wield failed! ERROR ERROR ERROR!"); return -1; @@ -2730,21 +2730,21 @@ int _invenWieldFunc(Object* critter, Object* item, int a3, bool a4) if (a4) { if (!isoIsDisabled()) { const char* soundEffectName = sfxBuildCharName(critter, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(critter, soundEffectName, 0); - reg_anim_animate(critter, ANIM_PUT_AWAY, 0); + animationRegisterPlaySoundEffect(critter, soundEffectName, 0); + animationRegisterAnimate(critter, ANIM_PUT_AWAY, 0); } } } if (a4 && !isoIsDisabled()) { if (weaponAnimationCode != 0) { - reg_anim_18(critter, weaponAnimationCode, -1); + animationRegisterTakeOutWeapon(critter, weaponAnimationCode, -1); } else { - int fid = buildFid(1, critter->fid & 0xFFF, 0, 0, critter->rotation + 1); - reg_anim_17(critter, fid, -1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, 0, critter->rotation + 1); + animationRegisterSetFid(critter, fid, -1); } } else { - int fid = buildFid(1, critter->fid & 0xFFF, 0, weaponAnimationCode, critter->rotation + 1); + int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, 0, weaponAnimationCode, critter->rotation + 1); _dude_stand(critter, critter->rotation, fid); } } @@ -2791,20 +2791,20 @@ int _invenUnwieldFunc(Object* obj, int a2, int a3) if (v6 == a2 && ((obj->fid & 0xF000) >> 12) != 0) { if (a3 && !isoIsDisabled()) { - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); const char* sfx = sfxBuildCharName(obj, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED); - reg_anim_play_sfx(obj, sfx, 0); + animationRegisterPlaySoundEffect(obj, sfx, 0); - reg_anim_animate(obj, 39, 0); + animationRegisterAnimate(obj, ANIM_PUT_AWAY, 0); - fid = buildFid(1, obj->fid & 0xFFF, 0, 0, obj->rotation + 1); - reg_anim_17(obj, fid, -1); + fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, 0, 0, obj->rotation + 1); + animationRegisterSetFid(obj, fid, -1); return reg_anim_end(); } - fid = buildFid(1, obj->fid & 0xFFF, 0, 0, obj->rotation + 1); + fid = buildFid(OBJ_TYPE_CRITTER, obj->fid & 0xFFF, 0, 0, obj->rotation + 1); _dude_stand(obj, obj->rotation, fid); } @@ -3003,7 +3003,7 @@ static void inventoryExamineItem(Object* critter, Object* item) unsigned char* windowBuffer = windowGetBuffer(gInventoryWindow); // Clear item description area. - int backgroundFid = buildFid(6, 48, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 48, 0, 0, 0); CacheEntry* handle; unsigned char* backgroundData = artLockFrameData(backgroundFid, 0, 0, &handle); @@ -3226,7 +3226,7 @@ static void inventoryWindowOpenContextMenu(int keyCode, int inventoryWindowType) windowBuffer + windowDescription->width * rect.top + rect.left, windowDescription->width); } else { - int backgroundFid = buildFid(6, windowDescription->field_0, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, windowDescription->field_0, 0, 0, 0); CacheEntry* backgroundFrmHandle; unsigned char* backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle); blitBufferToBuffer(backgroundFrmData + windowDescription->width * rect.top + rect.left, @@ -3403,8 +3403,8 @@ int inventoryOpenLooting(Object* a1, Object* a2) return 0; } - if (((a2->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { - if (_critter_flag_check(a2->pid, 0x20)) { + if (FID_TYPE(a2->fid) == OBJ_TYPE_CRITTER) { + if (_critter_flag_check(a2->pid, CRITTER_FLAG_0x20)) { // You can't find anything to take from that. messageListItem.num = 50; if (messageListGetItem(&gInventoryMessageList, &messageListItem)) { @@ -3414,7 +3414,7 @@ int inventoryOpenLooting(Object* a1, Object* a2) } } - if (((a2->fid & 0xF000000) >> 24) == OBJ_TYPE_ITEM) { + if (FID_TYPE(a2->fid) == OBJ_TYPE_ITEM) { if (itemGetType(a2) == ITEM_TYPE_CONTAINER) { if (a2->frame == 0) { CacheEntry* handle; @@ -3488,7 +3488,7 @@ int inventoryOpenLooting(Object* a1, Object* a2) int critterCount = 0; int critterIndex = 0; if (!_gIsSteal) { - if ((a2->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(a2->fid) == OBJ_TYPE_CRITTER) { critterCount = objectListCreate(a2->tile, a2->elevation, OBJ_TYPE_CRITTER, &critters); int endIndex = critterCount - 1; for (int index = 0; index < critterCount; index++) { @@ -3520,10 +3520,10 @@ int inventoryOpenLooting(Object* a1, Object* a2) } // Setup left arrow button. - fid = buildFid(6, arrowFrmIds[INVENTORY_ARROW_FRM_LEFT_ARROW_UP], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, arrowFrmIds[INVENTORY_ARROW_FRM_LEFT_ARROW_UP], 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(arrowFrmHandles[INVENTORY_ARROW_FRM_LEFT_ARROW_UP])); - fid = buildFid(6, arrowFrmIds[INVENTORY_ARROW_FRM_LEFT_ARROW_DOWN], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, arrowFrmIds[INVENTORY_ARROW_FRM_LEFT_ARROW_DOWN], 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(arrowFrmHandles[INVENTORY_ARROW_FRM_LEFT_ARROW_DOWN])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -3534,10 +3534,10 @@ int inventoryOpenLooting(Object* a1, Object* a2) } // Setup right arrow button. - fid = buildFid(6, arrowFrmIds[INVENTORY_ARROW_FRM_RIGHT_ARROW_UP], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, arrowFrmIds[INVENTORY_ARROW_FRM_RIGHT_ARROW_UP], 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(arrowFrmHandles[INVENTORY_ARROW_FRM_RIGHT_ARROW_UP])); - fid = buildFid(6, arrowFrmIds[INVENTORY_ARROW_FRM_RIGHT_ARROW_DOWN], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, arrowFrmIds[INVENTORY_ARROW_FRM_RIGHT_ARROW_DOWN], 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(arrowFrmHandles[INVENTORY_ARROW_FRM_RIGHT_ARROW_DOWN])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -3800,7 +3800,7 @@ int inventoryOpenStealing(Object* a1, Object* a2) return -1; } - _gIsSteal = (a1->pid >> 24) == OBJ_TYPE_CRITTER && critterIsActive(a2); + _gIsSteal = PID_TYPE(a1->pid) == OBJ_TYPE_CRITTER && critterIsActive(a2); _gStealCount = 0; _gStealSize = 0; @@ -3848,7 +3848,7 @@ static int _move_inventory(Object* a1, int a2, Object* a3, bool a4) unsigned char* windowBuffer = windowGetBuffer(gInventoryWindow); CacheEntry* handle; - int fid = buildFid(6, 114, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 114, 0, 0, 0); unsigned char* data = artLockFrameData(fid, 0, 0, &handle); if (data != NULL) { blitBufferToBuffer(data + 537 * rect.top + rect.left, INVENTORY_SLOT_WIDTH, INVENTORY_SLOT_HEIGHT, 537, windowBuffer + 537 * rect.top + rect.left, 537); @@ -3931,7 +3931,7 @@ static int _move_inventory(Object* a1, int a2, Object* a3, bool a4) if (rc != 1) { if (_item_move(a3, _inven_dude, a1, quantityToMove) == 0) { if ((a1->flags & OBJECT_IN_RIGHT_HAND) != 0) { - a3->fid = buildFid((a3->fid & 0xF000000) >> 24, a3->fid & 0xFFF, (a3->fid & 0xFF0000) >> 16, 0, a3->rotation + 1); + a3->fid = buildFid(FID_TYPE(a3->fid), a3->fid & 0xFFF, FID_ANIM_TYPE(a3->fid), 0, a3->rotation + 1); } a3->flags &= ~OBJECT_EQUIPPED; @@ -4735,7 +4735,7 @@ static void _draw_amount(int value, int inventoryWindowType) { // BIGNUM.frm CacheEntry* handle; - int fid = buildFid(6, 170, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 170, 0, 0, 0); unsigned char* data = artLockFrameData(fid, 0, 0, &handle); if (data == NULL) { return; @@ -4947,7 +4947,7 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item) unsigned char* windowBuffer = windowGetBuffer(_mt_wid); CacheEntry* backgroundHandle; - int backgroundFid = buildFid(6, windowDescription->field_0, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, windowDescription->field_0, 0, 0, 0); unsigned char* backgroundData = artLockFrameData(backgroundFid, 0, 0, &backgroundHandle); if (backgroundData != NULL) { blitBufferToBuffer(backgroundData, windowDescription->width, windowDescription->height, windowDescription->width, windowBuffer, windowDescription->width); @@ -4972,7 +4972,7 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item) // Timer overlay CacheEntry* overlayFrmHandle; - int overlayFid = buildFid(6, 306, 0, 0, 0); + int overlayFid = buildFid(OBJ_TYPE_INTERFACE, 306, 0, 0, 0); unsigned char* overlayFrmData = artLockFrameData(overlayFid, 0, 0, &overlayFrmHandle); if (overlayFrmData != NULL) { blitBufferToBuffer(overlayFrmData, 105, 81, 105, windowBuffer + 34 * windowDescription->width + 113, windowDescription->width); @@ -4999,10 +4999,10 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item) int btn; // Plus button - fid = buildFid(6, 193, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 193, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_mt_key[0])); - fid = buildFid(6, 194, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 194, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_mt_key[1])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -5013,10 +5013,10 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item) } // Minus button - fid = buildFid(6, 191, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 191, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_mt_key[2])); - fid = buildFid(6, 192, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 192, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_mt_key[3])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -5026,10 +5026,10 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item) } } - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_mt_key[4])); - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_mt_key[5])); if (buttonUpData != NULL && buttonDownData != NULL) { @@ -5047,10 +5047,10 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item) } if (inventoryWindowType == INVENTORY_WINDOW_TYPE_MOVE_ITEMS) { - fid = buildFid(6, 307, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 307, 0, 0, 0); buttonUpData = artLockFrameData(fid, 0, 0, &(_mt_key[6])); - fid = buildFid(6, 308, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 308, 0, 0, 0); buttonDownData = artLockFrameData(fid, 0, 0, &(_mt_key[7])); if (buttonUpData != NULL && buttonDownData != NULL) { diff --git a/src/item.cc b/src/item.cc index c182f4e..a429094 100644 --- a/src/item.cc +++ b/src/item.cc @@ -189,7 +189,7 @@ int itemAttemptAdd(Object* owner, Object* itemToAdd, int quantity) return -1; } - int parentType = (owner->fid & 0xF000000) >> 24; + int parentType = FID_TYPE(owner->fid); if (parentType == OBJ_TYPE_ITEM) { int itemType = itemGetType(owner); if (itemType == ITEM_TYPE_CONTAINER) { @@ -205,7 +205,7 @@ int itemAttemptAdd(Object* owner, Object* itemToAdd, int quantity) Object* containerOwner = objectGetOwner(owner); if (containerOwner != NULL) { - if (((containerOwner->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { + if (FID_TYPE(containerOwner->fid) == OBJ_TYPE_CRITTER) { int weightToAdd = itemGetWeight(itemToAdd); weightToAdd *= quantity; @@ -473,7 +473,7 @@ int _item_move_all_hidden(Object* a1, Object* a2) for (int j = i; j < inventory->length;) { bool v5; InventoryItem* inventoryItem = &(inventory->items[j]); - if (inventoryItem->item->pid >> 24 == OBJ_TYPE_ITEM) { + if (PID_TYPE(inventoryItem->item->pid) == OBJ_TYPE_ITEM) { Proto* proto; if (protoGetProto(inventoryItem->item->pid, &proto) != -1) { v5 = (proto->item.extendedFlags & ItemProtoExtendedFlags_NaturalWeapon) == 0; @@ -505,7 +505,7 @@ int _item_destroy_all_hidden(Object* a1) for (int j = i; j < inventory->length;) { bool v5; InventoryItem* inventoryItem = &(inventory->items[j]); - if (inventoryItem->item->pid >> 24 == OBJ_TYPE_ITEM) { + if (PID_TYPE(inventoryItem->item->pid) == OBJ_TYPE_ITEM) { Proto* proto; if (protoGetProto(inventoryItem->item->pid, &proto) != -1) { v5 = (proto->item.extendedFlags & ItemProtoExtendedFlags_NaturalWeapon) == 0; @@ -584,9 +584,9 @@ int _item_drop_all(Object* critter, int tile) if (hasEquippedItems) { Rect updatedRect; - int fid = buildFid(1, frmId, (critter->fid & 0xFF0000) >> 16, 0, (critter->fid & 0x70000000) >> 28); + int fid = buildFid(OBJ_TYPE_CRITTER, frmId, FID_ANIM_TYPE(critter->fid), 0, (critter->fid & 0x70000000) >> 28); objectSetFid(critter, fid, &updatedRect); - if (((critter->fid & 0xFF0000) >> 16) == 0) { + if (FID_ANIM_TYPE(critter->fid) == ANIM_STAND) { tileWindowRefreshRect(&updatedRect, gElevation); } } @@ -667,7 +667,7 @@ int itemGetType(Object* item) return ITEM_TYPE_MISC; } - if ((item->pid >> 24) != OBJ_TYPE_ITEM) { + if (PID_TYPE(item->pid) != OBJ_TYPE_ITEM) { return ITEM_TYPE_MISC; } @@ -845,7 +845,7 @@ int objectGetCost(Object* obj) } } - if ((obj->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_CRITTER) { Object* item2 = critterGetItem2(obj); if (item2 != NULL && (item2->flags & OBJECT_IN_RIGHT_HAND) == 0) { cost += itemGetCost(item2); @@ -883,7 +883,7 @@ int objectGetInventoryWeight(Object* obj) weight += itemGetWeight(item) * inventoryItem->quantity; } - if (((obj->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_CRITTER) { Object* item2 = critterGetItem2(obj); if (item2 != NULL) { if ((item2->flags & OBJECT_IN_RIGHT_HAND) == 0) { @@ -1088,7 +1088,7 @@ int weaponIsNatural(Object* obj) { Proto* proto; - if ((obj->pid >> 24) != OBJ_TYPE_ITEM) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_ITEM) { return 0; } @@ -1590,7 +1590,7 @@ int _item_w_range(Object* critter, int hitMode) return range; } - if (_critter_flag_check(critter->pid, 0x2000)) { + if (_critter_flag_check(critter->pid, CRITTER_FLAG_0x2000)) { return 2; } @@ -1942,14 +1942,10 @@ int _item_w_compute_ammo_cost(Object* obj, int* inout_a2) return 0; } -// Returns true if weapon's damage is explosion, plasma, or emp. -// Probably checks if weapon is granade. -// // 0x4790E8 -bool _item_w_is_grenade(Object* weapon) +bool weaponIsGrenade(Object* weapon) { int damageType = weaponGetDamageType(NULL, weapon); - return damageType == DAMAGE_TYPE_EXPLOSION || damageType == DAMAGE_TYPE_PLASMA || damageType == DAMAGE_TYPE_EMP; } @@ -1968,7 +1964,7 @@ int _item_w_area_damage_radius(Object* weapon, int hitMode) } } else if (attackType == ATTACK_TYPE_THROW) { // NOTE: Uninline. - if (_item_w_is_grenade(weapon)) { + if (weaponIsGrenade(weapon)) { // NOTE: Uninline. v1 = _item_w_grenade_dmg_radius(weapon); } @@ -2840,7 +2836,7 @@ int drugEffectEventProcess(Object* obj, void* data) return 0; } - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { return 0; } @@ -3009,7 +3005,7 @@ int withdrawalEventWrite(File* stream, void* data) // 0x47A4C4 static void performWithdrawalStart(Object* obj, int perk, int pid) { - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { debugPrint("\nERROR: perform_withdrawal_start: Was called on non-critter!"); return; } @@ -3039,7 +3035,7 @@ static void performWithdrawalStart(Object* obj, int perk, int pid) // 0x47A558 static void performWithdrawalEnd(Object* obj, int perk) { - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { debugPrint("\nERROR: perform_withdrawal_end: Was called on non-critter!"); return; } diff --git a/src/item.h b/src/item.h index 69dfc39..74176a2 100644 --- a/src/item.h +++ b/src/item.h @@ -76,7 +76,7 @@ Object* _item_w_unload(Object* weapon); int weaponGetActionPointCost1(Object* weapon); int weaponGetActionPointCost2(Object* weapon); int _item_w_compute_ammo_cost(Object* obj, int* inout_a2); -bool _item_w_is_grenade(Object* weapon); +bool weaponIsGrenade(Object* weapon); int _item_w_area_damage_radius(Object* weapon, int hitMode); int _item_w_grenade_dmg_radius(Object* weapon); int _item_w_rocket_dmg_radius(Object* weapon); diff --git a/src/light.cc b/src/light.cc index 2255743..df65b69 100644 --- a/src/light.cc +++ b/src/light.cc @@ -1,9 +1,9 @@ #include "light.h" #include "map_defs.h" +#include "object.h" #include "perk.h" #include "tile.h" -#include "object.h" #include @@ -111,7 +111,7 @@ void lightIncreaseIntensity(int elevation, int tile, int lightIntensity) if (!hexGridTileIsValid(tile)) { return; } - + gLightIntensity[elevation][tile] += lightIntensity; } @@ -125,7 +125,7 @@ void lightDecreaseIntensity(int elevation, int tile, int lightIntensity) if (!hexGridTileIsValid(tile)) { return; } - + gLightIntensity[elevation][tile] -= lightIntensity; } diff --git a/src/loadsave.cc b/src/loadsave.cc index a6a8833..1987489 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -1227,7 +1227,7 @@ static int lsgWindowInit(int windowType) } for (int index = 0; index < LOAD_SAVE_FRM_COUNT; index++) { - int fid = buildFid(6, gLoadSaveFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gLoadSaveFrmIds[index], 0, 0, 0); gLoadSaveFrmData[index] = artLockFrameDataReturningSize(fid, &(gLoadSaveFrmHandles[index]), &(gLoadSaveFrmSizes[index].width), diff --git a/src/main.cc b/src/main.cc index f5a7e4d..0e6645d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -23,13 +23,16 @@ #include "options.h" #include "palette.h" #include "platform_compat.h" +#include "proto.h" #include "random.h" #include "scripts.h" -#include "sfall_config.h" #include "selfrun.h" +#include "sfall_config.h" #include "text_font.h" #include "version.h" +#include "window.h" #include "window_manager.h" +#include "window_manager_private.h" #include "word_wrap.h" #include "world_map.h" @@ -57,7 +60,7 @@ typedef enum MainMenuOption { MAIN_MENU_INTRO, MAIN_MENU_NEW_GAME, MAIN_MENU_LOAD_GAME, - MAIN_MENU_3, + MAIN_MENU_SCREENSAVER, MAIN_MENU_TIMEOUT, MAIN_MENU_CREDITS, MAIN_MENU_QUOTES, @@ -70,6 +73,8 @@ static bool falloutInit(int argc, char** argv); static int _main_load_new(char* fname); static void mainLoop(FpsLimiter& fpsLimiter); static void _main_selfrun_exit(); +static void _main_selfrun_record(); +static void _main_selfrun_play(); static void showDeath(); static void _main_death_voiceover_callback(); static int _mainDeathGrabTextFile(const char* fileName, char* dest); @@ -99,6 +104,16 @@ static int _main_selfrun_index = 0; // 0x5194E8 static bool _main_show_death_scene = false; +// A switch to pick selfrun vs. intro video for screensaver: +// - `false` - will play next selfrun recording +// - `true` - will play intro video +// +// This value will alternate on every attempt, even if there are no selfrun +// recordings. +// +// 0x5194EC +static bool gMainMenuScreensaverCycle = false; + // 0x5194F0 static int gMainMenuWindow = -1; @@ -175,7 +190,7 @@ int falloutMain(int argc, char** argv) // SFALL: Allow to skip intro movies int skipOpeningMovies; configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, &skipOpeningMovies); - if(skipOpeningMovies < 1) { + if (skipOpeningMovies < 1) { gameMoviePlay(MOVIE_IPLOGO, GAME_MOVIE_FADE_IN); gameMoviePlay(MOVIE_INTRO, 0); gameMoviePlay(MOVIE_CREDITS, 0); @@ -207,7 +222,7 @@ int falloutMain(int argc, char** argv) gameMoviePlay(MOVIE_ELDER, GAME_MOVIE_STOP_MUSIC); randomSeedPrerandom(-1); - // SFALL: Override starting map. + // SFALL: Override starting map. char* mapName = NULL; if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_STARTING_MAP_KEY, &mapName)) { if (*mapName == '\0') { @@ -273,8 +288,8 @@ int falloutMain(int argc, char** argv) case MAIN_MENU_TIMEOUT: debugPrint("Main menu timed-out\n"); // FALLTHROUGH - case MAIN_MENU_3: - // _main_selfrun_play(); + case MAIN_MENU_SCREENSAVER: + _main_selfrun_play(); break; case MAIN_MENU_OPTIONS: mainMenuWindowHide(false); @@ -303,7 +318,7 @@ int falloutMain(int argc, char** argv) backgroundSoundDelete(); break; case MAIN_MENU_SELFRUN: - // _main_selfrun_record(); + _main_selfrun_record(); break; } } @@ -329,7 +344,7 @@ static bool falloutInit(int argc, char** argv) _main_selfrun_exit(); } - if (_selfrun_get_list(&_main_selfrun_list, &_main_selfrun_count) == 0) { + if (selfrunInitFileList(&_main_selfrun_list, &_main_selfrun_count) == 0) { _main_selfrun_index = 0; } @@ -408,7 +423,7 @@ static void mainLoop(FpsLimiter& fpsLimiter) static void _main_selfrun_exit() { if (_main_selfrun_list != NULL) { - _selfrun_free_list(&_main_selfrun_list); + selfrunFreeFileList(&_main_selfrun_list); } _main_selfrun_count = 0; @@ -416,6 +431,89 @@ static void _main_selfrun_exit() _main_selfrun_list = NULL; } +// 0x480F64 +static void _main_selfrun_record() +{ + SelfrunData selfrunData; + bool ready = false; + + char** fileList; + int fileListLength = fileNameListInit("maps\\*.map", &fileList, 0, 0); + if (fileListLength != 0) { + int selectedFileIndex = _win_list_select("Select Map", fileList, fileListLength, 0, 80, 80, 0x10000 | 0x100 | 4); + if (selectedFileIndex != -1) { + // NOTE: It's size is likely 13 chars (on par with SelfrunData + // fields), but due to the padding it takes 16 chars on stack. + char recordingName[SELFRUN_RECORDING_FILE_NAME_LENGTH]; + recordingName[0] = '\0'; + if (_win_get_str(recordingName, sizeof(recordingName) - 2, "Enter name for recording (8 characters max, no extension):", 100, 100) == 0) { + memset(&selfrunData, 0, sizeof(selfrunData)); + if (selfrunPrepareRecording(recordingName, fileList[selectedFileIndex], &selfrunData) == 0) { + ready = true; + } + } + } + fileNameListFree(&fileList, 0); + } + + if (ready) { + mainMenuWindowHide(true); + mainMenuWindowFree(); + backgroundSoundDelete(); + randomSeedPrerandom(0xBEEFFEED); + gameReset(); + _proto_dude_init("premade\\combat.gcd"); + _main_load_new(selfrunData.mapFileName); + selfrunRecordingLoop(&selfrunData); + paletteFadeTo(gPaletteWhite); + objectHide(gDude, NULL); + _map_exit(); + gameReset(); + mainMenuWindowInit(); + + if (_main_selfrun_list != NULL) { + _main_selfrun_exit(); + } + + if (selfrunInitFileList(&_main_selfrun_list, &_main_selfrun_count) == 0) { + _main_selfrun_index = 0; + } + } +} + +// 0x48109C +static void _main_selfrun_play() +{ + if (!gMainMenuScreensaverCycle && _main_selfrun_count > 0) { + SelfrunData selfrunData; + if (selfrunPreparePlayback(_main_selfrun_list[_main_selfrun_index], &selfrunData) == 0) { + mainMenuWindowHide(true); + mainMenuWindowFree(); + backgroundSoundDelete(); + randomSeedPrerandom(0xBEEFFEED); + gameReset(); + _proto_dude_init("premade\\combat.gcd"); + _main_load_new(selfrunData.mapFileName); + selfrunPlaybackLoop(&selfrunData); + paletteFadeTo(gPaletteWhite); + objectHide(gDude, NULL); + _map_exit(); + gameReset(); + mainMenuWindowInit(); + } + + _main_selfrun_index++; + if (_main_selfrun_index >= _main_selfrun_count) { + _main_selfrun_index = 0; + } + } else { + mainMenuWindowHide(true); + gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC); + } + + gMainMenuScreensaverCycle = !gMainMenuScreensaverCycle; +} + // 0x48118C static void showDeath() { @@ -445,7 +543,7 @@ static void showDeath() // DEATH.FRM CacheEntry* backgroundHandle; - int fid = buildFid(6, 309, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 309, 0, 0, 0); unsigned char* background = artLockFrameData(fid, 0, 0, &backgroundHandle); if (background == NULL) { break; @@ -591,32 +689,17 @@ static int _mainDeathGrabTextFile(const char* fileName, char* dest) // 0x481598 static int _mainDeathWordWrap(char* text, int width, short* beginnings, short* count) { - // TODO: Probably wrong. while (true) { - char* p = text; - while (*p != ':') { - if (*p != '\0') { - p++; - if (*p == ':') { - break; - } - if (*p != '\0') { - continue; - } - } - p = NULL; + char* sep = strchr(text, ':'); + if (sep == NULL) { break; } - if (p == NULL) { + if (sep - 1 < text) { break; } - - if (p - 1 < text) { - break; - } - p[0] = ' '; - p[-1] = ' '; + sep[0] = ' '; + sep[-1] = ' '; } if (wordWrap(text, width, beginnings, count) == -1) { @@ -671,7 +754,7 @@ static int mainMenuWindowInit() gMainMenuWindowBuffer = windowGetBuffer(gMainMenuWindow); // mainmenu.frm - int backgroundFid = buildFid(6, 140, 0, 0, 0); + int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 140, 0, 0, 0); gMainMenuBackgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &gMainMenuBackgroundFrmHandle); if (gMainMenuBackgroundFrmData == NULL) { mainMenuWindowFree(); @@ -692,7 +775,7 @@ static int mainMenuWindowInit() int fontSettings = _colorTable[21091], fontSettingsSFall = 0; configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY, &fontSettingsSFall); if (fontSettingsSFall && !(fontSettingsSFall & 0x010000)) - fontSettings = fontSettingsSFall & 0xFF; + fontSettings = fontSettingsSFall & 0xFF; // SFALL: Allow to move copyright text int offsetX = 0, offsetY = 0; @@ -717,7 +800,7 @@ static int mainMenuWindowInit() windowDrawText(gMainMenuWindow, version, 0, 615 - len, 460, fontSettings | 0x06000000); // menuup.frm - fid = buildFid(6, 299, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 299, 0, 0, 0); gMainMenuButtonUpFrmData = artLockFrameData(fid, 0, 0, &gMainMenuButtonUpFrmHandle); if (gMainMenuButtonUpFrmData == NULL) { mainMenuWindowFree(); @@ -725,7 +808,7 @@ static int mainMenuWindowInit() } // menudown.frm - fid = buildFid(6, 300, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 300, 0, 0, 0); gMainMenuButtonDownFrmData = artLockFrameData(fid, 0, 0, &gMainMenuButtonDownFrmHandle); if (gMainMenuButtonDownFrmData == NULL) { mainMenuWindowFree(); @@ -900,7 +983,7 @@ static int mainMenuWindowHandleEvents(FpsLimiter& fpsLimiter) } else if (keyCode == KEY_MINUS || keyCode == KEY_UNDERSCORE) { brightnessDecrease(); } else if (keyCode == KEY_UPPERCASE_D || keyCode == KEY_LOWERCASE_D) { - rc = MAIN_MENU_3; + rc = MAIN_MENU_SCREENSAVER; continue; } else if (keyCode == 1111) { if (!(mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_REPEAT)) { diff --git a/src/map.cc b/src/map.cc index 15d9eb6..c118cd8 100644 --- a/src/map.cc +++ b/src/map.cc @@ -33,6 +33,7 @@ #include "text_object.h" #include "tile.h" #include "window_manager.h" +#include "window_manager_private.h" #include "world_map.h" #include @@ -922,7 +923,7 @@ static int mapLoad(File* stream) } Object* object; - int fid = buildFid(5, 12, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_MISC, 12, 0, 0, 0); objectCreateWithFidPid(&object, fid, -1); object->flags |= (OBJECT_LIGHT_THRU | OBJECT_TEMPORARY | OBJECT_HIDDEN); objectSetLocation(object, 1, 0, NULL); @@ -1027,8 +1028,8 @@ int mapLoadSaved(char* fileName) int rc = mapLoadByName(mapName); - if (gameTimeGetTime() >= gMapHeader.field_38) { - if (((gameTimeGetTime() - gMapHeader.field_38) / 36000) >= 24) { + if (gameTimeGetTime() >= gMapHeader.lastVisitTime) { + if (((gameTimeGetTime() - gMapHeader.lastVisitTime) / GAME_TIME_TICKS_PER_HOUR) >= 24) { objectUnjamAll(); } @@ -1061,37 +1062,31 @@ static int _map_age_dead_critters() return 0; } - int v4 = (gameTimeGetTime() - gMapHeader.field_38) / 36000; - if (v4 == 0) { + int hoursSinceLastVisit = (gameTimeGetTime() - gMapHeader.lastVisitTime) / GAME_TIME_TICKS_PER_HOUR; + if (hoursSinceLastVisit == 0) { return 0; } Object* obj = objectFindFirst(); while (obj != NULL) { - if (obj->pid >> 24 == OBJ_TYPE_CRITTER + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER && obj != gDude && !objectIsPartyMember(obj) && !critterIsDead(obj)) { - obj->data.critter.combat.maneuver &= 0x04; - if (critterGetKillType(obj) != KILL_TYPE_ROBOT && _critter_flag_check(obj->pid, 512) == 0) { - _critter_heal_hours(obj, v4); + obj->data.critter.combat.maneuver &= ~CRITTER_MANUEVER_FLEEING; + if (critterGetKillType(obj) != KILL_TYPE_ROBOT && _critter_flag_check(obj->pid, CRITTER_FLAG_0x200) == 0) { + _critter_heal_hours(obj, hoursSinceLastVisit); } } obj = objectFindNext(); } - int v20; - if (v4 <= 336) { - if (v4 > 144) { - v20 = 1; - } else { - v20 = 0; - } + int agingType; + if (hoursSinceLastVisit > 6 * 24) { + agingType = 1; + } else if (hoursSinceLastVisit > 14 * 24) { + agingType = 2; } else { - v20 = 2; - } - - if (v20 == 0) { return 0; } @@ -1101,10 +1096,10 @@ static int _map_age_dead_critters() obj = objectFindFirst(); while (obj != NULL) { - int type = obj->pid >> 24; + int type = PID_TYPE(obj->pid); if (type == OBJ_TYPE_CRITTER) { if (obj != gDude && critterIsDead(obj)) { - if (critterGetKillType(obj) != KILL_TYPE_ROBOT && _critter_flag_check(obj->pid, 512) == 0) { + if (critterGetKillType(obj) != KILL_TYPE_ROBOT && _critter_flag_check(obj->pid, CRITTER_FLAG_0x200) == 0) { objects[count++] = obj; if (count >= capacity) { @@ -1117,7 +1112,7 @@ static int _map_age_dead_critters() } } } - } else if (v20 == 2 && type == OBJ_TYPE_MISC && obj->pid == 0x500000B) { + } else if (agingType == 2 && type == OBJ_TYPE_MISC && obj->pid == 0x500000B) { objects[count++] = obj; if (count >= capacity) { capacity *= 2; @@ -1134,18 +1129,18 @@ static int _map_age_dead_critters() int rc = 0; for (int index = 0; index < count; index++) { Object* obj = objects[index]; - if (obj->pid >> 24 == OBJ_TYPE_CRITTER) { - if (_critter_flag_check(obj->pid, 64) == 0) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { + if (_critter_flag_check(obj->pid, CRITTER_FLAG_0x40) == 0) { _item_drop_all(obj, obj->tile); } - Object* a1; - if (objectCreateWithPid(&a1, 0x5000004) == -1) { + Object* blood; + if (objectCreateWithPid(&blood, 0x5000004) == -1) { rc = -1; break; } - objectSetLocation(a1, obj->tile, obj->elevation, NULL); + objectSetLocation(blood, obj->tile, obj->elevation, NULL); Proto* proto; protoGetProto(obj->pid, &proto); @@ -1160,7 +1155,7 @@ static int _map_age_dead_critters() } } - objectSetFrame(a1, frame, NULL); + objectSetFrame(blood, frame, NULL); } reg_anim_clear(obj); @@ -1264,7 +1259,7 @@ static void _map_fix_critter_combat_data() continue; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { continue; } @@ -1327,13 +1322,13 @@ static int _map_save_file(File* stream) for (tile = 0; tile < SQUARE_GRID_SIZE; tile++) { int fid; - fid = buildFid(4, _square[elevation]->field_0[tile] & 0xFFF, 0, 0, 0); - if (fid != buildFid(4, 1, 0, 0, 0)) { + fid = buildFid(OBJ_TYPE_TILE, _square[elevation]->field_0[tile] & 0xFFF, 0, 0, 0); + if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { break; } - fid = buildFid(4, (_square[elevation]->field_0[tile] >> 16) & 0xFFF, 0, 0, 0); - if (fid != buildFid(4, 1, 0, 0, 0)) { + fid = buildFid(OBJ_TYPE_TILE, (_square[elevation]->field_0[tile] >> 16) & 0xFFF, 0, 0, 0); + if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { break; } } @@ -1383,14 +1378,12 @@ static int _map_save_file(File* stream) if (scriptSaveAll(stream) == -1) { sprintf(err, "Error saving scripts in %s", gMapHeader.name); - // TODO: Incomplete. - // _win_msg(err, 80, 80, _colorTable[31744]); + _win_msg(err, 80, 80, _colorTable[31744]); } if (objectSaveAll(stream) == -1) { sprintf(err, "Error saving objects in %s", gMapHeader.name); - // TODO: Incomplete. - // _win_msg(err, 80, 80, _colorTable[31744]); + _win_msg(err, 80, 80, _colorTable[31744]); } scriptsEnable(); @@ -1424,7 +1417,7 @@ int _map_save_in_game(bool a1) } gMapHeader.flags |= 0x01; - gMapHeader.field_38 = gameTimeGetTime(); + gMapHeader.lastVisitTime = gameTimeGetTime(); char name[16]; @@ -1545,9 +1538,9 @@ static void _map_place_dude_and_mouse() _obj_clear_seen(); if (gDude != NULL) { - if (((gDude->fid & 0xFF0000) >> 16) != 0) { + if (FID_ANIM_TYPE(gDude->fid) != ANIM_STAND) { objectSetFrame(gDude, 0, 0); - gDude->fid = buildFid(1, gDude->fid & 0xFFF, ANIM_STAND, (gDude->fid & 0xF000) >> 12, gDude->rotation + 1); + gDude->fid = buildFid(OBJ_TYPE_CRITTER, gDude->fid & 0xFFF, ANIM_STAND, (gDude->fid & 0xF000) >> 12, gDude->rotation + 1); } if (gDude->tile == -1) { @@ -1577,11 +1570,11 @@ static void _square_reset() // check subsequent calls. int fid = *p; fid &= ~0xFFFF; - *p = ((buildFid(4, 1, 0, 0, 0) & 0xFFF | (((fid >> 16) & 0xF000) >> 12)) << 16) | (fid & 0xFFFF); + *p = ((buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) & 0xFFF | (((fid >> 16) & 0xF000) >> 12)) << 16) | (fid & 0xFFFF); fid = *p; int v3 = (fid & 0xF000) >> 12; - int v4 = (buildFid(4, 1, 0, 0, 0) & 0xFFF) | v3; + int v4 = (buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) & 0xFFF) | v3; fid &= ~0xFFFF; @@ -1642,7 +1635,7 @@ static int mapHeaderWrite(MapHeader* ptr, File* stream) if (fileWriteInt32(stream, ptr->darkness) == -1) return -1; if (fileWriteInt32(stream, ptr->globalVariablesCount) == -1) return -1; if (fileWriteInt32(stream, ptr->field_34) == -1) return -1; - if (fileWriteInt32(stream, ptr->field_38) == -1) return -1; + if (fileWriteInt32(stream, ptr->lastVisitTime) == -1) return -1; if (fileWriteInt32List(stream, ptr->field_3C, 44) == -1) return -1; return 0; @@ -1662,7 +1655,7 @@ static int mapHeaderRead(MapHeader* ptr, File* stream) if (fileReadInt32(stream, &(ptr->darkness)) == -1) return -1; if (fileReadInt32(stream, &(ptr->globalVariablesCount)) == -1) return -1; if (fileReadInt32(stream, &(ptr->field_34)) == -1) return -1; - if (fileReadInt32(stream, &(ptr->field_38)) == -1) return -1; + if (fileReadInt32(stream, &(ptr->lastVisitTime)) == -1) return -1; if (fileReadInt32List(stream, ptr->field_3C, 44) == -1) return -1; return 0; diff --git a/src/map.h b/src/map.h index 3f3248d..2d55783 100644 --- a/src/map.h +++ b/src/map.h @@ -49,7 +49,9 @@ typedef struct MapHeader { // map_number int field_34; - int field_38; + + // Time in game ticks when PC last visited this map. + int lastVisitTime; int field_3C[44]; } MapHeader; diff --git a/src/mouse_manager.cc b/src/mouse_manager.cc index 6ec0c45..1586e5b 100644 --- a/src/mouse_manager.cc +++ b/src/mouse_manager.cc @@ -1,57 +1,641 @@ #include "mouse_manager.h" #include "core.h" +#include "datafile.h" +#include "db.h" +#include "debug.h" +#include "memory_manager.h" +#include "platform_compat.h" + +#include // 0x5195A8 -char* (*_mouseNameMangler)(char*) = _defaultNameMangler; +MouseManagerNameMangler* gMouseManagerNameMangler = mouseManagerNameManglerDefaultImpl; // 0x5195AC -int (*_rateCallback)() = _defaultRateCallback; +MouseManagerRateProvider* gMouseManagerRateProvider = mouseManagerRateProviderDefaultImpl; // 0x5195B0 -int (*_currentTimeCallback)() = _defaultTimeCallback; +MouseManagerTimeProvider* gMouseManagerTimeProvider = mouseManagerTimeProviderDefaultImpl; // 0x5195B4 -int _curref = 1; +int gMouseManagerCurrentRef = 1; + +// 0x63247C +MouseManagerCacheEntry gMouseManagerCache[MOUSE_MGR_CACHE_CAPACITY]; + +// 0x638DFC +bool gMouseManagerIsAnimating; + +// 0x638E00 +unsigned char* gMouseManagerCurrentPalette; + +// 0x638E04 +MouseManagerAnimatedData* gMouseManagerCurrentAnimatedData; + +// 0x638E08 +unsigned char* gMouseManagerCurrentStaticData; + +// 0x638E0C +int gMouseManagerCurrentCacheEntryIndex; // 0x485250 -char* _defaultNameMangler(char* a1) +char* mouseManagerNameManglerDefaultImpl(char* a1) { return a1; } // 0x485254 -int _defaultRateCallback() +int mouseManagerRateProviderDefaultImpl() { return 1000; } // 0x48525C -int _defaultTimeCallback() +int mouseManagerTimeProviderDefaultImpl() { return _get_time(); } // 0x485288 -void _mousemgrSetNameMangler(char* (*func)(char*)) +void mouseManagerSetNameMangler(MouseManagerNameMangler* func) { - _mouseNameMangler = func; + gMouseManagerNameMangler = func; +} + +// 0x4852B8 +void mouseManagerFreeCacheEntry(MouseManagerCacheEntry* entry) +{ + switch (entry->type) { + case MOUSE_MANAGER_MOUSE_TYPE_STATIC: + if (entry->staticData != NULL) { + if (entry->staticData->data != NULL) { + internal_free_safe(entry->staticData->data, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 120 + entry->staticData->data = NULL; + } + internal_free_safe(entry->staticData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 123 + entry->staticData = NULL; + } + break; + case MOUSE_MANAGER_MOUSE_TYPE_ANIMATED: + if (entry->animatedData != NULL) { + if (entry->animatedData->field_0 != NULL) { + for (int index = 0; index < entry->animatedData->frameCount; index++) { + internal_free_safe(entry->animatedData->field_0[index], __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 134 + internal_free_safe(entry->animatedData->field_4[index], __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 135 + } + internal_free_safe(entry->animatedData->field_0, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 137 + internal_free_safe(entry->animatedData->field_4, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 138 + internal_free_safe(entry->animatedData->field_8, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 139 + internal_free_safe(entry->animatedData->field_C, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 140 + } + internal_free_safe(entry->animatedData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 143 + entry->animatedData = NULL; + } + break; + } + + entry->type = 0; + entry->fileName[0] = '\0'; +} + +// 0x4853F8 +int mouseManagerInsertCacheEntry(void** data, int type, unsigned char* palette, const char* fileName) +{ + int foundIndex = -1; + int index; + for (index = 0; index < MOUSE_MGR_CACHE_CAPACITY; index++) { + MouseManagerCacheEntry* cacheEntry = &(gMouseManagerCache[index]); + if (cacheEntry->type == MOUSE_MANAGER_MOUSE_TYPE_NONE && foundIndex == -1) { + foundIndex = index; + } + + if (compat_stricmp(fileName, cacheEntry->fileName) == 0) { + mouseManagerFreeCacheEntry(cacheEntry); + foundIndex = index; + break; + } + } + + if (foundIndex != -1) { + index = foundIndex; + } + + if (index == MOUSE_MGR_CACHE_CAPACITY) { + int v2 = -1; + int v1 = gMouseManagerCurrentRef; + for (int index = 0; index < MOUSE_MGR_CACHE_CAPACITY; index++) { + MouseManagerCacheEntry* cacheEntry = &(gMouseManagerCache[index]); + if (v1 > cacheEntry->ref) { + v1 = cacheEntry->ref; + v2 = index; + } + } + + if (v2 == -1) { + debugPrint("Mouse cache overflow!!!!\n"); + exit(1); + } + + index = v2; + mouseManagerFreeCacheEntry(&(gMouseManagerCache[index])); + } + + MouseManagerCacheEntry* cacheEntry = &(gMouseManagerCache[index]); + cacheEntry->type = type; + memcpy(cacheEntry->palette, palette, sizeof(cacheEntry->palette)); + cacheEntry->ref = gMouseManagerCurrentRef++; + strncpy(cacheEntry->fileName, fileName, sizeof(cacheEntry->fileName) - 1); + cacheEntry->field_32C[0] = '\0'; + cacheEntry->data = *data; + + return index; +} + +// NOTE: Inlined. +// +// 0x4853D4 +void mouseManagerFlushCache() +{ + for (int index = 0; index < MOUSE_MGR_CACHE_CAPACITY; index++) { + mouseManagerFreeCacheEntry(&(gMouseManagerCache[index])); + } +} + +// 0x48554C +MouseManagerCacheEntry* mouseManagerFindCacheEntry(const char* fileName, unsigned char** palettePtr, int* a3, int* a4, int* widthPtr, int* heightPtr, int* typePtr) +{ + for (int index = 0; index < MOUSE_MGR_CACHE_CAPACITY; index++) { + MouseManagerCacheEntry* cacheEntry = &(gMouseManagerCache[index]); + if (compat_strnicmp(cacheEntry->fileName, fileName, 31) == 0 || compat_strnicmp(cacheEntry->field_32C, fileName, 31) == 0) { + *palettePtr = cacheEntry->palette; + *typePtr = cacheEntry->type; + + gMouseManagerCurrentCacheEntryIndex = index; + + switch (cacheEntry->type) { + case MOUSE_MANAGER_MOUSE_TYPE_STATIC: + *a3 = cacheEntry->staticData->field_4; + *a4 = cacheEntry->staticData->field_8; + *widthPtr = cacheEntry->staticData->width; + *heightPtr = cacheEntry->staticData->height; + break; + case MOUSE_MANAGER_MOUSE_TYPE_ANIMATED: + *widthPtr = cacheEntry->animatedData->width; + *heightPtr = cacheEntry->animatedData->height; + *a3 = cacheEntry->animatedData->field_8[cacheEntry->animatedData->field_26]; + *a4 = cacheEntry->animatedData->field_C[cacheEntry->animatedData->field_26]; + break; + } + + return cacheEntry; + } + } + + return NULL; } // 0x48568C -void _initMousemgr() +void mouseManagerInit() { mouseSetSensitivity(1.0); } +// 0x48569C +void mouseManagerExit() +{ + mouseSetFrame(NULL, 0, 0, 0, 0, 0, 0); + + if (gMouseManagerCurrentStaticData != NULL) { + internal_free_safe(gMouseManagerCurrentStaticData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 243 + gMouseManagerCurrentStaticData = NULL; + } + + // NOTE: Uninline. + mouseManagerFlushCache(); + + gMouseManagerCurrentPalette = NULL; + gMouseManagerCurrentAnimatedData = 0; +} + +// 0x485704 +void mouseManagerUpdate() +{ + if (!gMouseManagerIsAnimating) { + return; + } + + if (gMouseManagerCurrentAnimatedData == NULL) { + debugPrint("Animating == 1 but curAnim == 0\n"); + } + + if (gMouseManagerTimeProvider() >= gMouseManagerCurrentAnimatedData->field_1C) { + gMouseManagerCurrentAnimatedData->field_1C = (int)(gMouseManagerCurrentAnimatedData->field_18 / gMouseManagerCurrentAnimatedData->frameCount * gMouseManagerRateProvider() + gMouseManagerTimeProvider()); + if (gMouseManagerCurrentAnimatedData->field_24 != gMouseManagerCurrentAnimatedData->field_26) { + int v1 = gMouseManagerCurrentAnimatedData->field_26 + gMouseManagerCurrentAnimatedData->field_20; + if (v1 < 0) { + v1 = gMouseManagerCurrentAnimatedData->frameCount - 1; + } else if (v1 >= gMouseManagerCurrentAnimatedData->frameCount) { + v1 = 0; + } + + gMouseManagerCurrentAnimatedData->field_26 = v1; + memcpy(gMouseManagerCurrentAnimatedData->field_0[gMouseManagerCurrentAnimatedData->field_26], + gMouseManagerCurrentAnimatedData->field_4[gMouseManagerCurrentAnimatedData->field_26], + gMouseManagerCurrentAnimatedData->width * gMouseManagerCurrentAnimatedData->height); + + sub_42EE84(gMouseManagerCurrentAnimatedData->field_0[gMouseManagerCurrentAnimatedData->field_26], + gMouseManagerCurrentPalette, + gMouseManagerCurrentAnimatedData->width, + gMouseManagerCurrentAnimatedData->height); + + mouseSetFrame(gMouseManagerCurrentAnimatedData->field_0[v1], + gMouseManagerCurrentAnimatedData->width, + gMouseManagerCurrentAnimatedData->height, + gMouseManagerCurrentAnimatedData->width, + gMouseManagerCurrentAnimatedData->field_8[v1], + gMouseManagerCurrentAnimatedData->field_C[v1], + 0); + } + } +} + +// 0x485868 +int mouseManagerSetFrame(char* fileName, int a2) +{ + char* mangledFileName = gMouseManagerNameMangler(fileName); + + unsigned char* palette; + int temp; + int type; + MouseManagerCacheEntry* cacheEntry = mouseManagerFindCacheEntry(fileName, &palette, &temp, &temp, &temp, &temp, &type); + if (cacheEntry != NULL) { + if (type == MOUSE_MANAGER_MOUSE_TYPE_ANIMATED) { + cacheEntry->animatedData->field_24 = a2; + if (cacheEntry->animatedData->field_24 >= cacheEntry->animatedData->field_26) { + int v1 = cacheEntry->animatedData->field_24 - cacheEntry->animatedData->field_26; + int v2 = cacheEntry->animatedData->frameCount + cacheEntry->animatedData->field_26 - cacheEntry->animatedData->field_24; + if (v1 >= v2) { + cacheEntry->animatedData->field_20 = -1; + } else { + cacheEntry->animatedData->field_20 = 1; + } + } else { + int v1 = cacheEntry->animatedData->field_26 - cacheEntry->animatedData->field_24; + int v2 = cacheEntry->animatedData->frameCount + cacheEntry->animatedData->field_24 - cacheEntry->animatedData->field_26; + if (v1 < v2) { + cacheEntry->animatedData->field_20 = -1; + } else { + cacheEntry->animatedData->field_20 = 1; + } + } + + if (!gMouseManagerIsAnimating || gMouseManagerCurrentAnimatedData != cacheEntry->animatedData) { + memcpy(cacheEntry->animatedData->field_0[cacheEntry->animatedData->field_26], + cacheEntry->animatedData->field_4[cacheEntry->animatedData->field_26], + cacheEntry->animatedData->width * cacheEntry->animatedData->height); + + mouseSetFrame(cacheEntry->animatedData->field_0[cacheEntry->animatedData->field_26], + cacheEntry->animatedData->width, + cacheEntry->animatedData->height, + cacheEntry->animatedData->width, + cacheEntry->animatedData->field_8[cacheEntry->animatedData->field_26], + cacheEntry->animatedData->field_C[cacheEntry->animatedData->field_26], + 0); + + gMouseManagerIsAnimating = true; + } + + gMouseManagerCurrentAnimatedData = cacheEntry->animatedData; + gMouseManagerCurrentPalette = palette; + gMouseManagerCurrentAnimatedData->field_1C = gMouseManagerTimeProvider(); + return true; + } + + mouseManagerSetMousePointer(fileName); + return true; + } + + if (gMouseManagerIsAnimating) { + gMouseManagerCurrentPalette = 0; + gMouseManagerIsAnimating = 0; + gMouseManagerCurrentAnimatedData = 0; + } else { + if (gMouseManagerCurrentStaticData != NULL) { + internal_free_safe(gMouseManagerCurrentStaticData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 337 + gMouseManagerCurrentStaticData = NULL; + } + } + + File* stream = fileOpen(mangledFileName, "r"); + if (stream == NULL) { + debugPrint("mouseSetFrame: couldn't find %s\n", mangledFileName); + return false; + } + + char string[80]; + fileReadString(string, sizeof(string), stream); + if (compat_strnicmp(string, "anim", 4) != 0) { + fileClose(stream); + mouseManagerSetMousePointer(fileName); + return true; + } + + // NOTE: Uninline. + char* sep = strchr(string, ' '); + if (sep == NULL) { + // FIXME: Leaks stream. + return false; + } + + int v3; + float v4; + sscanf(sep + 1, "%d %f", &v3, &v4); + + MouseManagerAnimatedData* animatedData = (MouseManagerAnimatedData*)internal_malloc_safe(sizeof(*animatedData), __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 359 + animatedData->field_0 = (unsigned char**)internal_malloc_safe(sizeof(*animatedData->field_0) * v3, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 360 + animatedData->field_4 = (unsigned char**)internal_malloc_safe(sizeof(*animatedData->field_4) * v3, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 361 + animatedData->field_8 = (int*)internal_malloc_safe(sizeof(*animatedData->field_8) * v3, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 362 + animatedData->field_C = (int*)internal_malloc_safe(sizeof(*animatedData->field_8) * v3, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 363 + animatedData->field_18 = v4; + animatedData->field_1C = gMouseManagerTimeProvider(); + animatedData->field_26 = 0; + animatedData->field_24 = a2; + animatedData->frameCount = v3; + if (animatedData->frameCount / 2 <= a2) { + animatedData->field_20 = -1; + } else { + animatedData->field_20 = 1; + } + + int width; + int height; + for (int index = 0; index < v3; index++) { + string[0] = '\0'; + fileReadString(string, sizeof(string), stream); + if (string[0] == '\0') { + debugPrint("Not enough frames in %s, got %d, needed %d", mangledFileName, index, v3); + break; + } + + // NOTE: Uninline. + char* sep = strchr(string, ' '); + if (sep == NULL) { + debugPrint("Bad line %s in %s\n", string, fileName); + // FIXME: Leaking stream. + return false; + } + + *sep = '\0'; + + int v5; + int v6; + sscanf(sep + 1, "%d %d", &v5, &v6); + + animatedData->field_4[index] = datafileReadRaw(gMouseManagerNameMangler(string), &width, &height); + animatedData->field_0[index] = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 390 + memcpy(animatedData->field_0[index], animatedData->field_4[index], width * height); + sub_42EE84(animatedData->field_0[index], datafileGetPalette(), width, height); + animatedData->field_8[index] = v5; + animatedData->field_C[index] = v6; + } + + fileClose(stream); + + animatedData->width = width; + animatedData->height = height; + + gMouseManagerCurrentCacheEntryIndex = mouseManagerInsertCacheEntry(reinterpret_cast(&animatedData), MOUSE_MANAGER_MOUSE_TYPE_ANIMATED, datafileGetPalette(), fileName); + strncpy(gMouseManagerCache[gMouseManagerCurrentCacheEntryIndex].field_32C, fileName, 31); + + gMouseManagerCurrentAnimatedData = animatedData; + gMouseManagerCurrentPalette = gMouseManagerCache[gMouseManagerCurrentCacheEntryIndex].palette; + gMouseManagerIsAnimating = true; + + mouseSetFrame(animatedData->field_0[0], + animatedData->width, + animatedData->height, + animatedData->width, + animatedData->field_8[0], + animatedData->field_C[0], + 0); + + return true; +} + +// 0x485E58 +bool mouseManagerSetMouseShape(char* fileName, int a2, int a3) +{ + unsigned char* palette; + int temp; + int width; + int height; + int type; + MouseManagerCacheEntry* cacheEntry = mouseManagerFindCacheEntry(fileName, &palette, &temp, &temp, &width, &height, &type); + char* mangledFileName = gMouseManagerNameMangler(fileName); + + if (cacheEntry == NULL) { + MouseManagerStaticData* staticData; + staticData = (MouseManagerStaticData*)internal_malloc_safe(sizeof(*staticData), __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 430 + staticData->data = datafileReadRaw(mangledFileName, &height, &width); + staticData->field_4 = a2; + staticData->field_8 = a3; + staticData->width = width; + staticData->height = height; + gMouseManagerCurrentCacheEntryIndex = mouseManagerInsertCacheEntry(reinterpret_cast(&staticData), MOUSE_MANAGER_MOUSE_TYPE_STATIC, datafileGetPalette(), fileName); + + // NOTE: Original code is slightly different. It obtains address of + // `staticData` and sets it's it into `cacheEntry`, which is a bit + // awkward. Maybe there is more level on indirection was used. Any way + // in order to make code path below unaltered take entire cache entry. + cacheEntry = &(gMouseManagerCache[gMouseManagerCurrentCacheEntryIndex]); + + type = MOUSE_MANAGER_MOUSE_TYPE_STATIC; + palette = gMouseManagerCache[gMouseManagerCurrentCacheEntryIndex].palette; + } + + switch (type) { + case MOUSE_MANAGER_MOUSE_TYPE_STATIC: + if (gMouseManagerCurrentStaticData != NULL) { + internal_free_safe(gMouseManagerCurrentStaticData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 446 + } + + gMouseManagerCurrentStaticData = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 448 + memcpy(gMouseManagerCurrentStaticData, cacheEntry->staticData->data, width * height); + sub_42EE84(gMouseManagerCurrentStaticData, palette, width, height); + mouseSetFrame(gMouseManagerCurrentStaticData, width, height, width, a2, a3, 0); + gMouseManagerIsAnimating = false; + break; + case MOUSE_MANAGER_MOUSE_TYPE_ANIMATED: + gMouseManagerCurrentAnimatedData = cacheEntry->animatedData; + gMouseManagerIsAnimating = true; + gMouseManagerCurrentPalette = palette; + break; + } + + return true; +} + +// 0x486010 +bool mouseManagerSetMousePointer(char* fileName) +{ + unsigned char* palette; + int v1; + int v2; + int width; + int height; + int type; + MouseManagerCacheEntry* cacheEntry = mouseManagerFindCacheEntry(fileName, &palette, &v1, &v2, &width, &height, &type); + if (cacheEntry != NULL) { + if (gMouseManagerCurrentStaticData != NULL) { + internal_free_safe(gMouseManagerCurrentStaticData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 482 + gMouseManagerCurrentStaticData = NULL; + } + + gMouseManagerCurrentPalette = NULL; + gMouseManagerIsAnimating = false; + gMouseManagerCurrentAnimatedData = 0; + + switch (type) { + case MOUSE_MANAGER_MOUSE_TYPE_STATIC: + gMouseManagerCurrentStaticData = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 492 + memcpy(gMouseManagerCurrentStaticData, cacheEntry->staticData->data, width * height); + sub_42EE84(gMouseManagerCurrentStaticData, palette, width, height); + mouseSetFrame(gMouseManagerCurrentStaticData, width, height, width, v1, v2, 0); + gMouseManagerIsAnimating = false; + break; + case MOUSE_MANAGER_MOUSE_TYPE_ANIMATED: + gMouseManagerCurrentAnimatedData = cacheEntry->animatedData; + gMouseManagerCurrentPalette = palette; + gMouseManagerCurrentAnimatedData->field_26 = 0; + gMouseManagerCurrentAnimatedData->field_24 = 0; + mouseSetFrame(gMouseManagerCurrentAnimatedData->field_0[0], + gMouseManagerCurrentAnimatedData->width, + gMouseManagerCurrentAnimatedData->height, + gMouseManagerCurrentAnimatedData->width, + gMouseManagerCurrentAnimatedData->field_8[0], + gMouseManagerCurrentAnimatedData->field_C[0], + 0); + gMouseManagerIsAnimating = true; + break; + } + return true; + } + + char* dot = strrchr(fileName, '.'); + if (dot != NULL && compat_stricmp(dot + 1, "mou") == 0) { + return mouseManagerSetMouseShape(fileName, 0, 0); + } + + char* mangledFileName = gMouseManagerNameMangler(fileName); + File* stream = fileOpen(mangledFileName, "r"); + if (stream == NULL) { + debugPrint("Can't find %s\n", mangledFileName); + return false; + } + + char string[80]; + string[0] = '\0'; + fileReadString(string, sizeof(string) - 1, stream); + if (string[0] == '\0') { + return false; + } + + bool rc; + if (compat_strnicmp(string, "anim", 4) == 0) { + fileClose(stream); + rc = mouseManagerSetFrame(fileName, 0); + } else { + // NOTE: Uninline. + char* sep = strchr(string, ' '); + if (sep != NULL) { + return 0; + } + + *sep = '\0'; + + int v3; + int v4; + sscanf(sep + 1, "%d %d", &v3, &v4); + + fileClose(stream); + + rc = mouseManagerSetMouseShape(string, v3, v4); + } + + strncpy(gMouseManagerCache[gMouseManagerCurrentCacheEntryIndex].field_32C, fileName, 31); + + return rc; +} + +// 0x4862AC +void mouseManagerResetMouse() +{ + MouseManagerCacheEntry* entry = &(gMouseManagerCache[gMouseManagerCurrentCacheEntryIndex]); + + int imageWidth; + int imageHeight; + switch (entry->type) { + case MOUSE_MANAGER_MOUSE_TYPE_STATIC: + imageWidth = entry->staticData->width; + imageHeight = entry->staticData->height; + break; + case MOUSE_MANAGER_MOUSE_TYPE_ANIMATED: + imageWidth = entry->animatedData->width; + imageHeight = entry->animatedData->height; + break; + } + + switch (entry->type) { + case MOUSE_MANAGER_MOUSE_TYPE_STATIC: + if (gMouseManagerCurrentStaticData != NULL) { + if (gMouseManagerCurrentStaticData != NULL) { + internal_free_safe(gMouseManagerCurrentStaticData, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 572 + } + + gMouseManagerCurrentStaticData = (unsigned char*)internal_malloc_safe(imageWidth * imageHeight, __FILE__, __LINE__); // "..\\int\\MOUSEMGR.C", 574 + memcpy(gMouseManagerCurrentStaticData, entry->staticData->data, imageWidth * imageHeight); + sub_42EE84(gMouseManagerCurrentStaticData, entry->palette, imageWidth, imageHeight); + + mouseSetFrame(gMouseManagerCurrentStaticData, + imageWidth, + imageHeight, + imageWidth, + entry->staticData->field_4, + entry->staticData->field_8, + 0); + } else { + debugPrint("Hm, current mouse type is M_STATIC, but no current mouse pointer\n"); + } + break; + case MOUSE_MANAGER_MOUSE_TYPE_ANIMATED: + if (gMouseManagerCurrentAnimatedData != NULL) { + for (int index = 0; index < gMouseManagerCurrentAnimatedData->frameCount; index++) { + memcpy(gMouseManagerCurrentAnimatedData->field_0[index], gMouseManagerCurrentAnimatedData->field_4[index], imageWidth * imageHeight); + sub_42EE84(gMouseManagerCurrentAnimatedData->field_0[index], entry->palette, imageWidth, imageHeight); + } + + mouseSetFrame(gMouseManagerCurrentAnimatedData->field_0[gMouseManagerCurrentAnimatedData->field_26], + imageWidth, + imageHeight, + imageWidth, + gMouseManagerCurrentAnimatedData->field_8[gMouseManagerCurrentAnimatedData->field_26], + gMouseManagerCurrentAnimatedData->field_C[gMouseManagerCurrentAnimatedData->field_26], + 0); + } else { + debugPrint("Hm, current mouse type is M_ANIMATED, but no current mouse pointer\n"); + } + } +} + // 0x4865C4 -void _mouseHide() +void mouseManagerHideMouse() { mouseHideCursor(); } // 0x4865CC -void _mouseShow() +void mouseManagerShowMouse() { mouseShowCursor(); } diff --git a/src/mouse_manager.h b/src/mouse_manager.h index e27e9de..22b6778 100644 --- a/src/mouse_manager.h +++ b/src/mouse_manager.h @@ -1,16 +1,81 @@ #ifndef MOUSE_MANAGER_H #define MOUSE_MANAGER_H -extern char* (*_mouseNameMangler)(char*); -extern int (*_rateCallback)(); -extern int (*_currentTimeCallback)(); +#define MOUSE_MGR_CACHE_CAPACITY 32 -char* _defaultNameMangler(char* a1); -int _defaultRateCallback(); -int _defaultTimeCallback(); -void _mousemgrSetNameMangler(char* (*func)(char*)); -void _initMousemgr(); -void _mouseHide(); -void _mouseShow(); +typedef char*(MouseManagerNameMangler)(char* fileName); +typedef int(MouseManagerRateProvider)(); +typedef int(MouseManagerTimeProvider)(); + +typedef enum MouseManagerMouseType { + MOUSE_MANAGER_MOUSE_TYPE_NONE, + MOUSE_MANAGER_MOUSE_TYPE_STATIC, + MOUSE_MANAGER_MOUSE_TYPE_ANIMATED, +} MouseManagerMouseType; + +typedef struct MouseManagerStaticData { + unsigned char* data; + int field_4; + int field_8; + int width; + int height; +} MouseManagerStaticData; + +typedef struct MouseManagerAnimatedData { + unsigned char** field_0; + unsigned char** field_4; + int* field_8; + int* field_C; + int width; + int height; + float field_18; + int field_1C; + int field_20; + signed char field_24; + signed char frameCount; + signed char field_26; +} MouseManagerAnimatedData; + +typedef struct MouseManagerCacheEntry { + union { + void* data; + MouseManagerStaticData* staticData; + MouseManagerAnimatedData* animatedData; + }; + int type; + unsigned char palette[256 * 3]; + int ref; + char fileName[32]; + char field_32C[32]; +} MouseManagerCacheEntry; + +extern MouseManagerNameMangler* gMouseManagerNameMangler; +extern MouseManagerRateProvider* gMouseManagerRateProvider; +extern MouseManagerTimeProvider* gMouseManagerTimeProvider; + +extern MouseManagerCacheEntry gMouseManagerCache[MOUSE_MGR_CACHE_CAPACITY]; +extern bool gMouseManagerIsAnimating; +extern unsigned char* gMouseManagerCurrentPalette; +extern MouseManagerAnimatedData* gMouseManagerCurrentAnimatedData; +extern unsigned char* gMouseManagerCurrentStaticData; +extern int gMouseManagerCurrentCacheEntryIndex; + +char* mouseManagerNameManglerDefaultImpl(char* a1); +int mouseManagerRateProviderDefaultImpl(); +int mouseManagerTimeProviderDefaultImpl(); +void mouseManagerSetNameMangler(MouseManagerNameMangler* func); +void mouseManagerFreeCacheEntry(MouseManagerCacheEntry* entry); +int mouseManagerInsertCacheEntry(void** data, int type, unsigned char* palette, const char* fileName); +void mouseManagerFlushCache(); +MouseManagerCacheEntry* mouseManagerFindCacheEntry(const char* fileName, unsigned char** palettePtr, int* a3, int* a4, int* widthPtr, int* heightPtr, int* typePtr); +void mouseManagerInit(); +void mouseManagerExit(); +void mouseManagerUpdate(); +int mouseManagerSetFrame(char* fileName, int a2); +bool mouseManagerSetMouseShape(char* fileName, int a2, int a3); +bool mouseManagerSetMousePointer(char* fileName); +void mouseManagerResetMouse(); +void mouseManagerHideMouse(); +void mouseManagerShowMouse(); #endif /* MOUSE_MANAGER_H */ diff --git a/src/movie.cc b/src/movie.cc index f789f4a..af153c2 100644 --- a/src/movie.cc +++ b/src/movie.cc @@ -14,6 +14,7 @@ #include "pointer_registry.h" #include "sound.h" #include "text_font.h" +#include "window.h" #include "window_manager.h" #include @@ -29,11 +30,14 @@ typedef struct MovieSubtitleListNode { static void* movieMallocImpl(size_t size); static void movieFreeImpl(void* ptr); static bool movieReadImpl(int fileHandle, void* buf, int count); -static void movieDirectImpl(SDL_Surface* a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9); -static void movieBufferedImpl(SDL_Surface* a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9); -static int _movieScaleSubRectAlpha(int a1); -static int _blitAlpha(int win, unsigned char* a2, int a3, int a4, int a5); -static int _blitNormal(int win, int a2, int a3, int a4, int a5); +static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, int srcX, int srcY, int destWidth, int destHeight, int a8, int a9); +static void movieBufferedImpl(SDL_Surface* surface, int srcWidth, int srcHeight, int srcX, int srcY, int destWidth, int destHeight, int a8, int a9); +static int _movieScaleSubRect(int win, unsigned char* data, int width, int height, int pitch); +static int _movieScaleSubRectAlpha(int win, unsigned char* data, int width, int height, int pitch); +static int _movieScaleWindowAlpha(int win, unsigned char* data, int width, int height, int pitch); +static int _blitAlpha(int win, unsigned char* data, int width, int height, int pitch); +static int _movieScaleWindow(int win, unsigned char* data, int width, int height, int pitch); +static int _blitNormal(int win, unsigned char* data, int width, int height, int pitch); static void movieSetPaletteEntriesImpl(unsigned char* palette, int start, int end); static int _noop(); static void _cleanupMovie(int a1); @@ -51,6 +55,30 @@ static int gMovieWindow = -1; // 0x5195BC static int gMovieSubtitlesFont = -1; +// 0x5195C0 +static MovieBlitFunc* gMovieBlitFuncs[2][2][2] = { + { + { + _blitNormal, + _blitNormal, + }, + { + _movieScaleWindow, + _movieScaleSubRect, + }, + }, + { + { + _blitAlpha, + _blitAlpha, + }, + { + _movieScaleWindowAlpha, + _movieScaleSubRectAlpha, + }, + }, +}; + // 0x5195E0 static MovieSetPaletteEntriesProc* gMovieSetPaletteEntriesProc = _setSystemPaletteEntries; @@ -72,19 +100,21 @@ static Rect _movieRect; // 0x638E30 static void (*_movieCallback)(); +// 0x638E34 +MovieEndFunc* _endMovieFunc; + // 0x638E38 static MovieSetPaletteProc* gMoviePaletteProc; -// NOTE: Some kind of callback which was intended to change movie file path -// in place during opening movie file to find subsitutions. This callback is -// never set. -// // 0x638E3C -static int (*_failedOpenFunc)(char* filePath); +static MovieFailedOpenFunc* _failedOpenFunc; // 0x638E40 static MovieBuildSubtitleFilePathProc* gMovieBuildSubtitleFilePathProc; +// 0x638E44 +static MovieStartFunc* _startMovieFunc; + // 0x638E48 static int _subtitleW; @@ -103,6 +133,9 @@ static int _lastMovieSY; // 0x638E5C static int _movieScaleFlag; +// 0x638E60 +static MoviePreDrawFunc* _moviePreDrawFunc; + // 0x638E64 static int _lastMovieH; @@ -134,7 +167,7 @@ static int _movieH; static int _movieOffset; // 0x638E8C -static void (*_movieCaptureFrameFunc)(void*, int, int, int, int, int); +static MovieCaptureFrameProc* _movieCaptureFrameFunc; // 0x638E90 static unsigned char* _lastMovieBuffer; @@ -143,7 +176,7 @@ static unsigned char* _lastMovieBuffer; static int _movieW; // 0x638E98 -static void (*_movieFrameGrabFunc)(); +static MovieFrameGrabProc* _movieFrameGrabFunc; // 0x638EA0 static int _subtitleH; @@ -172,6 +205,31 @@ static unsigned char* _alphaBuf; static SDL_Surface* gMovieSdlSurface = NULL; static int gMovieFileStreamPointerKey = 0; +// NOTE: Unused. +// +// 0x4865E0 +void _movieSetPreDrawFunc(MoviePreDrawFunc* preDrawFunc) +{ + _moviePreDrawFunc = preDrawFunc; +} + +// NOTE: Unused. +// +// 0x4865E8 +void _movieSetFailedOpenFunc(MovieFailedOpenFunc* failedOpenFunc) +{ + _failedOpenFunc = failedOpenFunc; +} + +// NOTE: Unused. +// +// 0x4865F0 +void _movieSetFunc(MovieStartFunc* startFunc, MovieEndFunc* endFunc) +{ + _startMovieFunc = startFunc; + _endMovieFunc = endFunc; +} + // 0x4865FC static void* movieMallocImpl(size_t size) { @@ -249,7 +307,14 @@ static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, i if (_movieCaptureFrameFunc != NULL) { if (SDL_LockSurface(surface) == 0) { - _movieCaptureFrameFunc(surface->pixels, srcWidth, destRect.x, destRect.y, destRect.w, destRect.h); + _movieCaptureFrameFunc(static_cast(surface->pixels), + srcWidth, + srcHeight, + surface->pitch, + destRect.x, + destRect.y, + destRect.w, + destRect.h); SDL_UnlockSurface(surface); } } @@ -269,8 +334,6 @@ static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, i // 0x486900 static void movieBufferedImpl(SDL_Surface* a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) { - int v13; - if (gMovieWindow == -1) { return; } @@ -290,55 +353,135 @@ static void movieBufferedImpl(SDL_Surface* a1, int a2, int a3, int a4, int a5, i } if (_movieCaptureFrameFunc != NULL) { - // TODO: Ignore, _movieCaptureFrameFunc is never set. - // _movieCaptureFrameFunc() + _movieCaptureFrameFunc(static_cast(a1->pixels), a2, a3, a1->pitch, _movieRect.left, _movieRect.top, a6, a7); } if (_movieFrameGrabFunc != NULL) { - // TODO: Ignore, _movieFrameGrabFunc is never set. - // _movieFrameGrabFunc(); + _movieFrameGrabFunc(static_cast(a1->pixels), a2, a3, a1->pitch); } else { - v13 = 4 * _movieSubRectFlag + 8 * _movieScaleFlag + 16 * _movieAlphaFlag; - // TODO: Incomplete. + MovieBlitFunc* func = gMovieBlitFuncs[_movieAlphaFlag][_movieScaleFlag][_movieSubRectFlag]; + if (func(gMovieWindow, static_cast(a1->pixels), a2, a3, a1->pitch) != 0) { + if (_moviePreDrawFunc != NULL) { + _moviePreDrawFunc(gMovieWindow, &_movieRect); + } + + windowRefreshRect(gMovieWindow, &_movieRect); + } } SDL_UnlockSurface(a1); } +// NOTE: Unused. +// +// 0x486A98 +void _movieSetFrameGrabFunc(MovieFrameGrabProc* proc) +{ + _movieFrameGrabFunc = proc; +} + +// NOTE: Unused. +// +// 0x486AA0 +void _movieSetCaptureFrameFunc(MovieCaptureFrameProc* func) +{ + _movieCaptureFrameFunc = func; +} + +// 0x486B68 +int _movieScaleSubRect(int win, unsigned char* data, int width, int height, int pitch) +{ + int windowWidth = windowGetWidth(win); + unsigned char* windowBuffer = windowGetBuffer(win) + windowWidth * _movieY + _movieX; + if (width * 4 / 3 > _movieW) { + gMovieFlags |= 0x01; + return 0; + } + + int v1 = width / 3; + for (int y = 0; y < height; y++) { + int x; + for (x = 0; x < v1; x++) { + unsigned int value = data[0]; + value |= data[1] << 8; + value |= data[2] << 16; + value |= data[2] << 24; + + *(unsigned int*)windowBuffer = value; + + windowBuffer += 4; + data += 3; + } + + for (x = x * 3; x < width; x++) { + *windowBuffer++ = *data++; + } + + data += pitch - width; + windowBuffer += windowWidth - _movieW; + } + + return 1; +} + // 0x486C74 -static int _movieScaleSubRectAlpha(int a1) +int _movieScaleSubRectAlpha(int win, unsigned char* data, int width, int height, int pitch) +{ + gMovieFlags |= 1; + return 0; +} + +// NOTE: Uncollapsed 0x486C74. +int _movieScaleWindowAlpha(int win, unsigned char* data, int width, int height, int pitch) { gMovieFlags |= 1; return 0; } // 0x486C80 -static int _blitAlpha(int win, unsigned char* a2, int a3, int a4, int a5) +int _blitAlpha(int win, unsigned char* data, int width, int height, int pitch) { - unsigned char* buf; - int offset; + int windowWidth = windowGetWidth(win); + unsigned char* windowBuffer = windowGetBuffer(win); + _alphaBltBuf(data, width, height, pitch, _alphaWindowBuf, _alphaBuf, windowBuffer + windowWidth * _movieY + _movieX, windowWidth); + return 1; +} - offset = windowGetWidth(win) * _movieY + _movieX; - buf = windowGetBuffer(win); +// 0x486CD4 +int _movieScaleWindow(int win, unsigned char* data, int width, int height, int pitch) +{ + int windowWidth = windowGetWidth(win); + if (width != 3 * windowWidth / 4) { + gMovieFlags |= 1; + return 0; + } - // TODO: Incomplete. - // _alphaBltBuf(a2, a3, a4, a5, _alphaWindowBuf, _alphaBuf, buf + offset, windowGetWidth(win)); + unsigned char* windowBuffer = windowGetBuffer(win); + for (int y = 0; y < height; y++) { + int scaledWidth = width / 3; + for (int x = 0; x < scaledWidth; x++) { + unsigned int value = data[0]; + value |= data[1] << 8; + value |= data[2] << 16; + value |= data[3] << 24; + + *(unsigned int*)windowBuffer = value; + + windowBuffer += 4; + data += 3; + } + data += pitch - width; + } return 1; } // 0x486D84 -static int _blitNormal(int win, int a2, int a3, int a4, int a5) +int _blitNormal(int win, unsigned char* data, int width, int height, int pitch) { - unsigned char* buf; - int offset; - - offset = windowGetWidth(win) * _movieY + _movieX; - buf = windowGetBuffer(win); - - // TODO: Incomplete. - // _drawScaled(buf + offset, _movieW, _movieH, windowGetWidth(win), a2, a3, a4, a5); - + int windowWidth = windowGetWidth(win); + unsigned char* windowBuffer = windowGetBuffer(win); + _drawScaled(windowBuffer + windowWidth * _movieY + _movieX, _movieW, _movieH, windowWidth, data, width, height, pitch); return 1; } @@ -373,10 +516,9 @@ static void _cleanupMovie(int a1) return; } - // TODO: Probably can be ignored. - // if (_endMovieFunc) { - // _endMovieFunc(_movieW, _movieX, _movieH); - // } + if (_endMovieFunc != NULL) { + _endMovieFunc(gMovieWindow, _movieX, _movieY, _movieW, _movieH); + } int frame; int dropped; @@ -579,30 +721,18 @@ static void movieLoadSubtitles(char* filePath) char* pch; - pch = string; - while (*pch != '\0' && *pch != '\n') { - pch++; - } - - if (*pch != '\0') { + pch = strchr(string, '\n'); + if (pch != NULL) { *pch = '\0'; } - pch = string; - while (*pch != '\0' && *pch != '\r') { - pch++; - } - - if (*pch != '\0') { + pch = strchr(string, '\r'); + if (pch != NULL) { *pch = '\0'; } - pch = string; - while (*pch != '\0' && *pch != ':') { - pch++; - } - - if (*pch != '\0') { + pch = strchr(string, ':'); + if (pch != NULL) { *pch = '\0'; subtitle->num = atoi(string); subtitle->text = strdup_safe(pch + 1, __FILE__, __LINE__); // "..\\int\\MOVIE.C", 1058 @@ -737,14 +867,28 @@ static int _movieStart(int win, char* filePath, int (*a3)()) debugPrint("not scaled\n"); } - // TODO: Probably can be ignored, never set. - // if (_startMovieFunc) { - // _startMovieFunc(); - // } + if (_startMovieFunc != NULL) { + _startMovieFunc(gMovieWindow); + } if (_alphaHandle != NULL) { - // TODO: Probably can be ignored, never set. - abort(); + int size; + fileReadInt32(_alphaHandle, &size); + + short tmp; + fileReadInt16(_alphaHandle, &tmp); + fileReadInt16(_alphaHandle, &tmp); + + _alphaBuf = (unsigned char*)internal_malloc_safe(size, __FILE__, __LINE__); // "..\\int\\MOVIE.C", 1178 + _alphaWindowBuf = (unsigned char*)internal_malloc_safe(_movieH * _movieW, __FILE__, __LINE__); // "..\\int\\MOVIE.C", 1179 + + unsigned char* windowBuffer = windowGetBuffer(gMovieWindow); + blitBufferToBuffer(windowBuffer + windowGetWidth(gMovieWindow) * _movieY + _movieX, + _movieW, + _movieH, + windowGetWidth(gMovieWindow), + _alphaWindowBuf, + _movieW); } _movieRect.left = _movieX; diff --git a/src/movie.h b/src/movie.h index 893e35c..b478f55 100644 --- a/src/movie.h +++ b/src/movie.h @@ -1,6 +1,8 @@ #ifndef MOVIE_H #define MOVIE_H +#include "geometry.h" + typedef enum MovieFlags { MOVIE_FLAG_0x01 = 0x01, MOVIE_FLAG_0x02 = 0x02, @@ -19,6 +21,13 @@ typedef enum MovieExtendedFlags { typedef char* MovieBuildSubtitleFilePathProc(char* movieFilePath); typedef void MovieSetPaletteEntriesProc(unsigned char* palette, int start, int end); typedef void MovieSetPaletteProc(int frame); +typedef void(MovieFrameGrabProc)(unsigned char* data, int width, int height, int pitch); +typedef void(MovieCaptureFrameProc)(unsigned char* data, int width, int height, int pitch, int movieX, int movieY, int movieWidth, int movieHeight); +typedef int(MovieBlitFunc)(int win, unsigned char* data, int width, int height, int pitch); +typedef void(MoviePreDrawFunc)(int win, Rect* rect); +typedef void(MovieStartFunc)(int win); +typedef void(MovieEndFunc)(int win, int x, int y, int width, int height); +typedef int(MovieFailedOpenFunc)(char* path); void movieInit(); void movieExit(); diff --git a/src/movie_lib.cc b/src/movie_lib.cc index 8aaffbc..033de5f 100644 --- a/src/movie_lib.cc +++ b/src/movie_lib.cc @@ -715,11 +715,7 @@ static void* _ioRead(int size) return NULL; } - if (!gMovieLibReadProc(_io_handle, buf, size)) { - return NULL; - } - - return buf; + return gMovieLibReadProc(_io_handle, buf, size) < 1 ? NULL : buf; } // 0x4F4D40 diff --git a/src/nevs.cc b/src/nevs.cc index c261b80..916378f 100644 --- a/src/nevs.cc +++ b/src/nevs.cc @@ -89,7 +89,7 @@ static void _nevs_removeprogramreferences(Program* program) // 0x488418 void _nevs_initonce() { - _interpretRegisterProgramDeleteCallback(_nevs_removeprogramreferences); + intLibRegisterProgramDeleteCallback(_nevs_removeprogramreferences); if (gNevs == NULL) { gNevs = (Nevs*)internal_calloc_safe(sizeof(Nevs), NEVS_COUNT, __FILE__, __LINE__); // "..\\int\\NEVS.C", 131 diff --git a/src/obj_types.h b/src/obj_types.h index 0656a3c..41f5478 100644 --- a/src/obj_types.h +++ b/src/obj_types.h @@ -27,6 +27,10 @@ enum { OBJ_TYPE_COUNT, }; +#define FID_TYPE(value) ((value) & 0xF000000) >> 24 +#define PID_TYPE(value) (value) >> 24 +#define SID_TYPE(value) (value) >> 24 + typedef enum OutlineType { OUTLINE_TYPE_HOSTILE = 1, OUTLINE_TYPE_2 = 2, @@ -66,6 +70,20 @@ typedef enum ObjectFlags { OBJECT_OPEN_DOOR = OBJECT_SHOOT_THRU | OBJECT_LIGHT_THRU | OBJECT_NO_BLOCK, } ObjectFlags; +typedef enum CritterFlags { + CRITTER_FLAG_0x2 = 0x2, + CRITTER_FLAG_0x20 = 0x20, + CRITTER_FLAG_0x40 = 0x40, + CRITTER_FLAG_0x80 = 0x80, + CRITTER_FLAG_0x100 = 0x100, + CRITTER_FLAG_0x200 = 0x200, + CRITTER_FLAG_0x400 = 0x400, + CRITTER_FLAG_0x800 = 0x800, + CRITTER_FLAG_0x1000 = 0x1000, + CRITTER_FLAG_0x2000 = 0x2000, + CRITTER_FLAG_0x4000 = 0x4000, +} CritterFlags; + #define OUTLINE_TYPE_MASK 0xFFFFFF #define OUTLINE_PALETTED 0x40000000 #define OUTLINE_DISABLED 0x80000000 @@ -77,9 +95,12 @@ typedef enum ObjectFlags { #define CONTAINER_FLAG_LOCKED 0x02000000 #define DOOR_FLAG_LOCKED 0x02000000 -#define CRITTER_MANEUVER_0x01 0x01 -#define CRITTER_MANEUVER_STOP_ATTACKING 0x02 -#define CRITTER_MANUEVER_FLEEING 0x04 +typedef enum CritterManeuver { + CRITTER_MANEUVER_NONE = 0, + CRITTER_MANEUVER_0x01 = 0x01, + CRITTER_MANEUVER_STOP_ATTACKING = 0x02, + CRITTER_MANUEVER_FLEEING = 0x04, +} CritterManeuver; typedef enum Dam { DAM_KNOCKED_OUT = 0x01, @@ -178,18 +199,18 @@ typedef struct DoorSceneryData { } DoorSceneryData; typedef struct StairsSceneryData { - int field_0; // obj_pudg.pudstairs.destMap - int field_4; // obj_pudg.pudstairs.destBuiltTile + int destinationMap; // obj_pudg.pudstairs.destMap + int destinationBuiltTile; // obj_pudg.pudstairs.destBuiltTile } StairsSceneryData; typedef struct ElevatorSceneryData { - int field_0; // obj_pudg.pudelevator.elevType - int field_4; // obj_pudg.pudelevator.elevLevel + int type; + int level; } ElevatorSceneryData; typedef struct LadderSceneryData { - int field_0; - int field_4; + int destinationMap; + int destinationBuiltTile; } LadderSceneryData; typedef union SceneryObjectData { @@ -252,4 +273,30 @@ typedef struct ObjectListNode { struct ObjectListNode* next; } ObjectListNode; +#define BUILT_TILE_TILE_MASK 0x3FFFFFF +#define BUILT_TILE_ELEVATION_MASK 0xE0000000 +#define BUILT_TILE_ELEVATION_SHIFT 29 +#define BUILT_TILE_ROTATION_MASK 0x1C000000 +#define BUILT_TILE_ROTATION_SHIFT 26 + +static inline int builtTileGetTile(int builtTile) +{ + return builtTile & BUILT_TILE_TILE_MASK; +} + +static inline int builtTileGetElevation(int builtTile) +{ + return (builtTile & BUILT_TILE_ELEVATION_MASK) >> BUILT_TILE_ELEVATION_SHIFT; +} + +static inline int builtTileGetRotation(int builtTile) +{ + return (builtTile & BUILT_TILE_ROTATION_MASK) >> BUILT_TILE_ROTATION_SHIFT; +} + +static inline int builtTileCreate(int tile, int elevation) +{ + return tile | ((elevation << BUILT_TILE_ELEVATION_SHIFT) & BUILT_TILE_ELEVATION_MASK); +} + #endif /* OBJ_TYPES_H */ diff --git a/src/object.cc b/src/object.cc index 6e92e73..329206e 100644 --- a/src/object.cc +++ b/src/object.cc @@ -332,7 +332,7 @@ int objectsInit(unsigned char* buf, int width, int height, int pitch) gObjectsWindowBufferSize = height * width; gObjectsWindowPitch = pitch; - dudeFid = buildFid(1, _art_vault_guy_num, 0, 0, 0); + dudeFid = buildFid(OBJ_TYPE_CRITTER, _art_vault_guy_num, 0, 0, 0); objectCreateWithFidPid(&gDude, dudeFid, 0x1000000); gDude->flags |= OBJECT_FLAG_0x400; @@ -346,7 +346,7 @@ int objectsInit(unsigned char* buf, int width, int height, int pitch) exit(1); } - eggFid = buildFid(6, 2, 0, 0, 0); + eggFid = buildFid(OBJ_TYPE_INTERFACE, 2, 0, 0, 0); objectCreateWithFidPid(&gEgg, eggFid, -1); gEgg->flags |= OBJECT_FLAG_0x400; gEgg->flags |= OBJECT_TEMPORARY; @@ -437,13 +437,13 @@ int objectRead(Object* obj, File* stream) } if (obj->pid < 0x5000010 || obj->pid > 0x5000017) { - if ((obj->pid >> 24) == 0 && !(gMapHeader.flags & 0x01)) { + if (PID_TYPE(obj->pid) == 0 && !(gMapHeader.flags & 0x01)) { _object_fix_weapon_ammo(obj); } } else { if (obj->data.misc.map <= 0) { if ((obj->fid & 0xFFF) < 33) { - obj->fid = buildFid(5, (obj->fid & 0xFFF) + 16, (obj->fid & 0xFF0000) >> 16, 0, 0); + obj->fid = buildFid(OBJ_TYPE_MISC, (obj->fid & 0xFFF) + 16, FID_ANIM_TYPE(obj->fid), 0, 0); } } } @@ -544,7 +544,7 @@ static int objectLoadAllInternal(File* stream) _obj_insert(objectListNode); - if ((objectListNode->obj->flags & OBJECT_FLAG_0x400) && (objectListNode->obj->flags >> 24) == OBJ_TYPE_CRITTER && objectListNode->obj->pid != 18000) { + if ((objectListNode->obj->flags & OBJECT_FLAG_0x400) && PID_TYPE(objectListNode->obj->pid) == OBJ_TYPE_CRITTER && objectListNode->obj->pid != 18000) { objectListNode->obj->flags &= ~OBJECT_FLAG_0x400; } @@ -619,7 +619,7 @@ static void _obj_fix_combat_cid_for_dude() // 0x48911C static void _object_fix_weapon_ammo(Object* obj) { - if ((obj->pid >> 24) != OBJ_TYPE_ITEM) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_ITEM) { return; } @@ -641,7 +641,7 @@ static void _object_fix_weapon_ammo(Object* obj) obj->data.item.weapon.ammoQuantity = proto->item.data.weapon.ammoCapacity; } } else { - if ((obj->pid >> 24) == OBJ_TYPE_MISC) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_MISC) { // FIXME: looks like this code in unreachable charges = obj->data.item.misc.charges; if (charges == 0xCCCCCCCC) { @@ -723,7 +723,7 @@ int objectSaveAll(File* stream) CritterCombatData* combatData = NULL; Object* whoHitMe = NULL; - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { combatData = &(object->data.critter.combat); whoHitMe = combatData->whoHitMe; if (whoHitMe != 0) { @@ -739,7 +739,7 @@ int objectSaveAll(File* stream) return -1; } - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { combatData->whoHitMe = whoHitMe; } @@ -965,7 +965,7 @@ int objectCreateWithFidPid(Object** objectPtr, int fid, int pid) objectListNode->obj->pid = pid; objectListNode->obj->id = scriptsNewObjectId(); - if (pid == -1 || (pid >> 24) == OBJ_TYPE_TILE) { + if (pid == -1 || PID_TYPE(pid) == OBJ_TYPE_TILE) { Inventory* inventory = &(objectListNode->obj->data.inventory); inventory->length = 0; inventory->items = NULL; @@ -1451,7 +1451,7 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) } if (isInCombat()) { - if ((obj->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_CRITTER) { bool v8 = obj->outline != 0 && (obj->outline & OUTLINE_DISABLED) == 0; _combat_update_critter_outline_for_los(obj, v8); } @@ -1471,7 +1471,7 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) } if (elevation == elev) { - if ((obj->fid & 0xF000000) >> 24 == OBJ_TYPE_MISC) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_MISC) { if (obj->pid >= 0x5000010 && obj->pid <= 0x5000017) { ObjectData* data = &(obj->data); @@ -1498,9 +1498,9 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) int v15 = tile / 200 / 2; if (v14 != _obj_last_roof_x || v15 != _obj_last_roof_y || elevation != _obj_last_elev) { int v16 = _square[elevation]->field_0[v14 + 100 * v15]; - int v31 = buildFid(4, (v16 >> 16) & 0xFFF, 0, 0, 0); + int v31 = buildFid(OBJ_TYPE_TILE, (v16 >> 16) & 0xFFF, 0, 0, 0); int v32 = _square[elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y]; - int v34 = buildFid(4, 1, 0, 0, 0) == v31; + int v34 = buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) == v31; if (v34 != _obj_last_is_empty || (((v16 >> 16) & 0xF000) >> 12) != (((v32 >> 16) & 0xF000) >> 12)) { if (_obj_last_is_empty == 0) { @@ -1538,7 +1538,7 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) } } } else { - if (elevation != _obj_last_elev && (obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (elevation != _obj_last_elev && PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { _combat_delete_critter(obj); } } @@ -1549,8 +1549,8 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect) // 0x48A9A0 int _obj_reset_roof() { - int fid = buildFid(4, (_square[gDude->elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y] >> 16) & 0xFFF, 0, 0, 0); - if (fid != buildFid(4, 1, 0, 0, 0)) { + int fid = buildFid(OBJ_TYPE_TILE, (_square[gDude->elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y] >> 16) & 0xFFF, 0, 0, 0); + if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { _tile_fill_roof(_obj_last_roof_x, _obj_last_roof_y, gDude->elevation, 1); } return 0; @@ -2100,13 +2100,13 @@ bool _obj_action_can_use(Object* obj) // 0x48B278 bool _obj_action_can_talk_to(Object* obj) { - return _proto_action_can_talk_to(obj->pid) && ((obj->pid >> 24) == OBJ_TYPE_CRITTER) && critterIsActive(obj); + return _proto_action_can_talk_to(obj->pid) && (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) && critterIsActive(obj); } // 0x48B2A8 bool _obj_portal_is_walk_thru(Object* obj) { - if ((obj->pid >> 24) != OBJ_TYPE_SCENERY) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_SCENERY) { return false; } @@ -2207,7 +2207,7 @@ Object* objectFindFirst() } while (objectListNode != NULL) { - if (artIsObjectTypeHidden((objectListNode->obj->fid & 0xF000000) >> 24) == 0) { + if (artIsObjectTypeHidden(FID_TYPE(objectListNode->obj->fid)) == 0) { gObjectFindLastObjectListNode = objectListNode; return objectListNode->obj; } @@ -2234,7 +2234,7 @@ Object* objectFindNext() while (objectListNode != NULL) { Object* object = objectListNode->obj; - if (!artIsObjectTypeHidden((object->fid & 0xF000000) >> 24)) { + if (!artIsObjectTypeHidden(FID_TYPE(object->fid))) { gObjectFindLastObjectListNode = objectListNode; return object; } @@ -2257,7 +2257,7 @@ Object* objectFindFirstAtElevation(int elevation) while (objectListNode != NULL) { Object* object = objectListNode->obj; if (object->elevation == elevation) { - if (!artIsObjectTypeHidden((object->fid & 0xF000000) >> 24)) { + if (!artIsObjectTypeHidden(FID_TYPE(object->fid))) { gObjectFindLastObjectListNode = objectListNode; return object; } @@ -2287,7 +2287,7 @@ Object* objectFindNextAtElevation() while (objectListNode != NULL) { Object* object = objectListNode->obj; if (object->elevation == gObjectFindElevation) { - if (!artIsObjectTypeHidden((object->fid & 0xF000000) >> 24)) { + if (!artIsObjectTypeHidden(FID_TYPE(object->fid))) { gObjectFindLastObjectListNode = objectListNode; return object; } @@ -2310,7 +2310,7 @@ Object* objectFindFirstAtLocation(int elevation, int tile) while (objectListNode != NULL) { Object* object = objectListNode->obj; if (object->elevation == elevation) { - if (!artIsObjectTypeHidden((object->fid & 0xF000000) >> 24)) { + if (!artIsObjectTypeHidden(FID_TYPE(object->fid))) { gObjectFindLastObjectListNode = objectListNode; return object; } @@ -2334,7 +2334,7 @@ Object* objectFindNextAtLocation() while (objectListNode != NULL) { Object* object = objectListNode->obj; if (object->elevation == gObjectFindElevation) { - if (!artIsObjectTypeHidden((object->fid & 0xF000000) >> 24)) { + if (!artIsObjectTypeHidden(FID_TYPE(object->fid))) { gObjectFindLastObjectListNode = objectListNode; return object; } @@ -2449,7 +2449,7 @@ Object* _obj_blocking_at(Object* a1, int tile, int elev) v7 = objectListNode->obj; if (v7->elevation == elev) { if ((v7->flags & OBJECT_HIDDEN) == 0 && (v7->flags & OBJECT_NO_BLOCK) == 0 && v7 != a1) { - type = (v7->fid & 0xF000000) >> 24; + type = FID_TYPE(v7->fid); if (type == OBJ_TYPE_CRITTER || type == OBJ_TYPE_SCENERY || type == OBJ_TYPE_WALL) { @@ -2469,7 +2469,7 @@ Object* _obj_blocking_at(Object* a1, int tile, int elev) 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 = (v7->fid & 0xF000000) >> 24; + type = FID_TYPE(v7->fid); if (type == OBJ_TYPE_CRITTER || type == OBJ_TYPE_SCENERY || type == OBJ_TYPE_WALL) { @@ -2499,7 +2499,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev) 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) { - int type = (candidate->fid & 0xF000000) >> 24; + int type = FID_TYPE(candidate->fid); // SFALL: Fix to prevent corpses from blocking line of fire. if ((type == OBJ_TYPE_CRITTER && !critterIsDead(candidate)) || type == OBJ_TYPE_SCENERY @@ -2524,7 +2524,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev) if ((flags & OBJECT_MULTIHEX) != 0) { if (candidate->elevation == elev) { if ((flags & OBJECT_HIDDEN) == 0 && (flags & OBJECT_NO_BLOCK) == 0 && candidate != obj) { - int type = (candidate->fid & 0xF000000) >> 24; + int type = FID_TYPE(candidate->fid); // SFALL: Fix to prevent corpses from blocking line of // fire. if ((type == OBJ_TYPE_CRITTER && !critterIsDead(candidate)) @@ -2556,7 +2556,7 @@ Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation) if ((object->flags & OBJECT_HIDDEN) == 0 && (object->flags & OBJECT_NO_BLOCK) == 0 && object != a1) { - int objectType = (object->fid & 0xF000000) >> 24; + int objectType = FID_TYPE(object->fid); if (objectType == OBJ_TYPE_CRITTER || objectType == OBJ_TYPE_SCENERY || objectType == OBJ_TYPE_WALL) { @@ -2585,7 +2585,7 @@ Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation) if ((object->flags & OBJECT_HIDDEN) == 0 && (object->flags & OBJECT_NO_BLOCK) == 0 && object != a1) { - int objectType = (object->fid & 0xF000000) >> 24; + int objectType = FID_TYPE(object->fid); if (objectType == OBJ_TYPE_CRITTER || objectType == OBJ_TYPE_SCENERY || objectType == OBJ_TYPE_WALL) { @@ -2639,7 +2639,7 @@ Object* _obj_sight_blocking_at(Object* a1, int tile, int elevation) && (object->flags & OBJECT_HIDDEN) == 0 && (object->flags & OBJECT_LIGHT_THRU) == 0 && object != a1) { - int objectType = (object->fid & 0xF000000) >> 24; + int objectType = FID_TYPE(object->fid); if (objectType == OBJ_TYPE_SCENERY || objectType == OBJ_TYPE_WALL) { return object; } @@ -2713,7 +2713,7 @@ int objectListCreate(int tile, int elevation, int objectType, Object*** objectLi Object* obj = objectListNode->obj; if ((obj->flags & OBJECT_HIDDEN) == 0 && obj->elevation == elevation - && ((obj->fid & 0xF000000) >> 24) == objectType) { + && FID_TYPE(obj->fid) == objectType) { count++; } objectListNode = objectListNode->next; @@ -2725,7 +2725,7 @@ int objectListCreate(int tile, int elevation, int objectType, Object*** objectLi Object* obj = objectListNode->obj; if ((obj->flags & OBJECT_HIDDEN) == 0 && obj->elevation == elevation - && ((objectListNode->obj->fid & 0xF000000) >> 24) == objectType) { + && FID_TYPE(objectListNode->obj->fid) == objectType) { count++; } objectListNode = objectListNode->next; @@ -2748,7 +2748,7 @@ int objectListCreate(int tile, int elevation, int objectType, Object*** objectLi Object* obj = objectListNode->obj; if ((obj->flags & OBJECT_HIDDEN) == 0 && obj->elevation == elevation - && ((obj->fid & 0xF000000) >> 24) == objectType) { + && FID_TYPE(obj->fid) == objectType) { *objects++ = obj; } objectListNode = objectListNode->next; @@ -2760,7 +2760,7 @@ int objectListCreate(int tile, int elevation, int objectType, Object*** objectLi Object* obj = objectListNode->obj; if ((obj->flags & OBJECT_HIDDEN) == 0 && obj->elevation == elevation - && ((obj->fid & 0xF000000) >> 24) == objectType) { + && FID_TYPE(obj->fid) == objectType) { *objects++ = obj; } objectListNode = objectListNode->next; @@ -3003,7 +3003,7 @@ int _obj_intersects_with(Object* object, int x, int y) flags |= 0x02; } } else { - int type = (object->fid & 0xF000000) >> 24; + int type = FID_TYPE(object->fid); if (type == OBJ_TYPE_SCENERY || type == OBJ_TYPE_WALL) { Proto* proto; protoGetProto(object->pid, &proto); @@ -3064,7 +3064,7 @@ int _obj_create_intersect_list(int x, int y, int elevation, int objectType, Obje } if (object->elevation == elevation - && (objectType == -1 || (object->fid & 0xF000000) >> 24 == objectType) + && (objectType == -1 || FID_TYPE(object->fid) == objectType) && object != gEgg) { int flags = _obj_intersects_with(object, x, y); if (flags != 0) { @@ -3164,7 +3164,7 @@ void _obj_process_seen() // 0x48C8E4 char* objectGetName(Object* obj) { - int objectType = (obj->fid & 0xF000000) >> 24; + int objectType = FID_TYPE(obj->fid); switch (objectType) { case OBJ_TYPE_ITEM: return itemGetName(obj); @@ -3178,7 +3178,7 @@ char* objectGetName(Object* obj) // 0x48C914 char* objectGetDescription(Object* obj) { - if (((obj->fid & 0xF000000) >> 24) == OBJ_TYPE_ITEM) { + if (FID_TYPE(obj->fid) == OBJ_TYPE_ITEM) { return itemGetDescription(obj); } @@ -3226,13 +3226,13 @@ void _obj_preload_art_cache(int flags) int v11 = gObjectFidsLength; int v12 = gObjectFidsLength; - if ((gObjectFids[v12 - 1] & 0xF000000) >> 24 == 3) { - int v13 = 0; + if (FID_TYPE(gObjectFids[v12 - 1]) == OBJ_TYPE_WALL) { + int objectType = OBJ_TYPE_ITEM; do { v11--; - v13 = (gObjectFids[v12 - 1] & 0xF000000) >> 24; + objectType = FID_TYPE(gObjectFids[v12 - 1]); v12--; - } while (v13 == 3); + } while (objectType == OBJ_TYPE_WALL); v11++; } @@ -3251,7 +3251,7 @@ void _obj_preload_art_cache(int flags) for (int i = 0; i < 4096; i++) { if (arr[i] != 0) { - int fid = buildFid(4, i, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_TILE, i, 0, 0, 0); if (artLock(fid, &cache_handle) != NULL) { artUnlock(cache_handle); } @@ -3543,7 +3543,7 @@ static int _obj_save_obj(File* stream, Object* object) CritterCombatData* combatData = NULL; Object* whoHitMe = NULL; - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { combatData = &(object->data.critter.combat); whoHitMe = combatData->whoHitMe; if (whoHitMe != 0) { @@ -3559,7 +3559,7 @@ static int _obj_save_obj(File* stream, Object* object) return -1; } - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { combatData->whoHitMe = whoHitMe; } @@ -4602,7 +4602,7 @@ static int _obj_adjust_light(Object* obj, int a2, Rect* rect) v14 = (objectListNode->obj->flags & OBJECT_LIGHT_THRU) == 0; - if ((objectListNode->obj->fid & 0xF000000) >> 24 == OBJ_TYPE_WALL) { + if (FID_TYPE(objectListNode->obj->fid) == OBJ_TYPE_WALL) { if ((objectListNode->obj->flags & OBJECT_FLAT) == 0) { Proto* proto; protoGetProto(objectListNode->obj->pid, &proto); @@ -4933,7 +4933,7 @@ static void objectDrawOutline(Object* object, Rect* rect) // 0x48F1B0 static void _obj_render_object(Object* object, Rect* rect, int light) { - int type = (object->fid & 0xF000000) >> 24; + int type = FID_TYPE(object->fid); if (artIsObjectTypeHidden(type)) { return; } @@ -5146,7 +5146,7 @@ static void _obj_render_object(Object* object, Rect* rect, int light) // 0x48FA14 void _obj_fix_violence_settings(int* fid) { - if ((*fid >> 24) != OBJ_TYPE_CRITTER) { + if (FID_TYPE(*fid) != OBJ_TYPE_CRITTER) { return; } @@ -5181,12 +5181,12 @@ void _obj_fix_violence_settings(int* fid) break; } - int anim = (*fid & 0xFF0000) >> 16; + int anim = FID_ANIM_TYPE(*fid); if (anim >= start && anim <= end) { anim = (anim == ANIM_FALL_BACK_BLOOD_SF) ? ANIM_FALL_BACK_SF : ANIM_FALL_FRONT_SF; - *fid = buildFid(1, *fid & 0xFFF, anim, (*fid & 0xF000) >> 12, (*fid & 0x70000000) >> 28); + *fid = buildFid(OBJ_TYPE_CRITTER, *fid & 0xFFF, anim, (*fid & 0xF000) >> 12, (*fid & 0x70000000) >> 28); } if (shouldResetViolenceLevel) { @@ -5200,8 +5200,8 @@ static int _obj_preload_sort(const void* a1, const void* a2) int v1 = *(int*)a1; int v2 = *(int*)a2; - int v3 = _cd_order[(v1 & 0xF000000) >> 24]; - int v4 = _cd_order[(v2 & 0xF000000) >> 24]; + int v3 = _cd_order[FID_TYPE(v1)]; + int v4 = _cd_order[FID_TYPE(v2)]; int cmp = v3 - v4; if (cmp != 0) { diff --git a/src/options.cc b/src/options.cc index def7ba9..c6fdf9d 100644 --- a/src/options.cc +++ b/src/options.cc @@ -574,7 +574,7 @@ static int optionsWindowInit() } for (int index = 0; index < OPTIONS_WINDOW_FRM_COUNT; index++) { - int fid = buildFid(6, gOptionsWindowFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gOptionsWindowFrmIds[index], 0, 0, 0); gOptionsWindowFrmData[index] = artLockFrameDataReturningSize(fid, &(gOptionsWindowFrmHandles[index]), &(gOptionsWindowFrmSizes[index].width), &(gOptionsWindowFrmSizes[index].height)); if (gOptionsWindowFrmData[index] == NULL) { @@ -730,7 +730,7 @@ int showPause(bool a1) _ShadeScreen(a1); for (int index = 0; index < PAUSE_WINDOW_FRM_COUNT; index++) { - int fid = buildFid(6, graphicIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, graphicIds[index], 0, 0, 0); frmData[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height)); if (frmData[index] == NULL) { while (--index >= 0) { @@ -1498,7 +1498,7 @@ static int preferencesWindowInit() _SaveSettings(); for (i = 0; i < PREFERENCES_WINDOW_FRM_COUNT; i++) { - fid = buildFid(6, gPreferencesWindowFrmIds[i], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, gPreferencesWindowFrmIds[i], 0, 0, 0); gPreferencesWindowFrmData[i] = artLockFrameDataReturningSize(fid, &(gPreferencesWindowFrmHandles[i]), &(gPreferencesWindowFrmSizes[i].width), &(gPreferencesWindowFrmSizes[i].height)); if (gPreferencesWindowFrmData[i] == NULL) { for (; i != 0; i--) { @@ -2064,3 +2064,9 @@ static void _DoThing(int eventCode) _changed = true; } + +// 0x48FC48 +int _do_options() +{ + return showOptionsWithInitialKeyCode(-1); +} diff --git a/src/options.h b/src/options.h index c64e1b2..e91120e 100644 --- a/src/options.h +++ b/src/options.h @@ -29,5 +29,6 @@ int preferencesSave(File* stream); int preferencesLoad(File* stream); void brightnessIncrease(); void brightnessDecrease(); +int _do_options(); #endif /* OPTIONS_H */ diff --git a/src/party_member.cc b/src/party_member.cc index a29ed05..200bce8 100644 --- a/src/party_member.cc +++ b/src/party_member.cc @@ -1,9 +1,9 @@ #include "party_member.h" -#include "combat_ai.h" -#include "combat_ai_defs.h" #include "animation.h" #include "color.h" +#include "combat_ai.h" +#include "combat_ai_defs.h" #include "config.h" #include "critter.h" #include "debug.h" @@ -558,7 +558,7 @@ static int _partyMemberPrepLoadInstance(STRUCT_519DA8* a1) return 0; } - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { obj->data.critter.combat.whoHitMe = NULL; } @@ -605,7 +605,7 @@ static int _partyMemberPrepLoadInstance(STRUCT_519DA8* a1) scriptRemove(script->sid); - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { _dude_stand(obj, obj->rotation, -1); } @@ -660,7 +660,7 @@ static int _partyMemberRecoverLoadInstance(STRUCT_519DA8* a1) } int scriptType = SCRIPT_TYPE_CRITTER; - if ((a1->object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(a1->object->pid) != OBJ_TYPE_CRITTER) { scriptType = SCRIPT_TYPE_ITEM; } @@ -791,7 +791,7 @@ int _partyMemberSyncPosition() for (int index = 1; index < gPartyMembersLength; index++) { STRUCT_519DA8* partyMember = &(gPartyMembers[index]); Object* partyMemberObj = partyMember->object; - if ((partyMemberObj->flags & OBJECT_HIDDEN) == 0 && (partyMemberObj->pid >> 24) == OBJ_TYPE_CRITTER) { + if ((partyMemberObj->flags & OBJECT_HIDDEN) == 0 && PID_TYPE(partyMemberObj->pid) == OBJ_TYPE_CRITTER) { int rotation; if ((n % 2) != 0) { rotation = clockwiseRotation; @@ -822,7 +822,7 @@ int _partyMemberRestingHeal(int a1) for (int index = 0; index < gPartyMembersLength; index++) { STRUCT_519DA8* partyMember = &(gPartyMembers[index]); - if ((partyMember->object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(partyMember->object->pid) == OBJ_TYPE_CRITTER) { int healingRate = critterGetStat(partyMember->object, STAT_HEALING_RATE); critterAdjustHitPoints(partyMember->object, v1 * healingRate); } @@ -892,7 +892,7 @@ int _getPartyMemberCount() for (int index = 1; index < gPartyMembersLength; index++) { Object* object = gPartyMembers[index].object; - if ((object->pid >> 24) != OBJ_TYPE_CRITTER || critterIsDead(object) || (object->flags & OBJECT_HIDDEN) != 0) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER || critterIsDead(object) || (object->flags & OBJECT_HIDDEN) != 0) { count--; } } @@ -1126,7 +1126,7 @@ int partyMemberGetBestSkill(Object* object) return bestSkill; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return bestSkill; } @@ -1152,7 +1152,7 @@ Object* partyMemberGetBestInSkill(int skill) for (int index = 0; index < gPartyMembersLength; index++) { Object* object = gPartyMembers[index].object; - if ((object->flags & OBJECT_HIDDEN) == 0 && (object->pid >> 24) == OBJ_TYPE_CRITTER) { + if ((object->flags & OBJECT_HIDDEN) == 0 && PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { int value = skillGetValue(object, skill); if (value > bestValue) { bestValue = value; @@ -1173,7 +1173,7 @@ int partyGetBestSkillValue(int skill) for (int index = 0; index < gPartyMembersLength; index++) { Object* object = gPartyMembers[index].object; - if ((object->flags & OBJECT_HIDDEN) == 0 && (object->pid >> 24) == OBJ_TYPE_CRITTER) { + if ((object->flags & OBJECT_HIDDEN) == 0 && PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { int value = skillGetValue(object, skill); if (value > bestValue) { bestValue = value; @@ -1191,7 +1191,7 @@ static int _partyFixMultipleMembers() int critterCount = 0; for (Object* obj = objectFindFirst(); obj != NULL; obj = objectFindNext()) { - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { critterCount++; } @@ -1294,7 +1294,7 @@ bool partyMemberSupportsDisposition(Object* critter, int disposition) return false; } - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1317,7 +1317,7 @@ bool partyMemberSupportsAreaAttackMode(Object* object, int areaAttackMode) return false; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1340,7 +1340,7 @@ bool partyMemberSupportsRunAwayMode(Object* object, int runAwayMode) return false; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1363,7 +1363,7 @@ bool partyMemberSupportsBestWeapon(Object* object, int bestWeapon) return false; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1386,7 +1386,7 @@ bool partyMemberSupportsDistance(Object* object, int distanceMode) return false; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1409,7 +1409,7 @@ bool partyMemberSupportsAttackWho(Object* object, int attackWho) return false; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1432,7 +1432,7 @@ bool partyMemberSupportsChemUse(Object* object, int chemUse) return false; } - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) { return false; } @@ -1475,7 +1475,7 @@ int _partyMemberIncLevels() break; } - if ((obj->pid >> 24) != 1) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { continue; } @@ -1623,7 +1623,7 @@ bool partyIsAnyoneCanBeHealedByRest() STRUCT_519DA8* ptr = &(gPartyMembers[index]); Object* object = ptr->object; - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) continue; + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) continue; if (critterIsDead(object)) continue; if ((object->flags & OBJECT_HIDDEN) != 0) continue; if (critterGetKillType(object) == KILL_TYPE_ROBOT) continue; @@ -1650,7 +1650,7 @@ int partyGetMaxWoundToHealByRest() STRUCT_519DA8* ptr = &(gPartyMembers[index]); Object* object = ptr->object; - if ((object->pid >> 24) != OBJ_TYPE_CRITTER) continue; + if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) continue; if (critterIsDead(object)) continue; if ((object->flags & OBJECT_HIDDEN) != 0) continue; if (critterGetKillType(object) == KILL_TYPE_ROBOT) continue; diff --git a/src/pcx.cc b/src/pcx.cc new file mode 100644 index 0000000..c3ea7bf --- /dev/null +++ b/src/pcx.cc @@ -0,0 +1,178 @@ +#include "pcx.h" + +#include "memory_manager.h" + +// 0x519DC8 +unsigned char gPcxLastRunLength = 0; + +// 0x519DC9 +unsigned char gPcxLastValue = 0; + +// NOTE: The reading method in this function is a little bit odd. It does not +// use high level reading functions, which can read right into struct. Instead +// they read everything into temporary variables. There are no error checks. +// +// 0x4961D4 +void pcxReadHeader(PcxHeader* pcxHeader, File* stream) +{ + pcxHeader->identifier = fileReadChar(stream); + pcxHeader->version = fileReadChar(stream); + pcxHeader->encoding = fileReadChar(stream); + pcxHeader->bitsPerPixel = fileReadChar(stream); + + short minX; + fileRead(&minX, 2, 1, stream); + pcxHeader->minX = minX; + + short minY; + fileRead(&minY, 2, 1, stream); + pcxHeader->minY = minY; + + short maxX; + fileRead(&maxX, 2, 1, stream); + pcxHeader->maxX = maxX; + + short maxY; + fileRead(&maxY, 2, 1, stream); + pcxHeader->maxY = maxY; + + short horizontalResolution; + fileRead(&horizontalResolution, 2, 1, stream); + pcxHeader->horizontalResolution = horizontalResolution; + + short verticalResolution; + fileRead(&verticalResolution, 2, 1, stream); + pcxHeader->verticalResolution = verticalResolution; + + for (int index = 0; index < 48; index++) { + pcxHeader->palette[index] = fileReadChar(stream); + } + + pcxHeader->reserved1 = fileReadChar(stream); + pcxHeader->planeCount = fileReadChar(stream); + + short bytesPerLine; + fileRead(&bytesPerLine, 2, 1, stream); + pcxHeader->bytesPerLine = bytesPerLine; + + short paletteType; + fileRead(&paletteType, 2, 1, stream); + pcxHeader->paletteType = paletteType; + + short horizontalScreenSize; + fileRead(&horizontalScreenSize, 2, 1, stream); + pcxHeader->horizontalScreenSize = horizontalScreenSize; + + short verticalScreenSize; + fileRead(&verticalScreenSize, 2, 1, stream); + pcxHeader->verticalScreenSize = verticalScreenSize; + + for (int index = 0; index < 54; index++) { + pcxHeader->reserved2[index] = fileReadChar(stream); + } +} + +// 0x49636C +int pcxReadLine(unsigned char* data, int size, File* stream) +{ + unsigned char runLength = gPcxLastRunLength; + unsigned char value = gPcxLastValue; + + int uncompressedSize = 0; + int index = 0; + do { + uncompressedSize += runLength; + while (runLength > 0 && index < size) { + data[index] = value; + runLength--; + index++; + } + + gPcxLastRunLength = runLength; + gPcxLastValue = value; + + if (runLength != 0) { + uncompressedSize -= runLength; + break; + } + + value = fileReadChar(stream); + if ((value & 0xC0) == 0xC0) { + gPcxLastRunLength = value & 0x3F; + value = fileReadChar(stream); + runLength = gPcxLastRunLength; + } else { + runLength = 1; + } + } while (index < size); + + gPcxLastRunLength = runLength; + gPcxLastValue = value; + + return uncompressedSize; +} + +// 0x49641C +int pcxReadPalette(PcxHeader* pcxHeader, unsigned char* palette, File* stream) +{ + if (pcxHeader->version != 5) { + return 0; + } + + long pos = fileTell(stream); + long size = fileGetSize(stream); + fileSeek(stream, size - 769, SEEK_SET); + if (fileReadChar(stream) != 12) { + fileSeek(stream, pos, SEEK_SET); + return 0; + } + + for (int index = 0; index < 768; index++) { + palette[index] = fileReadChar(stream); + } + + fileSeek(stream, pos, SEEK_SET); + + return 1; +} + +// 0x496494 +unsigned char* pcxRead(const char* path, int* widthPtr, int* heightPtr, unsigned char* palette) +{ + File* stream = fileOpen(path, "rb"); + if (stream == NULL) { + return NULL; + } + + PcxHeader pcxHeader; + pcxReadHeader(&pcxHeader, stream); + + int width = pcxHeader.maxX - pcxHeader.minX + 1; + int height = pcxHeader.maxY - pcxHeader.minY + 1; + + *widthPtr = width; + *heightPtr = height; + + int bytesPerLine = pcxHeader.planeCount * pcxHeader.bytesPerLine; + unsigned char* data = (unsigned char*)internal_malloc_safe(bytesPerLine * height, __FILE__, __LINE__); // "..\\int\\PCX.C", 195 + if (data == NULL) { + // NOTE: This code is unreachable, internal_malloc_safe never fails. + fileClose(stream); + return NULL; + } + + gPcxLastRunLength = 0; + gPcxLastValue = 0; + + unsigned char* ptr = data; + for (int y = 0; y < height; y++) { + pcxReadLine(ptr, bytesPerLine, stream); + ptr += width; + } + + pcxReadPalette(&pcxHeader, palette, stream); + + fileClose(stream); + + return data; +} diff --git a/src/pcx.h b/src/pcx.h new file mode 100644 index 0000000..7900048 --- /dev/null +++ b/src/pcx.h @@ -0,0 +1,35 @@ +#ifndef PCX_H +#define PCX_H + +#include "db.h" + +typedef struct PcxHeader { + unsigned char identifier; + unsigned char version; + unsigned char encoding; + unsigned char bitsPerPixel; + short minX; + short minY; + short maxX; + short maxY; + short horizontalResolution; + short verticalResolution; + unsigned char palette[48]; + unsigned char reserved1; + unsigned char planeCount; + short bytesPerLine; + short paletteType; + short horizontalScreenSize; + short verticalScreenSize; + unsigned char reserved2[54]; +} PcxHeader; + +extern unsigned char gPcxLastRunLength; +extern unsigned char gPcxLastValue; + +void pcxReadHeader(PcxHeader* pcxHeader, File* stream); +int pcxReadLine(unsigned char* data, int size, File* stream); +int pcxReadPalette(PcxHeader* pcxHeader, unsigned char* palette, File* stream); +unsigned char* pcxRead(const char* path, int* widthPtr, int* heightPtr, unsigned char* palette); + +#endif /* PCX_H */ diff --git a/src/perk.cc b/src/perk.cc index b45a8b7..9c60dd5 100644 --- a/src/perk.cc +++ b/src/perk.cc @@ -535,7 +535,7 @@ int perkGetFrmId(int perk) // 0x496BFC void perkAddEffect(Object* critter, int perk) { - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { debugPrint("\nERROR: perk_add_effect: Was called on non-critter!"); return; } @@ -575,7 +575,7 @@ void perkAddEffect(Object* critter, int perk) // 0x496CE0 void perkRemoveEffect(Object* critter, int perk) { - if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) { debugPrint("\nERROR: perk_remove_effect: Was called on non-critter!"); return; } diff --git a/src/pipboy.cc b/src/pipboy.cc index 69e8080..362913f 100644 --- a/src/pipboy.cc +++ b/src/pipboy.cc @@ -512,7 +512,7 @@ static int pipboyWindowInit(bool forceRest) int index; for (index = 0; index < PIPBOY_FRM_COUNT; index++) { - int fid = buildFid(6, gPipboyFrmIds[index], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gPipboyFrmIds[index], 0, 0, 0); gPipboyFrmData[index] = artLockFrameDataReturningSize(fid, &(gPipboyFrmHandles[index]), &(gPipboyFrmSizes[index].width), &(gPipboyFrmSizes[index].height)); if (gPipboyFrmData[index] == NULL) { break; @@ -1087,7 +1087,7 @@ static void pipboyWindowHandleStatus(int a1) // Skip quests in the same location. // - // FIXME: This code should be identical to the one in the + // FIXME: This code should be identical to the one in the // `pipboyWindowRenderQuestLocationList`. See buffer overread // bug involved. for (; index < gQuestsCount; index++) { @@ -2013,7 +2013,7 @@ static bool pipboyRest(int hours, int minutes, int duration) rc = true; } - unsigned int v8 = (unsigned int)((double)hour / v7 * (hours * 36000.0) + gameTime); + unsigned int v8 = (unsigned int)((double)hour / v7 * (hours * GAME_TIME_TICKS_PER_HOUR) + gameTime); unsigned int nextEventTime = queueGetNextEventTime(); if (!rc && v8 >= nextEventTime) { gameTimeSetTime(nextEventTime + 1); @@ -2050,7 +2050,7 @@ static bool pipboyRest(int hours, int minutes, int duration) } if (!rc) { - gameTimeSetTime(gameTime + 36000 * hours); + gameTimeSetTime(gameTime + GAME_TIME_TICKS_PER_HOUR * hours); } pipboyDrawNumber(gameTimeGetHour(), 4, PIPBOY_WINDOW_TIME_X, PIPBOY_WINDOW_TIME_Y); diff --git a/src/platform_compat.cc b/src/platform_compat.cc index cf7162f..a46c55b 100644 --- a/src/platform_compat.cc +++ b/src/platform_compat.cc @@ -55,7 +55,7 @@ void compat_splitpath(const char* path, char* drive, char* dir, char* fname, cha #ifdef _WIN32 _splitpath(path, drive, dir, fname, ext); #else - const char *driveStart = path; + const char* driveStart = path; if (path[0] == '/' && path[1] == '/') { path += 2; while (*path != '\0' && *path != '/' && *path != '.') { @@ -130,7 +130,7 @@ void compat_makepath(char* path, const char* drive, const char* dir, const char* if (*drive != '\0') { strcpy(path, drive); path = strchr(path, '\0'); - + if (path[-1] == '/') { path--; } else { diff --git a/src/proto.cc b/src/proto.cc index 1807080..0b7427f 100644 --- a/src/proto.cc +++ b/src/proto.cc @@ -185,17 +185,21 @@ static char** _perk_code_strs; // 0x6648BC static char** _critter_stats_list; +// NOTE: Inlined. +void _proto_make_path(char* path, int pid) +{ + strcpy(path, _cd_path_base); + strcat(path, _proto_path_base); + if (pid != -1) { + strcat(path, artGetObjectTypeName(PID_TYPE(pid))); + } +} + // Append proto file name to proto_path from proto.lst. // // 0x49E758 int _proto_list_str(int pid, char* proto_path) { - char path[COMPAT_MAX_PATH]; - char str[COMPAT_MAX_PATH]; - char* pch; - File* stream; - int i; - if (pid == -1) { return -1; } @@ -204,17 +208,17 @@ int _proto_list_str(int pid, char* proto_path) return -1; } - strcpy(path, _cd_path_base); - strcat(path, "proto\\"); - strcat(path, artGetObjectTypeName(pid >> 24)); + char path[COMPAT_MAX_PATH]; + _proto_make_path(path, pid); strcat(path, "\\"); - strcat(path, artGetObjectTypeName(pid >> 24)); + strcat(path, artGetObjectTypeName(PID_TYPE(pid))); strcat(path, ".lst"); - stream = fileOpen(path, "rt"); + File* stream = fileOpen(path, "rt"); - i = 1; - while (fileReadString(str, sizeof(str), stream)) { + int i = 1; + char string[256]; + while (fileReadString(string, sizeof(string), stream)) { if (i == (pid & 0xFFFFFF)) { break; } @@ -228,14 +232,17 @@ int _proto_list_str(int pid, char* proto_path) return -1; } - pch = str; - while (*pch != '\0' && *pch != '\n') { - *proto_path = *pch; - proto_path++; - pch++; + char* pch = strchr(string, ' '); + if (pch != NULL) { + *pch = '\0'; } - *proto_path = '\0'; + pch = strchr(string, '\n'); + if (pch != NULL) { + *pch = '\0'; + } + + strcpy(proto_path, string); return 0; } @@ -252,7 +259,7 @@ bool _proto_action_can_use(int pid) return true; } - if ((pid >> 24) == OBJ_TYPE_ITEM && proto->item.type == ITEM_TYPE_CONTAINER) { + if (PID_TYPE(pid) == OBJ_TYPE_ITEM && proto->item.type == ITEM_TYPE_CONTAINER) { return true; } @@ -271,7 +278,7 @@ bool _proto_action_can_use_on(int pid) return true; } - if ((pid >> 24) == OBJ_TYPE_ITEM && proto->item.type == ITEM_TYPE_DRUG) { + if (PID_TYPE(pid) == OBJ_TYPE_ITEM && proto->item.type == ITEM_TYPE_DRUG) { return true; } @@ -286,7 +293,7 @@ bool _proto_action_can_talk_to(int pid) return false; } - if ((pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(pid) == OBJ_TYPE_CRITTER) { return true; } @@ -302,7 +309,7 @@ bool _proto_action_can_talk_to(int pid) // 0x49EA5C int _proto_action_can_pickup(int pid) { - if ((pid >> 24) != OBJ_TYPE_ITEM) { + if (PID_TYPE(pid) != OBJ_TYPE_ITEM) { return false; } @@ -326,7 +333,7 @@ char* protoGetMessage(int pid, int message) Proto* proto; if (protoGetProto(pid, &proto) != -1) { if (proto->messageId != -1) { - MessageList* messageList = &(_proto_msg_files[pid >> 24]); + MessageList* messageList = &(_proto_msg_files[PID_TYPE(pid)]); MessageListItem messageListItem; messageListItem.num = proto->messageId + message; @@ -366,7 +373,7 @@ static int _proto_critter_init(Proto* a1, int a2) a1->pid = -1; a1->messageId = 100 * v1; - a1->fid = buildFid(1, v1 - 1, 0, 0, 0); + a1->fid = buildFid(OBJ_TYPE_CRITTER, v1 - 1, 0, 0, 0); a1->critter.lightDistance = 0; a1->critter.lightIntensity = 0; a1->critter.flags = 0x20000000; @@ -377,7 +384,7 @@ static int _proto_critter_init(Proto* a1, int a2) a1->critter.headFid = -1; a1->critter.aiPacket = 1; if (!artExists(a1->fid)) { - a1->fid = buildFid(1, 0, 0, 0, 0); + a1->fid = buildFid(OBJ_TYPE_CRITTER, 0, 0, 0, 0); } CritterProtoData* data = &(a1->critter.data); @@ -437,7 +444,7 @@ int objectDataRead(Object* obj, File* stream) // TODO: See below. if (fileReadInt32(stream, (int*)&(inventory->items)) == -1) return -1; - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { if (fileReadInt32(stream, &(obj->data.critter.field_0)) == -1) return -1; if (objectCritterCombatDataRead(&(obj->data.critter.combat), stream) == -1) return -1; if (fileReadInt32(stream, &(obj->data.critter.hp)) == -1) return -1; @@ -451,7 +458,7 @@ int objectDataRead(Object* obj, File* stream) obj->data.flags = 0; } - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: if (protoGetProto(obj->pid, &proto) == -1) return -1; @@ -482,27 +489,27 @@ int objectDataRead(Object* obj, File* stream) if (fileReadInt32(stream, &(obj->data.scenery.door.openFlags)) == -1) return -1; break; case SCENERY_TYPE_STAIRS: - if (fileReadInt32(stream, &(obj->data.scenery.stairs.field_4)) == -1) return -1; - if (fileReadInt32(stream, &(obj->data.scenery.stairs.field_0)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.stairs.destinationBuiltTile)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.stairs.destinationMap)) == -1) return -1; break; case SCENERY_TYPE_ELEVATOR: - if (fileReadInt32(stream, &(obj->data.scenery.elevator.field_0)) == -1) return -1; - if (fileReadInt32(stream, &(obj->data.scenery.elevator.field_4)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.elevator.type)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.elevator.level)) == -1) return -1; break; case SCENERY_TYPE_LADDER_UP: if (gMapHeader.version == 19) { - if (fileReadInt32(stream, &(obj->data.scenery.ladder.field_4)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.ladder.destinationBuiltTile)) == -1) return -1; } else { - if (fileReadInt32(stream, &(obj->data.scenery.ladder.field_0)) == -1) return -1; - if (fileReadInt32(stream, &(obj->data.scenery.ladder.field_4)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.ladder.destinationMap)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.ladder.destinationBuiltTile)) == -1) return -1; } break; case SCENERY_TYPE_LADDER_DOWN: if (gMapHeader.version == 19) { - if (fileReadInt32(stream, &(obj->data.scenery.ladder.field_4)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.ladder.destinationBuiltTile)) == -1) return -1; } else { - if (fileReadInt32(stream, &(obj->data.scenery.ladder.field_0)) == -1) return -1; - if (fileReadInt32(stream, &(obj->data.scenery.ladder.field_4)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.ladder.destinationMap)) == -1) return -1; + if (fileReadInt32(stream, &(obj->data.scenery.ladder.destinationBuiltTile)) == -1) return -1; } break; } @@ -534,7 +541,7 @@ int objectDataWrite(Object* obj, File* stream) // this field is shared with something else. if (fileWriteInt32(stream, (intptr_t)data->inventory.items) == -1) return -1; - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { if (fileWriteInt32(stream, data->flags) == -1) return -1; if (objectCritterCombatDataWrite(&(obj->data.critter.combat), stream) == -1) return -1; if (fileWriteInt32(stream, data->critter.hp) == -1) return -1; @@ -543,7 +550,7 @@ int objectDataWrite(Object* obj, File* stream) } else { if (fileWriteInt32(stream, data->flags) == -1) return -1; - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: if (protoGetProto(obj->pid, &proto) == -1) return -1; @@ -571,20 +578,20 @@ int objectDataWrite(Object* obj, File* stream) if (fileWriteInt32(stream, data->scenery.door.openFlags) == -1) return -1; break; case SCENERY_TYPE_STAIRS: - if (fileWriteInt32(stream, data->scenery.stairs.field_4) == -1) return -1; - if (fileWriteInt32(stream, data->scenery.stairs.field_0) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.stairs.destinationBuiltTile) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.stairs.destinationMap) == -1) return -1; break; case SCENERY_TYPE_ELEVATOR: - if (fileWriteInt32(stream, data->scenery.elevator.field_0) == -1) return -1; - if (fileWriteInt32(stream, data->scenery.elevator.field_4) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.elevator.type) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.elevator.level) == -1) return -1; break; case SCENERY_TYPE_LADDER_UP: - if (fileWriteInt32(stream, data->scenery.ladder.field_0) == -1) return -1; - if (fileWriteInt32(stream, data->scenery.elevator.field_4) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.ladder.destinationMap) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.ladder.destinationBuiltTile) == -1) return -1; break; case SCENERY_TYPE_LADDER_DOWN: - if (fileWriteInt32(stream, data->scenery.ladder.field_0) == -1) return -1; - if (fileWriteInt32(stream, data->scenery.elevator.field_4) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.ladder.destinationMap) == -1) return -1; + if (fileWriteInt32(stream, data->scenery.ladder.destinationBuiltTile) == -1) return -1; break; default: break; @@ -624,7 +631,7 @@ static int _proto_update_gen(Object* obj) return -1; } - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: switch (proto->item.type) { case ITEM_TYPE_CONTAINER: @@ -651,16 +658,16 @@ static int _proto_update_gen(Object* obj) data->scenery.door.openFlags = proto->scenery.data.door.openFlags; break; case SCENERY_TYPE_STAIRS: - data->scenery.stairs.field_4 = proto->scenery.data.stairs.field_0; - data->scenery.stairs.field_0 = proto->scenery.data.stairs.field_4; + data->scenery.stairs.destinationBuiltTile = proto->scenery.data.stairs.field_0; + data->scenery.stairs.destinationMap = proto->scenery.data.stairs.field_4; break; case SCENERY_TYPE_ELEVATOR: - data->scenery.elevator.field_0 = proto->scenery.data.elevator.field_0; - data->scenery.elevator.field_4 = proto->scenery.data.elevator.field_4; + data->scenery.elevator.type = proto->scenery.data.elevator.type; + data->scenery.elevator.level = proto->scenery.data.elevator.level; break; case SCENERY_TYPE_LADDER_UP: case SCENERY_TYPE_LADDER_DOWN: - data->scenery.ladder.field_0 = proto->scenery.data.ladder.field_0; + data->scenery.ladder.destinationMap = proto->scenery.data.ladder.field_0; break; } break; @@ -698,7 +705,7 @@ int _proto_update_init(Object* obj) obj->field_2C_array[i] = 0; } - if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) { return _proto_update_gen(obj); } @@ -749,11 +756,11 @@ int _proto_dude_update_gender() v1 = (gDude->fid & 0xF000) >> 12; } - int fid = buildFid(1, _art_vault_guy_num, 0, v1, 0); + int fid = buildFid(OBJ_TYPE_CRITTER, _art_vault_guy_num, 0, v1, 0); objectSetFid(gDude, fid, NULL); } - proto->fid = buildFid(1, _art_vault_guy_num, 0, 0, 0); + proto->fid = buildFid(OBJ_TYPE_CRITTER, _art_vault_guy_num, 0, 0, 0); return 0; } @@ -762,7 +769,7 @@ int _proto_dude_update_gender() // 0x49FA64 int _proto_dude_init(const char* path) { - gDudeProto.fid = buildFid(1, _art_vault_guy_num, 0, 0, 0); + gDudeProto.fid = buildFid(OBJ_TYPE_CRITTER, _art_vault_guy_num, 0, 0, 0); if (_init_true) { _obj_inven_free(&(gDude->data.inventory)); @@ -822,7 +829,7 @@ int protoGetDataMember(int pid, int member, ProtoDataMemberValue* value) return -1; } - switch (pid >> 24) { + switch (PID_TYPE(pid)) { case OBJ_TYPE_ITEM: switch (member) { case ITEM_DATA_MEMBER_PID: @@ -1076,7 +1083,7 @@ int protoInit() _proto_critter_init((Proto*)&gDudeProto, 0x1000000); gDudeProto.pid = 0x1000000; - gDudeProto.fid = buildFid(1, 1, 0, 0, 0); + gDudeProto.fid = buildFid(OBJ_TYPE_CRITTER, 1, 0, 0, 0); gDude->pid = 0x1000000; gDude->sid = 1; @@ -1188,7 +1195,7 @@ void protoReset() // TODO: Get rid of cast. _proto_critter_init((Proto*)&gDudeProto, 0x1000000); gDudeProto.pid = 0x1000000; - gDudeProto.fid = buildFid(1, 1, 0, 0, 0); + gDudeProto.fid = buildFid(OBJ_TYPE_CRITTER, 1, 0, 0, 0); gDude->pid = 0x1000000; gDude->sid = -1; @@ -1233,9 +1240,7 @@ static int _proto_header_load() ptr->max_entries_num = 1; char path[COMPAT_MAX_PATH]; - strcpy(path, _cd_path_base); - strcat(path, _proto_path_base); - strcat(path, artGetObjectTypeName(index)); + _proto_make_path(path, index << 24); strcat(path, "\\"); strcat(path, artGetObjectTypeName(index)); strcat(path, ".lst"); @@ -1358,8 +1363,8 @@ static int protoSceneryDataRead(SceneryProtoData* scenery_data, int type, File* return 0; case SCENERY_TYPE_ELEVATOR: - if (fileReadInt32(stream, &(scenery_data->elevator.field_0)) == -1) return -1; - if (fileReadInt32(stream, &(scenery_data->elevator.field_4)) == -1) return -1; + if (fileReadInt32(stream, &(scenery_data->elevator.type)) == -1) return -1; + if (fileReadInt32(stream, &(scenery_data->elevator.level)) == -1) return -1; return 0; case SCENERY_TYPE_LADDER_UP: @@ -1384,7 +1389,7 @@ static int protoRead(Proto* proto, File* stream) if (fileReadInt32(stream, &(proto->messageId)) == -1) return -1; if (fileReadInt32(stream, &(proto->fid)) == -1) return -1; - switch (proto->pid >> 24) { + switch (PID_TYPE(proto->pid)) { case OBJ_TYPE_ITEM: if (fileReadInt32(stream, &(proto->item.lightDistance)) == -1) return -1; if (_db_freadInt(stream, &(proto->item.lightIntensity)) == -1) return -1; @@ -1544,8 +1549,8 @@ static int protoSceneryDataWrite(SceneryProtoData* scenery_data, int type, File* return 0; case SCENERY_TYPE_ELEVATOR: - if (fileWriteInt32(stream, scenery_data->elevator.field_0) == -1) return -1; - if (fileWriteInt32(stream, scenery_data->elevator.field_4) == -1) return -1; + if (fileWriteInt32(stream, scenery_data->elevator.type) == -1) return -1; + if (fileWriteInt32(stream, scenery_data->elevator.level) == -1) return -1; return 0; case SCENERY_TYPE_LADDER_UP: @@ -1569,7 +1574,7 @@ static int protoWrite(Proto* proto, File* stream) if (fileWriteInt32(stream, proto->messageId) == -1) return -1; if (fileWriteInt32(stream, proto->fid) == -1) return -1; - switch (proto->pid >> 24) { + switch (PID_TYPE(proto->pid)) { case OBJ_TYPE_ITEM: if (fileWriteInt32(stream, proto->item.lightDistance) == -1) return -1; if (_db_fwriteLong(stream, proto->item.lightIntensity) == -1) return -1; @@ -1645,13 +1650,7 @@ int _proto_save_pid(int pid) } char path[260]; - strcpy(path, _cd_path_base); - strcat(path, _proto_path_base); - - if (pid != -1) { - strcat(path, artGetObjectTypeName(pid >> 24)); - } - + _proto_make_path(path, pid); strcat(path, "\\"); _proto_list_str(pid, path + strlen(path)); @@ -1672,14 +1671,7 @@ int _proto_save_pid(int pid) static int _proto_load_pid(int pid, Proto** protoPtr) { char path[COMPAT_MAX_PATH]; - strcpy(path, _cd_path_base); - - strcat(path, "proto\\"); - - if (pid != -1) { - strcat(path, artGetObjectTypeName(pid >> 24)); - } - + _proto_make_path(path, pid); strcat(path, "\\"); if (_proto_list_str(pid, path + strlen(path)) == -1) { @@ -1693,7 +1685,7 @@ static int _proto_load_pid(int pid, Proto** protoPtr) return -1; } - if (_proto_find_free_subnode(pid >> 24, protoPtr) == -1) { + if (_proto_find_free_subnode(PID_TYPE(pid), protoPtr) == -1) { fileClose(stream); return -1; } @@ -1826,7 +1818,7 @@ int protoGetProto(int pid, Proto** protoPtr) return 0; } - ProtoList* protoList = &(_protoLists[pid >> 24]); + ProtoList* protoList = &(_protoLists[PID_TYPE(pid)]); ProtoListExtent* protoListExtent = protoList->head; while (protoListExtent != NULL) { for (int index = 0; index < protoListExtent->length; index++) { @@ -1841,7 +1833,7 @@ int protoGetProto(int pid, Proto** protoPtr) if (protoList->head != NULL && protoList->tail != NULL) { if (PROTO_LIST_EXTENT_SIZE * protoList->length - (PROTO_LIST_EXTENT_SIZE - protoList->tail->length) > PROTO_LIST_MAX_ENTRIES) { - _proto_remove_some_list(pid >> 24); + _proto_remove_some_list(PID_TYPE(pid)); } } diff --git a/src/proto.h b/src/proto.h index a3ea9bc..9c18257 100644 --- a/src/proto.h +++ b/src/proto.h @@ -100,6 +100,7 @@ extern char _cd_path_base[COMPAT_MAX_PATH]; extern MessageList gProtoMessageList; extern char* _proto_none_str; +void _proto_make_path(char* path, int pid); int _proto_list_str(int pid, char* proto_path); bool _proto_action_can_use(int pid); bool _proto_action_can_use_on(int pid); diff --git a/src/proto_instance.cc b/src/proto_instance.cc index 23bcde3..3af1c0a 100644 --- a/src/proto_instance.cc +++ b/src/proto_instance.cc @@ -76,7 +76,7 @@ int _obj_new_sid(Object* object, int* sidPtr) } int sid; - int objectType = object->pid >> 24; + int objectType = PID_TYPE(object->pid); if (objectType < OBJ_TYPE_TILE) { sid = proto->sid; } else if (objectType == OBJ_TYPE_TILE) { @@ -91,7 +91,7 @@ int _obj_new_sid(Object* object, int* sidPtr) return -1; } - int scriptType = sid >> 24; + int scriptType = SID_TYPE(sid); if (scriptAdd(sidPtr, scriptType) == -1) { return -1; } @@ -108,7 +108,7 @@ int _obj_new_sid(Object* object, int* sidPtr) } if (scriptType == SCRIPT_TYPE_SPATIAL) { - script->sp.built_tile = object->tile | ((object->elevation << 29) & 0xE0000000); + script->sp.built_tile = builtTileCreate(object->tile, object->elevation); script->sp.radius = 3; } @@ -143,7 +143,7 @@ int _obj_new_sid_inst(Object* obj, int scriptType, int a3) script->field_14 = a3; if (scriptType == SCRIPT_TYPE_SPATIAL) { - script->sp.built_tile = ((obj->elevation << 29) & 0xE0000000) | obj->tile; + script->sp.built_tile = builtTileCreate(obj->tile, obj->elevation); script->sp.radius = 3; } @@ -156,7 +156,7 @@ int _obj_new_sid_inst(Object* obj, int scriptType, int a3) _scr_find_str_run_info(a3 & 0xFFFFFF, &(script->field_50), sid); - if ((obj->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) { obj->field_80 = script->field_14; } @@ -176,7 +176,7 @@ int _obj_look_at_func(Object* a1, Object* a2, void (*a3)(char* string)) return -1; } - if (((a2->fid & 0xF000000) >> 24) == OBJ_TYPE_TILE) { + if (FID_TYPE(a2->fid) == OBJ_TYPE_TILE) { return -1; } @@ -202,7 +202,7 @@ int _obj_look_at_func(Object* a1, Object* a2, void (*a3)(char* string)) if (!scriptOverrides) { MessageListItem messageListItem; - if ((a2->pid >> 24) == OBJ_TYPE_CRITTER && critterIsDead(a2)) { + if (PID_TYPE(a2->pid) == OBJ_TYPE_CRITTER && critterIsDead(a2)) { messageListItem.num = 491 + randomBetween(0, 1); } else { messageListItem.num = 490; @@ -240,7 +240,7 @@ int _obj_examine_func(Object* critter, Object* target, void (*fn)(char* string)) return -1; } - if ((target->fid & 0xF000000) >> 24 == OBJ_TYPE_TILE) { + if (FID_TYPE(target->fid) == OBJ_TYPE_TILE) { return -1; } @@ -271,7 +271,7 @@ int _obj_examine_func(Object* critter, Object* target, void (*fn)(char* string)) } fn(messageListItem.text); } else { - if ((target->pid >> 24) != OBJ_TYPE_CRITTER || !critterIsDead(target)) { + if (PID_TYPE(target->pid) != OBJ_TYPE_CRITTER || !critterIsDead(target)) { fn(description); } } @@ -283,7 +283,7 @@ int _obj_examine_func(Object* critter, Object* target, void (*fn)(char* string)) char formattedText[260]; - int type = target->pid >> 24; + int type = PID_TYPE(target->pid); if (type == OBJ_TYPE_CRITTER) { if (target != gDude && perkGetRank(gDude, PERK_AWARENESS) && !critterIsDead(target)) { MessageListItem hpMessageListItem; @@ -597,7 +597,7 @@ static int _obj_remove_from_inven(Object* critter, Object* item) int v11 = 0; if (critterGetItem2(critter) == item) { if (critter != gDude || interfaceGetCurrentHand()) { - fid = buildFid(1, critter->fid & 0xFFF, (critter->fid & 0xFF0000) >> 16, 0, critter->rotation); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, FID_ANIM_TYPE(critter->fid), 0, critter->rotation); objectSetFid(critter, fid, &updatedRect); v11 = 2; } else { @@ -605,7 +605,7 @@ static int _obj_remove_from_inven(Object* critter, Object* item) } } else if (critterGetItem1(critter) == item) { if (critter == gDude && !interfaceGetCurrentHand()) { - fid = buildFid(1, critter->fid & 0xFFF, (critter->fid & 0xFF0000) >> 16, 0, critter->rotation); + fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, FID_ANIM_TYPE(critter->fid), 0, critter->rotation); objectSetFid(critter, fid, &updatedRect); v11 = 2; } else { @@ -620,7 +620,7 @@ static int _obj_remove_from_inven(Object* critter, Object* item) v5 = proto->fid; } - fid = buildFid(1, v5, (critter->fid & 0xFF0000) >> 16, (critter->fid & 0xF000) >> 12, critter->rotation); + fid = buildFid(OBJ_TYPE_CRITTER, v5, FID_ANIM_TYPE(critter->fid), (critter->fid & 0xF000) >> 12, critter->rotation); objectSetFid(critter, fid, &updatedRect); v11 = 3; } @@ -1165,7 +1165,7 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item) int rc; switch (itemGetType(item)) { case ITEM_TYPE_DRUG: - if ((a2->pid >> 24) != OBJ_TYPE_CRITTER) { + if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) { if (a1 == gDude) { // That does nothing messageListItem.num = 582; @@ -1422,7 +1422,7 @@ int _check_scenery_ap_cost(Object* obj, Object* a2) // 0x49C740 int _obj_use(Object* a1, Object* a2) { - int type = (a2->fid & 0xF000000) >> 24; + int type = FID_TYPE(a2->fid); if (a1 == gDude) { if (type != OBJ_TYPE_SCENERY) { return -1; @@ -1438,7 +1438,7 @@ int _obj_use(Object* a1, Object* a2) return -1; } - if ((a2->pid >> 24) == OBJ_TYPE_SCENERY && sceneryProto->scenery.type == SCENERY_TYPE_DOOR) { + if (PID_TYPE(a2->pid) == OBJ_TYPE_SCENERY && sceneryProto->scenery.type == SCENERY_TYPE_DOOR) { return _obj_use_door(a1, a2, 0); } @@ -1457,7 +1457,7 @@ int _obj_use(Object* a1, Object* a2) } if (!scriptOverrides) { - if ((a2->pid >> 24) == OBJ_TYPE_SCENERY) { + if (PID_TYPE(a2->pid) == OBJ_TYPE_SCENERY) { if (sceneryProto->scenery.type == SCENERY_TYPE_LADDER_DOWN) { if (useLadderDown(a1, a2, 0) == 0) { scriptOverrides = true; @@ -1498,21 +1498,21 @@ int _obj_use(Object* a1, Object* a2) // 0x49C900 static int useLadderDown(Object* a1, Object* ladder, int a3) { - int builtTile = ladder->data.scenery.ladder.field_4; + int builtTile = ladder->data.scenery.ladder.destinationBuiltTile; if (builtTile == -1) { return -1; } - int tile = builtTile & 0x3FFFFFF; - int elevation = (builtTile & 0xE0000000) >> 29; - if (ladder->data.scenery.ladder.field_0 != 0) { + int tile = builtTileGetTile(builtTile); + int elevation = builtTileGetElevation(builtTile); + if (ladder->data.scenery.ladder.destinationMap != 0) { MapTransition transition; memset(&transition, 0, sizeof(transition)); - transition.map = ladder->data.scenery.ladder.field_0; + transition.map = ladder->data.scenery.ladder.destinationMap; transition.elevation = elevation; transition.tile = tile; - transition.rotation = (builtTile & 0x1C000000) >> 26; + transition.rotation = builtTileGetRotation(builtTile); mapSetTransition(&transition); @@ -1532,21 +1532,21 @@ static int useLadderDown(Object* a1, Object* ladder, int a3) // 0x49C9A4 static int useLadderUp(Object* a1, Object* ladder, int a3) { - int builtTile = ladder->data.scenery.ladder.field_4; + int builtTile = ladder->data.scenery.ladder.destinationBuiltTile; if (builtTile == -1) { return -1; } - int tile = builtTile & 0x3FFFFFF; - int elevation = (builtTile & 0xE0000000) >> 29; - if (ladder->data.scenery.ladder.field_0 != 0) { + int tile = builtTileGetTile(builtTile); + int elevation = builtTileGetElevation(builtTile); + if (ladder->data.scenery.ladder.destinationMap != 0) { MapTransition transition; memset(&transition, 0, sizeof(transition)); - transition.map = ladder->data.scenery.ladder.field_0; + transition.map = ladder->data.scenery.ladder.destinationMap; transition.elevation = elevation; transition.tile = tile; - transition.rotation = (builtTile & 0x1C000000) >> 26; + transition.rotation = builtTileGetRotation(builtTile); mapSetTransition(&transition); @@ -1566,21 +1566,21 @@ static int useLadderUp(Object* a1, Object* ladder, int a3) // 0x49CA48 static int useStairs(Object* a1, Object* stairs, int a3) { - int builtTile = stairs->data.scenery.stairs.field_4; + int builtTile = stairs->data.scenery.stairs.destinationBuiltTile; if (builtTile == -1) { return -1; } - int tile = builtTile & 0x3FFFFFF; - int elevation = (builtTile & 0xE0000000) >> 29; - if (stairs->data.scenery.stairs.field_0 > 0) { + int tile = builtTileGetTile(builtTile); + int elevation = builtTileGetElevation(builtTile); + if (stairs->data.scenery.stairs.destinationMap > 0) { MapTransition transition; memset(&transition, 0, sizeof(transition)); - transition.map = stairs->data.scenery.stairs.field_0; + transition.map = stairs->data.scenery.stairs.destinationMap; transition.elevation = elevation; transition.tile = tile; - transition.rotation = (builtTile & 0x1C000000) >> 26; + transition.rotation = builtTileGetRotation(builtTile); mapSetTransition(&transition); @@ -1734,31 +1734,31 @@ int _obj_use_door(Object* a1, Object* a2, int a3) step = 1; } - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); for (int i = start; i != end; i += step) { if (i != 0) { if (a3 == 0) { - reg_anim_11_0(a2, a2, _set_door_state_closed, -1); + animationRegisterCallback(a2, a2, (AnimationCallback*)_set_door_state_closed, -1); } const char* sfx = sfxBuildOpenName(a2, SCENERY_SOUND_EFFECT_CLOSED); - reg_anim_play_sfx(a2, sfx, -1); + animationRegisterPlaySoundEffect(a2, sfx, -1); - reg_anim_animate_reverse(a2, 0, 0); + animationRegisterAnimateReversed(a2, ANIM_STAND, 0); } else { if (a3 == 0) { - reg_anim_11_0(a2, a2, _set_door_state_open, -1); + animationRegisterCallback(a2, a2, (AnimationCallback*)_set_door_state_open, -1); } const char* sfx = sfxBuildOpenName(a2, SCENERY_SOUND_EFFECT_CLOSED); - reg_anim_play_sfx(a2, sfx, -1); + animationRegisterPlaySoundEffect(a2, sfx, -1); - reg_anim_animate(a2, 0, 0); + animationRegisterAnimate(a2, ANIM_STAND, 0); } } - reg_anim_11_1(a2, a2, _check_door_state, -1); + animationRegisterCallbackForced(a2, a2, (AnimationCallback*)_check_door_state, -1); reg_anim_end(); } @@ -1769,7 +1769,7 @@ int _obj_use_door(Object* a1, Object* a2, int a3) // 0x49CE7C int _obj_use_container(Object* critter, Object* item) { - if (((item->fid & 0xF000000) >> 24) != OBJ_TYPE_ITEM) { + if (FID_TYPE(item->fid) != OBJ_TYPE_ITEM) { return -1; } @@ -1817,16 +1817,16 @@ int _obj_use_container(Object* critter, Object* item) return -1; } - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); if (item->frame == 0) { const char* sfx = sfxBuildOpenName(item, SCENERY_SOUND_EFFECT_OPEN); - reg_anim_play_sfx(item, sfx, 0); - reg_anim_animate(item, 0, 0); + animationRegisterPlaySoundEffect(item, sfx, 0); + animationRegisterAnimate(item, ANIM_STAND, 0); } else { const char* sfx = sfxBuildOpenName(item, SCENERY_SOUND_EFFECT_CLOSED); - reg_anim_play_sfx(item, sfx, 0); - reg_anim_animate_reverse(item, 0, 0); + animationRegisterPlaySoundEffect(item, sfx, 0); + animationRegisterAnimateReversed(item, ANIM_STAND, 0); } reg_anim_end(); @@ -1902,7 +1902,7 @@ static bool _obj_is_lockable(Object* obj) return false; } - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: if (proto->item.type == ITEM_TYPE_CONTAINER) { return true; @@ -1926,7 +1926,7 @@ bool objectIsLocked(Object* obj) } ObjectData* data = &(obj->data); - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: return data->flags & CONTAINER_FLAG_LOCKED; case OBJ_TYPE_SCENERY: @@ -1943,7 +1943,7 @@ int objectLock(Object* object) return -1; } - switch (object->pid >> 24) { + switch (PID_TYPE(object->pid)) { case OBJ_TYPE_ITEM: object->data.flags |= OBJ_LOCKED; break; @@ -1964,7 +1964,7 @@ int objectUnlock(Object* object) return -1; } - switch (object->pid >> 24) { + switch (PID_TYPE(object->pid)) { case OBJ_TYPE_ITEM: object->data.flags &= ~OBJ_LOCKED; return 0; @@ -1989,7 +1989,7 @@ static bool _obj_is_openable(Object* obj) return false; } - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: if (proto->item.type == ITEM_TYPE_CONTAINER) { return true; @@ -2028,24 +2028,24 @@ static int objectOpenClose(Object* obj) objectUnjamLock(obj); - reg_anim_begin(2); + reg_anim_begin(ANIMATION_REQUEST_RESERVED); if (obj->frame != 0) { - reg_anim_11_1(obj, obj, _set_door_state_closed, -1); + animationRegisterCallbackForced(obj, obj, (AnimationCallback*)_set_door_state_closed, -1); const char* sfx = sfxBuildOpenName(obj, SCENERY_SOUND_EFFECT_CLOSED); - reg_anim_play_sfx(obj, sfx, -1); + animationRegisterPlaySoundEffect(obj, sfx, -1); - reg_anim_animate_reverse(obj, 0, 0); + animationRegisterAnimateReversed(obj, ANIM_STAND, 0); } else { - reg_anim_11_1(obj, obj, _set_door_state_open, -1); + animationRegisterCallbackForced(obj, obj, (AnimationCallback*)_set_door_state_open, -1); const char* sfx = sfxBuildOpenName(obj, SCENERY_SOUND_EFFECT_OPEN); - reg_anim_play_sfx(obj, sfx, -1); - reg_anim_animate(obj, 0, 0); + animationRegisterPlaySoundEffect(obj, sfx, -1); + animationRegisterAnimate(obj, ANIM_STAND, 0); } - reg_anim_11_1(obj, obj, _check_door_state, -1); + animationRegisterCallbackForced(obj, obj, (AnimationCallback*)_check_door_state, -1); reg_anim_end(); @@ -2079,7 +2079,7 @@ static bool objectIsJammed(Object* obj) return false; } - if ((obj->pid >> 24) == OBJ_TYPE_SCENERY) { + if (PID_TYPE(obj->pid) == OBJ_TYPE_SCENERY) { if ((obj->data.scenery.door.openFlags & OBJ_JAMMED) != 0) { return true; } @@ -2101,7 +2101,7 @@ int objectJamLock(Object* obj) } ObjectData* data = &(obj->data); - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: data->flags |= CONTAINER_FLAG_JAMMED; break; @@ -2121,7 +2121,7 @@ int objectUnjamLock(Object* obj) } ObjectData* data = &(obj->data); - switch (obj->pid >> 24) { + switch (PID_TYPE(obj->pid)) { case OBJ_TYPE_ITEM: data->flags &= ~CONTAINER_FLAG_JAMMED; break; diff --git a/src/proto_types.h b/src/proto_types.h index 782b0df..d7cd633 100644 --- a/src/proto_types.h +++ b/src/proto_types.h @@ -362,8 +362,8 @@ typedef struct { } SceneryProtoStairsData; typedef struct { - int field_0; // d.lower_tile - int field_4; // d.upper_tile + int type; + int level; } SceneryProtoElevatorData; typedef struct { diff --git a/src/queue.h b/src/queue.h index 756617e..ff3556a 100644 --- a/src/queue.h +++ b/src/queue.h @@ -36,7 +36,7 @@ typedef struct WithdrawalEvent { typedef struct ScriptEvent { int sid; - int field_4; + int fixedParam; } ScriptEvent; typedef struct RadiationEvent { diff --git a/src/region.cc b/src/region.cc index 3a80083..0c59c94 100644 --- a/src/region.cc +++ b/src/region.cc @@ -44,6 +44,82 @@ void _regionSetBound(Region* region) } } +// 0x4A2C14 +bool regionContainsPoint(Region* region, int x, int y) +{ + if (region == NULL) { + return false; + } + + if (x < region->field_24 || x > region->field_2C || y < region->field_28 || y > region->field_30) { + return false; + } + + int v1; + + Point* prev = &(region->points[0]); + if (x >= prev->x) { + if (y >= prev->y) { + v1 = 2; + } else { + v1 = 1; + } + } else { + if (y >= prev->y) { + v1 = 3; + } else { + v1 = 0; + } + } + + int v4 = 0; + for (int index = 0; index < region->pointsLength; index++) { + int v2; + + Point* point = &(region->points[index + 1]); + if (x >= point->x) { + if (y >= point->y) { + v2 = 2; + } else { + v2 = 1; + } + } else { + if (y >= point->y) { + v2 = 3; + } else { + v2 = 0; + } + } + + int v3 = v2 - v1; + switch (v3) { + case -3: + v3 = 1; + break; + case -2: + case 2: + if ((double)x < ((double)point->x - (double)(prev->x - point->x) / (double)(prev->y - point->y) * (double)(point->y - y))) { + v3 = -v3; + } + break; + case 3: + v3 = -1; + break; + } + + prev = point; + v1 = v2; + + v4 += v3; + } + + if (v4 == 4 || v4 == -4) { + return true; + } + + return false; +} + // 0x4A2D78 Region* regionCreate(int initialCapacity) { @@ -62,24 +138,24 @@ Region* regionCreate(int initialCapacity) region->field_74 = 0; region->field_28 = INT_MIN; region->field_30 = INT_MAX; - region->field_54 = 0; - region->field_5C = 0; - region->field_64 = 0; + region->procs[3] = 0; + region->rightProcs[1] = 0; + region->rightProcs[3] = 0; region->field_68 = 0; - region->field_6C = 0; + region->rightProcs[0] = 0; region->field_70 = 0; - region->field_60 = 0; - region->field_78 = 0; - region->field_7C = 0; - region->field_80 = 0; - region->field_84 = 0; + region->rightProcs[2] = 0; + region->mouseEventCallback = NULL; + region->rightMouseEventCallback = NULL; + region->mouseEventCallbackUserData = 0; + region->rightMouseEventCallbackUserData = 0; region->pointsLength = 0; - region->field_24 = 0; - region->field_2C = 0; - region->field_50 = 0; - region->field_4C = 0; - region->field_48 = 0; - region->field_58 = 0; + region->field_24 = region->field_28; + region->field_2C = region->field_30; + region->procs[2] = 0; + region->procs[1] = 0; + region->procs[0] = 0; + region->rightProcs[0] = 0; return region; } diff --git a/src/region.h b/src/region.h index 22282d4..a53c054 100644 --- a/src/region.h +++ b/src/region.h @@ -6,6 +6,10 @@ #define REGION_NAME_LENGTH (32) +typedef struct Region Region; + +typedef void RegionMouseEventCallback(Region* region, void* userData, int event); + typedef struct Region { char name[REGION_NAME_LENGTH]; Point* points; @@ -18,22 +22,16 @@ typedef struct Region { int pointsLength; int pointsCapacity; Program* program; - int field_48; - int field_4C; - int field_50; - int field_54; - int field_58; - int field_5C; - int field_60; - int field_64; + int procs[4]; + int rightProcs[4]; int field_68; int field_6C; int field_70; int field_74; - int field_78; - int field_7C; - int field_80; - int field_84; + RegionMouseEventCallback* mouseEventCallback; + RegionMouseEventCallback* rightMouseEventCallback; + void* mouseEventCallbackUserData; + void* rightMouseEventCallbackUserData; void* userData; } Region; diff --git a/src/scripts.cc b/src/scripts.cc index 17ee020..6b6f30b 100644 --- a/src/scripts.cc +++ b/src/scripts.cc @@ -29,8 +29,8 @@ #include "window_manager_private.h" #include "world_map.h" -#include #include +#include #include #include @@ -567,12 +567,12 @@ Object* scriptGetSelf(Program* program) return script->owner; } - if ((sid >> 24) != SCRIPT_TYPE_SPATIAL) { + if (SID_TYPE(sid) != SCRIPT_TYPE_SPATIAL) { return NULL; } Object* object; - int fid = buildFid(6, 3, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, 3, 0, 0, 0); objectCreateWithFidPid(&object, fid, -1); objectHide(object, NULL); _obj_toggle_flat(object, NULL); @@ -595,7 +595,7 @@ Object* scriptGetSelf(Program* program) Script* spatialScript = scriptGetFirstSpatialScript(elevation); while (spatialScript != NULL) { if (spatialScript == script) { - objectSetLocation(object, script->sp.built_tile & 0x3FFFFFF, elevation, NULL); + objectSetLocation(object, builtTileGetTile(script->sp.built_tile), elevation, NULL); return object; } spatialScript = scriptGetNextSpatialScript(); @@ -780,7 +780,7 @@ void _scrSetQueueTestVals(Object* a1, int a2) int _scrQueueRemoveFixed(Object* obj, void* data) { ScriptEvent* scriptEvent = (ScriptEvent*)data; - return obj == _scrQueueTestObj && scriptEvent->field_4 == _scrQueueTestValue; + return obj == _scrQueueTestObj && scriptEvent->fixedParam == _scrQueueTestValue; } // 0x4A3E60 @@ -792,7 +792,7 @@ int scriptAddTimerEvent(int sid, int delay, int param) } scriptEvent->sid = sid; - scriptEvent->field_4 = param; + scriptEvent->fixedParam = param; Script* script; if (scriptGetScript(sid, &script) == -1) { @@ -814,7 +814,7 @@ int scriptEventWrite(File* stream, void* data) ScriptEvent* scriptEvent = (ScriptEvent*)data; if (fileWriteInt32(stream, scriptEvent->sid) == -1) return -1; - if (fileWriteInt32(stream, scriptEvent->field_4) == -1) return -1; + if (fileWriteInt32(stream, scriptEvent->fixedParam) == -1) return -1; return 0; } @@ -828,7 +828,7 @@ int scriptEventRead(File* stream, void** dataPtr) } if (fileReadInt32(stream, &(scriptEvent->sid)) == -1) goto err; - if (fileReadInt32(stream, &(scriptEvent->field_4)) == -1) goto err; + if (fileReadInt32(stream, &(scriptEvent->fixedParam)) == -1) goto err; *dataPtr = scriptEvent; @@ -852,7 +852,7 @@ int scriptEventProcess(Object* obj, void* data) return 0; } - script->fixedParam = scriptEvent->field_4; + script->fixedParam = scriptEvent->fixedParam; scriptExecProc(scriptEvent->sid, SCRIPT_PROC_TIMED); @@ -929,7 +929,7 @@ int scriptsHandleRequests() Object* elevatorDoors = objectFindFirstAtElevation(gDude->elevation); while (elevatorDoors != NULL) { int pid = elevatorDoors->pid; - if ((pid >> 24) == OBJ_TYPE_SCENERY + if (PID_TYPE(pid) == OBJ_TYPE_SCENERY && (pid == PROTO_ID_0x2000099 || pid == PROTO_ID_0x20001A5 || pid == PROTO_ID_0x20001D6) && tileDistanceBetween(elevatorDoors->tile, gDude->tile) <= 4) { break; @@ -955,7 +955,7 @@ int scriptsHandleRequests() Object* elevatorDoors = objectFindFirstAtElevation(gDude->elevation); while (elevatorDoors != NULL) { int pid = elevatorDoors->pid; - if ((pid >> 24) == OBJ_TYPE_SCENERY + if (PID_TYPE(pid) == OBJ_TYPE_SCENERY && (pid == PROTO_ID_0x2000099 || pid == PROTO_ID_0x20001A5 || pid == PROTO_ID_0x20001D6) && tileDistanceBetween(elevatorDoors->tile, gDude->tile) <= 4) { break; @@ -1035,7 +1035,7 @@ int _scripts_check_state_in_combat() Object* elevatorDoors = objectFindFirstAtElevation(gDude->elevation); while (elevatorDoors != NULL) { int pid = elevatorDoors->pid; - if ((pid >> 24) == OBJ_TYPE_SCENERY + if (PID_TYPE(pid) == OBJ_TYPE_SCENERY && (pid == PROTO_ID_0x2000099 || pid == PROTO_ID_0x20001A5 || pid == PROTO_ID_0x20001D6) && tileDistanceBetween(elevatorDoors->tile, gDude->tile) <= 4) { break; @@ -1137,8 +1137,8 @@ int scriptsRequestElevator(Object* a1, int a2) return -1; } - // TODO: What the hell is this? - tile -= 1005; + // In the following code we are looking for an elevator. 5 tiles in each direction + tile = tile - (HEX_GRID_WIDTH * 5) - 5; // left upper corner Object* obj; for (int y = -5; y < 5; y++) { @@ -1163,12 +1163,12 @@ int scriptsRequestElevator(Object* a1, int a2) break; } - tile += 190; + tile += HEX_GRID_WIDTH - 10; } if (obj != NULL) { - elevatorType = obj->data.scenery.elevator.field_0; - elevatorLevel = obj->data.scenery.elevator.field_4; + elevatorType = obj->data.scenery.elevator.type; + elevatorLevel = obj->data.scenery.elevator.level; } if (elevatorType == -1) { @@ -1224,6 +1224,13 @@ int scriptsRequestStealing(Object* a1, Object* a2) return 0; } +// NOTE: Inlined. +void _script_make_path(char* path) +{ + strcpy(path, _cd_path_base); + strcat(path, gScriptsBasePath); +} + // exec_script_proc // 0x4A4810 int scriptExecProc(int sid, int proc) @@ -1341,7 +1348,8 @@ bool scriptHasProc(int sid, int proc) static int scriptsLoadScriptsList() { char path[COMPAT_MAX_PATH]; - sprintf(path, "%s%s", "scripts\\", "scripts.lst"); + _script_make_path(path); + strcat(path, "scripts.lst"); File* stream = fileOpen(path, "rt"); if (stream == NULL) { @@ -1716,8 +1724,7 @@ static int _scr_header_load() _num_script_indexes = 0; char path[COMPAT_MAX_PATH]; - strcpy(path, _cd_path_base); - strcat(path, gScriptsBasePath); + _script_make_path(path); strcat(path, "scripts.lst"); File* stream = fileOpen(path, "rt"); @@ -1757,7 +1764,7 @@ static int scriptWrite(Script* scr, File* stream) if (fileWriteInt32(stream, scr->sid) == -1) return -1; if (fileWriteInt32(stream, scr->field_4) == -1) return -1; - switch (scr->sid >> 24) { + switch (SID_TYPE(scr->sid)) { case SCRIPT_TYPE_SPATIAL: if (fileWriteInt32(stream, scr->sp.built_tile) == -1) return -1; if (fileWriteInt32(stream, scr->sp.radius) == -1) return -1; @@ -1911,7 +1918,7 @@ static int scriptRead(Script* scr, File* stream) if (fileReadInt32(stream, &(scr->sid)) == -1) return -1; if (fileReadInt32(stream, &(scr->field_4)) == -1) return -1; - switch (scr->sid >> 24) { + switch (SID_TYPE(scr->sid)) { case SCRIPT_TYPE_SPATIAL: if (fileReadInt32(stream, &(scr->sp.built_tile)) == -1) return -1; if (fileReadInt32(stream, &(scr->sp.radius)) == -1) return -1; @@ -2066,7 +2073,7 @@ int scriptGetScript(int sid, Script** scriptPtr) return -1; } - ScriptList* scriptList = &(gScriptLists[sid >> 24]); + ScriptList* scriptList = &(gScriptLists[SID_TYPE(sid)]); ScriptListExtent* scriptListExtent = scriptList->head; while (scriptListExtent != NULL) { @@ -2221,7 +2228,7 @@ int scriptRemove(int sid) return -1; } - ScriptList* scriptList = &(gScriptLists[sid >> 24]); + ScriptList* scriptList = &(gScriptLists[SID_TYPE(sid)]); ScriptListExtent* scriptListExtent = scriptList->head; int index; @@ -2399,7 +2406,7 @@ static Script* scriptGetFirstSpatialScript(int elevation) } Script* script = &(gScriptsEnumerationScriptListExtent->scripts[0]); - if ((script->flags & SCRIPT_FLAG_0x02) != 0 || ((script->sp.built_tile & 0xE0000000) >> 29) != elevation) { + if ((script->flags & SCRIPT_FLAG_0x02) != 0 || builtTileGetElevation(script->sp.built_tile) != elevation) { script = scriptGetNextSpatialScript(); } @@ -2431,7 +2438,7 @@ static Script* scriptGetNextSpatialScript() } Script* script = &(scriptListExtent->scripts[scriptIndex]); - if ((script->flags & SCRIPT_FLAG_0x02) == 0 && ((script->sp.built_tile & 0xE0000000) >> 29) == gScriptsEnumerationElevation) { + if ((script->flags & SCRIPT_FLAG_0x02) == 0 && builtTileGetElevation(script->sp.built_tile) == gScriptsEnumerationElevation) { break; } } @@ -2486,7 +2493,7 @@ bool scriptsExecSpatialProc(Object* object, int tile, int elevation) _scr_SpatialsEnabled = false; - int builtTile = ((elevation << 29) & 0xE0000000) | tile; + int builtTile = builtTileCreate(tile, elevation); for (Script* script = scriptGetFirstSpatialScript(elevation); script != NULL; script = scriptGetNextSpatialScript()) { if (builtTile == script->sp.built_tile) { @@ -2497,7 +2504,7 @@ bool scriptsExecSpatialProc(Object* object, int tile, int elevation) continue; } - int distance = tileDistanceBetween(script->sp.built_tile & 0x3FFFFFF, tile); + int distance = tileDistanceBetween(builtTileGetTile(script->sp.built_tile), tile); if (distance > script->sp.radius) { continue; } @@ -2686,7 +2693,7 @@ char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3) return NULL; } - if (((gGameDialogHeadFid & 0xF000000) >> 24) != 8) { + if (FID_TYPE(gGameDialogHeadFid) != OBJ_TYPE_HEAD) { a3 = 0; } @@ -2717,7 +2724,7 @@ char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3) // 0x4A6D64 int scriptGetLocalVar(int sid, int variable, int* value) { - if (sid >> 24 == SCRIPT_TYPE_SYSTEM) { + if (SID_TYPE(sid) == SCRIPT_TYPE_SYSTEM) { debugPrint("\nError! System scripts/Map scripts not allowed local_vars! "); _tempStr1[0] = '\0'; @@ -2859,8 +2866,8 @@ int _scr_explode_scenery(Object* a1, int tile, int radius, int elevation) } if (script->procs[SCRIPT_PROC_DAMAGE] > 0 - && (script->sp.built_tile & 0xE0000000) >> 29 == elevation - && tileDistanceBetween(script->sp.built_tile & 0x3FFFFFF, tile) <= radius) { + && builtTileGetElevation(script->sp.built_tile) == elevation + && tileDistanceBetween(builtTileGetTile(script->sp.built_tile), tile) <= radius) { scriptIds[scriptsCount] = script->sid; scriptsCount += 1; } diff --git a/src/scripts.h b/src/scripts.h index 02e14f3..095dadc 100644 --- a/src/scripts.h +++ b/src/scripts.h @@ -12,6 +12,9 @@ #define SCRIPT_FLAG_0x08 (0x08) #define SCRIPT_FLAG_0x10 (0x10) +// 60 * 60 * 10 +#define GAME_TIME_TICKS_PER_HOUR 36000 + // 24 * 60 * 60 * 10 #define GAME_TIME_TICKS_PER_DAY (864000) @@ -175,6 +178,7 @@ void scriptsRequestDialog(Object* a1); void scriptsRequestEndgame(); int scriptsRequestLooting(Object* a1, Object* a2); int scriptsRequestStealing(Object* a1, Object* a2); +void _script_make_path(char* path); int scriptExecProc(int sid, int proc); bool scriptHasProc(int sid, int proc); int _scr_find_str_run_info(int a1, int* a2, int sid); diff --git a/src/selfrun.cc b/src/selfrun.cc index 5e00740..2e19973 100644 --- a/src/selfrun.cc +++ b/src/selfrun.cc @@ -1,15 +1,18 @@ #include "selfrun.h" +#include "core.h" #include "db.h" #include "game.h" +#include "game_config.h" +#include "platform_compat.h" #include // 0x51C8D8 -int _selfrun_state = 0; +int gSelfrunState = SELFRUN_STATE_TURNED_OFF; // 0x4A8BE0 -int _selfrun_get_list(char*** fileListPtr, int* fileListLengthPtr) +int selfrunInitFileList(char*** fileListPtr, int* fileListLengthPtr) { if (fileListPtr == NULL) { return -1; @@ -25,7 +28,7 @@ int _selfrun_get_list(char*** fileListPtr, int* fileListLengthPtr) } // 0x4A8C10 -int _selfrun_free_list(char*** fileListPtr) +int selfrunFreeFileList(char*** fileListPtr) { if (fileListPtr == NULL) { return -1; @@ -36,9 +39,198 @@ int _selfrun_free_list(char*** fileListPtr) return 0; } +// 0x4A8C28 +int selfrunPreparePlayback(const char* fileName, SelfrunData* selfrunData) +{ + if (fileName == NULL) { + return -1; + } + + if (selfrunData == NULL) { + return -1; + } + + if (vcrGetState() != VCR_STATE_TURNED_OFF) { + return -1; + } + + if (gSelfrunState != SELFRUN_STATE_TURNED_OFF) { + return -1; + } + + char path[COMPAT_MAX_PATH]; + sprintf(path, "%s%s", "selfrun\\", fileName); + + if (selfrunReadData(path, selfrunData) != 0) { + return -1; + } + + gSelfrunState = SELFRUN_STATE_PLAYING; + + return 0; +} + +// 0x4A8C88 +void selfrunPlaybackLoop(SelfrunData* selfrunData) +{ + if (gSelfrunState == SELFRUN_STATE_PLAYING) { + char path[COMPAT_MAX_PATH]; + sprintf(path, "%s%s", "selfrun\\", selfrunData->recordingFileName); + + if (vcrPlay(path, VCR_TERMINATE_ON_KEY_PRESS | VCR_TERMINATE_ON_MOUSE_PRESS, selfrunPlaybackCompleted)) { + bool cursorWasHidden = cursorIsHidden(); + if (cursorWasHidden) { + mouseShowCursor(); + } + + while (gSelfrunState == SELFRUN_STATE_PLAYING) { + int keyCode = _get_input(); + if (keyCode != selfrunData->stopKeyCode) { + gameHandleKey(keyCode, false); + } + } + + while (mouseGetEvent() != 0) { + _get_input(); + } + + if (cursorWasHidden) { + mouseHideCursor(); + } + } + } +} + +// 0x4A8D28 +int selfrunPrepareRecording(const char* recordingName, const char* mapFileName, SelfrunData* selfrunData) +{ + if (recordingName == NULL) { + return -1; + } + + if (mapFileName == NULL) { + return -1; + } + + if (vcrGetState() != VCR_STATE_TURNED_OFF) { + return -1; + } + + if (gSelfrunState != SELFRUN_STATE_TURNED_OFF) { + return -1; + } + + sprintf(selfrunData->recordingFileName, "%s%s", recordingName, ".vcr"); + strcpy(selfrunData->mapFileName, mapFileName); + + selfrunData->stopKeyCode = KEY_CTRL_R; + + char path[COMPAT_MAX_PATH]; + sprintf(path, "%s%s%s", "selfrun\\", recordingName, ".sdf"); + + if (selfrunWriteData(path, selfrunData) != 0) { + return -1; + } + + gSelfrunState = SELFRUN_STATE_RECORDING; + + return 0; +} + +// 0x4A8DDC +void selfrunRecordingLoop(SelfrunData* selfrunData) +{ + if (gSelfrunState == SELFRUN_STATE_RECORDING) { + char path[COMPAT_MAX_PATH]; + sprintf(path, "%s%s", "selfrun\\", selfrunData->recordingFileName); + if (vcrRecord(path)) { + if (!cursorIsHidden()) { + mouseShowCursor(); + } + + bool done = false; + while (!done) { + int keyCode = _get_input(); + if (keyCode == selfrunData->stopKeyCode) { + vcrStop(); + _game_user_wants_to_quit = 2; + done = true; + } else { + gameHandleKey(keyCode, false); + } + } + } + gSelfrunState = SELFRUN_STATE_TURNED_OFF; + } +} + // 0x4A8E74 -void _selfrun_playback_callback() +void selfrunPlaybackCompleted(int reason) { _game_user_wants_to_quit = 2; - _selfrun_state = 0; + gSelfrunState = SELFRUN_STATE_TURNED_OFF; +} + +// 0x4A8E8C +int selfrunReadData(const char* path, SelfrunData* selfrunData) +{ + if (path == NULL) { + return -1; + } + + if (selfrunData == NULL) { + return -1; + } + + File* stream = fileOpen(path, "rb"); + if (stream == NULL) { + return -1; + } + + int rc = -1; + if (fileReadFixedLengthString(stream, selfrunData->recordingFileName, SELFRUN_RECORDING_FILE_NAME_LENGTH) == 0 + && fileReadFixedLengthString(stream, selfrunData->mapFileName, SELFRUN_MAP_FILE_NAME_LENGTH) == 0 + && fileReadInt32(stream, &(selfrunData->stopKeyCode)) == 0) { + rc = 0; + } + + fileClose(stream); + + return rc; +} + +// 0x4A8EF4 +int selfrunWriteData(const char* path, SelfrunData* selfrunData) +{ + if (path == NULL) { + return -1; + } + + if (selfrunData == NULL) { + return -1; + } + + char* masterPatches; + configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, &masterPatches); + + char selfrunDirectoryPath[COMPAT_MAX_PATH]; + sprintf(selfrunDirectoryPath, "%s\\%s", masterPatches, "selfrun\\"); + + compat_mkdir(selfrunDirectoryPath); + + File* stream = fileOpen(path, "wb"); + if (stream == NULL) { + return -1; + } + + int rc = -1; + if (fileWriteFixedLengthString(stream, selfrunData->recordingFileName, SELFRUN_RECORDING_FILE_NAME_LENGTH) == 0 + && fileWriteFixedLengthString(stream, selfrunData->mapFileName, SELFRUN_MAP_FILE_NAME_LENGTH) == 0 + && fileWriteInt32(stream, selfrunData->stopKeyCode) == 0) { + rc = 0; + } + + fileClose(stream); + + return rc; } diff --git a/src/selfrun.h b/src/selfrun.h index 690ad94..756304e 100644 --- a/src/selfrun.h +++ b/src/selfrun.h @@ -1,10 +1,33 @@ #ifndef SELFRUN_H #define SELFRUN_H -extern int _selfrun_state; +#define SELFRUN_RECORDING_FILE_NAME_LENGTH 13 +#define SELFRUN_MAP_FILE_NAME_LENGTH 13 -int _selfrun_get_list(char*** fileListPtr, int* fileListLengthPtr); -int _selfrun_free_list(char*** fileListPtr); -void _selfrun_playback_callback(); +typedef enum SelfrunState { + SELFRUN_STATE_TURNED_OFF, + SELFRUN_STATE_PLAYING, + SELFRUN_STATE_RECORDING, +} SelfrunState; + +typedef struct SelfrunData { + char recordingFileName[SELFRUN_RECORDING_FILE_NAME_LENGTH]; + char mapFileName[SELFRUN_MAP_FILE_NAME_LENGTH]; + int stopKeyCode; +} SelfrunData; + +static_assert(sizeof(SelfrunData) == 32, "wrong size"); + +extern int gSelfrunState; + +int selfrunInitFileList(char*** fileListPtr, int* fileListLengthPtr); +int selfrunFreeFileList(char*** fileListPtr); +int selfrunPreparePlayback(const char* fileName, SelfrunData* selfrunData); +void selfrunPlaybackLoop(SelfrunData* selfrunData); +int selfrunPrepareRecording(const char* recordingName, const char* mapFileName, SelfrunData* selfrunData); +void selfrunRecordingLoop(SelfrunData* selfrunData); +void selfrunPlaybackCompleted(int reason); +int selfrunReadData(const char* path, SelfrunData* selfrunData); +int selfrunWriteData(const char* path, SelfrunData* selfrunData); #endif /* SELFRUN_H */ diff --git a/src/skill.cc b/src/skill.cc index f8b3d9a..ab3f02a 100644 --- a/src/skill.cc +++ b/src/skill.cc @@ -1032,7 +1032,7 @@ int skillsPerformStealing(Object* a1, Object* a2, Object* item, bool isPlanting) // -4% per item size stealModifier -= 4 * itemGetSize(item); - if (((a2->fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER) { + if (FID_TYPE(a2->fid) == OBJ_TYPE_CRITTER) { // check facing: -25% if face to face if (_is_hit_from_front(a1, a2)) { stealModifier -= 25; @@ -1064,7 +1064,7 @@ int skillsPerformStealing(Object* a1, Object* a2, Object* item, bool isPlanting) catchRoll = ROLL_SUCCESS; } else { int catchChance; - if ((a2->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(a2->pid) == OBJ_TYPE_CRITTER) { catchChance = skillGetValue(a2, SKILL_STEAL) - stealModifier; } else { catchChance = 30 - stealModifier; diff --git a/src/skilldex.cc b/src/skilldex.cc index d6d16e2..ae0a38f 100644 --- a/src/skilldex.cc +++ b/src/skilldex.cc @@ -162,7 +162,7 @@ static int skilldexWindowInit() int frmIndex; for (frmIndex = 0; frmIndex < SKILLDEX_FRM_COUNT; frmIndex++) { - int fid = buildFid(6, gSkilldexFrmIds[frmIndex], 0, 0, 0); + int fid = buildFid(OBJ_TYPE_INTERFACE, gSkilldexFrmIds[frmIndex], 0, 0, 0); gSkilldexFrmData[frmIndex] = artLockFrameDataReturningSize(fid, &(gSkilldexFrmHandles[frmIndex]), &(gSkilldexFrmSizes[frmIndex].width), &(gSkilldexFrmSizes[frmIndex].height)); if (gSkilldexFrmData[frmIndex] == NULL) { break; diff --git a/src/sound.cc b/src/sound.cc index 5a8bc59..23a8a35 100644 --- a/src/sound.cc +++ b/src/sound.cc @@ -446,7 +446,6 @@ Sound* soundAllocate(int a1, int a2) sound->field_78 = _numBuffers; sound->readLimit = sound->field_7C * _numBuffers; - if (a1 & 0x10) { sound->field_50 = -1; sound->field_3C |= 0x20; diff --git a/src/stat_defs.h b/src/stat_defs.h index b867888..7ef2a78 100644 --- a/src/stat_defs.h +++ b/src/stat_defs.h @@ -57,13 +57,13 @@ typedef enum Stat { STAT_CURRENT_POISON_LEVEL, STAT_CURRENT_RADIATION_LEVEL, STAT_COUNT, - + // Number of primary stats. PRIMARY_STAT_COUNT = 7, // Number of SPECIAL stats (primary + secondary). SPECIAL_STAT_COUNT = 33, - + // Number of saveable stats (i.e. excluding CURRENT pseudostats). SAVEABLE_STAT_COUNT = 35, } Stat; @@ -81,4 +81,3 @@ typedef enum PcStat { } PcStat; #endif /* STAT_DEFS */ - diff --git a/src/tile.cc b/src/tile.cc index e07bca7..4fecbf8 100644 --- a/src/tile.cc +++ b/src/tile.cc @@ -14,6 +14,7 @@ #include "platform_compat.h" #include +#include #include typedef struct STRUCT_51D99C { @@ -1228,8 +1229,8 @@ void tileRenderRoofsInRect(Rect* rect, int elevation) int frmId = gTileSquares[elevation]->field_0[squareTile]; frmId >>= 16; if ((((frmId & 0xF000) >> 12) & 0x01) == 0) { - int fid = buildFid(4, frmId & 0xFFF, 0, 0, 0); - if (fid != buildFid(4, 1, 0, 0, 0)) { + int fid = buildFid(OBJ_TYPE_TILE, frmId & 0xFFF, 0, 0, 0); + if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { int screenX; int screenY; squareTileToRoofScreenXY(squareTile, &screenX, &screenY, elevation); @@ -1250,7 +1251,7 @@ static void _roof_fill_on(int a1, int a2, int elevation) int upper = (value >> 16) & 0xFFFF; int id = upper & 0xFFF; - if (buildFid(4, id, 0, 0, 0) == buildFid(4, 1, 0, 0, 0)) { + if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) == buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { break; } @@ -1290,7 +1291,7 @@ static void sub_4B23DC(int a1, int a2, int elevation) int upper = (value >> 16) & 0xFFFF; int id = upper & 0xFFF; - if (buildFid(4, id, 0, 0, 0) == buildFid(4, 1, 0, 0, 0)) { + if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) == buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { break; } @@ -1462,7 +1463,7 @@ void tileRenderFloorsInRect(Rect* rect, int elevation) int v12; int v13; squareTileToScreenXY(v3, &v12, &v13, elevation); - int fid = buildFid(4, frmId & 0xFFF, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_TILE, frmId & 0xFFF, 0, 0, 0); tileRenderFloor(fid, v12, v13, rect); } } @@ -1486,10 +1487,10 @@ bool _square_roof_intersect(int x, int y, int elevation) TileData* ptr = gTileSquares[elevation]; int idx = gSquareGridWidth * tileY + tileX; int upper = ptr->field_0[gSquareGridWidth * tileY + tileX] >> 16; - int fid = buildFid(4, upper & 0xFFF, 0, 0, 0); - if (fid != buildFid(4, 1, 0, 0, 0)) { + int fid = buildFid(OBJ_TYPE_TILE, upper & 0xFFF, 0, 0, 0); + if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { if ((((upper & 0xF000) >> 12) & 1) == 0) { - int fid = buildFid(4, upper & 0xFFF, 0, 0, 0); + int fid = buildFid(OBJ_TYPE_TILE, upper & 0xFFF, 0, 0, 0); CacheEntry* handle; Art* art = artLock(fid, &handle); if (art != NULL) { @@ -1583,7 +1584,7 @@ static void _draw_grid(int tile, int elevation, Rect* rect) // 0x4B30C4 static void tileRenderFloor(int fid, int x, int y, Rect* rect) { - if (artIsObjectTypeHidden((fid & 0xF000000) >> 24) != 0) { + if (artIsObjectTypeHidden(FID_TYPE(fid)) != 0) { return; } diff --git a/src/widget.cc b/src/widget.cc index df48a57..b74eada 100644 --- a/src/widget.cc +++ b/src/widget.cc @@ -5,7 +5,6 @@ #include "window.h" static void _showRegion(int a1); -static int widgetGetTextFlags(); static unsigned char widgetGetHighlightColor(); // 0x50EB1C @@ -93,3 +92,9 @@ int widgetSetHighlightColor(float a1, float a2, float a3) return 1; } + +// 0x4B5998 +void sub_4B5998(int win) +{ + // TODO: Incomplete. +} diff --git a/src/widget.h b/src/widget.h index 96540a3..6d18e2b 100644 --- a/src/widget.h +++ b/src/widget.h @@ -4,9 +4,11 @@ int _update_widgets(); int widgetGetFont(); int widgetSetFont(int a1); +int widgetGetTextFlags(); int widgetSetTextFlags(int a1); unsigned char widgetGetTextColor(); int widgetSetTextColor(float a1, float a2, float a3); int widgetSetHighlightColor(float a1, float a2, float a3); +void sub_4B5998(int win); #endif /* WIDGET_H */ diff --git a/src/window.cc b/src/window.cc index ae00fe0..6d1fabd 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1,11 +1,15 @@ #include "window.h" +#include "color.h" #include "core.h" +#include "datafile.h" #include "draw.h" +#include "game.h" #include "interpreter_lib.h" #include "memory_manager.h" #include "mouse_manager.h" #include "movie.h" +#include "platform_compat.h" #include "text_font.h" #include "widget.h" #include "window_manager.h" @@ -18,36 +22,32 @@ typedef struct ManagedButton { int btn; - int field_4; - int field_8; - int field_C; - int field_10; + int width; + int height; + int x; + int y; int flags; int field_18; char name[32]; Program* program; - void* field_40; - void* field_44; - void* field_48; + unsigned char* pressed; + unsigned char* normal; + unsigned char* hover; void* field_4C; void* field_50; - int field_54; - int field_58; - int field_5C; - int field_60; - int field_64; - int field_68; - int field_6C; - int field_70; - int field_74; - int field_78; + int procs[MANAGED_BUTTON_MOUSE_EVENT_COUNT]; + int rightProcs[MANAGED_BUTTON_RIGHT_MOUSE_EVENT_COUNT]; + ManagedButtonMouseEventCallback* mouseEventCallback; + ManagedButtonMouseEventCallback* rightMouseEventCallback; + void* mouseEventCallbackUserData; + void* rightMouseEventCallbackUserData; } ManagedButton; typedef struct ManagedWindow { char name[32]; int window; - int field_24; - int field_28; + int width; + int height; Region** regions; int currentRegionIndex; int regionsLength; @@ -64,22 +64,6 @@ typedef struct ManagedWindow { typedef int (*INITVIDEOFN)(); -static int _selectWindow(const char* windowName); -static unsigned char* _windowGetBuffer(); -static int _pushWindow(const char* windowName); -static int _popWindow(); -static void _windowWrapLineWithSpacing(int win, char* string, int width, int height, int x, int y, int flags, int textAlignment, int a9); -static int _windowGetXres(); -static void _removeProgramReferences_3(Program* program); -static bool _windowAddButtonRightProc(const char* buttonName, Program* program, int a3, int a4); -static void _windowEndRegion(); -static bool _windowStartRegion(int initialCapacity); -static bool _windowAddRegionPoint(int x, int y, bool a3); -static bool _windowAddRegionName(const char* regionName); -static int _windowMoviePlaying(); -static bool _windowPlayMovie(char* filePath); -static bool _windowPlayMovieRect(char* filePath, int a2, int a3, int a4, int a5); - // 0x51DCAC static int _holdTime = 250; @@ -125,7 +109,7 @@ static Size _sizes_x[12] = { }; // 0x51DD7C -static int _numInputFunc = 0; +static int gWindowInputHandlersLength = 0; // 0x51DD80 static int _lastWin = -1; @@ -142,6 +126,12 @@ static char _alphaBlendTable[64 * 256]; // 0x6727B0 static ManagedWindow gManagedWindows[MANAGED_WINDOW_COUNT]; +// 0x672D70 +static WindowInputHandler** gWindowInputHandlers; + +// 0x672D74 +static ManagedWindowCreateCallback* off_672D74; + // NOTE: This value is never set. // // 0x672D78 @@ -150,6 +140,12 @@ static void (*_selectWindowFunc)(int, ManagedWindow*); // 0x672D7C static int _xres; +// 0x672D80 +static DisplayInWindowCallback* gDisplayInWindowCallback; + +// 0x672D84 +static WindowDeleteCallback* gWindowDeleteCallback; + // 0x672D88 static int _yres; @@ -161,6 +157,12 @@ int _currentHighlightColorR; // 0x672D90 int gWidgetFont; +// 0x672D98 +ButtonCallback* off_672D98; + +// 0x672D9C +ButtonCallback* off_672D9C; + // Text color (maybe g). // // 0x672DA0 @@ -189,6 +191,413 @@ int _currentHighlightColorG; // 0x672DB4 int _currentHighlightColorB; +// 0x4B62E4 +bool _checkRegion(int windowIndex, int mouseX, int mouseY, int mouseEvent) +{ + // TODO: Incomplete. + return false; +} + +// 0x4B6858 +bool _windowCheckRegion(int windowIndex, int mouseX, int mouseY, int mouseEvent) +{ + bool rc = _checkRegion(windowIndex, mouseX, mouseY, mouseEvent); + + ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]); + int v1 = managedWindow->field_38; + + for (int index = 0; index < managedWindow->regionsLength; index++) { + Region* region = managedWindow->regions[index]; + if (region != NULL) { + if (region->field_6C != 0) { + region->field_6C = 0; + rc = true; + + if (region->mouseEventCallback != NULL) { + region->mouseEventCallback(region, region->mouseEventCallbackUserData, 2); + if (v1 != managedWindow->field_38) { + return true; + } + } + + if (region->rightMouseEventCallback != NULL) { + region->rightMouseEventCallback(region, region->rightMouseEventCallbackUserData, 2); + if (v1 != managedWindow->field_38) { + return true; + } + } + + if (region->program != NULL && region->procs[2] != 0) { + _executeProc(region->program, region->procs[2]); + if (v1 != managedWindow->field_38) { + return true; + } + } + } + } + } + + return rc; +} + +// 0x4B69BC +bool _windowRefreshRegions() +{ + int mouseX; + int mouseY; + mouseGetPosition(&mouseX, &mouseY); + + int win = windowGetAtPoint(mouseX, mouseY); + + for (int windowIndex = 0; windowIndex < MANAGED_WINDOW_COUNT; windowIndex++) { + ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]); + if (managedWindow->window == win) { + for (int regionIndex = 0; regionIndex < managedWindow->regionsLength; regionIndex++) { + Region* region = managedWindow->regions[regionIndex]; + region->rightProcs[3] = 0; + } + + int mouseEvent = mouseGetEvent(); + return _windowCheckRegion(windowIndex, mouseX, mouseY, mouseEvent); + } + } + + return false; +} + +// 0x4B6A54 +bool _checkAllRegions() +{ + if (!_checkRegionEnable) { + return false; + } + + int mouseX; + int mouseY; + mouseGetPosition(&mouseX, &mouseY); + + int mouseEvent = mouseGetEvent(); + int win = windowGetAtPoint(mouseX, mouseY); + + for (int windowIndex = 0; windowIndex < MANAGED_WINDOW_COUNT; windowIndex++) { + ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]); + if (managedWindow->window != -1 && managedWindow->window == win) { + if (_lastWin != -1 && _lastWin != windowIndex && gManagedWindows[_lastWin].window != -1) { + ManagedWindow* managedWindow = &(gManagedWindows[_lastWin]); + int v1 = managedWindow->field_38; + + for (int regionIndex = 0; regionIndex < managedWindow->regionsLength; regionIndex++) { + Region* region = managedWindow->regions[regionIndex]; + if (region != NULL && region->rightProcs[3] != 0) { + region->rightProcs[3] = 0; + if (region->mouseEventCallback != NULL) { + region->mouseEventCallback(region, region->mouseEventCallbackUserData, 3); + if (v1 != managedWindow->field_38) { + return true; + } + } + + if (region->rightMouseEventCallback != NULL) { + region->rightMouseEventCallback(region, region->rightMouseEventCallbackUserData, 3); + if (v1 != managedWindow->field_38) { + return true; + } + } + + if (region->program != NULL && region->procs[3] != 0) { + _executeProc(region->program, region->procs[3]); + if (v1 != managedWindow->field_38) { + return 1; + } + } + } + } + _lastWin = -1; + } else { + _lastWin = windowIndex; + } + + return _windowCheckRegion(windowIndex, mouseX, mouseY, mouseEvent); + } + } + + return false; +} + +// 0x4B6C48 +void _windowAddInputFunc(WindowInputHandler* handler) +{ + int index; + for (index = 0; index < gWindowInputHandlersLength; index++) { + if (gWindowInputHandlers[index] == NULL) { + break; + } + } + + if (index == gWindowInputHandlersLength) { + if (gWindowInputHandlers != NULL) { + gWindowInputHandlers = (WindowInputHandler**)internal_realloc_safe(gWindowInputHandlers, sizeof(*gWindowInputHandlers) * (gWindowInputHandlersLength + 1), __FILE__, __LINE__); // "..\\int\\WINDOW.C", 521 + } else { + gWindowInputHandlers = (WindowInputHandler**)internal_malloc_safe(sizeof(*gWindowInputHandlers), __FILE__, __LINE__); // "..\\int\\WINDOW.C", 523 + } + } + + gWindowInputHandlers[gWindowInputHandlersLength] = handler; + gWindowInputHandlersLength++; +} + +// 0x4B6CE8 +void _doRegionRightFunc(Region* region, int a2) +{ + int v1 = gManagedWindows[gCurrentManagedWindowIndex].field_38; + if (region->rightMouseEventCallback != NULL) { + region->rightMouseEventCallback(region, region->rightMouseEventCallbackUserData, a2); + if (v1 != gManagedWindows[gCurrentManagedWindowIndex].field_38) { + return; + } + } + + if (a2 < 4) { + if (region->program != NULL && region->rightProcs[a2] != 0) { + _executeProc(region->program, region->rightProcs[a2]); + } + } +} + +// 0x4B6D68 +void _doRegionFunc(Region* region, int a2) +{ + int v1 = gManagedWindows[gCurrentManagedWindowIndex].field_38; + if (region->mouseEventCallback != NULL) { + region->mouseEventCallback(region, region->mouseEventCallbackUserData, a2); + if (v1 != gManagedWindows[gCurrentManagedWindowIndex].field_38) { + return; + } + } + + if (a2 < 4) { + if (region->program != NULL && region->rightProcs[a2] != 0) { + _executeProc(region->program, region->rightProcs[a2]); + } + } +} + +// 0x4B6DE8 +bool _windowActivateRegion(const char* regionName, int a2) +{ + if (gCurrentManagedWindowIndex == -1) { + return false; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + + if (a2 <= 4) { + for (int index = 0; index < managedWindow->regionsLength; index++) { + Region* region = managedWindow->regions[index]; + if (compat_stricmp(regionGetName(region), regionName) == 0) { + _doRegionFunc(region, a2); + return true; + } + } + } else { + for (int index = 0; index < managedWindow->regionsLength; index++) { + Region* region = managedWindow->regions[index]; + if (compat_stricmp(regionGetName(region), regionName) == 0) { + _doRegionRightFunc(region, a2 - 5); + return true; + } + } + } + + return false; +} + +// 0x4B6ED0 +int _getInput() +{ + int keyCode = _get_input(); + if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) { + showQuitConfirmationDialog(); + } + + if (_game_user_wants_to_quit != 0) { + _said_quit = 1 - _said_quit; + if (_said_quit) { + return -1; + } + + return KEY_ESCAPE; + } + + for (int index = 0; index < gWindowInputHandlersLength; index++) { + WindowInputHandler* handler = gWindowInputHandlers[index]; + if (handler != NULL) { + if (handler(keyCode) != 0) { + return -1; + } + } + } + + return keyCode; +} + +// 0x4B6F60 +void _doButtonOn(int btn, int keyCode) +{ + sub_4B6F68(btn, MANAGED_BUTTON_MOUSE_EVENT_ENTER); +} + +// 0x4B6F68 +void sub_4B6F68(int btn, int mouseEvent) +{ + int win = _win_last_button_winID(); + if (win == -1) { + return; + } + + for (int windowIndex = 0; windowIndex < MANAGED_WINDOW_COUNT; windowIndex++) { + ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]); + if (managedWindow->window == win) { + for (int buttonIndex = 0; buttonIndex < managedWindow->buttonsLength; buttonIndex++) { + ManagedButton* managedButton = &(managedWindow->buttons[buttonIndex]); + if (managedButton->btn == btn) { + if ((managedButton->flags & 0x02) != 0) { + _win_set_button_rest_state(managedButton->btn, 0, 0); + } else { + if (managedButton->program != NULL && managedButton->procs[mouseEvent] != 0) { + _executeProc(managedButton->program, managedButton->procs[mouseEvent]); + } + + if (managedButton->mouseEventCallback != NULL) { + managedButton->mouseEventCallback(managedButton->mouseEventCallbackUserData, mouseEvent); + } + } + } + } + } + } +} + +// 0x4B7028 +void _doButtonOff(int btn, int keyCode) +{ + sub_4B6F68(btn, MANAGED_BUTTON_MOUSE_EVENT_EXIT); +} + +// 0x4B7034 +void _doButtonPress(int btn, int keyCode) +{ + sub_4B6F68(btn, MANAGED_BUTTON_MOUSE_EVENT_BUTTON_DOWN); +} + +// 0x4B703C +void _doButtonRelease(int btn, int keyCode) +{ + sub_4B6F68(btn, MANAGED_BUTTON_MOUSE_EVENT_BUTTON_UP); +} + +// NOTE: Unused. +// +// 0x4B7048 +void _doRightButtonPress(int btn, int keyCode) +{ + sub_4B704C(btn, MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_DOWN); +} + +// NOTE: Unused. +// +// 0x4B704C +void sub_4B704C(int btn, int mouseEvent) +{ + int win = _win_last_button_winID(); + if (win == -1) { + return; + } + + for (int windowIndex = 0; windowIndex < MANAGED_WINDOW_COUNT; windowIndex++) { + ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]); + if (managedWindow->window == win) { + for (int buttonIndex = 0; buttonIndex < managedWindow->buttonsLength; buttonIndex++) { + ManagedButton* managedButton = &(managedWindow->buttons[buttonIndex]); + if (managedButton->btn == btn) { + if ((managedButton->flags & 0x02) != 0) { + _win_set_button_rest_state(managedButton->btn, 0, 0); + } else { + if (managedButton->program != NULL && managedButton->rightProcs[mouseEvent] != 0) { + _executeProc(managedButton->program, managedButton->rightProcs[mouseEvent]); + } + + if (managedButton->rightMouseEventCallback != NULL) { + managedButton->rightMouseEventCallback(managedButton->rightMouseEventCallbackUserData, mouseEvent); + } + } + } + } + } + } +} + +// NOTE: Unused. +// +// 0x4B710C +void _doRightButtonRelease(int btn, int keyCode) +{ + sub_4B704C(btn, MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_UP); +} + +// 0x4B7118 +void _setButtonGFX(int width, int height, unsigned char* normal, unsigned char* pressed, unsigned char* a5) +{ + if (normal != NULL) { + bufferFill(normal, width, height, width, _colorTable[0]); + bufferFill(normal + width + 1, width - 2, height - 2, width, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + bufferDrawLine(normal, width, 1, 1, width - 2, 1, _colorTable[32767]); + bufferDrawLine(normal, width, 2, 2, width - 3, 2, _colorTable[32767]); + bufferDrawLine(normal, width, 1, height - 2, width - 2, height - 2, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(normal, width, 2, height - 3, width - 3, height - 3, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(normal, width, width - 2, 1, width - 3, 2, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + bufferDrawLine(normal, width, 1, 2, 1, height - 3, _colorTable[32767]); + bufferDrawLine(normal, width, 2, 3, 2, height - 4, _colorTable[32767]); + bufferDrawLine(normal, width, width - 2, 2, width - 2, height - 3, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(normal, width, width - 3, 3, width - 3, height - 4, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(normal, width, 1, height - 2, 2, height - 3, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + } + + if (pressed != NULL) { + bufferFill(pressed, width, height, width, _colorTable[0]); + bufferFill(pressed + width + 1, width - 2, height - 2, width, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + bufferDrawLine(pressed, width, 1, 1, width - 2, 1, _colorTable[32767] + 44); + bufferDrawLine(pressed, width, 1, 1, 1, height - 2, _colorTable[32767] + 44); + } + + if (a5 != NULL) { + bufferFill(a5, width, height, width, _colorTable[0]); + bufferFill(a5 + width + 1, width - 2, height - 2, width, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + bufferDrawLine(a5, width, 1, 1, width - 2, 1, _colorTable[32767]); + bufferDrawLine(a5, width, 2, 2, width - 3, 2, _colorTable[32767]); + bufferDrawLine(a5, width, 1, height - 2, width - 2, height - 2, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(a5, width, 2, height - 3, width - 3, height - 3, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(a5, width, width - 2, 1, width - 3, 2, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + bufferDrawLine(a5, width, 1, 2, 1, height - 3, _colorTable[32767]); + bufferDrawLine(a5, width, 2, 3, 2, height - 4, _colorTable[32767]); + bufferDrawLine(a5, width, width - 2, 2, width - 2, height - 3, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(a5, width, width - 3, 3, width - 3, height - 4, _intensityColorTable[(_colorTable[32767] << 8) + 44]); + bufferDrawLine(a5, width, 1, height - 2, 2, height - 3, _intensityColorTable[(_colorTable[32767] << 8) + 89]); + } +} + +// 0x4B7734 +int _windowWidth() +{ + return gManagedWindows[gCurrentManagedWindowIndex].width; +} + +// 0x4B7754 +int _windowHeight() +{ + return gManagedWindows[gCurrentManagedWindowIndex].height; +} + // 0x4B7680 bool _windowDraw() { @@ -202,6 +611,165 @@ bool _windowDraw() return true; } +// 0x4B78A4 +bool _deleteWindow(const char* windowName) +{ + int index; + for (index = 0; index < MANAGED_WINDOW_COUNT; index++) { + ManagedWindow* managedWindow = &(gManagedWindows[index]); + if (compat_stricmp(managedWindow->name, windowName) == 0) { + break; + } + } + + if (index == MANAGED_WINDOW_COUNT) { + return false; + } + + if (gWindowDeleteCallback != NULL) { + gWindowDeleteCallback(index, windowName); + } + + ManagedWindow* managedWindow = &(gManagedWindows[index]); + sub_4B5998(managedWindow->window); + windowDestroy(managedWindow->window); + managedWindow->window = -1; + managedWindow->name[0] = '\0'; + + if (managedWindow->buttons != NULL) { + for (int index = 0; index < managedWindow->buttonsLength; index++) { + ManagedButton* button = &(managedWindow->buttons[index]); + if (button->hover != NULL) { + internal_free_safe(button->hover, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 802 + } + + if (button->field_4C != NULL) { + internal_free_safe(button->field_4C, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 804 + } + + if (button->pressed != NULL) { + internal_free_safe(button->pressed, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 806 + } + + if (button->normal != NULL) { + internal_free_safe(button->normal, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 808 + } + } + + internal_free_safe(managedWindow->buttons, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 810 + } + + if (managedWindow->regions != NULL) { + for (int index = 0; index < managedWindow->regionsLength; index++) { + Region* region = managedWindow->regions[index]; + if (region != NULL) { + regionDelete(region); + } + } + + internal_free_safe(managedWindow->regions, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 818 + managedWindow->regions = NULL; + } + + return true; +} + +// 0x4B7AC4 +int sub_4B7AC4(const char* windowName, int x, int y, int width, int height) +{ + // TODO: Incomplete. + return -1; +} + +// 0x4B7E7C +int sub_4B7E7C(const char* windowName, int x, int y, int width, int height) +{ + // TODO: Incomplete. + return -1; +} + +// 0x4B7F3C +int _createWindow(const char* windowName, int x, int y, int width, int height, int a6, int flags) +{ + int windowIndex = -1; + + // NOTE: Original code is slightly different. + for (int index = 0; index < MANAGED_WINDOW_COUNT; index++) { + ManagedWindow* managedWindow = &(gManagedWindows[index]); + if (managedWindow->window == -1) { + windowIndex = index; + break; + } else { + if (compat_stricmp(managedWindow->name, windowName) == 0) { + _deleteWindow(windowName); + windowIndex = index; + break; + } + } + } + + if (windowIndex == -1) { + return -1; + } + + ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]); + strncpy(managedWindow->name, windowName, 32); + managedWindow->field_54 = 1.0; + managedWindow->field_58 = 1.0; + managedWindow->field_38 = 0; + managedWindow->regions = NULL; + managedWindow->regionsLength = 0; + managedWindow->width = width; + managedWindow->height = height; + managedWindow->buttons = NULL; + managedWindow->buttonsLength = 0; + + flags |= 0x101; + if (off_672D74 != NULL) { + off_672D74(windowIndex, managedWindow->name, &flags); + } + + managedWindow->window = windowCreate(x, y, width, height, a6, flags); + managedWindow->field_48 = 0; + managedWindow->field_44 = 0; + managedWindow->field_4C = a6; + managedWindow->field_50 = flags; + + return windowIndex; +} + +// 0x4B80A4 +int _windowOutput(char* string) +{ + if (gCurrentManagedWindowIndex == -1) { + return 0; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + + int x = (int)(managedWindow->field_44 * managedWindow->field_54); + int y = (int)(managedWindow->field_48 * managedWindow->field_58); + // NOTE: Uses `add` at 0x4B810E, not bitwise `or`. + int flags = widgetGetTextColor() + widgetGetTextFlags(); + windowDrawText(managedWindow->window, string, 0, x, y, flags); + + return 1; +} + +// 0x4B814C +bool _windowGotoXY(int x, int y) +{ + if (gCurrentManagedWindowIndex == -1) { + return false; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + managedWindow->field_44 = (int)(x * managedWindow->field_54); + managedWindow->field_48 = (int)(y * managedWindow->field_58); + + return true; +} + // 0x4B81C4 bool _selectWindowID(int index) { @@ -382,7 +950,7 @@ char** _windowWordWrap(char* string, int maxLength, int a3, int* substringListLe char** substringList = NULL; int substringListLength = 0; - + char* start = string; char* pch = string; int v1 = a3; @@ -515,6 +1083,115 @@ bool _windowFormatMessage(char* string, int x, int y, int width, int height, int return true; } +// 0x4B8A60 +bool _windowPrint(char* string, int a2, int x, int y, int a5) +{ + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + x = (int)(x * managedWindow->field_54); + y = (int)(y * managedWindow->field_58); + + windowDrawText(managedWindow->window, string, a2, x, y, a5); + + return true; +} + +// 0x4B8B10 +void _displayInWindow(unsigned char* data, int width, int height, int pitch) +{ + if (gDisplayInWindowCallback != NULL) { + // NOTE: The second parameter is unclear as there is no distinction + // between address of entire window struct and it's name (since it's the + // first field). I bet on name since it matches WindowDeleteCallback, + // which accepts window index and window name as seen at 0x4B7927). + gDisplayInWindowCallback(gCurrentManagedWindowIndex, + gManagedWindows[gCurrentManagedWindowIndex].name, + data, + width, + height); + } + + if (width == pitch) { + // NOTE: Uninline. + if (pitch == _windowWidth() && height == _windowHeight()) { + // NOTE: Uninline. + unsigned char* windowBuffer = _windowGetBuffer(); + memcpy(windowBuffer, data, height * width); + } else { + // NOTE: Uninline. + unsigned char* windowBuffer = _windowGetBuffer(); + _drawScaledBuf(windowBuffer, _windowWidth(), _windowHeight(), data, width, height); + } + } else { + // NOTE: Uninline. + unsigned char* windowBuffer = _windowGetBuffer(); + _drawScaled(windowBuffer, + _windowWidth(), + _windowHeight(), + _windowWidth(), + data, + width, + height, + pitch); + } +} + +// 0x4B8C68 +void _displayFile(char* fileName) +{ + int width; + int height; + unsigned char* data = datafileRead(fileName, &width, &height); + if (data != NULL) { + _displayInWindow(data, width, height, width); + internal_free_safe(data, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1294 + } +} + +// 0x4B8CA8 +void _displayFileRaw(char* fileName) +{ + int width; + int height; + unsigned char* data = datafileReadRaw(fileName, &width, &height); + if (data != NULL) { + _displayInWindow(data, width, height, width); + internal_free_safe(data, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1305 + } +} + +// 0x4B8E50 +bool _windowDisplay(char* fileName, int x, int y, int width, int height) +{ + int imageWidth; + int imageHeight; + unsigned char* imageData = datafileRead(fileName, &imageWidth, &imageHeight); + if (imageData == NULL) { + return false; + } + + _windowDisplayBuf(imageData, imageWidth, imageHeight, x, y, width, height); + + internal_free_safe(imageData, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1376 + + return true; +} + +// 0x4B8EF0 +bool _windowDisplayBuf(unsigned char* src, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) +{ + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + unsigned char* windowBuffer = windowGetBuffer(managedWindow->window); + + blitBufferToBuffer(src, + destWidth, + destHeight, + srcWidth, + windowBuffer + managedWindow->width * destY + destX, + managedWindow->width); + + return true; +} + // 0x4B9048 int _windowGetXres() { @@ -537,10 +1214,10 @@ void _removeProgramReferences_3(Program* program) ManagedButton* managedButton = &(managedWindow->buttons[index]); if (program == managedButton->program) { managedButton->program = NULL; - managedButton->field_5C = 0; - managedButton->field_60 = 0; - managedButton->field_54 = 0; - managedButton->field_58 = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_ENTER] = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_EXIT] = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_BUTTON_DOWN] = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_BUTTON_UP] = 0; } } @@ -549,10 +1226,10 @@ void _removeProgramReferences_3(Program* program) if (region != NULL) { if (program == region->program) { region->program = NULL; - region->field_4C = 0; - region->field_48 = 0; - region->field_54 = 0; - region->field_50 = 0; + region->procs[1] = 0; + region->procs[0] = 0; + region->procs[3] = 0; + region->procs[2] = 0; } } } @@ -567,7 +1244,7 @@ void _initWindow(int resolution, int a2) int rc; int i, j; - _interpretRegisterProgramDeleteCallback(_removeProgramReferences_3); + intLibRegisterProgramDeleteCallback(_removeProgramReferences_3); _currentTextColorR = 0; _currentTextColorG = 0; @@ -651,9 +1328,9 @@ void _initWindow(int resolution, int a2) gWidgetFont = 100; fontSetCurrent(100); - _initMousemgr(); + mouseManagerInit(); - _mousemgrSetNameMangler(_interpretMangleName); + mouseManagerSetNameMangler(_interpretMangleName); for (i = 0; i < 64; i++) { for (j = 0; j < 256; j++) { @@ -670,10 +1347,15 @@ void _windowClose() for (int index = 0; index < MANAGED_WINDOW_COUNT; index++) { ManagedWindow* managedWindow = &(gManagedWindows[index]); if (managedWindow->window != -1) { - // _deleteWindow(managedWindow); + _deleteWindow(managedWindow->name); } } + if (gWindowInputHandlers != NULL) { + internal_free_safe(gWindowInputHandlers, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1573 + } + + mouseManagerExit(); dbExit(); windowManagerExit(); } @@ -697,9 +1379,9 @@ bool _windowDeleteButton(const char* buttonName) ManagedButton* managedButton = &(managedWindow->buttons[index]); buttonDestroy(managedButton->btn); - if (managedButton->field_48 != NULL) { - internal_free_safe(managedButton->field_48, __FILE__, __LINE__); // "..\int\WINDOW.C", 1648 - managedButton->field_48 = NULL; + if (managedButton->hover != NULL) { + internal_free_safe(managedButton->hover, __FILE__, __LINE__); // "..\int\WINDOW.C", 1648 + managedButton->hover = NULL; } if (managedButton->field_4C != NULL) { @@ -707,18 +1389,18 @@ bool _windowDeleteButton(const char* buttonName) managedButton->field_4C = NULL; } - if (managedButton->field_40 != NULL) { - internal_free_safe(managedButton->field_40, __FILE__, __LINE__); // "..\int\WINDOW.C", 1650 - managedButton->field_40 = NULL; + if (managedButton->pressed != NULL) { + internal_free_safe(managedButton->pressed, __FILE__, __LINE__); // "..\int\WINDOW.C", 1650 + managedButton->pressed = NULL; } - if (managedButton->field_44 != NULL) { - internal_free_safe(managedButton->field_44, __FILE__, __LINE__); // "..\int\WINDOW.C", 1651 - managedButton->field_44 = NULL; + if (managedButton->normal != NULL) { + internal_free_safe(managedButton->normal, __FILE__, __LINE__); // "..\int\WINDOW.C", 1651 + managedButton->normal = NULL; } if (managedButton->field_50 != NULL) { - internal_free_safe(managedButton->field_44, __FILE__, __LINE__); // "..\int\WINDOW.C", 1652 + internal_free_safe(managedButton->normal, __FILE__, __LINE__); // "..\int\WINDOW.C", 1652 managedButton->field_50 = NULL; } } @@ -735,9 +1417,9 @@ bool _windowDeleteButton(const char* buttonName) if (compat_stricmp(managedButton->name, buttonName) == 0) { buttonDestroy(managedButton->btn); - if (managedButton->field_48 != NULL) { - internal_free_safe(managedButton->field_48, __FILE__, __LINE__); // "..\int\WINDOW.C", 1665 - managedButton->field_48 = NULL; + if (managedButton->hover != NULL) { + internal_free_safe(managedButton->hover, __FILE__, __LINE__); // "..\int\WINDOW.C", 1665 + managedButton->hover = NULL; } if (managedButton->field_4C != NULL) { @@ -745,14 +1427,14 @@ bool _windowDeleteButton(const char* buttonName) managedButton->field_4C = NULL; } - if (managedButton->field_40 != NULL) { - internal_free_safe(managedButton->field_40, __FILE__, __LINE__); // "..\int\WINDOW.C", 1667 - managedButton->field_40 = NULL; + if (managedButton->pressed != NULL) { + internal_free_safe(managedButton->pressed, __FILE__, __LINE__); // "..\int\WINDOW.C", 1667 + managedButton->pressed = NULL; } - if (managedButton->field_44 != NULL) { - internal_free_safe(managedButton->field_44, __FILE__, __LINE__); // "..\int\WINDOW.C", 1668 - managedButton->field_44 = NULL; + if (managedButton->normal != NULL) { + internal_free_safe(managedButton->normal, __FILE__, __LINE__); // "..\int\WINDOW.C", 1668 + managedButton->normal = NULL; } // FIXME: Probably leaking field_50. It's freed when deleting all @@ -799,8 +1481,173 @@ bool _windowSetButtonFlag(const char* buttonName, int value) return false; } +// 0x4B99C8 +bool _windowAddButton(const char* buttonName, int x, int y, int width, int height, int flags) +{ + if (gCurrentManagedWindowIndex == -1) { + return false; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + int index; + for (index = 0; index < managedWindow->buttonsLength; index++) { + ManagedButton* managedButton = &(managedWindow->buttons[index]); + if (compat_stricmp(managedButton->name, buttonName) == 0) { + buttonDestroy(managedButton->btn); + + if (managedButton->hover != NULL) { + internal_free_safe(managedButton->hover, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1748 + managedButton->hover = NULL; + } + + if (managedButton->field_4C != NULL) { + internal_free_safe(managedButton->field_4C, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1749 + managedButton->field_4C = NULL; + } + + if (managedButton->pressed != NULL) { + internal_free_safe(managedButton->pressed, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1750 + managedButton->pressed = NULL; + } + + if (managedButton->normal != NULL) { + internal_free_safe(managedButton->normal, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1751 + managedButton->normal = NULL; + } + + break; + } + } + + if (index == managedWindow->buttonsLength) { + if (managedWindow->buttons == NULL) { + managedWindow->buttons = (ManagedButton*)internal_malloc_safe(sizeof(*managedWindow->buttons), __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1758 + } else { + managedWindow->buttons = (ManagedButton*)internal_realloc_safe(managedWindow->buttons, sizeof(*managedWindow->buttons) * (managedWindow->buttonsLength + 1), __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1761 + } + managedWindow->buttonsLength += 1; + } + + x = (int)(x * managedWindow->field_54); + y = (int)(y * managedWindow->field_58); + width = (int)(width * managedWindow->field_54); + height = (int)(height * managedWindow->field_58); + + ManagedButton* managedButton = &(managedWindow->buttons[index]); + strncpy(managedButton->name, buttonName, 31); + managedButton->program = NULL; + managedButton->flags = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_BUTTON_UP] = 0; + managedButton->rightProcs[MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_UP] = 0; + managedButton->mouseEventCallback = NULL; + managedButton->rightMouseEventCallback = NULL; + managedButton->field_50 = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_BUTTON_DOWN] = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_EXIT] = 0; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_ENTER] = 0; + managedButton->rightProcs[MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_DOWN] = 0; + managedButton->width = width; + managedButton->height = height; + managedButton->x = x; + managedButton->y = y; + + unsigned char* normal = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1792 + unsigned char* pressed = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 1793 + + if ((flags & BUTTON_FLAG_TRANSPARENT) != 0) { + memset(normal, 0, width * height); + memset(pressed, 0, width * height); + } else { + _setButtonGFX(width, height, normal, pressed, NULL); + } + + managedButton->btn = buttonCreate( + managedWindow->window, + x, + y, + width, + height, + -1, + -1, + -1, + -1, + normal, + pressed, + NULL, + flags); + + if (off_672D98 != NULL || off_672D9C != NULL) { + buttonSetCallbacks(managedButton->btn, off_672D98, off_672D9C); + } + + managedButton->hover = NULL; + managedButton->pressed = pressed; + managedButton->normal = normal; + managedButton->field_18 = flags; + managedButton->field_4C = NULL; + buttonSetMouseCallbacks(managedButton->btn, _doButtonOn, _doButtonOff, _doButtonPress, _doButtonRelease); + _windowSetButtonFlag(buttonName, 1); + + if ((flags & BUTTON_FLAG_TRANSPARENT) != 0) { + buttonSetMask(managedButton->btn, normal); + } + + return true; +} + +// 0x4B9DD0 +bool _windowAddButtonGfx(const char* buttonName, char* pressedFileName, char* normalFileName, char* hoverFileName) +{ + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + for (int index = 0; index < managedWindow->buttonsLength; index++) { + ManagedButton* managedButton = &(managedWindow->buttons[index]); + if (compat_stricmp(managedButton->name, buttonName) == 0) { + int width; + int height; + + if (pressedFileName != NULL) { + unsigned char* pressed = datafileRead(pressedFileName, &width, &height); + if (pressed != NULL) { + _drawScaledBuf(managedButton->pressed, managedButton->width, managedButton->height, pressed, width, height); + internal_free_safe(pressed, __FILE__, __LINE__); // "..\\int\\WINDOW.C, 1834 + } + } + + if (normalFileName != NULL) { + unsigned char* normal = datafileRead(normalFileName, &width, &height); + if (normal != NULL) { + _drawScaledBuf(managedButton->normal, managedButton->width, managedButton->height, normal, width, height); + internal_free_safe(normal, __FILE__, __LINE__); // "..\\int\\WINDOW.C, 1842 + } + } + + if (hoverFileName != NULL) { + unsigned char* hover = datafileRead(normalFileName, &width, &height); + if (hover != NULL) { + if (managedButton->hover == NULL) { + managedButton->hover = (unsigned char*)internal_malloc_safe(managedButton->height * managedButton->width, __FILE__, __LINE__); // "..\\int\\WINDOW.C, 1849 + } + + _drawScaledBuf(managedButton->hover, managedButton->width, managedButton->height, hover, width, height); + internal_free_safe(hover, __FILE__, __LINE__); // "..\\int\\WINDOW.C, 1853 + } + } + + if ((managedButton->field_18 & 0x20) != 0) { + buttonSetMask(managedButton->btn, managedButton->normal); + } + + _win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, 0); + + return true; + } + } + + return false; +} + // 0x4BA11C -bool _windowAddButtonProc(const char* buttonName, Program* program, int a3, int a4, int a5, int a6) +bool _windowAddButtonProc(const char* buttonName, Program* program, int mouseEnterProc, int mouseExitProc, int mouseDownProc, int mouseUpProc) { if (gCurrentManagedWindowIndex != -1) { return false; @@ -814,10 +1661,10 @@ bool _windowAddButtonProc(const char* buttonName, Program* program, int a3, int for (int index = 0; index < managedWindow->buttonsLength; index++) { ManagedButton* managedButton = &(managedWindow->buttons[index]); if (compat_stricmp(managedButton->name, buttonName) == 0) { - managedButton->field_5C = a3; - managedButton->field_60 = a4; - managedButton->field_54 = a5; - managedButton->field_58 = a6; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_ENTER] = mouseEnterProc; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_EXIT] = mouseExitProc; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_BUTTON_DOWN] = mouseDownProc; + managedButton->procs[MANAGED_BUTTON_MOUSE_EVENT_BUTTON_UP] = mouseUpProc; managedButton->program = program; return true; } @@ -827,7 +1674,7 @@ bool _windowAddButtonProc(const char* buttonName, Program* program, int a3, int } // 0x4BA1B4 -bool _windowAddButtonRightProc(const char* buttonName, Program* program, int a3, int a4) +bool _windowAddButtonRightProc(const char* buttonName, Program* program, int rightMouseDownProc, int rightMouseUpProc) { if (gCurrentManagedWindowIndex != -1) { return false; @@ -841,8 +1688,8 @@ bool _windowAddButtonRightProc(const char* buttonName, Program* program, int a3, for (int index = 0; index < managedWindow->buttonsLength; index++) { ManagedButton* managedButton = &(managedWindow->buttons[index]); if (compat_stricmp(managedButton->name, buttonName) == 0) { - managedButton->field_68 = a4; - managedButton->field_64 = a3; + managedButton->rightProcs[MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_UP] = rightMouseUpProc; + managedButton->rightProcs[MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_DOWN] = rightMouseDownProc; managedButton->program = program; return true; } @@ -851,6 +1698,230 @@ bool _windowAddButtonRightProc(const char* buttonName, Program* program, int a3, return false; } +// NOTE: Unused. +// +// 0x4BA238 +bool _windowAddButtonCfunc(const char* buttonName, ManagedButtonMouseEventCallback* callback, void* userData) +{ + if (gCurrentManagedWindowIndex != -1) { + return false; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + if (managedWindow->buttons == NULL) { + return false; + } + + for (int index = 0; index < managedWindow->buttonsLength; index++) { + ManagedButton* managedButton = &(managedWindow->buttons[index]); + if (compat_stricmp(managedButton->name, buttonName) == 0) { + managedButton->mouseEventCallbackUserData = userData; + managedButton->mouseEventCallback = callback; + return true; + } + } + + return false; +} + +// NOTE: Unused. +// +// 0x4BA2B4 +bool _windowAddButtonRightCfunc(const char* buttonName, ManagedButtonMouseEventCallback* callback, void* userData) +{ + if (gCurrentManagedWindowIndex != -1) { + return false; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + if (managedWindow->buttons == NULL) { + return false; + } + + for (int index = 0; index < managedWindow->buttonsLength; index++) { + ManagedButton* managedButton = &(managedWindow->buttons[index]); + if (compat_stricmp(managedButton->name, buttonName) == 0) { + managedButton->rightMouseEventCallback = callback; + managedButton->rightMouseEventCallbackUserData = userData; + buttonSetRightMouseCallbacks(managedButton->btn, -1, -1, _doRightButtonPress, _doRightButtonRelease); + return true; + } + } + + return false; +} + +// 0x4BA34C +bool _windowAddButtonText(const char* buttonName, const char* text) +{ + return _windowAddButtonTextWithOffsets(buttonName, text, 2, 2, 0, 0); +} + +// 0x4BA364 +bool _windowAddButtonTextWithOffsets(const char* buttonName, const char* text, int pressedImageOffsetX, int pressedImageOffsetY, int normalImageOffsetX, int normalImageOffsetY) +{ + if (gCurrentManagedWindowIndex == -1) { + return false; + } + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + if (managedWindow->buttons == NULL) { + return false; + } + + for (int index = 0; index < managedWindow->buttonsLength; index++) { + ManagedButton* managedButton = &(managedWindow->buttons[index]); + if (compat_stricmp(managedButton->name, buttonName) == 0) { + int normalImageHeight = fontGetLineHeight() + 1; + int normalImageWidth = fontGetStringWidth(text) + 1; + unsigned char* buffer = (unsigned char*)internal_malloc_safe(normalImageHeight * normalImageWidth, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 2010 + + int normalImageX = (managedButton->width - normalImageWidth) / 2 + normalImageOffsetX; + int normalImageY = (managedButton->height - normalImageHeight) / 2 + normalImageOffsetY; + + if (normalImageX < 0) { + normalImageWidth -= normalImageX; + normalImageX = 0; + } + + if (normalImageX + normalImageWidth >= managedButton->width) { + normalImageWidth = managedButton->width - normalImageX; + } + + if (normalImageY < 0) { + normalImageHeight -= normalImageY; + normalImageY = 0; + } + + if (normalImageY + normalImageHeight >= managedButton->height) { + normalImageHeight = managedButton->height - normalImageY; + } + + if (managedButton->normal != NULL) { + blitBufferToBuffer(managedButton->normal + managedButton->width * normalImageY + normalImageX, + normalImageWidth, + normalImageHeight, + managedButton->width, + buffer, + normalImageWidth); + } else { + memset(buffer, 0, normalImageHeight * normalImageWidth); + } + + fontDrawText(buffer, + text, + normalImageWidth, + normalImageWidth, + widgetGetTextColor() + widgetGetTextFlags()); + + blitBufferToBufferTrans(buffer, + normalImageWidth, + normalImageHeight, + normalImageWidth, + managedButton->normal + managedButton->width * normalImageY + normalImageX, + managedButton->width); + + int pressedImageWidth = fontGetStringWidth(text) + 1; + int pressedImageHeight = fontGetLineHeight() + 1; + + int pressedImageX = (managedButton->width - pressedImageWidth) / 2 + pressedImageOffsetX; + int pressedImageY = (managedButton->height - pressedImageHeight) / 2 + pressedImageOffsetY; + + if (pressedImageX < 0) { + pressedImageWidth -= pressedImageX; + pressedImageX = 0; + } + + if (pressedImageX + pressedImageWidth >= managedButton->width) { + pressedImageWidth = managedButton->width - pressedImageX; + } + + if (pressedImageY < 0) { + pressedImageHeight -= pressedImageY; + pressedImageY = 0; + } + + if (pressedImageY + pressedImageHeight >= managedButton->height) { + pressedImageHeight = managedButton->height - pressedImageY; + } + + if (managedButton->pressed != NULL) { + blitBufferToBuffer(managedButton->pressed + managedButton->width * pressedImageY + pressedImageX, + pressedImageWidth, + pressedImageHeight, + managedButton->width, + buffer, + pressedImageWidth); + } else { + memset(buffer, 0, pressedImageHeight * pressedImageWidth); + } + + fontDrawText(buffer, + text, + pressedImageWidth, + pressedImageWidth, + widgetGetTextColor() + widgetGetTextFlags()); + + blitBufferToBufferTrans(buffer, + pressedImageWidth, + normalImageHeight, + normalImageWidth, + managedButton->pressed + managedButton->width * pressedImageY + pressedImageX, + managedButton->width); + + internal_free_safe(buffer, __FILE__, __LINE__); // "..\\int\\WINDOW.C", 2078 + + if ((managedButton->field_18 & 0x20) != 0) { + buttonSetMask(managedButton->btn, managedButton->normal); + } + + _win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, 0); + + return true; + } + } + + return false; +} + +// 0x4BA694 +bool _windowFill(float r, float g, float b) +{ + int colorIndex = ((int)(r * 31.0) << 10) | ((int)(g * 31.0) << 5) | (int)(b * 31.0); + + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + windowFill(managedWindow->window, + 0, + 0, + _windowWidth(), + _windowHeight(), + _colorTable[colorIndex]); + + return true; +} + +// 0x4BA738 +bool _windowFillRect(int x, int y, int width, int height, float r, float g, float b) +{ + ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]); + + x = (int)(x * managedWindow->field_54); + y = (int)(y * managedWindow->field_58); + width = (int)(width * managedWindow->field_54); + height = (int)(height * managedWindow->field_58); + + int colorIndex = ((int)(r * 31.0) << 10) | ((int)(g * 31.0) << 5) | (int)(b * 31.0); + + windowFill(managedWindow->window, + x, + y, + width, + height, + _colorTable[colorIndex]); + + return true; +} + // TODO: There is a value returned, not sure which one - could be either // currentRegionIndex or points array. For now it can be safely ignored since // the only caller of this function is opAddRegion, which ignores the returned @@ -965,10 +2036,10 @@ bool _windowAddRegionProc(const char* regionName, Program* program, int a3, int Region* region = managedWindow->regions[index]; if (region != NULL) { if (compat_stricmp(region->name, regionName) == 0) { - region->field_50 = a3; - region->field_54 = a4; - region->field_48 = a5; - region->field_4C = a6; + region->procs[2] = a3; + region->procs[3] = a4; + region->procs[0] = a5; + region->procs[1] = a6; region->program = program; return true; } @@ -990,8 +2061,8 @@ bool _windowAddRegionRightProc(const char* regionName, Program* program, int a3, Region* region = managedWindow->regions[index]; if (region != NULL) { if (compat_stricmp(region->name, regionName) == 0) { - region->field_58 = a3; - region->field_5C = a4; + region->rightProcs[0] = a3; + region->rightProcs[1] = a4; region->program = program; return true; } @@ -1103,9 +2174,8 @@ bool _windowDeleteRegion(const char* regionName) void _updateWindows() { _movieUpdate(); - // TODO: Incomplete. - // _mousemgrUpdate(); - // _checkAllRegions(); + mouseManagerUpdate(); + _checkAllRegions(); _update_widgets(); } @@ -1121,7 +2191,7 @@ bool _windowSetMovieFlags(int flags) if (movieSetFlags(flags) != 0) { return false; } - + return true; } @@ -1150,3 +2220,351 @@ void _windowStopMovie() { _movieStop(); } + +// 0x4BB3A8 +void _drawScaled(unsigned char* dest, int destWidth, int destHeight, int destPitch, unsigned char* src, int srcWidth, int srcHeight, int srcPitch) +{ + if (destWidth == srcWidth && destHeight == srcHeight) { + blitBufferToBuffer(src, srcWidth, srcHeight, srcPitch, dest, destPitch); + return; + } + + int incrementX = (srcWidth << 16) / destWidth; + int incrementY = (srcHeight << 16) / destHeight; + int stepX = incrementX >> 16; + int stepY = incrementY >> 16; + int destSkip = destPitch - destWidth; + int srcSkip = stepY * srcPitch; + + if (srcSkip != 0) { + // Downscaling. + int srcPosY = 0; + for (int y = 0; y < destHeight; y++) { + int srcPosX = 0; + int offset = 0; + for (int x = 0; x < destWidth; x++) { + *dest++ = src[offset]; + offset += stepX; + + srcPosX += incrementX; + if (srcPosX >= 0x10000) { + srcPosX &= 0xFFFF; + } + } + + dest += destSkip; + src += srcSkip; + + srcPosY += stepY; + if (srcPosY >= 0x10000) { + srcPosY &= 0xFFFF; + src += srcPitch; + } + } + } else { + // Upscaling. + int y = 0; + int srcPosY = 0; + while (y < destHeight) { + unsigned char* destPtr = dest; + + int srcPosX = 0; + int offset = 0; + for (int x = 0; x < destWidth; x++) { + *dest++ = src[offset]; + offset += stepX; + + srcPosX += stepX; + if (srcPosX >= 0x10000) { + offset++; + srcPosX &= 0xFFFF; + } + } + + y++; + if (y < destHeight) { + dest += destSkip; + srcPosY += incrementY; + + while (y < destHeight && srcPosY < 0x10000) { + memcpy(dest, destPtr, destWidth); + dest += destWidth; + srcPosY += incrementY; + y++; + } + + srcPosY &= 0xFFFF; + src += srcPitch; + } + } + } +} + +// 0x4BB5D0 +void _drawScaledBuf(unsigned char* dest, int destWidth, int destHeight, unsigned char* src, int srcWidth, int srcHeight) +{ + if (destWidth == srcWidth && destHeight == srcHeight) { + memcpy(dest, src, srcWidth * srcHeight); + return; + } + + int incrementX = (srcWidth << 16) / destWidth; + int incrementY = (srcHeight << 16) / destHeight; + int stepX = incrementX >> 16; + int stepY = incrementY >> 16; + int srcSkip = stepY * srcWidth; + + if (srcSkip != 0) { + // Downscaling. + int srcPosY = 0; + for (int y = 0; y < destHeight; y++) { + int srcPosX = 0; + int offset = 0; + for (int x = 0; x < destWidth; x++) { + *dest++ = src[offset]; + offset += stepX; + + srcPosX += incrementX; + if (srcPosX >= 0x10000) { + srcPosX &= 0xFFFF; + } + } + + src += srcSkip; + + srcPosY += stepY; + if (srcPosY >= 0x10000) { + srcPosY &= 0xFFFF; + src += srcWidth; + } + } + } else { + // Upscaling. + int y = 0; + int srcPosY = 0; + while (y < destHeight) { + unsigned char* destPtr = dest; + + int srcPosX = 0; + int offset = 0; + for (int x = 0; x < destWidth; x++) { + *dest++ = src[offset]; + offset += stepX; + + srcPosX += stepX; + if (srcPosX >= 0x10000) { + offset++; + srcPosX &= 0xFFFF; + } + } + + y++; + if (y < destHeight) { + srcPosY += incrementY; + + while (y < destHeight && srcPosY < 0x10000) { + memcpy(dest, destPtr, destWidth); + dest += destWidth; + srcPosY += incrementY; + y++; + } + + srcPosY &= 0xFFFF; + src += srcWidth; + } + } + } +} + +// 0x4BB7D8 +void _alphaBltBuf(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* alphaWindowBuffer, unsigned char* alphaBuffer, unsigned char* dest, int destPitch) +{ + for (int y = 0; y < srcHeight; y++) { + for (int x = 0; x < srcWidth; x++) { + int rle = (alphaBuffer[0] << 8) + alphaBuffer[1]; + alphaBuffer += 2; + if ((rle & 0x8000) != 0) { + rle &= ~0x8000; + } else if ((rle & 0x4000) != 0) { + rle &= ~0x4000; + memcpy(dest, src, rle); + } else { + unsigned char* destPtr = dest; + unsigned char* srcPtr = src; + unsigned char* alphaWindowBufferPtr = alphaWindowBuffer; + unsigned char* alphaBufferPtr = alphaBuffer; + for (int index = 0; index < rle; index++) { + // TODO: Check. + unsigned char* v1 = &(_cmap[*srcPtr * 3]); + unsigned char* v2 = &(_cmap[*alphaWindowBufferPtr * 3]); + unsigned char alpha = *alphaBufferPtr; + + // NOTE: Original code is slightly different. + unsigned int r = _alphaBlendTable[(v1[0] << 8) | alpha] + _alphaBlendTable[(v2[0] << 8) | alpha]; + unsigned int g = _alphaBlendTable[(v1[1] << 8) | alpha] + _alphaBlendTable[(v2[1] << 8) | alpha]; + unsigned int b = _alphaBlendTable[(v1[2] << 8) | alpha] + _alphaBlendTable[(v2[2] << 8) | alpha]; + unsigned int colorIndex = (r << 10) | (g << 5) | b; + + *destPtr = _colorTable[colorIndex]; + + destPtr++; + srcPtr++; + alphaWindowBufferPtr++; + alphaBufferPtr++; + } + + alphaBuffer += rle; + if ((rle & 1) != 0) { + alphaBuffer++; + } + } + + src += rle; + dest += rle; + alphaWindowBuffer += rle; + } + + src += srcPitch - srcWidth; + dest += destPitch - srcWidth; + } +} + +// 0x4BBFC4 +void _fillBuf3x3(unsigned char* src, int srcWidth, int srcHeight, unsigned char* dest, int destWidth, int destHeight) +{ + int chunkWidth = srcWidth / 3; + int chunkHeight = srcHeight / 3; + + // Middle Middle + unsigned char* ptr = src + srcWidth * chunkHeight + chunkWidth; + for (int x = 0; x < destWidth; x += chunkWidth) { + for (int y = 0; y < destHeight; y += chunkHeight) { + int middleWidth; + if (x + chunkWidth >= destWidth) { + middleWidth = destWidth - x; + } else { + middleWidth = chunkWidth; + } + int middleY = y + chunkHeight; + if (middleY >= destHeight) { + middleY = destHeight; + } + blitBufferToBuffer(ptr, + middleWidth, + middleY - y, + srcWidth, + dest + destWidth * y + x, + destWidth); + } + } + + // Middle Column + for (int x = 0; x < destWidth; x += chunkWidth) { + // Top Middle + int topMiddleX = chunkWidth + x; + if (topMiddleX >= destWidth) { + topMiddleX = destWidth; + } + int topMiddleHeight = chunkHeight; + if (topMiddleHeight >= destHeight) { + topMiddleHeight = destHeight; + } + blitBufferToBuffer(src + chunkWidth, + topMiddleX - x, + topMiddleHeight, + srcWidth, + dest + x, + destWidth); + + // Bottom Middle + int bottomMiddleX = chunkWidth + x; + if (bottomMiddleX >= destWidth) { + bottomMiddleX = destWidth; + } + blitBufferToBuffer(src + srcWidth * 2 * chunkHeight + chunkWidth, + bottomMiddleX - x, + destHeight - (destHeight - chunkHeight), + srcWidth, + dest + destWidth * (destHeight - chunkHeight) + x, + destWidth); + } + + // Middle Row + for (int y = 0; y < destHeight; y += chunkHeight) { + // Middle Left + int middleLeftWidth = chunkWidth; + if (middleLeftWidth >= destWidth) { + middleLeftWidth = destWidth; + } + int middleLeftY = chunkHeight + y; + if (middleLeftY >= destHeight) { + middleLeftY = destHeight; + } + blitBufferToBuffer(src + srcWidth * chunkHeight, + middleLeftWidth, + middleLeftY - y, + srcWidth, + dest + destWidth * y, + destWidth); + + // Middle Right + int middleRightY = chunkHeight + y; + if (middleRightY >= destHeight) { + middleRightY = destHeight; + } + blitBufferToBuffer(src + 2 * chunkWidth + srcWidth * chunkHeight, + destWidth - (destWidth - chunkWidth), + middleRightY - y, + srcWidth, + dest + destWidth * y + destWidth - chunkWidth, + destWidth); + } + + // Top Left + int topLeftWidth = chunkWidth; + if (topLeftWidth >= destWidth) { + topLeftWidth = destWidth; + } + int topLeftHeight = chunkHeight; + if (topLeftHeight >= destHeight) { + topLeftHeight = destHeight; + } + blitBufferToBuffer(src, + topLeftWidth, + topLeftHeight, + srcWidth, + dest, + destWidth); + + // Bottom Left + int bottomLeftHeight = chunkHeight; + if (chunkHeight >= destHeight) { + bottomLeftHeight = destHeight; + } + blitBufferToBuffer(src + chunkWidth * 2, + destWidth - (destWidth - chunkWidth), + bottomLeftHeight, + srcWidth, + dest + destWidth - chunkWidth, + destWidth); + + // Top Right + int topRightWidth = chunkWidth; + if (chunkWidth >= destWidth) { + topRightWidth = destWidth; + } + blitBufferToBuffer(src + srcWidth * 2 * chunkHeight, + topRightWidth, + destHeight - (destHeight - chunkHeight), + srcWidth, + dest + destWidth * (destHeight - chunkHeight), + destWidth); + + // Bottom Right + blitBufferToBuffer(src + 2 * chunkWidth + srcWidth * 2 * chunkHeight, + destWidth - (destWidth - chunkWidth), + destHeight - (destHeight - chunkHeight), + srcWidth, + dest + destWidth * (destHeight - chunkHeight) + (destWidth - chunkWidth), + destWidth); +} diff --git a/src/window.h b/src/window.h index 2dfddeb..9f890b4 100644 --- a/src/window.h +++ b/src/window.h @@ -1,10 +1,18 @@ #ifndef WINDOW_H #define WINDOW_H +#include "geometry.h" +#include "interpreter.h" #include "region.h" +#include "window_manager.h" typedef void (*WINDOWDRAWINGPROC)(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y); typedef void WindowDrawingProc2(unsigned char* buf, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, unsigned char a10); +typedef bool(WindowInputHandler)(int key); +typedef void(WindowDeleteCallback)(int windowIndex, const char* windowName); +typedef void(DisplayInWindowCallback)(int windowIndex, const char* windowName, unsigned char* data, int width, int height); +typedef void(ManagedButtonMouseEventCallback)(void* userData, int eventType); +typedef void(ManagedWindowCreateCallback)(int windowIndex, const char* windowName, int* flagsPtr); typedef enum TextAlignment { TEXT_ALIGNMENT_LEFT, @@ -12,6 +20,20 @@ typedef enum TextAlignment { TEXT_ALIGNMENT_CENTER, } TextAlignment; +typedef enum ManagedButtonMouseEvent { + MANAGED_BUTTON_MOUSE_EVENT_BUTTON_DOWN, + MANAGED_BUTTON_MOUSE_EVENT_BUTTON_UP, + MANAGED_BUTTON_MOUSE_EVENT_ENTER, + MANAGED_BUTTON_MOUSE_EVENT_EXIT, + MANAGED_BUTTON_MOUSE_EVENT_COUNT, +} ManagedButtonMouseEvent; + +typedef enum ManagedButtonRightMouseEvent { + MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_DOWN, + MANAGED_BUTTON_RIGHT_MOUSE_EVENT_BUTTON_UP, + MANAGED_BUTTON_RIGHT_MOUSE_EVENT_COUNT, +} ManagedButtonRightMouseEvent; + extern int _currentHighlightColorR; extern int gWidgetFont; extern int _currentTextColorG; @@ -21,27 +43,86 @@ extern int _currentTextColorR; extern int _currentHighlightColorG; extern int _currentHighlightColorB; +bool _checkRegion(int windowIndex, int mouseX, int mouseY, int mouseEvent); +bool _windowCheckRegion(int windowIndex, int mouseX, int mouseY, int mouseEvent); +bool _windowRefreshRegions(); +bool _checkAllRegions(); +void _windowAddInputFunc(WindowInputHandler* handler); +void _doRegionRightFunc(Region* region, int a2); +void _doRegionFunc(Region* region, int a2); +bool _windowActivateRegion(const char* regionName, int a2); +int _getInput(); +void _doButtonOn(int btn, int keyCode); +void sub_4B6F68(int btn, int mouseEvent); +void _doButtonOff(int btn, int keyCode); +void _doButtonPress(int btn, int keyCode); +void _doButtonRelease(int btn, int keyCode); +void _doRightButtonPress(int btn, int keyCode); +void sub_4B704C(int btn, int mouseEvent); +void _doRightButtonRelease(int btn, int keyCode); +void _setButtonGFX(int width, int height, unsigned char* normal, unsigned char* pressed, unsigned char* a5); +int _windowWidth(); +int _windowHeight(); bool _windowDraw(); +bool _deleteWindow(const char* windowName); +int sub_4B7AC4(const char* windowName, int x, int y, int width, int height); +int sub_4B7E7C(const char* windowName, int x, int y, int width, int height); +int _createWindow(const char* windowName, int x, int y, int width, int height, int a6, int flags); +int _windowOutput(char* string); +bool _windowGotoXY(int x, int y); bool _selectWindowID(int index); +int _selectWindow(const char* windowName); +unsigned char* _windowGetBuffer(); +int _pushWindow(const char* windowName); +int _popWindow(); void _windowPrintBuf(int win, char* string, int stringLength, int width, int maxY, int x, int y, int flags, int textAlignment); char** _windowWordWrap(char* string, int maxLength, int a3, int* substringListLengthPtr); void _windowFreeWordList(char** substringList, int substringListLength); +void _windowWrapLineWithSpacing(int win, char* string, int width, int height, int x, int y, int flags, int textAlignment, int a9); void _windowWrapLine(int win, char* string, int width, int height, int x, int y, int flags, int textAlignment); bool _windowPrintRect(char* string, int a2, int textAlignment); bool _windowFormatMessage(char* string, int x, int y, int width, int height, int textAlignment); +bool _windowPrint(char* string, int a2, int x, int y, int a5); +void _displayInWindow(unsigned char* data, int width, int height, int pitch); +void _displayFile(char* fileName); +void _displayFileRaw(char* fileName); +bool _windowDisplay(char* fileName, int x, int y, int width, int height); +bool _windowDisplayBuf(unsigned char* src, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight); +int _windowGetXres(); int _windowGetYres(); +void _removeProgramReferences_3(Program* program); void _initWindow(int resolution, int a2); void _windowClose(); bool _windowDeleteButton(const char* buttonName); bool _windowSetButtonFlag(const char* buttonName, int value); -bool _windowAddButtonProc(const char* buttonName, Program* program, int a3, int a4, int a5, int a6); +bool _windowAddButton(const char* buttonName, int x, int y, int width, int height, int flags); +bool _windowAddButtonGfx(const char* buttonName, char* pressedFileName, char* normalFileName, char* hoverFileName); +bool _windowAddButtonProc(const char* buttonName, Program* program, int mouseEnterProc, int mouseExitProc, int mouseDownProc, int mouseUpProc); +bool _windowAddButtonRightProc(const char* buttonName, Program* program, int rightMouseDownProc, int rightMouseUpProc); +bool _windowAddButtonCfunc(const char* buttonName, ManagedButtonMouseEventCallback* callback, void* userData); +bool _windowAddButtonRightCfunc(const char* buttonName, ManagedButtonMouseEventCallback* callback, void* userData); +bool _windowAddButtonText(const char* buttonName, const char* text); +bool _windowAddButtonTextWithOffsets(const char* buttonName, const char* text, int pressedImageOffsetX, int pressedImageOffsetY, int normalImageOffsetX, int normalImageOffsetY); +bool _windowFill(float r, float g, float b); +bool _windowFillRect(int x, int y, int width, int height, float r, float g, float b); +void _windowEndRegion(); bool _windowCheckRegionExists(const char* regionName); +bool _windowStartRegion(int initialCapacity); +bool _windowAddRegionPoint(int x, int y, bool a3); bool _windowAddRegionProc(const char* regionName, Program* program, int a3, int a4, int a5, int a6); bool _windowAddRegionRightProc(const char* regionName, Program* program, int a3, int a4); bool _windowSetRegionFlag(const char* regionName, int value); +bool _windowAddRegionName(const char* regionName); bool _windowDeleteRegion(const char* regionName); void _updateWindows(); +int _windowMoviePlaying(); bool _windowSetMovieFlags(int flags); +bool _windowPlayMovie(char* filePath); +bool _windowPlayMovieRect(char* filePath, int a2, int a3, int a4, int a5); void _windowStopMovie(); +void _drawScaled(unsigned char* dest, int destWidth, int destHeight, int destPitch, unsigned char* src, int srcWidth, int srcHeight, int srcPitch); +void _drawScaledBuf(unsigned char* dest, int destWidth, int destHeight, unsigned char* src, int srcWidth, int srcHeight); +void _alphaBltBuf(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* alphaWindowBuffer, unsigned char* alphaBuffer, unsigned char* dest, int destPitch); +void _fillBuf3x3(unsigned char* src, int srcWidth, int srcHeight, unsigned char* dest, int destWidth, int destHeight); #endif /* WINDOW_H */ diff --git a/src/window_manager.cc b/src/window_manager.cc index 5db57ae..9840c71 100644 --- a/src/window_manager.cc +++ b/src/window_manager.cc @@ -24,20 +24,16 @@ static void windowFree(int win); static void _win_buffering(bool a1); static void _win_move(int win_index, int x, int y); -static void _GNW_win_refresh(Window* window, Rect* rect, unsigned char* a3); static void _win_clip(Window* window, RectListNode** rect, unsigned char* a3); static void _win_drag(int win); static void _refresh_all(Rect* rect, unsigned char* a2); static Button* buttonGetButton(int btn, Window** out_win); -static void _win_text(int win, char** fileNameList, int fileNameListLength, int maxWidth, int x, int y, int flags); static int paletteOpenFileImpl(const char* path, int flags); static int paletteReadFileImpl(int fd, void* buf, size_t count); static int paletteCloseFileImpl(int fd); -static int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, unsigned char* hover, int a5); static Button* buttonCreateInternal(int win, int x, int y, int width, int height, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, int flags, unsigned char* up, unsigned char* dn, unsigned char* hover); static int _GNW_check_buttons(Window* window, int* out_a2); static bool _button_under_mouse(Button* button, Rect* rect); -static int _win_last_button_winID(); static void buttonFree(Button* ptr); static int _win_group_check_buttons(int a1, int* a2, int a3, void (*a4)(int)); static int _button_check_group(Button* button); @@ -59,7 +55,7 @@ static HANDLE _GNW95_title_mutex = INVALID_HANDLE_VALUE; bool gWindowSystemInitialized = false; // 0x51E3E4 -static int _GNW_wcolor[6] = { +int _GNW_wcolor[6] = { 0, 0, 0, @@ -244,7 +240,7 @@ int windowManagerInit(VideoSystemInitProc* videoSystemInitProc, VideoSystemExitP window->buttonListHead = NULL; window->field_34 = NULL; window->field_38 = 0; - window->field_3C = 0; + window->menuBar = NULL; gWindowsLength = 1; gWindowSystemInitialized = 1; @@ -363,14 +359,14 @@ int windowCreate(int x, int y, int width, int height, int a4, int flags) a4 = _colorTable[_GNW_wcolor[0]]; } } else if ((a4 & 0xFF00) != 0) { - int v1 = (a4 & 0xFF00) >> 8; - a4 = (a4 & ~0xFFFF) | _colorTable[_GNW_wcolor[v1]]; + int colorIndex = (a4 & 0xFF) - 1; + a4 = (a4 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]]; } window->buttonListHead = 0; window->field_34 = 0; window->field_38 = 0; - window->field_3C = 0; + window->menuBar = NULL; window->blitProc = blitBufferToBufferTrans; window->field_20 = a4; gOrderedWindowIds[index] = gWindowsLength; @@ -454,8 +450,8 @@ void windowFree(int win) internal_free(window->buffer); } - if (window->field_3C != NULL) { - internal_free(window->field_3C); + if (window->menuBar != NULL) { + internal_free(window->menuBar); } Button* curr = window->buttonListHead; @@ -500,7 +496,7 @@ void windowDrawBorder(int win) } // 0x4D684C -void windowDrawText(int win, char* str, int a3, int x, int y, int a6) +void windowDrawText(int win, const char* str, int a3, int x, int y, int a6) { int v7; int v14; @@ -1021,7 +1017,7 @@ void _win_drag(int win) tickersExecute(); - if (_vcr_update() != 3) { + if (vcrUpdate() != 3) { _mouse_info(); } @@ -1209,10 +1205,10 @@ int _GNW_check_menu_bars(int a1) int v1 = a1; for (int index = gWindowsLength - 1; index >= 1; index--) { Window* window = gWindows[index]; - if (window->field_3C != NULL) { - for (int v2 = 0; v2 < window->field_3C->entriesCount; v2++) { - if (v1 == window->field_3C->entries[v2].field_10) { - v1 = _GNW_process_menu(window->field_3C, v2); + if (window->menuBar != NULL) { + for (int pulldownIndex = 0; pulldownIndex < window->menuBar->pulldownsLength; pulldownIndex++) { + if (v1 == window->menuBar->pulldowns[pulldownIndex].keyCode) { + v1 = _GNW_process_menu(window->menuBar, pulldownIndex); break; } } @@ -1242,7 +1238,7 @@ void _win_text(int win, char** fileNameList, int fileNameListLength, int maxWidt int width = window->width; unsigned char* ptr = window->buffer + y * width + x; int lineHeight = fontGetLineHeight(); - + int step = width * lineHeight; int v1 = lineHeight / 2; int v2 = v1 + 1; @@ -1376,6 +1372,103 @@ int buttonCreate(int win, int x, int y, int width, int height, int mouseEnterEve return button->id; } +// 0x4D8308 +int _win_register_text_button(int win, int x, int y, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, const char* title, int flags) +{ + Window* window = windowGetWindow(win); + + if (!gWindowSystemInitialized) { + return -1; + } + + if (window == NULL) { + return -1; + } + + int buttonWidth = fontGetStringWidth(title) + 16; + int buttonHeight = fontGetLineHeight() + 7; + unsigned char* normal = (unsigned char*)internal_malloc(buttonWidth * buttonHeight); + if (normal == NULL) { + return -1; + } + + unsigned char* pressed = (unsigned char*)internal_malloc(buttonWidth * buttonHeight); + if (pressed == NULL) { + internal_free(normal); + return -1; + } + + if (window->field_20 == 256 && _GNW_texture != NULL) { + // TODO: Incomplete. + } else { + bufferFill(normal, buttonWidth, buttonHeight, buttonWidth, window->field_20); + bufferFill(pressed, buttonWidth, buttonHeight, buttonWidth, window->field_20); + } + + _lighten_buf(normal, buttonWidth, buttonHeight, buttonWidth); + + fontDrawText(normal + buttonWidth * 3 + 8, title, buttonWidth, buttonWidth, _colorTable[_GNW_wcolor[3]]); + bufferDrawRectShadowed(normal, + buttonWidth, + 2, + 2, + buttonWidth - 3, + buttonHeight - 3, + _colorTable[_GNW_wcolor[1]], + _colorTable[_GNW_wcolor[2]]); + bufferDrawRectShadowed(normal, + buttonWidth, + 1, + 1, + buttonWidth - 2, + buttonHeight - 2, + _colorTable[_GNW_wcolor[1]], + _colorTable[_GNW_wcolor[2]]); + bufferDrawRect(normal, buttonWidth, 0, 0, buttonWidth - 1, buttonHeight - 1, _colorTable[0]); + + fontDrawText(pressed + buttonWidth * 4 + 9, title, buttonWidth, buttonWidth, _colorTable[_GNW_wcolor[3]]); + bufferDrawRectShadowed(pressed, + buttonWidth, + 2, + 2, + buttonWidth - 3, + buttonHeight - 3, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + bufferDrawRectShadowed(pressed, + buttonWidth, + 1, + 1, + buttonWidth - 2, + buttonHeight - 2, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + bufferDrawRect(pressed, buttonWidth, 0, 0, buttonWidth - 1, buttonHeight - 1, _colorTable[0]); + + Button* button = buttonCreateInternal(win, + x, + y, + buttonWidth, + buttonHeight, + mouseEnterEventCode, + mouseExitEventCode, + mouseDownEventCode, + mouseUpEventCode, + flags, + normal, + pressed, + NULL); + if (button == NULL) { + internal_free(normal); + internal_free(pressed); + return -1; + } + + _button_draw(button, window, button->mouseUpImage, 0, NULL, 0); + + return button->id; +} + // 0x4D8674 int _win_register_button_disable(int btn, unsigned char* up, unsigned char* down, unsigned char* hover) { diff --git a/src/window_manager.h b/src/window_manager.h index 42b4b5e..cd712e6 100644 --- a/src/window_manager.h +++ b/src/window_manager.h @@ -61,26 +61,23 @@ typedef enum ButtonFlags { BUTTON_FLAG_RIGHT_MOUSE_BUTTON_CONFIGURED = 0x080000, } ButtonFlags; -typedef struct struc_176 { - int field_0; - int field_4; - int field_8; - int field_C; - int field_10; - int field_14; - int field_18; +typedef struct MenuPulldown { + Rect rect; + int keyCode; + int itemsLength; + char** items; int field_1C; int field_20; -} struc_176; +} MenuPulldown; -typedef struct struc_177 { +typedef struct MenuBar { int win; Rect rect; - int entriesCount; - struc_176 entries[15]; - int field_234; - int field_238; -} struc_177; + int pulldownsLength; + MenuPulldown pulldowns[15]; + int borderColor; + int backgroundColor; +} MenuBar; typedef void WindowBlitProc(unsigned char* src, int width, int height, int srcPitch, unsigned char* dest, int destPitch); @@ -102,7 +99,7 @@ typedef struct Window { Button* buttonListHead; Button* field_34; Button* field_38; - struc_177* field_3C; + MenuBar* menuBar; WindowBlitProc* blitProc; } Window; @@ -151,13 +148,15 @@ typedef int(VideoSystemInitProc)(); typedef void(VideoSystemExitProc)(); extern bool gWindowSystemInitialized; +extern int _GNW_wcolor[6]; int windowManagerInit(VideoSystemInitProc* videoSystemInitProc, VideoSystemExitProc* videoSystemExitProc, int a3); void windowManagerExit(void); int windowCreate(int x, int y, int width, int height, int a4, int flags); void windowDestroy(int win); void windowDrawBorder(int win); -void windowDrawText(int win, char* str, int a3, int x, int y, int a6); +void windowDrawText(int win, const char* str, int a3, int x, int y, int a6); +void _win_text(int win, char** fileNameList, int fileNameListLength, int maxWidth, int x, int y, int flags); void windowDrawLine(int win, int left, int top, int right, int bottom, int color); void windowDrawRect(int win, int left, int top, int right, int bottom, int color); void windowFill(int win, int x, int y, int width, int height, int a6); @@ -165,6 +164,7 @@ void windowUnhide(int win); void windowHide(int win); void windowRefresh(int win); void windowRefreshRect(int win, const Rect* rect); +void _GNW_win_refresh(Window* window, Rect* rect, unsigned char* a3); void windowRefreshAll(Rect* rect); void _win_get_mouse_buf(unsigned char* a1); Window* windowGetWindow(int win); @@ -178,13 +178,16 @@ int _GNW_check_menu_bars(int a1); void programWindowSetTitle(const char* title); bool showMesageBox(const char* str); int buttonCreate(int win, int x, int y, int width, int height, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, unsigned char* up, unsigned char* dn, unsigned char* hover, int flags); +int _win_register_text_button(int win, int x, int y, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, const char* title, int flags); int _win_register_button_disable(int btn, unsigned char* up, unsigned char* down, unsigned char* hover); +int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, unsigned char* hover, int a5); int buttonSetMouseCallbacks(int btn, ButtonCallback* mouseEnterProc, ButtonCallback* mouseExitProc, ButtonCallback* mouseDownProc, ButtonCallback* mouseUpProc); int buttonSetRightMouseCallbacks(int btn, int rightMouseDownEventCode, int rightMouseUpEventCode, ButtonCallback* rightMouseDownProc, ButtonCallback* rightMouseUpProc); int buttonSetCallbacks(int btn, ButtonCallback* onPressed, ButtonCallback* onUnpressed); int buttonSetMask(int btn, unsigned char* mask); bool _win_button_down(int btn); int buttonGetWindowId(int btn); +int _win_last_button_winID(); int buttonDestroy(int btn); int buttonEnable(int btn); int buttonDisable(int btn); diff --git a/src/window_manager_private.cc b/src/window_manager_private.cc index 7e5d937..ee2fdf2 100644 --- a/src/window_manager_private.cc +++ b/src/window_manager_private.cc @@ -1,6 +1,8 @@ #include "window_manager_private.h" +#include "color.h" #include "core.h" +#include "draw.h" #include "memory.h" #include "text_font.h" #include "window_manager.h" @@ -22,22 +24,11 @@ typedef struct STRUCT_6B2370 { int field_8; } STRUCT_6B2370; -static void _win_debug_delete(); -static int _win_register_menu_bar(int win, int x, int y, int width, int height, int a6, int a7); -static int _win_register_menu_pulldown(int win, int x, char* str, int a4); -static int _win_width_needed(char** fileNameList, int fileNameListLength); -static int _calc_max_field_chars_wcursor(int a1, int a2); -static void _tm_watch_msgs(); -static void _tm_kill_msg(); -static void _tm_kill_out_of_order(int a1); -static void _tm_click_response(int btn); -static int _tm_index_active(int a1); - // 0x51E414 static int _wd = -1; // 0x51E418 -static int _curr_menu = 0; +static MenuBar* _curr_menu = NULL; // 0x51E41C static bool _tm_watch_active = false; @@ -82,14 +73,747 @@ static int _currx; // 0x6B23D0 char gProgramWindowTitle[256]; -// 0x4DC30C -int _win_debug(char* a1) +// 0x4DA6C0 +int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int a7) +{ + return _win_list_select_at(title, fileList, fileListLength, callback, x, y, a7, 0); +} + +// 0x4DA70C +int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int a7, int a8) { if (!gWindowSystemInitialized) { return -1; } - // TODO: Incomplete. + int listViewWidth = _win_width_needed(items, itemsLength); + int windowWidth = listViewWidth + 16; + + int titleWidth = fontGetStringWidth(title); + if (titleWidth > windowWidth) { + windowWidth = titleWidth; + listViewWidth = titleWidth - 16; + } + + windowWidth += 20; + + int win; + int windowHeight; + int listViewCapacity = 10; + for (int heightMultiplier = 13; heightMultiplier > 8; heightMultiplier--) { + windowHeight = heightMultiplier * fontGetLineHeight() + 22; + win = windowCreate(x, y, windowWidth, windowHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); + if (win != -1) { + break; + } + listViewCapacity--; + } + + if (win == -1) { + return -1; + } + + Window* window = windowGetWindow(win); + Rect* windowRect = &(window->rect); + unsigned char* windowBuffer = window->buffer; + + bufferDrawRect(windowBuffer, + windowWidth, + 0, + 0, + windowWidth - 1, + windowHeight - 1, + _colorTable[0]); + bufferDrawRectShadowed(windowBuffer, + windowWidth, + 1, + 1, + windowWidth - 2, + windowHeight - 2, + _colorTable[_GNW_wcolor[1]], + _colorTable[_GNW_wcolor[2]]); + + bufferFill(windowBuffer + windowWidth * 5 + 5, + windowWidth - 11, + fontGetLineHeight() + 3, + windowWidth, + _colorTable[_GNW_wcolor[0]]); + + fontDrawText(windowBuffer + windowWidth / 2 + 8 * windowWidth - fontGetStringWidth(title) / 2, + title, + windowWidth, + windowWidth, + _colorTable[_GNW_wcolor[3]]); + + bufferDrawRectShadowed(windowBuffer, + windowWidth, + 5, + 5, + windowWidth - 6, + fontGetLineHeight() + 8, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + + int listViewX = 8; + int listViewY = fontGetLineHeight() + 16; + unsigned char* listViewBuffer = windowBuffer + windowWidth * listViewY + listViewX; + int listViewMaxY = listViewCapacity * fontGetLineHeight() + listViewY; + + bufferFill(listViewBuffer + windowWidth * (-2) + (-3), + listViewWidth + listViewX - 2, + listViewCapacity * fontGetLineHeight() + 2, + windowWidth, + _colorTable[_GNW_wcolor[0]]); + + int scrollOffset = a8; + if (a8 < 0 || a8 >= itemsLength) { + scrollOffset = 0; + } + + // Relative to `scrollOffset`. + int selectedItemIndex; + if (itemsLength - scrollOffset < listViewCapacity) { + int newScrollOffset = itemsLength - listViewCapacity; + if (newScrollOffset < 0) { + newScrollOffset = 0; + } + int oldScrollOffset = scrollOffset; + scrollOffset = newScrollOffset; + selectedItemIndex = oldScrollOffset - newScrollOffset; + } else { + selectedItemIndex = 0; + } + + char** itemsTO = items + a8; + _win_text(win, + items + a8, + itemsLength < listViewCapacity ? itemsLength : listViewCapacity, + listViewWidth, + listViewX, + listViewY, + a7 | 0x2000000); + + _lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(), + listViewWidth, + fontGetLineHeight(), + windowWidth); + + bufferDrawRectShadowed(windowBuffer, + windowWidth, + 5, + listViewY - 3, + listViewWidth + 10, + listViewMaxY, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + + _win_register_text_button(win, + windowWidth - 25, + listViewY - 3, + -1, + -1, + KEY_ARROW_UP, + -1, + "\x18", + 0); + + _win_register_text_button(win, + windowWidth - 25, + listViewMaxY - fontGetLineHeight() - 5, + -1, + -1, + KEY_ARROW_DOWN, + -1, + "\x19", + 0); + + _win_register_text_button(win, + windowWidth / 2 - 32, + windowHeight - 8 - fontGetLineHeight() - 6, + -1, + -1, + -1, + KEY_ESCAPE, + "Done", + 0); + + int scrollbarX = windowWidth - 21; + int scrollbarY = listViewY + fontGetLineHeight() + 7; + int scrollbarKnobSize = 14; + int scrollbarHeight = listViewMaxY - scrollbarY; + unsigned char* scrollbarBuffer = windowBuffer + windowWidth * scrollbarY + scrollbarX; + + bufferFill(scrollbarBuffer, + scrollbarKnobSize + 1, + scrollbarHeight - fontGetLineHeight() - 8, + windowWidth, + _colorTable[_GNW_wcolor[0]]); + + buttonCreate(win, + scrollbarX, + scrollbarY, + scrollbarKnobSize + 1, + scrollbarHeight - fontGetLineHeight() - 8, + -1, + -1, + 2048, + -1, + NULL, + NULL, + NULL, + 0); + + bufferDrawRectShadowed(windowBuffer, + windowWidth, + windowWidth - 22, + scrollbarY - 1, + scrollbarX + scrollbarKnobSize + 1, + listViewMaxY - fontGetLineHeight() - 9, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + bufferDrawRectShadowed(windowBuffer, + windowWidth, + scrollbarX, + scrollbarY, + scrollbarX + scrollbarKnobSize, + scrollbarY + scrollbarKnobSize, + _colorTable[_GNW_wcolor[1]], + _colorTable[_GNW_wcolor[2]]); + + _lighten_buf(scrollbarBuffer, scrollbarKnobSize, scrollbarKnobSize, windowWidth); + + for (int index = 0; index < listViewCapacity; index++) { + buttonCreate(win, + listViewX, + listViewY + index * fontGetLineHeight(), + listViewWidth, + fontGetLineHeight(), + 512 + index, + -1, + 1024 + index, + -1, + NULL, + NULL, + NULL, + 0); + } + + buttonCreate(win, + 0, + 0, + windowWidth, + fontGetLineHeight() + 8, + -1, + -1, + -1, + -1, + NULL, + NULL, + NULL, + BUTTON_FLAG_0x10); + + windowRefresh(win); + + int absoluteSelectedItemIndex = -1; + + // Relative to `scrollOffset`. + int previousSelectedItemIndex = -1; + while (1) { + int keyCode = _get_input(); + int mouseX; + int mouseY; + mouseGetPosition(&mouseX, &mouseY); + + if (keyCode == KEY_RETURN || (keyCode >= 1024 && keyCode < listViewCapacity + 1024)) { + if (selectedItemIndex != -1) { + absoluteSelectedItemIndex = scrollOffset + selectedItemIndex; + if (absoluteSelectedItemIndex < itemsLength) { + if (callback == NULL) { + break; + } + + callback(items, absoluteSelectedItemIndex); + } + absoluteSelectedItemIndex = -1; + } + } else if (keyCode == 2048) { + if (window->rect.top + scrollbarY > mouseY) { + keyCode = KEY_PAGE_UP; + } else if (window->rect.top + scrollbarKnobSize + scrollbarY < mouseY) { + keyCode = KEY_PAGE_DOWN; + } + } + + if (keyCode == KEY_ESCAPE) { + break; + } + + if (keyCode >= 512 && keyCode < listViewCapacity + 512) { + int itemIndex = keyCode - 512; + if (itemIndex != selectedItemIndex && itemIndex < itemsLength) { + previousSelectedItemIndex = selectedItemIndex; + selectedItemIndex = itemIndex; + keyCode = -3; + } else { + continue; + } + } else { + switch (keyCode) { + case KEY_HOME: + if (scrollOffset > 0) { + keyCode = -4; + scrollOffset = 0; + } + break; + case KEY_ARROW_UP: + if (selectedItemIndex > 0) { + keyCode = -3; + previousSelectedItemIndex = selectedItemIndex; + selectedItemIndex -= 1; + } else { + if (scrollOffset > 0) { + keyCode = -4; + scrollOffset -= 1; + } + } + break; + case KEY_PAGE_UP: + if (scrollOffset > 0) { + scrollOffset -= listViewCapacity; + if (scrollOffset < 0) { + scrollOffset = 0; + } + keyCode = -4; + } + break; + case KEY_END: + if (scrollOffset < itemsLength - listViewCapacity) { + keyCode = -4; + scrollOffset = itemsLength - listViewCapacity; + } + break; + case KEY_ARROW_DOWN: + if (selectedItemIndex < listViewCapacity - 1 && selectedItemIndex < itemsLength - 1) { + keyCode = -3; + previousSelectedItemIndex = selectedItemIndex; + selectedItemIndex += 1; + } else { + if (scrollOffset + listViewCapacity < itemsLength) { + keyCode = -4; + scrollOffset += 1; + } + } + break; + case KEY_PAGE_DOWN: + if (scrollOffset < itemsLength - listViewCapacity) { + scrollOffset += listViewCapacity; + if (scrollOffset > itemsLength - listViewCapacity) { + scrollOffset = itemsLength - listViewCapacity; + } + keyCode = -4; + } + break; + default: + if (itemsLength > listViewCapacity) { + if ((keyCode >= 'a' && keyCode <= 'z') + || (keyCode >= 'A' && keyCode <= 'Z')) { + int found = _find_first_letter(keyCode, items, itemsLength); + if (found != -1) { + scrollOffset = found; + if (scrollOffset > itemsLength - listViewCapacity) { + scrollOffset = itemsLength - listViewCapacity; + } + keyCode = -4; + selectedItemIndex = found - scrollOffset; + } + } + } + break; + } + } + + if (keyCode == -4) { + bufferFill(listViewBuffer, + listViewWidth, + listViewMaxY - listViewY, + windowWidth, + _colorTable[_GNW_wcolor[0]]); + + _win_text(win, + items + scrollOffset, + itemsLength < listViewCapacity ? itemsLength : listViewCapacity, + listViewWidth, + listViewX, + listViewY, + a7 | 0x2000000); + + _lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(), + listViewWidth, + fontGetLineHeight(), + windowWidth); + + if (itemsLength > listViewCapacity) { + bufferFill(windowBuffer + windowWidth * scrollbarY + scrollbarX, + scrollbarKnobSize + 1, + scrollbarKnobSize + 1, + windowWidth, + _colorTable[_GNW_wcolor[0]]); + + scrollbarY = (scrollOffset * (listViewMaxY - listViewY - 2 * fontGetLineHeight() - 16 - scrollbarKnobSize - 1)) / (itemsLength - listViewCapacity) + + listViewY + fontGetLineHeight() + 7; + + bufferDrawRectShadowed(windowBuffer, + windowWidth, + scrollbarX, + scrollbarY, + scrollbarX + scrollbarKnobSize, + scrollbarY + scrollbarKnobSize, + _colorTable[_GNW_wcolor[1]], + _colorTable[_GNW_wcolor[2]]); + + _lighten_buf(windowBuffer + windowWidth * scrollbarY + scrollbarX, + scrollbarKnobSize, + scrollbarKnobSize, + windowWidth); + + _GNW_win_refresh(window, windowRect, NULL); + } + } else if (keyCode == -3) { + Rect itemRect; + itemRect.left = windowRect->left + listViewX; + itemRect.right = itemRect.left + listViewWidth; + + if (previousSelectedItemIndex != -1) { + itemRect.top = windowRect->top + listViewY + previousSelectedItemIndex * fontGetLineHeight(); + itemRect.bottom = itemRect.top + fontGetLineHeight(); + + bufferFill(listViewBuffer + windowWidth * previousSelectedItemIndex * fontGetLineHeight(), + listViewWidth, + fontGetLineHeight(), + windowWidth, + _colorTable[_GNW_wcolor[0]]); + + int color; + if ((a7 & 0xFF00) != 0) { + int colorIndex = (a7 & 0xFF) - 1; + color = (a7 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]]; + } else { + color = a7; + } + + fontDrawText(listViewBuffer + windowWidth * previousSelectedItemIndex * fontGetLineHeight(), + items[scrollOffset + previousSelectedItemIndex], + windowWidth, + windowWidth, + color); + + _GNW_win_refresh(window, &itemRect, NULL); + } + + if (selectedItemIndex != -1) { + itemRect.top = windowRect->top + listViewY + selectedItemIndex * fontGetLineHeight(); + itemRect.bottom = itemRect.top + fontGetLineHeight(); + + _lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(), + listViewWidth, + fontGetLineHeight(), + windowWidth); + + _GNW_win_refresh(window, &itemRect, NULL); + } + } + } + + windowDestroy(win); + + return absoluteSelectedItemIndex; +} + +// 0x4DB478 +int _win_get_str(char* dest, int length, const char* title, int x, int y) +{ + if (!gWindowSystemInitialized) { + return -1; + } + + int titleWidth = fontGetStringWidth(title) + 12; + if (titleWidth < fontGetMonospacedCharacterWidth() * length) { + titleWidth = fontGetMonospacedCharacterWidth() * length; + } + + int windowWidth = titleWidth + 16; + if (windowWidth < 160) { + windowWidth = 160; + } + + int windowHeight = 5 * fontGetLineHeight() + 16; + + int win = windowCreate(x, y, windowWidth, windowHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); + if (win == -1) { + return -1; + } + + windowDrawBorder(win); + + unsigned char* windowBuffer = windowGetBuffer(win); + + bufferFill(windowBuffer + windowWidth * (fontGetLineHeight() + 14) + 14, + windowWidth - 28, + fontGetLineHeight() + 2, + windowWidth, + _colorTable[_GNW_wcolor[0]]); + fontDrawText(windowBuffer + windowWidth * 8 + 8, title, windowWidth, windowWidth, _colorTable[_GNW_wcolor[4]]); + + bufferDrawRectShadowed(windowBuffer, + windowWidth, + 14, + fontGetLineHeight() + 14, + windowWidth - 14, + 2 * fontGetLineHeight() + 16, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + + _win_register_text_button(win, + windowWidth / 2 - 72, + windowHeight - 8 - fontGetLineHeight() - 6, + -1, + -1, + -1, + KEY_RETURN, + "Done", + 0); + + _win_register_text_button(win, + windowWidth / 2 + 8, + windowHeight - 8 - fontGetLineHeight() - 6, + -1, + -1, + -1, + KEY_ESCAPE, + "Cancel", + 0); + + windowRefresh(win); + + _win_input_str(win, + dest, + length, + 16, + fontGetLineHeight() + 16, + _colorTable[_GNW_wcolor[3]], + _colorTable[_GNW_wcolor[0]]); + + windowDestroy(win); + + return 0; +} + +// 0x4DBA98 +int _win_msg(const char* string, int x, int y, int flags) +{ + if (!gWindowSystemInitialized) { + return -1; + } + + int windowHeight = 3 * fontGetLineHeight() + 16; + + int windowWidth = fontGetStringWidth(string) + 16; + if (windowWidth < 80) { + windowWidth = 80; + } + + windowWidth += 16; + + int win = windowCreate(x, y, windowWidth, windowHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); + if (win == -1) { + return -1; + } + + windowDrawBorder(win); + + Window* window = windowGetWindow(win); + unsigned char* windowBuffer = window->buffer; + + int color; + if ((flags & 0xFF00) != 0) { + int index = (flags & 0xFF) - 1; + color = _colorTable[_GNW_wcolor[index]]; + color |= flags & ~0xFFFF; + } else { + color = flags; + } + + fontDrawText(windowBuffer + windowWidth * 8 + 16, string, windowWidth, windowWidth, color); + + _win_register_text_button(win, + windowWidth / 2 - 32, + windowHeight - 8 - fontGetLineHeight() - 6, + -1, + -1, + -1, + KEY_ESCAPE, + "Done", + 0); + + windowRefresh(win); + + while (_get_input() != KEY_ESCAPE) { + } + + windowDestroy(win); + + return 0; +} + +// 0x4DBBC4 +int _win_pull_down(char** items, int itemsLength, int x, int y, int a5) +{ + if (!gWindowSystemInitialized) { + return -1; + } + + Rect rect; + int win = _create_pull_down(items, itemsLength, x, y, a5, _colorTable[_GNW_wcolor[0]], &rect); + if (win == -1) { + return -1; + } + + return sub_4DBD04(win, &rect, items, itemsLength, a5, _colorTable[_GNW_wcolor[0]], NULL, -1); +} + +// 0x4DBC34 +int _create_pull_down(char** stringList, int stringListLength, int x, int y, int a5, int a6, Rect* rect) +{ + int windowHeight = stringListLength * fontGetLineHeight() + 16; + int windowWidth = _win_width_needed(stringList, stringListLength) + 4; + if (windowHeight < 2 || windowWidth < 2) { + return -1; + } + + int win = windowCreate(x, y, windowWidth, windowHeight, a6, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); + if (win == -1) { + return -1; + } + + _win_text(win, stringList, stringListLength, windowWidth - 4, 2, 8, a5); + windowDrawRect(win, 0, 0, windowWidth - 1, windowHeight - 1, _colorTable[0]); + windowDrawRect(win, 1, 1, windowWidth - 2, windowHeight - 2, a5); + windowRefresh(win); + windowGetRect(win, rect); + + return win; +} + +// 0x4DC30C +int _win_debug(char* string) +{ + if (!gWindowSystemInitialized) { + return -1; + } + + int lineHeight = fontGetLineHeight(); + + if (_wd == -1) { + _wd = windowCreate(80, 80, 300, 192, 256, WINDOW_FLAG_0x04); + if (_wd == -1) { + return -1; + } + + windowDrawBorder(_wd); + + Window* window = windowGetWindow(_wd); + unsigned char* windowBuffer = window->buffer; + + windowFill(_wd, 8, 8, 284, lineHeight, 0x100 | 1); + + windowDrawText(_wd, + "Debug", + 0, + (300 - fontGetStringWidth("Debug")) / 2, + 8, + 0x2000000 | 0x100 | 4); + + bufferDrawRectShadowed(windowBuffer, + 300, + 8, + 8, + 291, + lineHeight + 8, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + + windowFill(_wd, 9, 26, 282, 135, 0x100 | 1); + + bufferDrawRectShadowed(windowBuffer, + 300, + 8, + 25, + 291, + lineHeight + 145, + _colorTable[_GNW_wcolor[2]], + _colorTable[_GNW_wcolor[1]]); + + _currx = 9; + _curry = 26; + + int btn = _win_register_text_button(_wd, + (300 - fontGetStringWidth("Close")) / 2, + 192 - 8 - lineHeight - 6, + -1, + -1, + -1, + -1, + "Close", + 0); + buttonSetMouseCallbacks(btn, NULL, NULL, NULL, _win_debug_delete); + + buttonCreate(_wd, + 8, + 8, + 284, + lineHeight, + -1, + -1, + -1, + -1, + NULL, + NULL, + NULL, + BUTTON_FLAG_0x10); + } + + char temp[2]; + temp[1] = '\0'; + + char* pch = string; + while (*pch != '\0') { + int characterWidth = fontGetCharacterWidth(*pch); + if (*pch == '\n' || _currx + characterWidth > 291) { + _currx = 9; + _curry += lineHeight; + } + + while (160 - _curry < lineHeight) { + Window* window = windowGetWindow(_wd); + unsigned char* windowBuffer = window->buffer; + blitBufferToBuffer(windowBuffer + lineHeight * 300 + 300 * 26 + 9, + 282, + 134 - lineHeight - 1, + 300, + windowBuffer + 300 * 26 + 9, + 300); + _curry -= lineHeight; + windowFill(_wd, 9, _curry, 282, lineHeight, 0x100 | 1); + } + + if (*pch != '\n') { + temp[0] = *pch; + windowDrawText(_wd, temp, 0, _currx, _curry, 0x2000000 | 0x100 | 4); + _currx += characterWidth + fontGetLetterSpacing(); + } + + pch++; + } windowRefresh(_wd); @@ -97,14 +821,14 @@ int _win_debug(char* a1) } // 0x4DC65C -void _win_debug_delete() +void _win_debug_delete(int btn, int keyCode) { windowDestroy(_wd); _wd = -1; } // 0x4DC674 -int _win_register_menu_bar(int win, int x, int y, int width, int height, int a6, int a7) +int _win_register_menu_bar(int win, int x, int y, int width, int height, int borderColor, int backgroundColor) { Window* window = windowGetWindow(win); @@ -116,7 +840,7 @@ int _win_register_menu_bar(int win, int x, int y, int width, int height, int a6, return -1; } - if (window->field_3C != NULL) { + if (window->menuBar != NULL) { return -1; } @@ -130,28 +854,28 @@ int _win_register_menu_bar(int win, int x, int y, int width, int height, int a6, return -1; } - struc_177* v14 = window->field_3C = (struc_177*)internal_malloc(sizeof(struc_177)); - if (v14 == NULL) { + MenuBar* menuBar = window->menuBar = (MenuBar*)internal_malloc(sizeof(MenuBar)); + if (menuBar == NULL) { return -1; } - v14->win = win; - v14->rect.left = x; - v14->rect.top = y; - v14->rect.right = right - 1; - v14->rect.bottom = bottom - 1; - v14->entriesCount = 0; - v14->field_234 = a6; - v14->field_238 = a7; + menuBar->win = win; + menuBar->rect.left = x; + menuBar->rect.top = y; + menuBar->rect.right = right - 1; + menuBar->rect.bottom = bottom - 1; + menuBar->pulldownsLength = 0; + menuBar->borderColor = borderColor; + menuBar->backgroundColor = backgroundColor; - windowFill(win, x, y, width, height, a7); - windowDrawRect(win, x, y, right - 1, bottom - 1, a6); + windowFill(win, x, y, width, height, backgroundColor); + windowDrawRect(win, x, y, right - 1, bottom - 1, borderColor); return 0; } // 0x4DC768 -int _win_register_menu_pulldown(int win, int x, char* str, int a4) +int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int a7, int a8) { Window* window = windowGetWindow(win); @@ -163,23 +887,25 @@ int _win_register_menu_pulldown(int win, int x, char* str, int a4) return -1; } - struc_177* field_3C = window->field_3C; - if (field_3C == NULL) { + MenuBar* menuBar = window->menuBar; + if (menuBar == NULL) { return -1; } - if (window->field_3C->entriesCount == 15) { + if (window->menuBar->pulldownsLength == 15) { return -1; } + int titleX = menuBar->rect.left + x; + int titleY = (menuBar->rect.top + menuBar->rect.bottom - fontGetLineHeight()) / 2; int btn = buttonCreate(win, - field_3C->rect.left + x, - (field_3C->rect.top + field_3C->rect.bottom - fontGetLineHeight()) / 2, - fontGetStringWidth(str), + titleX, + titleY, + fontGetStringWidth(title), fontGetLineHeight(), -1, -1, - a4, + keyCode, -1, NULL, NULL, @@ -189,11 +915,69 @@ int _win_register_menu_pulldown(int win, int x, char* str, int a4) return -1; } - // TODO: Incomplete. + windowDrawText(win, title, 0, titleX, titleY, window->menuBar->borderColor | 0x2000000); + + MenuPulldown* pulldown = &(window->menuBar->pulldowns[window->menuBar->pulldownsLength]); + pulldown->rect.left = titleX; + pulldown->rect.top = titleY; + pulldown->rect.right = fontGetStringWidth(title) + titleX - 1; + pulldown->rect.bottom = fontGetLineHeight() + titleY - 1; + pulldown->keyCode = keyCode; + pulldown->itemsLength = itemsLength; + pulldown->items = items; + pulldown->field_1C = a7; + pulldown->field_20 = a8; + + window->menuBar->pulldownsLength++; return 0; } +// 0x4DC8D0 +void _win_delete_menu_bar(int win) +{ + Window* window = windowGetWindow(win); + + if (!gWindowSystemInitialized) { + return; + } + + if (window == NULL) { + return; + } + + if (window->menuBar == NULL) { + return; + } + + windowFill(win, + window->menuBar->rect.left, + window->menuBar->rect.top, + rectGetWidth(&(window->menuBar->rect)), + rectGetHeight(&(window->menuBar->rect)), + window->field_20); + + internal_free(window->menuBar); + window->menuBar = NULL; +} + +// 0x4DC9F0 +int _find_first_letter(int ch, char** stringList, int stringListLength) +{ + if (ch >= 'A' && ch <= 'Z') { + ch += ' '; + } + + for (int index = 0; index < stringListLength; index++) { + char* string = stringList[index]; + if (string[0] == ch || string[0] == ch - ' ') { + return index; + } + } + + return -1; +} + // 0x4DCA30 int _win_width_needed(char** fileNameList, int fileNameListLength) { @@ -209,14 +993,163 @@ int _win_width_needed(char** fileNameList, int fileNameListLength) return maxWidth; } -// 0x4DC930 -int _GNW_process_menu(struc_177* ptr, int i) +// 0x4DCA5C +int _win_input_str(int win, char* dest, int maxLength, int x, int y, int textColor, int backgroundColor) { - // TODO: Incomplete + Window* window = windowGetWindow(win); + unsigned char* buffer = window->buffer + window->width * y + x; + + int cursorPos = strlen(dest); + dest[cursorPos] = '_'; + dest[cursorPos + 1] = '\0'; + + int lineHeight = fontGetLineHeight(); + int stringWidth = fontGetStringWidth(dest); + bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor); + fontDrawText(buffer, dest, stringWidth, window->width, textColor); + + Rect dirtyRect; + dirtyRect.left = window->rect.left + x; + dirtyRect.top = window->rect.top + y; + dirtyRect.right = dirtyRect.left + stringWidth; + dirtyRect.bottom = dirtyRect.top + lineHeight; + _GNW_win_refresh(window, &dirtyRect, NULL); + + // NOTE: This loop is slightly different compared to other input handling + // loops. Cursor position is managed inside an incrementing loop. Cursor is + // decremented in the loop body when key is not handled. + bool isFirstKey = true; + for (; cursorPos <= maxLength; cursorPos++) { + int keyCode = _get_input(); + if (keyCode != -1) { + if (keyCode == KEY_ESCAPE) { + dest[cursorPos] = '\0'; + return -1; + } + + if (keyCode == KEY_BACKSPACE) { + if (cursorPos > 0) { + stringWidth = fontGetStringWidth(dest); + + if (isFirstKey) { + bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor); + + dirtyRect.left = window->rect.left + x; + dirtyRect.top = window->rect.top + y; + dirtyRect.right = dirtyRect.left + stringWidth; + dirtyRect.bottom = dirtyRect.top + lineHeight; + _GNW_win_refresh(window, &dirtyRect, NULL); + + dest[0] = '_'; + dest[1] = '\0'; + cursorPos = 1; + } else { + dest[cursorPos] = ' '; + dest[cursorPos - 1] = '_'; + } + + bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor); + fontDrawText(buffer, dest, stringWidth, window->width, textColor); + + dirtyRect.left = window->rect.left + x; + dirtyRect.top = window->rect.top + y; + dirtyRect.right = dirtyRect.left + stringWidth; + dirtyRect.bottom = dirtyRect.top + lineHeight; + _GNW_win_refresh(window, &dirtyRect, NULL); + + dest[cursorPos] = '\0'; + cursorPos -= 2; + + isFirstKey = false; + } else { + cursorPos--; + } + } else if (keyCode == KEY_RETURN) { + break; + } else { + if (cursorPos == maxLength) { + cursorPos = maxLength - 1; + } else { + if (keyCode > 0 && keyCode < 256) { + dest[cursorPos] = keyCode; + dest[cursorPos + 1] = '_'; + dest[cursorPos + 2] = '\0'; + + int stringWidth = fontGetStringWidth(dest); + bufferFill(buffer, stringWidth, lineHeight, window->width, backgroundColor); + fontDrawText(buffer, dest, stringWidth, window->width, textColor); + + dirtyRect.left = window->rect.left + x; + dirtyRect.top = window->rect.top + y; + dirtyRect.right = dirtyRect.left + stringWidth; + dirtyRect.bottom = dirtyRect.top + lineHeight; + _GNW_win_refresh(window, &dirtyRect, NULL); + + isFirstKey = false; + } else { + cursorPos--; + } + } + } + } else { + cursorPos--; + } + } + + dest[cursorPos] = '\0'; return 0; } +// 0x4DBD04 +int sub_4DBD04(int win, Rect* rect, char** items, int itemsLength, int a5, int a6, MenuBar* menuBar, int pulldownIndex) +{ + // TODO: Incomplete. + return -1; +} + +// 0x4DC930 +int _GNW_process_menu(MenuBar* menuBar, int pulldownIndex) +{ + if (_curr_menu != NULL) { + return -1; + } + + _curr_menu = menuBar; + + int keyCode; + Rect rect; + do { + MenuPulldown* pulldown = &(menuBar->pulldowns[pulldownIndex]); + int win = _create_pull_down(pulldown->items, + pulldown->itemsLength, + pulldown->rect.left, + menuBar->rect.bottom + 1, + pulldown->field_1C, + pulldown->field_20, + &rect); + if (win == -1) { + _curr_menu = NULL; + return -1; + } + + keyCode = sub_4DBD04(win, &rect, pulldown->items, pulldown->itemsLength, pulldown->field_1C, pulldown->field_20, menuBar, pulldownIndex); + if (keyCode < -1) { + pulldownIndex = -2 - keyCode; + } + } while (keyCode < -1); + + if (keyCode != -1) { + inputEventQueueReset(); + enqueueInputEvent(keyCode); + keyCode = menuBar->pulldowns[pulldownIndex].keyCode; + } + + _curr_menu = NULL; + + return keyCode; +} + // Calculates max length of string needed to represent a1 or a2. // // 0x4DD03C diff --git a/src/window_manager_private.h b/src/window_manager_private.h index 8231b6e..55353c1 100644 --- a/src/window_manager_private.h +++ b/src/window_manager_private.h @@ -1,13 +1,37 @@ #ifndef WINDOW_MANAGER_PRIVATE_H #define WINDOW_MANAGER_PRIVATE_H -typedef struct struc_177 struc_177; +#include "geometry.h" + +typedef struct MenuBar MenuBar; + +typedef void(ListSelectionHandler)(char** items, int index); extern char gProgramWindowTitle[256]; -int _win_debug(char* a1); -int _GNW_process_menu(struc_177* ptr, int i); +int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int a7); +int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int a7, int a8); +int _win_get_str(char* dest, int length, const char* title, int x, int y); +int _win_msg(const char* string, int x, int y, int flags); +int _win_pull_down(char** items, int itemsLength, int x, int y, int a5); +int _create_pull_down(char** stringList, int stringListLength, int x, int y, int a5, int a6, Rect* rect); +int _win_debug(char* string); +void _win_debug_delete(int btn, int keyCode); +int _win_register_menu_bar(int win, int x, int y, int width, int height, int borderColor, int backgroundColor); +int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int a7, int a8); +void _win_delete_menu_bar(int win); +int _find_first_letter(int ch, char** stringList, int stringListLength); +int _win_width_needed(char** fileNameList, int fileNameListLength); +int _win_input_str(int win, char* dest, int maxLength, int x, int y, int textColor, int backgroundColor); +int sub_4DBD04(int win, Rect* rect, char** items, int itemsLength, int a5, int a6, MenuBar* menuBar, int pulldownIndex); +int _GNW_process_menu(MenuBar* menuBar, int pulldownIndex); +int _calc_max_field_chars_wcursor(int a1, int a2); void _GNW_intr_init(); void _GNW_intr_exit(); +void _tm_watch_msgs(); +void _tm_kill_msg(); +void _tm_kill_out_of_order(int a1); +void _tm_click_response(int btn); +int _tm_index_active(int a1); #endif /* WINDOW_MANAGER_PRIVATE_H */ diff --git a/src/world_map.cc b/src/world_map.cc index b3bc2dd..b7b79c7 100644 --- a/src/world_map.cc +++ b/src/world_map.cc @@ -102,7 +102,6 @@ typedef enum EncounterFormationType { ENCOUNTER_FORMATION_TYPE_COUNT, } EncounterFormationType; - typedef enum EncounterFrequencyType { ENCOUNTER_FREQUENCY_TYPE_NONE, ENCOUNTER_FREQUENCY_TYPE_RARE, @@ -1549,7 +1548,7 @@ int worldmapConfigInit() // NOTE: Uninline. worldmapTileInfoInit(tile); - tile->fid = buildFid(6, artIndex, 0, 0, 0); + tile->fid = buildFid(OBJ_TYPE_INTERFACE, artIndex, 0, 0, 0); int encounterDifficulty; if (configGetInt(&config, section, "encounter_difficulty", &encounterDifficulty)) { @@ -1876,7 +1875,7 @@ int _wmReadEncBaseType(char* name, int* valuePtr) for (int index = 0; index < entry->field_34; index++) { ENC_BASE_TYPE_38* ptr = &(entry->field_38[index]); - if ((ptr->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(ptr->pid) == OBJ_TYPE_CRITTER) { ptr->team = team; } } @@ -2653,14 +2652,14 @@ int cityInit() city->field_28 = area_idx; if (num != -1) { - num = buildFid(6, num, 0, 0, 0); + num = buildFid(OBJ_TYPE_INTERFACE, num, 0, 0, 0); } city->mapFid = num; if (configGetInt(&cfg, section, "townmap_label_art_idx", &num)) { if (num != -1) { - num = buildFid(6, num, 0, 0, 0); + num = buildFid(OBJ_TYPE_INTERFACE, num, 0, 0, 0); } city->labelFid = num; @@ -4021,13 +4020,13 @@ int worldmapSetupCritters(int type_idx, Object** critterPtr, int critterCount) } if (*critterPtr == NULL) { - if ((v5->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(v5->pid) == OBJ_TYPE_CRITTER) { *critterPtr = object; } } if (v5->team != -1) { - if ((object->pid >> 24) == OBJ_TYPE_CRITTER) { + if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) { object->data.critter.combat.team = v5->team; } } @@ -4644,7 +4643,7 @@ int worldmapWindowInit() int fid; Art* frm; CacheEntry* frmHandle; - + _wmLastRndTime = _get_time(); _fontnum = fontGetCurrent(); fontSetCurrent(0); @@ -4666,7 +4665,7 @@ int worldmapWindowInit() return -1; } - fid = buildFid(6, 136, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 136, 0, 0, 0); frm = artLock(fid, &gWorldmapBoxFrmHandle); if (frm == NULL) { return -1; @@ -4678,7 +4677,7 @@ int worldmapWindowInit() artUnlock(gWorldmapBoxFrmHandle); gWorldmapBoxFrmHandle = INVALID_CACHE_ENTRY; - fid = buildFid(6, 136, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 136, 0, 0, 0); gWorldmapBoxFrmData = artLockFrameData(fid, 0, 0, &gWorldmapBoxFrmHandle); if (gWorldmapBoxFrmData == NULL) { return -1; @@ -4694,7 +4693,7 @@ int worldmapWindowInit() for (int citySize = 0; citySize < CITY_SIZE_COUNT; citySize++) { CitySizeDescription* citySizeDescription = &(gCitySizeDescriptions[citySize]); - fid = buildFid(6, 336 + citySize, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 336 + citySize, 0, 0, 0); citySizeDescription->fid = fid; frm = artLock(fid, &(citySizeDescription->handle)); @@ -4715,7 +4714,7 @@ int worldmapWindowInit() } } - fid = buildFid(6, 168, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 168, 0, 0, 0); frm = artLock(fid, &gWorldmapHotspotUpFrmHandle); if (frm == NULL) { return -1; @@ -4728,18 +4727,18 @@ int worldmapWindowInit() gWorldmapHotspotUpFrmHandle = INVALID_CACHE_ENTRY; // hotspot1.frm - town map selector shape #1 - fid = buildFid(6, 168, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 168, 0, 0, 0); gWorldmapHotspotUpFrmData = artLockFrameData(fid, 0, 0, &gWorldmapHotspotUpFrmHandle); // hotspot2.frm - town map selector shape #2 - fid = buildFid(6, 223, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 223, 0, 0, 0); gWorldmapHotspotDownFrmData = artLockFrameData(fid, 0, 0, &gWorldmapHotspotDownFrmHandle); if (gWorldmapHotspotDownFrmData == NULL) { return -1; } // wmaptarg.frm - world map move target maker #1 - fid = buildFid(6, 139, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 139, 0, 0, 0); frm = artLock(fid, &gWorldmapDestinationMarkerFrmHandle); if (frm == NULL) { return -1; @@ -4752,7 +4751,7 @@ int worldmapWindowInit() gWorldmapDestinationMarkerFrmHandle = INVALID_CACHE_ENTRY; // wmaploc.frm - world map location marker - fid = buildFid(6, 138, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 138, 0, 0, 0); frm = artLock(fid, &gWorldmapLocationMarkerFrmHandle); if (frm == NULL) { return -1; @@ -4765,21 +4764,21 @@ int worldmapWindowInit() gWorldmapLocationMarkerFrmHandle = INVALID_CACHE_ENTRY; // wmaptarg.frm - world map move target maker #1 - fid = buildFid(6, 139, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 139, 0, 0, 0); gWorldmapDestinationMarkerFrmData = artLockFrameData(fid, 0, 0, &gWorldmapDestinationMarkerFrmHandle); if (gWorldmapDestinationMarkerFrmData == NULL) { return -1; } // wmaploc.frm - world map location marker - fid = buildFid(6, 138, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 138, 0, 0, 0); gWorldmapLocationMarkerFrmData = artLockFrameData(fid, 0, 0, &gWorldmapLocationMarkerFrmHandle); if (gWorldmapLocationMarkerFrmData == NULL) { return -1; } for (int index = 0; index < WORLD_MAP_ENCOUNTER_FRM_COUNT; index++) { - fid = buildFid(6, gWorldmapEncounterFrmIds[index], 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, gWorldmapEncounterFrmIds[index], 0, 0, 0); frm = artLock(fid, &(gWorldmapEncounterFrmHandles[index])); if (frm == NULL) { return -1; @@ -4799,7 +4798,7 @@ int worldmapWindowInit() } // wmtabs.frm - worldmap town tabs underlay - fid = buildFid(6, 364, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 364, 0, 0, 0); frm = artLock(fid, &frmHandle); if (frm == NULL) { return -1; @@ -4816,14 +4815,14 @@ int worldmapWindowInit() } // wmtbedge.frm - worldmap town tabs edging overlay - fid = buildFid(6, 367, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 367, 0, 0, 0); gWorldmapTownTabsEdgeFrmData = artLockFrameData(fid, 0, 0, &gWorldmapTownTabsEdgeFrmHandle); if (gWorldmapTownTabsEdgeFrmData == NULL) { return -1; } // wmdial.frm - worldmap night/day dial - fid = buildFid(6, 365, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 365, 0, 0, 0); gWorldmapDialFrm = artLock(fid, &gWorldmapDialFrmHandle); if (gWorldmapDialFrm == NULL) { return -1; @@ -4833,7 +4832,7 @@ int worldmapWindowInit() gWorldmapDialFrmHeight = artGetHeight(gWorldmapDialFrm, 0, 0); // wmscreen - worldmap overlay screen - fid = buildFid(6, 363, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 363, 0, 0, 0); frm = artLock(fid, &frmHandle); if (frm == NULL) { return -1; @@ -4850,7 +4849,7 @@ int worldmapWindowInit() } // wmglobe.frm - worldmap globe stamp overlay - fid = buildFid(6, 366, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 366, 0, 0, 0); frm = artLock(fid, &frmHandle); if (frm == NULL) { return -1; @@ -4867,7 +4866,7 @@ int worldmapWindowInit() } // lilredup.frm - little red button up - fid = buildFid(6, 8, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0); frm = artLock(fid, &frmHandle); if (frm == NULL) { return -1; @@ -4881,18 +4880,18 @@ int worldmapWindowInit() gWorldmapLittleRedButtonUpFrmData = artLockFrameData(fid, 0, 0, &gWorldmapLittleRedButtonUpFrmHandle); // lilreddn.frm - little red button down - fid = buildFid(6, 9, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0); gWorldmapLittleRedButtonDownFrmData = artLockFrameData(fid, 0, 0, &gWorldmapLittleRedButtonDownFrmHandle); // months.frm - month strings for pip boy - fid = buildFid(6, 129, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 129, 0, 0, 0); gWorldmapMonthsFrm = artLock(fid, &gWorldmapMonthsFrmHandle); if (gWorldmapMonthsFrm == NULL) { return -1; } // numbers.frm - numbers for the hit points and fatigue counters - fid = buildFid(6, 82, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 82, 0, 0, 0); gWorldmapNumbersFrm = artLock(fid, &gWorldmapNumbersFrmHandle); if (gWorldmapNumbersFrm == NULL) { return -1; @@ -4902,37 +4901,37 @@ int worldmapWindowInit() buttonCreate(gWorldmapWindow, WM_TOWN_WORLD_SWITCH_X, WM_TOWN_WORLD_SWITCH_Y, - littleRedButtonUpWidth, - littleRedButtonUpHeight, - -1, - -1, + littleRedButtonUpWidth, + littleRedButtonUpHeight, + -1, + -1, -1, KEY_UPPERCASE_T, gWorldmapLittleRedButtonUpFrmData, gWorldmapLittleRedButtonDownFrmData, - NULL, + NULL, BUTTON_FLAG_TRANSPARENT); for (int index = 0; index < 7; index++) { _wmTownMapSubButtonIds[index] = buttonCreate(gWorldmapWindow, - 508, + 508, 138 + 27 * index, - littleRedButtonUpWidth, - littleRedButtonUpHeight, - -1, + littleRedButtonUpWidth, + littleRedButtonUpHeight, -1, - -1, - KEY_CTRL_F1 + index, - gWorldmapLittleRedButtonUpFrmData, - gWorldmapLittleRedButtonDownFrmData, - NULL, + -1, + -1, + KEY_CTRL_F1 + index, + gWorldmapLittleRedButtonUpFrmData, + gWorldmapLittleRedButtonDownFrmData, + NULL, BUTTON_FLAG_TRANSPARENT); } for (int index = 0; index < WORLDMAP_ARROW_FRM_COUNT; index++) { // 200 - uparwon.frm - character editor // 199 - uparwoff.frm - character editor - fid = buildFid(6, 200 - index, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 200 - index, 0, 0, 0); frm = artLock(fid, &(gWorldmapTownListScrollUpFrmHandle[index])); if (frm == NULL) { return -1; @@ -4946,7 +4945,7 @@ int worldmapWindowInit() for (int index = 0; index < WORLDMAP_ARROW_FRM_COUNT; index++) { // 182 - dnarwon.frm - character editor // 181 - dnarwoff.frm - character editor - fid = buildFid(6, 182 - index, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 182 - index, 0, 0, 0); frm = artLock(fid, &(gWorldmapTownListScrollDownFrmHandle[index])); if (frm == NULL) { return -1; @@ -4961,35 +4960,35 @@ int worldmapWindowInit() buttonCreate(gWorldmapWindow, WM_TOWN_LIST_SCROLL_UP_X, WM_TOWN_LIST_SCROLL_UP_Y, - gWorldmapTownListScrollUpFrmWidth, - gWorldmapTownListScrollUpFrmHeight, - -1, - -1, + gWorldmapTownListScrollUpFrmWidth, + gWorldmapTownListScrollUpFrmHeight, + -1, + -1, -1, KEY_CTRL_ARROW_UP, - gWorldmapTownListScrollUpFrmData[WORLDMAP_ARROW_FRM_NORMAL], + gWorldmapTownListScrollUpFrmData[WORLDMAP_ARROW_FRM_NORMAL], gWorldmapTownListScrollUpFrmData[WORLDMAP_ARROW_FRM_PRESSED], NULL, BUTTON_FLAG_TRANSPARENT); // Scroll down button. - buttonCreate(gWorldmapWindow, - WM_TOWN_LIST_SCROLL_DOWN_X, - WM_TOWN_LIST_SCROLL_DOWN_Y, - gWorldmapTownListScrollDownFrmWidth, + buttonCreate(gWorldmapWindow, + WM_TOWN_LIST_SCROLL_DOWN_X, + WM_TOWN_LIST_SCROLL_DOWN_Y, + gWorldmapTownListScrollDownFrmWidth, gWorldmapTownListScrollDownFrmHeight, -1, -1, - -1, + -1, KEY_CTRL_ARROW_DOWN, - gWorldmapTownListScrollDownFrmData[WORLDMAP_ARROW_FRM_NORMAL], + gWorldmapTownListScrollDownFrmData[WORLDMAP_ARROW_FRM_NORMAL], gWorldmapTownListScrollDownFrmData[WORLDMAP_ARROW_FRM_PRESSED], - NULL, + NULL, BUTTON_FLAG_TRANSPARENT); if (gWorldmapIsInCar) { // wmcarmve.frm - worldmap car movie - fid = buildFid(6, 433, 0, 0, 0); + fid = buildFid(OBJ_TYPE_INTERFACE, 433, 0, 0, 0); gWorldmapCarFrm = artLock(fid, &gWorldmapCarFrmHandle); if (gWorldmapCarFrm == NULL) { return -1;