3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
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];
32 object::object () : entity(0), MainMaterial(0) {}
33 int object::GetSpecialFlags () const { return ST_NORMAL
; }
34 col16
object::GetOutlineColor (int) const { return TRANSPARENT_COLOR
; }
35 cbitmap
*const *object::GetPicture () const { return GraphicData
.Picture
; }
38 object::object (const object
& Object
) : entity(Object
), id(Object
), VisualEffects(Object
.VisualEffects
) {
39 CopyMaterial(Object
.MainMaterial
, MainMaterial
);
40 mOnEvents
= Object
.mOnEvents
;
49 void object::CopyMaterial (material
*const &Source
, material
*&Dest
) {
51 Dest
= Source
->Duplicate();
52 Dest
->SetMotherEntity(this);
59 void object::Save (outputfile
&SaveFile
) const {
60 SaveFile
<< GraphicData
<< (int)VisualEffects
;
61 SaveFile
<< MainMaterial
;
65 void object::Load (inputfile
&SaveFile
) {
66 SaveFile
>> GraphicData
>> (int&)VisualEffects
;
67 LoadMaterial(SaveFile
, MainMaterial
);
71 void object::ObjectInitMaterials (material
*&FirstMaterial
, material
*FirstNewMaterial
, sLong FirstDefaultVolume
,
72 material
*&SecondMaterial
, material
*SecondNewMaterial
, sLong SecondDefaultVolume
, truth CallUpdatePictures
)
74 InitMaterial(FirstMaterial
, FirstNewMaterial
, FirstDefaultVolume
);
75 InitMaterial(SecondMaterial
, SecondNewMaterial
, SecondDefaultVolume
);
76 SignalVolumeAndWeightChange();
77 if (CallUpdatePictures
) UpdatePictures();
81 void object::InitMaterial (material
*&Material
, material
*NewMaterial
, sLong DefaultVolume
) {
82 Material
= NewMaterial
;
84 if (Material
->HasBe()) Enable();
85 if (DefaultVolume
&& !Material
->GetVolume()) Material
->SetVolume(DefaultVolume
);
86 Material
->SetMotherEntity(this);
87 SignalEmitationIncrease(Material
->GetEmitation());
92 void object::ChangeMaterial (material
*&Material
, material
*NewMaterial
, sLong DefaultVolume
, int SpecialFlags
) {
93 delete SetMaterial(Material
, NewMaterial
, DefaultVolume
, SpecialFlags
);
97 material
*object::SetMaterial (material
*&Material
, material
*NewMaterial
, sLong DefaultVolume
, int SpecialFlags
) {
98 material
*OldMaterial
= Material
;
100 Material
= NewMaterial
;
101 if ((!OldMaterial
|| !OldMaterial
->HasBe()) && NewMaterial
&& NewMaterial
->HasBe()) {
103 } else if (OldMaterial
&& OldMaterial
->HasBe() && (!NewMaterial
|| !NewMaterial
->HasBe()) && !CalculateHasBe()) {
107 if (!NewMaterial
->GetVolume()) {
108 if (OldMaterial
) NewMaterial
->SetVolume(OldMaterial
->GetVolume());
109 else if (DefaultVolume
) NewMaterial
->SetVolume(DefaultVolume
);
110 else ABORT("Singularity spawn detected!");
112 NewMaterial
->SetMotherEntity(this);
113 if (!(SpecialFlags
&NO_SIGNALS
)) SignalEmitationIncrease(NewMaterial
->GetEmitation());
115 if (!(SpecialFlags
&NO_SIGNALS
)) {
116 if (OldMaterial
) SignalEmitationDecrease(OldMaterial
->GetEmitation());
117 SignalVolumeAndWeightChange();
118 SignalMaterialChange();
120 if (!(SpecialFlags
&NO_PIC_UPDATE
)) UpdatePictures();
125 void object::UpdatePictures () {
126 static cv2
ZeroPos(0, 0);
128 UpdatePictures(GraphicData
, ZeroPos
, VisualEffects
|GetSpecialFlags(), GetMaxAlpha(), GetGraphicsContainerIndex(), &object::GetBitmapPos
);
132 truth
object::RandomizeSparklePos (v2
&SparklePos
, v2 BPos
, int &SparkleTime
, feuLong SeedBase
, int SpecialFlags
, int GraphicsContainerIndex
) const {
133 static int SeedModifier
= 1;
135 int ValidityArraySize
;
138 femath::SetSeed(SeedBase
+SeedModifier
);
139 if (++SeedModifier
> 0x10) SeedModifier
= 1;
141 if ((SpecialFlags
&0x38) == ST_RIGHT_ARM
) {
142 ValidityArray
= RightArmSparkleValidityArray
;
143 ValidityArraySize
= 128;
144 } else if ((SpecialFlags
&0x38) == ST_LEFT_ARM
) {
145 ValidityArray
= LeftArmSparkleValidityArray
;
146 ValidityArraySize
= 128;
147 } else if ((SpecialFlags
&0x38) == ST_GROIN
) {
148 ValidityArray
= GroinSparkleValidityArray
;
149 ValidityArraySize
= 169;
150 } else if ((SpecialFlags
&0x38) == ST_RIGHT_LEG
) {
151 ValidityArray
= RightLegSparkleValidityArray
;
152 ValidityArraySize
= 42;
153 } else if ((SpecialFlags
&0x38) == ST_LEFT_LEG
) {
154 ValidityArray
= LeftLegSparkleValidityArray
;
155 ValidityArraySize
= 45;
157 ValidityArray
= NormalSparkleValidityArray
;
158 ValidityArraySize
= 256;
161 SparklePos
= igraph::GetRawGraphic(GraphicsContainerIndex
)->RandomizeSparklePos(ValidityArray
, PossibleSparkleBuffer
, BPos
, TILE_V2
, ValidityArraySize
, GetSparkleFlags());
163 if (SparklePos
!= ERROR_V2
) {
164 SparkleTime
= RAND() % 241;
173 void object::UpdatePictures (graphicdata
&GraphicData
, v2 Position
, int SpecialFlags
, alpha MaxAlpha
,
174 int GraphicsContainerIndex
, bposretriever BitmapPosRetriever
) const
176 int AnimationFrames
= GetClassAnimationFrames();
180 int FlyAmount
= GetSpoilLevel();
181 truth Sparkling
= false, FrameNeeded
= false, SeedNeeded
= false;
182 v2 BPos
= (this->*BitmapPosRetriever
)(0);
185 if (!(SpecialFlags
&(ST_FLAMES
|ST_LIGHTNING
))) {
186 if (AllowSparkling()) {
187 int SparkleFlags
= GetSparkleFlags();
189 if (SparkleFlags
&& RandomizeSparklePos(SparklePos
, BPos
, SparkleTime
, BPos
.X
+BPos
.Y
+GetMaterialColorA(0), SpecialFlags
, GraphicsContainerIndex
)) {
191 if (AnimationFrames
<= 256) AnimationFrames
= 256;
197 if (AnimationFrames
<= 32) AnimationFrames
= 32;
199 } else if (SpecialFlags
&ST_FLAMES
) {
202 if (AnimationFrames
<= 16) AnimationFrames
= 16;
203 } else if (SpecialFlags
&ST_LIGHTNING
) {
205 if (AnimationFrames
<= 128) AnimationFrames
= 128;
208 static int SeedModifier
= 1;
209 Seed
= BPos
.X
+BPos
.Y
+GetMaterialColorA(0)+SeedModifier
+0x42;
210 if (++SeedModifier
> 0x10) SeedModifier
= 1;
213 int WobbleMask
= 0, WobbleData
= GetWobbleData();
215 if (WobbleData
&WOBBLE
) {
216 int Speed
= (WobbleData
&WOBBLE_SPEED_RANGE
)>>WOBBLE_SPEED_SHIFT
;
217 int Freq
= (WobbleData
&WOBBLE_FREQ_RANGE
)>>WOBBLE_FREQ_SHIFT
;
218 int WobbleFrames
= 512>>(Freq
+Speed
);
220 WobbleMask
= 7>>Freq
<<(6-Speed
);
221 if (AnimationFrames
<= WobbleFrames
) AnimationFrames
= WobbleFrames
;
224 ModifyAnimationFrames(AnimationFrames
);
226 int OldAnimationFrames
= GraphicData
.AnimationFrames
;
228 for (int c
= 0; c
< OldAnimationFrames
; ++c
) igraph::RemoveUser(GraphicData
.GraphicIterator
[c
]);
229 if (OldAnimationFrames
!= AnimationFrames
) {
230 if (OldAnimationFrames
) {
231 delete [] GraphicData
.Picture
;
232 delete [] GraphicData
.GraphicIterator
;
234 GraphicData
.Picture
= new bitmap
* [AnimationFrames
];
235 GraphicData
.GraphicIterator
= new tilemap::iterator
[AnimationFrames
];
237 GraphicData
.AnimationFrames
= AnimationFrames
;
239 if (!AllowRegularColors()) SpecialFlags
|= ST_DISALLOW_R_COLORS
;
242 GI
.BaseAlpha
= MaxAlpha
;
243 GI
.FileIndex
= GraphicsContainerIndex
;
244 GI
.SpecialFlags
= SpecialFlags
;
246 GI
.FlyAmount
= FlyAmount
;
247 GI
.Position
= Position
;
248 GI
.RustData
[0] = GetRustDataA();
249 GI
.RustData
[1] = GetRustDataB();
250 GI
.RustData
[2] = GetRustDataC();
251 GI
.RustData
[3] = GetRustDataD();
252 GI
.WobbleData
= WobbleData
;
254 for (int c
= 0; c
< AnimationFrames
; ++c
) {
255 GI
.Color
[0] = GetMaterialColorA(c
);
256 GI
.Color
[1] = GetMaterialColorB(c
);
257 GI
.Color
[2] = GetMaterialColorC(c
);
258 GI
.Color
[3] = GetMaterialColorD(c
);
259 Alpha
= GetAlphaA(c
);
260 GI
.Alpha
[0] = Alpha
< MaxAlpha
? Alpha
: MaxAlpha
;
261 Alpha
= GetAlphaB(c
);
262 GI
.Alpha
[1] = Alpha
< MaxAlpha
? Alpha
: MaxAlpha
;
263 Alpha
= GetAlphaC(c
);
264 GI
.Alpha
[2] = Alpha
< MaxAlpha
? Alpha
: MaxAlpha
;
265 Alpha
= GetAlphaD(c
);
266 GI
.Alpha
[3] = Alpha
< MaxAlpha
? Alpha
: MaxAlpha
;
267 v2 BPos
= (this->*BitmapPosRetriever
)(c
);
268 GI
.BitmapPosX
= BPos
.X
;
269 GI
.BitmapPosY
= BPos
.Y
;
270 if (Sparkling
&& c
> SparkleTime
&& c
< SparkleTime
+16) {
271 GI
.SparklePosX
= SparklePos
.X
;
272 GI
.SparklePosY
= SparklePos
.Y
;
273 GI
.SparkleFrame
= c
-SparkleTime
;
275 GI
.SparklePosX
= SPARKLE_POS_X_ERROR
;
281 ((SpecialFlags
&ST_LIGHTNING
) && !((c
+1)&7)) ||
282 ((WobbleData
&WOBBLE
) && !(c
&WobbleMask
)) ? c
: 0;
283 GI
.OutlineColor
= GetOutlineColor(c
);
284 GI
.OutlineAlpha
= GetOutlineAlpha(c
);
285 tilemap::iterator Iterator
= igraph::AddUser(GI
);
286 GraphicData
.GraphicIterator
[c
] = Iterator
;
287 GraphicData
.Picture
[c
] = Iterator
->second
.Bitmap
;
292 col16
object::GetMaterialColorA (int) const {
293 return MainMaterial
->GetColor();
297 truth
object::AddRustLevelDescription (festring
&String
, truth Articled
) const {
298 return MainMaterial
->AddRustLevelDescription(String
, Articled
);
302 truth
object::AddMaterialDescription (festring
&String
, truth Articled
) const {
303 //FIXME: gum solution
305 //FIXME: 'bone bone' removing
306 festring
s(MainMaterial
->GetName(Articled
));
307 festring::sizetype pos
= s
.FindLast("bone");
309 if (pos
!= festring::NPos
&& pos
== s
.GetSize()-4) {
310 while (pos
> 0 && s
[pos
-1] == ' ') --pos
;
311 s
.Erase(pos
, s
.GetSize()-pos
);
312 if (s
.GetSize() == 0) return true; // no name left
316 MainMaterial
->AddName(String
, Articled
);
323 void object::AddContainerPostFix (festring
&String
) const {
324 if (GetSecondaryMaterial()) GetSecondaryMaterial()->AddName(String
<< " full of ", false, false);
328 void object::AddLumpyPostFix (festring
&String
) const {
329 MainMaterial
->AddName(String
<< " of ", false, false);
333 alpha
object::GetAlphaA (int) const {
334 return MainMaterial
->GetAlpha();
338 void object::RandomizeVisualEffects () {
339 int AcceptedFlags
= GetOKVisualEffects();
342 SetVisualEffects((RAND()&0x7&AcceptedFlags
)|GetForcedVisualEffects());
344 SetVisualEffects(GetForcedVisualEffects());
349 void object::LoadMaterial (inputfile
&SaveFile
, material
*&Material
) {
350 SaveFile
>> Material
;
352 if (Material
->HasBe()) Enable();
353 Material
->SetMotherEntity(this);
354 game::CombineLights(Emitation
, Material
->GetEmitation());
359 int object::RandomizeMaterialConfiguration () {
360 const fearray
<sLong
>& MCC
= GetMaterialConfigChances();
362 return MCC
.Size
> 1 ? femath::WeightedRand(MCC
.Data
, GetMaterialConfigChanceSum()) : 0;
366 truth
object::AddEmptyAdjective (festring
&String
, truth Articled
) const {
367 if (GetSecondaryMaterial()) return false;
368 String
<< (Articled
? "an empty " : "empty ");
373 void object::CalculateEmitation () {
374 Emitation
= GetBaseEmitation();
375 if (MainMaterial
) game::CombineLights(Emitation
, MainMaterial
->GetEmitation());
379 truth
object::CalculateHasBe () const {
380 return MainMaterial
&& MainMaterial
->HasBe();
384 int object::GetSparkleFlags () const {
385 return MainMaterial
->IsSparkling() ? SPARKLING_A
: 0;
389 void object::InitSparkleValidityArrays () {
392 for (int y
= 0; y
< 16; ++y
)
393 for (int x
= 0; x
< 8; ++x
)
394 RightArmSparkleValidityArray
[Index
++] = v2(x
, y
);
397 for (int y
= 0; y
< 16; ++y
)
398 for (int x
= 8; x
< 16; ++x
)
399 LeftArmSparkleValidityArray
[Index
++] = v2(x
, y
);
402 for (int y
= 0; y
< 10; ++y
)
403 for (int x
= 0; x
< 16; ++x
)
404 GroinSparkleValidityArray
[Index
++] = v2(x
, y
);
405 for (int y
= 10; y
< 13; ++y
)
406 for (int x
= y
-5; x
< 20-y
; ++x
)
407 GroinSparkleValidityArray
[Index
++] = v2(x
, y
);
410 for (int y
= 10; y
< 16; ++y
)
411 for (int x
= 0; x
< 8; ++x
)
412 if ((y
!= 10 || x
< 5) && (y
!= 11 || x
< 6) && (y
!= 12 || x
< 7))
413 RightLegSparkleValidityArray
[Index
++] = v2(x
, y
);
416 for (int y
= 10; y
< 16; ++y
)
417 for (int x
= 8; x
< 16; ++x
)
418 if ((y
!= 10 || x
> 9) && (y
!= 11 || x
> 8))
419 LeftLegSparkleValidityArray
[Index
++] = v2(x
, y
);
422 for (int y
= 0; y
< 16; ++y
)
423 for (int x
= 0; x
< 16; ++x
)
424 NormalSparkleValidityArray
[Index
++] = v2(x
, y
);
428 int object::GetRustDataA () const {
429 return MainMaterial
->GetRustData();
433 truth
object::DetectMaterial (cmaterial
*Material
) const {
434 for (int c
= 0; c
< GetMaterials(); ++c
) if (GetMaterial(c
) && GetMaterial(c
)->IsSameAs(Material
)) return true;