item map::water_from(int x, int y) { item ret((*itypes)[itm_null], 0); int rn = rng(1, 10); if (ter(x, y) == t_water_sh) { if (rn <= 3) ret.type = (*itypes)[itm_water_dirty]; else ret.type = (*itypes)[itm_water]; } else if (ter(x, y) == t_water_dp) { if (rn <= 2) ret.type = (*itypes)[itm_water_dirty]; else ret.type = (*itypes)[itm_water]; } else if (ter(x, y) == t_sewage) { if (rn <= 9) ret.type = (*itypes)[itm_water_dirty]; else ret.type = (*itypes)[itm_water]; } else if (ter(x, y) == t_toilet) { if (rn <= 8) ret.type = (*itypes)[itm_water_dirty]; else ret.type = (*itypes)[itm_water]; } return ret; }
bool map::is_outside(int x, int y) { return (ter(x , y ) != t_floor && ter(x - 1, y - 1) != t_floor && ter(x - 1, y ) != t_floor && ter(x - 1, y + 1) != t_floor && ter(x , y - 1) != t_floor && ter(x , y ) != t_floor && ter(x , y + 1) != t_floor && ter(x + 1, y - 1) != t_floor && ter(x + 1, y ) != t_floor && ter(x + 1, y + 1) != t_floor ); }
bool map::close_door(int x, int y) { if (ter(x, y) == t_door_o) { ter(x, y) = t_door_c; return true; } else if (ter(x, y) == t_door_metal_o) { ter(x, y) = t_door_metal_c; return true; } return false; }
// map::destroy is only called (?) if the terrain is NOT bashable. void map::destroy(game *g, int x, int y, bool makesound) { switch (ter(x, y)) { case t_gas_pump: if (one_in(4)) g->explosion(x, y, 40, 0, true); else for (int i = x - 2; i <= x + 2; i++) { for (int j = y - 2; j <= y + 2; j++) { if (move_cost(i, j) > 0 && one_in(3)) add_item(i, j, g->itypes[itm_gasoline], 0); if (move_cost(i, j) > 0 && one_in(6)) add_item(i, j, g->itypes[itm_steel_chunk], 0); } } ter(x, y) = t_rubble; break; case t_door_c: case t_door_b: case t_door_locked: case t_door_boarded: ter(x, y) = t_door_frame; for (int i = x - 2; i <= x + 2; i++) { for (int j = y - 2; j <= y + 2; j++) { if (move_cost(i, j) > 0 && one_in(6)) add_item(i, j, g->itypes[itm_2x4], 0); } } case t_wall_v: case t_wall_h: for (int i = x - 2; i <= x + 2; i++) { for (int j = y - 2; j <= y + 2; j++) { if (move_cost(i, j) > 0 && one_in(5)) add_item(i, j, g->itypes[itm_rock], 0); if (move_cost(i, j) > 0 && one_in(4)) add_item(i, j, g->itypes[itm_2x4], 0); } } ter(x, y) = t_rubble; break; default: if (has_flag(explodes, x, y)) g->explosion(x, y, 40, 0, true); ter(x, y) = t_rubble; } if (makesound) g->sound(x, y, 40, "SMASH!!"); }
void cCamera::UpdateInput(float deltaTime) { cVector3df ter(0.0f,0.0f,-m_speed *deltaTime), ter2(-m_speed *deltaTime,0.0f,0.0f),ter3(m_speed *deltaTime,0.0f,0.0f),ter4(0.0f,0.0f,m_speed *deltaTime); cVector3df Front,Left,Right,Back; VectorRotate(ter,ENGINE->m_activeCamera->Camera,Front); VectorRotate(ter2,ENGINE->m_activeCamera->Camera,Left); VectorRotate(ter3,ENGINE->m_activeCamera->Camera,Right); VectorRotate(ter4,ENGINE->m_activeCamera->Camera,Back); if(INPUT->getMouseButtonState(LEFT_MOUSE_BUTTON)) setEnabledMouse(); if(!INPUT->getMouseButtonState(LEFT_MOUSE_BUTTON)) setDisabledMouse(); if(INPUT->getKey('W')||INPUT->getKey('w')) move(Front); if(INPUT->getKey('S')||INPUT->getKey('s')) move(Back); if(INPUT->getKey('A')||INPUT->getKey('a')) move(Left); if(INPUT->getKey('D')||INPUT->getKey('d')) move(Right); if(INPUT->getKey('R')||INPUT->getKey('r')) move(cVector3df(0,0.1f,0)); if(INPUT->getKey('F')||INPUT->getKey('f')) move(cVector3df(0,-0.1f,0)); }
bool map::trans(int x, int y) { // Control statement is a problem. Normally returning false on an out-of-bounds // is how we stop rays from going on forever. Instead we'll have to include // this check in the ray loop. if (!inbounds(x, y)) return true; return terlist[ter(x, y)].flags & mfb(transparent) && (field_at(x, y).type == 0 || // Fields may obscure the view, too fieldlist[field_at(x, y).type].transparent[field_at(x, y).density - 1]); }
std::string overmapbuffer::get_description_at( const tripoint &where ) { const std::string ter_name = ter( sm_to_omt_copy( where ) )->get_name(); if( where.z != 0 ) { return ter_name; } const auto closest_cref = closest_known_city( where ); if( !closest_cref ) { return ter_name; } const auto &closest_city = *closest_cref.city; const direction dir = direction_from( closest_cref.abs_sm_pos, where ); const std::string dir_name = direction_name( dir ); const int sm_size = omt_to_sm_copy( closest_cref.city->size ); const int sm_dist = closest_cref.distance; if( sm_dist <= 3 * sm_size / 4 ) { if( sm_size >= 16 ) { // The city is big enough to be split in districts. if( sm_dist <= sm_size / 4 ) { //~ First parameter is a terrain name, second parameter is a city name. return string_format( _( "%1$s in central %2$s" ), ter_name.c_str(), closest_city.name.c_str() ); } else { //~ First parameter is a terrain name, second parameter is a direction, and third parameter is a city name. return string_format( _( "%1$s in %2$s %3$s" ), ter_name.c_str(), dir_name.c_str(), closest_city.name.c_str() ); } } else { //~ First parameter is a terrain name, second parameter is a city name. return string_format( _( "%1$s in %2$s" ), ter_name.c_str(), closest_city.name.c_str() ); } } else if( sm_dist <= sm_size ) { if( sm_size >= 8 ) { // The city is big enough to have outskirts. //~ First parameter is a terrain name, second parameter is a direction, and third parameter is a city name. return string_format( _( "%1$s on the %2$s outskirts of %3$s" ), ter_name.c_str(), dir_name.c_str(), closest_city.name.c_str() ); } else { //~ First parameter is a terrain name, second parameter is a city name. return string_format( _( "%1$s in %2$s" ), ter_name.c_str(), closest_city.name.c_str() ); } } //~ First parameter is a terrain name, second parameter is a direction, and third parameter is a city name. return string_format( _( "%1$s %2$s from %3$s" ), ter_name.c_str(), dir_name.c_str(), closest_city.name.c_str() ); }
void map::marlossify(int x, int y) { int type = rng(1, 9); switch (type) { case 1: case 2: case 3: case 4: ter(x, y) = t_fungus; break; case 5: case 6: case 7: ter(x, y) = t_marloss; break; case 8: ter(x, y) = t_tree_fungal; break; case 9: ter(x, y) = t_slime; break; } }
bool map::open_door(int x, int y, bool inside) { if (ter(x, y) == t_door_c) { ter(x, y) = t_door_o; return true; } else if (ter(x, y) == t_door_metal_c) { ter(x, y) = t_door_metal_o; return true; } else if (inside && ter(x, y) == t_door_locked) { ter(x, y) = t_door_o; return true; } return false; }
string DCPGenerator::generateDCP(const string& fileName, string &headersb, string &funcdefs, const string& app) { ifstream infile; string data,allcontent; infile.open(fileName.c_str()); string file,dir; /*int s,en; s = fileName.find_last_of("/")+1; dir = fileName.substr(0,s-1); en = fileName.find_last_of("."); file = fileName.substr(s,en-s);*/ file = fileName; RegexUtil::replace(file,"[/]+","/"); StringUtil::replaceFirst(file, ConfigurationData::getInstance()->coreServerProperties.webPath, ""); RegexUtil::replace(file, "[^a-zA-Z0-9_]+", ""); if(infile) { while(getline(infile, data)) { if(data.find("<import>")!=string::npos && data.find("</import>")!=string::npos) { int s = data.find("<import>")+8; int e = data.find("</import>"); data=data.substr(s,e-s); string file1 = app + "/dcp/" + data; RegexUtil::replace(file1, "[^a-zA-Z0-9_]+", ""); allcontent.append("<DCPB>screen << _"+file1+"emittHTML();\n</DCPB>"); /*ifstream inf(data.c_str()); if(inf) { while(getline(inf, data)) { allcontent.append(data+"\n"); } }*/ } else allcontent.append(data+"\n"); } } string header,bodies,funcs; int b = allcontent.find("<DCPH>") + 6; int e = allcontent.find("</DCPH>"); int len = e - b; if(len>0) { header.append(allcontent.substr(b,len)); allcontent = allcontent.substr(e+7); headersb.append(header+"\n"); } while(allcontent.find("<DCPF>")!=string::npos) { b = allcontent.find("<DCPF>"); e = allcontent.find("</DCPF>") + 7; string temp1 = allcontent.substr(b,e-b); StringUtil::replaceAll(allcontent,temp1,""); //string ter(allcontent.substr(0,b-6)); //StringUtil::replaceAll(ter,"\n",""); //StringUtil::replaceAll(ter,"\"","\\\""); e = temp1.find("</DCPF>"); len = e - b; funcs.append(temp1.substr(6,e-6)); //allcontent = allcontent.substr(e+7); } bodies.append(funcs); //bodies.append(); funcdefs.append("string _"+file+"emittHTML();\n"); bodies.append("string _"+file+"emittHTML()\n{\n"); bodies.append("stringstream screen;\n"); while(allcontent.find("<DCPB>")!=string::npos) { b = allcontent.find("<DCPB>") + 6; string ter(allcontent.substr(0,b-6)); StringUtil::replaceAll(ter,"\n",""); StringUtil::replaceAll(ter,"\"","\\\""); bodies.append("screen << \""+ter+"\";"); e = allcontent.find("</DCPB>"); len = e - b; bodies.append(allcontent.substr(b,len)); allcontent = allcontent.substr(e+7); } string ter(allcontent.substr(0)); StringUtil::replaceAll(ter,"\n",""); StringUtil::replaceAll(ter,"\"","\\\""); bodies.append("screen << \""+ter+"\";\nstring scr;\nscr = screen.str();\n"); //bodies.append("\nAfcUtil::writeTofile(\""+dir+"_"+file+".html\",scr,true);\n"); bodies.append("\nreturn scr;\n"); bodies.append("\n}\n"); //bodies.append("}\n"); return bodies; }
bool map::process_fields_in_submap(game *g, int gridn) { bool found_field = false; field *cur; field_id curtype; for (int locx = 0; locx < SEEX; locx++) { for (int locy = 0; locy < SEEY; locy++) { cur = &(grid[gridn].fld[locx][locy]); int x = locx + SEEX * (gridn % my_MAPSIZE), y = locy + SEEY * int(gridn / my_MAPSIZE); curtype = cur->type; if (!found_field && curtype != fd_null) found_field = true; if (cur->density > 3 || cur->density < 1) debugmsg("Whoooooa density of %d", cur->density); if (cur->age == 0) // Don't process "newborn" fields curtype = fd_null; int part; vehicle *veh; switch (curtype) { case fd_null: break; // Do nothing, obviously. OBVIOUSLY. case fd_blood: case fd_bile: if (has_flag(swimmable, x, y)) // Dissipate faster in water cur->age += 250; break; case fd_acid: if (has_flag(swimmable, x, y)) // Dissipate faster in water cur->age += 20; for (int i = 0; i < i_at(x, y).size(); i++) { item *melting = &(i_at(x, y)[i]); if (melting->made_of(LIQUID) || melting->made_of(VEGGY) || melting->made_of(FLESH) || melting->made_of(POWDER) || melting->made_of(COTTON) || melting->made_of(WOOL) || melting->made_of(PAPER) || melting->made_of(PLASTIC) || (melting->made_of(GLASS) && !one_in(3)) || one_in(4)) { // Acid destructable objects here melting->damage++; if (melting->damage >= 5 || (melting->made_of(PAPER) && melting->damage >= 3)) { cur->age += melting->volume(); for (int m = 0; m < i_at(x, y)[i].contents.size(); m++) i_at(x, y).push_back( i_at(x, y)[i].contents[m] ); i_at(x, y).erase(i_at(x, y).begin() + i); i--; } } } break; case fd_sap: break; // It doesn't do anything. case fd_fire: { // Consume items as fuel to help us grow/last longer. bool destroyed = false; int vol = 0, smoke = 0, consumed = 0; for (int i = 0; i < i_at(x, y).size() && consumed < cur->density * 2; i++) { destroyed = false; vol = i_at(x, y)[i].volume(); item *it = &(i_at(x, y)[i]); if (it->is_ammo() && it->ammo_type() != AT_BATT && it->ammo_type() != AT_NAIL && it->ammo_type() != AT_BB && it->ammo_type() != AT_BOLT && it->ammo_type() != AT_ARROW) { cur->age /= 2; cur->age -= 600; destroyed = true; smoke += 6; consumed++; } else if (it->made_of(PAPER)) { destroyed = it->burn(cur->density * 3); consumed++; if (cur->density == 1) cur->age -= vol * 10; if (vol >= 4) smoke++; } else if ((it->made_of(WOOD) || it->made_of(VEGGY))) { if (vol <= cur->density * 10 || cur->density == 3) { cur->age -= 4; destroyed = it->burn(cur->density); smoke++; consumed++; } else if (it->burnt < cur->density) { destroyed = it->burn(1); smoke++; } } else if ((it->made_of(COTTON) || it->made_of(WOOL))) { if (vol <= cur->density * 5 || cur->density == 3) { cur->age--; destroyed = it->burn(cur->density); smoke++; consumed++; } else if (it->burnt < cur->density) { destroyed = it->burn(1); smoke++; } } else if (it->made_of(FLESH)) { if (vol <= cur->density * 5 || (cur->density == 3 && one_in(vol / 20))) { cur->age--; destroyed = it->burn(cur->density); smoke += 3; consumed++; } else if (it->burnt < cur->density * 5 || cur->density >= 2) { destroyed = it->burn(1); smoke++; } } else if (it->made_of(LIQUID)) { switch (it->type->id) { // TODO: Make this be not a hack. case itm_whiskey: case itm_vodka: case itm_rum: case itm_tequila: cur->age -= 300; smoke += 6; break; default: cur->age += rng(80 * vol, 300 * vol); smoke++; } destroyed = true; consumed++; } else if (it->made_of(POWDER)) { cur->age -= vol; destroyed = true; smoke += 2; } else if (it->made_of(PLASTIC)) { smoke += 3; if (it->burnt <= cur->density * 2 || (cur->density == 3 && one_in(vol))) { destroyed = it->burn(cur->density); if (one_in(vol + it->burnt)) cur->age--; } } if (destroyed) { for (int m = 0; m < i_at(x, y)[i].contents.size(); m++) i_at(x, y).push_back( i_at(x, y)[i].contents[m] ); i_at(x, y).erase(i_at(x, y).begin() + i); i--; } } veh = &(veh_at(x, y, part)); if (veh->type != veh_null && (veh->parts[part].flags & VHP_FUEL_TANK) && veh->fuel_type == AT_GAS) { if (cur->density > 1 && one_in (8) && veh->fuel > 0) veh->explode (g, x, y); } // Consume the terrain we're on if (has_flag(explodes, x, y)) { ter(x, y) = ter_id(int(ter(x, y)) + 1); cur->age = 0; cur->density = 3; g->explosion(x, y, 40, 0, true); } else if (has_flag(inflammable, x, y) && one_in(32 - cur->density * 10)) { cur->age -= cur->density * cur->density * 40; smoke += 15; if (cur->density == 3) ter(x, y) = t_ash; } else if (has_flag(flammable, x, y) && one_in(32 - cur->density * 10)) { cur->age -= cur->density * cur->density * 40; smoke += 15; if (cur->density == 3) ter(x, y) = t_rubble; } else if (has_flag(meltable, x, y) && one_in(32 - cur->density * 10)) { cur->age -= cur->density * cur->density * 40; if (cur->density == 3) ter(x, y) = t_b_metal; } else if (terlist[ter(x, y)].flags & mfb(swimmable)) cur->age += 800; // Flames die quickly on water // If we consumed a lot, the flames grow higher while (cur->density < 3 && cur->age < 0) { cur->age += 300; cur->density++; } // If the flames are in a pit, it can't spread to non-pit bool in_pit = (ter(x, y) == t_pit); // If the flames are REALLY big, they contribute to adjacent flames if (cur->density == 3 && cur->age < 0) { // Randomly offset our x/y shifts by 0-2, to randomly pick a square to spread to int starti = rng(0, 2); int startj = rng(0, 2); for (int i = 0; i < 3 && cur->age < 0; i++) { for (int j = 0; j < 3 && cur->age < 0; j++) { int fx = x + ((i + starti) % 3) - 1, fy = y + ((j + startj) % 3) - 1; if (field_at(fx, fy).type == fd_fire && field_at(fx, fy).density < 3 && (!in_pit || ter(fx, fy) == t_pit)) { field_at(fx, fy).density++; field_at(fx, fy).age = 0; cur->age = 0; } } } } // Consume adjacent fuel / terrain to spread. // Randomly offset our x/y shifts by 0-2, to randomly pick a square to spread to int starti = rng(0, 2); int startj = rng(0, 2); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { int fx = x + ((i + starti) % 3) - 1, fy = y + ((j + startj) % 3) - 1; if (INBOUNDS(fx, fy)) { int spread_chance = 20 * (cur->density - 1) + 10 * smoke; if (has_flag(explodes, fx, fy) && one_in(8 - cur->density)) { ter(fx, fy) = ter_id(int(ter(fx, fy)) + 1); g->explosion(fx, fy, 40, 0, true); } else if ((i != 0 || j != 0) && rng(1, 100) < spread_chance && (!in_pit || ter(fx, fy) == t_pit) && ((cur->density == 3 && (has_flag(flammable, fx, fy) || one_in(20))) || flammable_items_at(fx, fy) || field_at(fx, fy).type == fd_web)) { if (field_at(fx, fy).type == fd_smoke || field_at(fx, fy).type == fd_web) field_at(fx, fy) = field(fd_fire, 1, 0); else add_field(g, fx, fy, fd_fire, 1); } else { bool nosmoke = true; for (int ii = -1; ii <= 1; ii++) { for (int jj = -1; jj <= 1; jj++) { if (field_at(x+ii, y+jj).type == fd_fire && field_at(x+ii, y+jj).density == 3) smoke++; else if (field_at(x+ii, y+jj).type == fd_smoke) nosmoke = false; } } // If we're not spreading, maybe we'll stick out some smoke, huh? if (move_cost(fx, fy) > 0 && (!one_in(smoke) || (nosmoke && one_in(40))) && rng(3, 35) < cur->density * 10 && cur->age < 1000) { smoke--; add_field(g, fx, fy, fd_smoke, rng(1, cur->density)); } } } } } } break; case fd_smoke: for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 50; if (one_in(2)) { std::vector <point> spread; for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if ((field_at(x+a, y+b).type == fd_smoke && field_at(x+a, y+b).density < 3 ) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; if (field_at(p.x, p.y).type == fd_smoke && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_smoke, 1)){ cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_tear_gas: // Reset nearby scents to zero for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 30; // One in three chance that it spreads (less than smoke!) if (one_in(3)) { std::vector <point> spread; // Pick all eligible points to spread to for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (((field_at(x+a, y+b).type == fd_smoke || field_at(x+a, y+b).type == fd_tear_gas) && field_at(x+a, y+b).density < 3 ) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } // Then, spread to a nearby point if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; // Nearby teargas grows thicker if (field_at(p.x, p.y).type == fd_tear_gas && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; // Nearby smoke is converted into teargas } else if (field_at(p.x, p.y).type == fd_smoke) { field_at(p.x, p.y).type = fd_tear_gas; // Or, just create a new field. } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_tear_gas, 1)) { cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_toxic_gas: // Reset nearby scents to zero for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 40; if (one_in(2)) { std::vector <point> spread; // Pick all eligible points to spread to for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (((field_at(x+a, y+b).type == fd_smoke || field_at(x+a, y+b).type == fd_tear_gas || field_at(x+a, y+b).type == fd_toxic_gas || field_at(x+a, y+b).type == fd_nuke_gas ) && field_at(x+a, y+b).density < 3 ) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } // Then, spread to a nearby point if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; // Nearby toxic gas grows thicker if (field_at(p.x, p.y).type == fd_toxic_gas && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; // Nearby smoke & teargas is converted into toxic gas } else if (field_at(p.x, p.y).type == fd_smoke || field_at(p.x, p.y).type == fd_tear_gas) { field_at(p.x, p.y).type = fd_toxic_gas; // Or, just create a new field. } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_toxic_gas, 1)) { cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_nuke_gas: // Reset nearby scents to zero for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 40; // Increase long-term radiation in the land underneath radiation(x, y) += rng(0, cur->density); if (one_in(2)) { std::vector <point> spread; // Pick all eligible points to spread to for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (((field_at(x+a, y+b).type == fd_smoke || field_at(x+a, y+b).type == fd_tear_gas || field_at(x+a, y+b).type == fd_toxic_gas || field_at(x+a, y+b).type == fd_nuke_gas ) && field_at(x+a, y+b).density < 3 ) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } // Then, spread to a nearby point if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; // Nearby nukegas grows thicker if (field_at(p.x, p.y).type == fd_nuke_gas && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; // Nearby smoke, tear, and toxic gas is converted into nukegas } else if (field_at(p.x, p.y).type == fd_smoke || field_at(p.x, p.y).type == fd_toxic_gas || field_at(p.x, p.y).type == fd_tear_gas) { field_at(p.x, p.y).type = fd_nuke_gas; // Or, just create a new field. } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_nuke_gas, 1)) { cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_gas_vent: for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { if (field_at(i, j).type == fd_toxic_gas && field_at(i, j).density < 3) field_at(i, j).density++; else add_field(g, i, j, fd_toxic_gas, 3); } } break; case fd_fire_vent: if (cur->density > 1) { if (one_in(3)) cur->density--; } else { cur->type = fd_flame_burst; cur->density = 3; } break; case fd_flame_burst: if (cur->density > 1) cur->density--; else { cur->type = fd_fire_vent; cur->density = 3; } break; case fd_electricity: if (!one_in(5)) { // 4 in 5 chance to spread std::vector<point> valid; if (move_cost(x, y) == 0 && cur->density > 1) { // We're grounded int tries = 0; while (tries < 10 && cur->age < 50) { int cx = x + rng(-1, 1), cy = y + rng(-1, 1); if (move_cost(cx, cy) != 0 && field_at(cx, cy).is_null()) { add_field(g, cx, cy, fd_electricity, 1); cur->density--; tries = 0; } else tries++; } } else { // We're not grounded; attempt to ground for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (move_cost(x + a, y + b) == 0 && // Grounded tiles first field_at(x + a, y + b).is_null()) valid.push_back(point(x + a, y + b)); } } if (valid.size() == 0) { // Spread to adjacent space, then int px = x + rng(-1, 1), py = y + rng(-1, 1); if (move_cost(px, py) > 0 && field_at(px, py).type == fd_electricity && field_at(px, py).density < 3) field_at(px, py).density++; else if (move_cost(px, py) > 0) add_field(g, px, py, fd_electricity, 1); cur->density--; } while (valid.size() > 0 && cur->density > 0) { int index = rng(0, valid.size() - 1); add_field(g, valid[index].x, valid[index].y, fd_electricity, 1); cur->density--; valid.erase(valid.begin() + index); } } } break; case fd_fatigue: if (cur->density < 3 && int(g->turn) % 3600 == 0 && one_in(10)) cur->density++; else if (cur->density == 3 && one_in(600)) { // Spawn nether creature! mon_id type = mon_id(rng(mon_flying_polyp, mon_blank)); monster creature(g->mtypes[type]); creature.spawn(x + rng(-3, 3), y + rng(-3, 3)); g->z.push_back(creature); } break; } cur->age++; if (fieldlist[cur->type].halflife > 0) { if (cur->age > 0 && dice(3, cur->age) > dice(3, fieldlist[cur->type].halflife)) { cur->age = 0; cur->density--; } if (cur->density <= 0) { // Totally dissapated. grid[gridn].field_count--; grid[gridn].fld[locx][locy] = field(); } } } } return found_field; }
void map::generate_lightmap() { memset(lm, 0, sizeof(lm)); memset(sm, 0, sizeof(sm)); /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce significant slowdown, so for stuff like fire and lava: * Step 1: Store the position and luminance in buffer via add_light_source, for efficient checking of neighbors. * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant directions * Step 3: Profit! */ memset(light_source_buffer, 0, sizeof(light_source_buffer)); const int dir_x[] = { 1, 0 , -1, 0 }; const int dir_y[] = { 0, 1 , 0, -1 }; const int dir_d[] = { 180, 270, 0, 90 }; const float held_luminance = g->u.active_light(); const float natural_light = g->natural_light_level(); if (natural_light > LIGHT_SOURCE_BRIGHT) { // Apply sunlight, first light source so just assign for(int sx = DAYLIGHT_LEVEL - (natural_light / 2); sx < LIGHTMAP_CACHE_X - (natural_light / 2); ++sx) { for(int sy = DAYLIGHT_LEVEL - (natural_light / 2); sy < LIGHTMAP_CACHE_Y - (natural_light / 2); ++sy) { // In bright light indoor light exists to some degree if (!is_outside(sx, sy)) { lm[sx][sy] = LIGHT_AMBIENT_LOW; } else if (g->u.posx == sx && g->u.posy == sy ) { //Only apply daylight on square where player is standing to avoid flooding // the lightmap when in less than total sunlight. lm[sx][sy] = natural_light; } } } } // Apply player light sources if (held_luminance > LIGHT_AMBIENT_LOW) { apply_light_source(g->u.posx, g->u.posy, held_luminance, trigdist); } for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { const ter_id terrain = ter(sx, sy); const std::vector<item> &items = i_at(sx, sy); field ¤t_field = field_at(sx, sy); // When underground natural_light is 0, if this changes we need to revisit // Only apply this whole thing if the player is inside, // buildings will be shadowed when outside looking in. if (natural_light > LIGHT_AMBIENT_LOW && !is_outside(g->u.posx, g->u.posy) ) { if (!is_outside(sx, sy)) { // Apply light sources for external/internal divide for(int i = 0; i < 4; ++i) { if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) && is_outside(sx + dir_x[i], sy + dir_y[i])) { lm[sx][sy] = natural_light; if (light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID) { apply_light_arc(sx, sy, dir_d[i], natural_light); } } } } } for( std::vector<item>::const_iterator itm = items.begin(); itm != items.end(); ++itm ) { float ilum = 0.0; // brightness int iwidth = 0; // 0-360 degrees. 0 is a circular light_source int idir = 0; // otherwise, it's a light_arc pointed in this direction if ( itm->getlight(ilum, iwidth, idir ) ) { if ( iwidth > 0 ) { apply_light_arc( sx, sy, idir, ilum, iwidth ); } else { add_light_source(sx, sy, ilum); } } } if(terrain == t_lava) { add_light_source(sx, sy, 50 ); } if(terrain == t_console) { add_light_source(sx, sy, 3 ); } if(terrain == t_emergency_light) { add_light_source(sx, sy, 3 ); } if(terrain == t_utility_light) { add_light_source(sx, sy, 35 ); } field_entry *cur = NULL; for(std::map<field_id, field_entry *>::iterator field_list_it = current_field.getFieldStart(); field_list_it != current_field.getFieldEnd(); ++field_list_it) { cur = field_list_it->second; if(cur == NULL) { continue; } // TODO: [lightmap] Attach light brightness to fields switch(cur->getFieldType()) { case fd_fire: if (3 == cur->getFieldDensity()) { add_light_source(sx, sy, 160); } else if (2 == cur->getFieldDensity()) { add_light_source(sx, sy, 60); } else { add_light_source(sx, sy, 16); } break; case fd_fire_vent: case fd_flame_burst: add_light_source(sx, sy, 8); break; case fd_electricity: case fd_plasma: if (3 == cur->getFieldDensity()) { add_light_source(sx, sy, 8); } else if (2 == cur->getFieldDensity()) { add_light_source(sx, sy, 1); } else { apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL, trigdist); // kinda a hack as the square will still get marked } break; case fd_incendiary: if (3 == cur->getFieldDensity()) { add_light_source(sx, sy, 30); } else if (2 == cur->getFieldDensity()) { add_light_source(sx, sy, 16); } else { add_light_source(sx, sy, 8); } break; case fd_laser: apply_light_source(sx, sy, 1, trigdist); break; case fd_spotlight: add_light_source(sx, sy, 20); break; case fd_dazzling: add_light_source(sx, sy, 2); break; default: //Suppress warnings break; } } } } for (size_t i = 0; i < g->num_zombies(); ++i) { int mx = g->zombie(i).posx(); int my = g->zombie(i).posy(); if (INBOUNDS(mx, my)) { if (g->zombie(i).has_effect("onfire")) { apply_light_source(mx, my, 3, trigdist); } // 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 if (g->zombie(i).type->luminance > 0) { apply_light_source(mx, my, g->zombie(i).type->luminance, trigdist); } } } // Apply any vehicle light sources VehicleList vehs = get_vehicles(); for( size_t v = 0; v < vehs.size(); ++v ) { if(vehs[v].v->lights_on) { int dir = vehs[v].v->face.dir(); float veh_luminance = 0.0; float iteration = 1.0; std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CONE_LIGHT); for (std::vector<int>::iterator part = light_indices.begin(); part != light_indices.end(); ++part) { veh_luminance += ( vehs[v].v->part_info(*part).bonus / iteration ); iteration = iteration * 1.1; } if (veh_luminance > LL_LIT) { for (std::vector<int>::iterator part = light_indices.begin(); part != light_indices.end(); ++part) { int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0]; int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0]; if(INBOUNDS(px, py)) { apply_light_arc(px, py, dir + vehs[v].v->parts[*part].direction, veh_luminance, 45); } } } } if(vehs[v].v->overhead_lights_on) { std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT); for (std::vector<int>::iterator part = light_indices.begin(); part != light_indices.end(); ++part) { if((calendar::turn % 2 && vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN)) || (!(calendar::turn % 2) && vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN)) || (!vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN) && !vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN))) { int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0]; int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0]; if(INBOUNDS(px, py)) { add_light_source( px, py, vehs[v].v->part_info(*part).bonus ); } } } } } /* Now that we have position and intensity of all bulk light sources, apply_ them This may seem like extra work, but take a 12x12 raging inferno: unbuffered: (12^2)*(160*4) = apply_light_ray x 92160 buffered: (12*4)*(160) = apply_light_ray x 7680 */ for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { if ( light_source_buffer[sx][sy] > 0. ) { apply_light_source(sx, sy, light_source_buffer[sx][sy], ( trigdist && light_source_buffer[sx][sy] > 3. ) ); } } } if (g->u.has_active_bionic("bio_night") ) { for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { if (rl_dist(sx, sy, g->u.posx, g->u.posy) < 15) { lm[sx][sy] = 0; } } } } }
void PDBLoopParser::parse_single_pdb_file(string pdb_filename) { // Open the file stream ifstream ifs; ifs.open(pdb_filename.c_str()); string line; // Since some of the PDB files may have multiple Structures inside (i.e. // two HUs) seperated by a TER line, need to return multiple Structures Structure *s = new Structure(pdb_filename); Chain *c = new Chain(); Residue *r = new Residue(); Atom *a = new Atom(); // Save the previous Residue and Chain PDB IDs to compare and decide whether // or not a new one needs to be made. int r_id_prev = 0; string c_id_prev = ""; bool make_new = false; string atom("ATOM"); string ter("TER"); while( getline(ifs, line) ) { if (line.empty()) continue; if (make_new) { s = new Structure(pdb_filename); make_new = false; } if (line.compare(0, atom.length(), atom) == 0) { // Information in PDB files follow strict column sizes. This may // not be very robust, but works fine with my PDB files. //int a_id = atoi(line.substr(6,5).c_str()); string a_name = line.substr(13,3); string r_name = boost::trim_copy(line.substr(17,3)); string c_id = line.substr(21,1); int r_id = atoi(line.substr(23,3).c_str()); double x = atof(line.substr(31,7).c_str()); double y = atof(line.substr(38,7).c_str()); double z = atof(line.substr(46,7).c_str()); // If an Entity has a different ID than the one before, if (c_id_prev.compare(c_id) != 0) { c = new Chain(c_id); // Create a new chain with new ID s->add_child(c); // Attach to parent Entity c_id_prev = c_id; // Keep track of new ID } if (r_id_prev != r_id) { r = new Residue(r_name, r_id); c->add_child(r); r_id_prev = r_id; } // Every line should contain a new atom, then attach it to a residue a = new Atom(a_name, x, y, z); r->add_child(a); } /* If a TER comes in the file, denoting multiple structures in the PDB, add the previously parsed structure to the vector which will be loaded into the loop, then start a new structure. If the TER is before the EOF, an empty Structure will be created TODO: Ensure that the empty structure does not get committed to DB */ else if (line.compare(0, ter.length(), ter) == 0) { if (DEBUG) { cout << "Pushing back " << *s << endl; } m_loop.add_child(s); make_new = true; } } // If no TER at the EOF, add the structure if ( (s->get_child_vector().size() != 0) && !make_new ) { if (DEBUG) {cout << "Pushing back " << *s << endl;} m_loop.add_child(s); } }
bool map::has_flag(t_flag flag, int x, int y) { if (!inbounds(x, y)) return (flag == diggable ? true : false); // For the sake of worms, etc. return terlist[ter(x, y)].flags & mfb(flag); }
bool map::process_fields(game *g) { bool found_field = false; field *cur; field_id curtype; for (int x = 0; x < SEEX * 3; x++) { for (int y = 0; y < SEEY * 3; y++) { cur = &field_at(x, y); curtype = cur->type; if (!found_field && curtype != fd_null) found_field = true; if (cur->density > 3) debugmsg("Whoooooa density of %d", cur->density); if (cur->age == 0) // Don't process "newborn" fields curtype = fd_null; switch (curtype) { case fd_null: break; // Do nothing, obviously. OBVIOUSLY. case fd_blood: case fd_bile: if (has_flag(swimmable, x, y)) // Dissipate faster in water cur->age += 250; break; case fd_acid: if (has_flag(swimmable, x, y)) // Dissipate faster in water cur->age += 20; for (int i = 0; i < i_at(x, y).size(); i++) { item *melting = &(i_at(x, y)[i]); if (melting->made_of(LIQUID) || melting->made_of(VEGGY) || melting->made_of(FLESH) || melting->made_of(POWDER) || melting->made_of(COTTON) || melting->made_of(WOOL) || melting->made_of(PAPER) || melting->made_of(PLASTIC) || (melting->made_of(GLASS) && !one_in(3)) || one_in(4)) { // Acid destructable objects here melting->damage++; if (melting->damage >= 5 || (melting->made_of(PAPER) && melting->damage >= 3)) { cur->age += melting->volume(); for (int m = 0; m < i_at(x, y)[i].contents.size(); m++) i_at(x, y).push_back( i_at(x, y)[i].contents[m] ); i_at(x, y).erase(i_at(x, y).begin() + i); i--; } } } break; case fd_fire: // Consume items as fuel to help us grow/last longer. bool destroyed; int vol; for (int i = 0; i < i_at(x, y).size(); i++) { destroyed = false; vol = i_at(x, y)[i].volume(); if (i_at(x, y)[i].is_ammo()) { cur->age /= 2; cur->age -= 300; destroyed = true; } else if (i_at(x, y)[i].made_of(PAPER)) { cur->age -= vol * 10; destroyed = true; } else if ((i_at(x, y)[i].made_of(WOOD) || i_at(x, y)[i].made_of(VEGGY)) && (vol <= cur->density*10-(cur->age>0 ? rng(0,cur->age/10) : 0) || cur->density == 3)) { cur->age -= vol * 10; destroyed = true; } else if ((i_at(x, y)[i].made_of(COTTON) || i_at(x, y)[i].made_of(FLESH)|| i_at(x, y)[i].made_of(WOOL)) && (vol <= cur->density*2 || (cur->density == 3 && one_in(vol)))) { cur->age -= vol * 5; destroyed = true; } else if (i_at(x, y)[i].made_of(LIQUID) || i_at(x, y)[i].made_of(POWDER)|| i_at(x, y)[i].made_of(PLASTIC)|| (cur->density >= 2 && i_at(x, y)[i].made_of(GLASS)) || (cur->density == 3 && i_at(x, y)[i].made_of(IRON))) { switch (i_at(x, y)[i].type->id) { // TODO: Make this be not a hack. case itm_whiskey: case itm_vodka: case itm_rum: case itm_tequila: cur->age -= 220; break; } destroyed = true; } if (destroyed) { for (int m = 0; m < i_at(x, y)[i].contents.size(); m++) i_at(x, y).push_back( i_at(x, y)[i].contents[m] ); i_at(x, y).erase(i_at(x, y).begin() + i); i--; } } // Consume the terrain we're on if (terlist[ter(x, y)].flags & mfb(flammable) && one_in(8 - cur->density)) { cur->age -= cur->density * cur->density * 40; if (cur->density == 3) ter(x, y) = t_rubble; } else if (terlist[ter(x, y)].flags & mfb(explodes)) { ter(x, y) = ter_id(int(ter(x, y)) + 1); cur->age = 0; cur->density = 3; g->explosion(x, y, 40, 0, true); } else if (terlist[ter(x, y)].flags & mfb(swimmable)) cur->age += 800; // Flames die quickly on water // If we consumed a lot, the flames grow higher while (cur->density < 3 && cur->age < 0) { cur->age += 300; cur->density++; } // If the flames are REALLY big, they contribute to adjacent flames if (cur->density == 3 && cur->age < 0) { // If the flames are in a pit, it can't spread to non-pit bool in_pit = (ter(x, y) == t_pit); // Randomly offset our x/y shifts by 0-2, to randomly pick a square to spread to int starti = rng(0, 2); int startj = rng(0, 2); for (int i = 0; i < 3 && cur->age < 0; i++) { for (int j = 0; j < 3 && cur->age < 0; j++) { if (field_at(x+((i+starti)%3), y+((j+startj)%3)).type == fd_fire && field_at(x+((i+starti)%3), y+((j+startj)%3)).density < 3 && (!in_pit || ter(x+((i+starti)%3), y+((j+startj)%3)) == t_pit)) { field_at(x+((i+starti)%3), y+((j+startj)%3)).density++; field_at(x+((i+starti)%3), y+((j+startj)%3)).age = 0; cur->age = 0; } } } } // Consume adjacent fuel / terrain to spread. for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (x+i >= 0 && y+j >= 0 && x+i < SEEX * 3 && y+j <= SEEY * 3) { if (has_flag(explodes, x + i, y + j) && one_in(8 - cur->density)) { ter(x + i, y + i) = ter_id(int(ter(x + i, y + i)) + 1); g->explosion(x+i, y+j, 40, 0, true); } else if ((i != 0 || j != 0) && (i_at(x+i, y+j).size() > 0 || rng(15, 120) < cur->density * 10)) { if (field_at(x+i, y+j).type == fd_smoke) field_at(x+i, y+j) = field(fd_fire, 1, 0); // Fire in pits can only spread to adjacent pits else if (ter(x, y) != t_pit || ter(x + i, y + j) == t_pit) add_field(g, x+i, y+j, fd_fire, 1); // If we're not spreading, maybe we'll stick out some smoke, huh? } else if (move_cost(x+i, y+j) > 0 && rng(7, 40) < cur->density * 10 && cur->age < 1000) { add_field(g, x+i, y+j, fd_smoke, rng(1, cur->density)); } } } } break; case fd_smoke: for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 50; if (one_in(2)) { std::vector <point> spread; for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if ((field_at(x+a, y+b).type == fd_smoke && field_at(x+a, y+b).density < 3) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; if (field_at(p.x, p.y).type == fd_smoke && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_smoke, 1)){ cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_tear_gas: // Reset nearby scents to zero for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 30; // One in three chance that it spreads (less than smoke!) if (one_in(3)) { std::vector <point> spread; // Pick all eligible points to spread to for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (((field_at(x+a, y+b).type == fd_smoke || field_at(x+a, y+b).type == fd_tear_gas) && field_at(x+a, y+b).density < 3 ) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } // Then, spread to a nearby point if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; // Nearby teargas grows thicker if (field_at(p.x, p.y).type == fd_tear_gas && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; // Nearby smoke is converted into teargas } else if (field_at(p.x, p.y).type == fd_smoke) { field_at(p.x, p.y).type = fd_tear_gas; // Or, just create a new field. } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_tear_gas, 1)) { cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_nuke_gas: // Reset nearby scents to zero for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) g->scent(x+i, y+j) = 0; } if (is_outside(x, y)) cur->age += 40; // Increase long-term radiation in the land underneath radiation(x, y) += rng(0, cur->density); if (one_in(2)) { std::vector <point> spread; // Pick all eligible points to spread to for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (((field_at(x+a, y+b).type == fd_smoke || field_at(x+a, y+b).type == fd_tear_gas || field_at(x+a, y+b).type == fd_nuke_gas ) && field_at(x+a, y+b).density < 3 ) || (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0)) spread.push_back(point(x+a, y+b)); } } // Then, spread to a nearby point if (cur->density > 0 && cur->age > 0 && spread.size() > 0) { point p = spread[rng(0, spread.size() - 1)]; // Nearby nukegas grows thicker if (field_at(p.x, p.y).type == fd_nuke_gas && field_at(p.x, p.y).density < 3) { field_at(p.x, p.y).density++; cur->density--; // Nearby smoke & teargas is converted into nukegas } else if (field_at(p.x, p.y).type == fd_smoke || field_at(p.x, p.y).type == fd_tear_gas) { field_at(p.x, p.y).type = fd_nuke_gas; // Or, just create a new field. } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 && add_field(g, p.x, p.y, fd_nuke_gas, 1)) { cur->density--; field_at(p.x, p.y).age = cur->age; } } } break; case fd_electricity: if (!one_in(5)) { // 4 in 5 chance to spread std::vector<point> valid; if (move_cost(x, y) == 0 && cur->density > 1) { // We're grounded int tries = 0; while (tries < 10 && cur->age < 50) { int cx = x + rng(-1, 1), cy = y + rng(-1, 1); if (move_cost(cx, cy) != 0 && field_at(cx, cy).is_null()) { add_field(g, cx, cy, fd_electricity, 1); cur->density--; tries = 0; } else tries++; } } else { // We're not grounded; attempt to ground for (int a = -1; a <= 1; a++) { for (int b = -1; b <= 1; b++) { if (move_cost(x + a, y + b) == 0 && // Grounded tiles first field_at(x + a, y + b).is_null()) valid.push_back(point(x + a, y + b)); } } if (valid.size() == 0) { // Spread to adjacent space, then int px = x + rng(-1, 1), py = y + rng(-1, 1); if (move_cost(px, py) > 0 && field_at(px, py).type == fd_electricity && field_at(px, py).density < 3) field_at(px, py).density++; else if (move_cost(px, py) > 0) add_field(g, px, py, fd_electricity, 1); cur->density--; } while (valid.size() > 0 && cur->density > 0) { int index = rng(0, valid.size() - 1); add_field(g, valid[index].x, valid[index].y, fd_electricity, 1); cur->density--; valid.erase(valid.begin() + index); } } } break; case fd_fatigue: if (cur->density < 3 && g->turn % 3600 == 0 && one_in(10)) cur->density++; else if (cur->density == 3 && one_in(3600)) { // Spawn nether creature! mon_id type = mon_id(rng(mon_flying_polyp, mon_blank)); monster creature(g->mtypes[type]); creature.spawn(x + rng(-3, 3), y + rng(-3, 3)); g->z.push_back(creature); } break; } if (fieldlist[cur->type].halflife > 0) { cur->age++; if (cur->age > 0 && dice(3, cur->age) > dice(3, fieldlist[cur->type].halflife)) { cur->age = 0; cur->density--; } if (cur->density <= 0) // Totally dissapated. field_at(x, y) = field(); } } } return found_field; }
bool map::bash(int x, int y, int str, std::string &sound) { sound = ""; for (int i = 0; i < i_at(x, y).size(); i++) { // Destroy glass items (maybe) if (i_at(x, y)[i].made_of(GLASS) && one_in(2)) { if (sound == "") sound = "A " + i_at(x, y)[i].tname() + " shatters! "; else sound = "Some items shatter! "; for (int j = 0; j < i_at(x, y)[i].contents.size(); j++) i_at(x, y).push_back(i_at(x, y)[i].contents[j]); i_rem(x, y, i); i--; } } switch (ter(x, y)) { case t_door_c: case t_door_locked: if (str >= rng(0, 40)) { sound += "smash!"; ter(x, y) = t_door_b; return true; } else { sound += "whump!"; return true; } break; case t_door_b: if (str >= rng(0, 30)) { sound += "crash!"; ter(x, y) = t_door_frame; int num_boards = rng(2, 6); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "wham!"; return true; } break; case t_window: if (str >= rng(0, 6)) { sound += "glass breaking!"; ter(x, y) = t_window_frame; return true; } else { sound += "whack!"; return true; } break; case t_door_boarded: if (str >= dice(3, 50)) { sound += "crash!"; ter(x, y) = t_door_frame; int num_boards = rng(0, 2); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "wham!"; return true; } break; case t_window_boarded: if (str >= dice(3, 30)) { sound += "crash!"; ter(x, y) = t_window_frame; int num_boards = rng(0, 2) * rng(0, 1); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "wham!"; return true; } break; case t_paper: if (str >= dice(2, 6)) { sound += "rrrrip!"; ter(x, y) = t_dirt; return true; } else { sound += "slap!"; return true; } break; case t_toilet: if (str >= dice(8, 10)) { sound += "porcelain breaking!"; ter(x, y) = t_rubble; return true; } else { sound += "whunk!"; return true; } break; case t_dresser: if (str >= dice(3, 45)) { sound += "smash!"; ter(x, y) = t_floor; int num_boards = rng(4, 12); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "whump."; return true; } break; case t_wall_glass_h: case t_wall_glass_v: if (str >= rng(0, 20)) { sound += "glass breaking!"; ter(x, y) = t_floor; return true; } else { sound += "whack!"; return true; } break; case t_reinforced_glass_h: case t_reinforced_glass_v: if (str >= rng(60, 100)) { sound += "glass breaking!"; ter(x, y) = t_floor; return true; } else { sound += "whack!"; return true; } break; case t_tree_young: if (str >= rng(0, 50)) { sound += "crunch!"; ter(x, y) = t_underbrush; int num_sticks = rng(0, 3); for (int i = 0; i < num_sticks; i++) add_item(x, y, (*itypes)[itm_stick], 0); return true; } else { sound += "whack!"; return true; } break; case t_underbrush: if (str >= rng(0, 30) && !one_in(4)) { sound += "crunch."; ter(x, y) = t_dirt; return true; } else { sound += "brush."; return true; } break; case t_marloss: if (str > rng(0, 40)) { sound += "crunch!"; ter(x, y) = t_fungus; return true; } else { sound += "whack!"; return true; } break; case t_vat: if (str >= dice(2, 20)) { sound += "ker-rash!"; ter(x, y) = t_floor; return true; } else { sound += "plunk."; return true; } } if (move_cost(x, y) == 0) { sound += "thump!"; return true; } return false; // If we kick empty space, the action is cancelled }
int map::move_cost(int x, int y) { if (!inbounds(x, y)) return 2; // Out of bounds terrain is assumed to be floor, mostly return terlist[ter(x, y)].movecost; }
void map::drawsq(WINDOW* w, player &u, int x, int y, bool invert, bool show_items) { if (!inbounds(x, y)) return; // Out of bounds int k = x + SEEX - u.posx; int j = y + SEEY - u.posy; nc_color tercol; char sym = terlist[ter(x, y)].sym; bool hi = false; if (u.has_disease(DI_BOOMERED)) tercol = c_magenta; else if ((u.is_wearing(itm_goggles_nv) && u.has_active_item(itm_UPS_on)) || u.has_active_bionic(bio_night_vision)) tercol = c_ltgreen; else tercol = terlist[ter(x, y)].color; if (move_cost(x, y) == 0 && has_flag(swimmable, x, y) && !u.underwater) show_items = false; // Can only see underwater items if WE are underwater // If there's a trap here, and we have sufficient perception, draw that instead if (tr_at(x, y) != tr_null && u.per_cur - u.encumb(bp_eyes) >= (*traps)[tr_at(x, y)]->visibility) { tercol = (*traps)[tr_at(x, y)]->color; if ((*traps)[tr_at(x, y)]->sym == '%') { switch(rng(1, 5)) { case 1: sym = '*'; break; case 2: sym = '0'; break; case 3: sym = '8'; break; case 4: sym = '&'; break; case 5: sym = '+'; break; } } else sym = (*traps)[tr_at(x, y)]->sym; } // If there's a field here, draw that instead (unless its symbol is %) if (field_at(x, y).type != fd_null) { tercol = fieldlist[field_at(x, y).type].color[field_at(x, y).density - 1]; if (fieldlist[field_at(x, y).type].sym == '*') { switch (rng(1, 5)) { case 1: sym = '*'; break; case 2: sym = '0'; break; case 3: sym = '8'; break; case 4: sym = '&'; break; case 5: sym = '+'; break; } } else if (fieldlist[field_at(x, y).type].sym != '%') sym = fieldlist[field_at(x, y).type].sym; } // If there's items here, draw those instead if (show_items && i_at(x, y).size() > 0 && field_at(x, y).is_null()) { if ((terlist[ter(x, y)].sym != '.')) hi = true; else { tercol = i_at(x, y)[i_at(x, y).size() - 1].color(); if (i_at(x, y).size() > 1) invert = !invert; sym = i_at(x, y)[i_at(x, y).size() - 1].symbol(); } } if (invert) mvwputch_inv(w, j, k, tercol, sym); else if (hi) mvwputch_hi (w, j, k, tercol, sym); else mvwputch (w, j, k, tercol, sym); }
std::string map::tername(int x, int y) { return terlist[ter(x, y)].name; }
bool InfoManager::Init() { TextFileEntityReader ter(Platform::JoinPath(Platform::JoinPath(g_Config.ResolveStaticDataPath(), "Data"), "Tips.txt" ), Case_None, Comment_Semi); ter.Start(); if (!ter.Exists()) return false; ter.Key("", "", true); ter.Index("ENTRY"); STRINGLIST sections = ter.Sections(); int i = 0; for (auto a = sections.begin(); a != sections.end(); ++a) { ter.PushSection(*a); Tip t; t.mID = ++i; if (!t.EntityKeys(&ter) || !t.ReadEntity(&ter)) return false; mTips.push_back(t); ter.PopSection(); } ter.End(); std::string filename = Platform::JoinPath(Platform::JoinPath(g_Config.ResolveStaticDataPath(), "Data"), "Game.txt" ); FileReader lfr; if (lfr.OpenText(filename.c_str()) != Err_OK) { g_Logs.data->error("Could not open configuration file: %v", filename); return false; } else { static char Delimiter[] = { '=', 13, 10 }; lfr.Delimiter = Delimiter; lfr.CommentStyle = Comment_Semi; while (lfr.FileOpen() == true) { int r = lfr.ReadLine(); if (r > 0) { lfr.SingleBreak("="); char *NameBlock = lfr.BlockToString(0); if (strcmp(NameBlock, "GameName") == 0) { mGameName = lfr.BlockToStringC(1, 0); } else if (strcmp(NameBlock, "Edition") == 0) { mEdition = lfr.BlockToStringC(1, 0); } else if (strcmp(NameBlock, "StartZone") == 0) { mStartZone = lfr.BlockToInt(1); } else if (strcmp(NameBlock, "StartX") == 0) { mStartX = lfr.BlockToInt(1); } else if (strcmp(NameBlock, "StartY") == 0) { mStartY = lfr.BlockToInt(1); } else if (strcmp(NameBlock, "StartZ") == 0) { mStartZ = lfr.BlockToInt(1); } else if (strcmp(NameBlock, "StartRotation") == 0) { mStartRotation = lfr.BlockToInt(1); } else { g_Logs.data->error("Unknown identifier [%v] in config file [%v]", lfr.BlockToString(0), filename); } } } lfr.CloseCurrent(); } return true; }
void map::shoot(game *g, int x, int y, int &dam, bool hit_items, unsigned flags) { if (flags & mfb(WF_AMMO_FLAME) && has_flag(flammable, x, y)) add_field(g, x, y, fd_fire, 2); switch (ter(x, y)) { case t_door_c: case t_door_locked: dam -= rng(15, 30); if (dam > 0) ter(x, y) = t_door_b; break; case t_door_b: if (hit_items || one_in(8)) { // 1 in 8 chance of hitting the door dam -= rng(10, 30); if (dam > 0) ter(x, y) = t_door_frame; } else dam -= rng(0, 1); break; case t_door_boarded: dam -= rng(15, 35); if (dam > 0) ter(x, y) = t_door_b; break; case t_window: dam -= rng(0, 5); if (dam > 0) ter(x, y) = t_window_frame; break; case t_window_boarded: dam -= rng(10, 30); if (dam > 0) ter(x, y) = t_window_frame; break; case t_wall_glass_h: case t_wall_glass_v: dam -= rng(0, 8); if (dam > 0) ter(x, y) = t_floor; break; case t_paper: dam -= rng(4, 16); if (dam > 0) ter(x, y) = t_dirt; if (flags & mfb(WF_AMMO_INCENDIARY)) add_field(g, x, y, fd_fire, 1); break; case t_gas_pump: if (hit_items || one_in(3)) { if (dam > 15) { if (flags & mfb(WF_AMMO_INCENDIARY) || flags & mfb(WF_AMMO_FLAME)) g->explosion(x, y, 40, 0, true); else { for (int i = x - 2; i <= x + 2; i++) { for (int j = y - 2; j <= y + 2; j++) { if (move_cost(i, j) > 0 && one_in(3)) add_item(i, j, g->itypes[itm_gasoline], 0); } } } ter(x, y) = t_gas_pump_smashed; } dam -= 60; } break; case t_vat: if (dam >= 10) { g->sound(x, y, 15, "ke-rash!"); ter(x, y) = t_floor; } else dam = 0; break; default: if (move_cost(x, y) == 0 && !trans(x, y)) dam = 0; // TODO: Bullets can go through some walls? else dam -= (rng(0, 1) * rng(0, 1) * rng(0, 1)); } // Now, destroy items on that tile. if ((move_cost(x, y) == 2 && !hit_items) || !inbounds(x, y)) return; // Items on floor-type spaces won't be shot up. bool destroyed; for (int i = 0; i < i_at(x, y).size(); i++) { destroyed = false; switch (i_at(x, y)[i].type->m1) { case GLASS: case PAPER: if (dam > rng(2, 8) && one_in(i_at(x, y)[i].volume())) destroyed = true; break; case PLASTIC: if (dam > rng(2, 10) && one_in(i_at(x, y)[i].volume() * 3)) destroyed = true; break; case VEGGY: case FLESH: if (dam > rng(10, 40)) destroyed = true; break; case COTTON: case WOOL: i_at(x, y)[i].damage++; if (i_at(x, y)[i].damage >= 5) destroyed = true; break; } if (destroyed) { for (int j = 0; j < i_at(x, y)[i].contents.size(); j++) i_at(x, y).push_back(i_at(x, y)[i].contents[j]); i_rem(x, y, i); i--; } } }