freg  0.3
Free-Roaming Elementary Game
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Shred.cpp
Go to the documentation of this file.
1  /* freg, Free-Roaming Elementary Game with open and interactive world
2  * Copyright (C) 2012-2014 Alexander 'mmaulwurff' Kromm
3  * mmaulwurff@gmail.com
4  *
5  * This file is part of FREG.
6  *
7  * FREG is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * FREG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with FREG. If not, see <http://www.gnu.org/licenses/>. */
19 
20 #include <QDataStream>
21 #include "Shred.h"
22 #include "World.h"
23 #include "BlockManager.h"
24 #include "blocks/Active.h"
25 #include "blocks/Inventory.h"
26 
27 const quint8 DATASTREAM_VERSION = QDataStream::Qt_5_2;
28 const quint8 CURRENT_SHRED_FORMAT_VERSION = 14;
29 
30 const int RAIN_IS_DEW = 1;
31 
32 QString Shred::ShredTypeName(const shred_type type) {
33  switch ( type ) {
34  case SHRED_PLAIN: /*--------*/ return QObject::tr("Plain");
35  case SHRED_TESTSHRED: /*----*/ return QObject::tr("Test shred");
36  case SHRED_PYRAMID: /*------*/ return QObject::tr("Pyramid");
37  case SHRED_HILL: /*---------*/ return QObject::tr("Hill");
38  case SHRED_DESERT: /*-------*/ return QObject::tr("Desert");
39  case SHRED_WATER: /*--------*/ return QObject::tr("Water");
40  case SHRED_FOREST: /*-------*/ return QObject::tr("Forest");
41  case SHRED_MOUNTAIN: /*-----*/ return QObject::tr("Mountain");
42  case SHRED_EMPTY: /*--------*/ return QObject::tr("Empty");
43  case SHRED_CHAOS: /*--------*/ return QObject::tr("Chaos");
44  case SHRED_CASTLE: /*-------*/ return QObject::tr("Castle");
45  case SHRED_WASTE: /*--------*/ return QObject::tr("Waste");
46  case SHRED_ACID_LAKE: /*----*/ return QObject::tr("Acid lake");
47  case SHRED_LAVA_LAKE: /*----*/ return QObject::tr("Lava lake");
48  case SHRED_CRATER: /*-------*/ return QObject::tr("Crater");
49  case SHRED_DEAD_FOREST: /*--*/ return QObject::tr("Dead forest");
50  case SHRED_DEAD_HILL: /*----*/ return QObject::tr("Dead hill");
51  case SHRED_NULLMOUNTAIN: /*-*/ return QObject::tr("Null mountain");
52  case SHRED_NORMAL_UNDERGROUND: return QObject::tr("Normal underground");
53  }
54  Q_UNREACHABLE();
55  return QString();
56 }
57 
58 
59 long Shred::Longitude() const { return longitude; }
60 long Shred::Latitude() const { return latitude; }
61 int Shred::ShredX() const { return shredX; }
62 int Shred::ShredY() const { return shredY; }
63 World * Shred::GetWorld() const { return world; }
64 Block * Shred::Normal(const int sub) { return block_manager.Normal(sub); }
66 
68  const QByteArray * const data =
70  if ( data == nullptr ) return false;
71  QDataStream in(*data);
72  quint8 read;
73  in >> read;
74  if ( Q_UNLIKELY(CURRENT_SHRED_FORMAT_VERSION != read) ) {
75  qDebug("%s: Shred format: %d (must be %d). Generating new shred.",
76  Q_FUNC_INFO, read, CURRENT_SHRED_FORMAT_VERSION);
77  return false;
78  } // else:
79  in.setVersion(DATASTREAM_VERSION);
80  in >> read;
81  type = static_cast<shred_type>(read);
82  in >> read;
83  weather = static_cast<weathers>(read);
84  Block * const null_stone = block_manager.Normal(NULLSTONE);
85  Block * const air = block_manager.Normal(AIR);
87  for (int x=0; x<SHRED_WIDTH; ++x)
88  for (int y=0; y<SHRED_WIDTH; ++y) {
89  PutBlock(null_stone, x, y, 0);
90  for (int z=1; ; ++z) {
91  quint8 kind, sub;
92  if ( BlockManager::KindSubFromFile(in, &kind, &sub) ) { // normal
93  if ( sub==SKY || sub==STAR ) {
94  while (z < HEIGHT-1) {
95  PutBlock(air, x, y, z++);
96  }
97  PutBlock(Normal(sub), x, y, HEIGHT-1);
98  break;
99  } else {
100  PutBlock(Normal(sub), x, y, z);
101  }
102  } else {
103  Active * const active = (blocks[x][y][z] =
104  BlockManager::BlockFromFile(in, kind, sub))->ActiveBlock();
105  if ( active != nullptr ) {
106  active->SetXyz(x, y, z);
107  RegisterInit(active);
108  Falling * const falling = active->ShouldFall();
109  if ( falling != nullptr && falling->IsFalling() ) {
110  fallList.append(falling);
111  }
112  }
113  }
114  }
115  }
116  return true;
117 } // bool Shred::LoadShred()
118 
119 Shred::Shred(const int shred_x, const int shred_y,
120  const long longi, const long lati)
121  :
122  longitude(longi), latitude(lati),
123  shredX(shred_x), shredY(shred_y),
124  type(),
125  activeListAll(),
126  activeListFrequent(),
127  shiningList(),
128  fallList(),
129  weather(WEATHER_CLEAR)
130 {
131  if ( LoadShred() ) return; // successfull loading
132  // new shred generation:
133  Block * const null_stone = Normal(NULLSTONE);
134  Block * const air = Normal(AIR);
135  Block * const sky = Normal(SKY);
136  Block * const star = Normal(STAR);
138  for (int i=0; i<SHRED_WIDTH; ++i)
139  for (int j=0; j<SHRED_WIDTH; ++j) {
140  PutBlock(null_stone, i, j, 0);
141  for (int k=1; k<HEIGHT-1; ++k) {
142  PutBlock(air, i, j, k);
143  }
144  PutBlock(((qrand()%5) ? sky : star), i, j, HEIGHT-1);
145  }
146  switch ( type = static_cast<shred_type>
147  (GetWorld()->GetMap()->TypeOfShred(longi, lati)) )
148  {
149  case SHRED_WASTE: WasteShred(); break;
150  case SHRED_WATER: Water(); break;
151  case SHRED_PLAIN: Plain(); break;
152  case SHRED_MOUNTAIN: Mountain(); break;
153  case SHRED_DESERT: Desert(); break;
154  case SHRED_HILL: Hill(false); break;
155  case SHRED_DEAD_HILL: Hill(true); break;
156  case SHRED_FOREST: Forest(false); break;
157  case SHRED_DEAD_FOREST: Forest(true); break;
158  case SHRED_NULLMOUNTAIN: NullMountain(); break;
159  case SHRED_TESTSHRED: TestShred(); break;
160  case SHRED_PYRAMID: Pyramid(); break;
161  case SHRED_CASTLE: Castle(); break;
162  case SHRED_CHAOS: ChaosShred(); break;
163  case SHRED_EMPTY: break;
164  case SHRED_ACID_LAKE: Water(ACID ); break;
165  case SHRED_LAVA_LAKE: Water(STONE); break;
166  case SHRED_CRATER: Water(AIR); break;
168  }
169 } // Shred::Shred(int shred_x, shred_y, long longi, lati, Shred * mem)
170 
172  QByteArray * const shred_data = new QByteArray();
173  shred_data->reserve(30000);
174  QDataStream outstr(shred_data, QIODevice::WriteOnly);
176  outstr.setVersion(DATASTREAM_VERSION);
177  outstr << quint8(GetTypeOfShred()) << quint8(weather);
178  for (int x=0; x<SHRED_WIDTH; ++x)
179  for (int y=0; y<SHRED_WIDTH; ++y) {
180  int height = HEIGHT-2;
181  for ( ; blocks[x][y][height]->Sub()==AIR; --height);
182  for (int z=1; z <= height; ++z) {
183  Block * const block = blocks[x][y][z];
184  if ( block == Normal(block->Sub()) ) {
185  block->SaveNormalToFile(outstr);
186  } else {
187  block->SaveToFile(outstr);
188  delete block; // without unregistering.
189  }
190  }
191  blocks[x][y][HEIGHT-1]->SaveNormalToFile(outstr);
192  }
193  GetWorld()->SetShredData(shred_data, longitude, latitude);
194 }
195 
196 long Shred::GlobalX(const int x) const {
197  return (Latitude() - CoordOfShred(x))*SHRED_WIDTH + x;
198 }
199 
200 long Shred::GlobalY(const int y) const {
201  return (Longitude() - CoordOfShred(y))*SHRED_WIDTH + y;
202 }
203 
205  for (auto i = fallList.begin(); i != fallList.end(); ++i) {
206  if ( *i == nullptr ) {
207  continue;
208  } // else:
209  const int x_in = CoordInShred((*i)->X());
210  const int y_in = CoordInShred((*i)->Y());
211  Block * const floor_block = GetBlock(x_in, y_in, (*i)->Z()-1);
212  if ( (*i)->Weight() <= 0
213  || ( floor_block->PushResult(ANYWHERE) == ENVIRONMENT
214  && floor_block->Sub() != AIR ) )
215  {
216  (*i)->SetFalling(false);
217  *i = nullptr;
218  } else if ( not world->Move((*i)->X(), (*i)->Y(), (*i)->Z(), DOWN) ) {
219  (*i)->FallDamage();
220  *i = nullptr;
221  }
222  }
223  for (auto i = activeListFrequent.constBegin();
224  i != activeListFrequent.constEnd(); ++i)
225  {
226  if ( *i != nullptr ) {
227  (*i)->ActFrequent();
228  }
229  }
230 }
231 
233  for (auto i=activeListAll.constBegin(); i!=activeListAll.constEnd(); ++i) {
234  if ( *i != nullptr ) {
235  switch ( (*i)->ActInner() ) {
236  case INNER_ACTION_ONLY: break;
237  case INNER_ACTION_NONE: (*i)->ActRare(); break;
238  case INNER_ACTION_EXPLODE: break; /// \todo add explosion
239  case INNER_ACTION_MESSAGE: break;
240  }
241  }
242  }
243  activeListAll.removeAll(nullptr);
244  activeListFrequent.removeAll(nullptr);
245  fallList.removeAll(nullptr);
246 }
247 
248 void Shred::RegisterInit(Active * const active) {
249  active->SetShred(this);
250  activeListAll.append(active);
251  const int should_act = active->ShouldAct();
252  if ( should_act & FREQUENT_FIRST ) {
253  activeListFrequent.prepend(active);
254  } else if ( should_act & FREQUENT_SECOND ) {
255  activeListFrequent.append(active);
256  }
257  AddShining(active);
258 }
259 
260 void Shred::Register(Active * const active) {
261  RegisterInit(active);
262  AddFalling(active);
263 }
264 
265 void Shred::Unregister(Active * const active) {
266  *qFind(activeListAll.begin(), activeListAll.end(), active) = nullptr;
267  *qFind(activeListFrequent.begin(), activeListFrequent.end(), active) =
268  nullptr;
269  Falling * const falling = active->ShouldFall();
270  if ( falling != nullptr ) {
271  *qFind(fallList.begin(), fallList.end(), falling) = nullptr;
272  falling->SetFalling(false);
273  }
274  RemShining(active);
275 }
276 
277 void Shred::AddFalling(Block * const block) {
278  Falling * const falling = block->ShouldFall();
279  if ( falling != nullptr && not falling->IsFalling() ) {
280  falling->SetFalling(true);
281  fallList.append(falling);
282  }
283 }
284 
285 void Shred::AddShining(Active * const active) {
286  if ( active->LightRadius() != 0 ) {
287  shiningList.append(active);
288  }
289 }
290 
291 void Shred::RemShining(Active * const active) {shiningList.removeOne(active);}
292 
293 QLinkedList<Active * const>::const_iterator Shred::ShiningBegin() const {
294  return shiningList.constBegin();
295 }
296 
297 QLinkedList<Active * const>::const_iterator Shred::ShiningEnd() const {
298  return shiningList.constEnd();
299 }
300 
301 void Shred::ReloadTo(const dirs direction) {
302  switch ( direction ) {
303  case NORTH: ++shredY; break;
304  case SOUTH: --shredY; break;
305  case EAST: --shredX; break;
306  case WEST: ++shredX; break;
307  default: Q_UNREACHABLE(); break;
308  }
309 }
310 
311 void Shred::SetBlock(Block * block, const int x, const int y, const int z) {
312  Block * const to_delete = GetBlock(x, y, z);
313  if ( to_delete != block ) {
314  Active * const active = to_delete->ActiveBlock();
315  if ( active ) {
316  active->Unregister();
317  }
318  SetBlockNoCheck(block, x, y, z);
319  }
320 }
321 
322 void Shred::SetBlockNoCheck(Block * const block,
323  const int x, const int y, const int z)
324 {
325  Active * const active = ( blocks[x][y][z]=block )->ActiveBlock();
326  if ( active != nullptr ) {
327  active->SetXyz(x, y, z);
328  Register(active);
329  }
330 }
331 
332 void Shred::SetNewBlock(const int kind, const int sub,
333  const int x, const int y, const int z, const int dir)
334 {
335  Block * const block = BlockManager::NewBlock(kind, sub);
336  block->SetDir(dir);
337  SetBlock(block, x, y, z);
338 }
339 
340 QString Shred::FileName(const QString world_name,
341  const long longi, const long lati)
342 {
343  return QString("%1%2/%3-%4.fm").
344  arg(home_path).arg(world_name).arg(longi).arg(lati);
345 }
346 
347 // shred generators section
348 // these functions fill space between the lowest nullstone layer and sky.
349 // so use k from 1 to HEIGHT-2.
350 void Shred::CoverWith(const int kind, const int sub) {
351  for (int i=0; i<SHRED_WIDTH; ++i)
352  for (int j=0; j<SHRED_WIDTH; ++j) {
353  int k = HEIGHT-2;
354  for ( ; AIR==GetBlock(i, j, k)->Sub(); --k);
355  SetBlock(BlockManager::NewBlock(kind, sub), i, j, ++k);
356  }
357 }
358 
359 void Shred::RandomDrop(int num, const int kind, const int sub,
360  const bool on_water)
361 {
362  while ( num-- ) {
363  DropBlock(BlockManager::NewBlock(kind, sub), on_water);
364  }
365 }
366 
367 void Shred::DropBlock(Block * const block, const bool on_water) {
368  int y = qrand();
369  const int x = CoordInShred(y);
370  y = CoordInShred(unsigned(y) >> SHRED_WIDTH_SHIFT);
371  int z = HEIGHT-2;
372  for ( ; GetBlock(x, y, z)->Sub()==AIR; --z);
373  if( on_water || GetBlock(x, y, z)->Sub()!=WATER ) {
374  SetBlock(block, x, y, ++z);
375  }
376 }
377 
379  for (int i=0; i<SHRED_WIDTH; ++i)
380  for (int j=0; j<SHRED_WIDTH; ++j) {
381  int k = HEIGHT - 2;
382  for ( ; GetBlock(i, j, k)->Transparent(); --k);
383  if ( SOIL==GetBlock(i, j, k)->Sub()
384  && AIR==GetBlock(i, j, ++k)->Sub() )
385  {
387  }
388  }
389 }
390 
392  const int level = FlatUndeground()+1;
393  struct {
394  kinds kind;
395  subs sub;
396  } set[SHRED_WIDTH/2][SHRED_WIDTH] = {
397  { // rows
398  {CLOCK, IRON}, {CONTAINER, WOOD}, {FALLING, SAND},
399  {BLOCK, GLASS}, {BOX, DIFFERENT}, {PLATE, STONE},
401  {LADDER, STONE}, {DWARF, ADAMANTINE}, {BUSH, WOOD},
402  {WORKBENCH, IRON}, {DOOR, GLASS}, {WEAPON, IRON},
403  {BLOCK, SAND}
404  }, {
405  {BLOCK, WATER}, {FALLING, WATER}, {DOOR, STONE},
406  {BLOCK, CLAY}, {KIND_TEXT, PAPER}, {BELL, IRON},
407  {BUCKET, IRON}, {PICK, IRON}, {SHOVEL, IRON},
408  {HAMMER, IRON}, {AXE, IRON}, {FALLING, STONE},
409  {WEAPON, STONE}, {BLOCK, WOOD}, {KIND_TEXT, GLASS},
410  {BLOCK, COAL}
411  }, {
414  {CONTAINER, IRON}, {CONTAINER, WATER}, {WEAPON, SKY},
416  {BLOCK, ROSE}, {CONVERTER, STONE}, {TELEGRAPH, IRON},
417  {MEDKIT, IRON}
418  }, {
419  {ARMOUR, STEEL}, {HELMET, STEEL}, {BOOTS, STEEL},
420  }
421  };
422  for (int i=0; i<SHRED_WIDTH/2; ++i)
423  for (int j=0; j<SHRED_WIDTH ; ++j) {
424  if ( set[i][j].kind == 0 && set[i][j].sub == 0) continue;
425  SetNewBlock(set[i][j].kind, set[i][j].sub, j, i*2, level);
426  }
427 } // void Shred::TestShred()
428 
431  const int border_level = HEIGHT/2-2;
432  NormalCube(0,SHRED_WIDTH/2-1,1, SHRED_WIDTH,2,border_level, NULLSTONE);
433  NormalCube(SHRED_WIDTH/2-1,0,1, 2,SHRED_WIDTH,border_level, NULLSTONE);
434  Block * const null_stone = Normal(NULLSTONE);
435  for (int i=0; i<SHRED_WIDTH; ++i)
436  for (int j=0; j<SHRED_WIDTH; ++j) {
437  for (int k=border_level; k < HEIGHT-2; ++k) {
438  const int surface =
439  HEIGHT/2 * (pow(1./(i-7.5), 2) * pow(1./(j-7.5), 2)+1);
440  if ( HEIGHT/2+1 < surface && surface >= k ) {
441  PutBlock(null_stone, i, j, k);
442  }
443  }
444  }
445  const WorldMap * const map = GetWorld()->GetMap();
446  if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude-1, latitude) ) { //N
447  NormalCube(7,0,HEIGHT/2, 2,SHRED_WIDTH/2-1,HEIGHT/2-2, NULLSTONE);
448  }
449  if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude+1, latitude) ) { //S
450  NormalCube(7,SHRED_WIDTH/2+1,HEIGHT/2, 2,SHRED_WIDTH/2-1,HEIGHT/2-2,
451  NULLSTONE);
452  }
453  if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude, latitude+1) ) { //E
454  NormalCube(SHRED_WIDTH/2+1,7,HEIGHT/2, SHRED_WIDTH/2-1,2,HEIGHT/2-2,
455  NULLSTONE);
456  }
457  if ( SHRED_NULLMOUNTAIN == map->TypeOfShred(longitude, latitude-1) ) { //W
458  NormalCube(0,7,HEIGHT/2, SHRED_WIDTH/2-1,2,HEIGHT/2-2, NULLSTONE);
459  }
460 }
461 
463  const int level = qMin(FlatUndeground(), HEIGHT-1-16);
464  Block * const stone = Normal(STONE);
465  for (int z=level+1, dz=0; dz<SHRED_WIDTH/2; z+=2, ++dz) { // pyramid
466  for (int x=dz, y=dz; x<(SHRED_WIDTH - dz); ++x, ++y) {
467  blocks[x][dz][z] =
468  blocks[x][SHRED_WIDTH-1-dz][z ] =
469  blocks[x][ dz][z+1] =
470  blocks[x][SHRED_WIDTH-1-dz][z+1] =
471  blocks[dz][y][z] =
472  blocks[SHRED_WIDTH-1-dz][y][z ] =
473  blocks[ dz][y][z+1] =
474  blocks[SHRED_WIDTH-1-dz][y][z+1] = stone;
475  }
476  }
477  Block * const air = Normal(AIR);
478  PutBlock(air, SHRED_WIDTH/2, 0, level+1); // entrance
479  // room below
480  NormalCube(1, 1, HEIGHT/2-60, SHRED_WIDTH-2, SHRED_WIDTH-2, 8, AIR);
481  for (int z=HEIGHT/2-52; z<=level; ++z) { // horizontal tunnel
482  PutBlock(air, SHRED_WIDTH/2, SHRED_WIDTH/2, z);
483  }
485  Inventory * const inv =
486  GetBlock(SHRED_WIDTH-2,SHRED_WIDTH-2, level+1)->HasInventory();
487  inv->Get(Normal(GOLD));
489 }
490 
493  const int bottom_level = HEIGHT/2 - 1;
494  // basement
495  NormalCube(0,0,bottom_level-5, SHRED_WIDTH, SHRED_WIDTH, 9, IRON);
496  NormalCube(2,2,bottom_level-3, SHRED_WIDTH-4,SHRED_WIDTH-4,5, AIR );
497  // floors
498  int level = bottom_level;
499  for (int floors=CountShredTypeAround(SHRED_CASTLE); ; --floors) {
500  NormalCube(0,0,level, SHRED_WIDTH, SHRED_WIDTH, 6, STONE);
501  NormalCube(2,2,level+1, SHRED_WIDTH-4,SHRED_WIDTH-4,1, WOOD );
502  NormalCube(2,2,level+2, SHRED_WIDTH-4,SHRED_WIDTH-4,5, AIR );
503  // stairs down
504  NormalCube(4,2,level, 5,2,2, AIR);
505  for (int y=2; y<=3; ++y) {
506  for (int step=0; step<5; ++step) {
507  SetNewBlock(PLATE, STONE, 4+step, y, level-3+step);
508  }
509  }
510  if ( floors == 1 ) return; // roof
511  const WorldMap * const map = GetWorld()->GetMap();
512  if ( map->TypeOfShred(longitude-1, latitude) == SHRED_CASTLE
513  || level == bottom_level )
514  {// north pass
515  NormalCube(2,0,level+2, SHRED_WIDTH-4,2,4, AIR);
516  }
517  if ( map->TypeOfShred(longitude+1, latitude) == SHRED_CASTLE
518  || level == bottom_level )
519  { // south pass
520  NormalCube(2,SHRED_WIDTH-2,level+2, SHRED_WIDTH-4,2,4, AIR);
521  }
522  if ( map->TypeOfShred(longitude, latitude-1) == SHRED_CASTLE
523  || level == bottom_level )
524  { // west pass
525  NormalCube(0,2,level+2, 2,SHRED_WIDTH-4,4, AIR);
526  }
527  if ( map->TypeOfShred(longitude, latitude+1) == SHRED_CASTLE
528  || level == bottom_level )
529  { // east pass
530  NormalCube(SHRED_WIDTH-2,2,level+2, 2,SHRED_WIDTH-4,4, AIR);
531  }
532  if ( level == bottom_level + 5 ) {
533  LoadRoom(level + 2);
534  }
535  level += 5;
536  }
537 } // Shred::Castle()
538 
540  for (int i=0; i<SHRED_WIDTH; ++i)
541  for (int j=0; j<SHRED_WIDTH; ++j)
542  for (int k=1; k<HEIGHT/2; ++k) {
543  int kind = qrand() % LAST_KIND;
544  int sub = qrand() % LAST_SUB;
545  SetNewBlock(kind, sub, i, j, k);
546  }
547 }
548 
550  const int x_start, const int y_start, const int z_start,
551  const int x_size, const int y_size, const int z_size, const subs sub)
552 {
553  Block * const block = Normal(sub);
554  for (int x=x_start; x < x_start+x_size; ++x)
555  for (int y=y_start; y < y_start+y_size; ++y)
556  for (int z=z_start; z < z_start+z_size; ++z) {
557  if ( InBounds(x, y, z) ) {
558  PutBlock(block, x, y, z);
559  }
560  }
561 }
562 
563 bool Shred::Tree(const int x, const int y, const int z, const int height) {
564  if ( not InBounds(x+2, y+2, height+z) ) return false;
565  // check for room
566  for (int i=x; i<=x+2; ++i)
567  for (int j=y; j<=y+2; ++j)
568  for (int k=z; k<z+height; ++k) {
569  if ( AIR != GetBlock(i, j, k)->Sub() ) {
570  return false;
571  }
572  }
573  const int leaves_level = z+height/2;
574  Block * const leaves = Normal(GREENERY);
575  for (int i=x; i<=x+2; ++i)
576  for (int j=y; j<=y+2; ++j) {
577  for (int k=leaves_level; k<z+height; ++k ) {
578  PutBlock(leaves, i, j, k);
579  }
580  }
581  for (int k=qMax(z-1, 1); k < z+height-1; ++k) { // trunk
582  SetBlock(Normal(WOOD), x+1, y+1, k);
583  }
584  // branches
585  const int r = qrand();
586  if ( r & 0x1 ) SetNewBlock(BLOCK, WOOD, x, y+1, leaves_level, WEST);
587  if ( r & 0x2 ) SetNewBlock(BLOCK, WOOD, x+2, y+1, leaves_level, EAST);
588  if ( r & 0x4 ) SetNewBlock(BLOCK, WOOD, x+1, y, leaves_level, NORTH);
589  if ( r & 0x8 ) SetNewBlock(BLOCK, WOOD, x+1, y+2, leaves_level, SOUTH);
590  return true;
591 }
592 
593 int Shred::CountShredTypeAround(const int type) const {
594  int result = 0;
595  const WorldMap * const map = GetWorld()->GetMap();
596  for (long i=longitude-1; i<=longitude+1; ++i)
597  for (long j=latitude -1; j<=latitude +1; ++j) {
598  result += ( type == map->TypeOfShred(i, j) );
599  }
600  return result;
601 }
602 
603 bool Shred::InBounds(const int z) { return (0 <= z && z < HEIGHT-1 ); }
604 
605 bool Shred::InBounds(const int x, const int y) {
606  return (0 <= x && x < SHRED_WIDTH) && (0 <= y && y < SHRED_WIDTH);
607 }
608 
609 bool Shred::InBounds(const int x, const int y, const int z) {
610  return InBounds(x, y) && InBounds(z);
611 }
612 
613 void Shred::Dew(const int kind, const int sub) {
614  DropBlock(BlockManager::NewBlock(kind, sub), true);
615 }
616 
617 void Shred::Rain(const int kind, const int sub) {
618  if ( RAIN_IS_DEW == 1 ) { // RAIN_IS_DEW is defined in Freg.pro
619  Dew(kind, sub);
620  return;
621  } // else:
622  const int CLOUD_HEIGHT = HEIGHT*3/4;
623  int y = qrand();
624  const int x = CoordInShred(y);
625  y = CoordInShred(unsigned(y) >> SHRED_WIDTH_SHIFT);
626  const int to_replace_sub = GetBlock(x, y, CLOUD_HEIGHT)->Sub();
627  if ( to_replace_sub == AIR || to_replace_sub == SUB_CLOUD ) {
628  SetBlock(BlockManager::NewBlock(kind, sub), x, y, CLOUD_HEIGHT);
629  }
630 }
631 
632 void Shred::LoadRoom(const int level, const int index) {
633  QFile file(QString("%1%2.room").
634  arg(FileName(GetWorld()->WorldName(), longitude, latitude)).
635  arg((index >= 1 ) ?
636  QString("-%1").arg(index) : ""));
637  if ( not file.open(QIODevice::ReadOnly | QIODevice::Text) ) return;
638  for (int lines = 0; lines < SHRED_WIDTH; ++lines) {
639  char buffer[SHRED_WIDTH + 1] = {0};
640  file.readLine(buffer, sizeof(buffer));
641  for (unsigned i=0; i<sizeof(buffer); ++i) {
642  switch ( buffer[i] ) {
643  case '#':
644  PutBlock(block_manager.Normal(STONE), i, lines, level);
645  break;
646  case '+':
647  NormalCube(i, lines, level, 1, 1, qrand()%3+5, STONE);
648  break;
649  case '0':
650  NormalCube(i, lines, level, 1, 1, 6, NULLSTONE);
651  break;
652  case '|':
653  NormalCube(i, lines, level, 1, 1, 5, STONE);
654  break;
655  case '[': {
656  Block * const stone = block_manager.Normal(STONE);
657  PutBlock(stone, i, lines, level);
658  PutBlock(stone, i, lines, level+1);
659  PutBlock(stone, i, lines, level+3);
660  PutBlock(stone, i, lines, level+4);
661  } break;
662  case '=':
663  PutBlock(block_manager.Normal(WOOD), i, lines, level);
664  PutBlock(block_manager.Normal(STONE), i, lines, level+4);
665  break;
666  case '^':
667  for (int z=level; z<level+5; ++z) {
668  SetNewBlock(LADDER, WOOD, i, lines, z);
669  }
670  break;
671 
672  case '*': SetNewBlock(WORKBENCH, IRON, i, lines, level); break;
673  case '&': SetNewBlock(CONTAINER, WOOD, i, lines, level); break;
674  case 't': SetNewBlock(TELEGRAPH, IRON, i, lines, level); break;
675  case 'c': SetNewBlock(CLOCK, IRON, i, lines, level); break;
676  case 'V': SetNewBlock(CONVERTER, STONE, i,lines,level); break;
677  case 'b': SetNewBlock(BELL, IRON, i, lines, level); break;
678  case 'i': SetNewBlock(ILLUMINATOR, IRON, i,lines,level); break;
679  case '~': SetNewBlock(LIQUID, WATER, i, lines, level); break;
680  case 'M': SetNewBlock(MEDKIT, IRON, i, lines, level); break;
681  case 'R': SetNewBlock(RAIN_MACHINE,IRON, i,lines,level); break;
682  case 'F': SetNewBlock(FILTER, IRON, i, lines, level); break;
683 
684  case '.': // reserved for nothing
685  case 0:
686  case '\n':
687  default: break;
688  }
689  }
690  }
691 } // Shred::LoadRoom(const int level)
int ShredX() const
Definition: Shred.cpp:61
bool Move(int x, int y, int z, dirs dir)
Check and move.
Definition: World.cpp:375
void Plain()
const quint8 DATASTREAM_VERSION
Definition: Shred.cpp:27
void NullMountain()
Definition: Shred.cpp:429
int ShredY() const
Definition: Shred.cpp:62
20
Definition: header.h:135
static Block * Normal(int sub)
Puts block to coordinates, not activates it.
Definition: Shred.cpp:64
Shred(int shred_x, int shred_y, long longi, long lati)
Definition: Shred.cpp:119
QLinkedList< Active *const >::const_iterator ShiningEnd() const
Definition: Shred.cpp:297
void AddFalling(Block *)
Definition: Shred.cpp:277
void DropBlock(Block *bloc, bool on_water)
Definition: Shred.cpp:367
void NormalCube(int x_start, int y_start, int z_start, int x_size, int y_size, int z_size, subs)
Definition: Shred.cpp:549
void ReloadTo(dirs)
Definition: Shred.cpp:301
static int CoordInShred(const int x)
Get local coordinate.
Definition: Shred.h:100
void SaveNormalToFile(QDataStream &out) const
Definition: Block.cpp:324
void Hill(bool dead)
10
Definition: header.h:170
long GlobalX(int x) const
Make global coordinate from local (in loaded zone).
Definition: Shred.cpp:196
3
Definition: header.h:90
void SetDir(int dir)
Definition: Block.cpp:269
long Latitude() const
Returns x (column) shred coordinate on world map.
Definition: Shred.cpp:60
const QString home_path
Definition: main.cpp:50
32
Definition: header.h:147
void NormalUnderground(int depth=0, subs sub=SOIL)
void SetShredData(QByteArray *, long longi, long lati)
Definition: World.cpp:72
BlockManager block_manager
29
Definition: header.h:189
void PhysEventsFrequent()
Definition: Shred.cpp:204
const quint8 CURRENT_SHRED_FORMAT_VERSION
Definition: Shred.cpp:28
27
Definition: header.h:187
World * world
Definition: World.cpp:32
shred_type GetTypeOfShred() const
Definition: Shred.cpp:65
6
Definition: header.h:121
31
Definition: header.h:146
28
Definition: header.h:188
World provides global physics and shred connection.
Definition: World.h:52
QLinkedList< Active *const >::const_iterator ShiningBegin() const
Definition: Shred.cpp:293
void CoverWith(int kind, int sub)
Definition: Shred.cpp:350
void Water(subs sub=WATER)
QLinkedList< Active * > activeListFrequent
Definition: Shred.h:176
Block * Normal(int sub) const
Use this to receive a pointer to normal block.
void SetBlockNoCheck(Block *, int x, int y, int z)
Puts block to coordinates xyz and activates it.
Definition: Shred.cpp:322
void Mountain()
QLinkedList< Falling * > fallList
Definition: Shred.h:178
18
Definition: header.h:178
4
Definition: header.h:164
int Transparent() const
Definition: Block.h:143
~Shred()
Definition: Shred.cpp:171
21
Definition: header.h:181
static QString FileName(QString world_name, long longi, long lati)
Definition: Shred.cpp:340
29
Definition: header.h:144
2
Definition: header.h:89
virtual bool Get(Block *block, int start=0)
Returns true on success.
Definition: Inventory.cpp:78
void PhysEventsRare()
Definition: Shred.cpp:232
0
Definition: header.h:115
Nothing is made from LAST_SUB.
Definition: header.h:193
const long longitude
Definition: Shred.h:170
4
Definition: header.h:91
26
Definition: header.h:186
virtual Inventory * HasInventory()
Definition: Block.cpp:224
void PutBlock(Block *const block, const int x, int y, int z)
Definition: Shred.h:73
6
Definition: header.h:166
21
Definition: header.h:136
void SetBlock(Block *block, int x, int y, int z)
Removes last block at xyz, then SetBlock, then makes block normal.
Definition: Shred.cpp:311
void LoadRoom(int level, int index=0)
Definition: Shred.cpp:632
27
Definition: header.h:142
11
Definition: header.h:126
1
Definition: header.h:116
28
Definition: header.h:143
void RemShining(Active *)
Definition: Shred.cpp:291
void SetXyz(short x, short y, short z)
Definition: Xyz.cpp:32
const int HEIGHT
Definition: header.h:40
Block * blocks[SHRED_WIDTH][SHRED_WIDTH][HEIGHT]
Definition: Shred.h:168
7
Definition: header.h:122
weathers
Definition: Weather.h:25
12
Definition: header.h:127
9
Definition: header.h:124
virtual int LightRadius() const
Definition: Block.cpp:210
static bool InBounds(int x, int y, int z)
Lowest nullstone and sky are not in bounds.
Definition: Shred.cpp:609
virtual int ShouldAct() const
Definition: Active.cpp:29
9
Definition: header.h:169
11
Definition: header.h:171
shred_type type
Definition: Shred.h:172
3
Definition: header.h:163
20
Definition: header.h:180
Provides declaration for class Inventory for freg.
const long latitude
Definition: Shred.h:170
virtual Falling * ShouldFall()
Definition: Block.cpp:227
QLinkedList< Active *const > shiningList
Definition: Shred.h:177
int FlatUndeground(int depth=0)
void SetAllLightMapNull()
void Unregister(Active *)
Definition: Shred.cpp:265
shred_type
Definition: header.h:59
static QString ShredTypeName(shred_type)
Definition: Shred.cpp:32
26
Definition: header.h:141
14
Definition: header.h:129
2
Definition: header.h:162
kinds
Kinds of atom.
Definition: header.h:112
const WorldMap * GetMap() const
Definition: World.cpp:66
int Sub() const
Definition: Block.h:144
2
Definition: header.h:117
void Castle()
Definition: Shred.cpp:491
4
Definition: header.h:119
12
Definition: header.h:172
subs
Substance block is made from.
Definition: header.h:157
13
Definition: header.h:128
void RegisterInit(Active *)
Definition: Shred.cpp:248
19
Definition: header.h:179
void Rain(int kind, int sub)
Definition: Shred.cpp:617
static Block * NewBlock(int kind, int sub)
Use this to receive a pointer to new not-normal block.
const int RAIN_IS_DEW
Definition: Shred.cpp:30
void WasteShred()
Nothing is LAST_KIND.
Definition: header.h:150
19
Definition: header.h:134
World * GetWorld() const
Definition: Shred.cpp:63
22
Definition: header.h:137
long Longitude() const
Returns y (line) shred coordinate on world map.
Definition: Shred.cpp:59
Definition: Active.h:46
void ChaosShred()
For testing purposes.
Definition: Shred.cpp:539
23
Definition: header.h:183
13
Definition: header.h:173
char TypeOfShred(long longi, long lati) const
Definition: worldmap.cpp:63
24
Definition: header.h:184
1
Definition: header.h:88
weathers weather
Definition: Shred.h:180
int shredY
Definition: Shred.h:171
dirs
Definition: header.h:85
virtual Active * ActiveBlock()
Definition: Block.cpp:226
long GlobalY(int y) const
Definition: Shred.cpp:200
Provides block ability to contain other blocks inside.
Definition: Inventory.h:33
0
Definition: header.h:160
Block * GetBlock(const int x, const int y, const int z) const
Definition: Shred.h:61
void PlantGrass()
Definition: Shred.cpp:378
void Forest(bool dead)
int CountShredTypeAround(int type) const
Definition: Shred.cpp:593
bool Tree(int x, int y, int z, int height)
Block combinations section (trees, buildings, etc):
Definition: Shred.cpp:563
23
Definition: header.h:138
16
Definition: header.h:131
const int SHRED_WIDTH_SHIFT
Definition: header.h:39
void SaveToFile(QDataStream &out)
Definition: Block.cpp:309
17
Definition: header.h:132
10
Definition: header.h:125
int shredX
Definition: Shred.h:171
void SetFalling(bool set)
Definition: Active.cpp:291
static int CoordOfShred(const int x)
Get shred coordinate in loaded zone (from 0 to numShreds).
Definition: Shred.h:103
15
Definition: header.h:130
3
Definition: header.h:118
void AddShining(Active *)
Definition: Shred.cpp:285
5
Definition: header.h:120
void Unregister()
Definition: Active.cpp:79
void TestShred()
Definition: Shred.cpp:391
15
Definition: header.h:175
void Register(Active *)
Definition: Shred.cpp:260
void RandomDrop(int num, int kind, int sub, bool on_water=false)
Puts num things(kind-sub) in random places on shred surface.
Definition: Shred.cpp:359
const int SHRED_WIDTH
Definition: header.h:38
bool LoadShred()
Definition: Shred.cpp:67
static Block * BlockFromFile(QDataStream &, int kind, int sub)
Use this to load block from file.
Block without special physics and attributes.
Definition: Block.h:89
5
Definition: header.h:92
QLinkedList< Active * > activeListAll
Contains all active blocks.
Definition: Shred.h:175
30
Definition: header.h:145
8 (animal meat)
Definition: header.h:168
bool IsFalling() const
Definition: Active.cpp:260
void SetShred(Shred *)
Definition: Active.cpp:138
void Pyramid()
Definition: Shred.cpp:462
17
Definition: header.h:177
30
Definition: header.h:190
14
Definition: header.h:174
void Desert()
void SetNewBlock(int kind, int sub, int x, int y, int z, int dir=UP)
Definition: Shred.cpp:332
QByteArray * GetShredData(long longi, long lati) const
Definition: World.cpp:68
static bool KindSubFromFile(QDataStream &, quint8 *kind, quint8 *sub)
Returns true if block is normal.
void Dew(int kind, int sub)
Definition: Shred.cpp:613