Exemplo n.º 1
0
bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_region_details *details, int x, int y)
{
    // Find actual biome
    int bv = clip_range(details->biome[x][y] & 15, 1, 9);
    tile.biome_off = biome_delta[bv-1];

    df::world_data *data = &world->world_data;
    int bx = clip_range(details->pos.x + tile.biome_off.x, 0, data->world_width-1);
    int by = clip_range(details->pos.y + tile.biome_off.y, 0, data->world_height-1);
    tile.biome_pos = coord2d(bx, by);
    tile.biome = &data->region_map[bx][by];

    tile.geo_biome = df::world_geo_biome::find(tile.biome->geo_index);

    // Compute surface elevation
    tile.elevation = details->elevation[x][y];
    tile.max_soil_depth = std::max((154-tile.elevation)/5,1);
    tile.penalty.clear();

    // Special biome adjustments
    if (!tile.biome->flags.is_set(region_map_entry_flags::is_lake))
    {
        // Mountain biome
        if (tile.biome->elevation >= 150)
            tile.max_soil_depth = 0;
        // Ocean biome
        else if (tile.biome->elevation < 100)
        {
            if (tile.elevation == 99)
                tile.elevation = 98;

            if (tile.geo_biome && (tile.geo_biome->unk1 == 4 || tile.geo_biome->unk1 == 5))
            {
                auto b_details = get_details(data, tile.biome_pos);

                if (b_details && b_details->unk12e8 < 500)
                    tile.max_soil_depth = 0;
            }
        }
    }

    tile.base_z = tile.elevation-1;

    return true;
}
Exemplo n.º 2
0
rgbf lightThread::lightUpCell(rgbf power,int dx,int dy,int tx,int ty)
{
    int h=dispatch.getH();
    if(isInRect(coord2d(tx,ty),dispatch.viewPort))
    {
        size_t tile=tx*h+ty;
        int dsq=dx*dx+dy*dy;
        float dt=1;
        if(dsq == 1)
            dt=1;
        else if(dsq == 2)
            dt = RootTwo;
        else if(dsq == 0)
            dt = 0;
        else
            dt=sqrt((float)dsq);
        rgbf& v=dispatch.occlusion[tile];
        lightSource& ls=dispatch.lights[tile];
        bool wallhack=false;
        if(v.r+v.g+v.b==0)
            wallhack=true;

        if (dsq>0 && !wallhack)
        {
            power*=v.pow(dt);
        }
        if(ls.radius>0 && dsq>0)
        {
            if(power<=ls.power)
                return rgbf();
        }
        //float dt=sqrt(dsq);
        rgbf oldCol=canvas[tile];
        rgbf ncol=blendMax(power,oldCol);
        canvas[tile]=ncol;

        if(wallhack)
            return rgbf();


        return power;
    }
    else
        return rgbf();
}
Exemplo n.º 3
0
        "  If called during the embark selection screen, displays\n"
        "  an estimate of layer stone availability. If the 'all'\n"
        "  option is specified, also estimates veins.\n"
        "  The estimate is computed either for 1 embark tile of the\n"
        "  blinking biome, or for all tiles of the embark rectangle.\n"
    ));
    return CR_OK;
}

DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
    return CR_OK;
}

static coord2d biome_delta[] = {
    coord2d(-1,1), coord2d(0,1), coord2d(1,1),
    coord2d(-1,0), coord2d(0,0), coord2d(1,0),
    coord2d(-1,-1), coord2d(0,-1), coord2d(1,-1)
};

struct EmbarkTileLayout {
    coord2d biome_off, biome_pos;
    df::region_map_entry *biome;
    df::world_geo_biome *geo_biome;
    int elevation, max_soil_depth;
    int min_z, base_z;
    std::map<int, float> penalty;
};

static df::world_region_details *get_details(df::world_data *data, df::coord2d pos)
{
Exemplo n.º 4
0
bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_region_details *details, int x, int y)
{
    // Find actual biome
    int bv = clip_range(details->biome[x][y] & 15, 1, 9);
    tile.biome_off = biome_delta[bv-1];

    df::world_data *data = world->world_data;
    int bx = clip_range(details->pos.x + tile.biome_off.x, 0, data->world_width-1);
    int by = clip_range(details->pos.y + tile.biome_off.y, 0, data->world_height-1);
    tile.biome_pos = coord2d(bx, by);
    tile.biome = &data->region_map[bx][by];

    tile.geo_biome = df::world_geo_biome::find(tile.biome->geo_index);

    // Compute surface elevation
    tile.elevation = details->elevation[x][y];
    tile.max_soil_depth = std::max((154-tile.elevation)/5,1);
    tile.penalty.clear();

    // Special biome adjustments
    if (!tile.biome->flags.is_set(region_map_entry_flags::is_lake))
    {
        // Mountain biome
        if (tile.biome->elevation >= 150)
            tile.max_soil_depth = 0;
        // Ocean biome
        else if (tile.biome->elevation < 100)
        {
            if (tile.elevation == 99)
                tile.elevation = 98;

            if (tile.geo_biome && (tile.geo_biome->unk1 == 4 || tile.geo_biome->unk1 == 5))
            {
                auto b_details = get_details(data, tile.biome_pos);

                if (b_details && b_details->unk12e8 < 500)
                    tile.max_soil_depth = 0;
            }
        }
    }

    tile.base_z = tile.elevation-1;

    auto &features = details->features[x][y];

    // Collect global feature layer depths and apply penalties
    std::map<int, int> layer_bottom, layer_top;
    bool sea_found = false;

    for (size_t i = 0; i < features.size(); i++)
    {
        auto feature = features[i];
        auto layer = df::world_underground_region::find(feature->layer);
        if (!layer || feature->min_z == -30000) continue;

        layer_bottom[layer->layer_depth] = feature->min_z;
        layer_top[layer->layer_depth] = feature->max_z;
        tile.base_z = std::min(tile.base_z, (int)feature->min_z);

        float penalty = 1.0f;
        switch (layer->type) {
        case df::world_underground_region::Cavern:
            penalty = 0.75f;
            break;
        case df::world_underground_region::MagmaSea:
            sea_found = true;
            tile.min_z = feature->min_z;
            for (int i = feature->min_z; i <= feature->max_z; i++)
                tile.penalty[i] = 0.2 + 0.6f*(i-feature->min_z)/(feature->max_z-feature->min_z+1);
            break;
        case df::world_underground_region::Underworld:
            penalty = 0.0f;
            break;
        }

        if (penalty != 1.0f)
        {
            for (int i = feature->min_z; i <= feature->max_z; i++)
                tile.penalty[i] = penalty;
        }
    }

    if (!sea_found)
    {
        out.printerr("Could not find magma sea; depth may be incorrect.\n");
        tile.min_z = tile.base_z;
    }

    // Scan for big local features and apply their penalties
    for (size_t i = 0; i < features.size(); i++)
    {
        auto feature = features[i];
        auto lfeature = Maps::getLocalInitFeature(details->pos, feature->feature_idx);
        if (!lfeature)
            continue;

        switch (lfeature->getType())
        {
        case feature_type::pit:
        case feature_type::magma_pool:
        case feature_type::volcano:
            for (int i = layer_bottom[lfeature->end_depth];
                 i <= layer_top[lfeature->start_depth]; i++)
                tile.penalty[i] = std::min(0.4f, map_find(tile.penalty, i, 1.0f));
            break;
        default:
            break;
        }
    }

    return true;
}
Exemplo n.º 5
0
void lightingEngineViewscreen::doOcupancyAndLights()
{
    float daycol;
    if(dayHour<0)
    {
        int length=1200/daySpeed;
        daycol= (*df::global::cur_year_tick % length)/ (float)length;
    }
    else
        daycol= fmod(dayHour,24.0f)/24.0f; //1->12h 0->24h
    
    rgbf sky_col=getSkyColor(daycol);
    lightSource sky(sky_col, -1);//auto calculate best size
    
    MapExtras::MapCache cache;
    doSun(sky,cache);

    int window_x=*df::global::window_x;
    int window_y=*df::global::window_y;
    coord2d window2d(window_x,window_y);
    int window_z=*df::global::window_z;
    rect2d vp=getMapViewport();
    coord2d vpSize=rect_size(vp);
    rect2d blockVp;
    blockVp.first=coord2d(window_x,window_y)/16;
    blockVp.second=(window2d+vpSize)/16;
    blockVp.second.x=std::min(blockVp.second.x,(int16_t)df::global::world->map.x_count_block);
    blockVp.second.y=std::min(blockVp.second.y,(int16_t)df::global::world->map.y_count_block);
   
    for(int blockX=blockVp.first.x;blockX<=blockVp.second.x;blockX++)
    for(int blockY=blockVp.first.y;blockY<=blockVp.second.y;blockY++)
    {
        MapExtras::Block* b=cache.BlockAt(DFCoord(blockX,blockY,window_z));
        MapExtras::Block* bDown=cache.BlockAt(DFCoord(blockX,blockY,window_z-1));
        if(!b)
            continue; //empty blocks fixed by sun propagation
        
        for(int block_x = 0; block_x < 16; block_x++)
        for(int block_y = 0; block_y < 16; block_y++)
        {
            df::coord2d pos;
            pos.x = blockX*16+block_x;
            pos.y = blockY*16+block_y;
            df::coord2d gpos=pos;
            pos=worldToViewportCoord(pos,vp,window2d);
            if(!isInRect(pos,vp))
                continue;
            int tile=getIndex(pos.x,pos.y);
            rgbf& curCell=ocupancy[tile];
            curCell=matAmbience.transparency;
            

            df::tiletype type = b->tiletypeAt(gpos);
            df::tile_designation d = b->DesignationAt(gpos);
            if(d.bits.hidden)
            {
                curCell=rgbf(0,0,0);
                continue; // do not process hidden stuff, TODO other hidden stuff
            }
            //df::tile_occupancy o = b->OccupancyAt(gpos);
            df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,type);
            df::tiletype_shape_basic basic_shape = ENUM_ATTR(tiletype_shape, basic_shape, shape);
            df::tiletype_material tileMat= ENUM_ATTR(tiletype,material,type);
            
            DFHack::t_matpair mat=b->staticMaterialAt(gpos);
            
            matLightDef* lightDef=getMaterialDef(mat.mat_type,mat.mat_index);
            if(!lightDef || !lightDef->isTransparent)
                lightDef=&matWall;
            if(shape==df::tiletype_shape::BROOK_BED )
            {
                curCell=rgbf(0,0,0);
            }
            else if(shape==df::tiletype_shape::WALL)
            {
                if(tileMat==df::tiletype_material::FROZEN_LIQUID)
                    applyMaterial(tile,matIce);
                else
                    applyMaterial(tile,*lightDef);
            }
            else if(!d.bits.liquid_type && d.bits.flow_size>0 )
            {
                applyMaterial(tile,matWater, (float)d.bits.flow_size/7.0f, (float)d.bits.flow_size/7.0f);
            }
            if(d.bits.liquid_type && d.bits.flow_size>0) 
            {
                applyMaterial(tile,matLava,(float)d.bits.flow_size/7.0f,(float)d.bits.flow_size/7.0f);
            }
            else if(shape==df::tiletype_shape::EMPTY || shape==df::tiletype_shape::RAMP_TOP 
                || shape==df::tiletype_shape::STAIR_DOWN || shape==df::tiletype_shape::STAIR_UPDOWN)
            {
                if(bDown)
                {
                   df::tile_designation d2=bDown->DesignationAt(gpos);
                   if(d2.bits.liquid_type && d2.bits.flow_size>0)
                   {
                       applyMaterial(tile,matLava);
                   }
                }
            }
            

        }
        
        df::map_block* block=b->getRaw();
        if(!block)
            continue;
        //flows
        for(int i=0;i<block->flows.size();i++)
        {
            df::flow_info* f=block->flows[i];
            if(f && f->density>0 && f->type==df::flow_type::Dragonfire || f->type==df::flow_type::Fire)
            {
                df::coord2d pos=f->pos;
                pos=worldToViewportCoord(pos,vp,window2d);
                int tile=getIndex(pos.x,pos.y);
                if(isInRect(pos,vp))
                {
                    rgbf fireColor;
                    if(f->density>60)
                    {
                        fireColor=rgbf(0.98f,0.91f,0.30f);
                    }
                    else if(f->density>30)
                    {
                        fireColor=rgbf(0.93f,0.16f,0.16f);
                    }
                    else
                    {
                        fireColor=rgbf(0.64f,0.0f,0.0f);
                    }
                    lightSource fire(fireColor,f->density/5);
                    addLight(tile,fire);
                }
            }
        }
        
        //plants
        for(int i=0;i<block->plants.size();i++)
        {
            df::plant* cPlant=block->plants[i];
            if (cPlant->grow_counter <180000) //todo maybe smaller light/oclusion?
                continue;
            df::coord2d pos=cPlant->pos;
            pos=worldToViewportCoord(pos,vp,window2d);
            int tile=getIndex(pos.x,pos.y);
            if(isInRect(pos,vp))
            {
                applyMaterial(tile,419,cPlant->material);
            }
        }
        //blood and other goo
        for(int i=0;i<block->block_events.size();i++)
        {
            df::block_square_event* ev=block->block_events[i];
            df::block_square_event_type ev_type=ev->getType();
            if(ev_type==df::block_square_event_type::material_spatter)
            {
                df::block_square_event_material_spatterst* spatter=static_cast<df::block_square_event_material_spatterst*>(ev);
                matLightDef* m=getMaterialDef(spatter->mat_type,spatter->mat_index);
                if(!m)
                    continue;
                if(!m->isEmiting)
                    continue;
                for(int x=0;x<16;x++)
                for(int y=0;y<16;y++)
                {
                    df::coord2d pos;
                    pos.x = blockX*16+x;
                    pos.y = blockY*16+y;
                    int16_t amount=spatter->amount[x][y];
                    if(amount<=0)
                        continue;
                    pos=worldToViewportCoord(pos,vp,window2d);
                    if(isInRect(pos,vp))
                    {
                        addLight(getIndex(pos.x,pos.y),m->makeSource((float)amount/100));
                    }
                }
            }
        }
    }
    if(df::global::cursor->x>-30000)
    {
        int wx=df::global::cursor->x-window_x+vp.first.x;
        int wy=df::global::cursor->y-window_y+vp.first.y;
        int tile=getIndex(wx,wy);
        applyMaterial(tile,matCursor);
    }
    //citizen only emit light, if defined
    //or other creatures
    if(matCitizen.isEmiting || creatureDefs.size()>0)
    for (int i=0;i<df::global::world->units.active.size();++i)
    {
        df::unit *u = df::global::world->units.active[i];
        coord2d pos=worldToViewportCoord(coord2d(u->pos.x,u->pos.y),vp,window2d);
        if(u->pos.z==window_z && isInRect(pos,vp))
        {
            if (DFHack::Units::isCitizen(u) && !u->counters.unconscious)
                addLight(getIndex(pos.x,pos.y),matCitizen.makeSource());
            creatureLightDef *def=getCreatureDef(u);
            if(def && !u->flags1.bits.dead)
            {
                addLight(getIndex(pos.x,pos.y),def->light.makeSource());
            }
        }
    }
    //items
    if(itemDefs.size()>0)
    {
        std::vector<df::item*>& vec=df::global::world->items.other[items_other_id::IN_PLAY];
        for(size_t i=0;i<vec.size();i++)
        {
            df::item* curItem=vec[i];
            df::coord itemPos=DFHack::Items::getPosition(curItem);
            coord2d pos=worldToViewportCoord(itemPos,vp,window2d);
            itemLightDef* mat=0;
            if( itemPos.z==window_z && isInRect(pos,vp) && (mat=getItemDef(curItem)) )
            {
                if( ((mat->equiped || mat->haul ||mat->inBuilding ||mat->inContainer) && curItem->flags.bits.in_inventory)|| //TODO split this up
                    (mat->onGround && curItem->flags.bits.on_ground) )
                {
                    if(mat->light.isEmiting)
                        addLight(getIndex(pos.x,pos.y),mat->light.makeSource());
                    if(!mat->light.isTransparent)
                        addOclusion(getIndex(pos.x,pos.y),mat->light.transparency,1);
                }
            }
        }
    }
    
    //buildings
    for(size_t i = 0; i < df::global::world->buildings.all.size(); i++)
    {
        df::building *bld = df::global::world->buildings.all[i];
        
        if(window_z!=bld->z)
            continue;
        if(bld->getBuildStage()<bld->getMaxBuildStage()) //only work if fully built
            continue;

        df::coord2d p1(bld->x1,bld->y1);
        df::coord2d p2(bld->x2,bld->y2);
        p1=worldToViewportCoord(p1,vp,window2d);
        p2=worldToViewportCoord(p2,vp,window2d);
        if(isInRect(p1,vp)||isInRect(p2,vp))
        {
            
            int tile;
            if(isInRect(p1,vp))
                tile=getIndex(p1.x,p1.y); //TODO multitile buildings. How they would work?
            else
                tile=getIndex(p2.x,p2.y);
            df::building_type type = bld->getType();
            buildingLightDef* def=getBuildingDef(bld);
            if(!def)
                continue;
            if(type==df::enums::building_type::Door)
            {
                df::building_doorst* door=static_cast<df::building_doorst*>(bld);
                if(!door->door_flags.bits.closed)
                    continue;
            }
            else if(type==df::enums::building_type::Floodgate)
            {
                df::building_floodgatest* gate=static_cast<df::building_floodgatest*>(bld);
                if(!gate->gate_flags.bits.closed)
                    continue;
            }
            
            
            if(def->useMaterial)
            {
                matLightDef* mat=getMaterialDef(bld->mat_type,bld->mat_index);
                if(!mat)mat=&matWall;
                if(!def->poweredOnly || !bld->isUnpowered()) //not powered. Add occlusion only.
                {
                    if(def->light.isEmiting)
                    {
                        addLight(tile,def->light.makeSource(def->size));
                    }
                    else if(mat->isEmiting)
                    {
                        addLight(tile,mat->makeSource(def->size));
                    }
                }
                if(def->light.isTransparent)
                {
                    addOclusion(tile,def->light.transparency,def->size);
                }
                else
                {
                    addOclusion(tile,mat->transparency,def->size);
                }
            }
            else
            {
                if(!def->poweredOnly || !bld->isUnpowered())//not powered. Add occlusion only.
                    addOclusion(tile,def->light.transparency,def->size);
                else
                    applyMaterial(tile,def->light,def->size,def->thickness);
            }
        }
    }
    
}