freg  0.3
Free-Roaming Elementary Game
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
World.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 <QDir>
21 #include <QMutexLocker>
22 #include <QTimer>
23 #include "blocks/Active.h"
24 #include "blocks/Inventory.h"
25 #include "Shred.h"
26 #include "World.h"
27 #include "BlockManager.h"
28 #include "ShredStorage.h"
29 
30 const int MIN_WORLD_SIZE = 5;
31 
33 
34 bool World::ShredInCentralZone(const long longi, const long lati) const {
35  return ( qAbs(longi - longitude) <= 1 ) && ( qAbs(lati - latitude) <= 1 );
36 }
37 
38 int World::ShredPos(const int x, const int y) const { return y*NumShreds()+x; }
39 
40 Shred * World::GetShred(const int x, const int y) const {
42 }
43 
44 Shred * World::GetShredByPos(const int x, const int y) const {
45  return shreds[ShredPos(x, y)];
46 }
47 
48 Shred * World::GetNearShred(Shred * const shred, const dirs dir) const {
49  switch ( dir ) {
50  case NORTH: return GetShredByPos(shred->ShredX(), shred->ShredY()-1);
51  case SOUTH: return GetShredByPos(shred->ShredX(), shred->ShredY()+1);
52  case EAST: return GetShredByPos(shred->ShredX()+1, shred->ShredY());
53  case WEST: return GetShredByPos(shred->ShredX()-1, shred->ShredY());
54  default: Q_UNREACHABLE(); break;
55  }
56 }
57 
58 int World::NumShreds() const { return numShreds; }
59 int World::TimeOfDay() const { return time % SECONDS_IN_DAY; }
60 int World::MiniTime() const { return timeStep; }
61 ulong World::Time() const { return time; }
62 long World::Longitude() const { return longitude; }
63 long World::Latitude() const { return latitude; }
64 bool World::GetEvernight() const { return evernight; }
65 QString World::WorldName() const { return worldName; }
66 const WorldMap * World::GetMap() const { return &map; }
67 
68 QByteArray * World::GetShredData(long longi, long lati) const {
69  return shredStorage->GetShredData(longi, lati);
70 }
71 
72 void World::SetShredData(QByteArray * const data,
73  const long longi, const long lati)
74 {
75  shredStorage->SetShredData(data, longi, lati);
76 }
77 
79  return static_cast<times_of_day>(TimeOfDay() / SECONDS_IN_NIGHT);
80 }
81 
82 QString World::TimeOfDayStr() const {
83  return tr("Time is %1:%2.").
84  arg(TimeOfDay()/60).
85  arg(TimeOfDay()%60, 2, 10, QChar('0'));
86 }
87 
88 bool World::Drop(Block * const block_from,
89  const int x_to, const int y_to, const int z_to,
90  const int src, const int dest, const int num)
91 {
92  Block * const block_to = BlockManager::NewBlock(BOX, DIFFERENT);
93  if ( not Build(block_to, x_to, y_to, z_to) ) {
94  delete block_to;
95  }
96  return Exchange(block_from, GetBlock(x_to, y_to, z_to), src, dest, num);
97 }
98 
99 bool World::Get(Block * const block_to,
100  const int x_from, const int y_from, const int z_from,
101  const int src, const int dest, const int num)
102 {
103  Block * const block_from = GetBlock(x_from, y_from, z_from);
104  Inventory * const inv_from = block_from->HasInventory();
105  if ( inv_from ) {
106  if ( inv_from->Access() ) {
107  return Exchange(block_from, block_to, src, dest, num);
108  }
109  } else if ( Exchange(block_from, block_to, src, dest, num) ) {
110  Build(block_manager.Normal(AIR), x_from, y_from, z_from, UP,
111  nullptr, true);
112  return true;
113  }
114  return false;
115 }
116 
117 bool World::InBounds(const int x, const int y) const {
118  static const int max_xy = GetBound();
119  return ( (0 <= x && x <= max_xy) && (0 <= y && y <= max_xy) );
120 }
121 
122 bool World::InBounds(const int x, const int y, const int z) const {
123  return ( InBounds(x, y) && InVertBounds(z) );
124 }
125 
126 int World::GetBound() const {
127  static const int bound = NumShreds() * SHRED_WIDTH - 1;
128  return bound;
129 }
130 
131 bool World::InVertBounds(const int z) { return ( 0 <= z && z < HEIGHT ); }
132 
133 int World::SetNote(const QString note) {
134  notes.append(note);
135  return notes.size();
136 }
137 
138 int World::ChangeNote(const QString note, const int noteId) {
139  if ( noteId > notes.size() ) {
140  return SetNote(note);
141  } else {
142  notes[noteId - 1] = note;
143  return noteId;
144  }
145 }
146 
147 QString World::GetNote(const int noteId) const { return notes.at(noteId-1); }
148 
149 void World::ReloadAllShreds(const long lati, const long longi,
150  const int new_x, const int new_y, const int new_z)
151 {
152  newLati = lati;
153  newLongi = longi;
154  newX = new_x;
155  newY = new_y;
156  newZ = new_z;
157  toResetDir = DOWN; // full reset
158 }
159 
160 QMutex * World::GetLock() { return &mutex; }
161 void World::Lock() { mutex.lock(); }
162 bool World::TryLock() { return mutex.tryLock(); }
163 void World::Unlock() { mutex.unlock(); }
164 
166  switch ( dir ) {
167  case UP:
168  case DOWN: return dir;
169  case NORTH: return EAST;
170  case SOUTH: return WEST;
171  case EAST: return SOUTH;
172  case WEST: return NORTH;
173  }
174  Q_UNREACHABLE();
175  return NORTH;
176 }
177 
179  switch ( dir ) {
180  case UP:
181  case DOWN: return dir;
182  case NORTH: return WEST;
183  case SOUTH: return EAST;
184  case EAST: return NORTH;
185  case WEST: return SOUTH;
186  }
187  Q_UNREACHABLE();
188  return NORTH;
189 }
190 
191 dirs World::Anti(const dirs dir) {
192  switch ( dir ) {
193  case UP: return DOWN;
194  case DOWN: return UP;
195  case NORTH: return SOUTH;
196  case SOUTH: return NORTH;
197  case EAST: return WEST;
198  case WEST: return EAST;
199  }
200  Q_UNREACHABLE();
201  return NORTH;
202 }
203 
204 Block * World::GetBlock(const int x, const int y, const int z) const {
205  return GetShred(x, y)->
207 }
208 
209 Shred ** World::FindShred(const int x, const int y) const {
210  return &shreds[ShredPos(x, y)];
211 }
212 
214  switch ( toResetDir ) {
215  case UP: return; // no reset
216  case DOWN: // full reset
217  emit StartReloadAll();
218  DeleteAllShreds();
220  latitude = newLati;
221  LoadAllShreds();
222  emit NeedPlayer(newX, newY, newZ);
223  emit UpdatedAll();
224  emit FinishReloadAll();
225  toResetDir = UP; // set no reset
226  return;
227  // while reloading, reuse memory places.
228  case NORTH:
229  emit StartMove(NORTH);
230  --longitude;
231  for (int x=0; x<NumShreds(); ++x) {
232  delete *FindShred(x, NumShreds()-1);
233  for (int y=NumShreds()-1; y>0; --y) {
234  ( *FindShred(x, y) = *FindShred(x, y-1) )->ReloadTo(NORTH);
235  }
236  *FindShred(x, 0) = new Shred(x, 0,
237  longitude - NumShreds()/2,
238  latitude - NumShreds()/2+x);
239  }
240  break;
241  case SOUTH:
242  emit StartMove(SOUTH);
243  ++longitude;
244  for (int x=0; x<NumShreds(); ++x) {
245  delete *FindShred(x, 0);
246  for (int y=0; y<NumShreds()-1; ++y) {
247  ( *FindShred(x, y) = *FindShred(x, y+1) )->ReloadTo(SOUTH);
248  }
249  *FindShred(x, NumShreds()-1) = new Shred(x, NumShreds()-1,
250  longitude + NumShreds()/2,
251  latitude - NumShreds()/2+x);
252  }
253  break;
254  case EAST:
255  emit StartMove(EAST);
256  ++latitude;
257  for (int y=0; y<NumShreds(); ++y) {
258  delete *FindShred(0, y);
259  for (int x=0; x<NumShreds()-1; ++x) {
260  ( *FindShred(x, y) = *FindShred(x+1, y) )->ReloadTo(EAST);
261  }
262  *FindShred(NumShreds()-1, y) = new Shred(NumShreds()-1, y,
263  longitude - NumShreds()/2+y,
264  latitude + NumShreds()/2);
265  }
266  break;
267  case WEST:
268  emit StartMove(WEST);
269  --latitude;
270  for (int y=0; y<NumShreds(); ++y) {
271  delete *FindShred(NumShreds()-1, y);
272  for (int x=NumShreds()-1; x>0; --x) {
273  ( *FindShred(x, y) = *FindShred(x-1, y) )->ReloadTo(WEST);
274  }
275  *FindShred(0, y) = new Shred(0, y,
276  longitude - NumShreds()/2+y,
277  latitude - NumShreds()/2);
278  }
279  break;
280  }
283  emit Moved(toResetDir);
284  toResetDir = UP; // set no reset
285 } // void World::ReloadShreds()
286 
287 void World::SetReloadShreds(const int direction) {
288  toResetDir = static_cast<dirs>(direction);
289 }
290 
291 void World::run() {
292  QTimer timer;
293  connect(&timer, SIGNAL(timeout()), SLOT(PhysEvents()));
294  timer.start(1000 / TIME_STEPS_IN_SEC);
295  exec();
296 }
297 
299  static const int start = NumShreds()/2 - numActiveShreds/2;
300  static const int end = start + numActiveShreds;
301  Lock();
302  for (int i=start; i<end; ++i)
303  for (int j=start; j<end; ++j) {
305  }
306  if ( TIME_STEPS_IN_SEC > timeStep ) {
307  ++timeStep;
308  } else {
309  for (int i=start; i<end; ++i)
310  for (int j=start; j<end; ++j) {
311  shreds[ShredPos(i, j)]->PhysEventsRare();
312  }
313  timeStep = 0;
314  ++time;
315  switch ( TimeOfDay() ) {
316  default: break;
317  case END_OF_NIGHT:
318  case END_OF_EVENING: ReEnlightenTime(); break;
319  }
320  }
321  ReloadShreds();
322  Unlock();
323  emit UpdatesEnded();
324 }
325 
327  int x_from, int y_from, int z_from,
328  int x, int y, int z)
329 const {
330  /// optimized DDA line with integers only.
331  unsigned max = Abs(Abs(x-=x_from) > Abs(y-=y_from) ? x : y);
332  if ( Abs(z-=z_from) > max) {
333  max = Abs(z);
334  }
335  x_from *= max;
336  y_from *= max;
337  z_from *= max;
338  for (int i=max-1; i-- > 0; ) {
339  if ( not (GetBlock(
340  static_cast<unsigned>(x_from+=x)/max,
341  static_cast<unsigned>(y_from+=y)/max,
342  static_cast<unsigned>(z_from+=z)/max )->Transparent()
343  && GetBlock(
344  static_cast<unsigned>(x_from+max-1)/max,
345  static_cast<unsigned>(y_from+max-1)/max,
346  static_cast<unsigned>(z_from+max-1)/max )->Transparent()) )
347  {
348  return false;
349  }
350  }
351  return true;
352 }
353 
355  const int x_from, const int y_from, const int z_from,
356  const int x_to, const int y_to, const int z_to)
357 const {
358  int temp;
359  return ( DirectlyVisible(x_from, y_from, z_from, x_to, y_to, z_to)
360  || (x_to != x_from &&
361  GetBlock(x_to+(temp=(x_to>x_from) ? (-1) : 1), y_to, z_to)->
362  Transparent()
363  && DirectlyVisible(x_from, y_from, z_from, x_to+temp, y_to, z_to))
364  || (y_to != y_from &&
365  GetBlock(x_to, y_to+(temp=(y_to>y_from) ? (-1) : 1), z_to)->
366  Transparent()
367  && DirectlyVisible(x_from, y_from, z_from, x_to, y_to+temp, z_to))
368  || (z_to != z_from &&
369  GetBlock(x_to, y_to, z_to+(temp=(z_to>z_from) ? (-1) : 1))->
370  Transparent()
371  && DirectlyVisible(x_from, y_from, z_from, x_to, y_to, z_to+temp))
372  );
373 }
374 
375 bool World::Move(const int x, const int y, const int z, const dirs dir) {
376  int newx, newy, newz;
377  if ( Focus(x, y, z, &newx, &newy, &newz, dir) ) {
378  switch ( CanMove(x, y, z, newx, newy, newz, dir) ) {
379  case CAN_MOVE_OK:
380  NoCheckMove(x, y, z, newx, newy, newz, dir);
381  return true;
382  case CAN_MOVE_CANNOT: return false;
383  case CAN_MOVE_DESTROYED: return true;
384  }
385  return true;
386  } else {
387  return false;
388  }
389 }
390 
391 can_move_results World::CanMove(const int x, const int y, const int z,
392  const int newx, const int newy, const int newz, const dirs dir)
393 {
394  Block * const block = GetBlock(x, y, z);
395  Block * block_to = GetBlock(newx, newy, newz);
396  Falling * const falling = block->ShouldFall();
397  if ( DOWN != dir
398  && block->Weight() != 0
399  && falling != nullptr
400  && falling->IsFalling()
401  && AIR == GetBlock(x, y, z-1)->Sub()
402  && AIR == GetBlock(newx, newy, newz-1)->Sub() )
403  { // prevent moving while falling
404  return CAN_MOVE_CANNOT;
405  }
406  switch ( block->PushResult(dir) ) {
407  case DAMAGE:
408  case MOVABLE:
409  if ( Damage(newx, newy, newz, 1, DAMAGE_PUSH_UP + dir) <= 0 ) {
410  DestroyAndReplace(newx, newy, newz);
411  }
412  block_to = GetBlock(newx, newy, newz);
413  break;
414  case ENVIRONMENT:
415  if ( *block != *block_to ) { // prevent useless flow
416  break;
417  } // no break;
418  default: return CAN_MOVE_CANNOT;
419  }
420  switch ( block_to->PushResult(dir) ) {
421  case MOVABLE:
422  return ( block->Weight() > block_to->Weight()
423  && Move(newx, newy, newz, dir) ) ?
425  case ENVIRONMENT: return CAN_MOVE_OK;
426  case NOT_MOVABLE: break;
427  case MOVE_UP:
428  if ( dir > DOWN ) { // not UP and not DOWN
429  Move(x, y, z, UP);
430  }
431  break;
432  case JUMP:
433  if ( dir > DOWN ) { // not UP and not DOWN
434  Jump(x, y, z, dir);
435  }
436  break;
437  case DAMAGE:
438  if ( Damage(x, y, z, block_to->DamageLevel(), block_to->DamageKind())
439  <= 0 )
440  {
441  DestroyAndReplace(x, y, z);
442  return CAN_MOVE_DESTROYED;
443  }
444  break;
445  }
446  return CAN_MOVE_CANNOT;
447 } // bool World::CanMove(const int x, y, z, newx, newy, newz, int dir)
448 
449 void World::NoCheckMove(const int x, const int y, const int z,
450  const int newx, const int newy, const int newz, const dirs dir)
451 {
452  Shred * const shred_from = GetShred( x, y);
453  Shred * const shred_to = GetShred(newx, newy);
454  const int x_in = Shred::CoordInShred(x);
455  const int y_in = Shred::CoordInShred(y);
456  const int newx_in = Shred::CoordInShred(newx);
457  const int newy_in = Shred::CoordInShred(newy);
458  Block * const block = shred_from->GetBlock( x_in, y_in, z);
459  Block * const block_to = shred_to ->GetBlock(newx_in, newy_in, newz);
460 
461  shred_from->PutBlock(block_to, x_in, y_in, z);
462  shred_to ->PutBlock(block, newx_in, newy_in, newz);
463 
464  if ( block_to->Transparent() != block->Transparent() ) {
465  ReEnlighten(newx, newy, newz);
466  ReEnlighten(x, y, z);
467  }
468 
469  block->Move(dir);
470  emit Updated(newx, newy, newz);
471 
472  shred_from->AddFalling(shred_from->GetBlock( x_in, y_in, z+1));
473  shred_to ->AddFalling(shred_to ->GetBlock(newx_in, newy_in, newz+1));
474  shred_to ->AddFalling(block);
475 
476  if ( block_to->Sub() != AIR ) {
477  emit Updated(x, y, z);
478  block_to->Move(Anti(dir));
479  shred_from->AddFalling(block_to);
480  }
481 }
482 
483 void World::Jump(const int x, const int y, const int z, const dirs dir) {
484  if ( not (AIR == GetBlock(x, y, z-1)->Sub() && GetBlock(x, y, z)->Weight())
485  && Move(x, y, z, UP) )
486  {
487  Move(x, y, z+1, dir);
488  }
489 }
490 
491 bool World::Focus(const int x, const int y, const int z,
492  int * x_to, int * y_to, int * z_to, const dirs dir)
493 const {
494  *x_to = x;
495  *y_to = y;
496  *z_to = z;
497  switch ( dir ) {
498  case UP: ++*z_to; break;
499  case DOWN: --*z_to; break;
500  case NORTH: --*y_to; break;
501  case SOUTH: ++*y_to; break;
502  case EAST: ++*x_to; break;
503  case WEST: --*x_to; break;
504  }
505  return InBounds(*x_to, *y_to, *z_to);
506 }
507 
508 int World::Damage(const int x, const int y, const int z,
509  const int dmg, const int dmg_kind)
510 {
511  Shred * const shred = GetShred(x, y);
512  const int x_in = Shred::CoordInShred(x);
513  const int y_in = Shred::CoordInShred(y);
514  Block * temp = shred->GetBlock(x_in, y_in, z);
515  const int sub = temp->Sub();
516  if ( AIR == sub ) return 0;
517  if ( temp == block_manager.Normal(sub) ) {
518  temp = BlockManager::NewBlock(temp->Kind(), sub);
519  shred->SetBlockNoCheck(temp, x_in, y_in, z);
520  }
521  temp->Damage(dmg, dmg_kind);
522  return temp->GetDurability();
523 }
524 
525 void World::DestroyAndReplace(const int x, const int y, const int z) {
526  Shred * const shred = GetShred(x, y);
527  const int x_in_shred = Shred::CoordInShred(x);
528  const int y_in_shred = Shred::CoordInShred(y);
529  Block * const block = shred->GetBlock(x_in_shred, y_in_shred, z);
530  bool delete_block = true;
531  Block * const new_block = block->DropAfterDamage(&delete_block);
532  shred->SetBlockNoCheck(new_block, x_in_shred, y_in_shred, z);
533  if ( block->Transparent() != new_block->Transparent() ||
534  block->LightRadius() != new_block->LightRadius() )
535  {
536  ReEnlighten(x, y, z);
537  }
538  if ( delete_block ) {
539  block_manager.DeleteBlock(block);
540  } else {
541  Active * const active = block->ActiveBlock();
542  if ( active != nullptr ) {
543  active->Unregister();
544  }
545  }
546  shred->AddFalling(shred->GetBlock(x_in_shred, y_in_shred, z+1));
547  emit Updated(x, y, z);
548 }
549 
550 bool World::Build(Block * const block, const int x, const int y, const int z,
551  const int dir, Block * const who, const bool anyway)
552 {
553  Shred * const shred = GetShred(x, y);
554  const int x_in = Shred::CoordInShred(x);
555  const int y_in = Shred::CoordInShred(y);
556  Block * const target_block = shred->GetBlock(x_in, y_in, z);
557  if ( ENVIRONMENT!=target_block->PushResult(ANYWHERE) && not anyway ) {
558  if ( who != nullptr ) {
559  who->ReceiveSignal(tr("Cannot build here."));
560  }
561  return false;
562  } // else:
563  block->Restore();
564  block->SetDir(dir);
565  const int old_transparency = target_block->Transparent();
566  const int new_transparency = block->Transparent();
567  const int block_light = block->LightRadius();
568  shred->SetBlock(block, x_in, y_in, z);
569  if ( old_transparency != new_transparency ) {
570  ReEnlighten(x, y, z);
571  }
572  if ( block_light ) {
573  AddFireLight(x, y, z, block_light);
574  }
575  shred->AddFalling(shred->GetBlock(x_in, y_in, z+1));
576  return true;
577 }
578 
579 bool World::Inscribe(const int x, const int y, const int z) {
580  Shred * const shred = GetShred(x, y);
581  const int x_in = Shred::CoordInShred(x);
582  const int y_in = Shred::CoordInShred(y);
583  Block * block = shred->GetBlock(x_in, y_in, z);
584  if ( block == block_manager.Normal(block->Sub()) ) {
585  block = BlockManager::NewBlock(block->Kind(), block->Sub());
586  shred->SetBlockNoCheck(block, x_in, y_in, z);
587  }
588  QString str;
589  emit GetString(str);
590  return block->Inscribe(str);
591 }
592 
593 bool World::Exchange(Block * const block_from, Block * const block_to,
594  const int src, const int dest, const int num)
595 {
596  Inventory * const inv_to = block_to->HasInventory();
597  if ( not inv_to ) {
598  block_from->ReceiveSignal(tr("No room there."));
599  return false;
600  }
601  Inventory * const inv_from = block_from->HasInventory();
602  if ( not inv_from ) {
603  if ( block_from->Wearable() > WEARABLE_NOWHERE
604  && inv_to->Get(block_from, src) )
605  {
606  return true;
607  } else {
608  block_to->ReceiveSignal(tr("Nothing can be obtained."));
609  return false;
610  }
611  }
612  if ( src >= inv_from->Size() || inv_from->Number(src) == 0 ) {
613  block_from->ReceiveSignal(tr("Nothing here."));
614  block_to ->ReceiveSignal(tr("Nothing here."));
615  } else {
616  inv_from->Drop(src, dest, num, inv_to);
617  }
618  return false;
619 }
620 
622  for (long j=longitude-NumShreds()/2, y=0; y<NumShreds(); ++j, ++y)
623  for (long i=latitude -NumShreds()/2, x=0; x<NumShreds(); ++i, ++x) {
624  *FindShred(x, y) = new Shred(x, y, j, i);
625  }
627  0 : ( TIME_NIGHT==PartOfDay() ) ?
629  ReEnlightenAll();
630 }
631 
633  for (int i=0; i<NumShreds()*NumShreds(); ++i) {
634  delete shreds[i];
635  }
636 }
637 
638 void World::SetNumActiveShreds(const int num) {
639  const QMutexLocker locker(&mutex);
640  numActiveShreds = num;
641  if ( 1 != numActiveShreds%2 ) {
642  ++numActiveShreds;
643  emit Notify(tr("Invalid active shreds number. Set to %1.").
644  arg(numActiveShreds));
645  }
646  if ( numActiveShreds < 3 ) {
647  numActiveShreds = 3;
648  emit Notify(tr("Active shreds number too small, set to 3."));
649  } else if ( numActiveShreds > NumShreds() ) {
651  emit Notify(tr("Active shreds number too big. Set to %1.").
652  arg(numActiveShreds));
653  }
654  emit Notify(tr("Active shreds number is %1x%1.").arg(numActiveShreds));
655 }
656 
657 World::World(const QString world_name, bool * error) :
658  worldName(world_name),
659  map(world_name),
660  settings(home_path + worldName +"/settings.ini", QSettings::IniFormat),
661  time(settings.value("time", END_OF_NIGHT).toLongLong()),
662  timeStep(settings.value("time_step", 0).toInt()),
663  shreds(),
664  longitude(settings.value("longitude",
665  qlonglong(map.GetSpawnLongitude())).toLongLong()),
666  latitude (settings.value("latitude",
667  qlonglong(map.GetSpawnLatitude ())).toLongLong()),
668  numShreds(),
669  numActiveShreds(),
670  mutex(),
671  evernight(settings.value("evernight", false).toBool()),
672  newLati(),
673  newLongi(),
674  newX(),
675  newY(),
676  newZ(),
677  toResetDir(UP),
678  sunMoonFactor(),
679  shredStorage(),
680  initial_lighting(),
681  notes()
682 {
683  world = this;
684  QSettings game_settings(home_path + "freg.ini", QSettings::IniFormat);
685  numShreds=game_settings.value("number_of_shreds", MIN_WORLD_SIZE).toInt();
686  if ( 1 != numShreds%2 ) {
687  ++numShreds;
688  qDebug("%s: Invalid number of shreds. Set to %d.",
689  Q_FUNC_INFO, numShreds);
690  }
691  if ( numShreds < MIN_WORLD_SIZE ) {
692  qDebug("%s: Number of shreds to small: %d. Set to %d.",
693  Q_FUNC_INFO, numShreds, MIN_WORLD_SIZE);
695  }
696  SetNumActiveShreds(game_settings.value("number_of_active_shreds",
697  numShreds).toInt());
698  game_settings.setValue("number_of_shreds", numShreds);
699  game_settings.setValue("number_of_active_shreds", numActiveShreds);
700 
701  shreds = new Shred *[NumShreds()*NumShreds()];
702  if ( not QDir(home_path).mkpath(worldName + "/texts") ) {
703  *error = true;
704  }
705 
707  puts(qPrintable(tr("Loading world...")));
708 
709  QFile notes_file(home_path + worldName + "/notes.txt");
710  if ( notes_file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
711  char note[MAX_NOTE_LENGTH*2];
712  while ( notes_file.readLine(note, MAX_NOTE_LENGTH*2) > 0 ) {
713  notes.append(QString(note).trimmed());
714  }
715  }
716  LoadAllShreds();
717  emit UpdatedAll();
718 }
719 
721  Lock();
722  quit();
723  wait();
724  Unlock();
725 
726  DeleteAllShreds();
727  delete [] shreds;
728  delete shredStorage;
729 
730  settings.setValue("time", qlonglong(time));
731  settings.setValue("time_step", timeStep);
732  settings.setValue("longitude", qlonglong(longitude));
733  settings.setValue("latitude", qlonglong(latitude));
734  settings.setValue("evernight", evernight); // save if not present
735 
736  QFile notes_file(home_path + worldName + "/notes.txt");
737  if ( notes_file.open(QIODevice::WriteOnly | QIODevice::Text) ) {
738  for (int i=0; i<notes.size(); ++i) {
739  notes_file.write(qPrintable(notes.at(i)));
740  notes_file.putChar('\n');
741  }
742  }
743 }
int ShredX() const
Definition: Shred.cpp:61
bool Move(int x, int y, int z, dirs dir)
Check and move.
Definition: World.cpp:375
int TimeOfDay() const
This returns seconds from start of current day.
Definition: World.cpp:59
long newLati
Definition: World.h:243
const WorldMap map
Definition: World.h:227
void ReEnlightenTime()
static dirs TurnRight(dirs dir)
Definition: World.cpp:165
int ShredY() const
Definition: Shred.cpp:62
void AddFalling(Block *)
Definition: Shred.cpp:277
unsigned Abs(const int x)
Definition: header.h:219
static int CoordInShred(const int x)
Get local coordinate.
Definition: Shred.h:100
static bool InVertBounds(int z)
Definition: World.cpp:131
Shred * GetNearShred(Shred *, dirs dir) const
Definition: World.cpp:48
3
Definition: header.h:90
void SetDir(int dir)
Definition: Block.cpp:269
void DeleteBlock(Block *) const
Does not actually delete normal blocks.
int numShreds
size of loaded zone
Definition: World.h:239
const QString home_path
Definition: main.cpp:50
long Latitude() const
Definition: World.cpp:63
can_move_results
Definition: World.h:46
Definition: header.h:99
void SetShredData(QByteArray *, long longi, long lati)
Definition: World.cpp:72
BlockManager block_manager
void GetString(QString &) const
void PhysEventsFrequent()
Definition: Shred.cpp:204
Shred ** FindShred(int x, int y) const
Definition: World.cpp:209
World * world
Definition: World.cpp:32
int timeStep
Definition: World.h:230
bool Drop(Block *from, int x_to, int y_to, int z_to, int src, int dest, int num)
Returns true on success.
Definition: World.cpp:88
World provides global physics and shred connection.
Definition: World.h:52
void ReloadAllShreds(long lati, long longi, int new_x, int new_y, int new_z)
Definition: World.cpp:149
virtual void Damage(int dmg, int dmg_kind)
Definition: Block.cpp:117
void StartMove(int)
long Longitude() const
Definition: World.cpp:62
virtual int DamageKind() const
Definition: Block.cpp:208
Shred ** shreds
Definition: World.h:231
void Updated(int, int, int)
Definition: header.h:100
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
virtual int Weight() const
Definition: Block.cpp:242
virtual bool Access() const
Definition: Inventory.cpp:29
0
Definition: header.h:87
static dirs Anti(dirs dir)
Definition: World.cpp:191
int Transparent() const
Definition: Block.h:143
times_of_day
Definition: header.h:104
const int MIN_WORLD_SIZE
Definition: World.cpp:30
2
Definition: header.h:89
bool Inscribe(int x, int y, int z)
Returns true on success. Gets a string and inscribes block.
Definition: World.cpp:579
Shred * GetShredByPos(int x, int y) const
Definition: World.cpp:44
virtual push_reaction PushResult(dirs) const
Definition: Block.cpp:201
void PhysEventsRare()
Definition: Shred.cpp:232
int SetNote(QString note)
Definition: World.cpp:133
4
Definition: header.h:91
void Restore()
Set maximum durability.
Definition: Block.cpp:229
virtual Inventory * HasInventory()
Definition: Block.cpp:224
~World()
Definition: World.cpp:720
void PutBlock(Block *const block, const int x, int y, int z)
Definition: Shred.h:73
Definition: Shred.h:32
long latitude
Definition: World.h:238
const int MOON_LIGHT_FACTOR
Definition: World.h:37
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 Shift(int direction, long longitude, long latitude)
void AddFireLight(int x, int y, int z, int level)
QMutex * GetLock()
Definition: World.cpp:160
QString GetNote(int note_id) const
Definition: World.cpp:147
bool Visible(int x_from, int y_from, int z_from, int x_to, int y_to, int z_to) const
At least one side of block is visible.
Definition: World.cpp:354
const int HEIGHT
Definition: header.h:40
void ReloadShreds()
Definition: World.cpp:213
volatile dirs toResetDir
UP for no reset, DOWN for full reset, NSEW for side shift.
Definition: World.h:246
void StartReloadAll()
bool Exchange(Block *block_from, Block *block_to, int src, int dest, int num)
Returns true if block_from can be put into block_to.
Definition: World.cpp:593
void ReEnlightenAll()
const QString worldName
Definition: World.h:226
virtual int LightRadius() const
Definition: Block.cpp:210
void Lock()
Definition: World.cpp:161
void Jump(int x, int y, int z, dirs dir)
Definition: World.cpp:483
ulong Time() const
Returns time in seconds since world creation.
Definition: World.cpp:61
can_move_results CanMove(int x, int y, int z, int x_to, int y_to, int z_to, dirs dir)
This CAN move blocks, but not xyz block.
Definition: World.cpp:391
void Notify(QString) const
11
Definition: header.h:171
void NeedPlayer(int, int, int)
const int SUN_LIGHT_FACTOR
Definition: World.h:38
void ReEnlightenMove(dirs)
Called from ReloadShreds(int), enlightens only needed shreds.
Block * GetBlock(int x, int y, int z) const
Definition: World.cpp:204
virtual int DamageLevel() const
Definition: Block.cpp:209
Provides declaration for class Inventory for freg.
bool Get(Block *to, int x_from, int y_from, int z_from, int src, int dest, int num)
Definition: World.cpp:99
virtual Falling * ShouldFall()
Definition: Block.cpp:227
ulong time
Definition: World.h:229
World(QString world_name, bool *error)
Definition: World.cpp:657
void NoCheckMove(int x, int y, int z, int x_to, int y_to, int z_to, dirs dir)
Definition: World.cpp:449
void UpdatedAll()
int newX
Definition: World.h:244
bool GetEvernight() const
Definition: World.cpp:64
void UpdatesEnded()
This is emitted when a pack of updates is complete.
const WorldMap * GetMap() const
Definition: World.cpp:66
void Unlock()
Definition: World.cpp:163
int Kind() const
Definition: Block.h:145
int Sub() const
Definition: Block.h:144
void LoadAllShreds()
Definition: World.cpp:621
virtual wearable Wearable() const
Definition: Block.cpp:212
void SetShredData(QByteArray *, long longi, long lati)
void FinishReloadAll()
QString TimeOfDayStr() const
Definition: World.cpp:82
void ReEnlighten(int x, int y, int z)
Called when block is moved.
19
Definition: header.h:179
static Block * NewBlock(int kind, int sub)
Use this to receive a pointer to new not-normal block.
int GetBound() const
Definition: World.cpp:126
times_of_day PartOfDay() const
Definition: World.cpp:78
virtual Block * DropAfterDamage(bool *delete_self)
Should return dropped block.
Definition: Block.cpp:184
bool ShredInCentralZone(long longi, long lati) const
Definition: World.cpp:34
ShredStorage * shredStorage
Definition: World.h:249
int MiniTime() const
Returns number of physics steps since second start.
Definition: World.cpp:60
Definition: header.h:101
Definition: Active.h:46
void DestroyAndReplace(int x, int y, int z)
Does not check target block durability.
Definition: World.cpp:525
1
Definition: header.h:88
dirs
Definition: header.h:85
bool TryLock()
Definition: World.cpp:162
void PhysEvents()
Definition: World.cpp:298
void SetReloadShreds(int direction)
Definition: World.cpp:287
int numActiveShreds
size of active zone
Definition: World.h:240
virtual Active * ActiveBlock()
Definition: Block.cpp:226
Provides block ability to contain other blocks inside.
Definition: Inventory.h:33
Shred * GetShred(int i, int j) const
Definition: World.cpp:40
void DeleteAllShreds()
Also saves all shreds.
Definition: World.cpp:632
void run() override
Definition: World.cpp:291
bool DirectlyVisible(int x_from, int y_from, int z_from, int x_to, int y_to, int z_to) const
Definition: World.cpp:326
bool InBounds(int x, int y) const
Definition: World.cpp:117
int sunMoonFactor
Definition: World.h:247
bool Build(Block *thing, int x, int y, int z, int dir=UP, Block *who=nullptr, bool anyway=false)
Returns true on successfull build, otherwise false.
Definition: World.cpp:550
int Damage(int x, int y, int z, int level, int dmg_kind)
Returns damaged block result durability.
Definition: World.cpp:508
Block * GetBlock(const int x, const int y, const int z) const
Definition: Shred.h:61
QSettings settings
Definition: World.h:228
Definition: header.h:96
const int TIME_STEPS_IN_SEC
Definition: World.h:35
QByteArray * GetShredData(long longi, long lati) const
void Moved(int)
Emitted when world active zone moved to int direction.
int GetDurability() const
Definition: Block.cpp:232
const int MAX_NOTE_LENGTH
Definition: World.h:44
16
Definition: header.h:131
QList< QString > notes
Definition: World.h:251
int NumShreds() const
Definition: World.cpp:58
int newY
Definition: World.h:244
static int CoordOfShred(const int x)
Get shred coordinate in loaded zone (from 0 to numShreds).
Definition: Shred.h:103
void Unregister()
Definition: Active.cpp:79
int newZ
Definition: World.h:244
bool Focus(int x, int y, int z, int *x_targ, int *y_targ, int *z_targ, dirs dir) const
False on error, true if focus is received to _targ successfully.
Definition: World.cpp:491
int ShredPos(int x, int y) const
Definition: World.cpp:38
const int SHRED_WIDTH
Definition: header.h:38
virtual void Move(dirs direction)
Definition: Block.cpp:207
virtual void ReceiveSignal(QString)
Receive text signal.
Definition: Block.cpp:211
int ChangeNote(QString note, int note_id)
Definition: World.cpp:138
Block without special physics and attributes.
Definition: Block.h:89
5
Definition: header.h:92
long longitude
Definition: World.h:238
long newLongi
Definition: World.h:243
bool IsFalling() const
Definition: Active.cpp:260
static dirs TurnLeft(dirs dir)
Definition: World.cpp:178
virtual bool Inscribe(QString str)
Returns true on success.
Definition: Block.cpp:216
QString WorldName() const
Definition: World.cpp:65
QByteArray * GetShredData(long longi, long lati) const
Definition: World.cpp:68
void SetNumActiveShreds(int num)
Definition: World.cpp:638
const bool evernight
Definition: World.h:242
QMutex mutex
Definition: World.h:241