6d3dce4e16
Define separate enum values for rotation data in both the high bits, where it is usually kept, and the low bits, where it is sometimes used for math or comparisons. Define an enum value to represent the composite of the index and the rotation, since the composite is not suitable for use as an array subscript. Add helper functions to extract the component pieces.
691 lines
23 KiB
C++
691 lines
23 KiB
C++
/*
|
|
* Portions of this file are copyright Rebirth contributors and licensed as
|
|
* described in COPYING.txt.
|
|
* Portions of this file are copyright Parallax Software and licensed
|
|
* according to the Parallax license below.
|
|
* See COPYING.txt for license details.
|
|
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
|
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Mine specific editing functions, such as load_mine, save_mine
|
|
*
|
|
*/
|
|
|
|
#include <cinttypes>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include "key.h"
|
|
#include "gr.h"
|
|
#include "bm.h" // for MAX_TEXTURES
|
|
#include "inferno.h"
|
|
#include "segment.h"
|
|
#include "editor.h"
|
|
#include "editor/esegment.h"
|
|
#include "wall.h"
|
|
#include "dxxerror.h"
|
|
#include "textures.h"
|
|
#include "object.h"
|
|
#include "physfsx.h"
|
|
#include "gamemine.h"
|
|
#include "gamesave.h"
|
|
#include "gameseg.h"
|
|
#include "ui.h" // Because texpage.h need UI_DIALOG type
|
|
#include "texpage.h" // For texpage_goto_first
|
|
#include "medwall.h"
|
|
#include "switch.h"
|
|
#include "fuelcen.h"
|
|
|
|
#include "compiler-range_for.h"
|
|
#include "d_range.h"
|
|
#include "partial_range.h"
|
|
|
|
#define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0')
|
|
|
|
static int save_mine_data(PHYSFS_File * SaveFile);
|
|
|
|
int New_file_format_save = 1;
|
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
|
// Converts descent 2 texture numbers back to descent 1 texture numbers.
|
|
// Only works properly when the full Descent 1 texture set (descent.pig) is available.
|
|
static uint16_t convert_to_d1_tmap_num(const uint16_t tmap_num)
|
|
{
|
|
switch (tmap_num)
|
|
{
|
|
case 137: return 0; // grey rock001
|
|
case 0: return 1;
|
|
case 1: return 3; // rock021
|
|
case 270: return 6; // blue rock002
|
|
case 271: return 7; // yellow rock265
|
|
case 2: return 8; // rock004
|
|
case 138: return 9; // purple (devil:179)
|
|
case 272: return 10; // red rock006
|
|
case 139: return 11;
|
|
case 140: return 12; //devil:43
|
|
case 3: return 13; // rock014
|
|
case 4: return 14; // rock019
|
|
case 5: return 15; // rock020
|
|
case 6: return 16;
|
|
case 141: return 17;
|
|
case 129: return 18;
|
|
case 7: return 19;
|
|
case 142: return 20;
|
|
case 143: return 21;
|
|
case 8: return 22;
|
|
case 9: return 23;
|
|
case 10: return 24;
|
|
case 144: return 25; //devil:35
|
|
case 11: return 26;
|
|
case 12: return 27;
|
|
case 145: return 28; //devil:43
|
|
//range handled by default case, returns 13..21 (- 16)
|
|
case 163: return 38; //devil:27
|
|
case 147: return 39; //31
|
|
case 22: return 40;
|
|
case 266: return 41;
|
|
case 23: return 42;
|
|
case 24: return 43;
|
|
case 136: return 44; //devil:135
|
|
case 25: return 45;
|
|
case 26: return 46;
|
|
case 27: return 47;
|
|
case 28: return 48;
|
|
case 146: return 49; //devil:60
|
|
case 131: return 50; //devil:138
|
|
case 29: return 51;
|
|
case 30: return 52;
|
|
case 31: return 53;
|
|
case 32: return 54;
|
|
case 165: return 55; //devil:193
|
|
case 33: return 56;
|
|
case 132: return 57; //devil:119
|
|
// range handled by default case, returns 58..88 (+ 24)
|
|
case 197: return 88; //devil:15
|
|
// range handled by default case, returns 89..106 (- 25)
|
|
case 167: return 132;
|
|
// range handled by default case, returns 107..114 (- 26)
|
|
case 148: return 141; //devil:106
|
|
case 115: return 142;
|
|
case 116: return 143;
|
|
case 117: return 144;
|
|
case 118: return 145;
|
|
case 119: return 146;
|
|
case 149: return 147;
|
|
case 120: return 148;
|
|
case 121: return 149;
|
|
case 122: return 150;
|
|
case 123: return 151;
|
|
case 124: return 152;
|
|
case 125: return 153; // rock263
|
|
case 150: return 154;
|
|
case 126: return 155; // rock269
|
|
case 200: return 156; // metl002
|
|
case 201: return 157; // metl003
|
|
case 186: return 158; //devil:227
|
|
case 190: return 159; //devil:246
|
|
case 151: return 160;
|
|
case 152: return 161; //devil:206
|
|
case 202: return 162;
|
|
case 203: return 163;
|
|
case 204: return 164;
|
|
case 205: return 165;
|
|
case 206: return 166;
|
|
case 153: return 167;
|
|
case 154: return 168;
|
|
case 155: return 169;
|
|
case 156: return 170;//206;
|
|
case 157: return 171;//227;
|
|
case 207: return 172;
|
|
case 208: return 173;
|
|
case 158: return 174;
|
|
case 159: return 175;
|
|
// range handled by default case, returns 209..217 (+ 33)
|
|
case 160: return 185;
|
|
// range handled by default case, returns 218..224 (+ 32)
|
|
case 161: return 193;
|
|
case 162: return 194;//206;
|
|
case 166: return 195;
|
|
case 225: return 196;
|
|
case 226: return 197;
|
|
case 193: return 198;
|
|
case 168: return 199; //devil:204
|
|
case 169: return 200; //devil:204
|
|
case 227: return 201;
|
|
case 170: return 202; //devil:227
|
|
// range handled by default case, returns 228..234 (+ 25)
|
|
case 171: return 210; //devil:242
|
|
case 172: return 211; //devil:240
|
|
// range handled by default case, returns 235..242 (+ 23)
|
|
case 173: return 220; //devil:240
|
|
case 243: return 221;
|
|
case 244: return 222;
|
|
case 174: return 223;
|
|
case 245: return 224;
|
|
case 246: return 225;
|
|
case 164: return 226;//247; matching names but not matching textures
|
|
case 179: return 227; //devil:181
|
|
case 196: return 228;//248; matching names but not matching textures
|
|
case 175: return 229; //devil:66
|
|
case 176: return 230; //devil:66
|
|
// range handled by default case, returns 249..257 (+ 18)
|
|
case 177: return 240; //devil:132
|
|
case 130: return 241; //devil:131
|
|
case 178: return 242; //devil:15
|
|
case 180: return 243; //devil:38
|
|
case 258: return 244;
|
|
case 259: return 245;
|
|
case 181: return 246; // grate metl127
|
|
case 260: return 247;
|
|
case 261: return 248;
|
|
case 262: return 249;
|
|
case 340: return 250; // white doorframe metl126
|
|
case 412: return 251; // red doorframe metl133
|
|
case 410: return 252; // blue doorframe metl134
|
|
case 411: return 253; // yellow doorframe metl135
|
|
case 263: return 254; // metl136
|
|
case 264: return 255; // metl139
|
|
case 265: return 256; // metl140
|
|
case 182: return 257;//246; brig001
|
|
case 183: return 258;//246; brig002
|
|
case 184: return 259;//246; brig003
|
|
case 185: return 260;//246; brig004
|
|
case 273: return 261; // exit01
|
|
case 274: return 262; // exit02
|
|
case 187: return 263; // ceil001
|
|
case 275: return 264; // ceil002
|
|
case 276: return 265; // ceil003
|
|
case 188: return 266; //devil:291
|
|
// range handled by default case, returns 277..291 (+ 10)
|
|
case 293: return 282;
|
|
case 189: return 283;
|
|
case 295: return 284;
|
|
case 296: return 285;
|
|
case 298: return 286;
|
|
// range handled by default case, returns 300..310 (+ 13)
|
|
case 191: return 298; // devil:374 misc010
|
|
// range handled by default case, returns 311..326 (+ 12)
|
|
case 192: return 315; // bad producer misc044
|
|
// range handled by default case, returns 327..337 (+ 11)
|
|
case 352: return 327; // arw01
|
|
case 353: return 328; // misc17
|
|
case 354: return 329; // fan01
|
|
case 380: return 330; // mntr04
|
|
case 379: return 331;//373; matching names but not matching textures
|
|
case 355: return 332;//344; matching names but not matching textures
|
|
case 409: return 333; // lava misc11 //devil:404
|
|
case 356: return 334; // ctrl04
|
|
case 357: return 335; // ctrl01
|
|
case 358: return 336; // ctrl02
|
|
case 359: return 337; // ctrl03
|
|
case 360: return 338; // misc14
|
|
case 361: return 339; // producer misc16
|
|
case 362: return 340; // misc049
|
|
case 364: return 341; // misc060
|
|
case 363: return 342; // blown01
|
|
case 366: return 343; // misc061
|
|
case 365: return 344;
|
|
case 368: return 345;
|
|
case 376: return 346;
|
|
case 370: return 347;
|
|
case 367: return 348;
|
|
case 372: return 349;
|
|
case 369: return 350;
|
|
case 374: return 351;//429; matching names but not matching textures
|
|
case 375: return 352;//387; matching names but not matching textures
|
|
case 371: return 353;
|
|
case 377: return 354;//425; matching names but not matching textures
|
|
case 408: return 355;
|
|
case 378: return 356; // lava02
|
|
case 383: return 357;//384; matching names but not matching textures
|
|
case 384: return 358;//385; matching names but not matching textures
|
|
case 385: return 359;//386; matching names but not matching textures
|
|
case 386: return 360;
|
|
case 387: return 361;
|
|
case 194: return 362; // mntr04b (devil: -1)
|
|
case 388: return 363;
|
|
case 391: return 364;
|
|
case 392: return 365;
|
|
case 393: return 366;
|
|
case 394: return 367;
|
|
case 395: return 368;
|
|
case 396: return 369;
|
|
case 195: return 370; // mntr04d (devil: -1)
|
|
// range 371..584 handled by default case (wall01 and door frames)
|
|
default:
|
|
// ranges:
|
|
if (tmap_num >= 13 && tmap_num <= 21)
|
|
return tmap_num + 16;
|
|
if (tmap_num >= 34 && tmap_num <= 63)
|
|
return tmap_num + 24;
|
|
if (tmap_num >= 64 && tmap_num <= 106)
|
|
return tmap_num + 25;
|
|
if (tmap_num >= 107 && tmap_num <= 114)
|
|
return tmap_num + 26;
|
|
if (tmap_num >= 209 && tmap_num <= 217)
|
|
return tmap_num - 33;
|
|
if (tmap_num >= 218 && tmap_num <= 224)
|
|
return tmap_num - 32;
|
|
if (tmap_num >= 228 && tmap_num <= 234)
|
|
return tmap_num - 25;
|
|
if (tmap_num >= 235 && tmap_num <= 242)
|
|
return tmap_num - 23;
|
|
if (tmap_num >= 249 && tmap_num <= 257)
|
|
return tmap_num - 18;
|
|
if (tmap_num >= 277 && tmap_num <= 291)
|
|
return tmap_num - 10;
|
|
if (tmap_num >= 300 && tmap_num <= 310)
|
|
return tmap_num - 13;
|
|
if (tmap_num >= 311 && tmap_num <= 326)
|
|
return tmap_num - 12;
|
|
if (tmap_num >= 327 && tmap_num <= 337)
|
|
return tmap_num - 11; // matching names but not matching textures
|
|
// wall01 and door frames:
|
|
if (tmap_num > 434 && tmap_num < 731)
|
|
{
|
|
if (New_file_format_save) return tmap_num - 64;
|
|
// d1 shareware needs special treatment:
|
|
if (tmap_num < 478) return tmap_num - 68;
|
|
if (tmap_num < 490) return tmap_num - 73;
|
|
if (tmap_num < 537) return tmap_num - 91;
|
|
if (tmap_num < 557) return tmap_num - 104;
|
|
if (tmap_num < 573) return tmap_num - 111;
|
|
if (tmap_num < 603) return tmap_num - 117;
|
|
if (tmap_num < 635) return tmap_num - 141;
|
|
if (tmap_num < 731) return tmap_num - 147;
|
|
}
|
|
Warning("can't convert unknown texture #%hu to descent 1.\n", tmap_num);
|
|
return tmap_num;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Save mine will:
|
|
// 1. Write file info, header info, editor info, vertex data, segment data,
|
|
// and new_segment in that order, marking their file offset.
|
|
// 2. Go through all the fields and fill in the offset, size, and sizeof
|
|
// values in the headers.
|
|
|
|
int med_save_mine(const char * filename)
|
|
{
|
|
char ErrorMessage[256];
|
|
|
|
auto SaveFile = PHYSFSX_openWriteBuffered(filename);
|
|
if (!SaveFile)
|
|
{
|
|
snprintf(ErrorMessage, sizeof(ErrorMessage), "ERROR: Unable to open %s\n", filename);
|
|
ui_messagebox( -2, -2, 1, ErrorMessage, "Ok" );
|
|
return 1;
|
|
}
|
|
|
|
save_mine_data(SaveFile);
|
|
|
|
//==================== CLOSE THE FILE =============================
|
|
return 0;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// saves to an already-open file
|
|
static int save_mine_data(PHYSFS_File * SaveFile)
|
|
{
|
|
auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
|
|
int header_offset, editor_offset, vertex_offset, segment_offset, texture_offset, walls_offset, triggers_offset; //, links_offset;
|
|
int newseg_verts_offset;
|
|
int newsegment_offset;
|
|
med_compress_mine();
|
|
warn_if_concave_segments();
|
|
|
|
std::array<d_fname, MAX_TEXTURES> current_tmap_list;
|
|
auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
|
|
for (int i=0;i<NumTextures;i++)
|
|
current_tmap_list[i] = TmapInfo[i].filename;
|
|
|
|
//=================== Calculate offsets into file ==================
|
|
|
|
header_offset = PHYSFS_tell(SaveFile) + sizeof(mine_fileinfo);
|
|
editor_offset = header_offset + sizeof(mine_header);
|
|
texture_offset = editor_offset + sizeof(mine_editor);
|
|
vertex_offset = texture_offset + (13*NumTextures);
|
|
segment_offset = vertex_offset + (sizeof(vms_vector) * LevelSharedVertexState.Num_vertices);
|
|
newsegment_offset = segment_offset + (sizeof(segment) * LevelSharedSegmentState.Num_segments);
|
|
newseg_verts_offset = newsegment_offset + sizeof(segment);
|
|
walls_offset = newseg_verts_offset + (sizeof(vms_vector)*8);
|
|
auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
|
|
auto &Walls = LevelUniqueWallSubsystemState.Walls;
|
|
triggers_offset = walls_offset + (sizeof(wall)*Walls.get_count());
|
|
|
|
//===================== SAVE FILE INFO ========================
|
|
|
|
mine_fileinfo.fileinfo_signature= 0x2884;
|
|
mine_fileinfo.fileinfo_version = MINE_VERSION;
|
|
mine_fileinfo.fileinfo_sizeof = sizeof(mine_fileinfo);
|
|
mine_fileinfo.header_offset = header_offset;
|
|
mine_fileinfo.header_size = sizeof(mine_header);
|
|
mine_fileinfo.editor_offset = editor_offset;
|
|
mine_fileinfo.editor_size = sizeof(mine_editor);
|
|
mine_fileinfo.vertex_offset = vertex_offset;
|
|
mine_fileinfo.vertex_howmany = LevelSharedVertexState.Num_vertices;
|
|
mine_fileinfo.vertex_sizeof = sizeof(vms_vector);
|
|
mine_fileinfo.segment_offset = segment_offset;
|
|
mine_fileinfo.segment_howmany = LevelSharedSegmentState.Num_segments;
|
|
mine_fileinfo.segment_sizeof = sizeof(segment);
|
|
mine_fileinfo.newseg_verts_offset = newseg_verts_offset;
|
|
mine_fileinfo.newseg_verts_howmany = 8;
|
|
mine_fileinfo.newseg_verts_sizeof = sizeof(vms_vector);
|
|
mine_fileinfo.texture_offset = texture_offset;
|
|
mine_fileinfo.texture_howmany = NumTextures;
|
|
mine_fileinfo.texture_sizeof = 13; // num characters in a name
|
|
mine_fileinfo.walls_offset = walls_offset;
|
|
mine_fileinfo.walls_howmany = Walls.get_count();
|
|
mine_fileinfo.walls_sizeof = sizeof(wall);
|
|
mine_fileinfo.triggers_offset = triggers_offset;
|
|
mine_fileinfo.triggers_howmany = Triggers.get_count();
|
|
mine_fileinfo.triggers_sizeof = sizeof(trigger);
|
|
|
|
// Write the fileinfo
|
|
PHYSFS_write( SaveFile, &mine_fileinfo, sizeof(mine_fileinfo), 1 );
|
|
|
|
//===================== SAVE HEADER INFO ========================
|
|
|
|
mine_header.num_vertices = LevelSharedVertexState.Num_vertices;
|
|
mine_header.num_segments = LevelSharedSegmentState.Num_segments;
|
|
|
|
// Write the editor info
|
|
if (header_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
|
|
PHYSFS_write( SaveFile, &mine_header, sizeof(mine_header), 1 );
|
|
|
|
//===================== SAVE EDITOR INFO ==========================
|
|
mine_editor.current_seg = Cursegp;
|
|
mine_editor.newsegment_offset = newsegment_offset;
|
|
mine_editor.newsegment_size = sizeof(segment);
|
|
|
|
// Next 3 vars added 10/07 by JAS
|
|
mine_editor.Curside = Curside;
|
|
if (Markedsegp)
|
|
mine_editor.Markedsegp = Markedsegp;
|
|
else
|
|
mine_editor.Markedsegp = -1;
|
|
mine_editor.Markedside = Markedside;
|
|
range_for (const int i, xrange(10u))
|
|
mine_editor.Groupsegp[i] = vmsegptridx(Groupsegp[i]);
|
|
range_for (const int i, xrange(10u))
|
|
mine_editor.Groupside[i] = Groupside[i];
|
|
|
|
if (editor_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
PHYSFS_write( SaveFile, &mine_editor, sizeof(mine_editor), 1 );
|
|
|
|
//===================== SAVE TEXTURE INFO ==========================
|
|
|
|
if (texture_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
range_for (auto &i, partial_const_range(current_tmap_list, NumTextures))
|
|
PHYSFS_write(SaveFile, i.data(), i.size(), 1);
|
|
|
|
//===================== SAVE VERTEX INFO ==========================
|
|
|
|
if (vertex_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
auto &Vertices = LevelSharedVertexState.get_vertices();
|
|
PHYSFS_write(SaveFile, Vertices, sizeof(vms_vector), LevelSharedVertexState.Num_vertices);
|
|
|
|
//===================== SAVE SEGMENT INFO =========================
|
|
|
|
if (segment_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
Error("Sorry, v20 segment support is broken.");
|
|
#if 0
|
|
PHYSFS_write(SaveFile, &Segments.front(), sizeof(segment), LevelSharedSegmentState.Num_segments);
|
|
|
|
//===================== SAVE NEWSEGMENT INFO ======================
|
|
|
|
if (newsegment_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
PHYSFS_write( SaveFile, &New_segment, sizeof(segment), 1 );
|
|
#endif
|
|
|
|
if (newseg_verts_offset != PHYSFS_tell(SaveFile))
|
|
Error( "OFFSETS WRONG IN MINE.C!" );
|
|
PHYSFS_write( SaveFile, &Vertices[New_segment.verts[0]], sizeof(vms_vector), 8 );
|
|
|
|
//==================== CLOSE THE FILE =============================
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define COMPILED_MINE_VERSION 0
|
|
|
|
static void dump_fix_as_short( fix value, int nbits, PHYSFS_File *SaveFile )
|
|
{
|
|
short short_value;
|
|
|
|
auto int_value = value >> nbits;
|
|
if (int_value > INT16_MAX)
|
|
{
|
|
short_value = INT16_MAX;
|
|
}
|
|
else if( int_value < -0x7fff ) {
|
|
short_value = -0x7fff;
|
|
}
|
|
else
|
|
short_value = static_cast<short>(int_value);
|
|
|
|
PHYSFS_writeSLE16(SaveFile, short_value);
|
|
}
|
|
|
|
//version of dump for unsigned values
|
|
static void dump_fix_as_ushort( fix value, int nbits, PHYSFS_File *SaveFile )
|
|
{
|
|
uint int_value=0;
|
|
ushort short_value;
|
|
|
|
if (value < 0) {
|
|
Int3(); //hey---show this to Matt
|
|
value = 0;
|
|
}
|
|
else
|
|
int_value = value >> nbits;
|
|
|
|
if( int_value > 0xffff ) {
|
|
short_value = 0xffff;
|
|
}
|
|
else
|
|
short_value = int_value;
|
|
|
|
PHYSFS_writeULE16(SaveFile, short_value);
|
|
}
|
|
|
|
static void write_children(const shared_segment &seg, const unsigned bit_mask, PHYSFS_File *const SaveFile)
|
|
{
|
|
auto &children = seg.children;
|
|
for (int bit = 0; bit < MAX_SIDES_PER_SEGMENT; bit++)
|
|
{
|
|
if (bit_mask & (1 << bit))
|
|
PHYSFS_writeSLE16(SaveFile, children[bit]);
|
|
}
|
|
}
|
|
|
|
static void write_verts(const shared_segment &seg, PHYSFS_File *const SaveFile)
|
|
{
|
|
range_for (auto &i, seg.verts)
|
|
PHYSFS_writeSLE16(SaveFile, i);
|
|
}
|
|
|
|
static void write_special(const shared_segment &seg, const unsigned bit_mask, PHYSFS_File *const SaveFile)
|
|
{
|
|
if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT))
|
|
{
|
|
PHYSFSX_writeU8(SaveFile, seg.special);
|
|
PHYSFSX_writeU8(SaveFile, seg.matcen_num);
|
|
PHYSFS_writeULE16(SaveFile, seg.station_idx);
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
// saves compiled mine data to an already-open file...
|
|
namespace dsx {
|
|
int save_mine_data_compiled(PHYSFS_File *SaveFile)
|
|
{
|
|
auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
|
|
ubyte version = COMPILED_MINE_VERSION;
|
|
ubyte bit_mask = 0;
|
|
|
|
med_compress_mine();
|
|
warn_if_concave_segments();
|
|
|
|
if (Highest_segment_index >= MAX_SEGMENTS) {
|
|
char message[128];
|
|
snprintf(message, sizeof(message), "Error: Too many segments (%i > %" PRIuFAST32 ") for game (not editor)", Highest_segment_index+1, static_cast<uint_fast32_t>(MAX_SEGMENTS));
|
|
ui_messagebox( -2, -2, 1, message, "Ok" );
|
|
}
|
|
|
|
auto &Vertices = LevelSharedVertexState.get_vertices();
|
|
if (Vertices.get_count() > MAX_VERTICES)
|
|
{
|
|
char message[128];
|
|
snprintf(message, sizeof(message), "Error: Too many vertices (%i > %" PRIuFAST32 ") for game (not editor)", Vertices.get_count(), static_cast<uint_fast32_t>(MAX_VERTICES));
|
|
ui_messagebox( -2, -2, 1, message, "Ok" );
|
|
}
|
|
|
|
//=============================== Writing part ==============================
|
|
PHYSFSX_writeU8(SaveFile, version); // 1 byte = compiled version
|
|
if (New_file_format_save)
|
|
{
|
|
PHYSFS_writeSLE16(SaveFile, LevelSharedVertexState.Num_vertices); // 2 bytes = Num_vertices
|
|
PHYSFS_writeSLE16(SaveFile, LevelSharedSegmentState.Num_segments); // 2 bytes = Num_segments
|
|
}
|
|
else
|
|
{
|
|
PHYSFS_writeSLE32(SaveFile, LevelSharedVertexState.Num_vertices); // 4 bytes = Num_vertices
|
|
PHYSFS_writeSLE32(SaveFile, LevelSharedSegmentState.Num_segments); // 4 bytes = Num_segments
|
|
}
|
|
|
|
range_for (auto &i, partial_const_range(Vertices, LevelSharedVertexState.Num_vertices))
|
|
PHYSFSX_writeVector(SaveFile, i);
|
|
|
|
const auto Num_segments = LevelSharedSegmentState.Num_segments;
|
|
for (segnum_t segnum = 0; segnum < Num_segments; segnum++)
|
|
{
|
|
const cscusegment &&seg = vcsegptr(segnum);
|
|
for (short sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
|
|
{
|
|
if (seg.s.children[sidenum] != segment_none)
|
|
bit_mask |= (1 << sidenum);
|
|
}
|
|
|
|
if (seg.s.special != 0 || seg.s.matcen_num != 0 || seg.s.station_idx != station_none)
|
|
bit_mask |= (1 << MAX_SIDES_PER_SEGMENT);
|
|
|
|
if (New_file_format_save)
|
|
PHYSFSX_writeU8(SaveFile, bit_mask);
|
|
else
|
|
bit_mask = 0x7F;
|
|
|
|
if (Gamesave_current_version == 5) // d2 SHAREWARE level
|
|
{
|
|
write_special(seg, bit_mask, SaveFile);
|
|
write_verts(seg, SaveFile);
|
|
write_children(seg, bit_mask, SaveFile);
|
|
}
|
|
else
|
|
{
|
|
write_children(seg, bit_mask, SaveFile);
|
|
write_verts(seg, SaveFile);
|
|
if (Gamesave_current_version <= 1) // descent 1 level
|
|
write_special(seg, bit_mask, SaveFile);
|
|
}
|
|
|
|
if (Gamesave_current_version <= 5) // descent 1 thru d2 SHAREWARE level
|
|
dump_fix_as_ushort(seg.u.static_light, 4, SaveFile);
|
|
|
|
// Write the walls as a 6 byte array
|
|
bit_mask = 0;
|
|
for (short sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
|
|
{
|
|
uint wallnum;
|
|
|
|
if (seg.s.sides[sidenum].wall_num != wall_none)
|
|
{
|
|
bit_mask |= (1 << sidenum);
|
|
wallnum = seg.s.sides[sidenum].wall_num;
|
|
Assert( wallnum < 255 ); // Get John or Mike.. can only store up to 255 walls!!!
|
|
(void)wallnum;
|
|
}
|
|
}
|
|
if (New_file_format_save)
|
|
PHYSFSX_writeU8(SaveFile, bit_mask);
|
|
else
|
|
bit_mask = 0x3F;
|
|
|
|
for (short sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
|
|
{
|
|
if (bit_mask & (1 << sidenum))
|
|
PHYSFSX_writeU8(SaveFile, seg.s.sides[sidenum].wall_num);
|
|
}
|
|
|
|
for (short sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++)
|
|
{
|
|
if (seg.s.children[sidenum] == segment_none || seg.s.sides[sidenum].wall_num != wall_none)
|
|
{
|
|
auto tmap_num = seg.u.sides[sidenum].tmap_num;
|
|
auto tmap_num2 = seg.u.sides[sidenum].tmap_num2;
|
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
|
if (Gamesave_current_version <= 3) // convert texture numbers back to d1
|
|
{
|
|
tmap_num = convert_to_d1_tmap_num(tmap_num);
|
|
if (tmap_num2 != texture2_value::None)
|
|
{
|
|
tmap_num2 = build_texture2_value(convert_to_d1_tmap_num(get_texture_index(tmap_num2)), get_texture_rotation_high(tmap_num2));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (tmap_num2 != texture2_value::None && New_file_format_save)
|
|
tmap_num |= 0x8000;
|
|
|
|
PHYSFS_writeSLE16(SaveFile, tmap_num);
|
|
if (tmap_num2 != texture2_value::None || !New_file_format_save)
|
|
PHYSFS_writeSLE16(SaveFile, static_cast<uint16_t>(tmap_num2));
|
|
|
|
range_for (auto &i, seg.u.sides[sidenum].uvls)
|
|
{
|
|
dump_fix_as_short(i.u, 5, SaveFile);
|
|
dump_fix_as_short(i.v, 5, SaveFile);
|
|
dump_fix_as_ushort(i.l, 1, SaveFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
|
if (Gamesave_current_version > 5)
|
|
for (segnum_t i = 0; i < Num_segments; i++)
|
|
segment2_write(vcsegptr(i), SaveFile);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|