renamed alot of types; hope this will not break the game
[k8-i-v-a-n.git] / src / game / object.cpp
blob6bbe1e2ed9e94ad1538dd5c57cc00d697438c543
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
13 #include "object.h"
14 #include "materia.h"
15 #include "festring.h"
16 #include "whandler.h"
17 #include "rawbit.h"
18 #include "proto.h"
19 #include "game.h"
20 #include "bitmap.h"
21 #include "fesave.h"
23 v2 RightArmSparkleValidityArray[128];
24 v2 LeftArmSparkleValidityArray[128];
25 v2 GroinSparkleValidityArray[169];
26 v2 RightLegSparkleValidityArray[42];
27 v2 LeftLegSparkleValidityArray[45];
28 v2 NormalSparkleValidityArray[256];
29 v2 PossibleSparkleBuffer[256];
31 object::object() : entity(0), MainMaterial(0) {}
32 int object::GetSpecialFlags() const { return ST_NORMAL; }
33 col16 object::GetOutlineColor(int) const { return TRANSPARENT_COLOR; }
34 cbitmap*const* object::GetPicture() const { return GraphicData.Picture; }
36 object::object(const object& Object) : entity(Object), id(Object), VisualEffects(Object.VisualEffects)
38 CopyMaterial(Object.MainMaterial, MainMaterial);
39 mOnEvents = Object.mOnEvents;
42 object::~object()
44 delete MainMaterial;
47 void object::CopyMaterial(material* const& Source, material*& Dest)
49 if(Source)
51 Dest = Source->Duplicate();
52 Dest->SetMotherEntity(this);
54 else
55 Dest = 0;
58 void object::Save(outputfile& SaveFile) const
60 SaveFile << GraphicData << (int)VisualEffects;
61 SaveFile << MainMaterial;
64 void object::Load(inputfile& SaveFile)
66 SaveFile >> GraphicData >> (int&)VisualEffects;
67 LoadMaterial(SaveFile, MainMaterial);
70 void object::ObjectInitMaterials(material*& FirstMaterial, material* FirstNewMaterial, sLong FirstDefaultVolume, material*& SecondMaterial, material* SecondNewMaterial, sLong SecondDefaultVolume, truth CallUpdatePictures)
72 InitMaterial(FirstMaterial, FirstNewMaterial, FirstDefaultVolume);
73 InitMaterial(SecondMaterial, SecondNewMaterial, SecondDefaultVolume);
74 SignalVolumeAndWeightChange();
76 if(CallUpdatePictures)
77 UpdatePictures();
80 void object::InitMaterial(material*& Material, material* NewMaterial, sLong DefaultVolume)
82 Material = NewMaterial;
84 if(Material)
86 if(Material->HasBe())
87 Enable();
89 if(DefaultVolume && !Material->GetVolume())
90 Material->SetVolume(DefaultVolume);
92 Material->SetMotherEntity(this);
93 SignalEmitationIncrease(Material->GetEmitation());
97 void object::ChangeMaterial(material*& Material, material* NewMaterial, sLong DefaultVolume, int SpecialFlags)
99 delete SetMaterial(Material, NewMaterial, DefaultVolume, SpecialFlags);
102 material *object::SetMaterial (material *&Material, material *NewMaterial, sLong DefaultVolume, int SpecialFlags) {
103 material *OldMaterial = Material;
104 Material = NewMaterial;
106 if ((!OldMaterial || !OldMaterial->HasBe()) && NewMaterial && NewMaterial->HasBe()) {
107 Enable();
108 } else if (OldMaterial && OldMaterial->HasBe() && (!NewMaterial || !NewMaterial->HasBe()) && !CalculateHasBe()) {
109 Disable();
111 if (NewMaterial) {
112 if (!NewMaterial->GetVolume()) {
113 if (OldMaterial) NewMaterial->SetVolume(OldMaterial->GetVolume());
114 else if (DefaultVolume) NewMaterial->SetVolume(DefaultVolume);
115 else ABORT("Singularity spawn detected!");
117 NewMaterial->SetMotherEntity(this);
118 if (!(SpecialFlags & NO_SIGNALS)) SignalEmitationIncrease(NewMaterial->GetEmitation());
120 if (!(SpecialFlags & NO_SIGNALS)) {
121 if (OldMaterial) SignalEmitationDecrease(OldMaterial->GetEmitation());
122 SignalVolumeAndWeightChange();
123 SignalMaterialChange();
125 if (!(SpecialFlags & NO_PIC_UPDATE)) UpdatePictures();
126 return OldMaterial;
130 void object::UpdatePictures()
132 static cv2 ZeroPos(0, 0);
133 UpdatePictures(GraphicData, ZeroPos, VisualEffects|GetSpecialFlags(), GetMaxAlpha(), GetGraphicsContainerIndex(), &object::GetBitmapPos);
136 truth object::RandomizeSparklePos(v2& SparklePos, v2 BPos, int& SparkleTime, uLong SeedBase, int SpecialFlags, int GraphicsContainerIndex) const
138 static int SeedModifier = 1;
139 femath::SaveSeed();
140 femath::SetSeed(SeedBase + SeedModifier);
142 if(++SeedModifier > 0x10)
143 SeedModifier = 1;
145 v2* ValidityArray;
146 int ValidityArraySize;
148 if((SpecialFlags & 0x38) == ST_RIGHT_ARM)
150 ValidityArray = RightArmSparkleValidityArray;
151 ValidityArraySize = 128;
153 else if((SpecialFlags & 0x38) == ST_LEFT_ARM)
155 ValidityArray = LeftArmSparkleValidityArray;
156 ValidityArraySize = 128;
158 else if((SpecialFlags & 0x38) == ST_GROIN)
160 ValidityArray = GroinSparkleValidityArray;
161 ValidityArraySize = 169;
163 else if((SpecialFlags & 0x38) == ST_RIGHT_LEG)
165 ValidityArray = RightLegSparkleValidityArray;
166 ValidityArraySize = 42;
168 else if((SpecialFlags & 0x38) == ST_LEFT_LEG)
170 ValidityArray = LeftLegSparkleValidityArray;
171 ValidityArraySize = 45;
173 else
175 ValidityArray = NormalSparkleValidityArray;
176 ValidityArraySize = 256;
179 SparklePos = igraph::GetRawGraphic(GraphicsContainerIndex)->RandomizeSparklePos(ValidityArray, PossibleSparkleBuffer, BPos, TILE_V2, ValidityArraySize, GetSparkleFlags());
181 if(SparklePos != ERROR_V2)
183 SparkleTime = RAND() % 241;
184 femath::LoadSeed();
185 return true;
187 else
189 femath::LoadSeed();
190 return false;
194 void object::UpdatePictures(graphicdata& GraphicData, v2 Position, int SpecialFlags, alpha MaxAlpha, int GraphicsContainerIndex, bposretriever BitmapPosRetriever) const
196 int AnimationFrames = GetClassAnimationFrames();
197 v2 SparklePos;
198 int SparkleTime = 0;
199 int Seed = 0;
200 int FlyAmount = GetSpoilLevel();
201 truth Sparkling = false, FrameNeeded = false, SeedNeeded = false;
202 v2 BPos = (this->*BitmapPosRetriever)(0);
203 alpha Alpha;
205 if(!(SpecialFlags & (ST_FLAMES|ST_LIGHTNING)))
207 if(AllowSparkling())
209 int SparkleFlags = GetSparkleFlags();
211 if(SparkleFlags
212 && RandomizeSparklePos(SparklePos, BPos, SparkleTime,
213 BPos.X + BPos.Y + GetMaterialColorA(0),
214 SpecialFlags, GraphicsContainerIndex))
216 Sparkling = true;
218 if(AnimationFrames <= 256)
219 AnimationFrames = 256;
223 if(FlyAmount)
225 SeedNeeded = true;
226 FrameNeeded = true;
228 if(AnimationFrames <= 32)
229 AnimationFrames = 32;
232 else if(SpecialFlags & ST_FLAMES)
234 SeedNeeded = true;
235 FrameNeeded = true;
237 if(AnimationFrames <= 16)
238 AnimationFrames = 16;
240 else if(SpecialFlags & ST_LIGHTNING)
242 SeedNeeded = true;
244 if(AnimationFrames <= 128)
245 AnimationFrames = 128;
248 if(SeedNeeded)
250 static int SeedModifier = 1;
251 Seed = BPos.X + BPos.Y + GetMaterialColorA(0) + SeedModifier + 0x42;
253 if(++SeedModifier > 0x10)
254 SeedModifier = 1;
257 int WobbleMask = 0, WobbleData = GetWobbleData();
259 if(WobbleData & WOBBLE)
261 int Speed = (WobbleData & WOBBLE_SPEED_RANGE) >> WOBBLE_SPEED_SHIFT;
262 int Freq = (WobbleData & WOBBLE_FREQ_RANGE) >> WOBBLE_FREQ_SHIFT;
263 int WobbleFrames = 512 >> (Freq + Speed);
264 WobbleMask = 7 >> Freq << (6 - Speed);
266 if(AnimationFrames <= WobbleFrames)
267 AnimationFrames = WobbleFrames;
270 ModifyAnimationFrames(AnimationFrames);
271 int c;
272 int OldAnimationFrames = GraphicData.AnimationFrames;
274 for(c = 0; c < OldAnimationFrames; ++c)
275 igraph::RemoveUser(GraphicData.GraphicIterator[c]);
277 if(OldAnimationFrames != AnimationFrames)
279 if(OldAnimationFrames)
281 delete [] GraphicData.Picture;
282 delete [] GraphicData.GraphicIterator;
285 GraphicData.Picture = new bitmap*[AnimationFrames];
286 GraphicData.GraphicIterator = new tilemap::iterator[AnimationFrames];
289 GraphicData.AnimationFrames = AnimationFrames;
291 if(!AllowRegularColors())
292 SpecialFlags |= ST_DISALLOW_R_COLORS;
294 graphicid GI;
295 GI.BaseAlpha = MaxAlpha;
296 GI.FileIndex = GraphicsContainerIndex;
297 GI.SpecialFlags = SpecialFlags;
298 GI.Seed = Seed;
299 GI.FlyAmount = FlyAmount;
300 GI.Position = Position;
301 GI.RustData[0] = GetRustDataA();
302 GI.RustData[1] = GetRustDataB();
303 GI.RustData[2] = GetRustDataC();
304 GI.RustData[3] = GetRustDataD();
305 GI.WobbleData = WobbleData;
307 for(c = 0; c < AnimationFrames; ++c)
309 GI.Color[0] = GetMaterialColorA(c);
310 GI.Color[1] = GetMaterialColorB(c);
311 GI.Color[2] = GetMaterialColorC(c);
312 GI.Color[3] = GetMaterialColorD(c);
313 Alpha = GetAlphaA(c);
314 GI.Alpha[0] = Alpha < MaxAlpha ? Alpha : MaxAlpha;
315 Alpha = GetAlphaB(c);
316 GI.Alpha[1] = Alpha < MaxAlpha ? Alpha : MaxAlpha;
317 Alpha = GetAlphaC(c);
318 GI.Alpha[2] = Alpha < MaxAlpha ? Alpha : MaxAlpha;
319 Alpha = GetAlphaD(c);
320 GI.Alpha[3] = Alpha < MaxAlpha ? Alpha : MaxAlpha;
321 v2 BPos = (this->*BitmapPosRetriever)(c);
322 GI.BitmapPosX = BPos.X;
323 GI.BitmapPosY = BPos.Y;
325 if(Sparkling && c > SparkleTime && c < SparkleTime + 16)
327 GI.SparklePosX = SparklePos.X;
328 GI.SparklePosY = SparklePos.Y;
329 GI.SparkleFrame = c - SparkleTime;
331 else
333 GI.SparklePosX = SPARKLE_POS_X_ERROR;
334 GI.SparklePosY = 0;
335 GI.SparkleFrame = 0;
338 GI.Frame =
339 !c ||
340 FrameNeeded ||
341 ((SpecialFlags & ST_LIGHTNING) && !((c + 1) & 7)) ||
342 ((WobbleData & WOBBLE) && !(c & WobbleMask))
343 ? c : 0;
345 GI.OutlineColor = GetOutlineColor(c);
346 GI.OutlineAlpha = GetOutlineAlpha(c);
347 tilemap::iterator Iterator = igraph::AddUser(GI);
348 GraphicData.GraphicIterator[c] = Iterator;
349 GraphicData.Picture[c] = Iterator->second.Bitmap;
353 col16 object::GetMaterialColorA(int) const
355 return MainMaterial->GetColor();
358 truth object::AddRustLevelDescription(festring& String, truth Articled) const
360 return MainMaterial->AddRustLevelDescription(String, Articled);
364 truth object::AddMaterialDescription(festring& String, truth Articled) const {
365 //FIXME: gum solution
366 if (isBone()) {
367 festring s(MainMaterial->GetName(Articled));
368 festring::sizetype pos = s.FindLast("bone");
369 if (pos != festring::NPos && pos == s.GetSize()-4) {
370 while (pos > 0 && s[pos-1] == ' ') pos--;
371 s.Erase(pos, s.GetSize()-pos);
372 if (s.GetSize() == 0) return true; // no name left
374 String << s;
375 } else {
376 MainMaterial->AddName(String, Articled);
378 String << ' ';
379 return true;
383 void object::AddContainerPostFix(festring& String) const
385 if(GetSecondaryMaterial())
386 GetSecondaryMaterial()->AddName(String << " full of ", false, false);
389 void object::AddLumpyPostFix(festring& String) const
391 MainMaterial->AddName(String << " of ", false, false);
394 alpha object::GetAlphaA(int) const
396 return MainMaterial->GetAlpha();
399 void object::RandomizeVisualEffects()
401 int AcceptedFlags = GetOKVisualEffects();
403 if(AcceptedFlags)
404 SetVisualEffects((RAND() & 0x7 & AcceptedFlags) | GetForcedVisualEffects());
405 else
406 SetVisualEffects(GetForcedVisualEffects());
409 void object::LoadMaterial(inputfile& SaveFile, material*& Material)
411 SaveFile >> Material;
413 if(Material)
415 if(Material->HasBe())
416 Enable();
418 Material->SetMotherEntity(this);
419 game::CombineLights(Emitation, Material->GetEmitation());
423 int object::RandomizeMaterialConfiguration()
425 const fearray<sLong>& MCC = GetMaterialConfigChances();
426 return MCC.Size > 1
427 ? femath::WeightedRand(MCC.Data, GetMaterialConfigChanceSum())
428 : 0;
431 truth object::AddEmptyAdjective(festring& String, truth Articled) const
433 if(GetSecondaryMaterial())
434 return false;
435 else
437 String << (Articled ? "an empty " : "empty ");
438 return true;
442 void object::CalculateEmitation()
444 Emitation = GetBaseEmitation();
446 if(MainMaterial)
447 game::CombineLights(Emitation, MainMaterial->GetEmitation());
450 truth object::CalculateHasBe() const
452 return MainMaterial && MainMaterial->HasBe();
455 int object::GetSparkleFlags() const
457 return MainMaterial->IsSparkling() ? SPARKLING_A : 0;
460 void object::InitSparkleValidityArrays()
462 int y, x, Index = 0;
464 for(y = 0; y < 16; ++y)
465 for(x = 0; x < 8; ++x)
466 RightArmSparkleValidityArray[Index++] = v2(x, y);
468 Index = 0;
470 for(y = 0; y < 16; ++y)
471 for(x = 8; x < 16; ++x)
472 LeftArmSparkleValidityArray[Index++] = v2(x, y);
474 Index = 0;
476 for(y = 0; y < 10; ++y)
477 for(x = 0; x < 16; ++x)
478 GroinSparkleValidityArray[Index++] = v2(x, y);
480 for(y = 10; y < 13; ++y)
481 for(x = y - 5; x < 20 - y; ++x)
482 GroinSparkleValidityArray[Index++] = v2(x, y);
484 Index = 0;
486 for(y = 10; y < 16; ++y)
487 for(x = 0; x < 8; ++x)
488 if((y != 10 || x < 5) && (y != 11 || x < 6) && (y != 12 || x < 7))
489 RightLegSparkleValidityArray[Index++] = v2(x, y);
491 Index = 0;
493 for(y = 10; y < 16; ++y)
494 for(x = 8; x < 16; ++x)
495 if((y != 10 || x > 9) && (y != 11 || x > 8))
496 LeftLegSparkleValidityArray[Index++] = v2(x, y);
498 Index = 0;
500 for(y = 0; y < 16; ++y)
501 for(x = 0; x < 16; ++x)
502 NormalSparkleValidityArray[Index++] = v2(x, y);
505 int object::GetRustDataA() const
507 return MainMaterial->GetRustData();
510 truth object::DetectMaterial(cmaterial* Material) const
512 for(int c = 0; c < GetMaterials(); ++c)
513 if(GetMaterial(c) && GetMaterial(c)->IsSameAs(Material))
514 return true;
516 return false;