| 1 | /********************************************************************************/ |
|---|
| 2 | /* map.d */ |
|---|
| 3 | /*------------------------------------------------------------------------------*/ |
|---|
| 4 | /* 製作 ( ゜ワ゜)ノ / 松久貫太 */ |
|---|
| 5 | /* 製作開始 2008/01/03 */ |
|---|
| 6 | /* MAIL omega@personal.email.ne.jp */ |
|---|
| 7 | /* URL http://nagoya.cool.ne.jp/o_mega */ |
|---|
| 8 | /* */ |
|---|
| 9 | /* このソースは「やわらかライセンス」の元で配布されています。 */ |
|---|
| 10 | /*-更新履歴---------------------------------------------------------------------*/ |
|---|
| 11 | /* 2008/01/04 */ |
|---|
| 12 | /*-その他-----------------------------------------------------------------------*/ |
|---|
| 13 | /* なし */ |
|---|
| 14 | /********************************************************************************/ |
|---|
| 15 | |
|---|
| 16 | private import gamecore; |
|---|
| 17 | private import hell2; |
|---|
| 18 | private import boot; |
|---|
| 19 | private import actor; |
|---|
| 20 | private import vector; |
|---|
| 21 | private import keypad; |
|---|
| 22 | |
|---|
| 23 | private import character; |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | //******************************************************************************** |
|---|
| 27 | // マップちっぷ |
|---|
| 28 | //******************************************************************************** |
|---|
| 29 | |
|---|
| 30 | const static int CHIP_SIZE = 32; |
|---|
| 31 | |
|---|
| 32 | class MapChip{ |
|---|
| 33 | enum TYPE{ |
|---|
| 34 | NONE = 0, |
|---|
| 35 | CURSOR = 0, |
|---|
| 36 | MOVIE = 1, |
|---|
| 37 | FENCE, |
|---|
| 38 | WATER, |
|---|
| 39 | DARK, |
|---|
| 40 | } |
|---|
| 41 | const static string name[] = ["NONE" , "MOVIE" , "FENCE" , "WATER" , "DARK" ]; |
|---|
| 42 | |
|---|
| 43 | const static int TYPEDRAW_LOOP = 16; |
|---|
| 44 | static int GRASS_COLOR_R = 128; |
|---|
| 45 | static int GRASS_COLOR_G = 128; |
|---|
| 46 | static int GRASS_COLOR_B = 128; |
|---|
| 47 | |
|---|
| 48 | double grass; |
|---|
| 49 | |
|---|
| 50 | TYPE type; |
|---|
| 51 | |
|---|
| 52 | this(){ |
|---|
| 53 | init(); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | void init(){ |
|---|
| 57 | grass = 0; |
|---|
| 58 | type = TYPE.NONE; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | void drawBase(double x,double y){ |
|---|
| 62 | /* 本来はCHIP_SIZE * CHIP_SIZE分コピーすべきだが、高速化のため下半分だけコピーする */ |
|---|
| 63 | Hell_drawTexture("char" , x , y + CHIP_SIZE / 2 |
|---|
| 64 | ,0 |
|---|
| 65 | ,CHIP_SIZE / 2 |
|---|
| 66 | ,CHIP_SIZE |
|---|
| 67 | ,CHIP_SIZE / 2); |
|---|
| 68 | |
|---|
| 69 | /* 本来のコード |
|---|
| 70 | Hell_drawTexture("char" , x , y |
|---|
| 71 | ,0 |
|---|
| 72 | ,0 |
|---|
| 73 | ,CHIP_SIZE |
|---|
| 74 | ,CHIP_SIZE); |
|---|
| 75 | */ |
|---|
| 76 | } |
|---|
| 77 | void draw(double x , double y,int anime = 0){ |
|---|
| 78 | if(type == TYPE.NONE){ |
|---|
| 79 | // 芝 |
|---|
| 80 | if(getGrassLevel() < 1) return; |
|---|
| 81 | Hell_drawTexture("char" , x , y |
|---|
| 82 | ,0 |
|---|
| 83 | ,CHIP_SIZE * getGrassLevel() |
|---|
| 84 | ,CHIP_SIZE |
|---|
| 85 | ,CHIP_SIZE,1,1,0, GRASS_COLOR_R,GRASS_COLOR_G,GRASS_COLOR_B); |
|---|
| 86 | }else{ |
|---|
| 87 | // オブジェクト |
|---|
| 88 | Hell_drawTexture("char" , x , y |
|---|
| 89 | ,CHIP_SIZE * anime + CHIP_SIZE |
|---|
| 90 | ,CHIP_SIZE * (type % TYPEDRAW_LOOP) |
|---|
| 91 | ,CHIP_SIZE |
|---|
| 92 | ,CHIP_SIZE); |
|---|
| 93 | } |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | static void drawCursor(double x,double y,int anime = 0){ |
|---|
| 97 | Hell_drawTexture("char" , x , y ,CHIP_SIZE * anime + CHIP_SIZE ,0 |
|---|
| 98 | ,CHIP_SIZE |
|---|
| 99 | ,CHIP_SIZE); |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | int getGrassLevel(){ |
|---|
| 103 | if(grass < 10){ |
|---|
| 104 | return 0; |
|---|
| 105 | }else if(grass < 20){ |
|---|
| 106 | return 1; |
|---|
| 107 | }else if(grass < 40){ |
|---|
| 108 | return 2; |
|---|
| 109 | }else if(grass < 80){ |
|---|
| 110 | return 3; |
|---|
| 111 | }else{ |
|---|
| 112 | return 4; |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | char toSerializedChar(){ |
|---|
| 117 | if( type == TYPE.NONE ) return ' '; |
|---|
| 118 | if( type == TYPE.MOVIE ) return 'W'; |
|---|
| 119 | if( type == TYPE.FENCE ) return 'F'; |
|---|
| 120 | if( type == TYPE.WATER ) return 'M'; |
|---|
| 121 | if( type == TYPE.DARK ) return 'D'; |
|---|
| 122 | Hell_write("Undefined mapdata serialize to char."); |
|---|
| 123 | return ' '; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | bool setSerializedChar( char ch ){ |
|---|
| 127 | if( ch == ' ' ) return set( TYPE.NONE , 0 ); |
|---|
| 128 | if( ch == 'W' ) return set( TYPE.MOVIE , 0 ); |
|---|
| 129 | if( ch == 'F' ) return set( TYPE.FENCE , 0 ); |
|---|
| 130 | if( ch == 'M' ) return set( TYPE.WATER , 0 ); |
|---|
| 131 | if( ch == 'D' ) return set( TYPE.DARK , 0 ); |
|---|
| 132 | Hell_write("Undefine mapdata restore from char"); |
|---|
| 133 | return false; |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | bool set( TYPE type , double grass ){ |
|---|
| 137 | this.type = type; |
|---|
| 138 | this.grass = grass; |
|---|
| 139 | return true; |
|---|
| 140 | } |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | //******************************************************************************** |
|---|
| 144 | // マップ |
|---|
| 145 | //******************************************************************************** |
|---|
| 146 | |
|---|
| 147 | class Map{ |
|---|
| 148 | const static double DRAW_CHIP_W = 12.0; |
|---|
| 149 | const static double DRAW_CHIP_H = 6.0; |
|---|
| 150 | const static double MOUSE_OFS_X = 16.0; |
|---|
| 151 | const static double MOUSE_OFS_Y = 18.0; |
|---|
| 152 | |
|---|
| 153 | static double MAP_GRASS_AFFECT = 0.90; |
|---|
| 154 | static double MAP_GRASS_AFFECT_LIMIT = 0.3; |
|---|
| 155 | |
|---|
| 156 | static int MAP_REFRESH_INTERVAL = 10; |
|---|
| 157 | |
|---|
| 158 | static double MOVIE_GRASS_FEED = 200; |
|---|
| 159 | |
|---|
| 160 | static bool MAP_BORDER_IS_WALL = false; |
|---|
| 161 | |
|---|
| 162 | GameMain gamemain; |
|---|
| 163 | MapChip[] map; |
|---|
| 164 | bool[] movable_map; |
|---|
| 165 | |
|---|
| 166 | int width; |
|---|
| 167 | int height; |
|---|
| 168 | int timer; |
|---|
| 169 | |
|---|
| 170 | double draw_ofs_x; |
|---|
| 171 | double draw_ofs_y; |
|---|
| 172 | |
|---|
| 173 | this(GameMain gamemain , int width , int height){ |
|---|
| 174 | this.gamemain = gamemain; |
|---|
| 175 | this.width = width; |
|---|
| 176 | this.height = height; |
|---|
| 177 | |
|---|
| 178 | this.map = new MapChip[width * height]; |
|---|
| 179 | foreach(inout m;map) m = new MapChip(); |
|---|
| 180 | |
|---|
| 181 | this.movable_map = new bool[width * height]; |
|---|
| 182 | foreach(inout mm;movable_map) mm = true; |
|---|
| 183 | |
|---|
| 184 | this.draw_ofs_x = 0; |
|---|
| 185 | this.draw_ofs_y = 0; |
|---|
| 186 | |
|---|
| 187 | timer = 0; |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | void update(){ |
|---|
| 191 | timer++; |
|---|
| 192 | |
|---|
| 193 | // 各種ゲームパラメタ |
|---|
| 194 | MAP_GRASS_AFFECT = configparser.getfloat("MAP_GRASS_AFFECT"); |
|---|
| 195 | MAP_REFRESH_INTERVAL = configparser.getint("MAP_REFRESH_INTERVAL"); |
|---|
| 196 | MOVIE_GRASS_FEED = configparser.getfloat("MAP_MOVIE_GRASS_FEED"); |
|---|
| 197 | MAP_GRASS_AFFECT_LIMIT = configparser.getfloat("MAP_GRASS_AFFECT_LIMIT"); |
|---|
| 198 | |
|---|
| 199 | MAP_BORDER_IS_WALL = configparser.getboolean("MAP_BORDER_IS_WALL"); |
|---|
| 200 | |
|---|
| 201 | int[] vecx = [ -1 , 0 , 1 , 0 ]; |
|---|
| 202 | int[] vecy = [ 0 , -1 , 0 , 1 ]; |
|---|
| 203 | |
|---|
| 204 | for(int x = 0;x < width;x++){ |
|---|
| 205 | // 適当に負荷分散してみる |
|---|
| 206 | if(timer % MAP_REFRESH_INTERVAL != x % MAP_REFRESH_INTERVAL) continue; |
|---|
| 207 | |
|---|
| 208 | for(int y=0;y < height;y++){ |
|---|
| 209 | MapChip here = toMap(x,y); |
|---|
| 210 | if(isMap(x,y, MapChip.TYPE.NONE)){ |
|---|
| 211 | // 何もない場合は隣接マスから芝えねるぎーを算出する |
|---|
| 212 | int grass_density = 0; |
|---|
| 213 | |
|---|
| 214 | // 周りの芝濃度を算出する |
|---|
| 215 | for(int v=0;v < vecx.length ; v++){ |
|---|
| 216 | int px = x + vecx[v]; |
|---|
| 217 | int py = y + vecy[v]; |
|---|
| 218 | |
|---|
| 219 | if(inRange(px,py)){ |
|---|
| 220 | MapChip m = toMap(px,py); |
|---|
| 221 | grass_density += m.grass; |
|---|
| 222 | } |
|---|
| 223 | } |
|---|
| 224 | // 濃度にあわせようとする |
|---|
| 225 | grass_density /= vecx.length;//grass_cnt; |
|---|
| 226 | |
|---|
| 227 | if(here.grass < grass_density){ |
|---|
| 228 | double a = grass_density - here.grass; |
|---|
| 229 | if(a > MAP_GRASS_AFFECT_LIMIT) a = MAP_GRASS_AFFECT_LIMIT; |
|---|
| 230 | here.grass += a; |
|---|
| 231 | } |
|---|
| 232 | }else if(isMap(x,y, MapChip.TYPE.MOVIE)){ |
|---|
| 233 | // 動画がある場合は無条件に濃度上昇 |
|---|
| 234 | here.grass = MOVIE_GRASS_FEED; |
|---|
| 235 | } |
|---|
| 236 | } |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | updateMovableMap(); |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | // キャラクタ判定用・移動可能マップを更新する |
|---|
| 243 | void updateMovableMap(){ |
|---|
| 244 | for(int x = 0;x < width;x++){ |
|---|
| 245 | for(int y=0;y < height;y++){ |
|---|
| 246 | bool res = true; |
|---|
| 247 | |
|---|
| 248 | if(map[x + y * width].type != MapChip.TYPE.NONE) res = false; |
|---|
| 249 | |
|---|
| 250 | movable_map[x + y * width] = res; |
|---|
| 251 | } |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | CharacterPool cp = gamemain.charpool; |
|---|
| 255 | foreach(c;cp.actors){ |
|---|
| 256 | if(c.exist){ |
|---|
| 257 | Vec3 p = c.getPosition(); |
|---|
| 258 | if(inRange(cast(int)p.x , cast(int)p.y) && c.isBlocking()) |
|---|
| 259 | movable_map[cast(int)p.x + cast(int)p.y * width] = false; |
|---|
| 260 | } |
|---|
| 261 | } |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | // 作画 |
|---|
| 265 | // 参照・キャラクタバケットソート |
|---|
| 266 | void draw(){ |
|---|
| 267 | // 芝色 |
|---|
| 268 | MapChip.GRASS_COLOR_R = configparser.getint("MAP_GRASS_COLOR_R"); |
|---|
| 269 | MapChip.GRASS_COLOR_G = configparser.getint("MAP_GRASS_COLOR_G"); |
|---|
| 270 | MapChip.GRASS_COLOR_B = configparser.getint("MAP_GRASS_COLOR_B"); |
|---|
| 271 | |
|---|
| 272 | // Map座標系で作画範囲をクリップ |
|---|
| 273 | int x_st = toRoundMapX(toMapX(0,0)); |
|---|
| 274 | int y_st = toRoundMapY(toMapY(gamemain.getScreenWidth(),0)); |
|---|
| 275 | int x_ed = toRoundMapX(toMapX(gamemain.getScreenWidth() , gamemain.getScreenHeight()) + 2); |
|---|
| 276 | int y_ed = toRoundMapY(toMapY(0 , gamemain.getScreenHeight()) + 2); |
|---|
| 277 | |
|---|
| 278 | for(int x = x_st;x < x_ed;x++){ |
|---|
| 279 | for(int y = y_st;y < y_ed;y++){ |
|---|
| 280 | double dx = toViewX(x,y); |
|---|
| 281 | double dy = toViewY(x,y); |
|---|
| 282 | |
|---|
| 283 | if(dx < -32 || dy < -32 || dx > gamemain.getScreenWidth() + 32 |
|---|
| 284 | || dy > gamemain.getScreenHeight() + 32) continue; |
|---|
| 285 | |
|---|
| 286 | toMap(x,y).drawBase(dx , dy); |
|---|
| 287 | if(isMap(x,y, MapChip.TYPE.NONE)) toMap(x,y).draw(dx , dy , (timer / 5) % 4); |
|---|
| 288 | } |
|---|
| 289 | } |
|---|
| 290 | |
|---|
| 291 | for(int x = x_st;x < x_ed;x++){ |
|---|
| 292 | for(int y = y_st;y < y_ed;y++){ |
|---|
| 293 | double dx = toViewX(x,y); |
|---|
| 294 | double dy = toViewY(x,y); |
|---|
| 295 | |
|---|
| 296 | if(dx < -32 || dy < -32 || dx > gamemain.getScreenWidth() + 32 |
|---|
| 297 | || dy > gamemain.getScreenHeight() + 32) continue; |
|---|
| 298 | |
|---|
| 299 | if(!isMap(x,y, MapChip.TYPE.NONE)) toMap(x,y).draw(dx , dy , (timer / 5) % 4); |
|---|
| 300 | gamemain.charpool.drawAtMap(x,y); |
|---|
| 301 | } |
|---|
| 302 | } |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | // ロード |
|---|
| 306 | bool loadFile( string filename ){ |
|---|
| 307 | string[] buffer; |
|---|
| 308 | try{ |
|---|
| 309 | buffer = std.string.split( cast(string) std.file.read(filename) , "\n" ); |
|---|
| 310 | }catch(Exception e){ |
|---|
| 311 | Hell_write(e); |
|---|
| 312 | return false; |
|---|
| 313 | } |
|---|
| 314 | |
|---|
| 315 | for(int y = 0 ; y < buffer.length ; y++ ){ |
|---|
| 316 | string line = buffer[y]; |
|---|
| 317 | for(int x = 0 ; x < line.length ; x++ ){ |
|---|
| 318 | char ch = line[x]; |
|---|
| 319 | MapChip m = toMap( x , y ); |
|---|
| 320 | if(m) m.setSerializedChar( ch ); |
|---|
| 321 | } |
|---|
| 322 | } |
|---|
| 323 | return true; |
|---|
| 324 | } |
|---|
| 325 | // セーブ |
|---|
| 326 | bool saveFile( string filename ){ |
|---|
| 327 | string buffer = ""; |
|---|
| 328 | for(int y = 0; y < height ; y++ ){ |
|---|
| 329 | for(int x = 0 ; x <width ; x++ ){ |
|---|
| 330 | MapChip m = toMap(x,y); |
|---|
| 331 | buffer ~= m.toSerializedChar(); |
|---|
| 332 | } |
|---|
| 333 | buffer ~= "\n"; |
|---|
| 334 | } |
|---|
| 335 | |
|---|
| 336 | try{ |
|---|
| 337 | std.file.write( filename , buffer ); |
|---|
| 338 | }catch(Exception e){ |
|---|
| 339 | Hell_write(e); |
|---|
| 340 | return false; |
|---|
| 341 | } |
|---|
| 342 | return true; |
|---|
| 343 | } |
|---|
| 344 | |
|---|
| 345 | // マップチップを配置 |
|---|
| 346 | bool set(int x,int y,MapChip.TYPE type){ |
|---|
| 347 | if(!inRange(x,y)) return false; |
|---|
| 348 | |
|---|
| 349 | MapChip m = toMap(x,y); |
|---|
| 350 | return m.set( type , 0 ); |
|---|
| 351 | } |
|---|
| 352 | |
|---|
| 353 | // 芝えねるぎーを配置 |
|---|
| 354 | bool setGrass(int x,int y,double grass){ |
|---|
| 355 | if(!inRange(x,y)) return false; |
|---|
| 356 | |
|---|
| 357 | MapChip m = toMap(x,y); |
|---|
| 358 | m.grass = grass; |
|---|
| 359 | return true; |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | // 芝エネルギー値をえる |
|---|
| 363 | double getGrass(int x,int y){ |
|---|
| 364 | if(!inRange(x,y)) return 0; |
|---|
| 365 | |
|---|
| 366 | MapChip m = toMap(x,y); |
|---|
| 367 | return m.grass; |
|---|
| 368 | } |
|---|
| 369 | |
|---|
| 370 | int getGrassLevel(int x,int y){ |
|---|
| 371 | if(!inRange(x,y)) return 0; |
|---|
| 372 | |
|---|
| 373 | MapChip m = toMap(x,y); |
|---|
| 374 | return m.getGrassLevel(); |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | bool isMap(int x,int y,MapChip.TYPE type){ |
|---|
| 378 | if(!inRange(x,y)) return false; |
|---|
| 379 | |
|---|
| 380 | MapChip m = toMap(x,y); |
|---|
| 381 | return m.type == type; |
|---|
| 382 | } |
|---|
| 383 | |
|---|
| 384 | // 座標変換 |
|---|
| 385 | double toViewX(double x,double y){return (x - y) * DRAW_CHIP_W + draw_ofs_x;} |
|---|
| 386 | double toViewY(double x,double y){return (x + y) * DRAW_CHIP_H + draw_ofs_y;} |
|---|
| 387 | int toMapX(int x,int y){ |
|---|
| 388 | return cast(int)(((x - draw_ofs_x - MOUSE_OFS_X) / DRAW_CHIP_W + (y - draw_ofs_y - MOUSE_OFS_Y) / DRAW_CHIP_H) / 2); |
|---|
| 389 | } |
|---|
| 390 | int toMapY(int x,int y){ |
|---|
| 391 | return cast(int)(((y - draw_ofs_y - MOUSE_OFS_Y) / DRAW_CHIP_H - (x - draw_ofs_x - MOUSE_OFS_X) / DRAW_CHIP_W) / 2); |
|---|
| 392 | } |
|---|
| 393 | |
|---|
| 394 | int toRoundMapX(int x){ |
|---|
| 395 | if(x < 0) return 0; |
|---|
| 396 | if(x >= width) return width; |
|---|
| 397 | return x; |
|---|
| 398 | } |
|---|
| 399 | int toRoundMapY(int y){ |
|---|
| 400 | if(y < 0) return 0; |
|---|
| 401 | if(y >= height) return height; |
|---|
| 402 | return y; |
|---|
| 403 | } |
|---|
| 404 | |
|---|
| 405 | bool inRange(int x,int y){ |
|---|
| 406 | return x >= 0 && y >= 0 && x < width && y < height; |
|---|
| 407 | } |
|---|
| 408 | |
|---|
| 409 | MapChip toMap(int x,int y){return map[x + y * width];} |
|---|
| 410 | bool isMovable(int x,int y){ |
|---|
| 411 | if(inRange(x,y)) return movable_map[x + y * width]; |
|---|
| 412 | return !MAP_BORDER_IS_WALL; |
|---|
| 413 | } |
|---|
| 414 | |
|---|
| 415 | int count(MapChip.TYPE type){ |
|---|
| 416 | int result = 0; |
|---|
| 417 | foreach(m;map){ |
|---|
| 418 | if(m.type == type) result++; |
|---|
| 419 | } |
|---|
| 420 | return result; |
|---|
| 421 | } |
|---|
| 422 | } |
|---|
| 423 | |
|---|