bool light_map::sees(int fx, int fy, int tx, int ty, int max_range) { if(!INBOUNDS_LARGE(fx, fy) || !INBOUNDS_LARGE(tx, ty)) return false; if (max_range >= 0 && (abs(tx - fx) > max_range || abs(ty - fy) > max_range)) return false; // Out of range! int ax = abs(tx - fx) << 1; int ay = abs(ty - fy) << 1; int dx = (fx < tx) ? 1 : -1; int dy = (fy < ty) ? 1 : -1; int x = fx; int y = fy; float transparency = LIGHT_TRANSPARENCY_CLEAR; // TODO: [lightmap] Pull out the common code here rather than duplication if (ax > ay) { int t = ay - (ax >> 1); do { if(t >= 0 && ((y + dy != ty) || (x + dx == tx))) { y += dy; t -= ax; } x += dx; t += ay; if(c[x + LIGHTMAP_RANGE_X][y + LIGHTMAP_RANGE_Y].transparency == LIGHT_TRANSPARENCY_SOLID) break; } while(!(x == tx && y == ty)); } else {
bool light_map::is_outside(int dx, int dy) { // We don't know and true seems a better default than false if (!INBOUNDS_LARGE(dx, dy)) return true; return c[dx + LIGHTMAP_RANGE_X][dy + LIGHTMAP_RANGE_Y].is_outside; }
void light_map::generate(game* g, int x, int y, float natural_light, float luminance) { build_light_cache(g, x, y); fill(lm, 0.0f); fill(sm, 0.0f); int dir_x[] = { 1, 0 , -1, 0 }; int dir_y[] = { 0, 1 , 0, -1 }; int dir_d[] = { 180, 270, 0, 90 }; // Daylight vision handling returned back to map due to issues it causes here if (natural_light > LIGHT_SOURCE_BRIGHT) { // Apply sunlight, first light source so just assign for(int sx = x - SEEX; sx <= x + SEEX; ++sx) { for(int sy = y - SEEY; sy <= y + SEEY; ++sy) { // In bright light indoor light exists to some degree if (!c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].is_outside) lm[sx - x + SEEX][sy - y + SEEY] = LIGHT_AMBIENT_LOW; } } } // Apply player light sources if (luminance > LIGHT_AMBIENT_LOW) apply_light_source(x, y, x, y, luminance); for(int sx = x - LIGHTMAP_RANGE_X; sx <= x + LIGHTMAP_RANGE_X; ++sx) { for(int sy = y - LIGHTMAP_RANGE_Y; sy <= y + LIGHTMAP_RANGE_Y; ++sy) { // When underground natural_light is 0, if this changes we need to revisit if (natural_light > LIGHT_AMBIENT_LOW) { if (!c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].is_outside) { // Apply light sources for external/internal divide for(int i = 0; i < 4; ++i) { if (INBOUNDS_LARGE(sx - x + dir_x[i], sy - y + dir_y[i]) && c[sx - x + LIGHTMAP_RANGE_X + dir_x[i]][sy - y + LIGHTMAP_RANGE_Y + dir_y[i]].is_outside) { if (INBOUNDS(sx - x, sy - y) && c[LIGHTMAP_RANGE_X][LIGHTMAP_RANGE_Y].is_outside) lm[sx - x + SEEX][sy - y + SEEY] = natural_light; if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].transparency > LIGHT_TRANSPARENCY_SOLID) apply_light_arc(sx, sy, dir_d[i], x, y, natural_light); } } } } if (g->m.i_at(sx, sy).size() == 1 && g->m.i_at(sx, sy)[0].type->id == itm_flashlight_on) apply_light_source(sx, sy, x, y, 20); if(g->m.ter(sx, sy) == t_lava) apply_light_source(sx, sy, x, y, 50); if(g->m.ter(sx, sy) == t_console) apply_light_source(sx, sy, x, y, 3); if (g->m.i_at(sx, sy).size() == 1 && g->m.i_at(sx, sy)[0].type->id == itm_candle_lit) apply_light_source(sx, sy, x, y, 4); if(g->m.ter(sx, sy) == t_emergency_light) apply_light_source(sx, sy, x, y, 3); // TODO: [lightmap] Attach light brightness to fields switch(g->m.field_at(sx, sy).type) { case fd_fire: if (3 == g->m.field_at(sx, sy).density) apply_light_source(sx, sy, x, y, 160); else if (2 == g->m.field_at(sx, sy).density) apply_light_source(sx, sy, x, y, 60); else apply_light_source(sx, sy, x, y, 16); break; case fd_fire_vent: case fd_flame_burst: apply_light_source(sx, sy, x, y, 8); break; case fd_electricity: if (3 == g->m.field_at(sx, sy).density) apply_light_source(sx, sy, x, y, 8); else if (2 == g->m.field_at(sx, sy).density) apply_light_source(sx, sy, x, y, 1); else apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL); // kinda a hack as the square will still get marked break; } // Apply any vehicle light sources if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh && c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_DARK) { if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_LIT) { int dir = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh->face.dir(); float luminance = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light; apply_light_arc(sx, sy, dir, x, y, luminance); } } if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon >= 0) { if (g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].has_effect(ME_ONFIRE)) apply_light_source(sx, sy, x, y, 3); // TODO: [lightmap] Attach natural light brightness to creatures // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot) // TODO: [lightmap] Allow creatures to have facing and arc lights switch(g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].type->id) { case mon_zombie_electric: apply_light_source(sx, sy, x, y, 1); break; case mon_flaming_eye: apply_light_source(sx, sy, x, y, LIGHT_SOURCE_BRIGHT); break; case mon_manhack: apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL); break; } } } } }
void light_map::generate(game* g, int x, int y, float natural_light, float luminance) { build_light_cache(g, x, y); memset(lm, 0, sizeof(lm)); memset(sm, 0, sizeof(sm)); int dir_x[] = { 1, 0 , -1, 0 }; int dir_y[] = { 0, 1 , 0, -1 }; int dir_d[] = { 180, 270, 0, 90 }; //g->add_msg("natural_light %f", natural_light); //CAT-mgs: this is just for indoors to initialize it at low ambient light if(natural_light > LIGHT_AMBIENT_LOW) // LIGHT_SOURCE_BRIGHT { for(int sx = x - CAT_VX; sx <= x + CAT_VX; ++sx) { for(int sy = y - CAT_VY; sy <= y + CAT_VY; ++sy) { if(!is_outside(sx - x + g->u.view_offset_x, sy - y + g->u.view_offset_y)) lm[sx - x + CAT_VX][sy - y + CAT_VY] = LIGHT_AMBIENT_LOW; } } } if(luminance > LIGHT_AMBIENT_LOW) apply_light_source(g->u.posx, g->u.posy, x, y, luminance); for(int sx = x - LIGHTMAP_RANGE_X; sx <= x + LIGHTMAP_RANGE_X; ++sx) { for(int sy = y - LIGHTMAP_RANGE_Y; sy <= y + LIGHTMAP_RANGE_Y; ++sy) { const ter_id terrain = g->m.ter(sx, sy); const std::vector<item> items = g->m.i_at(sx, sy); const field current_field = g->m.field_at(sx, sy); // When underground natural_light is 0, if this changes we need to revisit if (natural_light > LIGHT_AMBIENT_LOW) { int lx= sx - x + g->u.view_offset_x; int ly= sy - y + g->u.view_offset_y; if(!is_outside(lx, ly)) { // Apply light sources for external/internal divide for(int i = 0; i < 4; ++i) { if(INBOUNDS_LARGE(lx + dir_x[i], ly + dir_y[i]) && is_outside(lx + dir_x[i], ly + dir_y[i])) { //CAT-mgs: I did that above, didn't I? //... no, yes, what's this for anyway? if(INBOUNDS(sx - x, sy - y) && is_outside(0, 0)) lm[sx - x + CAT_VX][sy - y + CAT_VY]= natural_light; if(c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].transparency > LIGHT_TRANSPARENCY_SOLID) apply_light_arc(sx, sy, dir_d[i], x, y, natural_light); } } } } //CAT-g: if(items.size() > 0) { if(items[0].type->id == itm_flashlight_on || items[items.size()-1].type->id == itm_flashlight_on) apply_light_source(sx, sy, x, y, 48); if(items[0].type->id == itm_torch_lit || items[items.size()-1].type->id == itm_torch_lit) apply_light_source(sx, sy, x, y, 20); if(items[0].type->id == itm_candle_lit || items[items.size()-1].type->id == itm_candle_lit) apply_light_source(sx, sy, x, y, 9); } if(terrain == t_lava) apply_light_source(sx, sy, x, y, 48); if(terrain == t_console) apply_light_source(sx, sy, x, y, 3); if(terrain == t_emergency_light) apply_light_source(sx, sy, x, y, 3); // TODO: [lightmap] Attach light brightness to fields switch(current_field.type) { case fd_fire: if(current_field.density > 5) apply_light_source(sx, sy, x, y, 48); else if (current_field.density > 2) apply_light_source(sx, sy, x, y, 20); else apply_light_source(sx, sy, x, y, 9); break; case fd_fire_vent: apply_light_source(sx, sy, x, y, 3); case fd_flame_burst: apply_light_source(sx, sy, x, y, 8); break; case fd_electricity: if (3 == current_field.density) apply_light_source(sx, sy, x, y, 9); else if (2 == current_field.density) apply_light_source(sx, sy, x, y, 1); else apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL); // kinda a hack as the square will still get marked break; } // Apply any vehicle light sources if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh && c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_DARK) { if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_LIT) { int dir = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh->face.dir(); //CAT-g: longer range headlights // float luminance = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light; float luminance = 4000 + c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light; apply_light_arc(sx, sy, dir, x, y, luminance); } } if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon >= 0) { if (g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].has_effect(ME_ONFIRE)) apply_light_source(sx, sy, x, y, 3); // TODO: [lightmap] Attach natural light brightness to creatures // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot) // TODO: [lightmap] Allow creatures to have facing and arc lights switch(g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].type->id) { case mon_zombie_electric: apply_light_source(sx, sy, x, y, 1); break; case mon_turret: apply_light_source(sx, sy, x, y, 2); break; case mon_flaming_eye: apply_light_source(sx, sy, x, y, LIGHT_SOURCE_BRIGHT); break; case mon_manhack: apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL); break; } } } } }