2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* 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 .
2006-03-20 17:12:09 +00:00
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
*
*/
2014-10-19 21:04:16 +00:00
# include <cinttypes>
2006-03-20 17:12:09 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include "gr.h"
# include "bm.h" // for MAX_TEXTURES
# include "inferno.h"
# include "segment.h"
# include "editor.h"
2013-03-16 03:10:55 +00:00
# include "editor/esegment.h"
2014-12-22 04:35:49 +00:00
# include "wall.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "textures.h"
2014-07-20 01:09:55 +00:00
# include "physfsx.h"
2006-03-20 17:12:09 +00:00
# include "gamemine.h"
# include "gamesave.h"
# include "switch.h"
# include "fuelcen.h"
2014-12-20 04:36:11 +00:00
# include "compiler-range_for.h"
2022-01-09 15:25:42 +00:00
# include "d_enumerate.h"
2019-05-04 18:27:36 +00:00
# include "d_range.h"
2021-09-04 12:17:14 +00:00
# include "d_underlying_value.h"
2014-12-20 04:36:11 +00:00
2006-03-20 17:12:09 +00:00
# define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0')
int New_file_format_save = 1 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2020-10-12 03:28:25 +00:00
namespace dsx {
namespace {
2006-03-20 17:12:09 +00:00
// 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.
2020-09-11 03:08:02 +00:00
static texture_index convert_to_d1_tmap_num ( const texture_index tmap_num )
2006-03-20 17:12:09 +00:00
{
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 ;
}
2020-08-24 01:31:28 +00:00
Warning ( " can't convert unknown texture #%hu to descent 1. \n " , tmap_num ) ;
return tmap_num ;
2006-03-20 17:12:09 +00:00
}
}
2020-10-12 03:28:25 +00:00
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2020-10-12 03:28:25 +00:00
namespace {
static int save_mine_data ( PHYSFS_File * SaveFile ) ;
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------
// 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.
2020-10-12 03:28:25 +00:00
static int med_save_mine ( const char * filename )
2006-03-20 17:12:09 +00:00
{
char ErrorMessage [ 256 ] ;
2021-07-25 23:00:56 +00:00
auto & & [ SaveFile , physfserr ] = PHYSFSX_openWriteBuffered ( filename ) ;
2006-03-20 17:12:09 +00:00
if ( ! SaveFile )
{
2021-07-25 23:00:56 +00:00
snprintf ( ErrorMessage , sizeof ( ErrorMessage ) , " ERROR: Unable to open %.200s: %s \n " , filename , PHYSFS_getErrorByCode ( physfserr ) ) ;
2012-04-17 08:11:42 +00:00
ui_messagebox ( - 2 , - 2 , 1 , ErrorMessage , " Ok " ) ;
2006-03-20 17:12:09 +00:00
return 1 ;
}
save_mine_data ( SaveFile ) ;
//==================== CLOSE THE FILE =============================
return 0 ;
}
// -----------------------------------------------------------------------------
// saves to an already-open file
2016-01-09 16:38:14 +00:00
static int save_mine_data ( PHYSFS_File * SaveFile )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2011-09-26 23:31:19 +00:00
int header_offset , editor_offset , vertex_offset , segment_offset , texture_offset , walls_offset , triggers_offset ; //, links_offset;
2006-03-20 17:12:09 +00:00
int newseg_verts_offset ;
int newsegment_offset ;
med_compress_mine ( ) ;
warn_if_concave_segments ( ) ;
2020-05-02 21:18:42 +00:00
std : : array < d_fname , MAX_TEXTURES > current_tmap_list ;
2018-12-30 00:43:59 +00:00
auto & TmapInfo = LevelUniqueTmapInfoState . TmapInfo ;
2014-09-26 02:42:12 +00:00
for ( int i = 0 ; i < NumTextures ; i + + )
2014-07-23 02:27:22 +00:00
current_tmap_list [ i ] = TmapInfo [ i ] . filename ;
2006-03-20 17:12:09 +00:00
//=================== Calculate offsets into file ==================
2011-06-01 07:59:55 +00:00
header_offset = PHYSFS_tell ( SaveFile ) + sizeof ( mine_fileinfo ) ;
2006-03-20 17:12:09 +00:00
editor_offset = header_offset + sizeof ( mine_header ) ;
texture_offset = editor_offset + sizeof ( mine_editor ) ;
vertex_offset = texture_offset + ( 13 * NumTextures ) ;
2018-12-30 00:43:57 +00:00
segment_offset = vertex_offset + ( sizeof ( vms_vector ) * LevelSharedVertexState . Num_vertices ) ;
2018-09-19 02:13:29 +00:00
newsegment_offset = segment_offset + ( sizeof ( segment ) * LevelSharedSegmentState . Num_segments ) ;
2006-03-20 17:12:09 +00:00
newseg_verts_offset = newsegment_offset + sizeof ( segment ) ;
walls_offset = newseg_verts_offset + ( sizeof ( vms_vector ) * 8 ) ;
2018-12-30 00:43:58 +00:00
auto & Triggers = LevelUniqueWallSubsystemState . Triggers ;
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
2018-12-13 02:31:39 +00:00
triggers_offset = walls_offset + ( sizeof ( wall ) * Walls . get_count ( ) ) ;
2006-03-20 17:12:09 +00:00
//===================== 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 ;
2018-12-30 00:43:57 +00:00
mine_fileinfo . vertex_howmany = LevelSharedVertexState . Num_vertices ;
2006-03-20 17:12:09 +00:00
mine_fileinfo . vertex_sizeof = sizeof ( vms_vector ) ;
mine_fileinfo . segment_offset = segment_offset ;
2018-09-19 02:13:29 +00:00
mine_fileinfo . segment_howmany = LevelSharedSegmentState . Num_segments ;
2006-03-20 17:12:09 +00:00
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 ;
2018-12-13 02:31:39 +00:00
mine_fileinfo . walls_howmany = Walls . get_count ( ) ;
2006-03-20 17:12:09 +00:00
mine_fileinfo . walls_sizeof = sizeof ( wall ) ;
mine_fileinfo . triggers_offset = triggers_offset ;
2018-12-13 02:31:39 +00:00
mine_fileinfo . triggers_howmany = Triggers . get_count ( ) ;
2006-03-20 17:12:09 +00:00
mine_fileinfo . triggers_sizeof = sizeof ( trigger ) ;
// Write the fileinfo
2010-08-19 13:32:33 +00:00
PHYSFS_write ( SaveFile , & mine_fileinfo , sizeof ( mine_fileinfo ) , 1 ) ;
2006-03-20 17:12:09 +00:00
//===================== SAVE HEADER INFO ========================
2018-12-30 00:43:57 +00:00
mine_header . num_vertices = LevelSharedVertexState . Num_vertices ;
2018-09-19 02:13:29 +00:00
mine_header . num_segments = LevelSharedSegmentState . Num_segments ;
2006-03-20 17:12:09 +00:00
// Write the editor info
2011-06-01 07:59:55 +00:00
if ( header_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2010-08-19 13:32:33 +00:00
PHYSFS_write ( SaveFile , & mine_header , sizeof ( mine_header ) , 1 ) ;
2006-03-20 17:12:09 +00:00
//===================== SAVE EDITOR INFO ==========================
2015-07-12 01:04:18 +00:00
mine_editor . current_seg = Cursegp ;
2006-03-20 17:12:09 +00:00
mine_editor . newsegment_offset = newsegment_offset ;
mine_editor . newsegment_size = sizeof ( segment ) ;
// Next 3 vars added 10/07 by JAS
2022-06-05 17:44:52 +00:00
mine_editor . Curside = underlying_value ( Curside ) ;
2006-03-20 17:12:09 +00:00
if ( Markedsegp )
2015-07-12 01:04:18 +00:00
mine_editor . Markedsegp = Markedsegp ;
2006-03-20 17:12:09 +00:00
else
mine_editor . Markedsegp = - 1 ;
2022-06-05 17:44:52 +00:00
mine_editor . Markedside = underlying_value ( Markedside ) ;
2019-05-04 18:27:36 +00:00
range_for ( const int i , xrange ( 10u ) )
2017-06-10 03:31:02 +00:00
mine_editor . Groupsegp [ i ] = vmsegptridx ( Groupsegp [ i ] ) ;
2019-05-04 18:27:36 +00:00
range_for ( const int i , xrange ( 10u ) )
2022-06-05 17:44:52 +00:00
mine_editor . Groupside [ i ] = underlying_value ( Groupside [ i ] ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
if ( editor_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2010-08-19 13:32:33 +00:00
PHYSFS_write ( SaveFile , & mine_editor , sizeof ( mine_editor ) , 1 ) ;
2006-03-20 17:12:09 +00:00
//===================== SAVE TEXTURE INFO ==========================
2011-06-01 07:59:55 +00:00
if ( texture_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2016-02-12 04:02:28 +00:00
range_for ( auto & i , partial_const_range ( current_tmap_list , NumTextures ) )
2014-12-20 04:36:11 +00:00
PHYSFS_write ( SaveFile , i . data ( ) , i . size ( ) , 1 ) ;
2006-03-20 17:12:09 +00:00
//===================== SAVE VERTEX INFO ==========================
2011-06-01 07:59:55 +00:00
if ( vertex_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2018-12-30 00:43:57 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2018-12-30 00:43:57 +00:00
PHYSFS_write ( SaveFile , Vertices , sizeof ( vms_vector ) , LevelSharedVertexState . Num_vertices ) ;
2006-03-20 17:12:09 +00:00
//===================== SAVE SEGMENT INFO =========================
2011-06-01 07:59:55 +00:00
if ( segment_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2018-06-24 05:06:14 +00:00
Error ( " Sorry, v20 segment support is broken. " ) ;
#if 0
2018-09-19 02:13:29 +00:00
PHYSFS_write ( SaveFile , & Segments . front ( ) , sizeof ( segment ) , LevelSharedSegmentState . Num_segments ) ;
2006-03-20 17:12:09 +00:00
//===================== SAVE NEWSEGMENT INFO ======================
2011-06-01 07:59:55 +00:00
if ( newsegment_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2010-08-19 13:32:33 +00:00
PHYSFS_write ( SaveFile , & New_segment , sizeof ( segment ) , 1 ) ;
2018-06-24 05:06:14 +00:00
# endif
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
if ( newseg_verts_offset ! = PHYSFS_tell ( SaveFile ) )
2006-03-20 17:12:09 +00:00
Error ( " OFFSETS WRONG IN MINE.C! " ) ;
2022-01-09 15:25:42 +00:00
PHYSFS_write ( SaveFile , & Vertices [ New_segment . verts . front ( ) ] , sizeof ( vms_vector ) , 8 ) ;
2006-03-20 17:12:09 +00:00
//==================== CLOSE THE FILE =============================
return 0 ;
}
# define COMPILED_MINE_VERSION 0
2016-01-09 16:38:14 +00:00
static void dump_fix_as_short ( fix value , int nbits , PHYSFS_File * SaveFile )
2006-03-20 17:12:09 +00:00
{
short short_value ;
2016-07-15 03:43:03 +00:00
auto int_value = value > > nbits ;
2017-02-22 03:05:43 +00:00
if ( int_value > INT16_MAX )
{
short_value = INT16_MAX ;
2006-03-20 17:12:09 +00:00
}
else if ( int_value < - 0x7fff ) {
short_value = - 0x7fff ;
}
else
2016-06-05 01:04:26 +00:00
short_value = static_cast < short > ( int_value ) ;
2006-03-20 17:12:09 +00:00
PHYSFS_writeSLE16 ( SaveFile , short_value ) ;
}
//version of dump for unsigned values
2016-01-09 16:38:14 +00:00
static void dump_fix_as_ushort ( fix value , int nbits , PHYSFS_File * SaveFile )
2006-03-20 17:12:09 +00:00
{
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 ) ;
}
2022-02-19 14:52:17 +00:00
static void write_children ( const shared_segment & seg , const sidemask_t bit_mask , PHYSFS_File * const SaveFile )
2006-03-20 17:12:09 +00:00
{
2022-01-09 15:25:42 +00:00
for ( const auto & & [ bit , child ] : enumerate ( seg . children ) )
2006-03-20 17:12:09 +00:00
{
2022-02-19 14:52:17 +00:00
if ( bit_mask & build_sidemask ( bit ) )
2022-01-09 15:25:42 +00:00
PHYSFS_writeSLE16 ( SaveFile , child ) ;
2006-03-20 17:12:09 +00:00
}
}
2018-09-19 02:13:29 +00:00
static void write_verts ( const shared_segment & seg , PHYSFS_File * const SaveFile )
2006-03-20 17:12:09 +00:00
{
2018-09-19 02:13:29 +00:00
range_for ( auto & i , seg . verts )
2020-12-26 21:17:29 +00:00
PHYSFS_writeSLE16 ( SaveFile , static_cast < uint16_t > ( i ) ) ;
2006-03-20 17:12:09 +00:00
}
2022-02-19 14:52:17 +00:00
static void write_special ( const shared_segment & seg , const sidemask_t bit_mask , PHYSFS_File * const SaveFile )
2006-03-20 17:12:09 +00:00
{
2022-02-19 14:52:17 +00:00
if ( bit_mask & build_sidemask ( MAX_SIDES_PER_SEGMENT ) )
2006-03-20 17:12:09 +00:00
{
2021-11-01 03:37:19 +00:00
PHYSFSX_writeU8 ( SaveFile , underlying_value ( seg . special ) ) ;
2021-11-01 03:37:20 +00:00
PHYSFSX_writeU8 ( SaveFile , underlying_value ( seg . matcen_num ) ) ;
2021-11-01 03:37:20 +00:00
PHYSFS_writeULE16 ( SaveFile , underlying_value ( seg . station_idx ) ) ;
2006-03-20 17:12:09 +00:00
}
}
2020-10-12 03:28:25 +00:00
}
int med_save_mine ( const mine_filename_type & filename )
{
return med_save_mine ( filename . data ( ) ) ;
}
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------
// saves compiled mine data to an already-open file...
2016-08-25 04:05:32 +00:00
namespace dsx {
2016-01-09 16:38:14 +00:00
int save_mine_data_compiled ( PHYSFS_File * SaveFile )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2006-03-20 17:12:09 +00:00
ubyte version = COMPILED_MINE_VERSION ;
med_compress_mine ( ) ;
warn_if_concave_segments ( ) ;
if ( Highest_segment_index > = MAX_SEGMENTS ) {
char message [ 128 ] ;
2016-01-09 16:38:17 +00:00
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 ) ) ;
2012-04-17 08:11:42 +00:00
ui_messagebox ( - 2 , - 2 , 1 , message , " Ok " ) ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:57 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2018-12-30 00:43:57 +00:00
if ( Vertices . get_count ( ) > MAX_VERTICES )
{
2006-03-20 17:12:09 +00:00
char message [ 128 ] ;
2018-12-30 00:43:57 +00:00
snprintf ( message , sizeof ( message ) , " Error: Too many vertices (%i > % " PRIuFAST32 " ) for game (not editor) " , Vertices . get_count ( ) , static_cast < uint_fast32_t > ( MAX_VERTICES ) ) ;
2012-04-17 08:11:42 +00:00
ui_messagebox ( - 2 , - 2 , 1 , message , " Ok " ) ;
2006-03-20 17:12:09 +00:00
}
//=============================== Writing part ==============================
PHYSFSX_writeU8 ( SaveFile , version ) ; // 1 byte = compiled version
if ( New_file_format_save )
{
2018-12-30 00:43:57 +00:00
PHYSFS_writeSLE16 ( SaveFile , LevelSharedVertexState . Num_vertices ) ; // 2 bytes = Num_vertices
2018-09-19 02:13:29 +00:00
PHYSFS_writeSLE16 ( SaveFile , LevelSharedSegmentState . Num_segments ) ; // 2 bytes = Num_segments
2006-03-20 17:12:09 +00:00
}
else
{
2018-12-30 00:43:57 +00:00
PHYSFS_writeSLE32 ( SaveFile , LevelSharedVertexState . Num_vertices ) ; // 4 bytes = Num_vertices
2018-09-19 02:13:29 +00:00
PHYSFS_writeSLE32 ( SaveFile , LevelSharedSegmentState . Num_segments ) ; // 4 bytes = Num_segments
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:57 +00:00
range_for ( auto & i , partial_const_range ( Vertices , LevelSharedVertexState . Num_vertices ) )
2016-12-11 01:56:44 +00:00
PHYSFSX_writeVector ( SaveFile , i ) ;
2006-03-20 17:12:09 +00:00
2018-09-19 02:13:29 +00:00
const auto Num_segments = LevelSharedSegmentState . Num_segments ;
2022-07-02 18:10:45 +00:00
auto & & segment_range = partial_const_range ( Segments , Num_segments ) ;
for ( const cscusegment seg : segment_range )
2006-03-20 17:12:09 +00:00
{
2022-02-19 14:52:17 +00:00
{
sidemask_t bit_mask { } ;
2022-01-09 15:25:42 +00:00
for ( const auto & & [ sidenum , child ] : enumerate ( seg . s . children ) )
2006-03-20 17:12:09 +00:00
{
2022-01-09 15:25:42 +00:00
if ( child ! = segment_none )
2022-02-19 14:52:17 +00:00
bit_mask | = build_sidemask ( sidenum ) ;
2006-03-20 17:12:09 +00:00
}
2021-11-01 03:37:20 +00:00
if ( seg . s . special ! = segment_special : : nothing | | seg . s . matcen_num ! = materialization_center_number : : None | | seg . s . station_idx ! = station_number : : None )
2022-02-19 14:52:17 +00:00
bit_mask | = build_sidemask ( MAX_SIDES_PER_SEGMENT ) ;
2006-03-20 17:12:09 +00:00
if ( New_file_format_save )
2022-02-19 14:52:17 +00:00
PHYSFSX_writeU8 ( SaveFile , underlying_value ( bit_mask ) ) ;
2006-03-20 17:12:09 +00:00
else
2022-02-19 14:52:17 +00:00
bit_mask = sidemask_t { 0x7f } ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version = = 5 ) // d2 SHAREWARE level
{
2013-03-03 01:03:33 +00:00
write_special ( seg , bit_mask , SaveFile ) ;
2006-03-20 17:12:09 +00:00
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
2013-03-03 01:03:33 +00:00
write_special ( seg , bit_mask , SaveFile ) ;
2006-03-20 17:12:09 +00:00
}
if ( Gamesave_current_version < = 5 ) // descent 1 thru d2 SHAREWARE level
2020-08-10 03:45:13 +00:00
dump_fix_as_ushort ( seg . u . static_light , 4 , SaveFile ) ;
2022-02-19 14:52:17 +00:00
}
2006-03-20 17:12:09 +00:00
// Write the walls as a 6 byte array
2022-02-19 14:52:17 +00:00
{
sidemask_t bit_mask { } ;
2022-01-09 15:25:42 +00:00
for ( const auto & & [ sidenum , side ] : enumerate ( seg . s . sides ) )
2006-03-20 17:12:09 +00:00
{
2022-01-09 15:25:42 +00:00
if ( side . wall_num ! = wall_none )
2022-02-19 14:52:17 +00:00
bit_mask | = build_sidemask ( sidenum ) ;
2006-03-20 17:12:09 +00:00
}
if ( New_file_format_save )
2022-02-19 14:52:17 +00:00
PHYSFSX_writeU8 ( SaveFile , underlying_value ( bit_mask ) ) ;
2006-03-20 17:12:09 +00:00
else
2022-02-19 14:52:17 +00:00
bit_mask = sidemask_t { 0x3f } ;
2006-03-20 17:12:09 +00:00
2022-01-09 15:25:42 +00:00
for ( const auto & & [ sidenum , side ] : enumerate ( seg . s . sides ) )
2006-03-20 17:12:09 +00:00
{
2022-02-19 14:52:17 +00:00
if ( bit_mask & build_sidemask ( sidenum ) )
2022-01-09 15:25:42 +00:00
PHYSFSX_writeU8 ( SaveFile , underlying_value ( side . wall_num ) ) ;
2006-03-20 17:12:09 +00:00
}
2022-02-19 14:52:17 +00:00
}
2006-03-20 17:12:09 +00:00
2022-01-09 15:25:42 +00:00
for ( const auto sidenum : MAX_SIDES_PER_SEGMENT )
2006-03-20 17:12:09 +00:00
{
2020-08-10 03:45:13 +00:00
if ( seg . s . children [ sidenum ] = = segment_none | | seg . s . sides [ sidenum ] . wall_num ! = wall_none )
2006-03-20 17:12:09 +00:00
{
2020-08-24 01:31:28 +00:00
auto tmap_num = seg . u . sides [ sidenum ] . tmap_num ;
auto tmap_num2 = seg . u . sides [ sidenum ] . tmap_num2 ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version < = 3 ) // convert texture numbers back to d1
{
2020-09-11 03:08:02 +00:00
tmap_num = build_texture1_value ( convert_to_d1_tmap_num ( get_texture_index ( tmap_num ) ) ) ;
2020-08-24 01:31:28 +00:00
if ( tmap_num2 ! = texture2_value : : None )
2020-08-24 01:31:28 +00:00
{
2020-08-24 01:31:28 +00:00
tmap_num2 = build_texture2_value ( convert_to_d1_tmap_num ( get_texture_index ( tmap_num2 ) ) , get_texture_rotation_high ( tmap_num2 ) ) ;
2020-08-24 01:31:28 +00:00
}
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2020-09-11 03:08:02 +00:00
uint16_t write_tmap_num = static_cast < uint16_t > ( tmap_num ) ;
2020-08-24 01:31:28 +00:00
if ( tmap_num2 ! = texture2_value : : None & & New_file_format_save )
2020-09-11 03:08:02 +00:00
write_tmap_num | = 0x8000 ;
2006-03-20 17:12:09 +00:00
2020-09-11 03:08:02 +00:00
PHYSFS_writeSLE16 ( SaveFile , write_tmap_num ) ;
2020-08-24 01:31:28 +00:00
if ( tmap_num2 ! = texture2_value : : None | | ! New_file_format_save )
PHYSFS_writeSLE16 ( SaveFile , static_cast < uint16_t > ( tmap_num2 ) ) ;
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
range_for ( auto & i , seg . u . sides [ sidenum ] . uvls )
2006-03-20 17:12:09 +00:00
{
2016-12-11 01:56:44 +00:00
dump_fix_as_short ( i . u , 5 , SaveFile ) ;
dump_fix_as_short ( i . v , 5 , SaveFile ) ;
dump_fix_as_ushort ( i . l , 1 , SaveFile ) ;
2006-03-20 17:12:09 +00:00
}
}
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > 5 )
2022-07-02 18:10:45 +00:00
for ( auto & s : segment_range )
segment2_write ( s , SaveFile ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
return 0 ;
}
2016-08-25 04:05:32 +00:00
}
2006-03-20 17:12:09 +00:00