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
13 /* Compiled through levelset.cpp */
15 lsquare
*** eyecontroller::Map
;
17 lsquare
*** pathcontroller::Map
;
18 ccharacter
* pathcontroller::Character
;
20 lsquare
*** stackcontroller::Map
;
21 lsquare
** stackcontroller::Stack
;
22 sLong
stackcontroller::StackIndex
;
23 int stackcontroller::LevelXSize
, stackcontroller::LevelYSize
;
24 v2
stackcontroller::Center
;
26 feuLong
tickcontroller::Tick
;
27 feuLong
tickcontroller::ShiftedTick
[4];
28 feuLong
tickcontroller::ShiftedQuadriTick
[4];
30 void tickcontroller::PrepareShiftedTick()
32 for(int c
= 0; c
< 4; ++c
)
34 ShiftedTick
[c
] = Tick
<< (c
<< 3);
35 ShiftedQuadriTick
[c
] = (Tick
+ 1) << (c
<< 3);
39 truth
lsquare::IsDipDestination() const { return GLTerrain
->IsDipDestination() || (OLTerrain
&& OLTerrain
->IsDipDestination()); }
41 lsquare::lsquare(level
* LevelUnder
, v2 Pos
)
42 : square(LevelUnder
, Pos
),
43 Fluid(0), Smoke(0), Rain(0), Trap(0),
44 GLTerrain(0), OLTerrain(0),
45 Memorized(0), FowMemorized(0),
47 GroundBorderPartnerTerrain(0),
48 GroundBorderPartnerInfo(0),
49 OverBorderPartnerTerrain(0),
50 OverBorderPartnerInfo(0),
51 SquarePartEmitationTick(0),
52 SquarePartLastSeen(0),
57 TemporaryEmitation(0),
58 SecondarySunLightEmitation(0),
62 Stack
= new stack(this, 0);
72 for(fluid
* F
= Fluid
; F
;)
81 delete StaticContentCache
.Bitmap
;
82 delete [] GroundBorderPartnerTerrain
;
83 delete [] OverBorderPartnerTerrain
;
85 for(smoke
* S
= Smoke
; S
;)
92 for(rain
* R
= Rain
; R
;)
99 for(trap
* T
= Trap
; T
;)
107 void lsquare::SignalEmitationIncrease(col24 EmitationUpdate
)
109 if(game::CompareLights(EmitationUpdate
, Emitation
) > 0 && !game::IsGenerating() && !(Flags
& FREEZED
))
111 CalculateEmitation(); // could this be optimized?
116 void lsquare::SignalEmitationDecrease(col24 EmitationUpdate
)
118 if(game::CompareLights(EmitationUpdate
, Emitation
) >= 0 && Emitation
&& !game::IsGenerating() && !(Flags
& FREEZED
))
120 col24 Backup
= Emitation
;
121 CalculateEmitation();
123 if(Backup
!= Emitation
)
126 Emitate(Emitation
, FORCE_ADD
);
131 void lsquare::CalculateEmitation()
133 Emitation
= Stack
->GetEmitation();
136 for(c
= 0; c
< 4; ++c
)
138 stack
* Stack
= GetStackOfAdjacentSquare(c
);
141 game::CombineLights(Emitation
, Stack
->GetSideEmitation(3 - c
));
145 game::CombineLights(Emitation
, Character
->GetEmitation());
147 game::CombineLights(Emitation
, GLTerrain
->GetEmitation());
150 game::CombineLights(Emitation
, OLTerrain
->GetEmitation());
152 game::CombineLights(Emitation
, TemporaryEmitation
);
154 for(const fluid
* F
= Fluid
; F
; F
= F
->Next
)
155 game::CombineLights(Emitation
, F
->GetEmitation());
157 for(const rain
* R
= Rain
; R
; R
= R
->Next
)
158 game::CombineLights(Emitation
, R
->GetEmitation());
161 void lsquare::UpdateMemorized()
163 if(Flags
& MEMORIZED_UPDATE_REQUEST
)
165 if(!IsDark() || CanBeFeltByPlayer())
167 blitdata B
= { Memorized
,
170 { TILE_SIZE
, TILE_SIZE
},
171 { NORMAL_LUMINANCE
},
175 DrawStaticContents(B
);
176 Memorized
->FastBlit(FowMemorized
);
177 B
.Bitmap
= FowMemorized
;
180 igraph::GetFOWGraphic()->NormalMaskedBlit(B
);
184 Memorized
->ClearToColor(0);
185 igraph::GetFOWGraphic()->FastBlit(FowMemorized
);
188 if(!StaticContentCache
.Bitmap
)
190 StaticContentCache
.Bitmap
= new bitmap(TILE_V2
);
191 StaticContentCache
.Bitmap
->ActivateFastFlag();
194 UpdateStaticContentCache(Luminance
);
195 Flags
&= ~MEMORIZED_UPDATE_REQUEST
;
199 void lsquare::UpdateStaticContentCache(col24 Luminance
) const
201 blitdata B
= { StaticContentCache
.Bitmap
,
204 { TILE_SIZE
, TILE_SIZE
},
209 Memorized
->LuminanceBlit(B
);
210 StaticContentCache
.Luminance
= Luminance
;
213 void lsquare::DrawStaticContents(blitdata
& BlitData
) const
215 if(BlitData
.CustomData
& ALLOW_ANIMATE
&& !StaticAnimatedEntities
&& Memorized
&& !game::GetSeeWholeMapCheatMode())
217 if(StaticContentCache
.Luminance
!= BlitData
.Luminance
)
218 UpdateStaticContentCache(BlitData
.Luminance
);
220 StaticContentCache
.Bitmap
->FastBlit(BlitData
.Bitmap
, BlitData
.Dest
);
224 if(!OLTerrain
|| OLTerrain
->ShowThingsUnder())
225 GLTerrain
->Draw(BlitData
);
228 int GroundPartners
= GroundBorderPartnerInfo
>> 24 & 15;
230 for(c
= 0; c
< GroundPartners
; ++c
)
232 BlitData
.CustomData
|= 8 - (GroundBorderPartnerInfo
>> ((c
<< 1) + c
) & 7);
233 GroundBorderPartnerTerrain
[c
]->Draw(BlitData
);
234 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
237 truth StackDrawn
= false;
239 if(OLTerrain
&& !IsFlyable())
241 if(OLTerrain
->IsTransparent() && OLTerrain
->ShowThingsUnder())
244 DrawStacks(BlitData
);
247 OLTerrain
->Draw(BlitData
);
250 for(const fluid
* F
= Fluid
; F
; F
= F
->Next
)
251 F
->SimpleDraw(BlitData
);
253 if(OLTerrain
&& IsFlyable())
254 OLTerrain
->Draw(BlitData
);
256 if(!StackDrawn
&& Flags
& IS_TRANSPARENT
)
257 DrawStacks(BlitData
);
259 for(const trap
* T
= Trap
; T
; T
= T
->Next
)
262 int OverPartners
= OverBorderPartnerInfo
>> 24 & 15;
264 for(c
= 0; c
< OverPartners
; ++c
)
266 BlitData
.CustomData
|= 8 - (OverBorderPartnerInfo
>> ((c
<< 1) + c
) & 7);
267 OverBorderPartnerTerrain
[c
]->Draw(BlitData
);
268 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
272 void lsquare::Draw(blitdata
& BlitData
) const
274 if(Flags
& NEW_DRAW_REQUEST
|| AnimatedEntities
)
276 if(!IsDark() || game::GetSeeWholeMapCheatMode())
278 if(game::GetSeeWholeMapCheatMode() == SHOW_MAP_IN_UNIFORM_LIGHT
279 || (game::GetSeeWholeMapCheatMode()
280 && !(Flags
& IS_TRANSPARENT
)))
281 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
283 BlitData
.Luminance
= ivanconfig::ApplyContrastTo(Luminance
);
285 DrawStaticContents(BlitData
);
287 if(Character
&& (Character
->CanBeSeenByPlayer() || game::GetSeeWholeMapCheatMode()))
289 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
291 if(Character
->IsFlying())
293 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
296 Character
->Draw(BlitData
);
300 Character
->Draw(BlitData
);
302 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
306 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
309 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
312 for(const rain
* R
= Rain
; R
; R
= R
->Next
)
316 else if(CanBeFeltByPlayer())
319 game::CombineLights(L
, DIM_LUMINANCE
);
320 BlitData
.Luminance
= ivanconfig::ApplyContrastTo(L
);
321 DrawStaticContents(BlitData
);
323 for(const rain
* R
= Rain
; R
; R
= R
->Next
)
329 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
331 if(Character
&& Character
->CanBeSeenByPlayer())
333 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
334 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
335 Character
->Draw(BlitData
);
336 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
340 Flags
&= ~STRONG_NEW_DRAW_REQUEST
;
344 struct emitationcontroller
: public tickcontroller
, public stackcontroller
346 static truth
Handler(int x
, int y
)
348 lsquare
* Square
= Map
[x
>> 1][y
>> 1];
349 culong SquareFlags
= Square
->Flags
;
351 if(SquareFlags
& PERFECTLY_QUADRI_HANDLED
)
352 return SquareFlags
& ALLOW_EMITATION_CONTINUE
;
354 if(SquareFlags
& IS_TRANSPARENT
)
355 return ProcessSquare(x
>> 1, y
>> 1, Square
);
357 if(!(SquareFlags
& IN_SQUARE_STACK
))
359 Square
->Flags
|= IN_SQUARE_STACK
;
360 Stack
[StackIndex
++] = Square
;
363 cint SquarePartIndex
= (x
& 1) + ((y
& 1) << 1);
364 Square
->SquarePartEmitationTick
=
365 (Square
->SquarePartEmitationTick
& ~SquarePartTickMask
[SquarePartIndex
]) | ShiftedTick
[SquarePartIndex
];
369 static int ProcessSquare(int X
, int Y
, lsquare
* Square
)
371 Stack
[StackIndex
++] = Square
;
372 culong SquareFlags
= Square
->Flags
;
373 cint MaxE
= MaxLuxTable
[X
- EmitterPosXMinus16
][Y
- EmitterPosYMinus16
];
375 if(MaxE
>= LIGHT_BORDER
376 && (SquareFlags
& INSIDE
377 || (!(ID
& SECONDARY_SUN_LIGHT
)
378 && MaxE
> MinNightAmbientLuminanceElement
)))
380 Square
->Flags
|= ALLOW_EMITATION_CONTINUE
| PERFECTLY_QUADRI_HANDLED
;
385 Square
->Flags
= (SquareFlags
& ~ALLOW_EMITATION_CONTINUE
) | PERFECTLY_QUADRI_HANDLED
;
389 static feuLong
& GetTickReference(int X
, int Y
)
391 return Map
[X
][Y
]->SquarePartEmitationTick
;
393 static void ProcessStack()
395 for(sLong c1
= 0; c1
< StackIndex
; ++c1
)
397 lsquare
* Square
= Stack
[c1
];
398 culong SquareTick
= Square
->SquarePartEmitationTick
;
401 for(int c2
= 0; c2
< 4; ++c2
)
402 if((SquareTick
& SquarePartTickMask
[c2
]) == ShiftedTick
[c2
])
403 TempID
|= 1 << EMITTER_SQUARE_PART_SHIFT
<< c2
;
405 Square
->Flags
&= ~(IN_SQUARE_STACK
|PERFECTLY_QUADRI_HANDLED
);
406 v2 Pos
= Square
->Pos
;
407 int XVal
= Pos
.X
- EmitterPosXMinus16
;
408 int YVal
= Pos
.Y
- EmitterPosYMinus16
;
410 if(MaxLuxTable
[XVal
][YVal
] >= LIGHT_BORDER
)
411 Square
->AlterLuminance(TempID
, MakeRGB24(RedLuxTable
[XVal
][YVal
],
412 GreenLuxTable
[XVal
][YVal
],
413 BlueLuxTable
[XVal
][YVal
]));
417 static int MinNightAmbientLuminanceElement
;
418 static int EmitterPosXMinus16
;
419 static int EmitterPosYMinus16
;
420 static uChar
** MaxLuxTable
;
421 static uChar
** RedLuxTable
;
422 static uChar
** GreenLuxTable
;
423 static uChar
** BlueLuxTable
;
426 feuLong
emitationcontroller::ID
;
427 int emitationcontroller::MinNightAmbientLuminanceElement
;
428 int emitationcontroller::EmitterPosXMinus16
;
429 int emitationcontroller::EmitterPosYMinus16
;
430 uChar
** emitationcontroller::MaxLuxTable
;
431 uChar
** emitationcontroller::RedLuxTable
;
432 uChar
** emitationcontroller::GreenLuxTable
;
433 uChar
** emitationcontroller::BlueLuxTable
;
435 void lsquare::Emitate(col24 Emitation
, feuLong IDFlags
)
437 if(game::IsDark(Emitation
))
440 int Radius
= game::CalculateMinimumEmitationRadius(Emitation
);
445 stackcontroller::Map
= GetLevel()->GetMap();
446 stackcontroller::Stack
= GetLevel()->GetSquareStack();
447 stackcontroller::StackIndex
= 0;
448 tickcontroller::Tick
= game::IncreaseSquarePartEmitationTicks();
449 tickcontroller::PrepareShiftedTick();
450 emitationcontroller::ID
= MakeEmitterID(Pos
) | IDFlags
;
451 emitationcontroller::MinNightAmbientLuminanceElement
= GetMinColor24(GetLevel()->GetNightAmbientLuminance());
452 emitationcontroller::EmitterPosXMinus16
= Pos
.X
- 16;
453 emitationcontroller::EmitterPosYMinus16
= Pos
.Y
- 16;
454 emitationcontroller::MaxLuxTable
= game::GetLuxTable()[GetMaxColor24(Emitation
)];
455 emitationcontroller::RedLuxTable
= game::GetLuxTable()[GetRed24(Emitation
)];
456 emitationcontroller::GreenLuxTable
= game::GetLuxTable()[GetGreen24(Emitation
)];
457 emitationcontroller::BlueLuxTable
= game::GetLuxTable()[GetBlue24(Emitation
)];
458 mapmath
<emitationcontroller
>::DoQuadriArea(Pos
.X
, Pos
.Y
,
460 GetLevel()->GetXSize(),
461 GetLevel()->GetYSize());
462 emitationcontroller::ProcessStack();
465 struct noxifycontroller
: public stackcontroller
467 static truth
Handler(int x
, int y
)
469 if(x
>= 0 && y
>= 0 && x
< LevelXSize
&& y
< LevelYSize
)
471 lsquare
* Square
= Map
[x
][y
];
473 if(Square
->SquarePartEmitationTick
!= Tick
)
475 Square
->SquarePartEmitationTick
= Tick
;
476 return Square
->NoxifyEmitter(ID
);
482 static int GetStartX(int) { return Center
.X
; }
483 static int GetStartY(int) { return Center
.Y
; }
488 feuLong
noxifycontroller::ID
;
489 feuLong
noxifycontroller::Tick
;
491 void lsquare::Noxify(col24 Emitation
, feuLong IDFlags
)
493 if(game::IsDark(Emitation
))
496 int Radius
= game::CalculateMinimumEmitationRadius(Emitation
);
501 stackcontroller::Map
= GetLevel()->GetMap();
502 stackcontroller::LevelXSize
= GetLevel()->GetXSize();
503 stackcontroller::LevelYSize
= GetLevel()->GetYSize();
504 stackcontroller::Center
= Pos
;
505 noxifycontroller::ID
= MakeEmitterID(Pos
) | IDFlags
;
506 noxifycontroller::Tick
= game::IncreaseSquarePartEmitationTicks();
507 NoxifyEmitter(noxifycontroller::ID
);
508 mapmath
<noxifycontroller
>::DoArea();
511 truth
lsquare::NoxifyEmitter(feuLong ID
)
513 emittervector::iterator i
, End
= Emitter
.end();
515 for(i
= Emitter
.begin(); i
!= End
; ++i
)
516 if(!((i
->ID
^ ID
) & (EMITTER_IDENTIFIER_BITS
|SECONDARY_SUN_LIGHT
)))
518 RemoveLuminance(i
->Emitation
);
519 Swap(*i
, Emitter
.back());
527 void lsquare::AlterLuminance(feuLong ID
, col24 NewLuminance
)
529 emittervector::iterator i
, End
= Emitter
.end();
531 if(!(ID
& FORCE_ADD
))
532 for(i
= Emitter
.begin(); i
!= End
; ++i
)
533 if(!((i
->ID
^ ID
) & (EMITTER_IDENTIFIER_BITS
|SECONDARY_SUN_LIGHT
)))
537 if(i
->Emitation
!= NewLuminance
)
538 ChangeLuminance(i
->Emitation
, NewLuminance
);
543 Emitter
.push_back(emitter(ID
, 0));
544 ChangeLuminance(Emitter
.back().Emitation
, NewLuminance
);
547 void lsquare::AddSunLightEmitter(feuLong ID
)
549 sunemittervector::iterator i
, End
= SunEmitter
.end();
551 for(i
= SunEmitter
.begin(); i
!= End
; ++i
)
552 if(!((*i
^ ID
) & EMITTER_IDENTIFIER_BITS
))
554 if(ID
& ~*i
& RE_SUN_EMITATED
)
555 *i
&= ~EMITTER_SHADOW_BITS
;
558 Swap(*i
, SunEmitter
.front());
562 SunEmitter
.push_back(ID
);
565 truth
lsquare::Open(character
* Opener
)
567 return GetStack()->Open(Opener
) || (OLTerrain
&& OLTerrain
->Open(Opener
));
570 truth
lsquare::Close(character
* Closer
)
572 if(!GetStack()->GetItems() && !Character
)
573 return OLTerrain
&& OLTerrain
->Close(Closer
);
576 ADD_MESSAGE("There's something in the way...");
581 void lsquare::Save(outputfile
& SaveFile
) const
583 Stack
->Save(SaveFile
); // This must be before square::Save! (Note: This comment is years old. It's probably obsolete)
584 square::Save(SaveFile
);
585 SaveFile
<< GLTerrain
<< OLTerrain
;
586 SaveFile
<< Emitter
<< SunEmitter
;
587 SaveFile
<< Emitation
<< Engraved
<< Luminance
;
588 SaveFile
<< SmokeAlphaSum
<< (uChar
)Flags
<< Memorized
;
589 SaveFile
<< SecondarySunLightEmitation
;
590 SaveFile
<< (uChar
)RoomIndex
;
591 SaveFile
<< SunLightLuminance
;
592 SaveLinkedList(SaveFile
, Fluid
);
593 SaveLinkedList(SaveFile
, Smoke
);
594 SaveLinkedList(SaveFile
, Rain
);
595 SaveLinkedList(SaveFile
, Trap
);
598 void lsquare::Load(inputfile
& SaveFile
)
600 Stack
->Load(SaveFile
); // This must be before square::Load! (Note: This comment is years old. It's probably obsolete)
601 Stack
->SetMotherSquare(this);
602 square::Load(SaveFile
);
603 SaveFile
>> GLTerrain
>> OLTerrain
;
604 SaveFile
>> Emitter
>> SunEmitter
;
605 SaveFile
>> Emitation
>> Engraved
>> Luminance
;
606 SaveFile
>> SmokeAlphaSum
>> (uChar
&)Flags
>> Memorized
;
607 Flags
&= INSIDE
|DESCRIPTION_CHANGE
; //only these flags are loaded
608 Flags
|= MEMORIZED_UPDATE_REQUEST
;
609 SecondarySunLightEmitation
= ReadType
<col24
>(SaveFile
);
610 RoomIndex
= ReadType
<uChar
>(SaveFile
);
611 SunLightLuminance
= ReadType
<col24
>(SaveFile
);
612 LoadLinkedList(SaveFile
, Fluid
);
613 LoadLinkedList(SaveFile
, Smoke
);
614 LoadLinkedList(SaveFile
, Rain
);
615 LoadLinkedList(SaveFile
, Trap
);
616 CalculateIsTransparent();
620 FowMemorized
= new bitmap(TILE_V2
);
621 FowMemorized
->ActivateFastFlag();
622 Memorized
->FastBlit(FowMemorized
);
623 blitdata B
= { FowMemorized
,
626 { TILE_SIZE
, TILE_SIZE
},
631 igraph::GetFOWGraphic()->NormalMaskedBlit(B
);
635 void lsquare::CalculateLuminance()
637 Luminance
= AmbientLuminance
;
638 emittervector::const_iterator i
, End
= Emitter
.end();
640 if(Flags
& IS_TRANSPARENT
)
642 game::CombineLights(Luminance
, SunLightLuminance
);
644 for(i
= Emitter
.begin(); i
!= End
; ++i
)
645 game::CombineLights(Luminance
, i
->Emitation
);
649 feuLong BitMask
= 0, LOSTick
= game::GetLOSTick();
651 for(int c
= 0; c
< 4; ++c
)
652 if((SquarePartLastSeen
>> (c
<< 3) & 0xFF) >= LOSTick
)
653 BitMask
|= 1 << EMITTER_SQUARE_PART_SHIFT
<< c
;
655 CalculateSunLightLuminance(BitMask
);
656 game::CombineLights(Luminance
, SunLightLuminance
);
658 for(i
= Emitter
.begin(); i
!= End
; ++i
)
660 game::CombineLights(Luminance
, i
->Emitation
);
664 void lsquare::AddCharacter(character
* Guy
)
667 ABORT("Overgrowth of square population detected!");
670 SignalEmitationIncrease(Guy
->GetEmitation());
671 Flags
|= STRONG_NEW_DRAW_REQUEST
;
673 if(Guy
->IsAnimated())
674 IncAnimatedEntities();
676 SignalPossibleTransparencyChange();
679 || (Guy
->CanBeSeenByPlayer(true) && CanBeSeenByPlayer()))
683 void lsquare::Clean()
688 void lsquare::RemoveCharacter()
692 character
* Backup
= Character
;
694 if(Backup
->IsAnimated())
695 DecAnimatedEntities();
698 SignalEmitationDecrease(Backup
->GetEmitation());
699 Flags
|= STRONG_NEW_DRAW_REQUEST
;
700 SignalPossibleTransparencyChange();
704 void lsquare::UpdateMemorizedDescription(truth Cheat
)
706 if(Flags
& DESCRIPTION_CHANGE
|| Cheat
)
708 if(!IsDark() || Cheat
)
710 MemorizedDescription
.Empty();
712 if(!OLTerrain
|| (OLTerrain
->IsTransparent() && OLTerrain
->ShowThingsUnder()))
714 truth Anything
= false;
716 if(OLTerrain
&& OLTerrain
->GetNameSingular().GetSize())
718 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
722 if(Flags
& IS_TRANSPARENT
)
724 itemvectorvector PileVector
;
725 GetStack()->Pile(PileVector
, PLAYER
, CENTER
);
727 if(PileVector
.size())
730 MemorizedDescription
<< " and ";
732 if(PileVector
.size() == 1)
733 PileVector
[0][0]->AddName(MemorizedDescription
, INDEFINITE
, PileVector
[0].size());
735 MemorizedDescription
<< "many items";
737 MemorizedDescription
<< " on ";
741 MemorizedDescription
<< " on ";
743 GLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
745 GetSideItemDescription(SideItems
, Cheat
);
747 if(!SideItems
.IsEmpty())
748 MemorizedDescription
<< " and " << SideItems
;
753 MemorizedDescription
<< " on ";
755 GLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
759 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
762 DisplayFluidInfo(MemorizedDescription
);
764 DisplayTrapInfo(MemorizedDescription
);
767 MemorizedDescription
<< " (pos " << Pos
.X
<< ':' << Pos
.Y
<< ")";
769 else if(CanBeFeltByPlayer())
771 MemorizedDescription
.Empty();
772 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
775 DisplayFluidInfo(MemorizedDescription
);
777 DisplayTrapInfo(MemorizedDescription
);
780 MemorizedDescription
= CONST_S("darkness");
782 Flags
&= ~DESCRIPTION_CHANGE
;
786 void lsquare::GetSideItemDescription(festring
& String
, truth Cheat
) const
790 for(int c
= 0; c
< 4; ++c
)
792 stack
* Stack
= GetStackOfAdjacentSquare(c
);
796 ? Stack
->GetSideItems(3 - c
)
797 : Stack
->GetVisibleSideItems(PLAYER
, 3 - c
);
801 String
<< "many items on the wall";
804 for(int c
= 0; c
< 4; ++c
)
806 stack
* Stack
= GetStackOfAdjacentSquare(c
);
809 && ((Cheat
&& Stack
->GetSideItems(3 - c
))
810 || (!Cheat
&& Stack
->GetVisibleSideItems(PLAYER
, 3 - c
))))
811 Stack
->GetBottomSideItem(PLAYER
, 3 - c
, Cheat
)->AddName(String
, INDEFINITE
);
814 String
<< " on the wall";
818 truth
lsquare::BeKicked(character
* Kicker
, item
* Boot
, bodypart
* Leg
, double KickDamage
, double KickToHitValue
, int Success
, int Direction
, truth Critical
, truth ForceHit
)
824 GetCharacter()->BeKicked(Kicker
, Boot
, Leg
, Pos
, KickDamage
, KickToHitValue
, Success
, Direction
, Critical
, ForceHit
);
831 GetLevel()->GetRoom(RoomIndex
)->KickSquare(Kicker
, this);
833 GetStack()->BeKicked(Kicker
, int(KickDamage
), Direction
);
836 GetOLTerrain()->BeKicked(Kicker
, int(KickDamage
* (100 + Success
) / 100), Direction
);
841 truth
lsquare::CanBeDug() const
843 if((!GetPos().X
|| !GetPos().Y
|| GetPos().X
== GetLevel()->GetXSize() - 1 || GetPos().Y
== GetLevel()->GetYSize() - 1) && !*GetLevel()->GetLevelScript()->IsOnGround())
845 ADD_MESSAGE("Somehow you feel that by digging this square you would collapse the whole dungeon.");
852 void lsquare::ChangeLTerrain(glterrain
* NewGround
, olterrain
* NewOver
)
854 ChangeGLTerrain(NewGround
);
855 ChangeOLTerrain(NewOver
);
858 void lsquare::ChangeGLTerrain(glterrain
* NewGround
)
860 if(GLTerrain
->IsAnimated())
861 DecStaticAnimatedEntities();
863 truth WasUsingBorderTiles
= GLTerrain
->UseBorderTiles();
865 GLTerrain
= NewGround
;
866 NewGround
->SetLSquareUnder(this);
867 Flags
|= NEW_DRAW_REQUEST
;
868 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
869 CalculateGroundBorderPartners();
870 SendMemorizedUpdateRequest();
872 if(WasUsingBorderTiles
|| NewGround
->UseBorderTiles())
873 RequestForGroundBorderPartnerUpdates();
875 if(NewGround
->IsAnimated())
876 IncStaticAnimatedEntities();
879 void lsquare::ChangeOLTerrain(olterrain
* NewOver
)
881 if(OLTerrain
&& OLTerrain
->IsAnimated())
882 DecStaticAnimatedEntities();
884 truth WasUsingBorderTiles
= OLTerrain
&& OLTerrain
->UseBorderTiles();
887 Flags
|= NEW_DRAW_REQUEST
;
888 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
889 CalculateOverBorderPartners();
890 CalculateIsTransparent();
891 SendMemorizedUpdateRequest();
893 if(WasUsingBorderTiles
|| (NewOver
&& NewOver
->UseBorderTiles()))
894 RequestForOverBorderPartnerUpdates();
898 NewOver
->SetLSquareUnder(this);
900 if(NewOver
->IsAnimated())
901 IncStaticAnimatedEntities();
905 void lsquare::SetLTerrain(glterrain
* NewGround
, olterrain
* NewOver
)
907 GLTerrain
= NewGround
;
908 NewGround
->SetLSquareUnder(this);
910 if(NewGround
->IsAnimated())
911 IncStaticAnimatedEntities();
917 NewOver
->SetLSquareUnder(this);
919 if(NewOver
->IsAnimated())
920 IncStaticAnimatedEntities();
922 if(!NewOver
->IsTransparent())
923 Flags
&= ~IS_TRANSPARENT
;
926 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
929 void lsquare::ApplyScript(const squarescript
* SquareScript
, room
* Room
)
931 if(SquareScript
->AttachRequired())
932 GetLevel()->AddToAttachQueue(Pos
);
934 int EntryIndex
= SquareScript
->GetEntryIndex();
936 if(EntryIndex
!= NO_ENTRY
)
937 GetLevel()->SetEntryPos(EntryIndex
, Pos
);
939 const contentscript
<character
>* CharacterScript
= SquareScript
->GetCharacter();
941 if (CharacterScript
) {
942 character
*Char
= CharacterScript
->Instantiate();
945 Char
->SetGenerationDanger(GetLevel()->GetDifficulty());
946 if (!Char
->GetTeam()) Char
->SetTeam(game::GetTeam(*GetLevel()->GetLevelScript()->GetTeamDefault()));
947 if (CharacterScript
->GetFlags() & IS_LEADER
) Char
->GetTeam()->SetLeader(Char
);
948 Char
->PutToOrNear(Pos
);
949 Char
->CreateHomeData();
950 if (Room
&& CharacterScript
->GetFlags() & IS_MASTER
) Room
->SetMasterID(Char
->GetID());
954 const fearray
<contentscript
<item
> >* Items
= SquareScript
->GetItems();
957 for(uInt c1
= 0; c1
< Items
->Size
; ++c1
)
959 const interval
* TimesPtr
= Items
->Data
[c1
].GetTimes();
960 int Times
= TimesPtr
? TimesPtr
->Randomize() : 1;
962 for(int c2
= 0; c2
< Times
; ++c2
)
964 item
* Item
= Items
->Data
[c1
].Instantiate();
968 int SquarePosition
= Items
->Data
[c1
].GetSquarePosition();
970 if(SquarePosition
!= CENTER
)
971 Item
->SignalSquarePositionChange(SquarePosition
);
973 GetStack()->AddItem(Item
);
974 Item
->SpecialGenerationHandler();
979 const contentscript
<glterrain
>* GLTerrainScript
= SquareScript
->GetGTerrain();
983 GetLevel()->AddFlag(Pos
, FORBIDDEN
);
984 ChangeGLTerrain(GLTerrainScript
->Instantiate());
986 if (GLTerrainScript
->IsInside()) {
987 if (*GLTerrainScript
->IsInside()) Flags
|= INSIDE
; else Flags
&= ~INSIDE
;
991 const contentscript
<olterrain
>* OLTerrainScript
= SquareScript
->GetOTerrain();
995 GetLevel()->AddFlag(Pos
, FORBIDDEN
);
996 ChangeOLTerrain(OLTerrainScript
->Instantiate());
1000 truth
lsquare::CanBeSeenByPlayer(truth IgnoreDarkness
) const
1002 return (IgnoreDarkness
|| !IsDark()) && LastSeen
== game::GetLOSTick();
1005 truth
lsquare::CanBeSeenFrom(v2 FromPos
, sLong MaxDistance
, truth IgnoreDarkness
) const
1007 if((Pos
- FromPos
).GetLengthSquare() <= MaxDistance
1008 && (IgnoreDarkness
|| !IsDark()))
1010 if(Character
&& Character
->IsPlayer()
1011 && GetNearLSquare(FromPos
)->CanBeSeenByPlayer(true))
1014 eyecontroller::Map
= GetLevel()->GetMap();
1015 return mapmath
<eyecontroller
>::DoLine(FromPos
.X
, FromPos
.Y
, GetPos().X
, GetPos().Y
, SKIP_FIRST
);
1021 void lsquare::StepOn(character
* Stepper
, lsquare
** ComingFrom
)
1025 truth WasInRoom
= false;
1028 for(int c
= 0; c
< Stepper
->GetSquaresUnder(); ++c
)
1029 if(ComingFrom
[c
]->GetRoomIndex() == RoomIndex
)
1036 GetLevel()->GetRoom(RoomIndex
)->Enter(Stepper
);
1039 GLTerrain
->StepOn(Stepper
);
1043 OLTerrain
->StepOn(Stepper
);
1045 if(Stepper
->DestroysWalls() && OLTerrain
->WillBeDestroyedBy(Stepper
))
1047 if(CanBeSeenByPlayer())
1048 ADD_MESSAGE("%s destroys %s.", Stepper
->CHAR_NAME(DEFINITE
), OLTerrain
->CHAR_NAME(DEFINITE
));
1050 Stepper
->EditAP(-100);
1051 OLTerrain
->BeDestroyed();
1056 std::vector
<trap
*> TrapVector
;
1058 for(trap
* T
= Trap
; T
; T
= T
->Next
)
1059 TrapVector
.push_back(T
);
1061 for(c
= 0; c
< TrapVector
.size(); ++c
)
1062 if(TrapVector
[c
]->Exists())
1064 TrapVector
[c
]->StepOnEffect(Stepper
);
1066 if(!Stepper
->IsEnabled())
1070 if(!Stepper
->IsFlying())
1072 std::vector
<fluid
*> FluidVector
;
1074 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
1075 FluidVector
.push_back(F
);
1077 for(c
= 0; c
< FluidVector
.size(); ++c
)
1078 if(FluidVector
[c
]->Exists())
1080 FluidVector
[c
]->StepOnEffect(Stepper
);
1082 if(!Stepper
->IsEnabled())
1086 GetStack()->CheckForStepOnEffect(Stepper
);
1090 void lsquare::ReceiveVomit(character
* Who
, liquid
* Liquid
)
1092 if(!GetOLTerrain() || !GetOLTerrain()->ReceiveVomit(Who
, Liquid
))
1094 SpillFluid(Who
, Liquid
);
1097 GetRoom()->ReceiveVomit(Who
);
1101 void lsquare::SetTemporaryEmitation(col24 What
)
1103 col24 Old
= TemporaryEmitation
;
1104 TemporaryEmitation
= 0;
1105 SignalEmitationDecrease(Old
);
1106 TemporaryEmitation
= What
;
1107 SignalEmitationIncrease(What
);
1110 void lsquare::ChangeOLTerrainAndUpdateLights(olterrain
* NewTerrain
)
1112 truth WasTransparent
= Flags
& IS_TRANSPARENT
, Noxified
= false;
1113 emittervector EmitterBackup
;
1115 if(WasTransparent
&& NewTerrain
&& !NewTerrain
->IsTransparent())
1117 EmitterBackup
= Emitter
;
1118 GetLevel()->ForceEmitterNoxify(EmitterBackup
);
1122 sLong OldEmit
= OLTerrain
? OLTerrain
->GetEmitation() : 0;
1123 ChangeOLTerrain(NewTerrain
);
1126 SignalEmitationIncrease(NewTerrain
->GetEmitation());
1128 SignalEmitationDecrease(OldEmit
);
1129 GetStack()->DropSideItems();
1131 if(!IsFlyable() && Smoke
)
1133 DecAnimatedEntities();
1135 for(smoke
* S
= Smoke
; S
; S
= S
->Next
)
1142 if(!WasTransparent
== !!CalculateIsTransparent())
1145 GetLevel()->ForceEmitterEmitation(EmitterBackup
, SunEmitter
, FORCE_ADD
);
1147 GetLevel()->ForceEmitterEmitation(Emitter
, SunEmitter
);
1149 CalculateLuminance();
1151 if(LastSeen
== game::GetLOSTick())
1152 game::SendLOSUpdateRequest();
1156 void lsquare::DrawParticles(sLong Color
, truth DrawHere
)
1158 if(GetPos().X
< game::GetCamera().X
1159 || GetPos().Y
< game::GetCamera().Y
1160 || GetPos().X
>= game::GetCamera().X
+ game::GetScreenXSize()
1161 || GetPos().Y
>= game::GetCamera().Y
+ game::GetScreenYSize()
1162 || !CanBeSeenByPlayer(true)
1163 || Color
== TRANSPARENT_COLOR
)
1166 clock_t StartTime
= clock();
1169 game::DrawEverythingNoBlit();
1171 if(Color
& RANDOM_COLOR
)
1172 Color
= MakeRGB16(60 + RAND() % 190, 60 + RAND() % 190, 60 + RAND() % 190);
1174 v2 Pos
= game::CalculateScreenCoordinates(GetPos());
1176 for(int c
= 0; c
< 10; ++c
)
1177 DOUBLE_BUFFER
->PutPixel(Pos
+ v2(1 + RAND() % 14, 1 + RAND() % 14), Color
);
1179 Flags
|= STRONG_NEW_DRAW_REQUEST
; // Clean the pixels from the screen afterwards
1183 graphics::BlitDBToScreen();
1184 while(clock() - StartTime
< 0.02 * CLOCKS_PER_SEC
);
1188 truth
lsquare::DipInto(item
* Thingy
, character
* Dipper
)
1190 if(IsDipDestination())
1192 room
* Room
= GetRoom();
1194 if(Room
&& Room
->HasDipHandler() && !Room
->Dip(Dipper
))
1197 return (GLTerrain
->IsDipDestination() && GLTerrain
->DipInto(Thingy
, Dipper
)) || (OLTerrain
&& OLTerrain
->IsDipDestination() && OLTerrain
->DipInto(Thingy
, Dipper
));
1201 if(Dipper
->IsPlayer())
1202 ADD_MESSAGE("You cannot dip %s on that square!", Thingy
->CHAR_NAME(DEFINITE
));
1208 // return true if key fits someplace
1210 truth
lsquare::TryKey(item
* Key
, character
* Applier
)
1212 if(GetOLTerrain() && GetOLTerrain()->TryKey(Key
, Applier
))
1215 if((!GetOLTerrain() || !GetOLTerrain()->HasKeyHole()) && !GetStack()->TryKey(Key
, Applier
))
1217 ADD_MESSAGE("There's no place here to put the key in!");
1224 void lsquare::SignalSeen(feuLong Tick
)
1226 if(LastSeen
< Tick
- 2)
1227 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1229 Flags
&= ~(IN_SQUARE_STACK
|PERFECTLY_QUADRI_HANDLED
);
1232 if(!(Flags
& IS_TRANSPARENT
))
1234 col24 OldLuminance
= Luminance
;
1235 CalculateLuminance();
1237 if(OldLuminance
!= Luminance
)
1239 Flags
|= NEW_DRAW_REQUEST
;
1241 if(IsDark() != game::IsDark(OldLuminance
))
1242 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
1248 v2 Dist
= Pos
- PLAYER
->GetPos();
1250 if(abs(Dist
.X
) > 1 || abs(Dist
.Y
) > 1)
1261 UpdateMemorizedDescription();
1264 Character
->CheckIfSeen();
1267 void lsquare::DrawMemorized(blitdata
& BlitData
) const
1270 Flags
&= ~STRONG_NEW_DRAW_REQUEST
;
1271 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
1274 FowMemorized
->LuminanceBlit(BlitData
);
1276 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
1278 ccharacter
* C
= Character
;
1280 if(C
&& C
->CanBeSeenByPlayer())
1282 BlitData
.CustomData
|= C
->GetSquareIndex(Pos
);
1284 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
1288 void lsquare::DrawMemorizedCharacter(blitdata
& BlitData
) const
1290 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
1293 FowMemorized
->LuminanceBlit(BlitData
);
1295 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
1297 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
1298 Character
->Draw(BlitData
);
1299 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
1300 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1303 truth
lsquare::IsDangerous(ccharacter
* Who
) const
1305 return ((!Who
->IsFlying()
1306 && (Stack
->IsDangerous(Who
)
1307 || HasDangerousFluids(Who
)))
1308 || IsDangerousToBreathe(Who
) || HasDangerousTraps(Who
));
1311 truth
lsquare::IsScary(ccharacter
* Who
) const
1313 return IsScaryToBreathe(Who
);
1316 stack
* lsquare::GetStackOfAdjacentSquare(int I
) const
1318 lsquare
* Square
= 0;
1322 case LEFT
: Square
= NeighbourLSquare
[3]; break;
1323 case DOWN
: Square
= NeighbourLSquare
[6]; break;
1324 case UP
: Square
= NeighbourLSquare
[1]; break;
1325 case RIGHT
: Square
= NeighbourLSquare
[4]; break;
1328 return Square
? Square
->Stack
: 0;
1331 void lsquare::SendMemorizedUpdateRequest()
1333 if(!(Flags
& FREEZED
))
1335 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
1337 if(!game::IsGenerating() && (CanBeSeenByPlayer() || CanBeFeltByPlayer()))
1343 UpdateMemorizedDescription();
1348 void lsquare::KickAnyoneStandingHereAway()
1352 character
* Backup
= Character
;
1354 Backup
->PutNear(Pos
);
1358 outputfile
& operator<<(outputfile
& SaveFile
, const emitter
& Emitter
)
1360 SaveFile
.Write(reinterpret_cast<cchar
*>(&Emitter
), sizeof(Emitter
));
1364 inputfile
& operator>>(inputfile
& SaveFile
, emitter
& Emitter
)
1366 SaveFile
.Read(reinterpret_cast<char*>(&Emitter
), sizeof(Emitter
));
1370 void lsquare::AddItem(item
* Item
)
1372 Stack
->AddItem(Item
);
1375 v2
lsquare::DrawLightning(v2 StartPos
, sLong Color
, int Direction
, truth DrawHere
)
1377 if(GetPos().X
< game::GetCamera().X
1378 || GetPos().Y
< game::GetCamera().Y
1379 || GetPos().X
>= game::GetCamera().X
+ game::GetScreenXSize()
1380 || GetPos().Y
>= game::GetCamera().Y
+ game::GetScreenYSize()
1381 || !CanBeSeenByPlayer(true))
1384 case 1: return v2(RAND() & 15, 15);
1385 case 3: return v2(15, RAND() & 15);
1386 case 4: return v2(0, RAND() & 15);
1387 case 6: return v2(RAND() & 15, 0);
1388 default: return StartPos
;
1391 clock_t StartTime
= clock();
1392 bitmap
Empty(TILE_V2
, TRANSPARENT_COLOR
);
1393 Empty
.ActivateFastFlag();
1395 if(Color
& RANDOM_COLOR
)
1396 Color
= MakeRGB16(60 + RAND() % 190, 60 + RAND() % 190, 60 + RAND() % 190);
1398 if(Direction
!= YOURSELF
)
1400 while(!Empty
.CreateLightning(StartPos
, game::GetMoveVector(Direction
), 16, Color
));
1405 case 0: EndPos
= v2(0, 0); break;
1406 case 1: EndPos
= v2(RAND() & 15, 0); StartPos
= v2(EndPos
.X
, 15); break;
1407 case 2: EndPos
= v2(15, 0); break;
1408 case 3: EndPos
= v2(0, RAND() & 15); StartPos
= v2(15, EndPos
.Y
); break;
1409 case 4: EndPos
= v2(15, RAND() & 15); StartPos
= v2(0, EndPos
.Y
); break;
1410 case 5: EndPos
= v2(0, 15); break;
1411 case 6: EndPos
= v2(RAND() & 15, 15); StartPos
= v2(EndPos
.X
, 0); break;
1412 case 7: EndPos
= v2(15, 15); break;
1415 while(!Empty
.CreateLightning(EndPos
, -game::GetMoveVector(Direction
), NO_LIMIT
, Color
));
1419 static v2 Dir
[4] = { v2(0, -1), v2(-1, 0), v2(1, 0), v2(0, 1) };
1421 for(int d
= 0; d
< 4; ++d
)
1422 while(!Empty
.CreateLightning(StartPos
+ Dir
[d
], ZERO_V2
, 10, Color
));
1426 game::DrawEverythingNoBlit();
1428 blitdata B
= { DOUBLE_BUFFER
,
1431 { TILE_SIZE
, TILE_SIZE
},
1436 B
.Dest
= game::CalculateScreenCoordinates(GetPos());
1437 Empty
.NormalMaskedBlit(B
);
1438 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1442 graphics::BlitDBToScreen();
1443 while(clock() - StartTime
< 0.02 * CLOCKS_PER_SEC
);
1449 truth
lsquare::Polymorph(const beamdata
& Beam
)
1451 GetStack()->Polymorph(Beam
.Owner
);
1454 GetOLTerrain()->Polymorph(Beam
.Owner
);
1456 character
* Character
= GetCharacter();
1460 if(Beam
.Owner
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
1461 Beam
.Owner
->Hostility(Character
);
1463 Character
->PolymorphRandomly(1, 999999, 5000 + RAND() % 5000);
1468 for(int c
= 0; Engraved
[c
] != '\0'; ++c
)
1472 Engraved
[c
] = 32 + RAND_N(95);
1479 truth
lsquare::Strike(const beamdata
& Beam
)
1481 int Damage
= 50 + RAND() % 21 - RAND() % 21;
1482 GetStack()->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
, Beam
.Direction
);
1483 ReceiveTrapDamage(Beam
.Owner
, Damage
, ENERGY
, Beam
.Direction
);
1485 character
* Char
= GetCharacter();
1489 if(Char
->IsPlayer())
1490 ADD_MESSAGE("You are hit by a burst of energy!");
1491 else if(Char
->CanBeSeenByPlayer())
1492 ADD_MESSAGE("%s is hit by a burst of energy!", Char
->CHAR_NAME(DEFINITE
));
1495 Beam
.Owner
->Hostility(Char
);
1497 Char
->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
, ALL
);
1498 Char
->CheckDeath(Beam
.DeathMsg
, Beam
.Owner
);
1502 GetOLTerrain()->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
);
1507 truth
lsquare::FireBall(const beamdata
& Beam
)
1509 if(!IsFlyable() || GetCharacter())
1511 if(CanBeSeenByPlayer(true))
1512 ADD_MESSAGE("A magical explosion is triggered!");
1514 GetLevel()->Explosion(Beam
.Owner
, Beam
.DeathMsg
, Pos
, 75 + RAND() % 25 - RAND() % 25);
1521 truth
lsquare::Teleport(const beamdata
& Beam
)
1525 if(Beam
.Owner
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
1526 Beam
.Owner
->Hostility(GetCharacter());
1528 if(Character
->IsPlayer())
1529 ADD_MESSAGE("You experience a forced teleportation.");
1530 else if(Character
->CanBeSeenByPlayer())
1531 ADD_MESSAGE("%s disappears!", Character
->CHAR_NAME(DEFINITE
));
1533 Character
->TeleportRandomly();
1537 GetLevel()->GetRoom(RoomIndex
)->TeleportSquare(Beam
.Owner
, this);
1539 GetStack()->TeleportRandomly();
1543 truth
lsquare::Haste(const beamdata
&)
1545 GetStack()->Haste();
1546 character
* Dude
= GetCharacter();
1554 truth
lsquare::Slow(const beamdata
& Beam
)
1557 character
* Dude
= GetCharacter();
1562 Beam
.Owner
->Hostility(Dude
);
1570 truth
lsquare::Confuse (const beamdata
&Beam
) {
1571 character
*Dude
= GetCharacter();
1573 if (Dude
&& Dude
->CanBeConfused()) {
1574 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1575 Dude
->BeginTemporaryState(CONFUSED
, 50+RAND()%50);
1581 truth
lsquare::Parasitize (const beamdata
&Beam
) {
1582 character
*Dude
= GetCharacter();
1584 if (Dude
&& Dude
->GetTorso()->CanHaveParasite()) {
1585 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1586 Dude
->GainIntrinsic(PARASITIZED
);
1592 truth
lsquare::InstillPanic (const beamdata
&Beam
) {
1593 character
* Dude
= GetCharacter();
1595 if (Dude
&& Dude
->CanPanic()) {
1596 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1597 Dude
->BeginTemporaryState(PANIC
, 50+RAND()%50);
1603 truth
lsquare::Resurrect(const beamdata
& Beam
)
1606 return GetCharacter()->RaiseTheDead(Beam
.Owner
);
1608 return GetStack()->RaiseTheDead(Beam
.Owner
);
1611 truth
lsquare::Invisibility(const beamdata
&)
1614 GetCharacter()->BeginTemporaryState(INVISIBLE
, 1000 + RAND() % 1001);
1619 truth
lsquare::Duplicate(const beamdata
& Beam
)
1621 truth DuplicatedSomething
= false;
1622 character
* Character
= GetCharacter();
1625 DuplicatedSomething
= truth(Character
->DuplicateToNearestSquare(Beam
.Owner
, Beam
.SpecialParameters
));
1627 if(GetStack()->Duplicate(DuplicatedSomething
? 4 : 5, Beam
.SpecialParameters
))
1628 DuplicatedSomething
= true;
1630 return DuplicatedSomething
;
1633 truth
lsquare::Lightning(const beamdata
& Beam
)
1635 int Damage
= 20 + RAND() % 6 - RAND() % 6;
1636 GetStack()->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
, Beam
.Direction
);
1637 ReceiveTrapDamage(Beam
.Owner
, Damage
, ELECTRICITY
, Beam
.Direction
);
1639 character
* Char
= GetCharacter();
1643 if(Char
->IsPlayer())
1644 ADD_MESSAGE("A massive burst of electricity runs through your body!");
1645 else if(Char
->CanBeSeenByPlayer())
1646 ADD_MESSAGE("A massive burst of electricity runs through %s!", Char
->CHAR_NAME(DEFINITE
));
1649 Beam
.Owner
->Hostility(Char
);
1651 Char
->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
, ALL
);
1652 Char
->CheckDeath(Beam
.DeathMsg
, Beam
.Owner
);
1656 GetOLTerrain()->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
);
1661 truth
lsquare::DoorCreation(const beamdata
& Beam
)
1664 || GetOLTerrain()->IsSafeToCreateDoor())
1666 && (GetLevel()->IsOnGround()
1667 || (Pos
.X
> 0 && Pos
.Y
> 0
1668 && Pos
.X
< GetLevel()->GetXSize() - 1 && Pos
.Y
< GetLevel()->GetYSize() - 1)))
1670 if(Beam
.Owner
&& GetRoom())
1671 GetRoom()->HostileAction(Beam
.Owner
);
1673 door
* Door
= door::Spawn(0, NO_MATERIALS
);
1674 Door
->InitMaterials(MAKE_MATERIAL(STEEL
));
1679 ChangeOLTerrainAndUpdateLights(Door
);
1686 truth (lsquare::*BeamEffect
[BEAM_EFFECTS
])(const beamdata
&) =
1688 &lsquare::Polymorph
,
1694 &lsquare::Resurrect
,
1695 &lsquare::Invisibility
,
1696 &lsquare::Duplicate
,
1697 &lsquare::Lightning
,
1698 &lsquare::DoorCreation
,
1700 &lsquare::Necromancy
1703 truth (lsquare::*lsquare::GetBeamEffect(int I
))(const beamdata
&)
1705 return BeamEffect
[I
];
1708 truth
lsquare::CheckKick(ccharacter
* Kicker
) const
1710 if(Character
&& Kicker
->CheckIfTooScaredToHit(Character
))
1713 if(RoomIndex
&& !GetLevel()->GetRoom(RoomIndex
)->CheckKickSquare(Kicker
, this))
1719 void lsquare::GetHitByExplosion(const explosion
* Explosion
)
1721 if(Explosion
->ID
== LastExplosionID
)
1724 LastExplosionID
= Explosion
->ID
;
1725 int DistanceSquare
= (Pos
- Explosion
->Pos
).GetLengthSquare();
1727 if(DistanceSquare
> Explosion
->RadiusSquare
)
1730 int Damage
= Explosion
->Strength
/ (DistanceSquare
+ 1);
1732 if (Character
&& (Explosion
->HurtNeutrals
|| (Explosion
->Terrorist
&& Character
->GetRelation(Explosion
->Terrorist
) == HOSTILE
))) {
1733 if (Character
->IsPlayer()) game::SetPlayerWasHurtByExplosion(true);
1734 else Character
->GetHitByExplosion(Explosion
, Damage
);
1737 GetStack()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1738 GetStack()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1740 ReceiveTrapDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1741 ReceiveTrapDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1744 GetOLTerrain()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1747 GetOLTerrain()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1750 int lsquare::GetSpoiledItems() const
1752 return GetStack()->GetSpoiledItems();
1755 truth
lsquare::LowerEnchantment(const beamdata
& Beam
)
1757 character
* Char
= GetCharacter();
1758 itemvector AllItems
;
1759 sortdata
SortData(AllItems
, Beam
.Owner
, true, &item::IsEnchantable
);
1760 SortAllItems(SortData
);
1763 if(!AllItems
.empty())
1764 RandomItem
= AllItems
[RAND() % AllItems
.size()];
1770 if(Char
->IsPlayer())
1771 ADD_MESSAGE("%s glows blue for a moment!", RandomItem
->CHAR_NAME(DEFINITE
));
1774 Beam
.Owner
->Hostility(Char
);
1777 if(RandomItem
->GetEnchantment() > -5)
1778 RandomItem
->EditEnchantment(-1);
1783 void lsquare::SortAllItems(const sortdata
& SortData
)
1786 GetCharacter()->SortAllItems(SortData
);
1788 GetStack()->SortAllItems(SortData
);
1791 truth
lsquare::SoftenMaterial (const beamdata
&Beam
) {
1792 character
*Char
= GetCharacter();
1794 itemvector AllItems
;
1796 sortdata
SortData(AllItems
, Beam
.Owner
, true, &item::IsEnchantable
);
1797 SortAllItems(SortData
);
1798 //sortdata SortData2(AllItems, Beam.Owner, true, &item::MaterialIsChangeable);
1799 //SortAllItems(SortData2);
1800 if (AllItems
.empty()) return false;
1801 RandomItem
= AllItems
[RAND() % AllItems
.size()];
1803 if (Char
->IsPlayer()) ADD_MESSAGE("Your %s glows yellow for a moment!", RandomItem
->CHAR_NAME(UNARTICLED
));
1804 if (Beam
.Owner
) Beam
.Owner
->Hostility(Char
);
1810 RandomItem
->AddName(Desc
, UNARTICLED
);
1811 material
*OldMaterial
= RandomItem
->GetMainMaterial();
1812 int NewMaterial
= RandomItem
->GetMainMaterial()->GetSoftenedMaterial(RandomItem
);
1814 if (NewMaterial
!= NONE
) {
1815 /* Don't Forget! It is an ugly thing, I know, but removal = seg-fault since cannot have NONE material */
1816 RandomItem
->ChangeMainMaterial(MAKE_MATERIAL(NewMaterial
)); /*->SpawnMore()*/
1817 if (OldMaterial
->GetConfig() != NewMaterial
) Changed
= 1;
1820 if (Changed
&& Char
->IsPlayer()) {
1821 ADD_MESSAGE("Your %s softens into %s!", Desc
.CStr(), RandomItem
->GetMainMaterial()->GetName(false, false).CStr());
1822 } else if (Changed
) {
1823 ADD_MESSAGE("%s's %s softens into %s!", Char
->CHAR_DESCRIPTION(DEFINITE
), Desc
.CStr(), RandomItem
->GetMainMaterial()->GetName(false, false).CStr());
1826 //may not need this message
1827 if (Char
->IsPlayer()) {
1828 ADD_MESSAGE("Your %s vibrates slightly but remains unchanged.", RandomItem
->CHAR_NAME(UNARTICLED
) );
1830 ADD_MESSAGE("%s's %s vibrates slightly but remains unchanged.", Char
->CHAR_DESCRIPTION(DEFINITE
), RandomItem
->CHAR_NAME(UNARTICLED
) );
1838 void lsquare::RemoveSmoke(smoke
* ToBeRemoved
)
1842 if(S
== ToBeRemoved
)
1847 DecAnimatedEntities();
1858 while(S
!= ToBeRemoved
);
1864 void lsquare::AddSmoke(gas
* ToBeAdded
)
1870 Smoke
= new smoke(ToBeAdded
, this);
1871 IncAnimatedEntities();
1879 if(ToBeAdded
->IsSameAs(S
->GetGas()))
1881 S
->Merge(ToBeAdded
);
1890 LS
->Next
= new smoke(ToBeAdded
, this);
1894 void lsquare::ShowSmokeMessage() const
1896 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
1897 S
->AddBreatheMessage();
1900 void lsquare::SignalSmokeAlphaChange(int What
)
1902 SmokeAlphaSum
+= What
;
1903 SignalPossibleTransparencyChange();
1906 int lsquare::GetDivineMaster() const
1908 return RoomIndex
? GetLevel()->GetRoom(RoomIndex
)->GetDivineMaster() : 0;
1911 void lsquare::DisplaySmokeInfo (festring
&Msg
) const {
1914 Msg
<< " A cloud of " << Smoke
->GetGas()->GetName(false, false) << " surrounds the square.";
1916 Msg
<< " A lot of gases hover over the square.";
1920 void lsquare::ReceiveEarthQuakeDamage()
1922 GetStack()->ReceiveDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1923 ReceiveTrapDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1926 if(GetOLTerrain() && GetOLTerrain()->IsDoor())
1927 GetOLTerrain()->ReceiveDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1930 truth
lsquare::CanBeFeltByPlayer() const
1932 if (!PLAYER
) return false;
1933 return OLTerrain
&& !PLAYER
->CanMoveOn(this) && Pos
.IsAdjacent(PLAYER
->GetPos());
1936 void lsquare::PreProcessForBone()
1942 OLTerrain
->PreProcessForBone();
1946 DecAnimatedEntities();
1948 for(smoke
* S
= Smoke
; S
; S
= S
->Next
)
1955 if(Character
&& !Character
->PreProcessForBone())
1957 Character
->SendToHell();
1958 Character
->Remove();
1961 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
1962 F
->PreProcessForBone();
1964 for(trap
* T
= Trap
; T
; T
= T
->Next
)
1965 T
->PreProcessForBone();
1967 GetStack()->PreProcessForBone();
1970 void lsquare::PostProcessForBone(double& DangerSum
, int& Enemies
)
1973 OLTerrain
->PostProcessForBone();
1975 if(Character
&& !Character
->PostProcessForBone(DangerSum
, Enemies
))
1977 Character
->SendToHell();
1978 Character
->Remove();
1981 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
1982 F
->PostProcessForBone();
1984 for(trap
* T
= Trap
; T
; T
= T
->Next
)
1985 T
->PostProcessForBone();
1987 GetStack()->PostProcessForBone();
1990 void lsquare::FinalProcessForBone()
1993 OLTerrain
->FinalProcessForBone();
1996 Character
->FinalProcessForBone();
1998 GetStack()->FinalProcessForBone();
2001 truth
lsquare::EngravingsCanBeReadByPlayer()
2003 return PLAYER
->CanRead(); // Might be a good idea to improve sometime in the distant future.
2006 void lsquare::DisplayEngravedInfo(festring
& Buffer
) const
2008 Buffer
<< " There is a message engraved here: \"" << Engraved
<< '\"';
2011 truth
lsquare::IsDangerousToBreathe(ccharacter
* Who
) const
2013 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
2014 if(S
->IsDangerousToBreathe(Who
))
2020 truth
lsquare::IsScaryToBreathe(ccharacter
* Who
) const
2022 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
2023 if(S
->IsScaryToBreathe(Who
))
2030 struct groundborderpartner
{
2031 truth
operator < (const groundborderpartner
&P
) const { return Terrain
->GetBorderTilePriority() < P
.Terrain
->GetBorderTilePriority(); }
2036 void lsquare::CalculateGroundBorderPartners () {
2037 if (GroundBorderPartnerInfo
& BORDER_PARTNER_ANIMATED
) DecStaticAnimatedEntities();
2038 groundborderpartner BorderPartner
[8*2]; //k8: *2 to make g++ shut up (WTF?!)
2040 int Priority
= GLTerrain
->GetBorderTilePriority();
2041 for (int d
= 0; d
< 8; ++d
) {
2042 lsquare
*Square
= NeighbourLSquare
[d
];
2044 glterrain
*Terrain
= Square
->GetGLTerrain();
2045 if (Terrain
&& Terrain
->UseBorderTiles() && Terrain
->GetBorderTilePriority() > Priority
) {
2046 BorderPartner
[Index
].Terrain
= Terrain
;
2047 BorderPartner
[Index
].SquareIndex
= 7-d
;
2052 GroundBorderPartnerInfo
= 0;
2054 delete [] GroundBorderPartnerTerrain
;
2055 GroundBorderPartnerTerrain
= 0;
2058 if (!GroundBorderPartnerTerrain
) GroundBorderPartnerTerrain
= new glterrain
*[8];
2059 std::sort(BorderPartner
, BorderPartner
+Index
); // why g++ complains here? ah, ignore it for now
2060 truth Animated
= false;
2061 for (int c
= 0; c
< Index
; ++c
) {
2062 glterrain
*T
= BorderPartner
[c
].Terrain
;
2063 GroundBorderPartnerTerrain
[c
] = T
;
2064 GroundBorderPartnerInfo
|= BorderPartner
[c
].SquareIndex
<<((c
<<1)+c
);
2065 if (T
->IsAnimated()) Animated
= true;
2068 GroundBorderPartnerInfo
|= BORDER_PARTNER_ANIMATED
;
2069 IncStaticAnimatedEntities();
2071 GroundBorderPartnerInfo
|= Index
<<24;
2075 struct overborderpartner
{
2076 truth
operator < (const overborderpartner
&P
) const { return Terrain
->GetBorderTilePriority() < P
.Terrain
->GetBorderTilePriority(); }
2081 void lsquare::CalculateOverBorderPartners () {
2082 if (OverBorderPartnerInfo
& BORDER_PARTNER_ANIMATED
) DecStaticAnimatedEntities();
2083 overborderpartner BorderPartner
[8*2]; //k8: *2 to make g++ shut up (WTF?!)
2085 int Priority
= OLTerrain
? OLTerrain
->GetBorderTilePriority() : 0;
2086 for (int d
= 0; d
< 8; ++d
) {
2087 lsquare
*Square
= NeighbourLSquare
[d
];
2089 olterrain
*Terrain
= Square
->GetOLTerrain();
2090 if (Terrain
&& Terrain
->UseBorderTiles() && Terrain
->GetBorderTilePriority() > Priority
) {
2091 BorderPartner
[Index
].Terrain
= Terrain
;
2092 BorderPartner
[Index
].SquareIndex
= 7-d
;
2097 OverBorderPartnerInfo
= 0;
2099 delete [] OverBorderPartnerTerrain
;
2100 OverBorderPartnerTerrain
= 0;
2103 if (!OverBorderPartnerTerrain
) OverBorderPartnerTerrain
= new olterrain
*[8];
2104 std::sort(BorderPartner
, BorderPartner
+Index
); // why g++ complains here? ah, ignore it for now
2105 truth Animated
= false;
2106 for (int c
= 0; c
< Index
; ++c
) {
2107 olterrain
*T
= BorderPartner
[c
].Terrain
;
2108 OverBorderPartnerTerrain
[c
] = T
;
2109 OverBorderPartnerInfo
|= BorderPartner
[c
].SquareIndex
<<((c
<<1)+c
);
2110 if (T
->IsAnimated()) Animated
= true;
2113 OverBorderPartnerInfo
|= BORDER_PARTNER_ANIMATED
;
2114 IncStaticAnimatedEntities();
2116 OverBorderPartnerInfo
|= Index
<<24;
2118 if(OverBorderPartnerInfo & BORDER_PARTNER_ANIMATED)
2119 int esko = esko = 2;
2124 void lsquare::RequestForGroundBorderPartnerUpdates()
2126 if(!game::IsGenerating())
2127 for(int d
= 0; d
< 8; ++d
)
2129 lsquare
* Square
= NeighbourLSquare
[d
];
2133 Square
->CalculateGroundBorderPartners();
2134 Square
->SendNewDrawRequest();
2135 Square
->SendMemorizedUpdateRequest();
2140 void lsquare::RequestForOverBorderPartnerUpdates()
2142 if(!game::IsGenerating())
2143 for(int d
= 0; d
< 8; ++d
)
2145 lsquare
* Square
= NeighbourLSquare
[d
];
2149 Square
->CalculateOverBorderPartners();
2150 Square
->SendNewDrawRequest();
2151 Square
->SendMemorizedUpdateRequest();
2156 int lsquare::GetWalkability() const
2158 if(!GetLevel()->IsOnGround())
2160 if(Pos
.X
>= 1 && Pos
.Y
>= 1 && Pos
.X
< GetLevel()->GetXSize() - 1 && Pos
.Y
< GetLevel()->GetYSize() - 1)
2161 return OLTerrain
? OLTerrain
->GetWalkability() & GLTerrain
->GetWalkability() : GLTerrain
->GetWalkability();
2166 return OLTerrain
? OLTerrain
->GetWalkability() & GLTerrain
->GetWalkability() : GLTerrain
->GetWalkability();
2169 void lsquare::RemoveFluid(fluid
* ToRemove
)
2171 fluid
*& F
= ListFind(Fluid
, pointercomparer
<fluid
>(ToRemove
));
2173 SignalEmitationDecrease(ToRemove
->GetEmitation());
2176 struct fluidcomparer
2178 fluidcomparer(const liquid
* Liquid
) : Liquid(Liquid
) { }
2179 truth
operator()(const fluid
* F
) const { return Liquid
->IsSameAs(F
->GetLiquid()); }
2180 const liquid
* Liquid
;
2183 fluid
* lsquare::AddFluid(liquid
* ToBeAdded
)
2185 fluid
*& F
= ListFind(Fluid
, fluidcomparer(ToBeAdded
));
2189 F
->AddLiquidAndVolume(ToBeAdded
->GetVolume());
2194 F
= new fluid(ToBeAdded
, this);
2195 SignalEmitationIncrease(ToBeAdded
->GetEmitation());
2198 SendNewDrawRequest();
2199 SendMemorizedUpdateRequest();
2203 void lsquare::DisplayFluidInfo(festring
& Msg
) const
2207 Msg
<< ". There is ";
2208 fluid::AddFluidInfo(Fluid
, Msg
);
2209 AddLocationDescription(Msg
);
2213 void lsquare::SpillFluid(character
* Spiller
, liquid
* Liquid
, truth ForceHit
, truth ShowMsg
)
2215 if(!Liquid
->GetVolume())
2225 if(Spiller
&& !GetCharacter()->IsAlly(Spiller
))
2226 Spiller
->Hostility(GetCharacter());
2228 sLong CharVolume
= GetCharacter()->GetVolume();
2229 double ChanceMultiplier
= 1. / (300 + sqrt(GetStack()->GetVolume() + CharVolume
));
2230 double Root
= sqrt(CharVolume
);
2232 if(ForceHit
|| Root
> RAND() % 400 || Root
> RAND() % 400)
2234 sLong SpillVolume
= sLong(Liquid
->GetVolume() * Root
* ChanceMultiplier
);
2238 if(ShowMsg
&& (GetCharacter()->IsPlayer() || GetCharacter()->CanBeSeenByPlayer()))
2239 ADD_MESSAGE("%s is spilled all over %s.", Liquid
->GetName(false, false).CStr(), GetCharacter()->CHAR_DESCRIPTION(DEFINITE
));
2241 Liquid
->EditVolume(-SpillVolume
);
2242 GetCharacter()->SpillFluid(Spiller
, Liquid
->SpawnMoreLiquid(SpillVolume
), GetCharacter()->GetSquareIndex(GetPos()));
2247 GetStack()->SpillFluid(Spiller
, Liquid
, Liquid
->GetVolume());
2250 if(Liquid
->GetVolume() && !Liquid
->IsSameAs(GLTerrain
->GetMainMaterial()))
2252 fluid
* F
= AddFluid(Liquid
);
2255 F
->StepOnEffect(GetCharacter());
2261 void lsquare::DrawStacks(blitdata
& BlitData
) const
2263 Stack
->Draw(PLAYER
, BlitData
, CENTER
);
2265 for(int c
= 0; c
< 4; ++c
)
2267 stack
* Stack
= GetStackOfAdjacentSquare(c
);
2270 Stack
->Draw(PLAYER
, BlitData
, 3 - c
);
2274 void lsquare::RemoveRain(rain
* ToBeRemoved
)
2276 SendNewDrawRequest();
2279 if(ToBeRemoved
->IsEnabled())
2280 DecAnimatedEntities();
2282 if(R
== ToBeRemoved
)
2293 while(R
!= ToBeRemoved
);
2298 SignalEmitationDecrease(ToBeRemoved
->GetEmitation());
2301 void lsquare::AddRain(liquid
* RainLiquid
, v2 Speed
, int Team
, truth OwnLiquid
)
2303 rain
* R
= Rain
, * NewRain
= new rain(RainLiquid
, this, Speed
, Team
, OwnLiquid
);
2305 if(NewRain
->IsEnabled())
2306 IncAnimatedEntities();
2325 void lsquare::RemoveSunLight()
2327 SunLightLuminance
= 0;
2331 void lsquare::CheckIfIsSecondarySunLightEmitter()
2333 col24 OldEmitation
= SecondarySunLightEmitation
;
2335 if(Flags
& IS_TRANSPARENT
&& (!(Flags
& INSIDE
) || SunLightLuminance
))
2336 for(int d
= 0; d
< 8; ++d
)
2338 lsquare
* Neighbour
= NeighbourLSquare
[d
];
2340 if(Neighbour
&& Neighbour
->Flags
& INSIDE
)
2342 col24 NewEmitation
= GetLevel()->GetAmbientLuminance();
2344 if(OldEmitation
!= NewEmitation
)
2346 SecondarySunLightEmitation
= NewEmitation
;
2348 if(game::CompareLights(NewEmitation
, OldEmitation
) >= 0)
2349 Emitate(NewEmitation
, SECONDARY_SUN_LIGHT
);
2352 Noxify(OldEmitation
, SECONDARY_SUN_LIGHT
);
2353 Emitate(NewEmitation
, SECONDARY_SUN_LIGHT
|FORCE_ADD
);
2363 Noxify(OldEmitation
, SECONDARY_SUN_LIGHT
);
2364 SecondarySunLightEmitation
= 0;
2368 void lsquare::CalculateNeighbourLSquares()
2370 int XSize
= GetLevel()->GetXSize();
2371 int YSize
= GetLevel()->GetYSize();
2373 for(int d
= 0; d
< 8; ++d
)
2375 v2 NPos
= Pos
+ game::GetMoveVector(d
);
2377 if(NPos
.X
>= 0 && NPos
.Y
>= 0 && NPos
.X
< XSize
&& NPos
.Y
< YSize
)
2378 NeighbourLSquare
[d
] = GetLevel()->GetLSquare(NPos
);
2380 NeighbourLSquare
[d
] = 0;
2384 void lsquare::RemoveLuminance(col24
& Emitation
)
2386 col24 OldLuminance
= Luminance
;
2387 col24 OldEmitation
= Emitation
;
2390 if(game::CompareLights(OldEmitation
, OldLuminance
) < 0)
2393 if(!(Flags
& IS_TRANSPARENT
))
2395 Flags
|= NEW_DRAW_REQUEST
;
2397 if(LastSeen
== game::GetLOSTick())
2398 game::SendLOSUpdateRequest();
2402 CalculateLuminance();
2404 if(OldLuminance
== Luminance
)
2407 Flags
|= NEW_DRAW_REQUEST
;
2411 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2413 if(LastSeen
== game::GetLOSTick())
2414 game::SendLOSUpdateRequest();
2419 void lsquare::ChangeLuminance(col24
& Emitation
, col24 NewLuminance
)
2421 col24 OldLuminance
= Luminance
;
2423 if(!(Flags
& IS_TRANSPARENT
))
2425 Emitation
= NewLuminance
;
2426 Flags
|= NEW_DRAW_REQUEST
;
2428 if(LastSeen
== game::GetLOSTick())
2429 game::SendLOSUpdateRequest();
2434 truth EmitationInsignificant
= !Emitation
2435 || game::CompareLights(Emitation
, OldLuminance
) < 0;
2436 Emitation
= NewLuminance
;
2438 if(game::CompareLights(NewLuminance
, OldLuminance
) > 0
2439 && EmitationInsignificant
)
2440 game::CombineLights(Luminance
, NewLuminance
);
2443 if(EmitationInsignificant
)
2446 CalculateLuminance();
2448 if(OldLuminance
== Luminance
)
2452 Flags
|= NEW_DRAW_REQUEST
;
2456 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2458 if(LastSeen
== game::GetLOSTick())
2459 game::SendLOSUpdateRequest();
2463 void lsquare::EnableGlobalRain()
2465 for(rain
* R
= Rain
; R
; R
= R
->Next
)
2466 if(!R
->HasOwnLiquid())
2469 IncAnimatedEntities();
2473 void lsquare::DisableGlobalRain()
2475 SendNewDrawRequest();
2477 for(rain
* R
= Rain
; R
; R
= R
->Next
)
2478 if(!R
->HasOwnLiquid())
2481 DecAnimatedEntities();
2485 void lsquare::InitLastSeen()
2487 LastSeen
= LastSeen
== game::GetLOSTick() ? 2 : 0;
2488 SquarePartLastSeen
= 0;
2491 truth
lsquare::Engrave(cfestring
& What
)
2498 Engraved
= new char[What
.GetSize() + 1];
2499 strcpy(Engraved
, What
.CStr());
2507 void lsquare::SendSunLightSignals()
2509 if(Flags
& IS_TRANSPARENT
)
2511 col24 OldLuminance
= Luminance
;
2512 CalculateLuminance();
2514 if(Luminance
!= OldLuminance
)
2516 Flags
|= NEW_DRAW_REQUEST
;
2518 if(!Luminance
!= !OldLuminance
)
2520 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2522 if(LastSeen
== game::GetLOSTick())
2523 game::SendLOSUpdateRequest();
2529 Flags
|= NEW_DRAW_REQUEST
;
2531 if(LastSeen
== game::GetLOSTick())
2532 game::SendLOSUpdateRequest();
2536 void lsquare::ZeroReSunEmitatedFlags()
2538 sunemittervector::iterator i
, End
= SunEmitter
.end();
2540 for(i
= SunEmitter
.begin(); i
!= End
; ++i
)
2541 *i
&= ~RE_SUN_EMITATED
;
2544 truth
lsquare::CalculateIsTransparent()
2546 if((!OLTerrain
|| OLTerrain
->IsTransparent()) && SmokeAlphaSum
< 175
2547 && (!Character
|| Character
->IsTransparent()))
2549 Flags
|= IS_TRANSPARENT
;
2554 Flags
&= ~IS_TRANSPARENT
;
2559 void lsquare::CalculateSunLightLuminance(feuLong SeenBitMask
)
2561 sunemittervector::const_iterator i
, SunEnd
= SunEmitter
.end();
2564 for(i
= SunEmitter
.begin(); i
!= SunEnd
; ++i
)
2566 feuLong ShadowFlag
= 1 << EMITTER_SHADOW_SHIFT
;
2567 feuLong SquarePartFlag
= 1 << EMITTER_SQUARE_PART_SHIFT
;
2568 for (int c
= 0; c
< 4; ++c
, ShadowFlag
<<= 1, SquarePartFlag
<<= 1) {
2569 if (SeenBitMask
& *i
& SquarePartFlag
) {
2570 if (*i
& ShadowFlag
) ++S
; else ++L
;
2576 SunLightLuminance
= 0;
2578 SunLightLuminance
= GetLevel()->GetSunLightEmitation();
2581 col24 ShadowColor
= GetLevel()->GetAmbientLuminance();
2582 col24 LightColor
= GetLevel()->GetSunLightEmitation();
2583 SunLightLuminance
= MakeRGB24((GetRed24(LightColor
) * L
2584 + GetRed24(ShadowColor
) * S
) / (S
+ L
),
2585 (GetGreen24(LightColor
) * L
2586 + GetGreen24(ShadowColor
) * S
) / (S
+ L
),
2587 (GetBlue24(LightColor
) * L
2588 + GetBlue24(ShadowColor
) * S
) / (S
+ L
));
2592 void lsquare::CreateMemorized()
2594 Memorized
= new bitmap(TILE_V2
);
2595 Memorized
->ActivateFastFlag();
2596 FowMemorized
= new bitmap(TILE_V2
);
2597 FowMemorized
->ActivateFastFlag();
2600 truth
lsquare::AcidRain(const beamdata
& Beam
)
2602 if(!IsFlyable() || GetCharacter() || Beam
.Direction
== YOURSELF
)
2604 int StackSize
= GetLevel()->AddRadiusToSquareStack(Pos
, 9);
2605 lsquare
** Stack
= GetLevel()->GetSquareStack();
2606 v2 Speed
= v2(512, 512);
2607 int Team
= Beam
.Owner
? Beam
.Owner
->GetTeam()->GetID() : MONSTER_TEAM
;
2609 for(int c
= 0; c
< StackSize
; ++c
)
2611 Stack
[c
]->AddRain(liquid::Spawn(SULPHURIC_ACID
, 300), Speed
, Team
, true);
2612 Stack
[c
]->Flags
&= ~IN_SQUARE_STACK
;
2615 if(Beam
.Owner
&& Character
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
2616 Beam
.Owner
->Hostility(Character
);
2624 truth
lsquare::DetectMaterial (cmaterial
*Material
) const {
2625 if (GLTerrain
->DetectMaterial(Material
) ||
2626 (OLTerrain
&& OLTerrain
->DetectMaterial(Material
)) ||
2627 Stack
->DetectMaterial(Material
) ||
2628 (Character
&& Character
->DetectMaterial(Material
))) return true;
2629 for (const fluid
*F
= Fluid
; F
; F
= F
->Next
) if (F
->GetLiquid()->IsSameAs(Material
)) return true;
2630 for (const smoke
*S
= Smoke
; S
; S
= S
->Next
) if (S
->GetGas()->IsSameAs(Material
)) return true;
2631 for (const rain
*R
= Rain
; R
; R
= R
->Next
) if (R
->GetLiquid()->IsSameAs(Material
)) return true;
2635 void lsquare::Reveal(feuLong Tick
, truth IgnoreDarkness
)
2643 Luminance
= NORMAL_LUMINANCE
;
2646 SquarePartLastSeen
= 0;
2648 for(int c
= 0; c
< 4; ++c
)
2649 SquarePartLastSeen
|= (Tick
<< (c
<< 3));
2651 CalculateLuminance();
2654 Flags
|= NEW_DRAW_REQUEST
2655 | MEMORIZED_UPDATE_REQUEST
2656 | DESCRIPTION_CHANGE
;
2658 UpdateMemorizedDescription();
2661 void lsquare::DestroyMemorized()
2664 delete FowMemorized
;
2669 void lsquare::SwapMemorized(lsquare
* Square
)
2671 Swap(Memorized
, Square
->Memorized
);
2672 Swap(FowMemorized
, Square
->FowMemorized
);
2673 MemorizedDescription
.SwapData(Square
->MemorizedDescription
);
2676 truth
lsquare::Necromancy(const beamdata
& Beam
)
2678 return GetStack()->Necromancy(Beam
.Owner
);
2681 // Returns 0 if fails
2683 lsquare
* lsquare::GetRandomAdjacentSquare() const
2688 for(int c
= 0; c
< 8; ++c
)
2690 lsquare
* Square
= NeighbourLSquare
[c
];
2693 OK
[Index
++] = Square
;
2697 return OK
[RAND_N(Index
)];
2702 truth
pathcontroller::Handler(int x
, int y
)
2704 return Character
->CanMoveOn(Map
[x
][y
]);
2707 void lsquare::SignalPossibleTransparencyChange()
2709 truth WasTransparent
= IsTransparent();
2710 CalculateIsTransparent();
2712 if(WasTransparent
&& !IsTransparent())
2714 Flags
|= IS_TRANSPARENT
;
2715 emittervector EmitterBackup
= Emitter
;
2716 GetLevel()->ForceEmitterNoxify(EmitterBackup
);
2717 Flags
&= ~IS_TRANSPARENT
;
2718 GetLevel()->ForceEmitterEmitation(EmitterBackup
, SunEmitter
, FORCE_ADD
);
2719 CalculateLuminance();
2720 Flags
|= DESCRIPTION_CHANGE
|MEMORIZED_UPDATE_REQUEST
;
2722 if(LastSeen
== game::GetLOSTick())
2723 game::SendLOSUpdateRequest();
2725 else if(!WasTransparent
&& IsTransparent())
2727 GetLevel()->ForceEmitterEmitation(Emitter
, SunEmitter
);
2728 CalculateLuminance();
2729 Flags
|= DESCRIPTION_CHANGE
|MEMORIZED_UPDATE_REQUEST
;
2731 if(LastSeen
== game::GetLOSTick())
2732 game::SendLOSUpdateRequest();
2736 void lsquare::RemoveTrap(trap
* ToRemove
)
2738 trap
*& T
= ListFind(Trap
, pointercomparer
<trap
>(ToRemove
));
2740 SendNewDrawRequest();
2741 SendMemorizedUpdateRequest();
2746 trapcomparer(int Type
) : Type(Type
) { }
2747 truth
operator()(const trap
* T
) const { return T
->GetType() == Type
; }
2751 truth
lsquare::AddTrap(trap
* ToBeAdded
)
2753 trap
*& T
= ListFind(Trap
, trapcomparer(ToBeAdded
->GetType()));
2763 ToBeAdded
->SetLSquareUnder(this);
2764 SendNewDrawRequest();
2765 SendMemorizedUpdateRequest();
2769 void lsquare::DisplayTrapInfo(festring
& Msg
) const
2771 for(const trap
* T
= Trap
; T
; T
= T
->Next
)
2772 T
->AddDescription(Msg
);
2775 void lsquare::FillTrapVector(std::vector
<trap
*>& TrapVector
) const
2777 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2778 TrapVector
.push_back(T
);
2781 void lsquare::ReceiveTrapDamage(character
* Damager
, int Damage
, int Type
, int Direction
)
2783 std::vector
<trap
*> TrapVector
;
2784 FillTrapVector(TrapVector
);
2786 for(uInt c
= 0; c
< TrapVector
.size(); ++c
)
2787 TrapVector
[c
]->ReceiveDamage(Damager
, Damage
, Type
, Direction
);
2790 truth
lsquare::HasDangerousTraps(ccharacter
* Who
) const
2792 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2793 if(T
->IsDangerous(Who
))
2799 truth
lsquare::HasDangerousFluids(ccharacter
* Who
) const
2801 for(const fluid
* F
= Fluid
; F
; F
= F
->Next
)
2802 if(F
->IsDangerous(Who
))
2808 truth
lsquare::HasNoBorderPartners() const
2810 return !(GroundBorderPartnerInfo
>> 24) && !(OverBorderPartnerInfo
>> 24);
2813 void lsquare::AddLocationDescription(festring
& String
) const
2816 GLTerrain
->AddLocationDescription(String
);
2818 OLTerrain
->AddLocationDescription(String
);
2821 truth
lsquare::VomitingIsDangerous(ccharacter
* Char
) const
2823 return ((OLTerrain
&& OLTerrain
->VomitingIsDangerous(Char
))
2824 || (Character
&& Character
->GetTeam() != Char
->GetTeam()
2825 && Character
->GetRelation(Char
) != HOSTILE
));
2828 bool lsquare::TeleportAllSmokeAway()
2833 bool lsquare::TeleportAllFluidsAway()
2838 bool lsquare::TeleportAllTrapsAway()
2840 for(trap
* T
= Trap
; T
; T
= Trap
)
2844 v2 V
, Pos
= GetPos();
2845 for(V
= GetLevel()->GetRandomSquare(); V
!= Pos
; V
= GetLevel()->GetRandomSquare());
2846 GetNearLSquare(V
)->AddTrap(T
);
2852 void lsquare::AddSpecialCursors()
2854 if((FowMemorized
|| game::GetSeeWholeMapCheatMode()) && OLTerrain
)
2855 OLTerrain
->AddSpecialCursors();