20130313
[gdash.git] / src / fileops / brcimport.cpp
blob789527a6fb1ac2405fbb1e155378778bc39167f5
1 /*
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.
17 #include "config.h"
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[]=
27 /* 0 */
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,
30 /* 1 */
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,
33 /* 2 */
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,
36 /* 3 */
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,
39 /* 4 */
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,
42 /* 5 */
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,
45 /* 6 */
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,
48 /* 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));
69 return O_UNKNOWN;
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));
79 return O_UNKNOWN;
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];
89 bool import_effect;
91 /* this is some kind of a version number */
92 import_effect=false;
93 switch (data[23]) {
94 case 0x0:
95 /* nothing to do */
96 break;
97 case 0xde:
98 /* import effects */
99 import_effect=true;
100 break;
101 default:
102 gd_warning(CPrintf("unknown brc version %02x") % unsigned(data[23]));
103 break;
106 for (int level=0; level<5; level++) {
107 for (int cavenum=0; cavenum<20; cavenum++) {
108 CaveStored *cave;
109 char s[128];
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;
113 int colind;
115 cave=new CaveStored;
116 imported[level*20+cavenum]=cave;
117 if (cavenum<16)
118 g_snprintf(s, sizeof(s), "Cave %c/%d", 'A'+cavenum, level+1);
119 else
120 g_snprintf(s, sizeof(s), "Intermission %d/%d", cavenum-15, level+1);
121 cave->name=s;
123 /* fixed intermission caves; are smaller. */
124 if (cavenum>=16) {
125 cave->w=20;
126 cave->h=12;
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++) {
132 guint8 import;
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];
171 else
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];
175 else
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;
183 /* colors */
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 */
193 if (import_effect) {
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. */
218 bool only_dirt=true;
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)
222 only_dirt=false;
224 /* append to caveset or forget it. */
225 if (!only_dirt)
226 caveset.caves.push_back_adopt(cave);
227 else
228 delete imported[i];