moved almost all hardcoded constants to "define.dat"
[k8-i-v-a-n.git] / src / game / igraph.cpp
blob8fbda43610e98516bd57d4090793346e87f931c4
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
13 #include "igraph.h"
14 #include "felist.h"
15 #include "bitmap.h"
16 #include "graphics.h"
17 #include "iconf.h"
18 #include "rawbit.h"
19 #include "game.h"
20 #include "fesave.h"
21 #include "feparse.h"
22 #include "object.h"
23 #include "allocate.h"
24 #include "whandler.h"
26 rawbitmap* igraph::RawGraphic[RAW_TYPES];
27 bitmap* igraph::Graphic[GRAPHIC_TYPES];
28 bitmap* igraph::TileBuffer;
29 bitmap* igraph::FlagBuffer;
30 cchar* igraph::RawGraphicFileName[] = { "graphics/GLTerra.pcx", "graphics/OLTerra.pcx", "graphics/Item.pcx", "graphics/Char.pcx", "graphics/Humanoid.pcx", "graphics/Effect.pcx", "graphics/Cursor.pcx" };
31 cchar* igraph::GraphicFileName[] = { "graphics/WTerra.pcx", "graphics/FOW.pcx", "graphics/Symbol.pcx", "graphics/Smiley.pcx" };
32 tilemap igraph::TileMap;
33 uChar igraph::RollBuffer[256];
34 int** igraph::BodyBitmapValidityMap;
35 bitmap* igraph::Menu;
36 bitmap* igraph::SilhouetteCache[HUMANOID_BODYPARTS][CONDITION_COLORS][SILHOUETTE_TYPES];
37 rawbitmap* igraph::ColorizeBuffer[2] = { new rawbitmap(TILE_V2), new rawbitmap(TILE_V2) };
38 bitmap* igraph::Cursor[CURSOR_TYPES];
39 bitmap* igraph::BigCursor[CURSOR_TYPES];
40 col16 igraph::CursorColor[CURSOR_TYPES] = { MakeRGB16(40, 40, 40),
41 MakeRGB16(255, 0, 0),
42 MakeRGB16(100, 100, 255),
43 MakeRGB16(200, 200, 0) };
44 bitmap* igraph::BackGround;
45 int igraph::CurrentColorType = -1;
47 void igraph::Init()
49 static truth AlreadyInstalled = false;
51 if(!AlreadyInstalled)
53 AlreadyInstalled = true;
54 graphics::Init();
55 graphics::SetMode("IVAN " IVAN_VERSION, festring(game::GetGameDir() + "graphics/Icon.bmp").CStr(), v2(800, 600), ivanconfig::GetFullScreenMode(), ivanconfig::GetDoubleResModifier());
56 DOUBLE_BUFFER->ClearToColor(0);
57 graphics::BlitDBToScreen();
58 graphics::SetSwitchModeHandler(ivanconfig::SwitchModeHandler);
59 graphics::LoadDefaultFont(game::GetGameDir() + "graphics/Font.pcx");
60 FONT->CreateFontCache(WHITE);
61 FONT->CreateFontCache(LIGHT_GRAY);
62 felist::CreateQuickDrawFontCaches(FONT, WHITE, 8);
63 felist::CreateQuickDrawFontCaches(FONT, LIGHT_GRAY, 8);
64 object::InitSparkleValidityArrays();
65 int c;
67 for(c = 0; c < RAW_TYPES; ++c)
68 RawGraphic[c] = new rawbitmap(game::GetGameDir() + RawGraphicFileName[c]);
70 for(c = 0; c < GRAPHIC_TYPES; ++c)
72 Graphic[c] = new bitmap(game::GetGameDir() + GraphicFileName[c]);
73 Graphic[c]->ActivateFastFlag();
76 ColorizeBuffer[0]->CopyPaletteFrom(RawGraphic[0]);
77 ColorizeBuffer[1]->CopyPaletteFrom(RawGraphic[0]);
78 TileBuffer = new bitmap(TILE_V2);
79 TileBuffer->ActivateFastFlag();
80 TileBuffer->InitPriorityMap(0);
81 FlagBuffer = new bitmap(TILE_V2);
82 FlagBuffer->ActivateFastFlag();
83 FlagBuffer->CreateAlphaMap(0);
84 Alloc2D(BodyBitmapValidityMap, 8, 16);
85 CreateBodyBitmapValidityMaps();
86 CreateSilhouetteCaches();
88 for(c = 0; c < CURSOR_TYPES; ++c)
90 packcol16 Color = CursorColor[c];
91 Cursor[c] = new bitmap(v2(48, 16), TRANSPARENT_COLOR);
92 Cursor[c]->CreateAlphaMap(255);
93 GetCursorRawGraphic()->MaskedBlit(Cursor[c], ZERO_V2, ZERO_V2, v2(48, 16), &Color);
94 BigCursor[c] = new bitmap(v2(96, 32), TRANSPARENT_COLOR);
95 BigCursor[c]->CreateAlphaMap(255);
96 GetCursorRawGraphic()->MaskedBlit(BigCursor[c], v2(0, 16), ZERO_V2, v2(96, 32), &Color);
101 void igraph::DeInit()
103 int c;
105 for(c = 0; c < RAW_TYPES; ++c)
106 delete RawGraphic[c];
108 for(c = 0; c < GRAPHIC_TYPES; ++c)
109 delete Graphic[c];
111 delete TileBuffer;
112 delete FlagBuffer;
113 delete [] BodyBitmapValidityMap;
114 delete BackGround;
117 void igraph::DrawCursor(v2 Pos, int CursorData, int Index)
119 /* Inefficient gum solution */
121 blitdata BlitData = { DOUBLE_BUFFER,
122 { 0, 0 },
123 { Pos.X, Pos.Y },
124 { TILE_SIZE, TILE_SIZE },
125 { ivanconfig::GetContrastLuminance() },
126 TRANSPARENT_COLOR,
127 0 };
129 bitmap* CursorBitmap;
130 int SrcX = 0;
132 if(CursorData & CURSOR_BIG)
134 CursorBitmap = BigCursor[CursorData&~CURSOR_FLAGS];
135 BlitData.Src.X = SrcX = (Index & 1) << 4;
136 BlitData.Src.Y = (Index & 2) << 3;
138 else
139 CursorBitmap = Cursor[CursorData&~CURSOR_FLAGS];
141 if(!(CursorData & (CURSOR_FLASH|CURSOR_TARGET)))
143 CursorBitmap->LuminanceMaskedBlit(BlitData);
144 return;
147 if(!(CursorData & CURSOR_TARGET))
149 int Tick = GET_TICK() & 31;
150 CursorBitmap->FillAlpha(95 + 10 * abs(Tick - 16));
151 CursorBitmap->AlphaLuminanceBlit(BlitData);
152 return;
155 int Tick = (GET_TICK() << 2) / 3;
156 int Frame = (Tick >> 4) % 3;
157 int Base = Frame << 4;
158 BlitData.Src.X = SrcX + (CursorData & CURSOR_BIG ? Base << 1 : Base);
159 CursorBitmap->FillAlpha(255 - (Tick & 0xF) * 16);
160 CursorBitmap->AlphaLuminanceBlit(BlitData);
161 Base = ((Frame + 1) % 3) << 4;
162 BlitData.Src.X = SrcX + (CursorData & CURSOR_BIG ? Base << 1 : Base);
163 CursorBitmap->FillAlpha((Tick & 0xF) * 16);
164 CursorBitmap->AlphaLuminanceBlit(BlitData);
167 tilemap::iterator igraph::AddUser(const graphicid& GI)
169 tilemap::iterator Iterator = TileMap.find(GI);
171 if(Iterator != TileMap.end())
173 tile& Tile = Iterator->second;
174 ++Tile.Users;
175 return Iterator;
177 else
179 cint SpecialFlags = GI.SpecialFlags;
180 cint BodyPartFlags = SpecialFlags & 0x78;
181 cint RotateFlags = SpecialFlags & 0x7;
182 cint Frame = GI.Frame;
183 v2 SparklePos = v2(GI.SparklePosX, GI.SparklePosY);
184 rawbitmap* RawBitmap = RawGraphic[GI.FileIndex];
185 v2 RawPos = v2(GI.BitmapPosX, GI.BitmapPosY);
187 if(BodyPartFlags && BodyPartFlags < ST_OTHER_BODYPART)
189 ColorizeBuffer[0]->Clear();
190 EditBodyPartTile(RawBitmap, ColorizeBuffer[0], RawPos, BodyPartFlags);
191 RawBitmap = ColorizeBuffer[0];
192 RawPos.X = RawPos.Y = 0;
194 if(RotateFlags)
196 ColorizeBuffer[1]->Clear();
197 SparklePos = RotateTile(RawBitmap, ColorizeBuffer[1], RawPos, SparklePos, RotateFlags);
198 RawBitmap = ColorizeBuffer[1];
201 else if(RotateFlags)
203 ColorizeBuffer[0]->Clear();
204 SparklePos = RotateTile(RawBitmap, ColorizeBuffer[0], RawPos, SparklePos, RotateFlags);
205 RawBitmap = ColorizeBuffer[0];
206 RawPos.X = RawPos.Y = 0;
209 bitmap* Bitmap = RawBitmap->Colorize(RawPos, TILE_V2, GI.Position, GI.Color, GI.BaseAlpha, GI.Alpha, GI.RustData, !(GI.SpecialFlags & ST_DISALLOW_R_COLORS));
210 Bitmap->ActivateFastFlag();
212 if(BodyPartFlags)
213 Bitmap->InitPriorityMap(SpecialFlags & ST_CLOAK ? CLOAK_PRIORITY : AVERAGE_PRIORITY);
215 if(GI.OutlineColor != TRANSPARENT_COLOR)
216 Bitmap->Outline(GI.OutlineColor, GI.OutlineAlpha, BodyPartFlags != ST_WIELDED ? ARMOR_OUTLINE_PRIORITY : AVERAGE_PRIORITY);
218 if(SparklePos.X != SPARKLE_POS_X_ERROR)
219 Bitmap->CreateSparkle(SparklePos + GI.Position, GI.SparkleFrame);
221 if(GI.FlyAmount)
222 Bitmap->CreateFlies(GI.Seed, Frame, GI.FlyAmount);
224 cint WobbleData = GI.WobbleData;
226 if(WobbleData & WOBBLE)
228 int Speed = (WobbleData & WOBBLE_SPEED_RANGE) >> WOBBLE_SPEED_SHIFT;
229 int Freq = (WobbleData & WOBBLE_FREQ_RANGE) >> WOBBLE_FREQ_SHIFT;
230 int WobbleMask = 7 >> Freq << (6 - Speed);
232 if(!(Frame & WobbleMask))
233 Bitmap->Wobble(Frame & ((1 << (6 - Speed)) - 1), Speed, WobbleData & WOBBLE_HORIZONTALLY_BIT);
236 if(SpecialFlags & ST_FLAMES)
238 feuLong SeedNFlags = (SpecialFlags >> ST_FLAME_SHIFT & 3) | (GI.Seed << 4);
239 Bitmap->CreateFlames(RawBitmap, RawPos - GI.Position, SeedNFlags, Frame);
242 if(SpecialFlags & ST_LIGHTNING && !((Frame + 1) & 7))
243 Bitmap->CreateLightning(GI.Seed + Frame, WHITE);
245 return TileMap.insert(std::make_pair(GI, tile(Bitmap))).first;
249 void igraph::EditBodyPartTile(rawbitmap* Source, rawbitmap* Dest, v2 Pos, int BodyPartFlags)
251 if(BodyPartFlags == ST_RIGHT_ARM)
252 Source->NormalBlit(Dest, Pos, ZERO_V2, v2(8, 16));
253 else if(BodyPartFlags == ST_LEFT_ARM)
254 Source->NormalBlit(Dest, v2(Pos.X + 8, Pos.Y), v2(8, 0), v2(8, 16));
255 else if(BodyPartFlags == ST_GROIN)
257 Source->NormalBlit(Dest, v2(Pos.X, Pos.Y + 8), v2(0, 8), v2(16, 2));
258 //int i;
259 v2 V;
261 for(V.Y = 10/*, i = 0*/; V.Y < 13; ++V.Y)
262 for(V.X = V.Y - 5; V.X < 20 - V.Y; ++V.X)
263 Dest->PutPixel(V, Source->GetPixel(Pos + V));
265 else if(BodyPartFlags == ST_RIGHT_LEG)
267 /* Right leg from the character's, NOT the player's point of view */
269 Source->NormalBlit(Dest, v2(Pos.X, Pos.Y + 10), v2(0, 10), v2(8, 6));
270 Dest->PutPixel(v2(5, 10), TRANSPARENT_PALETTE_INDEX);
271 Dest->PutPixel(v2(6, 10), TRANSPARENT_PALETTE_INDEX);
272 Dest->PutPixel(v2(7, 10), TRANSPARENT_PALETTE_INDEX);
273 Dest->PutPixel(v2(6, 11), TRANSPARENT_PALETTE_INDEX);
274 Dest->PutPixel(v2(7, 11), TRANSPARENT_PALETTE_INDEX);
275 Dest->PutPixel(v2(7, 12), TRANSPARENT_PALETTE_INDEX);
277 else if(BodyPartFlags == ST_LEFT_LEG)
279 /* Left leg from the character's, NOT the player's point of view */
281 Source->NormalBlit(Dest, v2(Pos.X + 8, Pos.Y + 10), v2(8, 10), v2(8, 6));
282 Dest->PutPixel(v2(8, 10), TRANSPARENT_PALETTE_INDEX);
283 Dest->PutPixel(v2(9, 10), TRANSPARENT_PALETTE_INDEX);
284 Dest->PutPixel(v2(8, 11), TRANSPARENT_PALETTE_INDEX);
288 v2 igraph::RotateTile(rawbitmap* Source, rawbitmap* Dest, v2 Pos, v2 SparklePos, int RotateFlags)
290 Source->NormalBlit(Dest, Pos, ZERO_V2, TILE_V2, RotateFlags);
292 if(SparklePos.X != SPARKLE_POS_X_ERROR)
294 if(RotateFlags & ROTATE)
296 cint T = SparklePos.X;
297 SparklePos.X = 15 - SparklePos.Y;
298 SparklePos.Y = T;
301 if(RotateFlags & MIRROR)
302 SparklePos.X = 15 - SparklePos.X;
304 if(RotateFlags & FLIP)
305 SparklePos.Y = 15 - SparklePos.Y;
308 return SparklePos;
311 void igraph::RemoveUser(tilemap::iterator Iterator)
313 /*k8!!! memory leak by me!*/
314 /*tile& Tile = Iterator->second;
316 if(!--Tile.Users)
318 delete Tile.Bitmap;
319 TileMap.erase(Iterator);
323 outputfile& operator<<(outputfile& SaveFile, const graphicid& Value)
325 SaveFile.Write(reinterpret_cast<cchar*>(&Value), sizeof(Value));
326 return SaveFile;
329 inputfile& operator>>(inputfile& SaveFile, graphicid& Value)
331 SaveFile.Read(reinterpret_cast<char*>(&Value), sizeof(Value));
332 return SaveFile;
335 graphicdata::~graphicdata()
337 if(AnimationFrames)
339 for(int c = 0; c < AnimationFrames; ++c)
340 igraph::RemoveUser(GraphicIterator[c]);
342 delete [] Picture;
343 delete [] GraphicIterator;
347 void graphicdata::Save(outputfile& SaveFile) const
349 SaveFile << (int)AnimationFrames;
351 for(int c = 0; c < AnimationFrames; ++c)
352 SaveFile << GraphicIterator[c]->first;
355 void graphicdata::Load(inputfile& SaveFile)
357 SaveFile >> (int&)AnimationFrames;
359 if(AnimationFrames)
361 Picture = new bitmap*[AnimationFrames];
362 GraphicIterator = new tilemap::iterator[AnimationFrames];
363 graphicid GraphicID;
365 for(int c = 0; c < AnimationFrames; ++c)
367 SaveFile >> GraphicID;
368 Picture[c] = (GraphicIterator[c] = igraph::AddUser(GraphicID))->second.Bitmap;
373 outputfile& operator<<(outputfile& SaveFile, const graphicdata& Data)
375 Data.Save(SaveFile);
376 return SaveFile;
379 inputfile& operator>>(inputfile& SaveFile, graphicdata& Data)
381 Data.Load(SaveFile);
382 return SaveFile;
385 void graphicdata::Retire()
387 if(AnimationFrames)
389 for(int c = 0; c < AnimationFrames; ++c)
390 igraph::RemoveUser(GraphicIterator[c]);
392 AnimationFrames = 0;
393 delete [] Picture;
394 delete [] GraphicIterator;
398 cint* igraph::GetBodyBitmapValidityMap(int SpecialFlags)
400 return BodyBitmapValidityMap[(SpecialFlags & 0x38) >> 3];
403 void igraph::CreateBodyBitmapValidityMaps()
405 memset(BodyBitmapValidityMap[0], 0xFF, 128 * sizeof(int));
406 int* Map = BodyBitmapValidityMap[ST_RIGHT_ARM >> 3];
407 int x, y;
409 for(x = 8; x < 16; ++x)
410 Map[x] = 0;
412 Map = BodyBitmapValidityMap[ST_LEFT_ARM >> 3];
414 for(x = 0; x < 8; ++x)
415 Map[x] = 0;
417 Map = BodyBitmapValidityMap[ST_GROIN >> 3];
418 memset(Map, 0, 16 * sizeof(int));
420 for(y = 10; y < 13; ++y)
421 for(x = y - 5; x < 20 - y; ++x)
422 Map[x] |= 1 << y;
424 Map = BodyBitmapValidityMap[ST_RIGHT_LEG >> 3];
426 for(x = 8; x < 16; ++x)
427 Map[x] = 0;
429 Map[5] &= ~(1 << 10);
430 Map[6] &= ~(1 << 10);
431 Map[7] &= ~(1 << 10);
432 Map[6] &= ~(1 << 11);
433 Map[7] &= ~(1 << 11);
434 Map[7] &= ~(1 << 12);
436 Map = BodyBitmapValidityMap[ST_LEFT_LEG >> 3];
438 for(x = 0; x < 8; ++x)
439 Map[x] = 0;
441 Map[8] &= ~(1 << 10);
442 Map[9] &= ~(1 << 10);
443 Map[8] &= ~(1 << 11);
446 void igraph::LoadMenu()
448 Menu = new bitmap(game::GetGameDir() + "graphics/Menu.pcx");
451 void igraph::UnLoadMenu()
453 delete Menu;
456 void igraph::CreateSilhouetteCaches()
458 int BodyPartSilhouetteMColorIndex[HUMANOID_BODYPARTS] = { 3, 0, 1, 2, 1, 2, 3 };
459 col24 ConditionColor[CONDITION_COLORS] = { MakeRGB16(48, 48, 48),
460 MakeRGB16(120, 0, 0),
461 MakeRGB16(180, 0, 0),
462 MakeRGB16(180, 120, 120),
463 MakeRGB16(180, 180, 180) };
464 v2 V(8, 64);
466 for(int c1 = 0; c1 < HUMANOID_BODYPARTS; ++c1)
468 if(c1 == 4)
469 V.X = 72;
471 for(int c2 = 0; c2 < CONDITION_COLORS; ++c2)
473 packcol16 Color[4] = { 0, 0, 0, 0 };
474 Color[BodyPartSilhouetteMColorIndex[c1]] = ConditionColor[c2];
476 for(int c3 = 0; c3 < SILHOUETTE_TYPES; ++c3)
478 SilhouetteCache[c1][c2][c3] = new bitmap(SILHOUETTE_SIZE, 0);
479 RawGraphic[GR_CHARACTER]->MaskedBlit(SilhouetteCache[c1][c2][c3],
480 V, ZERO_V2,
481 SILHOUETTE_SIZE, Color);
484 SilhouetteCache[c1][c2][SILHOUETTE_INTER_LACED]->InterLace();
489 void igraph::CreateBackGround(int ColorType)
491 if(CurrentColorType == ColorType)
492 return;
494 CurrentColorType = ColorType;
495 delete BackGround;
496 BackGround = new bitmap(RES);
497 int Side = 1025;
498 int** Map;
499 Alloc2D(Map, Side, Side);
500 femath::GenerateFractalMap(Map, Side, Side - 1, 800);
502 for(int x = 0; x < RES.X; ++x)
503 for(int y = 0; y < RES.Y; ++y)
505 int E = Limit<int>(abs(Map[1024 - x][1024 - (RES.Y - y)]) / 30, 0, 100);
506 BackGround->PutPixel(x, y, GetBackGroundColor(E));
509 delete [] Map;
512 col16 igraph::GetBackGroundColor(int Element)
514 switch(CurrentColorType)
516 case GRAY_FRACTAL: return MakeRGB16(Element, Element, Element);
517 case RED_FRACTAL: return MakeRGB16(Element + (Element >> 1), Element / 3, Element / 3);
518 case GREEN_FRACTAL: return MakeRGB16(Element / 3, Element + (Element >> 2), Element / 3);
519 case BLUE_FRACTAL: return MakeRGB16(Element / 3, Element / 3, Element + (Element >> 1));
520 case YELLOW_FRACTAL: return MakeRGB16(Element + (Element >> 1), Element + (Element >> 1), Element / 3);
523 return 0;
526 void igraph::BlitBackGround(v2 Pos, v2 Border)
528 blitdata B = { DOUBLE_BUFFER,
529 { Pos.X, Pos.Y },
530 { Pos.X, Pos.Y },
531 { Border.X, Border.Y },
532 { 0 },
534 0 };
536 BackGround->NormalBlit(B);
539 bitmap* igraph::GenerateScarBitmap(int BodyPart, int Severity, int Color)
541 bitmap* CacheBitmap = SilhouetteCache[BodyPart][0][SILHOUETTE_NORMAL];
542 bitmap* Scar = new bitmap(SILHOUETTE_SIZE, 0);
544 v2 StartPos;
545 while(true)
547 StartPos = v2(RAND_N(SILHOUETTE_SIZE.X),RAND_N(SILHOUETTE_SIZE.Y));
548 if(CacheBitmap->GetPixel(StartPos) != 0)
549 break;
552 v2 EndPos;
553 while(true)
555 double Angle = 2 * FPI * RAND_256 / 256;
556 EndPos.X = int(StartPos.X + cos(Angle) * (Severity + 1));
557 EndPos.Y = int(StartPos.Y + sin(Angle) * (Severity + 1));
558 if(CacheBitmap->IsValidPos(EndPos) && CacheBitmap->GetPixel(EndPos) != 0)
559 break;
561 Scar->DrawLine(StartPos, EndPos, Color);
562 return Scar;