2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include "cave/cavestored.hpp"
20 #include "cave/caveset.hpp"
21 #include "misc/logger.hpp"
22 #include "misc/printf.hpp"
23 #include "cave/elementproperties.hpp"
25 static GdElementEnum brc_import_table
[]=
28 O_SPACE
, O_DIRT
, O_BRICK
, O_MAGIC_WALL
, O_PRE_OUTBOX
, O_OUTBOX
, O_UNKNOWN
, O_STEEL
,
29 O_H_EXPANDING_WALL
, O_H_EXPANDING_WALL_scanned
, O_FIREFLY_1_scanned
, O_FIREFLY_1_scanned
, O_FIREFLY_1
, O_FIREFLY_2
, O_FIREFLY_3
, O_FIREFLY_4
,
31 O_BUTTER_1_scanned
, O_BUTTER_1_scanned
, O_BUTTER_1
, O_BUTTER_2
, O_BUTTER_3
, O_BUTTER_4
, O_PLAYER
, O_PLAYER_scanned
,
32 O_STONE
, O_STONE_scanned
, O_STONE_F
, O_STONE_F_scanned
, O_DIAMOND
, O_DIAMOND_scanned
, O_DIAMOND_F
, O_DIAMOND_F_scanned
,
34 O_NONE
/* WILL_EXPLODE_THING */, O_EXPLODE_1
, O_EXPLODE_2
, O_EXPLODE_3
, O_EXPLODE_4
, O_EXPLODE_5
, O_NONE
/* WILL EXPLODE TO DIAMOND_THING */, O_PRE_DIA_1
,
35 O_PRE_DIA_2
, O_PRE_DIA_3
, O_PRE_DIA_4
, O_PRE_DIA_5
, O_AMOEBA
, O_AMOEBA_scanned
, O_SLIME
, O_NONE
,
37 O_CLOCK
, O_NONE
/* clock eaten */, O_INBOX
, O_PRE_PL_1
, O_PRE_PL_2
, O_PRE_PL_3
, O_NONE
, O_NONE
,
38 O_NONE
, O_NONE
, O_V_EXPANDING_WALL
, O_NONE
, O_VOODOO
, O_UNKNOWN
, O_EXPANDING_WALL
, O_EXPANDING_WALL_scanned
,
40 O_FALLING_WALL
, O_FALLING_WALL_F
, O_FALLING_WALL_F_scanned
, O_UNKNOWN
, O_ACID
, O_ACID_scanned
, O_NITRO_PACK
, O_NITRO_PACK_scanned
,
41 O_NITRO_PACK_F
, O_NITRO_PACK_F_scanned
, O_NONE
, O_NONE
, O_NONE
, O_NONE
, O_NONE
, O_NONE
,
43 O_NONE
/* bomb explosion utolso */, O_UNKNOWN
, O_NONE
/* solid bomb glued */, O_UNKNOWN
, O_STONE_GLUED
, O_UNKNOWN
, O_DIAMOND_GLUED
, O_UNKNOWN
,
44 O_UNKNOWN
, O_UNKNOWN
, O_NONE
, O_NONE
, O_NONE
, O_NONE
, O_NONE
, O_NONE
,
46 O_ALT_FIREFLY_1_scanned
, O_ALT_FIREFLY_1_scanned
, O_ALT_FIREFLY_1
, O_ALT_FIREFLY_2
, O_ALT_FIREFLY_3
, O_ALT_FIREFLY_4
, O_PLAYER_BOMB
, O_PLAYER_BOMB_scanned
,
47 O_BOMB
, O_BOMB_TICK_1
, O_BOMB_TICK_2
, O_BOMB_TICK_3
, O_BOMB_TICK_4
, O_BOMB_TICK_5
, O_BOMB_TICK_6
, O_BOMB_TICK_7
,
49 O_BOMB_TICK_7
, O_BOMB_EXPL_1
, O_BOMB_EXPL_2
, O_BOMB_EXPL_3
, O_BOMB_EXPL_4
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
,
50 O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
,
53 static GdElementEnum brc_effect_table
[]=
55 O_STEEL
, O_DIRT
, O_SPACE
, O_STONE
, O_STONE_F
, O_STONE_GLUED
, O_DIAMOND
, O_DIAMOND_F
, O_DIAMOND_GLUED
, O_PRE_DIA_1
,
56 O_PLAYER
, O_PRE_PL_1
, O_PLAYER_BOMB
, O_PRE_OUTBOX
, O_OUTBOX
, O_FIREFLY_1
, O_FIREFLY_2
, O_FIREFLY_3
, O_FIREFLY_4
,
57 O_BUTTER_1
, O_BUTTER_2
, O_BUTTER_3
, O_BUTTER_4
, O_BRICK
, O_MAGIC_WALL
, O_H_EXPANDING_WALL
, O_V_EXPANDING_WALL
, O_EXPANDING_WALL
,
58 O_FALLING_WALL
, O_FALLING_WALL_F
, O_AMOEBA
, O_SLIME
, O_ACID
, O_VOODOO
, O_CLOCK
, O_BOMB
, O_UNKNOWN
, O_UNKNOWN
, O_UNKNOWN
,
59 O_ALT_FIREFLY_1
, O_ALT_FIREFLY_2
, O_ALT_FIREFLY_3
, O_ALT_FIREFLY_4
, O_ALT_BUTTER_1
, O_ALT_BUTTER_2
, O_ALT_BUTTER_3
, O_ALT_BUTTER_4
,
60 O_EXPLODE_1
, O_BOMB_EXPL_1
, O_UNKNOWN
,
63 static double brc_hue_table
[] = { 92, 211, 29, 346, 263, 147, 317, 10, 64 };
65 static GdElementEnum
brc_effect(unsigned char byt
)
67 if (byt
>=G_N_ELEMENTS(brc_effect_table
)) {
68 gd_warning(CPrintf("invalid element identifier for brc effect: %02x") % unsigned(byt
));
72 return brc_effect_table
[byt
];
75 GdElementEnum
brc_import_elem(unsigned char c
)
77 if (c
>=G_N_ELEMENTS(brc_import_table
)) {
78 gd_warning(CPrintf("invalid brc element byte %x") % unsigned(c
));
81 return nonscanned_pair(brc_import_table
[c
]);
85 void brc_import(CaveSet
&caveset
, guint8
*data
)
87 /* we import 100 caves, and the put them in the correct order. */
88 CaveStored
*imported
[100];
91 /* this is some kind of a version number */
102 gd_warning(CPrintf("unknown brc version %02x") % unsigned(data
[23]));
106 for (int level
=0; level
<5; level
++) {
107 for (int cavenum
=0; cavenum
<20; cavenum
++) {
111 int c
=5*20*24; /* 5 levels, 20 caves, 24 bytes - max 40*2 properties for each cave */
112 int datapos
=(cavenum
*5+level
)*24+22;
116 imported
[level
*20+cavenum
]=cave
;
118 g_snprintf(s
, sizeof(s
), "Cave %c/%d", 'A'+cavenum
, level
+1);
120 g_snprintf(s
, sizeof(s
), "Intermission %d/%d", cavenum
-15, level
+1);
123 /* fixed intermission caves; are smaller. */
128 cave
->map
.set_size(cave
->w
, cave
->h
);
130 for (int y
=0; y
<cave
->h
; y
++) {
131 for (int x
=0; x
<cave
->w
; x
++) {
134 import
=data
[y
+level
*24+cavenum
*24*5+x
*24*5*20];
135 cave
->map(x
, y
)=brc_import_elem(import
);
139 for (int i
=0; i
<5; i
++) {
140 cave
->level_time
[i
]=data
[0*c
+datapos
];
141 cave
->level_diamonds
[i
]=data
[1*c
+datapos
];
142 cave
->level_magic_wall_time
[i
]=data
[4*c
+datapos
];
143 cave
->level_amoeba_time
[i
]=data
[5*c
+datapos
];
144 cave
->level_amoeba_threshold
[i
]=data
[6*c
+datapos
];
145 /* bonus time: 100 was added, so it could also be negative */
146 cave
->level_bonus_time
[i
]=(int)data
[11*c
+datapos
+1]-100;
147 cave
->level_hatching_delay_frame
[i
]=data
[10*c
+datapos
];
148 cave
->level_slime_permeability
[i
]=1.0/data
[9*c
+datapos
];
150 /* this was not set in boulder remake. */
151 cave
->level_speed
[i
]=150;
153 cave
->diamond_value
=data
[2*c
+datapos
];
154 cave
->extra_diamond_value
=data
[3*c
+datapos
];
155 /* BRC PROBABILITIES */
156 /* a typical code example:
157 46:if (random(slime*4)<4) and (tab[x,y+2]=0) then
158 Begin tab[x,y]:=0;col[x,y+2]:=col[x,y];tab[x,y+2]:=27;mat[x,y+2]:=9;Voice4:=2;end;
159 where slime is the byte loaded from the file as it is.
160 pascal random function generates a random number between 0..limit-1, inclusive, for random(limit).
162 so a random number between 0..limit*4-1 is generated.
163 for limit=1, 0..3, which is always < 4, so P=1.
164 for limit=2, 0..7, 0..7 is < 4 in P=50%.
165 for limit=3, 0..11, is < 4 in P=33%.
166 So the probability is exactly 100%/limit.
167 just make sure we do not divide by zero for some broken input.
169 if (data
[7*c
+datapos
]!=0)
170 cave
->amoeba_growth_prob
=1.0/data
[7*c
+datapos
];
172 gd_warning(CPrintf("amoeba growth cannot be zero, error at byte %d") % unsigned(data
[7*c
+datapos
]));
173 if (data
[8*c
+datapos
]!=0)
174 cave
->amoeba_fast_growth_prob
=1.0/data
[8*c
+datapos
];
176 gd_warning(CPrintf("amoeba growth cannot be zero, error at byte %d") % unsigned(data
[8*c
+datapos
]));
177 cave
->slime_predictable
=false;
178 cave
->acid_spread_ratio
=1.0/data
[10*c
+datapos
];
179 cave
->pushing_stone_prob
=1.0/data
[11*c
+datapos
]; /* br only allowed values 1..8 in here, but works the same way. */
180 cave
->magic_wall_stops_amoeba
=data
[12*c
+datapos
+1]!=0;
181 cave
->intermission
=cavenum
>=16 || data
[14*c
+datapos
+1]!=0;
184 colind
=data
[31*c
+datapos
]%G_N_ELEMENTS(brc_hue_table
);
185 cave
->colorb
=GdColor::from_rgb(0, 0, 0); /* fixed rgb black */
186 cave
->color0
=GdColor::from_rgb(0, 0, 0); /* fixed rgb black */
187 cave
->color1
=GdColor::from_hsv(brc_hue_table
[colind
], 0.70, 0.70); /* brc specified dirt color */
188 cave
->color2
=GdColor::from_hsv(brc_hue_table
[colind
]+120, 0.85, 0.80);
189 cave
->color3
=GdColor::from_hsv(brc_hue_table
[colind
]+240, 0.15, 0.90); /* almost white for brick */
190 cave
->color4
=GdColor::from_hsv(120, 0.90, 0.90); /* fixed for amoeba */
191 cave
->color5
=GdColor::from_hsv(240, 0.90, 0.90); /* fixed for slime */
194 cave
->amoeba_enclosed_effect
=brc_effect(data
[14*c
+datapos
+1]);
195 cave
->amoeba_too_big_effect
=brc_effect(data
[15*c
+datapos
+1]);
196 cave
->explosion_effect
=brc_effect(data
[16*c
+datapos
+1]);
197 cave
->bomb_explosion_effect
=brc_effect(data
[17*c
+datapos
+1]);
198 /* 18 solid bomb explode to */
199 cave
->diamond_birth_effect
=brc_effect(data
[19*c
+datapos
+1]);
200 cave
->stone_bouncing_effect
=brc_effect(data
[20*c
+datapos
+1]);
201 cave
->diamond_bouncing_effect
=brc_effect(data
[21*c
+datapos
+1]);
202 cave
->magic_diamond_to
=brc_effect(data
[22*c
+datapos
+1]);
203 cave
->acid_eats_this
=brc_effect(data
[23*c
+datapos
+1]);
204 /* slime eats: (diamond,boulder,bomb), (diamond,boulder), (diamond,bomb), (boulder,bomb) */
205 cave
->amoeba_enclosed_effect
=brc_effect(data
[14*c
+datapos
+1]);
210 /* put them in the caveset - take correct order into consideration. */
211 for (int level
=0; level
<5; level
++) {
212 for (int cavenum
=0; cavenum
<20; cavenum
++) {
213 static const int reorder
[]={0, 1, 2, 3, 16, 4, 5, 6, 7, 17, 8, 9, 10, 11, 18, 12, 13, 14, 15, 19};
214 int i
=level
*20+reorder
[cavenum
];
215 CaveStored
*cave
=imported
[i
];
217 /* check if cave contains only dirt. that is an empty cave, and do not import. */
219 for (int y
=1; y
<cave
->h
-1 && only_dirt
; y
++)
220 for (int x
=1; x
<cave
->w
-1 && only_dirt
; x
++)
221 if (cave
->map(x
,y
)!=O_DIRT
)
224 /* append to caveset or forget it. */
226 caveset
.caves
.push_back_adopt(cave
);