freg  0.3
Free-Roaming Elementary Game
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Active.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 "Active.h"
21 #include "Shred.h"
22 #include "World.h"
23 #include "Xyz.h"
24 #include "blocks/Inventory.h"
25 
26 // Active section
27 
28 Active * Active::ActiveBlock() { return this; }
29 int Active::ShouldAct() const { return FREQUENT_NEVER; }
31 
33  if ( LightRadius() ) {
34  GetShred()->AddShining(this);
35  GetWorld()->Shine(X(), Y(), Z(), LightRadius());
36  } else {
37  GetShred()->RemShining(this);
38  }
39 }
40 
42  qDebug("Active::ActFrequent called, check ShouldAct\
43  return value or add ActFrequent implementation.\nKind: %d, sub: %d.",
44  Kind(), Sub());
45  Q_UNREACHABLE();
46 }
47 
49  qDebug("Active::DoRareAction called, check ShouldAct and ActInner\
50  return values or add DoRareAction implementation.\nKind: %d, sub: %d.",
51  Kind(), Sub());
52  Q_UNREACHABLE();
53 }
54 
56  Inventory * const inv = HasInventory();
57  if ( inv == nullptr ) {
58  DoRareAction();
59  return;
60  } // else:
61  for (int i=inv->Size()-1; i; --i) {
62  const int number = inv->Number(i);
63  if ( number == 0 ) continue;
64  Active * const top_active = inv->ShowBlock(i)->ActiveBlock();
65  if ( top_active == nullptr ) continue;
66  for (int j=0; j<number; ++j) {
67  Active * const active = inv->ShowBlockInSlot(i, j)->ActiveBlock();
68  if ( active->ActInner() == INNER_ACTION_MESSAGE ) {
69  ReceiveSignal( tr("%1 in slot '%2': %3").
70  arg(inv->InvFullName(i)).
71  arg(char('a'+i)).
72  arg(inv->ShowBlockInSlot(i, j)->GetNote()) );
73  }
74  }
75  }
76  DoRareAction();
77 }
78 
80  if ( shred != nullptr ) {
81  shred->Unregister(this);
82  shred = nullptr;
83  }
84 }
85 
86 void Active::Move(const dirs dir) {
87  switch ( dir ) {
88  case UP: ++z_self; break;
89  case DOWN: --z_self; break;
90  case NORTH: --y_self; ReRegister(NORTH); break;
91  case SOUTH: ++y_self; ReRegister(SOUTH); break;
92  case EAST: ++x_self; ReRegister(EAST ); break;
93  case WEST: --x_self; ReRegister(WEST ); break;
94  }
95  emit Moved(dir);
96 }
97 
98 void Active::ReRegister(const dirs dir) {
99  if ( Shred::InBounds(x_self, y_self) ) return;
100  x_self &= 0xF;
101  y_self &= 0xF;
102  shred->Unregister(this);
103  (shred = GetWorld()->GetNearShred(shred, dir))->Register(this);
104 }
105 
106 void Active::SendSignalAround(const QString signal) const {
107  if ( shred == nullptr ) return; // for blocks inside inventories
108  World * const world = GetWorld();
109  const int bound = world->GetBound();
110  if ( X() > 0 ) world->GetBlock(X()-1, Y(), Z())->ReceiveSignal(signal);
111  if ( X() < bound ) world->GetBlock(X()+1, Y(), Z())->ReceiveSignal(signal);
112  if ( Y() > 0 ) world->GetBlock(X(), Y()-1, Z())->ReceiveSignal(signal);
113  if ( Y() < bound ) world->GetBlock(X(), Y()+1, Z())->ReceiveSignal(signal);
114  world->GetBlock(X(), Y(), Z()-1)->ReceiveSignal(signal);
115  world->GetBlock(X(), Y(), Z()+1)->ReceiveSignal(signal);
116 }
117 
118 void Active::DamageAround() const {
119  const int bound = GetWorld()->GetBound();
120  int x_temp = X()-1;
121  int y_temp = Y();
122  int z_temp = Z();
123  if ( x_temp >= 0 ) TryDestroy( x_temp, y_temp, z_temp);
124  if ( (x_temp+=2) <= bound ) TryDestroy( x_temp, y_temp, z_temp);
125  if ( --y_temp >= 0 ) TryDestroy(--x_temp, y_temp, z_temp);
126  if ( (y_temp+=2) <= bound ) TryDestroy( x_temp, y_temp, z_temp);
127  TryDestroy(x_temp, --y_temp, --z_temp);
128  TryDestroy(x_temp, y_temp, z_temp+=2);
129 }
130 
131 void Active::TryDestroy(const int x, const int y, const int z) const {
132  World * const world = GetWorld();
133  if ( world->Damage(x, y, z, DamageLevel(), DamageKind()) <= 0 ) {
134  world->DestroyAndReplace(x, y, z);
135  }
136 }
137 
138 void Active::SetShred(Shred * const new_shred) { shred = new_shred; }
139 Shred * Active::GetShred() const { return shred; }
140 World * Active::GetWorld() const { return world; }
141 
142 void Active::Damage(const int dmg, const int dmg_kind) {
143  const int last_dur = GetDurability();
144  Block::Damage(dmg, dmg_kind);
145  if ( last_dur != GetDurability() ) {
146  switch ( dmg_kind ) {
147  case DAMAGE_HUNGER: ReceiveSignal(tr("You weaken from hunger!"));break;
148  case DAMAGE_HEAT: ReceiveSignal(tr("You burn!")); break;
149  case DAMAGE_BREATH: ReceiveSignal(tr("You choke withot air!")); break;
150  default: ReceiveSignal(tr("Received damage!"));
151  }
152  emit Updated();
153  }
154 }
155 
156 void Active::ReceiveSignal(const QString str) { emit ReceivedText(str); }
157 
158 int Active::X() const {
159  return GetShred()->ShredX() << SHRED_WIDTH_SHIFT | Xyz::X();
160 }
161 
162 int Active::Y() const {
163  return GetShred()->ShredY() << SHRED_WIDTH_SHIFT | Xyz::Y();
164 }
165 
166 Active::Active(const int kind, const int sub, const int transp) :
167  Block(kind, sub, transp),
168  Xyz()
169 {}
170 
171 Active::Active(QDataStream & str, const int kind, const int sub,
172  const int transp)
173  :
174  Block(str, kind, sub, transp),
175  Xyz()
176 {}
177 
178 bool Active::Gravitate(const int range, int bottom, int top,
179  const int calmness)
180 {
181  World * const world = GetWorld();
182  const int bound = world->GetBound();
183  // analyse world around
184  int for_north = 0, for_west = 0;
185  const int y_start = qMax(Y()-range, 0);
186  const int y_end = qMin(Y()+range, bound);
187  const int x_end = qMin(X()+range, bound);
188  bottom = qMax(Z()-bottom, 0);
189  top = qMin(Z()+top, HEIGHT-1);
190  for (int x=qMax(X()-range, 0); x<=x_end; ++x)
191  for (int y=y_start; y<=y_end; ++y) {
192  Shred * const shred = world->GetShred(x, y);
193  const int x_in = Shred::CoordInShred(x);
194  const int y_in = Shred::CoordInShred(y);
195  for (int z=bottom; z<=top; ++z) {
196  const int attractive =
197  Attractive(shred->GetBlock(x_in, y_in, z)->Sub());
198  if ( attractive != 0
199  && world->DirectlyVisible(X(), Y(), Z(), x, y, z) )
200  {
201  if ( y!=Y() ) for_north += attractive/(Y()-y);
202  if ( x!=X() ) for_west += attractive/(X()-x);
203  }
204  }
205  }
206  // make direction and move there
207  if ( qAbs(for_north)>calmness || qAbs(for_west)>calmness ) {
208  SetDir( ( qAbs(for_north)>qAbs(for_west) ) ?
209  ( ( for_north>0 ) ? NORTH : SOUTH ) :
210  ( ( for_west >0 ) ? WEST : EAST ) );
211  return true;
212  } else {
213  return false;
214  }
215 }
216 
217 int Active::Attractive(int) const { return 0; }
218 
219 bool Active::IsSubAround(const int sub) const {
220  const World * const world = GetWorld();
221  const int bound = world->GetBound();
222  return (sub == world->GetBlock(X(), Y(), Z()-1)->Sub() ||
223  sub == world->GetBlock(X(), Y(), Z()+1)->Sub() ||
224  (X() > 0 && sub == world->GetBlock(X()-1, Y(), Z())->Sub()) ||
225  (X() < bound && sub == world->GetBlock(X()+1, Y(), Z())->Sub()) ||
226  (Y() > 0 && sub == world->GetBlock(X(), Y()-1, Z())->Sub()) ||
227  (Y() < bound && sub == world->GetBlock(X(), Y()+1, Z())->Sub()) );
228 }
229 
230 // Falling section
231 
232 Falling::Falling(const int kind, const int sub, const int transp) :
233  Active(kind, sub, transp),
234  fallHeight(0),
235  falling(false)
236 {}
237 
238 Falling::Falling(QDataStream & str, const int kind, const int sub,
239  const int transp)
240  :
241  Active(str, kind, sub, transp),
242  fallHeight(),
243  falling()
244 {
245  str >> fallHeight >> falling;
246 }
247 
248 void Falling::SaveAttributes(QDataStream & out) const {
249  out << fallHeight << falling;
250 }
251 
252 QString Falling::FullName() const {
253  switch ( Sub() ) {
254  default: return SubNameUpper(Sub());
255  case WATER: return tr("Snow");
256  case STONE: return tr("Masonry");
257  }
258 }
259 
260 bool Falling::IsFalling() const { return falling; }
261 Falling * Falling::ShouldFall() { return this; }
263 
265  const int SAFE_FALL_HEIGHT = 5;
266  if ( fallHeight > SAFE_FALL_HEIGHT ) {
267  const int dmg = (fallHeight - SAFE_FALL_HEIGHT)*10;
268  World * const world = GetWorld();
269  Block * const block_under = world->GetBlock(X(), Y(), Z()-1);
270  world->Damage(X(), Y(), Z()-1, dmg, DamageKind());
271  if ( block_under->GetDurability() <= 0 ) {
272  world->DestroyAndReplace(X(), Y(), Z()-1);
273  }
274  Damage(dmg, block_under->DamageKind());
275  if ( GetDurability() <= 0 ) {
276  world->DestroyAndReplace(X(), Y(), Z());
277  return;
278  }
279  }
280  falling = false;
281  fallHeight = 0;
282 }
283 
284 void Falling::Move(const dirs dir) {
285  Active::Move(dir);
286  if ( DOWN == dir ) {
287  ++fallHeight;
288  }
289 }
290 
291 void Falling::SetFalling(const bool set) {
292  if ( not (falling=set) ) {
293  fallHeight = 0;
294  }
295 }
int ShredX() const
Definition: Shred.cpp:61
int X() const
Definition: Active.cpp:158
void ReRegister(dirs)
Definition: Active.cpp:98
void SendSignalAround(QString) const
Definition: Active.cpp:106
void ActRare()
Definition: Active.cpp:55
push_reaction PushResult(dirs) const override
Definition: Active.cpp:262
int ShredY() const
Definition: Shred.cpp:62
virtual void UpdateLightRadius()
Definition: Active.cpp:32
static int CoordInShred(const int x)
Get local coordinate.
Definition: Shred.h:100
short y_self
Definition: Xyz.h:32
Shred * GetNearShred(Shred *, dirs dir) const
Definition: World.cpp:48
3
Definition: header.h:90
void SetDir(int dir)
Definition: Block.cpp:269
push_reaction
Definition: header.h:95
int Number(int i) const
Definition: Inventory.cpp:28
World * world
Definition: World.cpp:32
static QString SubNameUpper(int sub)
Returns translated substance name with first upper letter.
Definition: Block.cpp:77
World provides global physics and shred connection.
Definition: World.h:52
short z_self
Definition: Xyz.h:44
virtual void Damage(int dmg, int dmg_kind)
Definition: Block.cpp:117
short Z() const
Definition: Xyz.cpp:30
virtual int DamageKind() const
Definition: Block.cpp:208
void Move(dirs dir) override
Definition: Active.cpp:284
0
Definition: header.h:87
short X() const
Definition: Xyz.cpp:28
2
Definition: header.h:89
void Moved(int)
Active * ActiveBlock() overridefinal
Definition: Active.cpp:28
QString FullName() const override
Definition: Active.cpp:252
void Updated()
bool Gravitate(int range, int down, int up, int calmness)
Definition: Active.cpp:178
4
Definition: header.h:91
virtual Inventory * HasInventory()
Definition: Block.cpp:224
Block * ShowBlock(int slot) const
Definition: Inventory.cpp:182
Definition: Shred.h:32
void RemShining(Active *)
Definition: Shred.cpp:291
5
Definition: Block.h:44
const int HEIGHT
Definition: header.h:40
virtual int Attractive(int sub) const
Definition: Active.cpp:217
Shred * GetShred() const
Definition: Active.cpp:139
int Size() const
Definition: Inventory.cpp:27
virtual void ActFrequent()
Definition: Active.cpp:41
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
void Shine(int x, int y, int z, int level)
If init is false, light will not spread from non-invisible blocks.
inner_actions
See Shred::PhysEventsRare() for details.
Definition: Active.h:36
void ReceiveSignal(QString) override
Receive text signal.
Definition: Active.cpp:156
int Y() const
Definition: Active.cpp:162
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.
World * GetWorld() const
Definition: Active.cpp:140
short x_self
Definition: Xyz.h:32
Active(int sub, int id, int transp=UNDEF)
Definition: Active.cpp:166
void DamageAround() const
Definition: Active.cpp:118
void Unregister(Active *)
Definition: Shred.cpp:265
void TryDestroy(int x, int y, int z) const
Damages block and destroys it if it is broken.
Definition: Active.cpp:131
Block * ShowBlockInSlot(int slot, int index) const
Don't move block shown by this function.
Definition: Inventory.cpp:177
short Y() const
Definition: Xyz.cpp:29
int Kind() const
Definition: Block.h:145
int Sub() const
Definition: Block.h:144
quint8 fallHeight
Definition: Active.h:121
QString GetNote() const
Definition: Block.cpp:234
int GetBound() const
Definition: World.cpp:126
void SaveAttributes(QDataStream &out) const override
Definition: Active.cpp:248
virtual inner_actions ActInner()
Definition: Active.cpp:30
void FallDamage()
Definition: Active.cpp:264
Definition: Active.h:46
13
Definition: header.h:173
Definition: Xyz.h:35
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
virtual Active * ActiveBlock()
Definition: Block.cpp:226
Provides block ability to contain other blocks inside.
Definition: Inventory.h:33
void Damage(int dmg, int dmg_kind) override
Definition: Active.cpp:142
0
Definition: header.h:160
Shred * GetShred(int i, int j) const
Definition: World.cpp:40
Falling * ShouldFall() overridefinal
Definition: Active.cpp:261
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
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
void ReceivedText(const QString)
Definition: header.h:96
Falling(int sub, int id, int transp=UNDEF)
Definition: Active.cpp:232
int GetDurability() const
Definition: Block.cpp:232
virtual void DoRareAction()
Definition: Active.cpp:48
const int SHRED_WIDTH_SHIFT
Definition: header.h:39
void SetFalling(bool set)
Definition: Active.cpp:291
void AddShining(Active *)
Definition: Shred.cpp:285
void Unregister()
Definition: Active.cpp:79
bool falling
Definition: Active.h:122
virtual void ReceiveSignal(QString)
Receive text signal.
Definition: Block.cpp:211
Block without special physics and attributes.
Definition: Block.h:89
5
Definition: header.h:92
virtual QString InvFullName(int num) const
Definition: Inventory.cpp:145
bool IsFalling() const
Definition: Active.cpp:260
Shred * shred
Definition: Active.h:99
bool IsSubAround(int sub) const
Returns true if there is at least 1 block of substance sub around.
Definition: Active.cpp:219
void SetShred(Shred *)
Definition: Active.cpp:138
void Move(dirs dir) override
Definition: Active.cpp:86