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
12 /* Compiled through levelset.cpp */
14 lsquare
*** eyecontroller::Map
;
16 lsquare
*** pathcontroller::Map
;
17 ccharacter
* pathcontroller::Character
;
19 lsquare
*** stackcontroller::Map
;
20 lsquare
** stackcontroller::Stack
;
21 sLong
stackcontroller::StackIndex
;
22 int stackcontroller::LevelXSize
, stackcontroller::LevelYSize
;
23 v2
stackcontroller::Center
;
25 feuLong
tickcontroller::Tick
;
26 feuLong
tickcontroller::ShiftedTick
[4];
27 feuLong
tickcontroller::ShiftedQuadriTick
[4];
29 void tickcontroller::PrepareShiftedTick()
31 for(int c
= 0; c
< 4; ++c
)
33 ShiftedTick
[c
] = Tick
<< (c
<< 3);
34 ShiftedQuadriTick
[c
] = (Tick
+ 1) << (c
<< 3);
38 truth
lsquare::IsDipDestination() const { return GLTerrain
->IsDipDestination() || (OLTerrain
&& OLTerrain
->IsDipDestination()); }
40 lsquare::lsquare (level
*LevelUnder
, v2 Pos
) :
41 square(LevelUnder
, Pos
),
42 Fluid(0), Smoke(0), Rain(0), Trap(0),
43 GLTerrain(0), OLTerrain(0),
44 Memorized(0), FowMemorized(0),
46 GroundBorderPartnerTerrain(0),
47 GroundBorderPartnerInfo(0),
48 OverBorderPartnerTerrain(0),
49 OverBorderPartnerInfo(0),
50 SquarePartEmitationTick(0),
51 SquarePartLastSeen(0),
56 TemporaryEmitation(0),
57 SecondarySunLightEmitation(0),
61 Stack
= new stack(this, 0);
65 lsquare::~lsquare () {
75 delete StaticContentCache
.Bitmap
;
76 delete [] GroundBorderPartnerTerrain
;
77 delete [] OverBorderPartnerTerrain
;
85 void lsquare::SignalEmitationIncrease (col24 EmitationUpdate
) {
86 if (game::CompareLights(EmitationUpdate
, Emitation
) > 0 && !game::IsGenerating() && !(Flags
& FREEZED
)) {
87 CalculateEmitation(); // could this be optimized?
93 void lsquare::SignalEmitationDecrease (col24 EmitationUpdate
) {
94 if (game::CompareLights(EmitationUpdate
, Emitation
) >= 0 && Emitation
&& !game::IsGenerating() && !(Flags
& FREEZED
)) {
95 col24 Backup
= Emitation
;
97 if (Backup
!= Emitation
) {
99 Emitate(Emitation
, FORCE_ADD
);
105 void lsquare::CalculateEmitation () {
106 Emitation
= Stack
->GetEmitation();
108 for (int c
= 0; c
< 4; ++c
) {
109 stack
*Stack
= GetStackOfAdjacentSquare(c
);
110 if (Stack
) game::CombineLights(Emitation
, Stack
->GetSideEmitation(3 - c
));
113 if (Character
) game::CombineLights(Emitation
, Character
->GetEmitation());
114 game::CombineLights(Emitation
, GLTerrain
->GetEmitation());
115 if (OLTerrain
) game::CombineLights(Emitation
, OLTerrain
->GetEmitation());
116 game::CombineLights(Emitation
, TemporaryEmitation
);
117 for (const fluid
* F
= Fluid
; F
; F
= F
->Next
) game::CombineLights(Emitation
, F
->GetEmitation());
118 for (const rain
* R
= Rain
; R
; R
= R
->Next
) game::CombineLights(Emitation
, R
->GetEmitation());
122 void lsquare::UpdateMemorized () {
123 if (Flags
&MEMORIZED_UPDATE_REQUEST
) {
124 if (!IsDark() || CanBeFeltByPlayer()) {
125 blitdata B
= { Memorized
,
128 { TILE_SIZE
, TILE_SIZE
},
129 { NORMAL_LUMINANCE
},
132 DrawStaticContents(B
);
133 Memorized
->FastBlit(FowMemorized
);
134 B
.Bitmap
= FowMemorized
;
137 igraph::GetFOWGraphic()->NormalMaskedBlit(B
);
139 Memorized
->ClearToColor(0);
140 igraph::GetFOWGraphic()->FastBlit(FowMemorized
);
143 if (!StaticContentCache
.Bitmap
) {
144 StaticContentCache
.Bitmap
= new bitmap(TILE_V2
);
145 StaticContentCache
.Bitmap
->ActivateFastFlag();
148 UpdateStaticContentCache(Luminance
);
149 Flags
&= ~MEMORIZED_UPDATE_REQUEST
;
154 void lsquare::UpdateStaticContentCache (col24 Luminance
) const {
155 blitdata B
= { StaticContentCache
.Bitmap
,
158 { TILE_SIZE
, TILE_SIZE
},
162 Memorized
->LuminanceBlit(B
);
163 StaticContentCache
.Luminance
= Luminance
;
167 void lsquare::DrawStaticContents (blitdata
&BlitData
) const {
168 if ((BlitData
.CustomData
&ALLOW_ANIMATE
) && !StaticAnimatedEntities
&& Memorized
&& !game::GetSeeWholeMapCheatMode()) {
169 if (StaticContentCache
.Luminance
!= BlitData
.Luminance
) UpdateStaticContentCache(BlitData
.Luminance
);
170 StaticContentCache
.Bitmap
->FastBlit(BlitData
.Bitmap
, BlitData
.Dest
);
174 if (!OLTerrain
|| OLTerrain
->ShowThingsUnder()) GLTerrain
->Draw(BlitData
);
176 int GroundPartners
= (GroundBorderPartnerInfo
>>24)&15;
178 for (int c
= 0; c
< GroundPartners
; ++c
) {
179 BlitData
.CustomData
|= 8-((GroundBorderPartnerInfo
>>((c
<<1)+c
))&7);
180 GroundBorderPartnerTerrain
[c
]->Draw(BlitData
);
181 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
184 truth StackDrawn
= false;
186 if (OLTerrain
&& !IsFlyable()) {
187 if (OLTerrain
->IsTransparent() && OLTerrain
->ShowThingsUnder()) {
189 DrawStacks(BlitData
);
191 OLTerrain
->Draw(BlitData
);
194 for (const fluid
* F
= Fluid
; F
; F
= F
->Next
) F
->SimpleDraw(BlitData
);
195 if (OLTerrain
&& IsFlyable()) OLTerrain
->Draw(BlitData
);
196 if (!StackDrawn
&& Flags
& IS_TRANSPARENT
) DrawStacks(BlitData
);
197 for (const trap
* T
= Trap
; T
; T
= T
->Next
) T
->Draw(BlitData
);
199 int OverPartners
= OverBorderPartnerInfo
>> 24 & 15;
201 for (int c
= 0; c
< OverPartners
; ++c
) {
202 BlitData
.CustomData
|= 8-((OverBorderPartnerInfo
>>((c
<<1)+c
))&7);
203 OverBorderPartnerTerrain
[c
]->Draw(BlitData
);
204 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
209 void lsquare::Draw (blitdata
& BlitData
) const {
210 if ((Flags
&NEW_DRAW_REQUEST
) || AnimatedEntities
) {
211 if (!IsDark() || game::GetSeeWholeMapCheatMode()) {
212 if (game::GetSeeWholeMapCheatMode() == SHOW_MAP_IN_UNIFORM_LIGHT
|| (game::GetSeeWholeMapCheatMode() && !(Flags
& IS_TRANSPARENT
)))
213 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
215 BlitData
.Luminance
= ivanconfig::ApplyContrastTo(Luminance
);
217 DrawStaticContents(BlitData
);
219 if (Character
&& (Character
->CanBeSeenByPlayer() || game::GetSeeWholeMapCheatMode())) {
220 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
222 if (Character
->IsFlying()) {
223 for (const smoke
*S
= Smoke
; S
; S
= S
->Next
) S
->Draw(BlitData
);
224 Character
->Draw(BlitData
);
226 Character
->Draw(BlitData
);
227 for (const smoke
*S
= Smoke
; S
; S
= S
->Next
) S
->Draw(BlitData
);
229 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
231 for(const smoke
*S
= Smoke
; S
; S
= S
->Next
) S
->Draw(BlitData
);
234 for (const rain
*R
= Rain
; R
; R
= R
->Next
) if (R
->IsEnabled()) R
->Draw(BlitData
);
235 } else if (CanBeFeltByPlayer()) {
237 game::CombineLights(L
, DIM_LUMINANCE
);
238 BlitData
.Luminance
= ivanconfig::ApplyContrastTo(L
);
239 DrawStaticContents(BlitData
);
240 for (const rain
* R
= Rain
; R
; R
= R
->Next
) if (R
->IsEnabled()) R
->Draw(BlitData
);
242 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
243 if (Character
&& Character
->CanBeSeenByPlayer()) {
244 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
245 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
246 Character
->Draw(BlitData
);
247 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
251 Flags
&= ~STRONG_NEW_DRAW_REQUEST
;
255 struct emitationcontroller
: public tickcontroller
, public stackcontroller
257 static truth
Handler(int x
, int y
)
259 lsquare
* Square
= Map
[x
>> 1][y
>> 1];
260 culong SquareFlags
= Square
->Flags
;
262 if(SquareFlags
& PERFECTLY_QUADRI_HANDLED
)
263 return SquareFlags
& ALLOW_EMITATION_CONTINUE
;
265 if(SquareFlags
& IS_TRANSPARENT
)
266 return ProcessSquare(x
>> 1, y
>> 1, Square
);
268 if(!(SquareFlags
& IN_SQUARE_STACK
))
270 Square
->Flags
|= IN_SQUARE_STACK
;
271 Stack
[StackIndex
++] = Square
;
274 cint SquarePartIndex
= (x
& 1) + ((y
& 1) << 1);
275 Square
->SquarePartEmitationTick
=
276 (Square
->SquarePartEmitationTick
& ~SquarePartTickMask
[SquarePartIndex
]) | ShiftedTick
[SquarePartIndex
];
280 static int ProcessSquare(int X
, int Y
, lsquare
* Square
)
282 Stack
[StackIndex
++] = Square
;
283 culong SquareFlags
= Square
->Flags
;
284 cint MaxE
= MaxLuxTable
[X
- EmitterPosXMinus16
][Y
- EmitterPosYMinus16
];
286 if(MaxE
>= LIGHT_BORDER
&& (SquareFlags
& INSIDE
|| (!(ID
& SECONDARY_SUN_LIGHT
) && MaxE
> MinNightAmbientLuminanceElement
)))
288 Square
->Flags
|= ALLOW_EMITATION_CONTINUE
| PERFECTLY_QUADRI_HANDLED
;
293 Square
->Flags
= (SquareFlags
& ~ALLOW_EMITATION_CONTINUE
) | PERFECTLY_QUADRI_HANDLED
;
297 static feuLong
& GetTickReference(int X
, int Y
)
299 return Map
[X
][Y
]->SquarePartEmitationTick
;
301 static void ProcessStack()
303 for(sLong c1
= 0; c1
< StackIndex
; ++c1
)
305 lsquare
* Square
= Stack
[c1
];
306 culong SquareTick
= Square
->SquarePartEmitationTick
;
309 for(int c2
= 0; c2
< 4; ++c2
) {
310 if ((SquareTick
& SquarePartTickMask
[c2
]) == ShiftedTick
[c2
]) {
311 TempID
|= 1 << EMITTER_SQUARE_PART_SHIFT
<< c2
;
315 Square
->Flags
&= ~(IN_SQUARE_STACK
|PERFECTLY_QUADRI_HANDLED
);
316 v2 Pos
= Square
->Pos
;
317 int XVal
= Pos
.X
- EmitterPosXMinus16
;
318 int YVal
= Pos
.Y
- EmitterPosYMinus16
;
320 if (MaxLuxTable
[XVal
][YVal
] >= LIGHT_BORDER
)
321 Square
->AlterLuminance(TempID
, MakeRGB24(RedLuxTable
[XVal
][YVal
], GreenLuxTable
[XVal
][YVal
], BlueLuxTable
[XVal
][YVal
]));
325 static int MinNightAmbientLuminanceElement
;
326 static int EmitterPosXMinus16
;
327 static int EmitterPosYMinus16
;
328 static uChar
** MaxLuxTable
;
329 static uChar
** RedLuxTable
;
330 static uChar
** GreenLuxTable
;
331 static uChar
** BlueLuxTable
;
334 feuLong
emitationcontroller::ID
;
335 int emitationcontroller::MinNightAmbientLuminanceElement
;
336 int emitationcontroller::EmitterPosXMinus16
;
337 int emitationcontroller::EmitterPosYMinus16
;
338 uChar
** emitationcontroller::MaxLuxTable
;
339 uChar
** emitationcontroller::RedLuxTable
;
340 uChar
** emitationcontroller::GreenLuxTable
;
341 uChar
** emitationcontroller::BlueLuxTable
;
343 void lsquare::Emitate(col24 Emitation
, feuLong IDFlags
)
345 if(game::IsDark(Emitation
))
348 int Radius
= game::CalculateMinimumEmitationRadius(Emitation
);
353 stackcontroller::Map
= GetLevel()->GetMap();
354 stackcontroller::Stack
= GetLevel()->GetSquareStack();
355 stackcontroller::StackIndex
= 0;
356 tickcontroller::Tick
= game::IncreaseSquarePartEmitationTicks();
357 tickcontroller::PrepareShiftedTick();
358 emitationcontroller::ID
= MakeEmitterID(Pos
) | IDFlags
;
359 emitationcontroller::MinNightAmbientLuminanceElement
= GetMinColor24(GetLevel()->GetNightAmbientLuminance());
360 emitationcontroller::EmitterPosXMinus16
= Pos
.X
- 16;
361 emitationcontroller::EmitterPosYMinus16
= Pos
.Y
- 16;
362 emitationcontroller::MaxLuxTable
= game::GetLuxTable()[GetMaxColor24(Emitation
)];
363 emitationcontroller::RedLuxTable
= game::GetLuxTable()[GetRed24(Emitation
)];
364 emitationcontroller::GreenLuxTable
= game::GetLuxTable()[GetGreen24(Emitation
)];
365 emitationcontroller::BlueLuxTable
= game::GetLuxTable()[GetBlue24(Emitation
)];
366 mapmath
<emitationcontroller
>::DoQuadriArea(Pos
.X
, Pos
.Y
,
368 GetLevel()->GetXSize(),
369 GetLevel()->GetYSize());
370 emitationcontroller::ProcessStack();
373 struct noxifycontroller
: public stackcontroller
375 static truth
Handler(int x
, int y
)
377 if(x
>= 0 && y
>= 0 && x
< LevelXSize
&& y
< LevelYSize
)
379 lsquare
* Square
= Map
[x
][y
];
381 if(Square
->SquarePartEmitationTick
!= Tick
)
383 Square
->SquarePartEmitationTick
= Tick
;
384 return Square
->NoxifyEmitter(ID
);
390 static int GetStartX(int) { return Center
.X
; }
391 static int GetStartY(int) { return Center
.Y
; }
396 feuLong
noxifycontroller::ID
;
397 feuLong
noxifycontroller::Tick
;
399 void lsquare::Noxify(col24 Emitation
, feuLong IDFlags
)
401 if(game::IsDark(Emitation
))
404 int Radius
= game::CalculateMinimumEmitationRadius(Emitation
);
409 stackcontroller::Map
= GetLevel()->GetMap();
410 stackcontroller::LevelXSize
= GetLevel()->GetXSize();
411 stackcontroller::LevelYSize
= GetLevel()->GetYSize();
412 stackcontroller::Center
= Pos
;
413 noxifycontroller::ID
= MakeEmitterID(Pos
) | IDFlags
;
414 noxifycontroller::Tick
= game::IncreaseSquarePartEmitationTicks();
415 NoxifyEmitter(noxifycontroller::ID
);
416 mapmath
<noxifycontroller
>::DoArea();
419 truth
lsquare::NoxifyEmitter(feuLong ID
)
421 emittervector::iterator i
, End
= Emitter
.end();
423 for(i
= Emitter
.begin(); i
!= End
; ++i
)
424 if(!((i
->ID
^ ID
) & (EMITTER_IDENTIFIER_BITS
|SECONDARY_SUN_LIGHT
)))
426 RemoveLuminance(i
->Emitation
);
427 Swap(*i
, Emitter
.back());
435 void lsquare::AlterLuminance(feuLong ID
, col24 NewLuminance
)
437 emittervector::iterator i
, End
= Emitter
.end();
439 if(!(ID
& FORCE_ADD
))
440 for(i
= Emitter
.begin(); i
!= End
; ++i
)
441 if(!((i
->ID
^ ID
) & (EMITTER_IDENTIFIER_BITS
|SECONDARY_SUN_LIGHT
)))
445 if(i
->Emitation
!= NewLuminance
)
446 ChangeLuminance(i
->Emitation
, NewLuminance
);
451 Emitter
.push_back(emitter(ID
, 0));
452 ChangeLuminance(Emitter
.back().Emitation
, NewLuminance
);
455 void lsquare::AddSunLightEmitter(feuLong ID
)
457 sunemittervector::iterator i
, End
= SunEmitter
.end();
459 for(i
= SunEmitter
.begin(); i
!= End
; ++i
)
460 if(!((*i
^ ID
) & EMITTER_IDENTIFIER_BITS
))
462 if(ID
& ~*i
& RE_SUN_EMITATED
) *i
&= ~EMITTER_SHADOW_BITS
;
465 Swap(*i
, SunEmitter
.front());
469 SunEmitter
.push_back(ID
);
472 truth
lsquare::Open(character
* Opener
)
474 return GetStack()->Open(Opener
) || (OLTerrain
&& OLTerrain
->Open(Opener
));
477 truth
lsquare::Close(character
* Closer
)
479 if(!GetStack()->GetItems() && !Character
)
480 return OLTerrain
&& OLTerrain
->Close(Closer
);
483 ADD_MESSAGE("There's something in the way...");
488 void lsquare::Save(outputfile
& SaveFile
) const
490 Stack
->Save(SaveFile
); // This must be before square::Save! (Note: This comment is years old. It's probably obsolete)
491 square::Save(SaveFile
);
493 SaveFile
<< GLTerrain
<< OLTerrain
;
494 SaveFile
<< Emitter
<< SunEmitter
;
495 SaveFile
<< Emitation
<< Engraved
<< Luminance
;
496 SaveFile
<< SmokeAlphaSum
<< (uChar
)Flags
<< Memorized
;
497 SaveFile
<< SecondarySunLightEmitation
;
498 SaveFile
<< (uChar
)RoomIndex
;
499 SaveFile
<< SunLightLuminance
;
500 SaveLinkedList(SaveFile
, Fluid
);
501 SaveLinkedList(SaveFile
, Smoke
);
502 SaveLinkedList(SaveFile
, Rain
);
503 SaveLinkedList(SaveFile
, Trap
);
506 void lsquare::Load(inputfile
& SaveFile
)
508 Stack
->Load(SaveFile
); // This must be before square::Load! (Note: This comment is years old. It's probably obsolete)
509 Stack
->SetMotherSquare(this);
510 square::Load(SaveFile
);
512 SaveFile
>> GLTerrain
>> OLTerrain
;
513 SaveFile
>> Emitter
>> SunEmitter
;
514 SaveFile
>> Emitation
>> Engraved
>> Luminance
;
515 SaveFile
>> SmokeAlphaSum
>> (uChar
&)Flags
>> Memorized
;
516 Flags
&= INSIDE
|DESCRIPTION_CHANGE
; //only these flags are loaded
517 Flags
|= MEMORIZED_UPDATE_REQUEST
;
518 SecondarySunLightEmitation
= ReadType(col24
, SaveFile
);
519 RoomIndex
= ReadType(uChar
, SaveFile
);
520 SunLightLuminance
= ReadType(col24
, SaveFile
);
521 LoadLinkedList(SaveFile
, Fluid
);
522 LoadLinkedList(SaveFile
, Smoke
);
523 LoadLinkedList(SaveFile
, Rain
);
524 LoadLinkedList(SaveFile
, Trap
);
525 CalculateIsTransparent();
528 FowMemorized
= new bitmap(TILE_V2
);
529 FowMemorized
->ActivateFastFlag();
530 Memorized
->FastBlit(FowMemorized
);
531 blitdata B
= { FowMemorized
,
534 { TILE_SIZE
, TILE_SIZE
},
539 igraph::GetFOWGraphic()->NormalMaskedBlit(B
);
543 void lsquare::CalculateLuminance()
545 Luminance
= AmbientLuminance
;
546 emittervector::const_iterator i
, End
= Emitter
.end();
548 if(Flags
& IS_TRANSPARENT
)
550 game::CombineLights(Luminance
, SunLightLuminance
);
552 for(i
= Emitter
.begin(); i
!= End
; ++i
)
553 game::CombineLights(Luminance
, i
->Emitation
);
557 feuLong BitMask
= 0, LOSTick
= game::GetLOSTick();
559 for(int c
= 0; c
< 4; ++c
)
560 if((SquarePartLastSeen
>> (c
<< 3) & 0xFF) >= LOSTick
)
561 BitMask
|= 1 << EMITTER_SQUARE_PART_SHIFT
<< c
;
563 CalculateSunLightLuminance(BitMask
);
564 game::CombineLights(Luminance
, SunLightLuminance
);
566 for(i
= Emitter
.begin(); i
!= End
; ++i
)
567 if(BitMask
& i
->ID
) game::CombineLights(Luminance
, i
->Emitation
);
571 void lsquare::AddCharacter(character
* Guy
)
574 ABORT("Overgrowth of square population detected!");
577 SignalEmitationIncrease(Guy
->GetEmitation());
578 Flags
|= STRONG_NEW_DRAW_REQUEST
;
580 if (Guy
->IsAnimated()) IncAnimatedEntities();
582 SignalPossibleTransparencyChange();
584 if (Guy
->IsPlayer() || (Guy
->CanBeSeenByPlayer(true) && CanBeSeenByPlayer())) {
589 void lsquare::Clean()
594 void lsquare::RemoveCharacter()
598 character
* Backup
= Character
;
600 if(Backup
->IsAnimated())
601 DecAnimatedEntities();
604 SignalEmitationDecrease(Backup
->GetEmitation());
605 Flags
|= STRONG_NEW_DRAW_REQUEST
;
606 SignalPossibleTransparencyChange();
611 void lsquare::UpdateMemorizedDescription (truth Cheat
) {
612 if ((Flags
& DESCRIPTION_CHANGE
) || Cheat
) {
613 if (!IsDark() || Cheat
) {
614 MemorizedDescription
.Empty();
616 if (!OLTerrain
|| (OLTerrain
->IsTransparent() && OLTerrain
->ShowThingsUnder() && !OLTerrain
->IsWall())) {
617 truth Anything
= false;
619 if (OLTerrain
&& OLTerrain
->GetNameSingular().GetSize()) {
620 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
624 if (Flags
& IS_TRANSPARENT
) {
625 itemvectorvector PileVector
;
626 GetStack()->Pile(PileVector
, PLAYER
, CENTER
);
628 if (PileVector
.size()) {
629 if (Anything
) MemorizedDescription
<< " and ";
631 if (PileVector
.size() == 1)
632 PileVector
[0][0]->AddName(MemorizedDescription
, INDEFINITE
, PileVector
[0].size());
634 MemorizedDescription
<< "many items";
636 MemorizedDescription
<< " on ";
638 } else if (Anything
) {
639 MemorizedDescription
<< " on ";
642 GLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
644 GetSideItemDescription(SideItems
, Cheat
);
646 if (!SideItems
.IsEmpty()) MemorizedDescription
<< " and " << SideItems
;
648 if (Anything
) MemorizedDescription
<< " on ";
650 GLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
653 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
656 if (FluidIsVisible()) DisplayFluidInfo(MemorizedDescription
);
658 DisplayTrapInfo(MemorizedDescription
);
660 if (Cheat
) MemorizedDescription
<< " (pos " << Pos
.X
<< ':' << Pos
.Y
<< ")";
661 } else if (CanBeFeltByPlayer()) {
662 MemorizedDescription
.Empty();
663 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
665 if (FluidIsVisible()) DisplayFluidInfo(MemorizedDescription
);
667 DisplayTrapInfo(MemorizedDescription
);
669 MemorizedDescription
= CONST_S("darkness");
672 Flags
&= ~DESCRIPTION_CHANGE
;
676 void lsquare::GetSideItemDescription(festring
& String
, truth Cheat
) const
680 for(int c
= 0; c
< 4; ++c
)
682 stack
* Stack
= GetStackOfAdjacentSquare(c
);
686 ? Stack
->GetSideItems(3 - c
)
687 : Stack
->GetVisibleSideItems(PLAYER
, 3 - c
);
691 String
<< "many items on the wall";
694 for(int c
= 0; c
< 4; ++c
)
696 stack
* Stack
= GetStackOfAdjacentSquare(c
);
698 if (Stack
&& ((Cheat
&& Stack
->GetSideItems(3 - c
)) || (!Cheat
&& Stack
->GetVisibleSideItems(PLAYER
, 3 - c
))))
699 Stack
->GetBottomSideItem(PLAYER
, 3 - c
, Cheat
)->AddName(String
, INDEFINITE
);
702 String
<< " on the wall";
706 truth
lsquare::BeKicked(character
* Kicker
, item
* Boot
, bodypart
* Leg
, double KickDamage
, double KickToHitValue
, int Success
, int Direction
, truth Critical
, truth ForceHit
)
712 GetCharacter()->BeKicked(Kicker
, Boot
, Leg
, Pos
, KickDamage
, KickToHitValue
, Success
, Direction
, Critical
, ForceHit
);
719 GetLevel()->GetRoom(RoomIndex
)->KickSquare(Kicker
, this);
721 GetStack()->BeKicked(Kicker
, int(KickDamage
), Direction
);
724 GetOLTerrain()->BeKicked(Kicker
, int(KickDamage
* (100 + Success
) / 100), Direction
);
729 truth
lsquare::CanBeDug() const
731 if((!GetPos().X
|| !GetPos().Y
|| GetPos().X
== GetLevel()->GetXSize() - 1 || GetPos().Y
== GetLevel()->GetYSize() - 1) && !*GetLevel()->GetLevelScript()->IsOnGround())
733 ADD_MESSAGE("Somehow you feel that by digging this square you would collapse the whole dungeon.");
740 void lsquare::ChangeLTerrain(glterrain
* NewGround
, olterrain
* NewOver
)
742 ChangeGLTerrain(NewGround
);
743 ChangeOLTerrain(NewOver
);
746 void lsquare::ChangeGLTerrain(glterrain
* NewGround
)
748 if(GLTerrain
->IsAnimated())
749 DecStaticAnimatedEntities();
751 truth WasUsingBorderTiles
= GLTerrain
->UseBorderTiles();
753 GLTerrain
= NewGround
;
754 NewGround
->SetLSquareUnder(this);
755 Flags
|= NEW_DRAW_REQUEST
;
756 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
757 CalculateGroundBorderPartners();
758 SendMemorizedUpdateRequest();
760 if(WasUsingBorderTiles
|| NewGround
->UseBorderTiles())
761 RequestForGroundBorderPartnerUpdates();
763 if(NewGround
->IsAnimated())
764 IncStaticAnimatedEntities();
767 void lsquare::ChangeOLTerrain(olterrain
* NewOver
)
769 if(OLTerrain
&& OLTerrain
->IsAnimated())
770 DecStaticAnimatedEntities();
772 truth WasUsingBorderTiles
= OLTerrain
&& OLTerrain
->UseBorderTiles();
775 Flags
|= NEW_DRAW_REQUEST
;
776 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
777 CalculateOverBorderPartners();
778 CalculateIsTransparent();
779 SendMemorizedUpdateRequest();
781 if(WasUsingBorderTiles
|| (NewOver
&& NewOver
->UseBorderTiles()))
782 RequestForOverBorderPartnerUpdates();
786 NewOver
->SetLSquareUnder(this);
788 if(NewOver
->IsAnimated())
789 IncStaticAnimatedEntities();
793 void lsquare::SetLTerrain(glterrain
* NewGround
, olterrain
* NewOver
)
795 GLTerrain
= NewGround
;
796 NewGround
->SetLSquareUnder(this);
798 if(NewGround
->IsAnimated())
799 IncStaticAnimatedEntities();
805 NewOver
->SetLSquareUnder(this);
807 if(NewOver
->IsAnimated())
808 IncStaticAnimatedEntities();
810 if(!NewOver
->IsTransparent())
811 Flags
&= ~IS_TRANSPARENT
;
814 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
818 void lsquare::ApplyScript (const squarescript
*SquareScript
, room
*Room
) {
819 if (SquareScript
->AttachRequired()) GetLevel()->AddToAttachQueue(Pos
);
821 int EntryIndex
= SquareScript
->GetEntryIndex();
823 if (EntryIndex
!= NO_ENTRY
) GetLevel()->SetEntryPos(EntryIndex
, Pos
);
825 const contentscript
<character
> *CharacterScript
= SquareScript
->GetCharacter();
827 if (CharacterScript
) {
828 character
*Char
= CharacterScript
->Instantiate();
831 Char
->SetGenerationDanger(GetLevel()->GetDifficulty());
832 if (!Char
->GetTeam()) Char
->SetTeam(game::GetTeam(*GetLevel()->GetLevelScript()->GetTeamDefault()));
833 if (CharacterScript
->GetFlags() & IS_LEADER
) Char
->GetTeam()->SetLeader(Char
);
834 Char
->PutToOrNear(Pos
);
835 Char
->CreateHomeData();
836 if (Room
&& CharacterScript
->GetFlags() & IS_MASTER
) Room
->SetMasterID(Char
->GetID());
840 const fearray
<contentscript
<item
> >* Items
= SquareScript
->GetItems();
843 for (uInt c1
= 0; c1
< Items
->Size
; ++c1
) {
844 const interval
*TimesPtr
= Items
->Data
[c1
].GetTimes();
845 int Times
= TimesPtr
? TimesPtr
->Randomize() : 1;
847 for (int c2
= 0; c2
< Times
; ++c2
) {
848 item
*Item
= Items
->Data
[c1
].Instantiate();
851 int SquarePosition
= Items
->Data
[c1
].GetSquarePosition();
853 if (SquarePosition
!= CENTER
) Item
->SignalSquarePositionChange(SquarePosition
);
854 GetStack()->AddItem(Item
);
855 Item
->SpecialGenerationHandler();
861 const contentscript
<glterrain
> *GLTerrainScript
= SquareScript
->GetGTerrain();
863 if (GLTerrainScript
) {
864 GetLevel()->AddFlag(Pos
, FORBIDDEN
);
865 ChangeGLTerrain(GLTerrainScript
->Instantiate());
867 if (GLTerrainScript
->IsInside()) {
868 if (*GLTerrainScript
->IsInside()) Flags
|= INSIDE
; else Flags
&= ~INSIDE
;
872 const contentscript
<olterrain
> *OLTerrainScript
= SquareScript
->GetOTerrain();
874 if (OLTerrainScript
) {
875 olterrain
*terra
= OLTerrainScript
->Instantiate();
878 GetLevel()->AddFlag(Pos
, FORBIDDEN
);
879 // check for random altars
880 if (terra
->AcceptsOffers()) {
881 //FIXME: make IsAltar()? for now only altars can accept offers
882 if (Room
->GetDivineMaster()) {
883 //if (Terrain->GetConfig() != RoomClass->GetDivineMaster()) ABORT("Random altar in room with DivineMaster!");
884 if (terra
->GetConfig() != Room
->GetDivineMaster()) {
886 //fprintf(stderr, "forced altar!\n");
888 terra
= altar::Spawn(Room
->GetDivineMaster());
891 // no DivineMaster yet, assign it
892 const fearray
<int> *am
= Room
->GetScript()->GetAllowedDivineMasters();
894 if (am
&& am
->Size
> 0) {
895 int Owner
= am
->GetRandomElement();
898 fprintf(stderr, "AllowedDivineMasters:");
899 for (uInt f = 0; f < am->Size; ++f) fprintf(stderr, " %d", (*am)[f]);
900 fprintf(stderr, "\n");
903 if (Owner
< 1 || Owner
> GODS
) ABORT("Your god is a bad god!");
905 if (terra
->GetConfig() != Owner
) {
906 //fprintf(stderr, "recreating altar %d --> %d\n", terra->GetConfig(), Owner);
908 terra
= altar::Spawn(Owner
);
910 //fprintf(stderr, "spawned altar in room w/o divine master, assigning %d\n", terra->GetConfig());
913 //fprintf(stderr, "spawned altar in room w/o divine master, assigning %d\n", terra->GetConfig());
915 Room
->SetDivineMaster(terra
->GetConfig());
919 ChangeOLTerrain(terra
);
921 //fprintf(stderr, "WARNING: LTerra spawn error [lsquare] in file %s, line %d\n", OLTerrainScript->GetSrcFile().CStr(), OLTerrainScript->GetSrcLine());
928 truth
lsquare::CanBeSeenByPlayer (truth IgnoreDarkness
) const {
929 return ((IgnoreDarkness
|| !IsDark()) && LastSeen
== game::GetLOSTick());
933 truth
lsquare::CanBeSeenFrom (v2 FromPos
, sLong MaxDistance
, truth IgnoreDarkness
) const {
934 if ((Pos
-FromPos
).GetLengthSquare() <= MaxDistance
&& (IgnoreDarkness
|| !IsDark())) {
935 if (Character
&& Character
->IsPlayer() && GetNearLSquare(FromPos
)->CanBeSeenByPlayer(true)) {
938 eyecontroller::Map
= GetLevel()->GetMap();
939 return mapmath
<eyecontroller
>::DoLine(FromPos
.X
, FromPos
.Y
, GetPos().X
, GetPos().Y
, SKIP_FIRST
|LINE_BOTH_DIRS
);
945 void lsquare::StepOn (character
* Stepper
, lsquare
** ComingFrom
) {
947 truth WasInRoom
= false;
950 for (int c
= 0; c
< Stepper
->GetSquaresUnder(); ++c
) {
951 if (ComingFrom
[c
]->GetRoomIndex() == RoomIndex
) {
958 if (!WasInRoom
) GetLevel()->GetRoom(RoomIndex
)->Enter(Stepper
);
961 GLTerrain
->StepOn(Stepper
);
964 OLTerrain
->StepOn(Stepper
);
966 if (Stepper
->DestroysWalls() && OLTerrain
->WillBeDestroyedBy(Stepper
)) {
967 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s destroys %s.", Stepper
->CHAR_NAME(DEFINITE
), OLTerrain
->CHAR_NAME(DEFINITE
));
969 Stepper
->EditAP(-100);
970 OLTerrain
->BeDestroyed();
975 std::vector
<trap
*> TrapVector
;
977 for (trap
* T
= Trap
; T
; T
= T
->Next
) TrapVector
.push_back(T
);
979 for (c
= 0; c
< TrapVector
.size(); ++c
) {
980 if (TrapVector
[c
]->Exists()) {
981 TrapVector
[c
]->StepOnEffect(Stepper
);
982 if (!Stepper
->IsEnabled()) return;
986 if (!Stepper
->IsFlying()) {
987 std::vector
<fluid
*> FluidVector
;
989 for (fluid
* F
= Fluid
; F
; F
= F
->Next
) FluidVector
.push_back(F
);
991 for (c
= 0; c
< FluidVector
.size(); ++c
) {
992 if (FluidVector
[c
]->Exists()) {
993 FluidVector
[c
]->StepOnEffect(Stepper
);
994 if (!Stepper
->IsEnabled()) return;
998 GetStack()->CheckForStepOnEffect(Stepper
);
1003 void lsquare::ReceiveVomit (character
*Who
, liquid
*Liquid
) {
1004 if (!GetOLTerrain() || !GetOLTerrain()->ReceiveVomit(Who
, Liquid
)) {
1005 SpillFluid(Who
, Liquid
);
1006 if (RoomIndex
) GetRoom()->ReceiveVomit(Who
);
1011 void lsquare::SetTemporaryEmitation (col24 What
) {
1012 col24 Old
= TemporaryEmitation
;
1013 TemporaryEmitation
= 0;
1014 SignalEmitationDecrease(Old
);
1015 TemporaryEmitation
= What
;
1016 SignalEmitationIncrease(What
);
1020 void lsquare::ChangeOLTerrainAndUpdateLights(olterrain
* NewTerrain
)
1022 truth WasTransparent
= Flags
& IS_TRANSPARENT
, Noxified
= false;
1023 emittervector EmitterBackup
;
1025 if(WasTransparent
&& NewTerrain
&& !NewTerrain
->IsTransparent())
1027 EmitterBackup
= Emitter
;
1028 GetLevel()->ForceEmitterNoxify(EmitterBackup
);
1032 sLong OldEmit
= OLTerrain
? OLTerrain
->GetEmitation() : 0;
1033 ChangeOLTerrain(NewTerrain
);
1036 SignalEmitationIncrease(NewTerrain
->GetEmitation());
1038 SignalEmitationDecrease(OldEmit
);
1039 GetStack()->DropSideItems();
1041 if(!IsFlyable() && Smoke
)
1043 DecAnimatedEntities();
1045 for(smoke
* S
= Smoke
; S
; S
= S
->Next
)
1052 if(!WasTransparent
== !!CalculateIsTransparent())
1055 GetLevel()->ForceEmitterEmitation(EmitterBackup
, SunEmitter
, FORCE_ADD
);
1057 GetLevel()->ForceEmitterEmitation(Emitter
, SunEmitter
);
1059 CalculateLuminance();
1061 if(LastSeen
== game::GetLOSTick())
1062 game::SendLOSUpdateRequest();
1066 void lsquare::DrawParticles(sLong Color
, truth DrawHere
)
1068 if(GetPos().X
< game::GetCamera().X
1069 || GetPos().Y
< game::GetCamera().Y
1070 || GetPos().X
>= game::GetCamera().X
+ game::GetScreenXSize()
1071 || GetPos().Y
>= game::GetCamera().Y
+ game::GetScreenYSize()
1072 || !CanBeSeenByPlayer(true)
1073 || Color
== TRANSPARENT_COLOR
)
1076 clock_t StartTime
= clock();
1079 game::DrawEverythingNoBlit();
1081 if(Color
& RANDOM_COLOR
)
1082 Color
= MakeRGB16(60 + RAND() % 190, 60 + RAND() % 190, 60 + RAND() % 190);
1084 v2 Pos
= game::CalculateScreenCoordinates(GetPos());
1086 for(int c
= 0; c
< 10; ++c
)
1087 DOUBLE_BUFFER
->PutPixel(Pos
+ v2(1 + RAND() % 14, 1 + RAND() % 14), Color
);
1089 Flags
|= STRONG_NEW_DRAW_REQUEST
; // Clean the pixels from the screen afterwards
1093 graphics::BlitDBToScreen();
1094 while(clock() - StartTime
< 0.02 * CLOCKS_PER_SEC
);
1098 truth
lsquare::DipInto(item
* Thingy
, character
* Dipper
)
1100 if(IsDipDestination())
1102 room
* Room
= GetRoom();
1104 if(Room
&& Room
->HasDipHandler() && !Room
->Dip(Dipper
))
1107 return (GLTerrain
->IsDipDestination() && GLTerrain
->DipInto(Thingy
, Dipper
)) || (OLTerrain
&& OLTerrain
->IsDipDestination() && OLTerrain
->DipInto(Thingy
, Dipper
));
1111 if(Dipper
->IsPlayer())
1112 ADD_MESSAGE("You cannot dip %s on that square!", Thingy
->CHAR_NAME(DEFINITE
));
1118 // return true if key fits someplace
1120 truth
lsquare::TryKey(item
* Key
, character
* Applier
)
1122 if(GetOLTerrain() && GetOLTerrain()->TryKey(Key
, Applier
))
1125 if((!GetOLTerrain() || !GetOLTerrain()->HasKeyHole()) && !GetStack()->TryKey(Key
, Applier
))
1127 ADD_MESSAGE("There's no place here to put the key in!");
1134 void lsquare::SignalSeen(feuLong Tick
)
1136 if(LastSeen
< Tick
- 2)
1137 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1139 Flags
&= ~(IN_SQUARE_STACK
|PERFECTLY_QUADRI_HANDLED
);
1142 if(!(Flags
& IS_TRANSPARENT
))
1144 col24 OldLuminance
= Luminance
;
1145 CalculateLuminance();
1147 if(OldLuminance
!= Luminance
)
1149 Flags
|= NEW_DRAW_REQUEST
;
1151 if (IsDark() != game::IsDark(OldLuminance
))
1152 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
1158 v2 Dist
= Pos
- PLAYER
->GetPos();
1160 if(abs(Dist
.X
) > 1 || abs(Dist
.Y
) > 1)
1171 UpdateMemorizedDescription();
1174 Character
->CheckIfSeen();
1178 #define DIMMED_LUMINANCE 0x656565
1180 void lsquare::DrawMemorized (blitdata
&BlitData
) const {
1182 Flags
&= ~STRONG_NEW_DRAW_REQUEST
;
1183 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
1186 blitdata nbd
= BlitData
;
1187 if (nbd
.Luminance
== NORMAL_LUMINANCE
) nbd
.Luminance
= DIMMED_LUMINANCE
;
1188 FowMemorized
->LuminanceBlit(nbd
);
1190 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
1193 ccharacter
*C
= Character
;
1195 if (C
&& C
->CanBeSeenByPlayer()) {
1196 BlitData
.CustomData
|= C
->GetSquareIndex(Pos
);
1198 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
1203 void lsquare::DrawMemorizedCharacter (blitdata
&BlitData
) const {
1204 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
1207 blitdata nbd
= BlitData
;
1208 if (nbd
.Luminance
== NORMAL_LUMINANCE
) nbd
.Luminance
= DIMMED_LUMINANCE
;
1209 FowMemorized
->LuminanceBlit(nbd
);
1211 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
1214 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
1215 Character
->Draw(BlitData
);
1216 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
1217 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1221 truth
lsquare::IsDangerous(ccharacter
* Who
) const
1224 ((!Who
->IsFlying() && (Stack
->IsDangerous(Who
) || HasDangerousFluids(Who
))) ||
1225 IsDangerousToBreathe(Who
) || HasDangerousTraps(Who
));
1228 truth
lsquare::IsScary(ccharacter
* Who
) const
1230 return IsScaryToBreathe(Who
);
1233 stack
* lsquare::GetStackOfAdjacentSquare(int I
) const
1235 lsquare
* Square
= 0;
1237 if (I
== LEFT
) Square
= NeighbourLSquare
[3];
1238 else if (I
== DOWN
) Square
= NeighbourLSquare
[6];
1239 else if (I
== UP
) Square
= NeighbourLSquare
[1];
1240 else if (I
== RIGHT
) Square
= NeighbourLSquare
[4];
1242 return (Square
? Square
->Stack
: 0);
1245 void lsquare::SendMemorizedUpdateRequest()
1247 if(!(Flags
& FREEZED
))
1249 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
1251 if(!game::IsGenerating() && (CanBeSeenByPlayer() || CanBeFeltByPlayer()))
1253 if(!Memorized
) CreateMemorized();
1256 UpdateMemorizedDescription();
1261 truth
lsquare::KickAnyoneStandingHereAway (truth allowTeleport
) {
1263 character
*Backup
= Character
;
1264 v2 oldpos
= Backup
->GetPos(); // largecreatures should be returned to their exact place
1266 if (allowTeleport
) {
1267 if (!Backup
->PutNear(Pos
, true)) {
1269 //Backup->Die(nullptr, CONST_S(""), DISALLOW_MSG|FORBID_REINCARNATION);
1272 if (Character
!= Backup
) ABORT("lsquare::KickAnyoneStandingHereAway: oops no0!");
1274 Backup
->PutTo(oldpos
);
1277 Backup
->ReceiveDamage(0, 100000000, PHYSICAL_DAMAGE
); // kill it
1278 Backup
->CheckDeath(CONST_S("Killed by a fatal accident"), nullptr, FORCE_DEATH
|FORBID_REINCARNATION
/*|DISALLOW_CORPSE*/);
1283 if (!Backup
->PutNearNoTeleport(Pos
)) {
1286 if (Character
!= Backup
) ABORT("lsquare::KickAnyoneStandingHereAway: oops no1!");
1288 Backup
->PutTo(oldpos
);
1296 outputfile
& operator<<(outputfile
& SaveFile
, const emitter
& Emitter
)
1298 SaveFile
.Write(reinterpret_cast<cchar
*>(&Emitter
), sizeof(Emitter
));
1302 inputfile
& operator>>(inputfile
& SaveFile
, emitter
& Emitter
)
1304 SaveFile
.Read(reinterpret_cast<char*>(&Emitter
), sizeof(Emitter
));
1308 void lsquare::AddItem(item
* Item
)
1310 Stack
->AddItem(Item
);
1313 v2
lsquare::DrawLightning(v2 StartPos
, sLong Color
, int Direction
, truth DrawHere
)
1315 if(GetPos().X
< game::GetCamera().X
1316 || GetPos().Y
< game::GetCamera().Y
1317 || GetPos().X
>= game::GetCamera().X
+ game::GetScreenXSize()
1318 || GetPos().Y
>= game::GetCamera().Y
+ game::GetScreenYSize()
1319 || !CanBeSeenByPlayer(true))
1322 case 1: return v2(RAND() & 15, 15);
1323 case 3: return v2(15, RAND() & 15);
1324 case 4: return v2(0, RAND() & 15);
1325 case 6: return v2(RAND() & 15, 0);
1326 default: return StartPos
;
1329 clock_t StartTime
= clock();
1330 bitmap
Empty(TILE_V2
, TRANSPARENT_COLOR
);
1331 Empty
.ActivateFastFlag();
1333 if(Color
& RANDOM_COLOR
)
1334 Color
= MakeRGB16(60 + RAND() % 190, 60 + RAND() % 190, 60 + RAND() % 190);
1336 if(Direction
!= YOURSELF
)
1338 while(!Empty
.CreateLightning(StartPos
, game::GetMoveVector(Direction
), 16, Color
));
1343 case 0: EndPos
= v2(0, 0); break;
1344 case 1: EndPos
= v2(RAND() & 15, 0); StartPos
= v2(EndPos
.X
, 15); break;
1345 case 2: EndPos
= v2(15, 0); break;
1346 case 3: EndPos
= v2(0, RAND() & 15); StartPos
= v2(15, EndPos
.Y
); break;
1347 case 4: EndPos
= v2(15, RAND() & 15); StartPos
= v2(0, EndPos
.Y
); break;
1348 case 5: EndPos
= v2(0, 15); break;
1349 case 6: EndPos
= v2(RAND() & 15, 15); StartPos
= v2(EndPos
.X
, 0); break;
1350 case 7: EndPos
= v2(15, 15); break;
1353 while(!Empty
.CreateLightning(EndPos
, -game::GetMoveVector(Direction
), NO_LIMIT
, Color
));
1357 static v2 Dir
[4] = { v2(0, -1), v2(-1, 0), v2(1, 0), v2(0, 1) };
1359 for(int d
= 0; d
< 4; ++d
)
1360 while(!Empty
.CreateLightning(StartPos
+ Dir
[d
], ZERO_V2
, 10, Color
));
1364 game::DrawEverythingNoBlit();
1366 blitdata B
= { DOUBLE_BUFFER
,
1369 { TILE_SIZE
, TILE_SIZE
},
1374 B
.Dest
= game::CalculateScreenCoordinates(GetPos());
1375 Empty
.NormalMaskedBlit(B
);
1376 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1380 graphics::BlitDBToScreen();
1381 while(clock() - StartTime
< 0.02 * CLOCKS_PER_SEC
);
1387 truth
lsquare::Polymorph(const beamdata
& Beam
)
1389 GetStack()->Polymorph(Beam
.Owner
);
1392 GetOLTerrain()->Polymorph(Beam
.Owner
);
1394 character
* Character
= GetCharacter();
1398 if(Beam
.Owner
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
1399 Beam
.Owner
->Hostility(Character
);
1401 Character
->PolymorphRandomly(1, 999999, 5000 + RAND() % 5000);
1406 for(int c
= 0; Engraved
[c
] != '\0'; ++c
)
1410 Engraved
[c
] = 32 + RAND_N(95);
1417 truth
lsquare::Strike(const beamdata
& Beam
)
1419 int Damage
= 50 + RAND() % 21 - RAND() % 21;
1420 GetStack()->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
, Beam
.Direction
);
1421 ReceiveTrapDamage(Beam
.Owner
, Damage
, ENERGY
, Beam
.Direction
);
1423 character
* Char
= GetCharacter();
1427 if(Char
->IsPlayer())
1428 ADD_MESSAGE("You are hit by a burst of energy!");
1429 else if(Char
->CanBeSeenByPlayer())
1430 ADD_MESSAGE("%s is hit by a burst of energy!", Char
->CHAR_NAME(DEFINITE
));
1433 Beam
.Owner
->Hostility(Char
);
1435 Char
->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
, ALL
);
1436 Char
->CheckDeath(Beam
.DeathMsg
, Beam
.Owner
);
1440 GetOLTerrain()->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
);
1445 truth
lsquare::FireBall(const beamdata
& Beam
)
1447 if(!IsFlyable() || GetCharacter())
1449 if(CanBeSeenByPlayer(true))
1450 ADD_MESSAGE("A magical explosion is triggered!");
1452 GetLevel()->Explosion(Beam
.Owner
, Beam
.DeathMsg
, Pos
, 75 + RAND() % 25 - RAND() % 25);
1459 truth
lsquare::Teleport(const beamdata
& Beam
)
1463 if(Beam
.Owner
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
1464 Beam
.Owner
->Hostility(GetCharacter());
1466 if(Character
->IsPlayer())
1467 ADD_MESSAGE("You experience a forced teleportation.");
1468 else if(Character
->CanBeSeenByPlayer())
1469 ADD_MESSAGE("%s disappears!", Character
->CHAR_NAME(DEFINITE
));
1471 Character
->TeleportRandomly();
1475 GetLevel()->GetRoom(RoomIndex
)->TeleportSquare(Beam
.Owner
, this);
1477 GetStack()->TeleportRandomly();
1481 truth
lsquare::Haste(const beamdata
&)
1483 GetStack()->Haste();
1484 character
* Dude
= GetCharacter();
1492 truth
lsquare::Slow(const beamdata
& Beam
)
1495 character
* Dude
= GetCharacter();
1500 Beam
.Owner
->Hostility(Dude
);
1509 truth
lsquare::Confuse (const beamdata
&Beam
) {
1510 character
*Dude
= GetCharacter();
1512 if (Dude
&& Dude
->CanBeConfused()) {
1513 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1514 Dude
->BeginTemporaryState(CONFUSED
, 50+RAND()%50);
1520 truth
lsquare::Parasitize (const beamdata
&Beam
) {
1521 character
*Dude
= GetCharacter();
1523 if (Dude
&& Dude
->GetTorso()->CanHaveParasite()) {
1524 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1525 Dude
->GainIntrinsic(PARASITIZED
);
1531 truth
lsquare::InstillPanic (const beamdata
&Beam
) {
1532 character
* Dude
= GetCharacter();
1534 if (Dude
&& Dude
->CanPanic()) {
1535 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1536 Dude
->BeginTemporaryState(PANIC
, 50+RAND()%50);
1542 truth
lsquare::Resurrect(const beamdata
& Beam
)
1545 return GetCharacter()->RaiseTheDead(Beam
.Owner
);
1547 return GetStack()->RaiseTheDead(Beam
.Owner
);
1550 truth
lsquare::Invisibility(const beamdata
&)
1553 GetCharacter()->BeginTemporaryState(INVISIBLE
, 1000 + RAND() % 1001);
1558 truth
lsquare::Duplicate(const beamdata
& Beam
)
1560 truth DuplicatedSomething
= false;
1561 character
* Character
= GetCharacter();
1564 DuplicatedSomething
= !!(Character
->DuplicateToNearestSquare(Beam
.Owner
, Beam
.SpecialParameters
));
1566 if(GetStack()->Duplicate(DuplicatedSomething
? 4 : 5, Beam
.SpecialParameters
))
1567 DuplicatedSomething
= true;
1569 return DuplicatedSomething
;
1572 truth
lsquare::Lightning(const beamdata
& Beam
)
1574 int Damage
= 20 + RAND() % 6 - RAND() % 6;
1575 GetStack()->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
, Beam
.Direction
);
1576 ReceiveTrapDamage(Beam
.Owner
, Damage
, ELECTRICITY
, Beam
.Direction
);
1578 character
* Char
= GetCharacter();
1582 if(Char
->IsPlayer())
1583 ADD_MESSAGE("A massive burst of electricity runs through your body!");
1584 else if(Char
->CanBeSeenByPlayer())
1585 ADD_MESSAGE("A massive burst of electricity runs through %s!", Char
->CHAR_NAME(DEFINITE
));
1588 Beam
.Owner
->Hostility(Char
);
1590 Char
->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
, ALL
);
1591 Char
->CheckDeath(Beam
.DeathMsg
, Beam
.Owner
);
1595 GetOLTerrain()->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
);
1600 truth
lsquare::DoorCreation(const beamdata
& Beam
)
1602 if ((!GetOLTerrain() || GetOLTerrain()->IsSafeToCreateDoor()) &&
1604 (GetLevel()->IsOnGround() ||
1605 (Pos
.X
> 0 && Pos
.Y
> 0 && Pos
.X
< GetLevel()->GetXSize()-1 && Pos
.Y
< GetLevel()->GetYSize()-1)))
1607 if(Beam
.Owner
&& GetRoom())
1608 GetRoom()->HostileAction(Beam
.Owner
);
1610 door
* Door
= door::Spawn(0, NO_MATERIALS
);
1611 Door
->InitMaterials(MAKE_MATERIAL(STEEL
));
1616 ChangeOLTerrainAndUpdateLights(Door
);
1623 truth (lsquare::*BeamEffect
[BEAM_EFFECTS
])(const beamdata
&) =
1625 &lsquare::Polymorph
,
1631 &lsquare::Resurrect
,
1632 &lsquare::Invisibility
,
1633 &lsquare::Duplicate
,
1634 &lsquare::Lightning
,
1635 &lsquare::DoorCreation
,
1637 &lsquare::Necromancy
1640 truth (lsquare::*lsquare::GetBeamEffect(int I
))(const beamdata
&)
1642 return BeamEffect
[I
];
1645 truth
lsquare::CheckKick(ccharacter
* Kicker
) const
1647 if(Character
&& Kicker
->CheckIfTooScaredToHit(Character
))
1650 if(RoomIndex
&& !GetLevel()->GetRoom(RoomIndex
)->CheckKickSquare(Kicker
, this))
1656 void lsquare::GetHitByExplosion(const explosion
* Explosion
)
1658 if(Explosion
->ID
== LastExplosionID
)
1661 LastExplosionID
= Explosion
->ID
;
1662 int DistanceSquare
= (Pos
- Explosion
->Pos
).GetLengthSquare();
1664 if(DistanceSquare
> Explosion
->RadiusSquare
)
1667 int Damage
= Explosion
->Strength
/ (DistanceSquare
+ 1);
1669 if (Character
&& (Explosion
->HurtNeutrals
|| (Explosion
->Terrorist
&& Character
->GetRelation(Explosion
->Terrorist
) == HOSTILE
))) {
1670 if (Character
->IsPlayer()) game::SetPlayerWasHurtByExplosion(true);
1671 else Character
->GetHitByExplosion(Explosion
, Damage
);
1674 GetStack()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1675 GetStack()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1677 ReceiveTrapDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1678 ReceiveTrapDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1681 GetOLTerrain()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1684 GetOLTerrain()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1687 int lsquare::GetSpoiledItems() const
1689 return GetStack()->GetSpoiledItems();
1692 truth
lsquare::LowerEnchantment(const beamdata
& Beam
)
1694 character
* Char
= GetCharacter();
1695 itemvector AllItems
;
1696 sortdata
SortData(AllItems
, Beam
.Owner
, true, &item::IsEnchantable
);
1697 SortAllItems(SortData
);
1700 if(!AllItems
.empty())
1701 RandomItem
= AllItems
[RAND() % AllItems
.size()];
1707 if(Char
->IsPlayer())
1708 ADD_MESSAGE("%s glows blue for a moment!", RandomItem
->CHAR_NAME(DEFINITE
));
1711 Beam
.Owner
->Hostility(Char
);
1714 if(RandomItem
->GetEnchantment() > -5)
1715 RandomItem
->EditEnchantment(-1);
1720 void lsquare::SortAllItems(const sortdata
& SortData
)
1723 GetCharacter()->SortAllItems(SortData
);
1725 GetStack()->SortAllItems(SortData
);
1729 truth
lsquare::SoftenMaterial (const beamdata
&Beam
) {
1730 character
*Char
= GetCharacter();
1732 itemvector AllItems
;
1734 sortdata
SortData(AllItems
, Beam
.Owner
, true, &item::IsEnchantable
);
1735 SortAllItems(SortData
);
1736 //sortdata SortData2(AllItems, Beam.Owner, true, &item::MaterialIsChangeable);
1737 //SortAllItems(SortData2);
1738 if (AllItems
.empty()) return false;
1739 RandomItem
= AllItems
[RAND() % AllItems
.size()];
1741 if (Char
->IsPlayer()) ADD_MESSAGE("Your %s glows yellow for a moment!", RandomItem
->CHAR_NAME(UNARTICLED
));
1742 if (Beam
.Owner
) Beam
.Owner
->Hostility(Char
);
1748 RandomItem
->AddName(Desc
, UNARTICLED
);
1749 material
*OldMaterial
= RandomItem
->GetMainMaterial();
1750 int NewMaterial
= RandomItem
->GetMainMaterial()->GetSoftenedMaterial(RandomItem
);
1752 if (NewMaterial
!= NONE
) {
1753 /* Don't Forget! It is an ugly thing, I know, but removal = seg-fault since cannot have NONE material */
1754 RandomItem
->ChangeMainMaterial(MAKE_MATERIAL(NewMaterial
)); /*->SpawnMore()*/
1755 if (OldMaterial
->GetConfig() != NewMaterial
) Changed
= 1;
1758 if (Changed
&& Char
->IsPlayer()) {
1759 ADD_MESSAGE("Your %s softens into %s!", Desc
.CStr(), RandomItem
->GetMainMaterial()->GetName(false, false).CStr());
1760 } else if (Changed
) {
1761 ADD_MESSAGE("%s's %s softens into %s!", Char
->CHAR_DESCRIPTION(DEFINITE
), Desc
.CStr(), RandomItem
->GetMainMaterial()->GetName(false, false).CStr());
1764 //may not need this message
1765 if (Char
->IsPlayer()) {
1766 ADD_MESSAGE("Your %s vibrates slightly but remains unchanged.", RandomItem
->CHAR_NAME(UNARTICLED
) );
1768 ADD_MESSAGE("%s's %s vibrates slightly but remains unchanged.", Char
->CHAR_DESCRIPTION(DEFINITE
), RandomItem
->CHAR_NAME(UNARTICLED
) );
1776 void lsquare::RemoveSmoke(smoke
* ToBeRemoved
)
1780 if(S
== ToBeRemoved
)
1785 DecAnimatedEntities();
1796 while(S
!= ToBeRemoved
);
1802 void lsquare::AddSmoke(gas
* ToBeAdded
)
1808 Smoke
= new smoke(ToBeAdded
, this);
1809 IncAnimatedEntities();
1817 if(ToBeAdded
->IsSameAs(S
->GetGas()))
1819 S
->Merge(ToBeAdded
);
1828 LS
->Next
= new smoke(ToBeAdded
, this);
1832 void lsquare::ShowSmokeMessage() const
1834 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
1835 S
->AddBreatheMessage();
1838 void lsquare::SignalSmokeAlphaChange(int What
)
1840 SmokeAlphaSum
+= What
;
1841 SignalPossibleTransparencyChange();
1844 int lsquare::GetDivineMaster() const
1846 return RoomIndex
? GetLevel()->GetRoom(RoomIndex
)->GetDivineMaster() : 0;
1849 void lsquare::DisplaySmokeInfo (festring
&Msg
) const {
1852 Msg
<< " A cloud of " << Smoke
->GetGas()->GetName(false, false) << " surrounds the square.";
1854 Msg
<< " A lot of gases hover over the square.";
1858 void lsquare::ReceiveEarthQuakeDamage()
1860 GetStack()->ReceiveDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1861 ReceiveTrapDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1864 if(GetOLTerrain() && GetOLTerrain()->IsDoor())
1865 GetOLTerrain()->ReceiveDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1868 truth
lsquare::CanBeFeltByPlayer() const
1870 if (!PLAYER
) return false;
1871 return OLTerrain
&& !PLAYER
->CanMoveOn(this) && Pos
.IsAdjacent(PLAYER
->GetPos());
1874 void lsquare::PreProcessForBone()
1880 OLTerrain
->PreProcessForBone();
1884 DecAnimatedEntities();
1886 for(smoke
* S
= Smoke
; S
; S
= S
->Next
)
1893 if(Character
&& !Character
->PreProcessForBone())
1895 Character
->SendToHell();
1896 Character
->Remove();
1899 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
1900 F
->PreProcessForBone();
1902 for(trap
* T
= Trap
; T
; T
= T
->Next
)
1903 T
->PreProcessForBone();
1905 GetStack()->PreProcessForBone();
1908 void lsquare::PostProcessForBone(double& DangerSum
, int& Enemies
)
1911 OLTerrain
->PostProcessForBone();
1913 if(Character
&& !Character
->PostProcessForBone(DangerSum
, Enemies
))
1915 Character
->SendToHell();
1916 Character
->Remove();
1919 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
1920 F
->PostProcessForBone();
1922 for(trap
* T
= Trap
; T
; T
= T
->Next
)
1923 T
->PostProcessForBone();
1925 GetStack()->PostProcessForBone();
1928 void lsquare::FinalProcessForBone()
1931 OLTerrain
->FinalProcessForBone();
1934 Character
->FinalProcessForBone();
1936 GetStack()->FinalProcessForBone();
1939 truth
lsquare::EngravingsCanBeReadByPlayer()
1941 return PLAYER
->CanRead(); // Might be a good idea to improve sometime in the distant future.
1944 void lsquare::DisplayEngravedInfo(festring
& Buffer
) const
1946 Buffer
<< " There is a message engraved here: \"" << Engraved
<< '\"';
1949 truth
lsquare::IsDangerousToBreathe(ccharacter
* Who
) const
1951 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
1952 if(S
->IsDangerousToBreathe(Who
))
1958 truth
lsquare::IsScaryToBreathe(ccharacter
* Who
) const
1960 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
1961 if(S
->IsScaryToBreathe(Who
))
1968 struct groundborderpartner
{
1969 truth
operator < (const groundborderpartner
&P
) const { return Terrain
->GetBorderTilePriority() < P
.Terrain
->GetBorderTilePriority(); }
1975 void lsquare::CalculateGroundBorderPartners () {
1976 if (GroundBorderPartnerInfo
& BORDER_PARTNER_ANIMATED
) DecStaticAnimatedEntities();
1977 groundborderpartner BorderPartner
[8*2]; //k8: *2 to make g++ shut up (WTF?!)
1979 int Priority
= GLTerrain
->GetBorderTilePriority();
1980 for (int d
= 0; d
< 8; ++d
) {
1981 lsquare
*Square
= NeighbourLSquare
[d
];
1983 glterrain
*Terrain
= Square
->GetGLTerrain();
1984 if (Terrain
&& Terrain
->UseBorderTiles() && Terrain
->GetBorderTilePriority() > Priority
) {
1985 BorderPartner
[Index
].Terrain
= Terrain
;
1986 BorderPartner
[Index
].SquareIndex
= 7-d
;
1991 GroundBorderPartnerInfo
= 0;
1993 delete [] GroundBorderPartnerTerrain
;
1994 GroundBorderPartnerTerrain
= 0;
1997 if (!GroundBorderPartnerTerrain
) GroundBorderPartnerTerrain
= new glterrain
*[8];
1998 std::sort(BorderPartner
, BorderPartner
+Index
); //k8: why g++ complains here? ah, ignore it for now
1999 truth Animated
= false;
2000 for (int c
= 0; c
< Index
; ++c
) {
2001 glterrain
*T
= BorderPartner
[c
].Terrain
;
2002 GroundBorderPartnerTerrain
[c
] = T
;
2003 GroundBorderPartnerInfo
|= BorderPartner
[c
].SquareIndex
<<((c
<<1)+c
);
2004 if (T
->IsAnimated()) Animated
= true;
2007 GroundBorderPartnerInfo
|= BORDER_PARTNER_ANIMATED
;
2008 IncStaticAnimatedEntities();
2010 GroundBorderPartnerInfo
|= Index
<<24;
2014 struct overborderpartner
{
2015 truth
operator < (const overborderpartner
&P
) const { return Terrain
->GetBorderTilePriority() < P
.Terrain
->GetBorderTilePriority(); }
2020 void lsquare::CalculateOverBorderPartners () {
2021 if (OverBorderPartnerInfo
& BORDER_PARTNER_ANIMATED
) DecStaticAnimatedEntities();
2022 overborderpartner BorderPartner
[8*2]; //k8: *2 to make g++ shut up (WTF?!)
2024 int Priority
= OLTerrain
? OLTerrain
->GetBorderTilePriority() : 0;
2025 for (int d
= 0; d
< 8; ++d
) {
2026 lsquare
*Square
= NeighbourLSquare
[d
];
2028 olterrain
*Terrain
= Square
->GetOLTerrain();
2029 if (Terrain
&& Terrain
->UseBorderTiles() && Terrain
->GetBorderTilePriority() > Priority
) {
2030 BorderPartner
[Index
].Terrain
= Terrain
;
2031 BorderPartner
[Index
].SquareIndex
= 7-d
;
2036 OverBorderPartnerInfo
= 0;
2038 delete [] OverBorderPartnerTerrain
;
2039 OverBorderPartnerTerrain
= 0;
2042 if (!OverBorderPartnerTerrain
) OverBorderPartnerTerrain
= new olterrain
*[8];
2043 std::sort(BorderPartner
, BorderPartner
+Index
); //k8: why g++ complains here? ah, ignore it for now
2044 truth Animated
= false;
2045 for (int c
= 0; c
< Index
; ++c
) {
2046 olterrain
*T
= BorderPartner
[c
].Terrain
;
2047 OverBorderPartnerTerrain
[c
] = T
;
2048 OverBorderPartnerInfo
|= BorderPartner
[c
].SquareIndex
<<((c
<<1)+c
);
2049 if (T
->IsAnimated()) Animated
= true;
2052 OverBorderPartnerInfo
|= BORDER_PARTNER_ANIMATED
;
2053 IncStaticAnimatedEntities();
2055 OverBorderPartnerInfo
|= Index
<<24;
2057 if (OverBorderPartnerInfo & BORDER_PARTNER_ANIMATED)
2058 int esko = esko = 2;
2063 void lsquare::RequestForGroundBorderPartnerUpdates()
2065 if(!game::IsGenerating())
2066 for(int d
= 0; d
< 8; ++d
)
2068 lsquare
* Square
= NeighbourLSquare
[d
];
2072 Square
->CalculateGroundBorderPartners();
2073 Square
->SendNewDrawRequest();
2074 Square
->SendMemorizedUpdateRequest();
2079 void lsquare::RequestForOverBorderPartnerUpdates()
2081 if(!game::IsGenerating())
2082 for(int d
= 0; d
< 8; ++d
)
2084 lsquare
* Square
= NeighbourLSquare
[d
];
2088 Square
->CalculateOverBorderPartners();
2089 Square
->SendNewDrawRequest();
2090 Square
->SendMemorizedUpdateRequest();
2095 int lsquare::GetWalkability() const
2097 if(!GetLevel()->IsOnGround())
2099 if(Pos
.X
>= 1 && Pos
.Y
>= 1 && Pos
.X
< GetLevel()->GetXSize() - 1 && Pos
.Y
< GetLevel()->GetYSize() - 1)
2100 return OLTerrain
? OLTerrain
->GetWalkability() & GLTerrain
->GetWalkability() : GLTerrain
->GetWalkability();
2105 return OLTerrain
? OLTerrain
->GetWalkability() & GLTerrain
->GetWalkability() : GLTerrain
->GetWalkability();
2108 void lsquare::RemoveFluid(fluid
* ToRemove
)
2110 fluid
*& F
= ListFind(Fluid
, pointercomparer
<fluid
>(ToRemove
));
2112 SignalEmitationDecrease(ToRemove
->GetEmitation());
2115 struct fluidcomparer
2117 fluidcomparer(const liquid
* Liquid
) : Liquid(Liquid
) { }
2118 truth
operator()(const fluid
* F
) const { return Liquid
->IsSameAs(F
->GetLiquid()); }
2119 const liquid
* Liquid
;
2122 fluid
* lsquare::AddFluid(liquid
* ToBeAdded
)
2124 fluid
*& F
= ListFind(Fluid
, fluidcomparer(ToBeAdded
));
2128 F
->AddLiquidAndVolume(ToBeAdded
->GetVolume());
2129 //delete ToBeAdded; //k8: this is BUG!
2130 ToBeAdded
->SendToHell();
2134 F
= new fluid(ToBeAdded
, this);
2135 SignalEmitationIncrease(ToBeAdded
->GetEmitation());
2138 SendNewDrawRequest();
2139 SendMemorizedUpdateRequest();
2143 void lsquare::DisplayFluidInfo(festring
& Msg
) const
2147 Msg
<< ". There is ";
2148 fluid::AddFluidInfo(Fluid
, Msg
);
2149 AddLocationDescription(Msg
);
2153 void lsquare::SpillFluid(character
* Spiller
, liquid
* Liquid
, truth ForceHit
, truth ShowMsg
)
2155 if(!Liquid
->GetVolume())
2157 // delete Liquid; //k8: this is BUG!
2158 //fprintf(stderr, "!!!!!!!!!!! (02)\n");
2159 Liquid
->SendToHell();
2167 if(Spiller
&& !GetCharacter()->IsAlly(Spiller
))
2168 Spiller
->Hostility(GetCharacter());
2170 sLong CharVolume
= GetCharacter()->GetVolume();
2171 double ChanceMultiplier
= 1. / (300 + sqrt(GetStack()->GetVolume() + CharVolume
));
2172 double Root
= sqrt(CharVolume
);
2174 if(ForceHit
|| Root
> RAND() % 400 || Root
> RAND() % 400)
2176 sLong SpillVolume
= sLong(Liquid
->GetVolume() * Root
* ChanceMultiplier
);
2180 if(ShowMsg
&& (GetCharacter()->IsPlayer() || GetCharacter()->CanBeSeenByPlayer()))
2181 ADD_MESSAGE("%s is spilled all over %s.", Liquid
->GetName(false, false).CStr(), GetCharacter()->CHAR_DESCRIPTION(DEFINITE
));
2183 Liquid
->EditVolume(-SpillVolume
);
2184 GetCharacter()->SpillFluid(Spiller
, Liquid
->SpawnMoreLiquid(SpillVolume
), GetCharacter()->GetSquareIndex(GetPos()));
2189 GetStack()->SpillFluid(Spiller
, Liquid
, Liquid
->GetVolume());
2192 if(Liquid
->GetVolume() && !Liquid
->IsSameAs(GLTerrain
->GetMainMaterial()))
2194 fluid
* F
= AddFluid(Liquid
);
2197 F
->StepOnEffect(GetCharacter());
2199 //fprintf(stderr, "!!!!!!!!!!! (03)\n");
2200 //delete Liquid; //k8: this is BUG!
2201 Liquid
->SendToHell();
2205 void lsquare::DrawStacks(blitdata
& BlitData
) const
2207 Stack
->Draw(PLAYER
, BlitData
, CENTER
);
2209 for(int c
= 0; c
< 4; ++c
)
2211 stack
* Stack
= GetStackOfAdjacentSquare(c
);
2214 Stack
->Draw(PLAYER
, BlitData
, 3 - c
);
2218 void lsquare::RemoveRain(rain
* ToBeRemoved
)
2220 SendNewDrawRequest();
2223 if(ToBeRemoved
->IsEnabled())
2224 DecAnimatedEntities();
2226 if(R
== ToBeRemoved
)
2237 while(R
!= ToBeRemoved
);
2242 SignalEmitationDecrease(ToBeRemoved
->GetEmitation());
2245 void lsquare::AddRain(liquid
* RainLiquid
, v2 Speed
, int Team
, truth OwnLiquid
)
2247 rain
* R
= Rain
, * NewRain
= new rain(RainLiquid
, this, Speed
, Team
, OwnLiquid
);
2249 if(NewRain
->IsEnabled())
2250 IncAnimatedEntities();
2269 void lsquare::RemoveSunLight()
2271 SunLightLuminance
= 0;
2275 void lsquare::CheckIfIsSecondarySunLightEmitter()
2277 col24 OldEmitation
= SecondarySunLightEmitation
;
2279 if(Flags
& IS_TRANSPARENT
&& (!(Flags
& INSIDE
) || SunLightLuminance
))
2281 for(int d
= 0; d
< 8; ++d
)
2283 lsquare
* Neighbour
= NeighbourLSquare
[d
];
2285 if(Neighbour
&& Neighbour
->Flags
& INSIDE
)
2287 col24 NewEmitation
= GetLevel()->GetAmbientLuminance();
2289 if(OldEmitation
!= NewEmitation
)
2291 SecondarySunLightEmitation
= NewEmitation
;
2293 if(game::CompareLights(NewEmitation
, OldEmitation
) >= 0)
2294 Emitate(NewEmitation
, SECONDARY_SUN_LIGHT
);
2297 Noxify(OldEmitation
, SECONDARY_SUN_LIGHT
);
2298 Emitate(NewEmitation
, SECONDARY_SUN_LIGHT
|FORCE_ADD
);
2309 Noxify(OldEmitation
, SECONDARY_SUN_LIGHT
);
2310 SecondarySunLightEmitation
= 0;
2314 void lsquare::CalculateNeighbourLSquares()
2316 int XSize
= GetLevel()->GetXSize();
2317 int YSize
= GetLevel()->GetYSize();
2319 for(int d
= 0; d
< 8; ++d
)
2321 v2 NPos
= Pos
+ game::GetMoveVector(d
);
2323 if(NPos
.X
>= 0 && NPos
.Y
>= 0 && NPos
.X
< XSize
&& NPos
.Y
< YSize
)
2324 NeighbourLSquare
[d
] = GetLevel()->GetLSquare(NPos
);
2326 NeighbourLSquare
[d
] = 0;
2330 void lsquare::RemoveLuminance(col24
& Emitation
)
2332 col24 OldLuminance
= Luminance
;
2333 col24 OldEmitation
= Emitation
;
2336 if(game::CompareLights(OldEmitation
, OldLuminance
) < 0) return;
2338 if(!(Flags
& IS_TRANSPARENT
))
2340 Flags
|= NEW_DRAW_REQUEST
;
2342 if(LastSeen
== game::GetLOSTick()) game::SendLOSUpdateRequest();
2346 CalculateLuminance();
2348 if(OldLuminance
== Luminance
)
2351 Flags
|= NEW_DRAW_REQUEST
;
2355 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2357 if(LastSeen
== game::GetLOSTick()) game::SendLOSUpdateRequest();
2362 void lsquare::ChangeLuminance(col24
& Emitation
, col24 NewLuminance
)
2364 col24 OldLuminance
= Luminance
;
2366 if(!(Flags
& IS_TRANSPARENT
))
2368 Emitation
= NewLuminance
;
2369 Flags
|= NEW_DRAW_REQUEST
;
2371 if(LastSeen
== game::GetLOSTick())
2372 game::SendLOSUpdateRequest();
2377 truth EmitationInsignificant
= !Emitation
2378 || game::CompareLights(Emitation
, OldLuminance
) < 0;
2379 Emitation
= NewLuminance
;
2381 if(game::CompareLights(NewLuminance
, OldLuminance
) > 0 && EmitationInsignificant
)
2382 game::CombineLights(Luminance
, NewLuminance
);
2385 if(EmitationInsignificant
)
2388 CalculateLuminance();
2390 if(OldLuminance
== Luminance
)
2394 Flags
|= NEW_DRAW_REQUEST
;
2398 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2400 if(LastSeen
== game::GetLOSTick())
2401 game::SendLOSUpdateRequest();
2405 void lsquare::EnableGlobalRain()
2407 for(rain
* R
= Rain
; R
; R
= R
->Next
)
2408 if(!R
->HasOwnLiquid())
2411 IncAnimatedEntities();
2415 void lsquare::DisableGlobalRain()
2417 SendNewDrawRequest();
2419 for(rain
* R
= Rain
; R
; R
= R
->Next
)
2420 if(!R
->HasOwnLiquid())
2423 DecAnimatedEntities();
2427 void lsquare::InitLastSeen()
2429 LastSeen
= LastSeen
== game::GetLOSTick() ? 2 : 0;
2430 SquarePartLastSeen
= 0;
2433 truth
lsquare::Engrave(cfestring
& What
)
2440 Engraved
= new char[What
.GetSize() + 1];
2441 strcpy(Engraved
, What
.CStr());
2449 void lsquare::SendSunLightSignals()
2451 if(Flags
& IS_TRANSPARENT
)
2453 col24 OldLuminance
= Luminance
;
2454 CalculateLuminance();
2456 if(Luminance
!= OldLuminance
)
2458 Flags
|= NEW_DRAW_REQUEST
;
2460 if(!Luminance
!= !OldLuminance
)
2462 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2464 if(LastSeen
== game::GetLOSTick())
2465 game::SendLOSUpdateRequest();
2471 Flags
|= NEW_DRAW_REQUEST
;
2473 if(LastSeen
== game::GetLOSTick())
2474 game::SendLOSUpdateRequest();
2478 void lsquare::ZeroReSunEmitatedFlags()
2480 sunemittervector::iterator i
, End
= SunEmitter
.end();
2482 for(i
= SunEmitter
.begin(); i
!= End
; ++i
) *i
&= ~RE_SUN_EMITATED
;
2485 truth
lsquare::CalculateIsTransparent()
2487 if((!OLTerrain
|| OLTerrain
->IsTransparent()) && SmokeAlphaSum
< 175
2488 && (!Character
|| Character
->IsTransparent()))
2490 Flags
|= IS_TRANSPARENT
;
2495 Flags
&= ~IS_TRANSPARENT
;
2500 void lsquare::CalculateSunLightLuminance(feuLong SeenBitMask
)
2502 sunemittervector::const_iterator i
, SunEnd
= SunEmitter
.end();
2505 for(i
= SunEmitter
.begin(); i
!= SunEnd
; ++i
)
2507 feuLong ShadowFlag
= 1 << EMITTER_SHADOW_SHIFT
;
2508 feuLong SquarePartFlag
= 1 << EMITTER_SQUARE_PART_SHIFT
;
2509 for (int c
= 0; c
< 4; ++c
, ShadowFlag
<<= 1, SquarePartFlag
<<= 1) {
2510 if (SeenBitMask
& *i
& SquarePartFlag
) {
2511 if (*i
& ShadowFlag
) ++S
; else ++L
;
2517 SunLightLuminance
= 0;
2519 SunLightLuminance
= GetLevel()->GetSunLightEmitation();
2522 col24 ShadowColor
= GetLevel()->GetAmbientLuminance();
2523 col24 LightColor
= GetLevel()->GetSunLightEmitation();
2524 SunLightLuminance
= MakeRGB24(
2525 (GetRed24(LightColor
)*L
+GetRed24(ShadowColor
)*S
)/(S
+L
),
2526 (GetGreen24(LightColor
)*L
+GetGreen24(ShadowColor
)*S
)/(S
+L
),
2527 (GetBlue24(LightColor
)*L
+GetBlue24(ShadowColor
)*S
)/(S
+L
));
2531 void lsquare::CreateMemorized()
2533 Memorized
= new bitmap(TILE_V2
);
2534 Memorized
->ActivateFastFlag();
2535 FowMemorized
= new bitmap(TILE_V2
);
2536 FowMemorized
->ActivateFastFlag();
2539 truth
lsquare::AcidRain(const beamdata
& Beam
)
2541 if(!IsFlyable() || GetCharacter() || Beam
.Direction
== YOURSELF
)
2543 int StackSize
= GetLevel()->AddRadiusToSquareStack(Pos
, 9);
2544 lsquare
** Stack
= GetLevel()->GetSquareStack();
2545 v2 Speed
= v2(512, 512);
2546 int Team
= Beam
.Owner
? Beam
.Owner
->GetTeam()->GetID() : MONSTER_TEAM
;
2548 for(int c
= 0; c
< StackSize
; ++c
)
2550 Stack
[c
]->AddRain(liquid::Spawn(SULPHURIC_ACID
, 300), Speed
, Team
, true);
2551 Stack
[c
]->Flags
&= ~IN_SQUARE_STACK
;
2554 if(Beam
.Owner
&& Character
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
2555 Beam
.Owner
->Hostility(Character
);
2563 truth
lsquare::DetectMaterial (cmaterial
*Material
) const {
2564 if (GLTerrain
->DetectMaterial(Material
) ||
2565 (OLTerrain
&& OLTerrain
->DetectMaterial(Material
)) ||
2566 Stack
->DetectMaterial(Material
) ||
2567 (Character
&& Character
->DetectMaterial(Material
))) return true;
2568 for (const fluid
*F
= Fluid
; F
; F
= F
->Next
) if (F
->GetLiquid()->IsSameAs(Material
)) return true;
2569 for (const smoke
*S
= Smoke
; S
; S
= S
->Next
) if (S
->GetGas()->IsSameAs(Material
)) return true;
2570 for (const rain
*R
= Rain
; R
; R
= R
->Next
) if (R
->GetLiquid()->IsSameAs(Material
)) return true;
2574 void lsquare::Reveal(feuLong Tick
, truth IgnoreDarkness
)
2582 Luminance
= NORMAL_LUMINANCE
;
2585 SquarePartLastSeen
= 0;
2587 for(int c
= 0; c
< 4; ++c
)
2588 SquarePartLastSeen
|= (Tick
<< (c
<< 3));
2590 CalculateLuminance();
2595 MEMORIZED_UPDATE_REQUEST
|
2598 UpdateMemorizedDescription();
2601 void lsquare::DestroyMemorized()
2604 delete FowMemorized
;
2609 void lsquare::SwapMemorized(lsquare
* Square
)
2611 Swap(Memorized
, Square
->Memorized
);
2612 Swap(FowMemorized
, Square
->FowMemorized
);
2613 MemorizedDescription
.SwapData(Square
->MemorizedDescription
);
2616 truth
lsquare::Necromancy(const beamdata
& Beam
)
2618 return GetStack()->Necromancy(Beam
.Owner
);
2621 // Returns 0 if fails
2623 lsquare
* lsquare::GetRandomAdjacentSquare() const
2628 for(int c
= 0; c
< 8; ++c
)
2630 lsquare
* Square
= NeighbourLSquare
[c
];
2633 OK
[Index
++] = Square
;
2637 return OK
[RAND_N(Index
)];
2642 truth
pathcontroller::Handler(int x
, int y
)
2644 return Character
->CanMoveOn(Map
[x
][y
]);
2647 void lsquare::SignalPossibleTransparencyChange()
2649 truth WasTransparent
= IsTransparent();
2650 CalculateIsTransparent();
2652 if(WasTransparent
&& !IsTransparent())
2654 Flags
|= IS_TRANSPARENT
;
2655 emittervector EmitterBackup
= Emitter
;
2656 GetLevel()->ForceEmitterNoxify(EmitterBackup
);
2657 Flags
&= ~IS_TRANSPARENT
;
2658 GetLevel()->ForceEmitterEmitation(EmitterBackup
, SunEmitter
, FORCE_ADD
);
2659 CalculateLuminance();
2660 Flags
|= DESCRIPTION_CHANGE
|MEMORIZED_UPDATE_REQUEST
;
2662 if(LastSeen
== game::GetLOSTick())
2663 game::SendLOSUpdateRequest();
2665 else if(!WasTransparent
&& IsTransparent())
2667 GetLevel()->ForceEmitterEmitation(Emitter
, SunEmitter
);
2668 CalculateLuminance();
2669 Flags
|= DESCRIPTION_CHANGE
|MEMORIZED_UPDATE_REQUEST
;
2671 if(LastSeen
== game::GetLOSTick())
2672 game::SendLOSUpdateRequest();
2676 void lsquare::RemoveTrap(trap
* ToRemove
)
2678 trap
*& T
= ListFind(Trap
, pointercomparer
<trap
>(ToRemove
));
2680 SendNewDrawRequest();
2681 SendMemorizedUpdateRequest();
2686 trapcomparer(int Type
) : Type(Type
) { }
2687 truth
operator()(const trap
* T
) const { return T
->GetType() == Type
; }
2691 truth
lsquare::AddTrap(trap
* ToBeAdded
)
2693 trap
*& T
= ListFind(Trap
, trapcomparer(ToBeAdded
->GetType()));
2703 ToBeAdded
->SetLSquareUnder(this);
2704 SendNewDrawRequest();
2705 SendMemorizedUpdateRequest();
2709 void lsquare::DisplayTrapInfo(festring
& Msg
) const
2711 for(const trap
* T
= Trap
; T
; T
= T
->Next
)
2712 T
->AddDescription(Msg
);
2715 void lsquare::FillTrapVector(std::vector
<trap
*>& TrapVector
) const
2717 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2718 TrapVector
.push_back(T
);
2721 void lsquare::ReceiveTrapDamage(character
* Damager
, int Damage
, int Type
, int Direction
)
2723 std::vector
<trap
*> TrapVector
;
2724 FillTrapVector(TrapVector
);
2726 for(uInt c
= 0; c
< TrapVector
.size(); ++c
)
2727 TrapVector
[c
]->ReceiveDamage(Damager
, Damage
, Type
, Direction
);
2730 truth
lsquare::HasDangerousTraps(ccharacter
* Who
) const
2732 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2733 if(T
->IsDangerous(Who
))
2739 truth
lsquare::HasDangerousFluids(ccharacter
* Who
) const
2741 for(const fluid
* F
= Fluid
; F
; F
= F
->Next
)
2742 if(F
->IsDangerous(Who
))
2748 truth
lsquare::HasNoBorderPartners() const
2750 return !(GroundBorderPartnerInfo
>> 24) && !(OverBorderPartnerInfo
>> 24);
2753 void lsquare::AddLocationDescription(festring
& String
) const
2756 GLTerrain
->AddLocationDescription(String
);
2758 OLTerrain
->AddLocationDescription(String
);
2761 truth
lsquare::VomitingIsDangerous(ccharacter
* Char
) const
2763 return ((OLTerrain
&& OLTerrain
->VomitingIsDangerous(Char
))
2764 || (Character
&& Character
->GetTeam() != Char
->GetTeam()
2765 && Character
->GetRelation(Char
) != HOSTILE
));
2768 bool lsquare::TeleportAllSmokeAway()
2773 bool lsquare::TeleportAllFluidsAway()
2778 bool lsquare::TeleportAllTrapsAway()
2780 for(trap
* T
= Trap
; T
; T
= Trap
)
2784 v2 V
, Pos
= GetPos();
2785 for (V
= GetLevel()->GetRandomSquare(); V
!= Pos
; V
= GetLevel()->GetRandomSquare()) {
2786 if (V
== ERROR_V2
) {
2787 fprintf(stderr
, "No country for old trap! possible memleak!\n");
2791 if (V
!= ERROR_V2
) GetNearLSquare(V
)->AddTrap(T
);
2797 void lsquare::AddSpecialCursors()
2799 if((FowMemorized
|| game::GetSeeWholeMapCheatMode()) && OLTerrain
)
2800 OLTerrain
->AddSpecialCursors();