void Shred::Pyramid() { const int level = qMin(FlatUndeground(), HEIGHT-1-16); Block * const stone = Normal(STONE); for (int z=level+1, dz=0; dz<SHRED_WIDTH/2; z+=2, ++dz) { // pyramid for (int x=dz, y=dz; x<(SHRED_WIDTH - dz); ++x, ++y) { blocks[x][dz][z] = blocks[x][SHRED_WIDTH-1-dz][z ] = blocks[x][ dz][z+1] = blocks[x][SHRED_WIDTH-1-dz][z+1] = blocks[dz][y][z] = blocks[SHRED_WIDTH-1-dz][y][z ] = blocks[ dz][y][z+1] = blocks[SHRED_WIDTH-1-dz][y][z+1] = stone; } } Block * const air = Normal(AIR); PutBlock(air, SHRED_WIDTH/2, 0, level+1); // entrance // room below NormalCube(1, 1, HEIGHT/2-60, SHRED_WIDTH-2, SHRED_WIDTH-2, 8, AIR); for (int z=HEIGHT/2-52; z<=level; ++z) { // horizontal tunnel PutBlock(air, SHRED_WIDTH/2, SHRED_WIDTH/2, z); } SetNewBlock(CONTAINER, STONE, SHRED_WIDTH-2, SHRED_WIDTH-2, level+1); Inventory * const inv = GetBlock(SHRED_WIDTH-2,SHRED_WIDTH-2, level+1)->HasInventory(); inv->Get(Normal(GOLD)); SetNewBlock(PREDATOR, A_MEAT, SHRED_WIDTH-3, SHRED_WIDTH-2, level+1); }
void World::NoCheckMove(const ushort x, const ushort y, const ushort z, const ushort newx, const ushort newy, const ushort newz, const quint8 dir) { Block * const block = GetBlock(x, y, z); Block * const block_to = GetBlock(newx, newy, newz); PutBlock(block_to, x, y, z); PutBlock(block, newx, newy, newz); if ( block_to->Transparent() != block->Transparent() ) { ReEnlighten(newx, newy, newz); ReEnlighten(x, y, z); } block_to->Move( Anti(dir) ); block->Move(dir); Shred * shred = GetShred(x, y); shred->AddFalling(Shred::CoordInShred(x), Shred::CoordInShred(y), z+1); shred->AddFalling(Shred::CoordInShred(x), Shred::CoordInShred(y), z); shred = GetShred(newx, newy); shred->AddFalling(Shred::CoordInShred(newx), Shred::CoordInShred(newy), newz+1); shred->AddFalling(Shred::CoordInShred(newx), Shred::CoordInShred(newy), newz); }
bool Shred::LoadShred() { const QByteArray * const data = GetWorld()->GetShredData(longitude, latitude); if ( data == nullptr ) return false; QDataStream in(*data); quint8 read; in >> read; if ( Q_UNLIKELY(CURRENT_SHRED_FORMAT_VERSION != read) ) { fprintf(stderr, "%s: Shred format: %d (must be %d). Generating new shred.\n", Q_FUNC_INFO, read, CURRENT_SHRED_FORMAT_VERSION); return false; } // else: in.setVersion(DATASTREAM_VERSION); in >> read; type = static_cast<shred_type>(read); in >> read; weather = static_cast<weathers>(read); Block * const null_stone = block_manager.Normal(NULLSTONE); Block * const air = block_manager.Normal(AIR); SetAllLightMapNull(); for (int x=0; x<SHRED_WIDTH; ++x) for (int y=0; y<SHRED_WIDTH; ++y) { PutBlock(null_stone, x, y, 0); for (int z=1; ; ++z) { quint8 kind, sub; if ( BlockManager::KindSubFromFile(in, &kind, &sub) ) { // normal if ( sub==SKY || sub==STAR ) { while (z < HEIGHT-1) { PutBlock(air, x, y, z++); } PutBlock(Normal(sub), x, y, HEIGHT-1); break; } else { PutBlock(Normal(sub), x, y, z); } } else { Active * const active = (blocks[x][y][z] = BlockManager::BlockFromFile(in, kind, sub))->ActiveBlock(); if ( active != nullptr ) { active->SetXyz(x, y, z); RegisterInit(active); Falling * const falling = active->ShouldFall(); if ( falling != nullptr && falling->IsFalling() ) { fallList.append(falling); } } } } } return true; } // bool Shred::LoadShred()
Shred::Shred(const int shred_x, const int shred_y, const long longi, const long lati) : longitude(longi), latitude(lati), shredX(shred_x), shredY(shred_y), type(), activeListAll(), activeListFrequent(), shiningList(), fallList(), weather(WEATHER_CLEAR) { if ( LoadShred() ) return; // successfull loading // new shred generation: Block * const null_stone = Normal(NULLSTONE); Block * const air = Normal(AIR); Block * const sky = Normal(SKY); Block * const star = Normal(STAR); SetAllLightMapNull(); for (int i=0; i<SHRED_WIDTH; ++i) for (int j=0; j<SHRED_WIDTH; ++j) { PutBlock(null_stone, i, j, 0); for (int k=1; k<HEIGHT-1; ++k) { PutBlock(air, i, j, k); } PutBlock(((qrand()%5) ? sky : star), i, j, HEIGHT-1); } switch ( type = static_cast<shred_type> (GetWorld()->GetMap()->TypeOfShred(longi, lati)) ) { case SHRED_WASTE: WasteShred(); break; case SHRED_WATER: Water(); break; case SHRED_PLAIN: Plain(); break; case SHRED_MOUNTAIN: Mountain(); break; case SHRED_DESERT: Desert(); break; case SHRED_HILL: Hill(false); break; case SHRED_DEAD_HILL: Hill(true); break; case SHRED_FOREST: Forest(false); break; case SHRED_DEAD_FOREST: Forest(true); break; case SHRED_NULLMOUNTAIN: NullMountain(); break; case SHRED_TESTSHRED: TestShred(); break; case SHRED_PYRAMID: Pyramid(); break; case SHRED_CASTLE: Castle(); break; case SHRED_CHAOS: ChaosShred(); break; case SHRED_EMPTY: break; case SHRED_ACID_LAKE: Water(ACID ); break; case SHRED_LAVA_LAKE: Water(STONE); break; case SHRED_CRATER: Water(AIR); break; case SHRED_NORMAL_UNDERGROUND: NormalUnderground(); break; } } // Shred::Shred(int shred_x, shred_y, long longi, lati, Shred * mem)
bool Shred::Tree(const int x, const int y, const int z, const int height) { if ( not InBounds(x+2, y+2, height+z) ) return false; // check for room for (int i=x; i<=x+2; ++i) for (int j=y; j<=y+2; ++j) for (int k=z; k<z+height; ++k) { if ( AIR != GetBlock(i, j, k)->Sub() ) { return false; } } const int leaves_level = z+height/2; Block * const leaves = Normal(GREENERY); for (int i=x; i<=x+2; ++i) for (int j=y; j<=y+2; ++j) { for (int k=leaves_level; k<z+height; ++k ) { PutBlock(leaves, i, j, k); } } for (int k=qMax(z-1, 1); k < z+height-1; ++k) { // trunk SetBlock(Normal(WOOD), x+1, y+1, k); } // branches const int r = qrand(); if ( r & 0x1 ) SetNewBlock(BLOCK, WOOD, x, y+1, leaves_level, WEST); if ( r & 0x2 ) SetNewBlock(BLOCK, WOOD, x+2, y+1, leaves_level, EAST); if ( r & 0x4 ) SetNewBlock(BLOCK, WOOD, x+1, y, leaves_level, NORTH); if ( r & 0x8 ) SetNewBlock(BLOCK, WOOD, x+1, y+2, leaves_level, SOUTH); return true; }
void Shred::NullMountain() { NormalUnderground(); const int border_level = HEIGHT/2-2; NormalCube(0,SHRED_WIDTH/2-1,1, SHRED_WIDTH,2,border_level, NULLSTONE); NormalCube(SHRED_WIDTH/2-1,0,1, 2,SHRED_WIDTH,border_level, NULLSTONE); Block * const null_stone = Normal(NULLSTONE); for (int i=0; i<SHRED_WIDTH; ++i) for (int j=0; j<SHRED_WIDTH; ++j) { for (int k=border_level; k < HEIGHT-2; ++k) { const int surface = HEIGHT/2 * (pow(1./(i-7.5), 2) * pow(1./(j-7.5), 2)+1); if ( HEIGHT/2+1 < surface && surface >= k ) { PutBlock(null_stone, i, j, k); } } } const WorldMap * const map = GetWorld()->GetMap(); if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude-1, latitude) ) { //N NormalCube(7,0,HEIGHT/2, 2,SHRED_WIDTH/2-1,HEIGHT/2-2, NULLSTONE); } if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude+1, latitude) ) { //S NormalCube(7,SHRED_WIDTH/2+1,HEIGHT/2, 2,SHRED_WIDTH/2-1,HEIGHT/2-2, NULLSTONE); } if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude, latitude+1) ) { //E NormalCube(SHRED_WIDTH/2+1,7,HEIGHT/2, SHRED_WIDTH/2-1,2,HEIGHT/2-2, NULLSTONE); } if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude, latitude-1) ) { //W NormalCube(0,7,HEIGHT/2, SHRED_WIDTH/2-1,2,HEIGHT/2-2, NULLSTONE); } }
/*left,top:方块的左上角坐标,x,y:特殊方块的坐标 size:当前的子棋盘大小*/ void ChessBoard(int left,int top,int x,int y,int size) { int i,t,s,pos;/*t是方块的编号,s是棋盘的一半尺寸!(size/2),pos表示方块位于哪一角 */ if(size==1) return; t=tile++;/*当前L行方块的编号!递增*/ s=size/2; /*------------处理左上角----------*/ if(x<left+s && y<top+s) { ChessBoard(left,top,x,y,s);/*设置位于左上角的标识*/ pos=1; } else { Board[left+s-1][top+s-1]=t; /*不在左上角*/ ChessBoard(left,top,left+s-1,top+s-1,s); } /*------------处理右上角----------*/ if(x>=left+s && y<top+s) { ChessBoard(left+s,top,x,y,s); pos=2; } else { Board[left+s][top+s-1]=t;/*不在右上角*/ ChessBoard(left+s,top,left+s,top+s-1,s); } /*------------处理左下角----------*/ if(x<left+s && y>=top+s) { ChessBoard(left,top+s,x,y,s); pos=3; } else { Board[left+s-1][top+s]=t; ChessBoard(left,top+s,left+s-1,top+s-1,s); } /*------------处理右下角----------*/ if(x>=left+s && y>=top+s) { ChessBoard(left+s,top+s,x,y,s); pos=4; } else { Board[left+s][top+s]=t; ChessBoard(left+s,top+s,left+s,top+s,s); } /*画出当前的L方块*/ PutBlock(left+s,top+s,pos); }
void Shred::NormalCube( const int x_start, const int y_start, const int z_start, const int x_size, const int y_size, const int z_size, const subs sub) { Block * const block = Normal(sub); for (int x=x_start; x < x_start+x_size; ++x) for (int y=y_start; y < y_start+y_size; ++y) for (int z=z_start; z < z_start+z_size; ++z) { if ( InBounds(x, y, z) ) { PutBlock(block, x, y, z); } } }
bool World::CanMove(const ushort x, const ushort y, const ushort z, const ushort newx, const ushort newy, const ushort newz, const quint8 dir) { if ( !InBounds(x, y, z) ) { return false; } Block * const block = GetBlock(x, y, z); if ( NOT_MOVABLE == block->Movable() ) { return false; } Block * block_to = GetBlock(newx, newy, newz); if ( ENVIRONMENT == block->Movable() ) { if ( *block == *block_to ) { return false; } else if ( MOVABLE == block_to->Movable() ) { NoCheckMove(x, y, z, newx, newy, newz, dir); return true; } } switch ( block_to->BeforePush(dir, block) ) { case MOVE_SELF: block_to = GetBlock(newx, newy, newz); break; case DESTROY: DeleteBlock(block_to); PutBlock(Normal(AIR), newx, newy, newz); return true; break; case JUMP: if ( DOWN!=dir && UP!=dir ) { Jump(x, y, z, dir); return false; } break; case MOVE_UP: if ( DOWN!=dir && UP!=dir ) { Move(x, y, z, UP); return false; } break; case DAMAGE: Damage(x, y, z, block_to->DamageLevel(), block_to->DamageKind()); return false; break; } return ( ENVIRONMENT==block_to->Movable() );/* || ( (block->Weight() > block_to->Weight()) && Move(newx, newy, newz, dir) ) );*/ } // bool World::CanMove(ushort x, y, z, newx, newy, newz, quint8 dir)
void World::DestroyAndReplace(const ushort x, const ushort y, const ushort z) { Block * const temp = GetBlock(x, y, z); if ( temp->Durability() > 0 ) { return; } Block * const dropped = temp->DropAfterDamage(); Shred * const shred = GetShred(x, y); const ushort x_in_shred = Shred::CoordInShred(x); const ushort y_in_shred = Shred::CoordInShred(y); if ( PILE!=temp->Kind() && (temp->HasInventory() || dropped) ) { Block * const new_pile=( ( dropped && PILE==dropped->Kind() ) ? dropped : NewBlock(PILE, DIFFERENT) ); shred->SetBlock(new_pile, x_in_shred, y_in_shred, z); Inventory * const inv = temp->HasInventory(); Inventory * const new_pile_inv = new_pile->HasInventory(); if ( inv ) { new_pile_inv->GetAll(inv); } if ( dropped && PILE!=dropped->Kind() && !new_pile_inv->Get(dropped) ) { DeleteBlock(dropped); } shred->AddFalling(x_in_shred, y_in_shred, z); } else { PutBlock(Normal(AIR), x, y, z); } const int old_transparency = temp->Transparent(); const uchar old_light = temp->LightRadius(); DeleteBlock(temp); shred->AddFalling(x_in_shred, y_in_shred, z+1); if ( old_transparency != INVISIBLE ) { ReEnlightenBlockRemove(x, y, z); } if ( old_light ) { RemoveFireLight(x, y, z); } } // void World::DestroyAndReplace(ushort x, y, z)
void World::PhysEvents() { const QWriteLocker writeLock(rwLock); switch ( toResetDir ) { case UP: break; // no reset case DOWN: // full reset emit StartReloadAll(); DeleteAllShreds(); longitude = newLongi; latitude = newLati; LoadAllShreds(); emit NeedPlayer(newX, newY, newZ); emit UpdatedAll(); emit FinishReloadAll(); toResetDir = UP; // set no reset break; default: ReloadShreds(toResetDir); toResetDir = UP; // set no reset } static const ushort start = numShreds/2-numActiveShreds/2; static const ushort end = start+numActiveShreds; for (ushort i=start; i<end; ++i) for (ushort j=start; j<end; ++j) { shreds[i+j*NumShreds()]->PhysEventsFrequent(); } if ( TimeStepsInSec() > timeStep ) { ++timeStep; for (ushort i=start; i<end; ++i) for (ushort j=start; j<end; ++j) { shreds[i+j*NumShreds()]->DeleteDestroyedActives(); } return; } // else: for (ushort i=start; i<end; ++i) for (ushort j=start; j<end; ++j) { shreds[i+j*NumShreds()]->PhysEventsRare(); } for (ushort i=start; i<end; ++i) for (ushort j=start; j<end; ++j) { shreds[i+j*NumShreds()]->DeleteDestroyedActives(); } timeStep = 0; ++time; // sun/moon moving if ( sun_moon_x != SunMoonX() ) { const ushort y = SHRED_WIDTH*numShreds/2; PutBlock(Normal(ifStar ? STAR : SKY), sun_moon_x, y, HEIGHT-1); emit Updated(sun_moon_x, y, HEIGHT-1); sun_moon_x = SunMoonX(); ifStar = ( STAR==Sub(sun_moon_x, y, HEIGHT-1) ); PutBlock(Normal(SUN_MOON), sun_moon_x, y, HEIGHT-1); emit Updated(sun_moon_x, y, HEIGHT-1); } switch ( TimeOfDay() ) { case END_OF_NIGHT: ReEnlightenTime(); emit Notify(tr("It's morning now.")); break; case END_OF_MORNING: emit Notify(tr("It's day now.")); break; case END_OF_NOON: emit Notify(tr("It's evening now.")); break; case END_OF_EVENING: ReEnlightenTime(); emit Notify(tr("It's night now.")); break; } emit UpdatesEnded(); // emit ExitReceived(); // close all after 1 turn } // void World::PhysEvents()
void World::MakeSun() { ifStar = ( STAR==Sub( (sun_moon_x=SunMoonX()), SHRED_WIDTH*numShreds/2, HEIGHT-1) ); PutBlock(Normal(SUN_MOON), sun_moon_x, SHRED_WIDTH*numShreds/2, HEIGHT-1); }