void colorTile(const df::tiletype_material& tileMat,MapExtras::MapCache& cache,const DFCoord& pos,screenTile& trg,bool isUndug=false) { t_matpair mat; switch(tileMat) { case df::tiletype_material::ASHES: trg.fg=COLOR_GREY; trg.bold=false; break; case df::tiletype_material::CAMPFIRE: trg.fg=COLOR_YELLOW; trg.bold=true; break; case df::tiletype_material::SOIL: mat=cache.baseMaterialAt(pos); { df::material* m=lookupMaterial(mat,trg); if(m && isUndug) { trg.tile=m->tile; } break; } case df::tiletype_material::STONE: case df::tiletype_material::LAVA_STONE: mat=cache.baseMaterialAt(pos); lookupMaterial(mat,trg); break; case df::tiletype_material::CONSTRUCTION: mat=cache.staticMaterialAt(pos); lookupMaterial(mat,trg,true); break; case df::tiletype_material::MINERAL: mat.mat_index=cache.veinMaterialAt(pos); mat.mat_type=0;//inorganic { df::material* m=lookupMaterial(mat,trg); if(m && isUndug) { trg.tile=m->tile; } } break; case df::tiletype_material::FROZEN_LIQUID: trg.fg=COLOR_CYAN; trg.bold=true; break; case df::tiletype_material::PLANT: case df::tiletype_material::GRASS_LIGHT: //MORE INFO IN MAP BLOCK EVENTS trg.fg=COLOR_GREEN; trg.bold=true; break; case df::tiletype_material::GRASS_DARK: trg.fg=COLOR_GREEN; trg.bold=false; break; case df::tiletype_material::GRASS_DRY: trg.fg=COLOR_YELLOW; trg.bold=true; break; case df::tiletype_material::GRASS_DEAD: trg.fg=COLOR_BROWN; trg.bold=false; break; case df::tiletype_material::DRIFTWOOD: trg.fg=COLOR_WHITE; trg.bold=true; break; case df::tiletype_material::MAGMA: trg.fg=COLOR_RED; trg.bold=true; break; case df::tiletype_material::POOL: case df::tiletype_material::RIVER: case df::tiletype_material::BROOK: trg.fg=COLOR_BROWN; trg.bold=false; break; } }
command_result df_probe (color_ostream &out, vector <string> & parameters) { //bool showBlock, showDesig, showOccup, showTile, showMisc; /* if (!parseOptions(parameters, showBlock, showDesig, showOccup, showTile, showMisc)) { out.printerr("Unknown parameters!\n"); return CR_FAILURE; } */ CoreSuspender suspend; DFHack::Materials *Materials = Core::getInstance().getMaterials(); std::vector<t_matglossInorganic> inorganic; bool hasmats = Materials->CopyInorganicMaterials(inorganic); if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } MapExtras::MapCache mc; int32_t regionX, regionY, regionZ; Maps::getPosition(regionX,regionY,regionZ); int32_t cursorX, cursorY, cursorZ; Gui::getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX == -30000) { out.printerr("No cursor; place cursor over tile to probe.\n"); return CR_FAILURE; } DFCoord cursor (cursorX,cursorY,cursorZ); uint32_t blockX = cursorX / 16; uint32_t tileX = cursorX % 16; uint32_t blockY = cursorY / 16; uint32_t tileY = cursorY % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); if(!b || !b->is_valid()) { out.printerr("No data.\n"); return CR_OK; } auto &block = *b->getRaw(); out.print("block addr: 0x%x\n\n", &block); /* if (showBlock) { out.print("block flags:\n"); print_bits<uint32_t>(block.blockflags.whole,out); out.print("\n\n"); } */ df::tiletype tiletype = mc.tiletypeAt(cursor); df::tile_designation &des = block.designation[tileX][tileY]; df::tile_occupancy &occ = block.occupancy[tileX][tileY]; /* if(showDesig) { out.print("designation\n"); print_bits<uint32_t>(block.designation[tileX][tileY].whole, out); out.print("\n\n"); } if(showOccup) { out.print("occupancy\n"); print_bits<uint32_t>(block.occupancy[tileX][tileY].whole, out); out.print("\n\n"); } */ // tiletype out.print("tiletype: "); describeTile(out, tiletype); out.print("static: "); describeTile(out, mc.staticTiletypeAt(cursor)); out.print("base: "); describeTile(out, mc.baseTiletypeAt(cursor)); out.print("temperature1: %d U\n",mc.temperature1At(cursor)); out.print("temperature2: %d U\n",mc.temperature2At(cursor)); int offset = block.region_offset[des.bits.biome]; int bx = clip_range(block.region_pos.x + (offset % 3) - 1, 0, world->world_data->world_width-1); int by = clip_range(block.region_pos.y + (offset / 3) - 1, 0, world->world_data->world_height-1); auto biome = &world->world_data->region_map[bx][by]; int sav = biome->savagery; int evi = biome->evilness; int sindex = sav > 65 ? 2 : sav < 33 ? 0 : 1; int eindex = evi > 65 ? 2 : evi < 33 ? 0 : 1; int surr = sindex + eindex * 3; const char* surroundings[] = { "Serene", "Mirthful", "Joyous Wilds", "Calm", "Wilderness", "Untamed Wilds", "Sinister", "Haunted", "Terrifying" }; // biome, geolayer out << "biome: " << des.bits.biome << " (" << "region id=" << biome->region_id << ", " << surroundings[surr] << ", " << "savagery " << biome->savagery << ", " << "evilness " << biome->evilness << ")" << std::endl; out << "geolayer: " << des.bits.geolayer_index << std::endl; int16_t base_rock = mc.layerMaterialAt(cursor); if(base_rock != -1) { out << "Layer material: " << dec << base_rock; if(hasmats) out << " / " << inorganic[base_rock].id << " / " << inorganic[base_rock].name << endl; else out << endl; } int16_t vein_rock = mc.veinMaterialAt(cursor); if(vein_rock != -1) { out << "Vein material (final): " << dec << vein_rock; if(hasmats) out << " / " << inorganic[vein_rock].id << " / " << inorganic[vein_rock].name << endl; else out << endl; } MaterialInfo minfo(mc.baseMaterialAt(cursor)); if (minfo.isValid()) out << "Base material: " << minfo.getToken() << " / " << minfo.toString() << endl; minfo.decode(mc.staticMaterialAt(cursor)); if (minfo.isValid()) out << "Static material: " << minfo.getToken() << " / " << minfo.toString() << endl; // liquids if(des.bits.flow_size) { if(des.bits.liquid_type == tile_liquid::Magma) out <<"magma: "; else out <<"water: "; out << des.bits.flow_size << std::endl; } if(des.bits.flow_forbid) out << "flow forbid" << std::endl; if(des.bits.pile) out << "stockpile?" << std::endl; if(des.bits.rained) out << "rained?" << std::endl; if(des.bits.smooth) out << "smooth?" << std::endl; if(des.bits.water_salt) out << "salty" << endl; if(des.bits.water_stagnant) out << "stagnant" << endl; #define PRINT_FLAG( FIELD, BIT ) out.print("%-16s= %c\n", #BIT , ( FIELD.bits.BIT ? 'Y' : ' ' ) ) PRINT_FLAG( des, hidden ); PRINT_FLAG( des, light ); PRINT_FLAG( des, outside ); PRINT_FLAG( des, subterranean ); PRINT_FLAG( des, water_table ); PRINT_FLAG( des, rained ); PRINT_FLAG( occ, monster_lair); df::coord2d pc(blockX, blockY); t_feature local; t_feature global; Maps::ReadFeatures(&block,&local,&global); PRINT_FLAG( des, feature_local ); if(local.type != -1) { out.print("%-16s", ""); out.print(" %4d", block.local_feature); out.print(" (%2d)", local.type); out.print(" addr 0x%X ", local.origin); out.print(" %s\n", sa_feature(local.type)); } PRINT_FLAG( des, feature_global ); if(global.type != -1) { out.print("%-16s", ""); out.print(" %4d", block.global_feature); out.print(" (%2d)", global.type); out.print(" %s\n", sa_feature(global.type)); } #undef PRINT_FLAG out << "local feature idx: " << block.local_feature << endl; out << "global feature idx: " << block.global_feature << endl; out << std::endl; if(block.occupancy[tileX][tileY].bits.no_grow) out << "no grow" << endl; for(size_t e=0; e<block.block_events.size(); e++) { df::block_square_event * blev = block.block_events[e]; df::block_square_event_type blevtype = blev->getType(); switch(blevtype) { case df::block_square_event_type::grass: { df::block_square_event_grassst * gr_ev = (df::block_square_event_grassst *)blev; if(gr_ev->amount[tileX][tileY] > 0) { out << "amount of grass: " << (int)gr_ev->amount[tileX][tileY] << endl; } break; } case df::block_square_event_type::world_construction: { df::block_square_event_world_constructionst * co_ev = (df::block_square_event_world_constructionst*)blev; uint16_t bits = co_ev->tile_bitmask[tileY]; out << "construction bits: " << bits << endl; break; } default: //out << "unhandled block event type!" << endl; break; } } return CR_OK; }
void Offscreen::drawBuffer( rect2d window,int z,std::vector<screenTile>& buffer ) { if(!df::global::world) return; //TODO static array of images for each tiletype MapExtras::MapCache cache; int w=window.second.x-window.first.x; int h=window.second.y-window.first.y; rect2d localWindow=mkrect_wh(0,0,w+1,h+1); if(buffer.size()!=w*h) buffer.resize(w*h); //basic tiletype stuff here for(int x=window.first.x;x<window.second.x;x++) //todo, make it by block, minimal improvement over cache prob though for(int y=window.first.y;y<window.second.y;y++) { DFCoord coord(x,y,z); df::tiletype tt=cache.tiletypeAt(coord); df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,tt); df::tiletype_shape_basic basic_shape = ENUM_ATTR(tiletype_shape, basic_shape, shape); t_matpair mat=cache.staticMaterialAt(coord); df::tiletype_material tileMat= ENUM_ATTR(tiletype,material,tt); df::tile_designation d=cache.designationAt(coord); df::tile_occupancy o=cache.occupancyAt(coord); df::tiletype_special sp=ENUM_ATTR(tiletype,special,tt); int wx=x-window.first.x; int wy=y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; if(d.bits.hidden) { curTile.tile=0; continue; } if(shape==df::tiletype_shape::EMPTY || shape==df::tiletype_shape::RAMP_TOP) { //empty,liquids and '.' for other stuff... DFCoord coord2(x,y,z-1); df::tiletype tt2=cache.tiletypeAt(coord2); df::tiletype_shape shape2 = ENUM_ATTR(tiletype,shape,tt); df::tiletype_material tileMat2= ENUM_ATTR(tiletype,material,tt2); df::tile_designation d2=cache.designationAt(coord2); df::tiletype_special sp2=ENUM_ATTR(tiletype,special,tt2); bool unDug2= (sp2!=df::tiletype_special::SMOOTH && shape2==df::tiletype_shape::WALL); if (d2.bits.flow_size>0) { if(shape!=df::tiletype_shape::RAMP_TOP) //don't show liquid amount on ramp tops curTile.tile='0'+d2.bits.flow_size; //TODO lookup setting for this else curTile.tile=tilePics[tt]; curTile.fg=(d2.bits.liquid_type)?(COLOR_RED):(COLOR_BLUE); continue; } else if(shape2==df::tiletype_shape::EMPTY) { curTile.tile=178; //look up settings curTile.fg=COLOR_CYAN; continue; } else { if(shape==df::tiletype_shape::RAMP_TOP) curTile.tile=tilePics[tt]; else curTile.tile='.'; colorTile(tileMat2,cache,coord2,curTile,unDug2); continue; } } bool inliquid=false; bool unDug= (sp!=df::tiletype_special::SMOOTH && shape==df::tiletype_shape::WALL); if (d.bits.flow_size>0) { curTile.tile='0'+d.bits.flow_size; curTile.fg=(d.bits.liquid_type)?(COLOR_RED):(COLOR_BLUE); curTile.bold=true; inliquid=true; } if(!inliquid && shape!=df::tiletype_shape::RAMP_TOP) { curTile.tile=tilePics[tt]; colorTile(tileMat,cache,coord,curTile,unDug); if(!unDug) { curTile.bg=0; } } else { if(shape==df::tiletype_shape::RAMP || shape==df::tiletype_shape::BROOK_BED || shape==df::tiletype_shape::RAMP_TOP) curTile.tile=tilePics[tt]; if(!inliquid) colorTile(tileMat,cache,coord,curTile,true); } } //plants for(int bx=window.first.x/16;bx<=window.second.x/16;bx++) //blocks have items by id. So yeah each item a search would be slow for(int by=window.first.y/16;by<=window.second.y/16;by++) { MapExtras::Block* b=cache.BlockAt(DFCoord(bx,by,z)); if(!b || !b->getRaw()) continue; std::vector<df::plant*>& plants=b->getRaw()->plants; for(int i=0;i<plants.size();i++) { df::plant* p=plants[i]; if(p->pos.z==z && isInRect(df::coord2d(p->pos.x,p->pos.y),window)) { int wx=p->pos.x-window.first.x; int wy=p->pos.y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; drawPlant(p,curTile); } } std::vector<df::block_square_event*>& events=b->getRaw()->block_events; for(size_t i=0;i<events.size();i++)//maybe aggregate all the events to one array and move to a function. { df::block_square_event* e=events[i]; switch(e->getType()) { case df::block_square_event_type::grass: { df::block_square_event_grassst* grass=static_cast<df::block_square_event_grassst*>(e); MaterialInfo mat(419, grass->plant_index); if(mat.isPlant()) { df::plant_raw* p=mat.plant; for(int x=0;x<16;x++) for(int y=0;y<16;y++) { int wx=x+bx*16-window.first.x; int wy=y+by*16-window.first.y; if(isInRect(df::coord2d(wx,wy),localWindow) && grass->amount[x][y]>0) { screenTile& curTile=buffer[wx*h+wy]; /* df::tiletype tt=b->tiletypeAt(df::coord2d(x,y)); df::tiletype_special sp=ENUM_ATTR(tiletype,special,tt); df::tiletype_special::DEAD; df::tiletype_special::WET; df::tiletype_special::NORMAL; +variants */ curTile.tile=p->tiles.grass_tiles[0]; curTile.fg=p->colors.grass_colors_0[0]; curTile.bg=p->colors.grass_colors_1[0]; curTile.bold=p->colors.grass_colors_2[0]; } } //TODO alt-tiles } break; } case df::block_square_event_type::material_spatter: { //liquid: //0 nothing //1->49 color //50->99 wave //100->255 two waves //color only, if small //draw waves, if pool df::block_square_event_material_spatterst* spatter=static_cast<df::block_square_event_material_spatterst*>(e); MaterialInfo mat(spatter); if(mat.material) { for(int x=0;x<16;x++) for(int y=0;y<16;y++) { int wx=x+bx*16-window.first.x; int wy=y+by*16-window.first.y; uint8_t amount=spatter->amount[x][y]; if(isInRect(df::coord2d(wx,wy),localWindow) && amount>0) { screenTile& curTile=buffer[wx*h+wy]; curTile.fg=mat.material->tile_color[0]; curTile.bold=mat.material->tile_color[2]; if(spatter->mat_state==df::matter_state::Liquid && amount>49) { if(amount>99) curTile.tile=247; else curTile.tile=126; } } } } break; } default:; } } std::vector<df::flow_info*>& flows=b->getRaw()->flows; for(size_t i=0;i<flows.size();i++) { df::flow_info* f=flows[i]; int wx=f->pos.x-window.first.x; int wy=f->pos.y-window.first.y; if(f->density>0 && isInRect(df::coord2d(wx,wy),localWindow)) { screenTile& curTile=buffer[wx*h+wy]; drawFlow(f,curTile); } } } //in df items blink between stuff, but i don't have time for that //also move up, before flows std::vector<df::item*>& items=df::global::world->items.other[df::items_other_id::IN_PLAY]; for(int i=0;i<items.size();i++) { df::item* it=items[i]; if(it->flags.bits.on_ground && it->pos.z==z && isInRect(df::coord2d(it->pos.x,it->pos.y),window)) { int wx=it->pos.x-window.first.x; int wy=it->pos.y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; drawItem(it,curTile); } } //buildings std::vector<df::building*>& buildings=df::global::world->buildings.all; for(int i=0;i<buildings.size();i++) { df::building* build=buildings[i]; if(z!=build->z) continue; if(!build->isVisibleInUI()) continue; if(isInRect(df::coord2d(build->x1,build->y1),window)||isInRect(df::coord2d(build->x2,build->y2),window)) { df::building_drawbuffer drawBuffer; build->getDrawExtents(&drawBuffer); int bw=drawBuffer.x2-drawBuffer.x1; int bh=drawBuffer.y2-drawBuffer.y1; build->drawBuilding(&drawBuffer,0); //might be viewscreen dependant int wx=build->x1-window.first.x; int wy=build->y1-window.first.y; for(int x=0;x<=bw;x++) for(int y=0;y<=bh;y++) { df::coord2d p(x+wx,y+wy); if(isInRect(p,localWindow)) { screenTile& curTile=buffer[p.x*h+p.y]; if(drawBuffer.tile[x][y]!=32) { curTile.tile=drawBuffer.tile[x][y]; curTile.fg=drawBuffer.fore[x][y]; curTile.bg=drawBuffer.back[x][y]; curTile.bold=drawBuffer.bright[x][y]; } } } } } //units. TODO No multi tile units yet. std::vector<df::unit*>& units=df::global::world->units.active; for(int i=0;i<units.size();i++) { df::unit* u=units[i]; if(!u->flags1.bits.dead && u->pos.z==z && isInRect(df::coord2d(u->pos.x,u->pos.y),window)) { int wx=u->pos.x-window.first.x; int wy=u->pos.y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; drawUnit(u,curTile); } } }