Review light.cc

This commit is contained in:
Alexander Batalov 2023-01-03 23:56:52 +03:00
parent 9ee4cb4a26
commit 66955f893a
9 changed files with 96 additions and 91 deletions

View File

@ -1745,7 +1745,7 @@ static bool aiHaveAmmo(Object* critter, Object* weapon, Object** ammoPtr)
} }
if (weapon->pid == PROTO_ID_SOLAR_SCORCHER) { if (weapon->pid == PROTO_ID_SOLAR_SCORCHER) {
return lightGetLightLevel() > 62259; return lightGetAmbientIntensity() > LIGHT_INTENSITY_MAX * 0.95;
} }
int inventoryItemIndex = -1; int inventoryItemIndex = -1;
@ -2879,7 +2879,7 @@ static int _ai_try_attack(Object* a1, Object* a2)
// 0x42AE90 // 0x42AE90
int _cAIPrepWeaponItem(Object* critter, Object* item) int _cAIPrepWeaponItem(Object* critter, Object* item)
{ {
if (item != NULL && critterGetStat(critter, STAT_INTELLIGENCE) >= 3 && item->pid == PROTO_ID_FLARE && lightGetLightLevel() < 55705) { if (item != NULL && critterGetStat(critter, STAT_INTELLIGENCE) >= 3 && item->pid == PROTO_ID_FLARE && lightGetAmbientIntensity() < LIGHT_INTENSITY_MAX * 0.85) {
_protinst_use_item(critter, item); _protinst_use_item(critter, item);
} }
return 0; return 0;

View File

@ -343,21 +343,6 @@ static void opGetPcStat(Program* program);
// 0x504B0C // 0x504B0C
static char _aCritter[] = "<Critter>"; static char _aCritter[] = "<Critter>";
// Maps light level to light intensity.
//
// Middle value is mapped one-to-one which corresponds to 50% light level
// (cavern lighting). Light levels above (51-100%) and below (0-49) is
// calculated as percentage from two adjacent light values.
//
// See [opSetLightLevel] for math.
//
// 0x453F90
static const int dword_453F90[3] = {
0x4000,
0xA000,
0x10000,
};
// 0x453FC0 // 0x453FC0
static Rect stru_453FC0 = { 0, 0, 640, 480 }; static Rect stru_453FC0 = { 0, 0, 640, 480 };
@ -2234,23 +2219,36 @@ static void opCritterHeal(Program* program)
// 0x457934 // 0x457934
static void opSetLightLevel(Program* program) static void opSetLightLevel(Program* program)
{ {
// Maps light level to light intensity.
//
// Middle value is mapped one-to-one which corresponds to 50% light level
// (cavern lighting). Light levels above (51-100%) and below (0-49%) is
// calculated as percentage from two adjacent light values.
//
// 0x453F90
static const int intensities[3] = {
LIGHT_INTENSITY_MIN,
(LIGHT_INTENSITY_MIN + LIGHT_INTENSITY_MAX) / 2,
LIGHT_INTENSITY_MAX,
};
int data = programStackPopInteger(program); int data = programStackPopInteger(program);
int lightLevel = data; int lightLevel = data;
if (data == 50) { if (data == 50) {
lightSetLightLevel(dword_453F90[1], true); lightSetAmbientIntensity(intensities[1], true);
return; return;
} }
int lightIntensity; int lightIntensity;
if (data > 50) { if (data > 50) {
lightIntensity = dword_453F90[1] + data * (dword_453F90[2] - dword_453F90[1]) / 100; lightIntensity = intensities[1] + data * (intensities[2] - intensities[1]) / 100;
} else { } else {
lightIntensity = dword_453F90[0] + data * (dword_453F90[1] - dword_453F90[0]) / 100; lightIntensity = intensities[0] + data * (intensities[1] - intensities[0]) / 100;
} }
lightSetLightLevel(lightIntensity, true); lightSetAmbientIntensity(lightIntensity, true);
} }
// game_time // game_time

View File

@ -3315,7 +3315,7 @@ int _invenWieldFunc(Object* critter, Object* item, int a3, bool a4)
int lightIntensity; int lightIntensity;
int lightDistance; int lightDistance;
if (critter == gDude) { if (critter == gDude) {
lightIntensity = LIGHT_LEVEL_MAX; lightIntensity = LIGHT_INTENSITY_MAX;
lightDistance = 4; lightDistance = 4;
} else { } else {
Proto* proto; Proto* proto;

View File

@ -1494,7 +1494,7 @@ bool weaponCanBeReloadedWith(Object* weapon, Object* ammo)
{ {
if (weapon->pid == PROTO_ID_SOLAR_SCORCHER) { if (weapon->pid == PROTO_ID_SOLAR_SCORCHER) {
// Check light level to recharge solar scorcher. // Check light level to recharge solar scorcher.
if (lightGetLightLevel() > 62259) { if (lightGetAmbientIntensity() > LIGHT_INTENSITY_MAX * 0.95) {
return true; return true;
} }

View File

@ -13,50 +13,55 @@ namespace fallout {
#define LIGHT_LEVEL_NIGHT_VISION_BONUS (65536 / 5) #define LIGHT_LEVEL_NIGHT_VISION_BONUS (65536 / 5)
// 0x51923C // 0x51923C
static int gLightLevel = LIGHT_LEVEL_MAX; static int gAmbientIntensity = LIGHT_INTENSITY_MAX;
// light intensity per elevation per tile // light intensity per elevation per tile
// 0x59E994 // 0x59E994
static int gLightIntensity[ELEVATION_COUNT][HEX_GRID_SIZE]; static int gTileIntensity[ELEVATION_COUNT][HEX_GRID_SIZE];
// 0x47A8F0 // 0x47A8F0
int lightInit() int lightInit()
{ {
lightResetIntensity(); lightResetTileIntensity();
return 0; return 0;
} }
// 0x47A8F8 // 0x47A8F0
int lightGetLightLevel() void lightReset()
{ {
return gLightLevel; lightResetTileIntensity();
}
// 0x47A8F0
void lightExit()
{
lightResetTileIntensity();
}
// 0x47A8F8
int lightGetAmbientIntensity()
{
return gAmbientIntensity;
} }
// 0x47A908 // 0x47A908
void lightSetLightLevel(int lightLevel, bool shouldUpdateScreen) void lightSetAmbientIntensity(int intensity, bool shouldUpdateScreen)
{ {
int normalizedLightLevel = lightLevel + perkGetRank(gDude, PERK_NIGHT_VISION) * LIGHT_LEVEL_NIGHT_VISION_BONUS; int adjustedIntensity = intensity + perkGetRank(gDude, PERK_NIGHT_VISION) * LIGHT_LEVEL_NIGHT_VISION_BONUS;
int normalizedIntensity = std::clamp(adjustedIntensity, LIGHT_INTENSITY_MIN, LIGHT_INTENSITY_MAX);
if (normalizedLightLevel < LIGHT_LEVEL_MIN) { int oldAmbientIntensity = gAmbientIntensity;
normalizedLightLevel = LIGHT_LEVEL_MIN; gAmbientIntensity = normalizedIntensity;
}
if (normalizedLightLevel > LIGHT_LEVEL_MAX) {
normalizedLightLevel = LIGHT_LEVEL_MAX;
}
int oldLightLevel = gLightLevel;
gLightLevel = normalizedLightLevel;
if (shouldUpdateScreen) { if (shouldUpdateScreen) {
if (oldLightLevel != normalizedLightLevel) { if (oldAmbientIntensity != normalizedIntensity) {
tileWindowRefresh(); tileWindowRefresh();
} }
} }
} }
// 0x47A980 // 0x47A980
int _light_get_tile(int elevation, int tile) int lightGetTileIntensity(int elevation, int tile)
{ {
if (!elevationIsValid(elevation)) { if (!elevationIsValid(elevation)) {
return 0; return 0;
@ -66,11 +71,11 @@ int _light_get_tile(int elevation, int tile)
return 0; return 0;
} }
return std::min(gLightIntensity[elevation][tile], LIGHT_LEVEL_MAX); return std::min(gTileIntensity[elevation][tile], LIGHT_INTENSITY_MAX);
} }
// 0x47A9C4 // 0x47A9C4
int lightGetIntensity(int elevation, int tile) int lightGetTrueTileIntensity(int elevation, int tile)
{ {
if (!elevationIsValid(elevation)) { if (!elevationIsValid(elevation)) {
return 0; return 0;
@ -80,11 +85,11 @@ int lightGetIntensity(int elevation, int tile)
return 0; return 0;
} }
return gLightIntensity[elevation][tile]; return gTileIntensity[elevation][tile];
} }
// 0x47A9EC // 0x47A9EC
void lightSetIntensity(int elevation, int tile, int lightIntensity) void lightSetTileIntensity(int elevation, int tile, int intensity)
{ {
if (!elevationIsValid(elevation)) { if (!elevationIsValid(elevation)) {
return; return;
@ -94,11 +99,11 @@ void lightSetIntensity(int elevation, int tile, int lightIntensity)
return; return;
} }
gLightIntensity[elevation][tile] = lightIntensity; gTileIntensity[elevation][tile] = intensity;
} }
// 0x47AA10 // 0x47AA10
void lightIncreaseIntensity(int elevation, int tile, int lightIntensity) void lightIncreaseTileIntensity(int elevation, int tile, int intensity)
{ {
if (!elevationIsValid(elevation)) { if (!elevationIsValid(elevation)) {
return; return;
@ -108,11 +113,11 @@ void lightIncreaseIntensity(int elevation, int tile, int lightIntensity)
return; return;
} }
gLightIntensity[elevation][tile] += lightIntensity; gTileIntensity[elevation][tile] += intensity;
} }
// 0x47AA48 // 0x47AA48
void lightDecreaseIntensity(int elevation, int tile, int lightIntensity) void lightDecreaseTileIntensity(int elevation, int tile, int intensity)
{ {
if (!elevationIsValid(elevation)) { if (!elevationIsValid(elevation)) {
return; return;
@ -122,15 +127,15 @@ void lightDecreaseIntensity(int elevation, int tile, int lightIntensity)
return; return;
} }
gLightIntensity[elevation][tile] -= lightIntensity; gTileIntensity[elevation][tile] -= intensity;
} }
// 0x47AA84 // 0x47AA84
void lightResetIntensity() void lightResetTileIntensity()
{ {
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) { for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
for (int tile = 0; tile < HEX_GRID_SIZE; tile++) { for (int tile = 0; tile < HEX_GRID_SIZE; tile++) {
gLightIntensity[elevation][tile] = 655; gTileIntensity[elevation][tile] = 655;
} }
} }
} }

View File

@ -3,20 +3,22 @@
namespace fallout { namespace fallout {
#define LIGHT_LEVEL_MIN (65536 / 4) #define LIGHT_INTENSITY_MIN (65536 / 4)
#define LIGHT_LEVEL_MAX 65536 #define LIGHT_INTENSITY_MAX 65536
typedef void AdjustLightIntensityProc(int elevation, int tile, int intensity); typedef void AdjustLightIntensityProc(int elevation, int tile, int intensity);
int lightInit(); int lightInit();
int lightGetLightLevel(); void lightReset();
void lightSetLightLevel(int lightLevel, bool shouldUpdateScreen); void lightExit();
int _light_get_tile(int elevation, int tile); int lightGetAmbientIntensity();
int lightGetIntensity(int elevation, int tile); void lightSetAmbientIntensity(int intensity, bool shouldUpdateScreen);
void lightSetIntensity(int elevation, int tile, int intensity); int lightGetTileIntensity(int elevation, int tile);
void lightIncreaseIntensity(int elevation, int tile, int intensity); int lightGetTrueTileIntensity(int elevation, int tile);
void lightDecreaseIntensity(int elevation, int tile, int intensity); void lightSetTileIntensity(int elevation, int tile, int intensity);
void lightResetIntensity(); void lightIncreaseTileIntensity(int elevation, int tile, int intensity);
void lightDecreaseTileIntensity(int elevation, int tile, int intensity);
void lightResetTileIntensity();
} // namespace fallout } // namespace fallout

View File

@ -924,7 +924,7 @@ static int mapLoad(File* stream)
goto err; goto err;
} }
lightSetLightLevel(LIGHT_LEVEL_MAX, false); lightSetAmbientIntensity(LIGHT_INTENSITY_MAX, false);
objectSetLocation(gDude, gCenterTile, gElevation, NULL); objectSetLocation(gDude, gCenterTile, gElevation, NULL);
objectSetRotation(gDude, gEnteringRotation, NULL); objectSetRotation(gDude, gEnteringRotation, NULL);
gMapHeader.field_34 = wmMapMatchNameToIdx(gMapHeader.name); gMapHeader.field_34 = wmMapMatchNameToIdx(gMapHeader.name);

View File

@ -379,7 +379,7 @@ void objectsReset()
textObjectsReset(); textObjectsReset();
_obj_remove_all(); _obj_remove_all();
memset(_obj_seen, 0, 5001); memset(_obj_seen, 0, 5001);
lightResetIntensity(); lightReset();
} }
} }
@ -396,7 +396,7 @@ void objectsExit()
// NOTE: Uninline. // NOTE: Uninline.
_obj_blend_table_exit(); _obj_blend_table_exit();
lightResetIntensity(); lightExit();
// NOTE: Uninline. // NOTE: Uninline.
_obj_render_table_exit(); _obj_render_table_exit();
@ -763,7 +763,7 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
return; return;
} }
int ambientLight = lightGetLightLevel(); int ambientIntensity = lightGetAmbientIntensity();
int minX = updatedRect.left - 320; int minX = updatedRect.left - 320;
int minY = updatedRect.top - 240; int minY = updatedRect.top - 240;
int maxX = updatedRect.right + 320; int maxX = updatedRect.right + 320;
@ -804,14 +804,14 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
for (int i = 0; i < gObjectsUpdateAreaHexSize; i++) { for (int i = 0; i < gObjectsUpdateAreaHexSize; i++) {
int offsetIndex = *orders++; int offsetIndex = *orders++;
if (updateAreaHexHeight > _offsetDivTable[offsetIndex] && updateAreaHexWidth > _offsetModTable[offsetIndex]) { if (updateAreaHexHeight > _offsetDivTable[offsetIndex] && updateAreaHexWidth > _offsetModTable[offsetIndex]) {
int light; int lightIntensity;
ObjectListNode* objectListNode = hexGridTileIsValid(topLeftTile + offsets[offsetIndex]) ObjectListNode* objectListNode = hexGridTileIsValid(topLeftTile + offsets[offsetIndex])
? gObjectListHeadByTile[topLeftTile + offsets[offsetIndex]] ? gObjectListHeadByTile[topLeftTile + offsets[offsetIndex]]
: NULL; : NULL;
if (objectListNode != NULL) { if (objectListNode != NULL) {
// NOTE: Calls `_light_get_tile` twice. // NOTE: Calls `lightGetTileIntensity` twice.
light = std::max(ambientLight, _light_get_tile(elevation, objectListNode->obj->tile)); lightIntensity = std::max(ambientIntensity, lightGetTileIntensity(elevation, objectListNode->obj->tile));
} }
while (objectListNode != NULL) { while (objectListNode != NULL) {
@ -825,7 +825,7 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
} }
if ((objectListNode->obj->flags & OBJECT_HIDDEN) == 0) { if ((objectListNode->obj->flags & OBJECT_HIDDEN) == 0) {
_obj_render_object(objectListNode->obj, &updatedRect, light); _obj_render_object(objectListNode->obj, &updatedRect, lightIntensity);
if ((objectListNode->obj->outline & OUTLINE_TYPE_MASK) != 0) { if ((objectListNode->obj->outline & OUTLINE_TYPE_MASK) != 0) {
if ((objectListNode->obj->outline & OUTLINE_DISABLED) == 0 && _outlineCount < 100) { if ((objectListNode->obj->outline & OUTLINE_DISABLED) == 0 && _outlineCount < 100) {
@ -845,12 +845,12 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
} }
for (int i = 0; i < renderCount; i++) { for (int i = 0; i < renderCount; i++) {
int light; int lightIntensity;
ObjectListNode* objectListNode = _renderTable[i]; ObjectListNode* objectListNode = _renderTable[i];
if (objectListNode != NULL) { if (objectListNode != NULL) {
// NOTE: Calls `_light_get_tile` twice. // NOTE: Calls `lightGetTileIntensity` twice.
light = std::max(ambientLight, _light_get_tile(elevation, objectListNode->obj->tile)); lightIntensity = std::max(ambientIntensity, lightGetTileIntensity(elevation, objectListNode->obj->tile));
} }
while (objectListNode != NULL) { while (objectListNode != NULL) {
@ -861,7 +861,7 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
if (elevation == objectListNode->obj->elevation) { if (elevation == objectListNode->obj->elevation) {
if ((objectListNode->obj->flags & OBJECT_HIDDEN) == 0) { if ((objectListNode->obj->flags & OBJECT_HIDDEN) == 0) {
_obj_render_object(object, &updatedRect, light); _obj_render_object(object, &updatedRect, lightIntensity);
if ((objectListNode->obj->outline & OUTLINE_TYPE_MASK) != 0) { if ((objectListNode->obj->outline & OUTLINE_TYPE_MASK) != 0) {
if ((objectListNode->obj->outline & OUTLINE_DISABLED) == 0 && _outlineCount < 100) { if ((objectListNode->obj->outline & OUTLINE_DISABLED) == 0 && _outlineCount < 100) {
@ -1721,7 +1721,7 @@ int objectRotateCounterClockwise(Object* obj, Rect* dirtyRect)
// 0x48AC54 // 0x48AC54
void _obj_rebuild_all_light() void _obj_rebuild_all_light()
{ {
lightResetIntensity(); lightResetTileIntensity();
for (int tile = 0; tile < HEX_GRID_SIZE; tile++) { for (int tile = 0; tile < HEX_GRID_SIZE; tile++) {
ObjectListNode* objectListNode = gObjectListHeadByTile[tile]; ObjectListNode* objectListNode = gObjectListHeadByTile[tile];
@ -1762,22 +1762,22 @@ int objectSetLight(Object* obj, int lightDistance, int lightIntensity, Rect* rec
// 0x48AD04 // 0x48AD04
int objectGetLightIntensity(Object* obj) int objectGetLightIntensity(Object* obj)
{ {
int lightLevel = lightGetLightLevel(); int ambientIntensity = lightGetAmbientIntensity();
int lightIntensity = lightGetIntensity(obj->elevation, obj->tile); int tileIntensity = lightGetTrueTileIntensity(obj->elevation, obj->tile);
if (obj == gDude) { if (obj == gDude) {
lightIntensity -= gDude->lightIntensity; tileIntensity -= gDude->lightIntensity;
} }
if (lightIntensity >= lightLevel) { if (tileIntensity >= ambientIntensity) {
if (lightIntensity > 0x10000) { if (tileIntensity > LIGHT_INTENSITY_MAX) {
lightIntensity = 0x10000; tileIntensity = LIGHT_INTENSITY_MAX;
} }
} else { } else {
lightIntensity = lightLevel; tileIntensity = ambientIntensity;
} }
return lightIntensity; return tileIntensity;
} }
// 0x48AD48 // 0x48AD48
@ -3993,7 +3993,7 @@ static int _obj_adjust_light(Object* obj, int a2, Rect* rect)
return -1; return -1;
} }
AdjustLightIntensityProc* adjustLightIntensity = a2 ? lightDecreaseIntensity : lightIncreaseIntensity; AdjustLightIntensityProc* adjustLightIntensity = a2 ? lightDecreaseTileIntensity : lightIncreaseTileIntensity;
adjustLightIntensity(obj->elevation, obj->tile, obj->lightIntensity); adjustLightIntensity(obj->elevation, obj->tile, obj->lightIntensity);
Rect objectRect; Rect objectRect;

View File

@ -1226,7 +1226,7 @@ void tileRenderRoofsInRect(Rect* rect, int elevation)
minY = gSquareGridHeight - 1; minY = gSquareGridHeight - 1;
} }
int light = lightGetLightLevel(); int light = lightGetAmbientIntensity();
int baseSquareTile = gSquareGridWidth * minY; int baseSquareTile = gSquareGridWidth * minY;
@ -1449,7 +1449,7 @@ void tileRenderFloorsInRect(Rect* rect, int elevation)
minY = gSquareGridHeight - 1; minY = gSquareGridHeight - 1;
} }
lightGetLightLevel(); lightGetAmbientIntensity();
int baseSquareTile = gSquareGridWidth * minY; int baseSquareTile = gSquareGridWidth * minY;
@ -1660,10 +1660,10 @@ static void tileRenderFloor(int fid, int x, int y, Rect* rect)
tile = tileFromScreenXY(savedX, savedY + 13, gElevation); tile = tileFromScreenXY(savedX, savedY + 13, gElevation);
if (tile != -1) { if (tile != -1) {
int parity = tile & 1; int parity = tile & 1;
int ambientIntensity = lightGetLightLevel(); int ambientIntensity = lightGetAmbientIntensity();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
// NOTE: Calls `_light_get_tile` twice. // NOTE: Calls `lightGetTileIntensity` twice.
_verticies[i].intensity = std::max(_light_get_tile(elev, tile + _verticies[i].offsets[parity]), ambientIntensity); _verticies[i].intensity = std::max(lightGetTileIntensity(elev, tile + _verticies[i].offsets[parity]), ambientIntensity);
} }
int v23 = 0; int v23 = 0;