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) {
return lightGetLightLevel() > 62259;
return lightGetAmbientIntensity() > LIGHT_INTENSITY_MAX * 0.95;
}
int inventoryItemIndex = -1;
@ -2879,7 +2879,7 @@ static int _ai_try_attack(Object* a1, Object* a2)
// 0x42AE90
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);
}
return 0;

View File

@ -343,21 +343,6 @@ static void opGetPcStat(Program* program);
// 0x504B0C
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
static Rect stru_453FC0 = { 0, 0, 640, 480 };
@ -2234,23 +2219,36 @@ static void opCritterHeal(Program* program)
// 0x457934
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 lightLevel = data;
if (data == 50) {
lightSetLightLevel(dword_453F90[1], true);
lightSetAmbientIntensity(intensities[1], true);
return;
}
int lightIntensity;
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 {
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1226,7 +1226,7 @@ void tileRenderRoofsInRect(Rect* rect, int elevation)
minY = gSquareGridHeight - 1;
}
int light = lightGetLightLevel();
int light = lightGetAmbientIntensity();
int baseSquareTile = gSquareGridWidth * minY;
@ -1449,7 +1449,7 @@ void tileRenderFloorsInRect(Rect* rect, int elevation)
minY = gSquareGridHeight - 1;
}
lightGetLightLevel();
lightGetAmbientIntensity();
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);
if (tile != -1) {
int parity = tile & 1;
int ambientIntensity = lightGetLightLevel();
int ambientIntensity = lightGetAmbientIntensity();
for (int i = 0; i < 10; i++) {
// NOTE: Calls `_light_get_tile` twice.
_verticies[i].intensity = std::max(_light_get_tile(elev, tile + _verticies[i].offsets[parity]), ambientIntensity);
// NOTE: Calls `lightGetTileIntensity` twice.
_verticies[i].intensity = std::max(lightGetTileIntensity(elev, tile + _verticies[i].offsets[parity]), ambientIntensity);
}
int v23 = 0;