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
);
586 SaveFile
<< GLTerrain
<< OLTerrain
;
587 SaveFile
<< Emitter
<< SunEmitter
;
588 SaveFile
<< Emitation
<< Engraved
<< Luminance
;
589 SaveFile
<< SmokeAlphaSum
<< (uChar
)Flags
<< Memorized
;
590 SaveFile
<< SecondarySunLightEmitation
;
591 SaveFile
<< (uChar
)RoomIndex
;
592 SaveFile
<< SunLightLuminance
;
593 SaveLinkedList(SaveFile
, Fluid
);
594 SaveLinkedList(SaveFile
, Smoke
);
595 SaveLinkedList(SaveFile
, Rain
);
596 SaveLinkedList(SaveFile
, Trap
);
599 void lsquare::Load(inputfile
& SaveFile
)
601 Stack
->Load(SaveFile
); // This must be before square::Load! (Note: This comment is years old. It's probably obsolete)
602 Stack
->SetMotherSquare(this);
603 square::Load(SaveFile
);
605 SaveFile
>> GLTerrain
>> OLTerrain
;
606 SaveFile
>> Emitter
>> SunEmitter
;
607 SaveFile
>> Emitation
>> Engraved
>> Luminance
;
608 SaveFile
>> SmokeAlphaSum
>> (uChar
&)Flags
>> Memorized
;
609 Flags
&= INSIDE
|DESCRIPTION_CHANGE
; //only these flags are loaded
610 Flags
|= MEMORIZED_UPDATE_REQUEST
;
611 SecondarySunLightEmitation
= ReadType(col24
, SaveFile
);
612 RoomIndex
= ReadType(uChar
, SaveFile
);
613 SunLightLuminance
= ReadType(col24
, SaveFile
);
614 LoadLinkedList(SaveFile
, Fluid
);
615 LoadLinkedList(SaveFile
, Smoke
);
616 LoadLinkedList(SaveFile
, Rain
);
617 LoadLinkedList(SaveFile
, Trap
);
618 CalculateIsTransparent();
622 FowMemorized
= new bitmap(TILE_V2
);
623 FowMemorized
->ActivateFastFlag();
624 Memorized
->FastBlit(FowMemorized
);
625 blitdata B
= { FowMemorized
,
628 { TILE_SIZE
, TILE_SIZE
},
633 igraph::GetFOWGraphic()->NormalMaskedBlit(B
);
637 void lsquare::CalculateLuminance()
639 Luminance
= AmbientLuminance
;
640 emittervector::const_iterator i
, End
= Emitter
.end();
642 if(Flags
& IS_TRANSPARENT
)
644 game::CombineLights(Luminance
, SunLightLuminance
);
646 for(i
= Emitter
.begin(); i
!= End
; ++i
)
647 game::CombineLights(Luminance
, i
->Emitation
);
651 feuLong BitMask
= 0, LOSTick
= game::GetLOSTick();
653 for(int c
= 0; c
< 4; ++c
)
654 if((SquarePartLastSeen
>> (c
<< 3) & 0xFF) >= LOSTick
)
655 BitMask
|= 1 << EMITTER_SQUARE_PART_SHIFT
<< c
;
657 CalculateSunLightLuminance(BitMask
);
658 game::CombineLights(Luminance
, SunLightLuminance
);
660 for(i
= Emitter
.begin(); i
!= End
; ++i
)
662 game::CombineLights(Luminance
, i
->Emitation
);
666 void lsquare::AddCharacter(character
* Guy
)
669 ABORT("Overgrowth of square population detected!");
672 SignalEmitationIncrease(Guy
->GetEmitation());
673 Flags
|= STRONG_NEW_DRAW_REQUEST
;
675 if(Guy
->IsAnimated())
676 IncAnimatedEntities();
678 SignalPossibleTransparencyChange();
681 || (Guy
->CanBeSeenByPlayer(true) && CanBeSeenByPlayer()))
685 void lsquare::Clean()
690 void lsquare::RemoveCharacter()
694 character
* Backup
= Character
;
696 if(Backup
->IsAnimated())
697 DecAnimatedEntities();
700 SignalEmitationDecrease(Backup
->GetEmitation());
701 Flags
|= STRONG_NEW_DRAW_REQUEST
;
702 SignalPossibleTransparencyChange();
706 void lsquare::UpdateMemorizedDescription(truth Cheat
)
708 if(Flags
& DESCRIPTION_CHANGE
|| Cheat
)
710 if(!IsDark() || Cheat
)
712 MemorizedDescription
.Empty();
714 if(!OLTerrain
|| (OLTerrain
->IsTransparent() && OLTerrain
->ShowThingsUnder()))
716 truth Anything
= false;
718 if(OLTerrain
&& OLTerrain
->GetNameSingular().GetSize())
720 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
724 if(Flags
& IS_TRANSPARENT
)
726 itemvectorvector PileVector
;
727 GetStack()->Pile(PileVector
, PLAYER
, CENTER
);
729 if(PileVector
.size())
732 MemorizedDescription
<< " and ";
734 if(PileVector
.size() == 1)
735 PileVector
[0][0]->AddName(MemorizedDescription
, INDEFINITE
, PileVector
[0].size());
737 MemorizedDescription
<< "many items";
739 MemorizedDescription
<< " on ";
743 MemorizedDescription
<< " on ";
745 GLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
747 GetSideItemDescription(SideItems
, Cheat
);
749 if(!SideItems
.IsEmpty())
750 MemorizedDescription
<< " and " << SideItems
;
755 MemorizedDescription
<< " on ";
757 GLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
761 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
764 DisplayFluidInfo(MemorizedDescription
);
766 DisplayTrapInfo(MemorizedDescription
);
769 MemorizedDescription
<< " (pos " << Pos
.X
<< ':' << Pos
.Y
<< ")";
771 else if(CanBeFeltByPlayer())
773 MemorizedDescription
.Empty();
774 OLTerrain
->AddName(MemorizedDescription
, INDEFINITE
);
777 DisplayFluidInfo(MemorizedDescription
);
779 DisplayTrapInfo(MemorizedDescription
);
782 MemorizedDescription
= CONST_S("darkness");
784 Flags
&= ~DESCRIPTION_CHANGE
;
788 void lsquare::GetSideItemDescription(festring
& String
, truth Cheat
) const
792 for(int c
= 0; c
< 4; ++c
)
794 stack
* Stack
= GetStackOfAdjacentSquare(c
);
798 ? Stack
->GetSideItems(3 - c
)
799 : Stack
->GetVisibleSideItems(PLAYER
, 3 - c
);
803 String
<< "many items on the wall";
806 for(int c
= 0; c
< 4; ++c
)
808 stack
* Stack
= GetStackOfAdjacentSquare(c
);
811 && ((Cheat
&& Stack
->GetSideItems(3 - c
))
812 || (!Cheat
&& Stack
->GetVisibleSideItems(PLAYER
, 3 - c
))))
813 Stack
->GetBottomSideItem(PLAYER
, 3 - c
, Cheat
)->AddName(String
, INDEFINITE
);
816 String
<< " on the wall";
820 truth
lsquare::BeKicked(character
* Kicker
, item
* Boot
, bodypart
* Leg
, double KickDamage
, double KickToHitValue
, int Success
, int Direction
, truth Critical
, truth ForceHit
)
826 GetCharacter()->BeKicked(Kicker
, Boot
, Leg
, Pos
, KickDamage
, KickToHitValue
, Success
, Direction
, Critical
, ForceHit
);
833 GetLevel()->GetRoom(RoomIndex
)->KickSquare(Kicker
, this);
835 GetStack()->BeKicked(Kicker
, int(KickDamage
), Direction
);
838 GetOLTerrain()->BeKicked(Kicker
, int(KickDamage
* (100 + Success
) / 100), Direction
);
843 truth
lsquare::CanBeDug() const
845 if((!GetPos().X
|| !GetPos().Y
|| GetPos().X
== GetLevel()->GetXSize() - 1 || GetPos().Y
== GetLevel()->GetYSize() - 1) && !*GetLevel()->GetLevelScript()->IsOnGround())
847 ADD_MESSAGE("Somehow you feel that by digging this square you would collapse the whole dungeon.");
854 void lsquare::ChangeLTerrain(glterrain
* NewGround
, olterrain
* NewOver
)
856 ChangeGLTerrain(NewGround
);
857 ChangeOLTerrain(NewOver
);
860 void lsquare::ChangeGLTerrain(glterrain
* NewGround
)
862 if(GLTerrain
->IsAnimated())
863 DecStaticAnimatedEntities();
865 truth WasUsingBorderTiles
= GLTerrain
->UseBorderTiles();
867 GLTerrain
= NewGround
;
868 NewGround
->SetLSquareUnder(this);
869 Flags
|= NEW_DRAW_REQUEST
;
870 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
871 CalculateGroundBorderPartners();
872 SendMemorizedUpdateRequest();
874 if(WasUsingBorderTiles
|| NewGround
->UseBorderTiles())
875 RequestForGroundBorderPartnerUpdates();
877 if(NewGround
->IsAnimated())
878 IncStaticAnimatedEntities();
881 void lsquare::ChangeOLTerrain(olterrain
* NewOver
)
883 if(OLTerrain
&& OLTerrain
->IsAnimated())
884 DecStaticAnimatedEntities();
886 truth WasUsingBorderTiles
= OLTerrain
&& OLTerrain
->UseBorderTiles();
889 Flags
|= NEW_DRAW_REQUEST
;
890 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
891 CalculateOverBorderPartners();
892 CalculateIsTransparent();
893 SendMemorizedUpdateRequest();
895 if(WasUsingBorderTiles
|| (NewOver
&& NewOver
->UseBorderTiles()))
896 RequestForOverBorderPartnerUpdates();
900 NewOver
->SetLSquareUnder(this);
902 if(NewOver
->IsAnimated())
903 IncStaticAnimatedEntities();
907 void lsquare::SetLTerrain(glterrain
* NewGround
, olterrain
* NewOver
)
909 GLTerrain
= NewGround
;
910 NewGround
->SetLSquareUnder(this);
912 if(NewGround
->IsAnimated())
913 IncStaticAnimatedEntities();
919 NewOver
->SetLSquareUnder(this);
921 if(NewOver
->IsAnimated())
922 IncStaticAnimatedEntities();
924 if(!NewOver
->IsTransparent())
925 Flags
&= ~IS_TRANSPARENT
;
928 GetLevel()->SetWalkability(Pos
, GetTheoreticalWalkability());
932 void lsquare::ApplyScript (const squarescript
*SquareScript
, room
*Room
) {
933 if (SquareScript
->AttachRequired()) GetLevel()->AddToAttachQueue(Pos
);
935 int EntryIndex
= SquareScript
->GetEntryIndex();
937 if (EntryIndex
!= NO_ENTRY
) 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
) {
958 const interval
*TimesPtr
= Items
->Data
[c1
].GetTimes();
959 int Times
= TimesPtr
? TimesPtr
->Randomize() : 1;
961 for (int c2
= 0; c2
< Times
; ++c2
) {
962 item
*Item
= Items
->Data
[c1
].Instantiate();
965 int SquarePosition
= Items
->Data
[c1
].GetSquarePosition();
967 if (SquarePosition
!= CENTER
) Item
->SignalSquarePositionChange(SquarePosition
);
968 GetStack()->AddItem(Item
);
969 Item
->SpecialGenerationHandler();
975 const contentscript
<glterrain
> *GLTerrainScript
= SquareScript
->GetGTerrain();
977 if (GLTerrainScript
) {
978 GetLevel()->AddFlag(Pos
, FORBIDDEN
);
979 ChangeGLTerrain(GLTerrainScript
->Instantiate());
981 if (GLTerrainScript
->IsInside()) {
982 if (*GLTerrainScript
->IsInside()) Flags
|= INSIDE
; else Flags
&= ~INSIDE
;
986 const contentscript
<olterrain
> *OLTerrainScript
= SquareScript
->GetOTerrain();
988 if (OLTerrainScript
) {
989 olterrain
*terra
= OLTerrainScript
->Instantiate();
992 GetLevel()->AddFlag(Pos
, FORBIDDEN
);
993 // check for random altars
994 if (terra
->AcceptsOffers()) {
995 //FIXME: make IsAltar()? for now only altars can accept offers
996 if (Room
->GetDivineMaster()) {
997 //if (Terrain->GetConfig() != RoomClass->GetDivineMaster()) ABORT("Random altar in room with DivineMaster!");
998 if (terra
->GetConfig() != Room
->GetDivineMaster()) {
1000 fprintf(stderr
, "forced altar!\n");
1002 terra
= altar::Spawn(Room
->GetDivineMaster());
1005 // no DivineMaster yet, assign it
1006 const fearray
<int> *am
= Room
->GetScript()->GetAllowedDivineMasters();
1008 if (am
&& am
->Size
> 0) {
1009 int Owner
= am
->GetRandomElement();
1012 fprintf(stderr, "AllowedDivineMasters:");
1013 for (uInt f = 0; f < am->Size; ++f) fprintf(stderr, " %d", (*am)[f]);
1014 fprintf(stderr, "\n");
1017 if (Owner
< 1 || Owner
> GODS
) ABORT("Your god is a bad god!");
1019 if (terra
->GetConfig() != Owner
) {
1020 fprintf(stderr
, "recreating altar %d --> %d\n", terra
->GetConfig(), Owner
);
1022 terra
= altar::Spawn(Owner
);
1024 fprintf(stderr
, "spawned altar in room w/o divine master, assigning %d\n", terra
->GetConfig());
1027 fprintf(stderr
, "spawned altar in room w/o divine master, assigning %d\n", terra
->GetConfig());
1029 Room
->SetDivineMaster(terra
->GetConfig());
1033 ChangeOLTerrain(terra
);
1035 //fprintf(stderr, "WARNING: LTerra spawn error [lsquare] in file %s, line %d\n", OLTerrainScript->GetSrcFile().CStr(), OLTerrainScript->GetSrcLine());
1042 truth
lsquare::CanBeSeenByPlayer(truth IgnoreDarkness
) const
1044 return (IgnoreDarkness
|| !IsDark()) && LastSeen
== game::GetLOSTick();
1047 truth
lsquare::CanBeSeenFrom(v2 FromPos
, sLong MaxDistance
, truth IgnoreDarkness
) const
1049 if((Pos
- FromPos
).GetLengthSquare() <= MaxDistance
1050 && (IgnoreDarkness
|| !IsDark()))
1052 if(Character
&& Character
->IsPlayer()
1053 && GetNearLSquare(FromPos
)->CanBeSeenByPlayer(true))
1056 eyecontroller::Map
= GetLevel()->GetMap();
1057 return mapmath
<eyecontroller
>::DoLine(FromPos
.X
, FromPos
.Y
, GetPos().X
, GetPos().Y
, SKIP_FIRST
);
1063 void lsquare::StepOn(character
* Stepper
, lsquare
** ComingFrom
)
1067 truth WasInRoom
= false;
1070 for(int c
= 0; c
< Stepper
->GetSquaresUnder(); ++c
)
1071 if(ComingFrom
[c
]->GetRoomIndex() == RoomIndex
)
1078 GetLevel()->GetRoom(RoomIndex
)->Enter(Stepper
);
1081 GLTerrain
->StepOn(Stepper
);
1085 OLTerrain
->StepOn(Stepper
);
1087 if(Stepper
->DestroysWalls() && OLTerrain
->WillBeDestroyedBy(Stepper
))
1089 if(CanBeSeenByPlayer())
1090 ADD_MESSAGE("%s destroys %s.", Stepper
->CHAR_NAME(DEFINITE
), OLTerrain
->CHAR_NAME(DEFINITE
));
1092 Stepper
->EditAP(-100);
1093 OLTerrain
->BeDestroyed();
1098 std::vector
<trap
*> TrapVector
;
1100 for(trap
* T
= Trap
; T
; T
= T
->Next
)
1101 TrapVector
.push_back(T
);
1103 for(c
= 0; c
< TrapVector
.size(); ++c
)
1104 if(TrapVector
[c
]->Exists())
1106 TrapVector
[c
]->StepOnEffect(Stepper
);
1108 if(!Stepper
->IsEnabled())
1112 if(!Stepper
->IsFlying())
1114 std::vector
<fluid
*> FluidVector
;
1116 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
1117 FluidVector
.push_back(F
);
1119 for(c
= 0; c
< FluidVector
.size(); ++c
)
1120 if(FluidVector
[c
]->Exists())
1122 FluidVector
[c
]->StepOnEffect(Stepper
);
1124 if(!Stepper
->IsEnabled())
1128 GetStack()->CheckForStepOnEffect(Stepper
);
1132 void lsquare::ReceiveVomit(character
* Who
, liquid
* Liquid
)
1134 if(!GetOLTerrain() || !GetOLTerrain()->ReceiveVomit(Who
, Liquid
))
1136 SpillFluid(Who
, Liquid
);
1139 GetRoom()->ReceiveVomit(Who
);
1143 void lsquare::SetTemporaryEmitation(col24 What
)
1145 col24 Old
= TemporaryEmitation
;
1146 TemporaryEmitation
= 0;
1147 SignalEmitationDecrease(Old
);
1148 TemporaryEmitation
= What
;
1149 SignalEmitationIncrease(What
);
1152 void lsquare::ChangeOLTerrainAndUpdateLights(olterrain
* NewTerrain
)
1154 truth WasTransparent
= Flags
& IS_TRANSPARENT
, Noxified
= false;
1155 emittervector EmitterBackup
;
1157 if(WasTransparent
&& NewTerrain
&& !NewTerrain
->IsTransparent())
1159 EmitterBackup
= Emitter
;
1160 GetLevel()->ForceEmitterNoxify(EmitterBackup
);
1164 sLong OldEmit
= OLTerrain
? OLTerrain
->GetEmitation() : 0;
1165 ChangeOLTerrain(NewTerrain
);
1168 SignalEmitationIncrease(NewTerrain
->GetEmitation());
1170 SignalEmitationDecrease(OldEmit
);
1171 GetStack()->DropSideItems();
1173 if(!IsFlyable() && Smoke
)
1175 DecAnimatedEntities();
1177 for(smoke
* S
= Smoke
; S
; S
= S
->Next
)
1184 if(!WasTransparent
== !!CalculateIsTransparent())
1187 GetLevel()->ForceEmitterEmitation(EmitterBackup
, SunEmitter
, FORCE_ADD
);
1189 GetLevel()->ForceEmitterEmitation(Emitter
, SunEmitter
);
1191 CalculateLuminance();
1193 if(LastSeen
== game::GetLOSTick())
1194 game::SendLOSUpdateRequest();
1198 void lsquare::DrawParticles(sLong Color
, truth DrawHere
)
1200 if(GetPos().X
< game::GetCamera().X
1201 || GetPos().Y
< game::GetCamera().Y
1202 || GetPos().X
>= game::GetCamera().X
+ game::GetScreenXSize()
1203 || GetPos().Y
>= game::GetCamera().Y
+ game::GetScreenYSize()
1204 || !CanBeSeenByPlayer(true)
1205 || Color
== TRANSPARENT_COLOR
)
1208 clock_t StartTime
= clock();
1211 game::DrawEverythingNoBlit();
1213 if(Color
& RANDOM_COLOR
)
1214 Color
= MakeRGB16(60 + RAND() % 190, 60 + RAND() % 190, 60 + RAND() % 190);
1216 v2 Pos
= game::CalculateScreenCoordinates(GetPos());
1218 for(int c
= 0; c
< 10; ++c
)
1219 DOUBLE_BUFFER
->PutPixel(Pos
+ v2(1 + RAND() % 14, 1 + RAND() % 14), Color
);
1221 Flags
|= STRONG_NEW_DRAW_REQUEST
; // Clean the pixels from the screen afterwards
1225 graphics::BlitDBToScreen();
1226 while(clock() - StartTime
< 0.02 * CLOCKS_PER_SEC
);
1230 truth
lsquare::DipInto(item
* Thingy
, character
* Dipper
)
1232 if(IsDipDestination())
1234 room
* Room
= GetRoom();
1236 if(Room
&& Room
->HasDipHandler() && !Room
->Dip(Dipper
))
1239 return (GLTerrain
->IsDipDestination() && GLTerrain
->DipInto(Thingy
, Dipper
)) || (OLTerrain
&& OLTerrain
->IsDipDestination() && OLTerrain
->DipInto(Thingy
, Dipper
));
1243 if(Dipper
->IsPlayer())
1244 ADD_MESSAGE("You cannot dip %s on that square!", Thingy
->CHAR_NAME(DEFINITE
));
1250 // return true if key fits someplace
1252 truth
lsquare::TryKey(item
* Key
, character
* Applier
)
1254 if(GetOLTerrain() && GetOLTerrain()->TryKey(Key
, Applier
))
1257 if((!GetOLTerrain() || !GetOLTerrain()->HasKeyHole()) && !GetStack()->TryKey(Key
, Applier
))
1259 ADD_MESSAGE("There's no place here to put the key in!");
1266 void lsquare::SignalSeen(feuLong Tick
)
1268 if(LastSeen
< Tick
- 2)
1269 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1271 Flags
&= ~(IN_SQUARE_STACK
|PERFECTLY_QUADRI_HANDLED
);
1274 if(!(Flags
& IS_TRANSPARENT
))
1276 col24 OldLuminance
= Luminance
;
1277 CalculateLuminance();
1279 if(OldLuminance
!= Luminance
)
1281 Flags
|= NEW_DRAW_REQUEST
;
1283 if(IsDark() != game::IsDark(OldLuminance
))
1284 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
1290 v2 Dist
= Pos
- PLAYER
->GetPos();
1292 if(abs(Dist
.X
) > 1 || abs(Dist
.Y
) > 1)
1303 UpdateMemorizedDescription();
1306 Character
->CheckIfSeen();
1309 void lsquare::DrawMemorized(blitdata
& BlitData
) const
1312 Flags
&= ~STRONG_NEW_DRAW_REQUEST
;
1313 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
1316 FowMemorized
->LuminanceBlit(BlitData
);
1318 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
1320 ccharacter
* C
= Character
;
1322 if(C
&& C
->CanBeSeenByPlayer())
1324 BlitData
.CustomData
|= C
->GetSquareIndex(Pos
);
1326 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
1330 void lsquare::DrawMemorizedCharacter(blitdata
& BlitData
) const
1332 BlitData
.Luminance
= ivanconfig::GetContrastLuminance();
1335 FowMemorized
->LuminanceBlit(BlitData
);
1337 DOUBLE_BUFFER
->Fill(BlitData
.Dest
, BlitData
.Border
, 0);
1339 BlitData
.CustomData
|= Character
->GetSquareIndex(Pos
);
1340 Character
->Draw(BlitData
);
1341 BlitData
.CustomData
&= ~SQUARE_INDEX_MASK
;
1342 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1345 truth
lsquare::IsDangerous(ccharacter
* Who
) const
1347 return ((!Who
->IsFlying()
1348 && (Stack
->IsDangerous(Who
)
1349 || HasDangerousFluids(Who
)))
1350 || IsDangerousToBreathe(Who
) || HasDangerousTraps(Who
));
1353 truth
lsquare::IsScary(ccharacter
* Who
) const
1355 return IsScaryToBreathe(Who
);
1358 stack
* lsquare::GetStackOfAdjacentSquare(int I
) const
1360 lsquare
* Square
= 0;
1364 case LEFT
: Square
= NeighbourLSquare
[3]; break;
1365 case DOWN
: Square
= NeighbourLSquare
[6]; break;
1366 case UP
: Square
= NeighbourLSquare
[1]; break;
1367 case RIGHT
: Square
= NeighbourLSquare
[4]; break;
1370 return Square
? Square
->Stack
: 0;
1373 void lsquare::SendMemorizedUpdateRequest()
1375 if(!(Flags
& FREEZED
))
1377 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
1379 if(!game::IsGenerating() && (CanBeSeenByPlayer() || CanBeFeltByPlayer()))
1385 UpdateMemorizedDescription();
1390 void lsquare::KickAnyoneStandingHereAway()
1394 character
* Backup
= Character
;
1396 Backup
->PutNear(Pos
);
1400 outputfile
& operator<<(outputfile
& SaveFile
, const emitter
& Emitter
)
1402 SaveFile
.Write(reinterpret_cast<cchar
*>(&Emitter
), sizeof(Emitter
));
1406 inputfile
& operator>>(inputfile
& SaveFile
, emitter
& Emitter
)
1408 SaveFile
.Read(reinterpret_cast<char*>(&Emitter
), sizeof(Emitter
));
1412 void lsquare::AddItem(item
* Item
)
1414 Stack
->AddItem(Item
);
1417 v2
lsquare::DrawLightning(v2 StartPos
, sLong Color
, int Direction
, truth DrawHere
)
1419 if(GetPos().X
< game::GetCamera().X
1420 || GetPos().Y
< game::GetCamera().Y
1421 || GetPos().X
>= game::GetCamera().X
+ game::GetScreenXSize()
1422 || GetPos().Y
>= game::GetCamera().Y
+ game::GetScreenYSize()
1423 || !CanBeSeenByPlayer(true))
1426 case 1: return v2(RAND() & 15, 15);
1427 case 3: return v2(15, RAND() & 15);
1428 case 4: return v2(0, RAND() & 15);
1429 case 6: return v2(RAND() & 15, 0);
1430 default: return StartPos
;
1433 clock_t StartTime
= clock();
1434 bitmap
Empty(TILE_V2
, TRANSPARENT_COLOR
);
1435 Empty
.ActivateFastFlag();
1437 if(Color
& RANDOM_COLOR
)
1438 Color
= MakeRGB16(60 + RAND() % 190, 60 + RAND() % 190, 60 + RAND() % 190);
1440 if(Direction
!= YOURSELF
)
1442 while(!Empty
.CreateLightning(StartPos
, game::GetMoveVector(Direction
), 16, Color
));
1447 case 0: EndPos
= v2(0, 0); break;
1448 case 1: EndPos
= v2(RAND() & 15, 0); StartPos
= v2(EndPos
.X
, 15); break;
1449 case 2: EndPos
= v2(15, 0); break;
1450 case 3: EndPos
= v2(0, RAND() & 15); StartPos
= v2(15, EndPos
.Y
); break;
1451 case 4: EndPos
= v2(15, RAND() & 15); StartPos
= v2(0, EndPos
.Y
); break;
1452 case 5: EndPos
= v2(0, 15); break;
1453 case 6: EndPos
= v2(RAND() & 15, 15); StartPos
= v2(EndPos
.X
, 0); break;
1454 case 7: EndPos
= v2(15, 15); break;
1457 while(!Empty
.CreateLightning(EndPos
, -game::GetMoveVector(Direction
), NO_LIMIT
, Color
));
1461 static v2 Dir
[4] = { v2(0, -1), v2(-1, 0), v2(1, 0), v2(0, 1) };
1463 for(int d
= 0; d
< 4; ++d
)
1464 while(!Empty
.CreateLightning(StartPos
+ Dir
[d
], ZERO_V2
, 10, Color
));
1468 game::DrawEverythingNoBlit();
1470 blitdata B
= { DOUBLE_BUFFER
,
1473 { TILE_SIZE
, TILE_SIZE
},
1478 B
.Dest
= game::CalculateScreenCoordinates(GetPos());
1479 Empty
.NormalMaskedBlit(B
);
1480 Flags
|= STRONG_NEW_DRAW_REQUEST
;
1484 graphics::BlitDBToScreen();
1485 while(clock() - StartTime
< 0.02 * CLOCKS_PER_SEC
);
1491 truth
lsquare::Polymorph(const beamdata
& Beam
)
1493 GetStack()->Polymorph(Beam
.Owner
);
1496 GetOLTerrain()->Polymorph(Beam
.Owner
);
1498 character
* Character
= GetCharacter();
1502 if(Beam
.Owner
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
1503 Beam
.Owner
->Hostility(Character
);
1505 Character
->PolymorphRandomly(1, 999999, 5000 + RAND() % 5000);
1510 for(int c
= 0; Engraved
[c
] != '\0'; ++c
)
1514 Engraved
[c
] = 32 + RAND_N(95);
1521 truth
lsquare::Strike(const beamdata
& Beam
)
1523 int Damage
= 50 + RAND() % 21 - RAND() % 21;
1524 GetStack()->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
, Beam
.Direction
);
1525 ReceiveTrapDamage(Beam
.Owner
, Damage
, ENERGY
, Beam
.Direction
);
1527 character
* Char
= GetCharacter();
1531 if(Char
->IsPlayer())
1532 ADD_MESSAGE("You are hit by a burst of energy!");
1533 else if(Char
->CanBeSeenByPlayer())
1534 ADD_MESSAGE("%s is hit by a burst of energy!", Char
->CHAR_NAME(DEFINITE
));
1537 Beam
.Owner
->Hostility(Char
);
1539 Char
->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
, ALL
);
1540 Char
->CheckDeath(Beam
.DeathMsg
, Beam
.Owner
);
1544 GetOLTerrain()->ReceiveDamage(Beam
.Owner
, Damage
, ENERGY
);
1549 truth
lsquare::FireBall(const beamdata
& Beam
)
1551 if(!IsFlyable() || GetCharacter())
1553 if(CanBeSeenByPlayer(true))
1554 ADD_MESSAGE("A magical explosion is triggered!");
1556 GetLevel()->Explosion(Beam
.Owner
, Beam
.DeathMsg
, Pos
, 75 + RAND() % 25 - RAND() % 25);
1563 truth
lsquare::Teleport(const beamdata
& Beam
)
1567 if(Beam
.Owner
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
1568 Beam
.Owner
->Hostility(GetCharacter());
1570 if(Character
->IsPlayer())
1571 ADD_MESSAGE("You experience a forced teleportation.");
1572 else if(Character
->CanBeSeenByPlayer())
1573 ADD_MESSAGE("%s disappears!", Character
->CHAR_NAME(DEFINITE
));
1575 Character
->TeleportRandomly();
1579 GetLevel()->GetRoom(RoomIndex
)->TeleportSquare(Beam
.Owner
, this);
1581 GetStack()->TeleportRandomly();
1585 truth
lsquare::Haste(const beamdata
&)
1587 GetStack()->Haste();
1588 character
* Dude
= GetCharacter();
1596 truth
lsquare::Slow(const beamdata
& Beam
)
1599 character
* Dude
= GetCharacter();
1604 Beam
.Owner
->Hostility(Dude
);
1612 truth
lsquare::Confuse (const beamdata
&Beam
) {
1613 character
*Dude
= GetCharacter();
1615 if (Dude
&& Dude
->CanBeConfused()) {
1616 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1617 Dude
->BeginTemporaryState(CONFUSED
, 50+RAND()%50);
1623 truth
lsquare::Parasitize (const beamdata
&Beam
) {
1624 character
*Dude
= GetCharacter();
1626 if (Dude
&& Dude
->GetTorso()->CanHaveParasite()) {
1627 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1628 Dude
->GainIntrinsic(PARASITIZED
);
1634 truth
lsquare::InstillPanic (const beamdata
&Beam
) {
1635 character
* Dude
= GetCharacter();
1637 if (Dude
&& Dude
->CanPanic()) {
1638 if (Beam
.Owner
) Beam
.Owner
->Hostility(Dude
);
1639 Dude
->BeginTemporaryState(PANIC
, 50+RAND()%50);
1645 truth
lsquare::Resurrect(const beamdata
& Beam
)
1648 return GetCharacter()->RaiseTheDead(Beam
.Owner
);
1650 return GetStack()->RaiseTheDead(Beam
.Owner
);
1653 truth
lsquare::Invisibility(const beamdata
&)
1656 GetCharacter()->BeginTemporaryState(INVISIBLE
, 1000 + RAND() % 1001);
1661 truth
lsquare::Duplicate(const beamdata
& Beam
)
1663 truth DuplicatedSomething
= false;
1664 character
* Character
= GetCharacter();
1667 DuplicatedSomething
= truth(Character
->DuplicateToNearestSquare(Beam
.Owner
, Beam
.SpecialParameters
));
1669 if(GetStack()->Duplicate(DuplicatedSomething
? 4 : 5, Beam
.SpecialParameters
))
1670 DuplicatedSomething
= true;
1672 return DuplicatedSomething
;
1675 truth
lsquare::Lightning(const beamdata
& Beam
)
1677 int Damage
= 20 + RAND() % 6 - RAND() % 6;
1678 GetStack()->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
, Beam
.Direction
);
1679 ReceiveTrapDamage(Beam
.Owner
, Damage
, ELECTRICITY
, Beam
.Direction
);
1681 character
* Char
= GetCharacter();
1685 if(Char
->IsPlayer())
1686 ADD_MESSAGE("A massive burst of electricity runs through your body!");
1687 else if(Char
->CanBeSeenByPlayer())
1688 ADD_MESSAGE("A massive burst of electricity runs through %s!", Char
->CHAR_NAME(DEFINITE
));
1691 Beam
.Owner
->Hostility(Char
);
1693 Char
->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
, ALL
);
1694 Char
->CheckDeath(Beam
.DeathMsg
, Beam
.Owner
);
1698 GetOLTerrain()->ReceiveDamage(Beam
.Owner
, Damage
, ELECTRICITY
);
1703 truth
lsquare::DoorCreation(const beamdata
& Beam
)
1706 || GetOLTerrain()->IsSafeToCreateDoor())
1708 && (GetLevel()->IsOnGround()
1709 || (Pos
.X
> 0 && Pos
.Y
> 0
1710 && Pos
.X
< GetLevel()->GetXSize() - 1 && Pos
.Y
< GetLevel()->GetYSize() - 1)))
1712 if(Beam
.Owner
&& GetRoom())
1713 GetRoom()->HostileAction(Beam
.Owner
);
1715 door
* Door
= door::Spawn(0, NO_MATERIALS
);
1716 Door
->InitMaterials(MAKE_MATERIAL(STEEL
));
1721 ChangeOLTerrainAndUpdateLights(Door
);
1728 truth (lsquare::*BeamEffect
[BEAM_EFFECTS
])(const beamdata
&) =
1730 &lsquare::Polymorph
,
1736 &lsquare::Resurrect
,
1737 &lsquare::Invisibility
,
1738 &lsquare::Duplicate
,
1739 &lsquare::Lightning
,
1740 &lsquare::DoorCreation
,
1742 &lsquare::Necromancy
1745 truth (lsquare::*lsquare::GetBeamEffect(int I
))(const beamdata
&)
1747 return BeamEffect
[I
];
1750 truth
lsquare::CheckKick(ccharacter
* Kicker
) const
1752 if(Character
&& Kicker
->CheckIfTooScaredToHit(Character
))
1755 if(RoomIndex
&& !GetLevel()->GetRoom(RoomIndex
)->CheckKickSquare(Kicker
, this))
1761 void lsquare::GetHitByExplosion(const explosion
* Explosion
)
1763 if(Explosion
->ID
== LastExplosionID
)
1766 LastExplosionID
= Explosion
->ID
;
1767 int DistanceSquare
= (Pos
- Explosion
->Pos
).GetLengthSquare();
1769 if(DistanceSquare
> Explosion
->RadiusSquare
)
1772 int Damage
= Explosion
->Strength
/ (DistanceSquare
+ 1);
1774 if (Character
&& (Explosion
->HurtNeutrals
|| (Explosion
->Terrorist
&& Character
->GetRelation(Explosion
->Terrorist
) == HOSTILE
))) {
1775 if (Character
->IsPlayer()) game::SetPlayerWasHurtByExplosion(true);
1776 else Character
->GetHitByExplosion(Explosion
, Damage
);
1779 GetStack()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1780 GetStack()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1782 ReceiveTrapDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1783 ReceiveTrapDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1786 GetOLTerrain()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, FIRE
);
1789 GetOLTerrain()->ReceiveDamage(Explosion
->Terrorist
, Damage
>> 1, PHYSICAL_DAMAGE
);
1792 int lsquare::GetSpoiledItems() const
1794 return GetStack()->GetSpoiledItems();
1797 truth
lsquare::LowerEnchantment(const beamdata
& Beam
)
1799 character
* Char
= GetCharacter();
1800 itemvector AllItems
;
1801 sortdata
SortData(AllItems
, Beam
.Owner
, true, &item::IsEnchantable
);
1802 SortAllItems(SortData
);
1805 if(!AllItems
.empty())
1806 RandomItem
= AllItems
[RAND() % AllItems
.size()];
1812 if(Char
->IsPlayer())
1813 ADD_MESSAGE("%s glows blue for a moment!", RandomItem
->CHAR_NAME(DEFINITE
));
1816 Beam
.Owner
->Hostility(Char
);
1819 if(RandomItem
->GetEnchantment() > -5)
1820 RandomItem
->EditEnchantment(-1);
1825 void lsquare::SortAllItems(const sortdata
& SortData
)
1828 GetCharacter()->SortAllItems(SortData
);
1830 GetStack()->SortAllItems(SortData
);
1833 truth
lsquare::SoftenMaterial (const beamdata
&Beam
) {
1834 character
*Char
= GetCharacter();
1836 itemvector AllItems
;
1838 sortdata
SortData(AllItems
, Beam
.Owner
, true, &item::IsEnchantable
);
1839 SortAllItems(SortData
);
1840 //sortdata SortData2(AllItems, Beam.Owner, true, &item::MaterialIsChangeable);
1841 //SortAllItems(SortData2);
1842 if (AllItems
.empty()) return false;
1843 RandomItem
= AllItems
[RAND() % AllItems
.size()];
1845 if (Char
->IsPlayer()) ADD_MESSAGE("Your %s glows yellow for a moment!", RandomItem
->CHAR_NAME(UNARTICLED
));
1846 if (Beam
.Owner
) Beam
.Owner
->Hostility(Char
);
1852 RandomItem
->AddName(Desc
, UNARTICLED
);
1853 material
*OldMaterial
= RandomItem
->GetMainMaterial();
1854 int NewMaterial
= RandomItem
->GetMainMaterial()->GetSoftenedMaterial(RandomItem
);
1856 if (NewMaterial
!= NONE
) {
1857 /* Don't Forget! It is an ugly thing, I know, but removal = seg-fault since cannot have NONE material */
1858 RandomItem
->ChangeMainMaterial(MAKE_MATERIAL(NewMaterial
)); /*->SpawnMore()*/
1859 if (OldMaterial
->GetConfig() != NewMaterial
) Changed
= 1;
1862 if (Changed
&& Char
->IsPlayer()) {
1863 ADD_MESSAGE("Your %s softens into %s!", Desc
.CStr(), RandomItem
->GetMainMaterial()->GetName(false, false).CStr());
1864 } else if (Changed
) {
1865 ADD_MESSAGE("%s's %s softens into %s!", Char
->CHAR_DESCRIPTION(DEFINITE
), Desc
.CStr(), RandomItem
->GetMainMaterial()->GetName(false, false).CStr());
1868 //may not need this message
1869 if (Char
->IsPlayer()) {
1870 ADD_MESSAGE("Your %s vibrates slightly but remains unchanged.", RandomItem
->CHAR_NAME(UNARTICLED
) );
1872 ADD_MESSAGE("%s's %s vibrates slightly but remains unchanged.", Char
->CHAR_DESCRIPTION(DEFINITE
), RandomItem
->CHAR_NAME(UNARTICLED
) );
1880 void lsquare::RemoveSmoke(smoke
* ToBeRemoved
)
1884 if(S
== ToBeRemoved
)
1889 DecAnimatedEntities();
1900 while(S
!= ToBeRemoved
);
1906 void lsquare::AddSmoke(gas
* ToBeAdded
)
1912 Smoke
= new smoke(ToBeAdded
, this);
1913 IncAnimatedEntities();
1921 if(ToBeAdded
->IsSameAs(S
->GetGas()))
1923 S
->Merge(ToBeAdded
);
1932 LS
->Next
= new smoke(ToBeAdded
, this);
1936 void lsquare::ShowSmokeMessage() const
1938 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
1939 S
->AddBreatheMessage();
1942 void lsquare::SignalSmokeAlphaChange(int What
)
1944 SmokeAlphaSum
+= What
;
1945 SignalPossibleTransparencyChange();
1948 int lsquare::GetDivineMaster() const
1950 return RoomIndex
? GetLevel()->GetRoom(RoomIndex
)->GetDivineMaster() : 0;
1953 void lsquare::DisplaySmokeInfo (festring
&Msg
) const {
1956 Msg
<< " A cloud of " << Smoke
->GetGas()->GetName(false, false) << " surrounds the square.";
1958 Msg
<< " A lot of gases hover over the square.";
1962 void lsquare::ReceiveEarthQuakeDamage()
1964 GetStack()->ReceiveDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1965 ReceiveTrapDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1968 if(GetOLTerrain() && GetOLTerrain()->IsDoor())
1969 GetOLTerrain()->ReceiveDamage(0, 5 + RAND() % 10, PHYSICAL_DAMAGE
);
1972 truth
lsquare::CanBeFeltByPlayer() const
1974 if (!PLAYER
) return false;
1975 return OLTerrain
&& !PLAYER
->CanMoveOn(this) && Pos
.IsAdjacent(PLAYER
->GetPos());
1978 void lsquare::PreProcessForBone()
1984 OLTerrain
->PreProcessForBone();
1988 DecAnimatedEntities();
1990 for(smoke
* S
= Smoke
; S
; S
= S
->Next
)
1997 if(Character
&& !Character
->PreProcessForBone())
1999 Character
->SendToHell();
2000 Character
->Remove();
2003 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
2004 F
->PreProcessForBone();
2006 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2007 T
->PreProcessForBone();
2009 GetStack()->PreProcessForBone();
2012 void lsquare::PostProcessForBone(double& DangerSum
, int& Enemies
)
2015 OLTerrain
->PostProcessForBone();
2017 if(Character
&& !Character
->PostProcessForBone(DangerSum
, Enemies
))
2019 Character
->SendToHell();
2020 Character
->Remove();
2023 for(fluid
* F
= Fluid
; F
; F
= F
->Next
)
2024 F
->PostProcessForBone();
2026 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2027 T
->PostProcessForBone();
2029 GetStack()->PostProcessForBone();
2032 void lsquare::FinalProcessForBone()
2035 OLTerrain
->FinalProcessForBone();
2038 Character
->FinalProcessForBone();
2040 GetStack()->FinalProcessForBone();
2043 truth
lsquare::EngravingsCanBeReadByPlayer()
2045 return PLAYER
->CanRead(); // Might be a good idea to improve sometime in the distant future.
2048 void lsquare::DisplayEngravedInfo(festring
& Buffer
) const
2050 Buffer
<< " There is a message engraved here: \"" << Engraved
<< '\"';
2053 truth
lsquare::IsDangerousToBreathe(ccharacter
* Who
) const
2055 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
2056 if(S
->IsDangerousToBreathe(Who
))
2062 truth
lsquare::IsScaryToBreathe(ccharacter
* Who
) const
2064 for(const smoke
* S
= Smoke
; S
; S
= S
->Next
)
2065 if(S
->IsScaryToBreathe(Who
))
2072 struct groundborderpartner
{
2073 truth
operator < (const groundborderpartner
&P
) const { return Terrain
->GetBorderTilePriority() < P
.Terrain
->GetBorderTilePriority(); }
2078 void lsquare::CalculateGroundBorderPartners () {
2079 if (GroundBorderPartnerInfo
& BORDER_PARTNER_ANIMATED
) DecStaticAnimatedEntities();
2080 groundborderpartner BorderPartner
[8*2]; //k8: *2 to make g++ shut up (WTF?!)
2082 int Priority
= GLTerrain
->GetBorderTilePriority();
2083 for (int d
= 0; d
< 8; ++d
) {
2084 lsquare
*Square
= NeighbourLSquare
[d
];
2086 glterrain
*Terrain
= Square
->GetGLTerrain();
2087 if (Terrain
&& Terrain
->UseBorderTiles() && Terrain
->GetBorderTilePriority() > Priority
) {
2088 BorderPartner
[Index
].Terrain
= Terrain
;
2089 BorderPartner
[Index
].SquareIndex
= 7-d
;
2094 GroundBorderPartnerInfo
= 0;
2096 delete [] GroundBorderPartnerTerrain
;
2097 GroundBorderPartnerTerrain
= 0;
2100 if (!GroundBorderPartnerTerrain
) GroundBorderPartnerTerrain
= new glterrain
*[8];
2101 std::sort(BorderPartner
, BorderPartner
+Index
); // why g++ complains here? ah, ignore it for now
2102 truth Animated
= false;
2103 for (int c
= 0; c
< Index
; ++c
) {
2104 glterrain
*T
= BorderPartner
[c
].Terrain
;
2105 GroundBorderPartnerTerrain
[c
] = T
;
2106 GroundBorderPartnerInfo
|= BorderPartner
[c
].SquareIndex
<<((c
<<1)+c
);
2107 if (T
->IsAnimated()) Animated
= true;
2110 GroundBorderPartnerInfo
|= BORDER_PARTNER_ANIMATED
;
2111 IncStaticAnimatedEntities();
2113 GroundBorderPartnerInfo
|= Index
<<24;
2117 struct overborderpartner
{
2118 truth
operator < (const overborderpartner
&P
) const { return Terrain
->GetBorderTilePriority() < P
.Terrain
->GetBorderTilePriority(); }
2123 void lsquare::CalculateOverBorderPartners () {
2124 if (OverBorderPartnerInfo
& BORDER_PARTNER_ANIMATED
) DecStaticAnimatedEntities();
2125 overborderpartner BorderPartner
[8*2]; //k8: *2 to make g++ shut up (WTF?!)
2127 int Priority
= OLTerrain
? OLTerrain
->GetBorderTilePriority() : 0;
2128 for (int d
= 0; d
< 8; ++d
) {
2129 lsquare
*Square
= NeighbourLSquare
[d
];
2131 olterrain
*Terrain
= Square
->GetOLTerrain();
2132 if (Terrain
&& Terrain
->UseBorderTiles() && Terrain
->GetBorderTilePriority() > Priority
) {
2133 BorderPartner
[Index
].Terrain
= Terrain
;
2134 BorderPartner
[Index
].SquareIndex
= 7-d
;
2139 OverBorderPartnerInfo
= 0;
2141 delete [] OverBorderPartnerTerrain
;
2142 OverBorderPartnerTerrain
= 0;
2145 if (!OverBorderPartnerTerrain
) OverBorderPartnerTerrain
= new olterrain
*[8];
2146 std::sort(BorderPartner
, BorderPartner
+Index
); // why g++ complains here? ah, ignore it for now
2147 truth Animated
= false;
2148 for (int c
= 0; c
< Index
; ++c
) {
2149 olterrain
*T
= BorderPartner
[c
].Terrain
;
2150 OverBorderPartnerTerrain
[c
] = T
;
2151 OverBorderPartnerInfo
|= BorderPartner
[c
].SquareIndex
<<((c
<<1)+c
);
2152 if (T
->IsAnimated()) Animated
= true;
2155 OverBorderPartnerInfo
|= BORDER_PARTNER_ANIMATED
;
2156 IncStaticAnimatedEntities();
2158 OverBorderPartnerInfo
|= Index
<<24;
2160 if(OverBorderPartnerInfo & BORDER_PARTNER_ANIMATED)
2161 int esko = esko = 2;
2166 void lsquare::RequestForGroundBorderPartnerUpdates()
2168 if(!game::IsGenerating())
2169 for(int d
= 0; d
< 8; ++d
)
2171 lsquare
* Square
= NeighbourLSquare
[d
];
2175 Square
->CalculateGroundBorderPartners();
2176 Square
->SendNewDrawRequest();
2177 Square
->SendMemorizedUpdateRequest();
2182 void lsquare::RequestForOverBorderPartnerUpdates()
2184 if(!game::IsGenerating())
2185 for(int d
= 0; d
< 8; ++d
)
2187 lsquare
* Square
= NeighbourLSquare
[d
];
2191 Square
->CalculateOverBorderPartners();
2192 Square
->SendNewDrawRequest();
2193 Square
->SendMemorizedUpdateRequest();
2198 int lsquare::GetWalkability() const
2200 if(!GetLevel()->IsOnGround())
2202 if(Pos
.X
>= 1 && Pos
.Y
>= 1 && Pos
.X
< GetLevel()->GetXSize() - 1 && Pos
.Y
< GetLevel()->GetYSize() - 1)
2203 return OLTerrain
? OLTerrain
->GetWalkability() & GLTerrain
->GetWalkability() : GLTerrain
->GetWalkability();
2208 return OLTerrain
? OLTerrain
->GetWalkability() & GLTerrain
->GetWalkability() : GLTerrain
->GetWalkability();
2211 void lsquare::RemoveFluid(fluid
* ToRemove
)
2213 fluid
*& F
= ListFind(Fluid
, pointercomparer
<fluid
>(ToRemove
));
2215 SignalEmitationDecrease(ToRemove
->GetEmitation());
2218 struct fluidcomparer
2220 fluidcomparer(const liquid
* Liquid
) : Liquid(Liquid
) { }
2221 truth
operator()(const fluid
* F
) const { return Liquid
->IsSameAs(F
->GetLiquid()); }
2222 const liquid
* Liquid
;
2225 fluid
* lsquare::AddFluid(liquid
* ToBeAdded
)
2227 fluid
*& F
= ListFind(Fluid
, fluidcomparer(ToBeAdded
));
2231 F
->AddLiquidAndVolume(ToBeAdded
->GetVolume());
2236 F
= new fluid(ToBeAdded
, this);
2237 SignalEmitationIncrease(ToBeAdded
->GetEmitation());
2240 SendNewDrawRequest();
2241 SendMemorizedUpdateRequest();
2245 void lsquare::DisplayFluidInfo(festring
& Msg
) const
2249 Msg
<< ". There is ";
2250 fluid::AddFluidInfo(Fluid
, Msg
);
2251 AddLocationDescription(Msg
);
2255 void lsquare::SpillFluid(character
* Spiller
, liquid
* Liquid
, truth ForceHit
, truth ShowMsg
)
2257 if(!Liquid
->GetVolume())
2267 if(Spiller
&& !GetCharacter()->IsAlly(Spiller
))
2268 Spiller
->Hostility(GetCharacter());
2270 sLong CharVolume
= GetCharacter()->GetVolume();
2271 double ChanceMultiplier
= 1. / (300 + sqrt(GetStack()->GetVolume() + CharVolume
));
2272 double Root
= sqrt(CharVolume
);
2274 if(ForceHit
|| Root
> RAND() % 400 || Root
> RAND() % 400)
2276 sLong SpillVolume
= sLong(Liquid
->GetVolume() * Root
* ChanceMultiplier
);
2280 if(ShowMsg
&& (GetCharacter()->IsPlayer() || GetCharacter()->CanBeSeenByPlayer()))
2281 ADD_MESSAGE("%s is spilled all over %s.", Liquid
->GetName(false, false).CStr(), GetCharacter()->CHAR_DESCRIPTION(DEFINITE
));
2283 Liquid
->EditVolume(-SpillVolume
);
2284 GetCharacter()->SpillFluid(Spiller
, Liquid
->SpawnMoreLiquid(SpillVolume
), GetCharacter()->GetSquareIndex(GetPos()));
2289 GetStack()->SpillFluid(Spiller
, Liquid
, Liquid
->GetVolume());
2292 if(Liquid
->GetVolume() && !Liquid
->IsSameAs(GLTerrain
->GetMainMaterial()))
2294 fluid
* F
= AddFluid(Liquid
);
2297 F
->StepOnEffect(GetCharacter());
2303 void lsquare::DrawStacks(blitdata
& BlitData
) const
2305 Stack
->Draw(PLAYER
, BlitData
, CENTER
);
2307 for(int c
= 0; c
< 4; ++c
)
2309 stack
* Stack
= GetStackOfAdjacentSquare(c
);
2312 Stack
->Draw(PLAYER
, BlitData
, 3 - c
);
2316 void lsquare::RemoveRain(rain
* ToBeRemoved
)
2318 SendNewDrawRequest();
2321 if(ToBeRemoved
->IsEnabled())
2322 DecAnimatedEntities();
2324 if(R
== ToBeRemoved
)
2335 while(R
!= ToBeRemoved
);
2340 SignalEmitationDecrease(ToBeRemoved
->GetEmitation());
2343 void lsquare::AddRain(liquid
* RainLiquid
, v2 Speed
, int Team
, truth OwnLiquid
)
2345 rain
* R
= Rain
, * NewRain
= new rain(RainLiquid
, this, Speed
, Team
, OwnLiquid
);
2347 if(NewRain
->IsEnabled())
2348 IncAnimatedEntities();
2367 void lsquare::RemoveSunLight()
2369 SunLightLuminance
= 0;
2373 void lsquare::CheckIfIsSecondarySunLightEmitter()
2375 col24 OldEmitation
= SecondarySunLightEmitation
;
2377 if(Flags
& IS_TRANSPARENT
&& (!(Flags
& INSIDE
) || SunLightLuminance
))
2378 for(int d
= 0; d
< 8; ++d
)
2380 lsquare
* Neighbour
= NeighbourLSquare
[d
];
2382 if(Neighbour
&& Neighbour
->Flags
& INSIDE
)
2384 col24 NewEmitation
= GetLevel()->GetAmbientLuminance();
2386 if(OldEmitation
!= NewEmitation
)
2388 SecondarySunLightEmitation
= NewEmitation
;
2390 if(game::CompareLights(NewEmitation
, OldEmitation
) >= 0)
2391 Emitate(NewEmitation
, SECONDARY_SUN_LIGHT
);
2394 Noxify(OldEmitation
, SECONDARY_SUN_LIGHT
);
2395 Emitate(NewEmitation
, SECONDARY_SUN_LIGHT
|FORCE_ADD
);
2405 Noxify(OldEmitation
, SECONDARY_SUN_LIGHT
);
2406 SecondarySunLightEmitation
= 0;
2410 void lsquare::CalculateNeighbourLSquares()
2412 int XSize
= GetLevel()->GetXSize();
2413 int YSize
= GetLevel()->GetYSize();
2415 for(int d
= 0; d
< 8; ++d
)
2417 v2 NPos
= Pos
+ game::GetMoveVector(d
);
2419 if(NPos
.X
>= 0 && NPos
.Y
>= 0 && NPos
.X
< XSize
&& NPos
.Y
< YSize
)
2420 NeighbourLSquare
[d
] = GetLevel()->GetLSquare(NPos
);
2422 NeighbourLSquare
[d
] = 0;
2426 void lsquare::RemoveLuminance(col24
& Emitation
)
2428 col24 OldLuminance
= Luminance
;
2429 col24 OldEmitation
= Emitation
;
2432 if(game::CompareLights(OldEmitation
, OldLuminance
) < 0)
2435 if(!(Flags
& IS_TRANSPARENT
))
2437 Flags
|= NEW_DRAW_REQUEST
;
2439 if(LastSeen
== game::GetLOSTick())
2440 game::SendLOSUpdateRequest();
2444 CalculateLuminance();
2446 if(OldLuminance
== Luminance
)
2449 Flags
|= NEW_DRAW_REQUEST
;
2453 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2455 if(LastSeen
== game::GetLOSTick())
2456 game::SendLOSUpdateRequest();
2461 void lsquare::ChangeLuminance(col24
& Emitation
, col24 NewLuminance
)
2463 col24 OldLuminance
= Luminance
;
2465 if(!(Flags
& IS_TRANSPARENT
))
2467 Emitation
= NewLuminance
;
2468 Flags
|= NEW_DRAW_REQUEST
;
2470 if(LastSeen
== game::GetLOSTick())
2471 game::SendLOSUpdateRequest();
2476 truth EmitationInsignificant
= !Emitation
2477 || game::CompareLights(Emitation
, OldLuminance
) < 0;
2478 Emitation
= NewLuminance
;
2480 if(game::CompareLights(NewLuminance
, OldLuminance
) > 0
2481 && EmitationInsignificant
)
2482 game::CombineLights(Luminance
, NewLuminance
);
2485 if(EmitationInsignificant
)
2488 CalculateLuminance();
2490 if(OldLuminance
== Luminance
)
2494 Flags
|= NEW_DRAW_REQUEST
;
2498 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2500 if(LastSeen
== game::GetLOSTick())
2501 game::SendLOSUpdateRequest();
2505 void lsquare::EnableGlobalRain()
2507 for(rain
* R
= Rain
; R
; R
= R
->Next
)
2508 if(!R
->HasOwnLiquid())
2511 IncAnimatedEntities();
2515 void lsquare::DisableGlobalRain()
2517 SendNewDrawRequest();
2519 for(rain
* R
= Rain
; R
; R
= R
->Next
)
2520 if(!R
->HasOwnLiquid())
2523 DecAnimatedEntities();
2527 void lsquare::InitLastSeen()
2529 LastSeen
= LastSeen
== game::GetLOSTick() ? 2 : 0;
2530 SquarePartLastSeen
= 0;
2533 truth
lsquare::Engrave(cfestring
& What
)
2540 Engraved
= new char[What
.GetSize() + 1];
2541 strcpy(Engraved
, What
.CStr());
2549 void lsquare::SendSunLightSignals()
2551 if(Flags
& IS_TRANSPARENT
)
2553 col24 OldLuminance
= Luminance
;
2554 CalculateLuminance();
2556 if(Luminance
!= OldLuminance
)
2558 Flags
|= NEW_DRAW_REQUEST
;
2560 if(!Luminance
!= !OldLuminance
)
2562 Flags
|= MEMORIZED_UPDATE_REQUEST
|DESCRIPTION_CHANGE
;
2564 if(LastSeen
== game::GetLOSTick())
2565 game::SendLOSUpdateRequest();
2571 Flags
|= NEW_DRAW_REQUEST
;
2573 if(LastSeen
== game::GetLOSTick())
2574 game::SendLOSUpdateRequest();
2578 void lsquare::ZeroReSunEmitatedFlags()
2580 sunemittervector::iterator i
, End
= SunEmitter
.end();
2582 for(i
= SunEmitter
.begin(); i
!= End
; ++i
)
2583 *i
&= ~RE_SUN_EMITATED
;
2586 truth
lsquare::CalculateIsTransparent()
2588 if((!OLTerrain
|| OLTerrain
->IsTransparent()) && SmokeAlphaSum
< 175
2589 && (!Character
|| Character
->IsTransparent()))
2591 Flags
|= IS_TRANSPARENT
;
2596 Flags
&= ~IS_TRANSPARENT
;
2601 void lsquare::CalculateSunLightLuminance(feuLong SeenBitMask
)
2603 sunemittervector::const_iterator i
, SunEnd
= SunEmitter
.end();
2606 for(i
= SunEmitter
.begin(); i
!= SunEnd
; ++i
)
2608 feuLong ShadowFlag
= 1 << EMITTER_SHADOW_SHIFT
;
2609 feuLong SquarePartFlag
= 1 << EMITTER_SQUARE_PART_SHIFT
;
2610 for (int c
= 0; c
< 4; ++c
, ShadowFlag
<<= 1, SquarePartFlag
<<= 1) {
2611 if (SeenBitMask
& *i
& SquarePartFlag
) {
2612 if (*i
& ShadowFlag
) ++S
; else ++L
;
2618 SunLightLuminance
= 0;
2620 SunLightLuminance
= GetLevel()->GetSunLightEmitation();
2623 col24 ShadowColor
= GetLevel()->GetAmbientLuminance();
2624 col24 LightColor
= GetLevel()->GetSunLightEmitation();
2625 SunLightLuminance
= MakeRGB24((GetRed24(LightColor
) * L
2626 + GetRed24(ShadowColor
) * S
) / (S
+ L
),
2627 (GetGreen24(LightColor
) * L
2628 + GetGreen24(ShadowColor
) * S
) / (S
+ L
),
2629 (GetBlue24(LightColor
) * L
2630 + GetBlue24(ShadowColor
) * S
) / (S
+ L
));
2634 void lsquare::CreateMemorized()
2636 Memorized
= new bitmap(TILE_V2
);
2637 Memorized
->ActivateFastFlag();
2638 FowMemorized
= new bitmap(TILE_V2
);
2639 FowMemorized
->ActivateFastFlag();
2642 truth
lsquare::AcidRain(const beamdata
& Beam
)
2644 if(!IsFlyable() || GetCharacter() || Beam
.Direction
== YOURSELF
)
2646 int StackSize
= GetLevel()->AddRadiusToSquareStack(Pos
, 9);
2647 lsquare
** Stack
= GetLevel()->GetSquareStack();
2648 v2 Speed
= v2(512, 512);
2649 int Team
= Beam
.Owner
? Beam
.Owner
->GetTeam()->GetID() : MONSTER_TEAM
;
2651 for(int c
= 0; c
< StackSize
; ++c
)
2653 Stack
[c
]->AddRain(liquid::Spawn(SULPHURIC_ACID
, 300), Speed
, Team
, true);
2654 Stack
[c
]->Flags
&= ~IN_SQUARE_STACK
;
2657 if(Beam
.Owner
&& Character
&& Character
->GetTeam() != Beam
.Owner
->GetTeam())
2658 Beam
.Owner
->Hostility(Character
);
2666 truth
lsquare::DetectMaterial (cmaterial
*Material
) const {
2667 if (GLTerrain
->DetectMaterial(Material
) ||
2668 (OLTerrain
&& OLTerrain
->DetectMaterial(Material
)) ||
2669 Stack
->DetectMaterial(Material
) ||
2670 (Character
&& Character
->DetectMaterial(Material
))) return true;
2671 for (const fluid
*F
= Fluid
; F
; F
= F
->Next
) if (F
->GetLiquid()->IsSameAs(Material
)) return true;
2672 for (const smoke
*S
= Smoke
; S
; S
= S
->Next
) if (S
->GetGas()->IsSameAs(Material
)) return true;
2673 for (const rain
*R
= Rain
; R
; R
= R
->Next
) if (R
->GetLiquid()->IsSameAs(Material
)) return true;
2677 void lsquare::Reveal(feuLong Tick
, truth IgnoreDarkness
)
2685 Luminance
= NORMAL_LUMINANCE
;
2688 SquarePartLastSeen
= 0;
2690 for(int c
= 0; c
< 4; ++c
)
2691 SquarePartLastSeen
|= (Tick
<< (c
<< 3));
2693 CalculateLuminance();
2696 Flags
|= NEW_DRAW_REQUEST
2697 | MEMORIZED_UPDATE_REQUEST
2698 | DESCRIPTION_CHANGE
;
2700 UpdateMemorizedDescription();
2703 void lsquare::DestroyMemorized()
2706 delete FowMemorized
;
2711 void lsquare::SwapMemorized(lsquare
* Square
)
2713 Swap(Memorized
, Square
->Memorized
);
2714 Swap(FowMemorized
, Square
->FowMemorized
);
2715 MemorizedDescription
.SwapData(Square
->MemorizedDescription
);
2718 truth
lsquare::Necromancy(const beamdata
& Beam
)
2720 return GetStack()->Necromancy(Beam
.Owner
);
2723 // Returns 0 if fails
2725 lsquare
* lsquare::GetRandomAdjacentSquare() const
2730 for(int c
= 0; c
< 8; ++c
)
2732 lsquare
* Square
= NeighbourLSquare
[c
];
2735 OK
[Index
++] = Square
;
2739 return OK
[RAND_N(Index
)];
2744 truth
pathcontroller::Handler(int x
, int y
)
2746 return Character
->CanMoveOn(Map
[x
][y
]);
2749 void lsquare::SignalPossibleTransparencyChange()
2751 truth WasTransparent
= IsTransparent();
2752 CalculateIsTransparent();
2754 if(WasTransparent
&& !IsTransparent())
2756 Flags
|= IS_TRANSPARENT
;
2757 emittervector EmitterBackup
= Emitter
;
2758 GetLevel()->ForceEmitterNoxify(EmitterBackup
);
2759 Flags
&= ~IS_TRANSPARENT
;
2760 GetLevel()->ForceEmitterEmitation(EmitterBackup
, SunEmitter
, FORCE_ADD
);
2761 CalculateLuminance();
2762 Flags
|= DESCRIPTION_CHANGE
|MEMORIZED_UPDATE_REQUEST
;
2764 if(LastSeen
== game::GetLOSTick())
2765 game::SendLOSUpdateRequest();
2767 else if(!WasTransparent
&& IsTransparent())
2769 GetLevel()->ForceEmitterEmitation(Emitter
, SunEmitter
);
2770 CalculateLuminance();
2771 Flags
|= DESCRIPTION_CHANGE
|MEMORIZED_UPDATE_REQUEST
;
2773 if(LastSeen
== game::GetLOSTick())
2774 game::SendLOSUpdateRequest();
2778 void lsquare::RemoveTrap(trap
* ToRemove
)
2780 trap
*& T
= ListFind(Trap
, pointercomparer
<trap
>(ToRemove
));
2782 SendNewDrawRequest();
2783 SendMemorizedUpdateRequest();
2788 trapcomparer(int Type
) : Type(Type
) { }
2789 truth
operator()(const trap
* T
) const { return T
->GetType() == Type
; }
2793 truth
lsquare::AddTrap(trap
* ToBeAdded
)
2795 trap
*& T
= ListFind(Trap
, trapcomparer(ToBeAdded
->GetType()));
2805 ToBeAdded
->SetLSquareUnder(this);
2806 SendNewDrawRequest();
2807 SendMemorizedUpdateRequest();
2811 void lsquare::DisplayTrapInfo(festring
& Msg
) const
2813 for(const trap
* T
= Trap
; T
; T
= T
->Next
)
2814 T
->AddDescription(Msg
);
2817 void lsquare::FillTrapVector(std::vector
<trap
*>& TrapVector
) const
2819 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2820 TrapVector
.push_back(T
);
2823 void lsquare::ReceiveTrapDamage(character
* Damager
, int Damage
, int Type
, int Direction
)
2825 std::vector
<trap
*> TrapVector
;
2826 FillTrapVector(TrapVector
);
2828 for(uInt c
= 0; c
< TrapVector
.size(); ++c
)
2829 TrapVector
[c
]->ReceiveDamage(Damager
, Damage
, Type
, Direction
);
2832 truth
lsquare::HasDangerousTraps(ccharacter
* Who
) const
2834 for(trap
* T
= Trap
; T
; T
= T
->Next
)
2835 if(T
->IsDangerous(Who
))
2841 truth
lsquare::HasDangerousFluids(ccharacter
* Who
) const
2843 for(const fluid
* F
= Fluid
; F
; F
= F
->Next
)
2844 if(F
->IsDangerous(Who
))
2850 truth
lsquare::HasNoBorderPartners() const
2852 return !(GroundBorderPartnerInfo
>> 24) && !(OverBorderPartnerInfo
>> 24);
2855 void lsquare::AddLocationDescription(festring
& String
) const
2858 GLTerrain
->AddLocationDescription(String
);
2860 OLTerrain
->AddLocationDescription(String
);
2863 truth
lsquare::VomitingIsDangerous(ccharacter
* Char
) const
2865 return ((OLTerrain
&& OLTerrain
->VomitingIsDangerous(Char
))
2866 || (Character
&& Character
->GetTeam() != Char
->GetTeam()
2867 && Character
->GetRelation(Char
) != HOSTILE
));
2870 bool lsquare::TeleportAllSmokeAway()
2875 bool lsquare::TeleportAllFluidsAway()
2880 bool lsquare::TeleportAllTrapsAway()
2882 for(trap
* T
= Trap
; T
; T
= Trap
)
2886 v2 V
, Pos
= GetPos();
2887 for(V
= GetLevel()->GetRandomSquare(); V
!= Pos
; V
= GetLevel()->GetRandomSquare());
2888 GetNearLSquare(V
)->AddTrap(T
);
2894 void lsquare::AddSpecialCursors()
2896 if((FowMemorized
|| game::GetSeeWholeMapCheatMode()) && OLTerrain
)
2897 OLTerrain
->AddSpecialCursors();