dxx-rebirth/similar/main/dumpmine.cpp

1190 lines
37 KiB
C++
Raw Normal View History

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-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
*/
/*
*
* Functions to dump text description of mine.
* An editor-only function, called at mine load time.
* To be read by a human to verify the correctness and completeness of a mine.
*
*/
#include <bitset>
2006-03-20 17:12:09 +00:00
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include "pstypes.h"
#include "console.h"
2014-07-20 01:09:55 +00:00
#include "physfsx.h"
2006-03-20 17:12:09 +00:00
#include "key.h"
#include "gr.h"
#include "palette.h"
#include "fmtcheck.h"
2006-03-20 17:12:09 +00:00
#include "inferno.h"
#if DXX_USE_EDITOR
2006-03-20 17:12:09 +00:00
#include "editor/editor.h"
#endif
#include "dxxerror.h"
2006-03-20 17:12:09 +00:00
#include "object.h"
#include "wall.h"
#include "gamemine.h"
2013-12-26 04:18:28 +00:00
#include "gameseg.h"
2006-03-20 17:12:09 +00:00
#include "robot.h"
#include "player.h"
#include "newmenu.h"
#include "textures.h"
#include "bm.h"
#include "menu.h"
#include "switch.h"
#include "fuelcen.h"
#include "powerup.h"
#include "gameseq.h"
#include "polyobj.h"
#include "gamesave.h"
2012-11-11 00:14:30 +00:00
#include "piggy.h"
2006-03-20 17:12:09 +00:00
#include "compiler-range_for.h"
#include "partial_range.h"
#include "segiter.h"
#if DXX_USE_EDITOR
2016-05-22 17:49:30 +00:00
namespace dsx {
namespace {
#if defined(DXX_BUILD_DESCENT_I)
using perm_tmap_buffer_type = array<int, MAX_TEXTURES>;
using level_tmap_buffer_type = array<int8_t, MAX_TEXTURES>;
using wall_buffer_type = array<int, MAX_WALL_ANIMS>;
#elif defined(DXX_BUILD_DESCENT_II)
using perm_tmap_buffer_type = array<int, MAX_BITMAP_FILES>;
using level_tmap_buffer_type = array<int8_t, MAX_BITMAP_FILES>;
using wall_buffer_type = array<int, MAX_BITMAP_FILES>;
#endif
}
}
namespace dcx {
2015-04-02 02:36:56 +00:00
const array<char[10], 7> Wall_names{{
"NORMAL ",
"BLASTABLE",
"DOOR ",
"ILLUSION ",
"OPEN ",
"CLOSED ",
"EXTERNAL "
}};
2016-05-22 17:49:30 +00:00
}
2015-04-02 02:36:56 +00:00
static void dump_used_textures_level(PHYSFS_File *my_file, int level_num);
static void say_totals(fvcobjptridx &vcobjptridx, PHYSFS_File *my_file, const char *level_name);
2006-03-20 17:12:09 +00:00
2016-05-22 17:49:30 +00:00
namespace dsx {
2015-03-22 18:49:21 +00:00
const array<char[9], MAX_OBJECT_TYPES> Object_type_names{{
"WALL ",
"FIREBALL",
"ROBOT ",
"HOSTAGE ",
"PLAYER ",
"WEAPON ",
"CAMERA ",
"POWERUP ",
"DEBRIS ",
"CNTRLCEN",
"FLARE ",
"CLUTTER ",
"GHOST ",
"LIGHT ",
"COOP ",
#if defined(DXX_BUILD_DESCENT_II)
"MARKER ",
#endif
}};
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
2016-05-22 17:49:30 +00:00
static const char *object_types(const object_base &objp)
2006-03-20 17:12:09 +00:00
{
2016-05-22 17:49:30 +00:00
const auto type = objp.type;
2015-05-28 03:08:39 +00:00
assert(type == OBJ_NONE || type < MAX_OBJECT_TYPES);
return &Object_type_names[type][0];
2006-03-20 17:12:09 +00:00
}
2016-05-22 17:49:30 +00:00
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
static const char *object_ids(const object_base &objp)
2006-03-20 17:12:09 +00:00
{
switch (objp.type)
2015-05-28 03:08:39 +00:00
{
2006-03-20 17:12:09 +00:00
case OBJ_ROBOT:
2016-07-09 17:58:34 +00:00
return Robot_names[get_robot_id(objp)].data();
2006-03-20 17:12:09 +00:00
case OBJ_POWERUP:
2016-07-09 17:58:34 +00:00
return Powerup_names[get_powerup_id(objp)].data();
2016-11-20 23:12:00 +00:00
default:
return nullptr;
2006-03-20 17:12:09 +00:00
}
}
static void err_puts(PHYSFS_File *f, const char *str, size_t len) __attribute_nonnull();
static void err_puts(PHYSFS_File *f, const char *str, size_t len)
#define err_puts(A1,S,...) (err_puts(A1,S, _dxx_call_puts_parameter2(1, ## __VA_ARGS__, strlen(S))))
{
con_puts(CON_CRITICAL, str, len);
PHYSFSX_puts(f, str);
Errors_in_mine++;
}
template <size_t len>
static void err_puts_literal(PHYSFS_File *f, const char (&str)[len]) __attribute_nonnull();
template <size_t len>
static void err_puts_literal(PHYSFS_File *f, const char (&str)[len])
{
err_puts(f, str, len);
}
static void err_printf(PHYSFS_File *my_file, const char * format, ... ) __attribute_format_printf(2, 3);
static void err_printf(PHYSFS_File *my_file, const char * format, ... )
#define err_printf(A1,F,...) dxx_call_printf_checked(err_printf,err_puts_literal,(A1),(F),##__VA_ARGS__)
2006-03-20 17:12:09 +00:00
{
va_list args;
char message[256];
va_start(args, format );
size_t len = vsnprintf(message,sizeof(message),format,args);
2006-03-20 17:12:09 +00:00
va_end(args);
err_puts(my_file, message, len);
2006-03-20 17:12:09 +00:00
}
static void warning_puts(PHYSFS_File *f, const char *str, size_t len) __attribute_nonnull();
static void warning_puts(PHYSFS_File *f, const char *str, size_t len)
#define warning_puts(A1,S,...) (warning_puts(A1,S, _dxx_call_puts_parameter2(1, ## __VA_ARGS__, strlen(S))))
{
con_puts(CON_URGENT, str, len);
PHYSFSX_puts(f, str);
}
template <size_t len>
static void warning_puts_literal(PHYSFS_File *f, const char (&str)[len]) __attribute_nonnull();
template <size_t len>
static void warning_puts_literal(PHYSFS_File *f, const char (&str)[len])
{
warning_puts(f, str, len);
}
static void warning_printf(PHYSFS_File *my_file, const char * format, ... ) __attribute_format_printf(2, 3);
static void warning_printf(PHYSFS_File *my_file, const char * format, ... )
#define warning_printf(A1,F,...) dxx_call_printf_checked(warning_printf,warning_puts_literal,(A1),(F),##__VA_ARGS__)
2006-03-20 17:12:09 +00:00
{
va_list args;
char message[256];
va_start(args, format );
2012-06-30 05:05:33 +00:00
vsnprintf(message,sizeof(message),format,args);
2006-03-20 17:12:09 +00:00
va_end(args);
warning_puts(my_file, message);
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------
namespace dsx {
static void write_exit_text(fvcsegptridx &vcsegptridx, fvcwallptridx &vcwallptridx, PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
int j, count;
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Exit stuff\n");
2006-03-20 17:12:09 +00:00
// ---------- Find exit triggers ----------
count=0;
auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
auto &vctrgptridx = Triggers.vcptridx;
2017-07-08 18:17:48 +00:00
range_for (const auto &&t, vctrgptridx)
{
if (trigger_is_exit(t))
{
2006-03-20 17:12:09 +00:00
int count2;
2017-07-08 18:17:48 +00:00
const auto i = t.get_unchecked_index();
PHYSFSX_printf(my_file, "Trigger %2i, is an exit trigger with %i links.\n", i, t->num_links);
2006-03-20 17:12:09 +00:00
count++;
if (t->num_links != 0)
err_printf(my_file, "Error: Exit triggers must have 0 links, this one has %i links.", t->num_links);
2006-03-20 17:12:09 +00:00
// Find wall pointing to this trigger.
count2 = 0;
2016-02-12 04:02:28 +00:00
range_for (const auto &&w, vcwallptridx)
{
if (w->trigger == i)
{
2006-03-20 17:12:09 +00:00
count2++;
2016-02-12 04:02:28 +00:00
PHYSFSX_printf(my_file, "Exit trigger %i is in segment %i, on side %i, bound to wall %i\n", i, w->segnum, w->sidenum, static_cast<wallnum_t>(w));
2006-03-20 17:12:09 +00:00
}
2016-02-12 04:02:28 +00:00
}
2006-03-20 17:12:09 +00:00
if (count2 == 0)
err_printf(my_file, "Error: Trigger %i is not bound to any wall.", i);
2006-03-20 17:12:09 +00:00
else if (count2 > 1)
err_printf(my_file, "Error: Trigger %i is bound to %i walls.", i, count2);
2006-03-20 17:12:09 +00:00
}
}
2006-03-20 17:12:09 +00:00
if (count == 0)
err_printf(my_file, "Error: No exit trigger in this mine.");
2006-03-20 17:12:09 +00:00
else if (count != 1)
err_printf(my_file, "Error: More than one exit trigger in this mine.");
2006-03-20 17:12:09 +00:00
else
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
// ---------- Find exit doors ----------
count = 0;
2016-02-12 04:02:28 +00:00
range_for (const auto &&segp, vcsegptridx)
2015-06-13 22:42:16 +00:00
{
2006-03-20 17:12:09 +00:00
for (j=0; j<MAX_SIDES_PER_SEGMENT; j++)
2015-06-13 22:42:16 +00:00
if (segp->children[j] == segment_exit)
{
PHYSFSX_printf(my_file, "Segment %3hu, side %i is an exit door.\n", static_cast<uint16_t>(segp), j);
2006-03-20 17:12:09 +00:00
count++;
}
2015-06-13 22:42:16 +00:00
}
2006-03-20 17:12:09 +00:00
if (count == 0)
err_printf(my_file, "Error: No external wall in this mine.");
2006-03-20 17:12:09 +00:00
else if (count != 1) {
#if defined(DXX_BUILD_DESCENT_I)
warning_printf(my_file, "Warning: %i external walls in this mine.", count);
warning_printf(my_file, "(If %i are secret exits, then no problem.)", count-1);
#endif
2006-03-20 17:12:09 +00:00
} else
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
}
}
2006-03-20 17:12:09 +00:00
namespace {
2006-03-20 17:12:09 +00:00
class key_stat
{
const char *const label;
unsigned wall_count = 0, powerup_count = 0;
segnum_t seg = segment_none;
uint8_t side = 0;
public:
key_stat(const char *const p) :
label(p)
{
}
void check_wall(const segment_array &segments, PHYSFS_File *const fp, const vcwallptridx_t wpi, const wall_key_t key)
{
auto &w = *wpi;
if (!(w.keys & key))
return;
PHYSFSX_printf(fp, "Wall %i (seg=%i, side=%i) is keyed to the %s key.\n", static_cast<wallnum_t>(wpi), w.segnum, w.sidenum, label);
if (seg == segment_none)
{
seg = w.segnum;
side = w.sidenum;
2006-03-20 17:12:09 +00:00
}
else
{
const auto &&connect_side = find_connect_side(segments.vcptridx(w.segnum), segments.vcptr(seg));
if (connect_side == side)
return;
warning_printf(fp, "Warning: This door at seg %i, is different than the one at seg %i, side %i", w.segnum, seg, side);
2006-03-20 17:12:09 +00:00
}
++wall_count;
}
void report_walls(PHYSFS_File *const fp) const
{
if (wall_count > 1)
warning_printf(fp, "Warning: %i doors are keyed to the %s key.", wall_count, label);
}
void found_powerup(const unsigned amount = 1)
{
powerup_count += amount;
}
void report_keys(PHYSFS_File *const fp) const
{
if (!powerup_count)
{
if (wall_count)
err_printf(fp, "Error: There is a door keyed to the %s key, but no %s key!", label, label);
2006-03-20 17:12:09 +00:00
}
else if (powerup_count > 1)
err_printf(fp, "Error: There are %i %s keys!", powerup_count, label);
2006-03-20 17:12:09 +00:00
}
};
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
static void write_key_text(fvcobjptridx &vcobjptridx, segment_array &segments, fvcwallptridx &vcwallptridx, PHYSFS_File *my_file)
{
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Key stuff:\n");
2006-03-20 17:12:09 +00:00
key_stat blue("blue"), gold("gold"), red("red");
2006-03-20 17:12:09 +00:00
range_for (const auto &&w, vcwallptridx)
{
blue.check_wall(segments, my_file, w, KEY_BLUE);
gold.check_wall(segments, my_file, w, KEY_GOLD);
red.check_wall(segments, my_file, w, KEY_RED);
}
2006-03-20 17:12:09 +00:00
blue.report_walls(my_file);
gold.report_walls(my_file);
red.report_walls(my_file);
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
range_for (const auto &&objp, vcobjptridx)
2014-10-12 23:05:46 +00:00
{
2015-06-13 22:42:16 +00:00
if (objp->type == OBJ_POWERUP)
2016-09-04 19:10:42 +00:00
{
const char *color;
const auto id = get_powerup_id(objp);
if (
(id == POW_KEY_BLUE && (blue.found_powerup(), color = "BLUE", true)) ||
(id == POW_KEY_RED && (red.found_powerup(), color = "RED", true)) ||
(id == POW_KEY_GOLD && (gold.found_powerup(), color = "GOLD", true))
2016-09-04 19:10:42 +00:00
)
{
PHYSFSX_printf(my_file, "The %s key is object %hu in segment %i\n", color, static_cast<objnum_t>(objp), objp->segnum);
2006-03-20 17:12:09 +00:00
}
2016-09-04 19:10:42 +00:00
}
2006-03-20 17:12:09 +00:00
2016-09-04 19:10:42 +00:00
if (const auto contains_count = objp->contains_count)
2015-06-13 22:42:16 +00:00
{
if (objp->contains_type == OBJ_POWERUP)
{
2016-09-04 19:10:42 +00:00
const char *color;
const auto id = objp->contains_id;
if (
(id == POW_KEY_BLUE && (blue.found_powerup(contains_count), color = "BLUE", true)) ||
(id == POW_KEY_RED && (red.found_powerup(contains_count), color = "RED", true)) ||
(id == POW_KEY_GOLD && (gold.found_powerup(contains_count), color = "GOLD", true))
2016-09-04 19:10:42 +00:00
)
PHYSFSX_printf(my_file, "The %s key is contained in object %hu (a %s %s) in segment %hu\n", color, static_cast<objnum_t>(objp), object_types(objp), Robot_names[get_robot_id(objp)].data(), objp->segnum);
2006-03-20 17:12:09 +00:00
}
}
}
blue.report_keys(my_file);
gold.report_keys(my_file);
red.report_keys(my_file);
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------
static void write_control_center_text(fvcsegptridx &vcsegptridx, PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
2014-10-12 23:10:05 +00:00
int count, count2;
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Control Center stuff:\n");
2006-03-20 17:12:09 +00:00
count = 0;
2016-02-12 04:02:28 +00:00
range_for (const auto &&segp, vcsegptridx)
2015-06-13 22:42:16 +00:00
{
if (segp->special == SEGMENT_IS_CONTROLCEN)
{
2006-03-20 17:12:09 +00:00
count++;
PHYSFSX_printf(my_file, "Segment %3hu is a control center.\n", static_cast<uint16_t>(segp));
2006-03-20 17:12:09 +00:00
count2 = 0;
2017-08-13 20:38:31 +00:00
range_for (const auto objp, objects_in(segp, vcobjptridx, vcsegptr))
{
if (objp->type == OBJ_CNTRLCEN)
2006-03-20 17:12:09 +00:00
count2++;
}
if (count2 == 0)
PHYSFSX_printf(my_file, "No control center object in control center segment.\n");
2006-03-20 17:12:09 +00:00
else if (count2 != 1)
PHYSFSX_printf(my_file, "%i control center objects in control center segment.\n", count2);
2006-03-20 17:12:09 +00:00
}
2015-06-13 22:42:16 +00:00
}
2006-03-20 17:12:09 +00:00
if (count == 0)
err_printf(my_file, "Error: No control center in this mine.");
2006-03-20 17:12:09 +00:00
else if (count != 1)
err_printf(my_file, "Error: More than one control center in this mine.");
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------
static void write_fuelcen_text(PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
int i;
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Fuel Center stuff: (Note: This means fuel, repair, materialize, control centers!)\n");
2006-03-20 17:12:09 +00:00
for (i=0; i<Num_fuelcenters; i++) {
PHYSFSX_printf(my_file, "Fuelcenter %i: Type=%i (%s), segment = %3i\n", i, Station[i].Type, Special_names[Station[i].Type], Station[i].segnum);
2013-10-06 16:20:00 +00:00
if (Segments[Station[i].segnum].special != Station[i].Type)
err_printf(my_file, "Error: Conflicting data: Segment %i has special type %i (%s), expected to be %i", Station[i].segnum, Segments[Station[i].segnum].special, Special_names[Segments[Station[i].segnum].special], Station[i].Type);
2006-03-20 17:12:09 +00:00
}
}
// ----------------------------------------------------------------------------
static void write_segment_text(fvcsegptridx &vcsegptridx, PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Segment stuff:\n");
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
range_for (const auto &&segp, vcsegptridx)
2014-10-12 23:10:05 +00:00
{
PHYSFSX_printf(my_file, "Segment %4hu:", static_cast<uint16_t>(segp));
2015-06-13 22:42:16 +00:00
if (segp->special != 0)
PHYSFSX_printf(my_file, " special = %3i (%s), station_idx=%3i", segp->special, Special_names[segp->special], segp->station_idx);
2015-06-13 22:42:16 +00:00
if (segp->matcen_num != -1)
PHYSFSX_printf(my_file, " matcen = %3i", segp->matcen_num);
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
}
2016-02-12 04:02:28 +00:00
range_for (const auto &&segp, vcsegptridx)
2014-10-12 23:10:05 +00:00
{
2006-03-20 17:12:09 +00:00
int depth;
PHYSFSX_printf(my_file, "Segment %4hu: ", static_cast<uint16_t>(segp));
2006-03-20 17:12:09 +00:00
depth=0;
PHYSFSX_printf(my_file, "Objects: ");
2017-08-13 20:38:31 +00:00
range_for (const auto objp, objects_in(segp, vcobjptridx, vcsegptr))
{
short objnum = objp;
2015-05-28 03:08:39 +00:00
PHYSFSX_printf(my_file, "[%8s %8s %3i] ", object_types(objp), object_ids(objp), objnum);
2006-03-20 17:12:09 +00:00
if (depth++ > 30) {
PHYSFSX_printf(my_file, "\nAborted after %i links\n", depth);
2006-03-20 17:12:09 +00:00
break;
}
}
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
}
}
// ----------------------------------------------------------------------------
// This routine is bogus. It assumes that all centers are matcens,
// which is not true. The setting of segnum is bogus.
static void write_matcen_text(PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
int i;
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Materialization centers:\n");
auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
auto &vctrgptridx = Triggers.vcptridx;
2006-03-20 17:12:09 +00:00
for (i=0; i<Num_robot_centers; i++) {
int trigger_count=0, fuelcen_num;
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "FuelCenter[%02i].Segment = %04i ", i, Station[i].segnum);
2013-10-06 16:20:00 +00:00
PHYSFSX_printf(my_file, "Segment[%04i].matcen_num = %02i ", Station[i].segnum, Segments[Station[i].segnum].matcen_num);
2006-03-20 17:12:09 +00:00
fuelcen_num = RobotCenters[i].fuelcen_num;
if (Station[fuelcen_num].Type != SEGMENT_IS_ROBOTMAKER)
err_printf(my_file, "Error: Matcen %i corresponds to Station %i, which has type %i (%s).", i, fuelcen_num, Station[fuelcen_num].Type, Special_names[Station[fuelcen_num].Type]);
2006-03-20 17:12:09 +00:00
2014-11-20 03:00:36 +00:00
auto segnum = Station[fuelcen_num].segnum;
2006-03-20 17:12:09 +00:00
// Find trigger for this materialization center.
2017-07-08 18:17:48 +00:00
range_for (auto &&t, vctrgptridx)
{
if (trigger_is_matcen(t))
{
2016-02-12 04:02:28 +00:00
range_for (auto &k, partial_const_range(t->seg, t->num_links))
if (k == segnum)
{
2017-07-08 18:17:48 +00:00
PHYSFSX_printf(my_file, "Trigger = %2i ", t.get_unchecked_index());
2006-03-20 17:12:09 +00:00
trigger_count++;
}
}
}
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
if (trigger_count == 0)
err_printf(my_file, "Error: Matcen %i in segment %i has no trigger!", i, segnum);
2006-03-20 17:12:09 +00:00
}
}
// ----------------------------------------------------------------------------
namespace dsx {
static void write_wall_text(fvcsegptridx &vcsegptridx, fvcwallptridx &vcwallptridx, PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
int j;
array<int8_t, MAX_WALLS> wall_flags;
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Walls:\n");
#if defined(DXX_BUILD_DESCENT_II)
auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
#endif
range_for (auto &&wp, vcwallptridx)
{
auto &w = *wp;
int sidenum;
2006-03-20 17:12:09 +00:00
const auto i = static_cast<wallnum_t>(wp);
PHYSFSX_printf(my_file, "Wall %03i: seg=%3i, side=%2i, linked_wall=%3i, type=%s, flags=%4x, hps=%3i, trigger=%2i, clip_num=%2i, keys=%2i, state=%i\n", i,
w.segnum, w.sidenum, w.linked_wall, Wall_names[w.type], w.flags, w.hps >> 16, w.trigger, w.clip_num, w.keys, w.state);
2006-03-20 17:12:09 +00:00
#if defined(DXX_BUILD_DESCENT_II)
if (w.trigger >= Triggers.get_count())
PHYSFSX_printf(my_file, "Wall %03d points to invalid trigger %d\n",i,w.trigger);
#endif
2006-03-20 17:12:09 +00:00
auto segnum = w.segnum;
sidenum = w.sidenum;
2006-03-20 17:12:09 +00:00
2018-12-13 02:31:38 +00:00
if (Segments[segnum].shared_segment::sides[sidenum].wall_num != wp)
err_printf(my_file, "Error: Wall %u points at segment %i, side %i, but that segment doesn't point back (it's wall_num = %hi)", i, segnum, sidenum, static_cast<int16_t>(Segments[segnum].shared_segment::sides[sidenum].wall_num));
2006-03-20 17:12:09 +00:00
}
wall_flags = {};
2006-03-20 17:12:09 +00:00
range_for (const auto &&segp, vcsegptridx)
2014-10-12 23:10:05 +00:00
{
2006-03-20 17:12:09 +00:00
for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
2018-12-13 02:31:38 +00:00
const auto sidep = &segp->shared_segment::sides[j];
2014-10-04 15:04:44 +00:00
if (sidep->wall_num != wall_none)
2006-03-20 17:12:09 +00:00
{
if (wall_flags[sidep->wall_num])
err_printf(my_file, "Error: Wall %hu appears in two or more segments, including segment %hu, side %i.", static_cast<int16_t>(sidep->wall_num), static_cast<segnum_t>(segp), j);
2006-03-20 17:12:09 +00:00
else
wall_flags[sidep->wall_num] = 1;
}
}
}
}
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
namespace dsx {
static void write_player_text(fvcobjptridx &vcobjptridx, PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
2014-10-12 23:05:46 +00:00
int num_players=0;
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Players:\n");
2016-02-12 04:02:28 +00:00
range_for (const auto &&objp, vcobjptridx)
2014-10-12 23:05:46 +00:00
{
2015-06-13 22:42:16 +00:00
if (objp->type == OBJ_PLAYER)
{
2006-03-20 17:12:09 +00:00
num_players++;
PHYSFSX_printf(my_file, "Player %2i is object #%3hu in segment #%3i.\n", get_player_id(objp), static_cast<uint16_t>(objp), objp->segnum);
2006-03-20 17:12:09 +00:00
}
}
#if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if (num_players != MAX_PLAYERS)
err_printf(my_file, "Error: %i player objects. %i are required.", num_players, MAX_PLAYERS);
#endif
2006-03-20 17:12:09 +00:00
if (num_players > MAX_MULTI_PLAYERS)
err_printf(my_file, "Error: %i player objects. %i are required.", num_players, MAX_PLAYERS);
2006-03-20 17:12:09 +00:00
}
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
namespace dsx {
static void write_trigger_text(PHYSFS_File *my_file)
2006-03-20 17:12:09 +00:00
{
PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n");
PHYSFSX_printf(my_file, "Triggers:\n");
auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
auto &vctrgptridx = Triggers.vcptridx;
auto &Walls = LevelUniqueWallSubsystemState.Walls;
auto &vcwallptr = Walls.vcptr;
range_for (auto &&t, vctrgptridx)
{
const auto i = static_cast<trgnum_t>(t);
#if defined(DXX_BUILD_DESCENT_I)
2018-12-30 00:43:58 +00:00
PHYSFSX_printf(my_file, "Trigger %03i: flags=%04x, value=%08x, time=%8x, num_links=%i ", i, t->flags, static_cast<unsigned>(t->value), 0, t->num_links);
#elif defined(DXX_BUILD_DESCENT_II)
PHYSFSX_printf(my_file, "Trigger %03i: type=%02x flags=%04x, value=%08x, time=%8x, num_links=%i ", i,
2016-02-06 22:12:55 +00:00
t->type, t->flags, t->value, 0, t->num_links);
#endif
2006-03-20 17:12:09 +00:00
for (unsigned j = 0; j < t->num_links; ++j)
PHYSFSX_printf(my_file, "[%03i:%i] ", t->seg[j], t->side[j]);
2006-03-20 17:12:09 +00:00
// Find which wall this trigger is connected to.
const auto &&we = vcwallptr.end();
const auto &&wi = std::find_if(vcwallptr.begin(), we, [i](const wall *const p) { return p->trigger == i; });
if (wi == we)
err_printf(my_file, "Error: Trigger %i is not connected to any wall, so it can never be triggered.", i);
2006-03-20 17:12:09 +00:00
else
{
const auto &&w = *wi;
2018-12-13 02:31:38 +00:00
PHYSFSX_printf(my_file, "Attached to seg:side = %i:%i, wall %hi\n", w->segnum, w->sidenum, static_cast<int16_t>(vcsegptr(w->segnum)->shared_segment::sides[w->sidenum].wall_num));
}
2006-03-20 17:12:09 +00:00
}
}
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
void write_game_text_file(const char *filename)
2006-03-20 17:12:09 +00:00
{
char my_filename[128];
int namelen;
Errors_in_mine = 0;
namelen = strlen(filename);
Assert (namelen > 4);
Assert (filename[namelen-4] == '.');
strcpy(my_filename, filename);
strcpy( &my_filename[namelen-4], ".txm");
auto my_file = PHYSFSX_openWriteBuffered(my_filename);
2006-03-20 17:12:09 +00:00
if (!my_file) {
gr_palette_load(gr_palette);
nm_messagebox( NULL, 1, "Ok", "ERROR: Unable to open %s\nErrno = %i", my_filename, errno);
2006-03-20 17:12:09 +00:00
return;
}
dump_used_textures_level(my_file, 0);
say_totals(vcobjptridx, my_file, Gamesave_current_filename);
2006-03-20 17:12:09 +00:00
PHYSFSX_printf(my_file, "\nNumber of segments: %4i\n", Highest_segment_index+1);
PHYSFSX_printf(my_file, "Number of objects: %4i\n", Highest_object_index+1);
auto &Walls = LevelUniqueWallSubsystemState.Walls;
auto &vcwallptridx = Walls.vcptridx;
PHYSFSX_printf(my_file, "Number of walls: %4i\n", Walls.get_count());
auto &ActiveDoors = LevelUniqueWallSubsystemState.ActiveDoors;
2016-12-10 17:51:08 +00:00
PHYSFSX_printf(my_file, "Number of open doors: %4i\n", ActiveDoors.get_count());
{
auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
PHYSFSX_printf(my_file, "Number of triggers: %4i\n", Triggers.get_count());
}
PHYSFSX_printf(my_file, "Number of matcens: %4i\n", Num_robot_centers);
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
write_segment_text(vcsegptridx, my_file);
2006-03-20 17:12:09 +00:00
write_fuelcen_text(my_file);
write_matcen_text(my_file);
write_player_text(vcobjptridx, my_file);
2006-03-20 17:12:09 +00:00
write_wall_text(vcsegptridx, vcwallptridx, my_file);
2006-03-20 17:12:09 +00:00
write_trigger_text(my_file);
write_exit_text(vcsegptridx, vcwallptridx, my_file);
2006-03-20 17:12:09 +00:00
// ---------- Find control center segment ----------
write_control_center_text(vcsegptridx, my_file);
2006-03-20 17:12:09 +00:00
// ---------- Show keyed walls ----------
write_key_text(vcobjptridx, Segments, vcwallptridx, my_file);
2006-03-20 17:12:09 +00:00
}
#if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
// Adam: Change NUM_ADAM_LEVELS to the number of levels.
#define NUM_ADAM_LEVELS 30
// Adam: Stick the names here.
constexpr char Adam_level_names[NUM_ADAM_LEVELS][13] = {
2006-03-20 17:12:09 +00:00
"D2LEVA-1.LVL",
"D2LEVA-2.LVL",
"D2LEVA-3.LVL",
"D2LEVA-4.LVL",
"D2LEVA-S.LVL",
"D2LEVB-1.LVL",
"D2LEVB-2.LVL",
"D2LEVB-3.LVL",
"D2LEVB-4.LVL",
"D2LEVB-S.LVL",
"D2LEVC-1.LVL",
"D2LEVC-2.LVL",
"D2LEVC-3.LVL",
"D2LEVC-4.LVL",
"D2LEVC-S.LVL",
"D2LEVD-1.LVL",
"D2LEVD-2.LVL",
"D2LEVD-3.LVL",
"D2LEVD-4.LVL",
"D2LEVD-S.LVL",
"D2LEVE-1.LVL",
"D2LEVE-2.LVL",
"D2LEVE-3.LVL",
"D2LEVE-4.LVL",
"D2LEVE-S.LVL",
"D2LEVF-1.LVL",
"D2LEVF-2.LVL",
"D2LEVF-3.LVL",
"D2LEVF-4.LVL",
"D2LEVF-S.LVL",
};
static int Ignore_tmap_num2_error;
#endif
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
namespace dsx {
2018-12-30 00:43:57 +00:00
#if defined(DXX_BUILD_DESCENT_I)
#define determine_used_textures_level(LevelSharedDestructibleLightState,load_level_flag,shareware_flag,level_num,tmap_buf,wall_buffer_type,level_tmap_buf,max_tmap) determine_used_textures_level(load_level_flag,shareware_flag,level_num,tmap_buf,wall_buffer_type,level_tmap_buf,max_tmap)
2018-12-30 00:43:57 +00:00
#endif
static void determine_used_textures_level(d_level_shared_destructible_light_state &LevelSharedDestructibleLightState, int load_level_flag, int shareware_flag, int level_num, perm_tmap_buffer_type &tmap_buf, wall_buffer_type &wall_buf, level_tmap_buffer_type &level_tmap_buf, int max_tmap)
2006-03-20 17:12:09 +00:00
{
int sidenum;
2016-05-22 17:49:30 +00:00
int j;
2006-03-20 17:12:09 +00:00
auto &Walls = LevelUniqueWallSubsystemState.Walls;
#if defined(DXX_BUILD_DESCENT_I)
2016-05-22 17:49:30 +00:00
tmap_buf = {};
if (load_level_flag) {
load_level(shareware_flag ? Shareware_level_names[level_num] : Registered_level_names[level_num]);
}
2016-02-12 04:02:28 +00:00
range_for (const auto &&segp, vcsegptr)
{
for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
{
2018-12-13 02:31:38 +00:00
auto &sside = segp->shared_segment::sides[sidenum];
if (sside.wall_num != wall_none)
{
const auto clip_num = Walls.vcptr(sside.wall_num)->clip_num;
if (clip_num != -1) {
2017-06-17 23:05:16 +00:00
const auto num_frames = WallAnims[clip_num].num_frames;
wall_buf[clip_num] = 1;
for (j=0; j<num_frames; j++) {
int tmap_num;
tmap_num = WallAnims[clip_num].frames[j];
tmap_buf[tmap_num]++;
if (level_tmap_buf[tmap_num] == -1)
level_tmap_buf[tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
}
}
}
2018-12-13 02:31:38 +00:00
auto &uside = segp->unique_segment::sides[sidenum];
if (uside.tmap_num >= 0)
{
2018-12-13 02:31:38 +00:00
if (uside.tmap_num < max_tmap)
{
2018-12-13 02:31:38 +00:00
tmap_buf[uside.tmap_num]++;
if (level_tmap_buf[uside.tmap_num] == -1)
level_tmap_buf[uside.tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
}
else
{
Int3(); // Error, bogus texture map. Should not be greater than max_tmap.
}
}
2018-12-13 02:31:38 +00:00
if (const auto tmap_num2 = uside.tmap_num2 & 0x3fff)
{
2018-12-13 02:31:38 +00:00
if (tmap_num2 < max_tmap) {
++tmap_buf[tmap_num2];
if (level_tmap_buf[tmap_num2] == -1)
level_tmap_buf[tmap_num2] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
} else
Int3(); // Error, bogus texture map. Should not be greater than max_tmap.
}
}
}
#elif defined(DXX_BUILD_DESCENT_II)
2015-01-18 01:58:33 +00:00
(void)max_tmap;
(void)shareware_flag;
2006-03-20 17:12:09 +00:00
2016-05-22 17:49:30 +00:00
tmap_buf = {};
2006-03-20 17:12:09 +00:00
if (load_level_flag) {
load_level(LevelSharedDestructibleLightState, Adam_level_names[level_num]);
2006-03-20 17:12:09 +00:00
}
auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
2006-03-20 17:12:09 +00:00
// Process robots.
2016-02-12 04:02:28 +00:00
range_for (const auto &&objp, vcobjptr)
2014-10-12 23:05:46 +00:00
{
2006-03-20 17:12:09 +00:00
if (objp->render_type == RT_POLYOBJ) {
polymodel *po = &Polygon_models[objp->rtype.pobj_info.model_num];
2016-05-22 17:49:30 +00:00
for (unsigned i = 0; i < po->n_textures; ++i)
{
2016-07-14 01:59:05 +00:00
unsigned tli = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index;
2006-03-20 17:12:09 +00:00
2016-07-14 01:59:05 +00:00
if (tli < tmap_buf.size())
{
2006-03-20 17:12:09 +00:00
tmap_buf[tli]++;
if (level_tmap_buf[tli] == -1)
level_tmap_buf[tli] = level_num;
} else
Int3(); // Hmm, It seems this texture is bogus!
}
}
}
Ignore_tmap_num2_error = 0;
// Process walls and segment sides.
range_for (const auto &&segp, vmsegptr)
2014-10-12 23:10:05 +00:00
{
2006-03-20 17:12:09 +00:00
for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
2018-12-13 02:31:38 +00:00
auto &sside = segp->shared_segment::sides[sidenum];
auto &uside = segp->unique_segment::sides[sidenum];
if (sside.wall_num != wall_none) {
const auto clip_num = Walls.vcptr(sside.wall_num)->clip_num;
2006-03-20 17:12:09 +00:00
if (clip_num != -1) {
// -- int num_frames = WallAnims[clip_num].num_frames;
wall_buf[clip_num] = 1;
for (j=0; j<1; j++) { // Used to do through num_frames, but don't really want all the door01#3 stuff.
2016-07-14 01:59:05 +00:00
unsigned tmap_num = Textures[WallAnims[clip_num].frames[j]].index;
Assert(tmap_num < tmap_buf.size());
2006-03-20 17:12:09 +00:00
tmap_buf[tmap_num]++;
if (level_tmap_buf[tmap_num] == -1)
level_tmap_buf[tmap_num] = level_num;
}
}
} else if (segp->children[sidenum] == segment_none) {
2006-03-20 17:12:09 +00:00
2018-12-13 02:31:38 +00:00
if (uside.tmap_num >= 0)
2006-03-20 17:12:09 +00:00
{
2018-12-13 02:31:38 +00:00
if (uside.tmap_num < Textures.size()) {
const auto ti = Textures[uside.tmap_num].index;
2016-07-14 01:59:05 +00:00
assert(ti < tmap_buf.size());
++tmap_buf[ti];
if (level_tmap_buf[ti] == -1)
level_tmap_buf[ti] = level_num;
2006-03-20 17:12:09 +00:00
} else
Int3(); // Error, bogus texture map. Should not be greater than max_tmap.
}
2018-12-13 02:31:38 +00:00
if (const auto masked_tmap_num2 = (uside.tmap_num2 & 0x3fff))
2006-03-20 17:12:09 +00:00
{
2016-07-14 01:59:05 +00:00
if (masked_tmap_num2 < Textures.size())
{
const auto ti = Textures[masked_tmap_num2].index;
assert(ti < tmap_buf.size());
++tmap_buf[ti];
if (level_tmap_buf[ti] == -1)
level_tmap_buf[ti] = level_num;
2006-03-20 17:12:09 +00:00
} else {
if (!Ignore_tmap_num2_error)
Int3(); // Error, bogus texture map. Should not be greater than max_tmap.
Ignore_tmap_num2_error = 1;
2018-12-13 02:31:38 +00:00
uside.tmap_num2 = 0;
2006-03-20 17:12:09 +00:00
}
}
}
}
}
#endif
2006-03-20 17:12:09 +00:00
}
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
2016-05-22 17:49:30 +00:00
template <std::size_t N>
static void merge_buffers(array<int, N> &dest, const array<int, N> &src)
2006-03-20 17:12:09 +00:00
{
2016-05-22 17:49:30 +00:00
std::transform(dest.begin(), dest.end(), src.begin(), dest.begin(), std::plus<int>());
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------
namespace dsx {
2016-05-22 17:49:30 +00:00
static void say_used_tmaps(PHYSFS_File *const my_file, const perm_tmap_buffer_type &tb)
2006-03-20 17:12:09 +00:00
{
int i;
#if defined(DXX_BUILD_DESCENT_I)
int count = 0;
2006-03-20 17:12:09 +00:00
auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
for (i=0; i<Num_tmaps; i++)
if (tb[i]) {
2014-07-26 22:45:01 +00:00
PHYSFSX_printf(my_file, "[%3i %8s (%4i)] ", i, static_cast<const char *>(TmapInfo[i].filename), tb[i]);
if (count++ >= 4) {
PHYSFSX_printf(my_file, "\n");
count = 0;
}
}
#elif defined(DXX_BUILD_DESCENT_II)
2016-07-14 01:59:05 +00:00
for (i = 0; i < tb.size(); ++i)
2006-03-20 17:12:09 +00:00
if (tb[i]) {
2018-08-26 18:10:36 +00:00
PHYSFSX_printf(my_file, "[%3i %8s (%4i)]\n", i, AllBitmaps[i].name.data(), tb[i]);
2006-03-20 17:12:09 +00:00
}
#endif
2006-03-20 17:12:09 +00:00
}
}
2006-03-20 17:12:09 +00:00
#if defined(DXX_BUILD_DESCENT_I)
// -----------------------------------------------------------------------------
2016-05-22 17:49:30 +00:00
static void say_used_once_tmaps(PHYSFS_File *const my_file, const perm_tmap_buffer_type &tb, const level_tmap_buffer_type &tb_lnum)
{
int i;
const char *level_name;
auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
for (i=0; i<Num_tmaps; i++)
if (tb[i] == 1) {
int level_num = tb_lnum[i];
if (level_num >= NUM_SHAREWARE_LEVELS) {
Assert((level_num - NUM_SHAREWARE_LEVELS >= 0) && (level_num - NUM_SHAREWARE_LEVELS < NUM_REGISTERED_LEVELS));
level_name = Registered_level_names[level_num - NUM_SHAREWARE_LEVELS];
} else {
Assert((level_num >= 0) && (level_num < NUM_SHAREWARE_LEVELS));
level_name = Shareware_level_names[level_num];
}
2014-07-26 22:45:01 +00:00
PHYSFSX_printf(my_file, "Texture %3i %8s used only once on level %s\n", i, static_cast<const char *>(TmapInfo[i].filename), level_name);
}
}
#endif
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
namespace dsx {
2016-05-22 17:49:30 +00:00
static void say_unused_tmaps(PHYSFS_File *my_file, perm_tmap_buffer_type &tb)
2006-03-20 17:12:09 +00:00
{
int i;
int count = 0;
#if defined(DXX_BUILD_DESCENT_I)
2014-05-03 22:08:51 +00:00
const unsigned bound = Num_tmaps;
auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
#elif defined(DXX_BUILD_DESCENT_II)
2014-05-03 22:08:51 +00:00
const unsigned bound = MAX_BITMAP_FILES;
#endif
2014-05-03 22:08:51 +00:00
for (i=0; i < bound; i++)
2006-03-20 17:12:09 +00:00
if (!tb[i]) {
2015-02-28 19:36:01 +00:00
if (GameBitmaps[Textures[i].index].bm_data == bogus_data.data())
PHYSFSX_printf(my_file, "U");
2006-03-20 17:12:09 +00:00
else
PHYSFSX_printf(my_file, " ");
2006-03-20 17:12:09 +00:00
#if defined(DXX_BUILD_DESCENT_I)
2014-07-26 22:45:01 +00:00
PHYSFSX_printf(my_file, "[%3i %8s] ", i, static_cast<const char *>(TmapInfo[i].filename));
#elif defined(DXX_BUILD_DESCENT_II)
2018-08-26 18:10:36 +00:00
PHYSFSX_printf(my_file, "[%3i %8s] ", i, AllBitmaps[i].name.data());
#endif
2006-03-20 17:12:09 +00:00
if (count++ >= 4) {
PHYSFSX_printf(my_file, "\n");
2006-03-20 17:12:09 +00:00
count = 0;
}
}
}
}
2006-03-20 17:12:09 +00:00
#if defined(DXX_BUILD_DESCENT_I)
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
2016-05-22 17:49:30 +00:00
static void say_unused_walls(PHYSFS_File *my_file, const wall_buffer_type &tb)
{
int i;
for (i=0; i<Num_wall_anims; i++)
if (!tb[i])
PHYSFSX_printf(my_file, "Wall %3i is unused.\n", i);
}
#endif
static void say_totals(fvcobjptridx &vcobjptridx, PHYSFS_File *my_file, const char *level_name)
2006-03-20 17:12:09 +00:00
{
int total_robots = 0;
int objects_processed = 0;
PHYSFSX_printf(my_file, "\nLevel %s\n", level_name);
std::bitset<MAX_OBJECTS> used_objects;
2006-03-20 17:12:09 +00:00
while (objects_processed < Highest_object_index+1) {
int objtype, objid, objcount, min_obj_val;
2006-03-20 17:12:09 +00:00
// Find new min objnum.
min_obj_val = 0x7fff0000;
const object_base *min_objp = nullptr;
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
range_for (const auto &&objp, vcobjptridx)
2014-10-12 23:05:46 +00:00
{
if (!used_objects[objp] && objp->type != OBJ_NONE)
2015-06-13 22:42:16 +00:00
{
const auto cur_obj_val = (objp->type << 10) + objp->id;
2006-03-20 17:12:09 +00:00
if (cur_obj_val < min_obj_val) {
min_objp = &*objp;
2006-03-20 17:12:09 +00:00
min_obj_val = cur_obj_val;
}
}
}
if (!min_objp || min_objp->type == OBJ_NONE)
2006-03-20 17:12:09 +00:00
break;
objcount = 0;
objtype = min_objp->type;
objid = min_objp->id;
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
range_for (const auto &&objp, vcobjptridx)
2014-10-12 23:05:46 +00:00
{
2017-09-30 18:00:15 +00:00
if (auto &&uo = used_objects[objp])
{
}
else
{
2015-06-13 22:42:16 +00:00
if ((objp->type == objtype && objp->id == objid) ||
(objp->type == objtype && objtype == OBJ_PLAYER) ||
(objp->type == objtype && objtype == OBJ_COOP) ||
(objp->type == objtype && objtype == OBJ_HOSTAGE)) {
if (objp->type == OBJ_ROBOT)
2006-03-20 17:12:09 +00:00
total_robots++;
2017-09-30 18:00:15 +00:00
uo = true;
2006-03-20 17:12:09 +00:00
objcount++;
objects_processed++;
}
}
}
if (objcount) {
PHYSFSX_printf(my_file, "Object: %8s %8s %3i\n", object_types(*min_objp), object_ids(*min_objp), objcount);
2006-03-20 17:12:09 +00:00
}
}
PHYSFSX_printf(my_file, "Total robots = %3i\n", total_robots);
2006-03-20 17:12:09 +00:00
}
#if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
int First_dump_level = 0;
int Last_dump_level = NUM_ADAM_LEVELS-1;
#endif
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
namespace dsx {
2013-10-27 22:00:14 +00:00
static void say_totals_all(void)
2006-03-20 17:12:09 +00:00
{
int i;
auto my_file = PHYSFSX_openWriteBuffered("levels.all");
2006-03-20 17:12:09 +00:00
if (!my_file) {
gr_palette_load(gr_palette);
nm_messagebox( NULL, 1, "Ok", "ERROR: Unable to open levels.all\nErrno=%i", errno );
2006-03-20 17:12:09 +00:00
return;
}
#if defined(DXX_BUILD_DESCENT_I)
for (i=0; i<NUM_SHAREWARE_LEVELS; i++) {
load_level(Shareware_level_names[i]);
say_totals(vcobjptridx, my_file, Shareware_level_names[i]);
}
for (i=0; i<NUM_REGISTERED_LEVELS; i++) {
load_level(Registered_level_names[i]);
say_totals(vcobjptridx, my_file, Registered_level_names[i]);
}
#elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
for (i=First_dump_level; i<=Last_dump_level; i++) {
load_level(LevelSharedSegmentState.DestructibleLights, Adam_level_names[i]);
say_totals(vcobjptridx, my_file, Adam_level_names[i]);
2006-03-20 17:12:09 +00:00
}
#endif
2006-03-20 17:12:09 +00:00
}
}
2006-03-20 17:12:09 +00:00
static void dump_used_textures_level(PHYSFS_File *my_file, int level_num)
2006-03-20 17:12:09 +00:00
{
2016-05-22 17:49:30 +00:00
perm_tmap_buffer_type temp_tmap_buf;
level_tmap_buffer_type level_tmap_buf;
2006-03-20 17:12:09 +00:00
2016-05-22 17:49:30 +00:00
level_tmap_buf.fill(-1);
2006-03-20 17:12:09 +00:00
2016-05-22 17:49:30 +00:00
wall_buffer_type temp_wall_buf;
determine_used_textures_level(LevelSharedSegmentState.DestructibleLights, 0, 1, level_num, temp_tmap_buf, temp_wall_buf, level_tmap_buf, sizeof(level_tmap_buf)/sizeof(level_tmap_buf[0]));
PHYSFSX_printf(my_file, "\nTextures used in [%s]\n", Gamesave_current_filename);
2006-03-20 17:12:09 +00:00
say_used_tmaps(my_file, temp_tmap_buf);
}
// ----------------------------------------------------------------------------
namespace dsx {
2006-03-20 17:12:09 +00:00
void dump_used_textures_all(void)
{
int i;
say_totals_all();
auto my_file = PHYSFSX_openWriteBuffered("textures.dmp");
2006-03-20 17:12:09 +00:00
if (!my_file) {
gr_palette_load(gr_palette);
nm_messagebox( NULL, 1, "Ok", "ERROR: Can't open textures.dmp\nErrno=%i", errno);
2006-03-20 17:12:09 +00:00
return;
}
2016-05-22 17:49:30 +00:00
perm_tmap_buffer_type perm_tmap_buf{};
level_tmap_buffer_type level_tmap_buf;
level_tmap_buf.fill(-1);
2006-03-20 17:12:09 +00:00
2016-05-22 17:49:30 +00:00
perm_tmap_buffer_type temp_tmap_buf;
#if defined(DXX_BUILD_DESCENT_I)
2016-05-22 17:49:30 +00:00
wall_buffer_type perm_wall_buf{};
for (i=0; i<NUM_SHAREWARE_LEVELS; i++) {
2016-05-22 17:49:30 +00:00
wall_buffer_type temp_wall_buf;
determine_used_textures_level(LevelSharedDestructibleLightState, 1, 1, i, temp_tmap_buf, temp_wall_buf, level_tmap_buf, sizeof(level_tmap_buf)/sizeof(level_tmap_buf[0]));
PHYSFSX_printf(my_file, "\nTextures used in [%s]\n", Shareware_level_names[i]);
say_used_tmaps(my_file, temp_tmap_buf);
2016-05-22 17:49:30 +00:00
merge_buffers(perm_tmap_buf, temp_tmap_buf);
merge_buffers(perm_wall_buf, temp_wall_buf);
}
PHYSFSX_printf(my_file, "\n\nUsed textures in all shareware mines:\n");
say_used_tmaps(my_file, perm_tmap_buf);
PHYSFSX_printf(my_file, "\nUnused textures in all shareware mines:\n");
say_unused_tmaps(my_file, perm_tmap_buf);
PHYSFSX_printf(my_file, "\nTextures used exactly once in all shareware mines:\n");
say_used_once_tmaps(my_file, perm_tmap_buf, level_tmap_buf);
PHYSFSX_printf(my_file, "\nWall anims (eg, doors) unused in all shareware mines:\n");
say_unused_walls(my_file, perm_wall_buf);
for (i=0; i<NUM_REGISTERED_LEVELS; i++)
#elif defined(DXX_BUILD_DESCENT_II)
2013-10-06 16:20:00 +00:00
for (i=First_dump_level; i<=Last_dump_level; i++)
#endif
2013-10-06 16:20:00 +00:00
{
2016-05-22 17:49:30 +00:00
wall_buffer_type temp_wall_buf;
determine_used_textures_level(LevelSharedSegmentState.DestructibleLights, 1, 0, i, temp_tmap_buf, temp_wall_buf, level_tmap_buf, sizeof(level_tmap_buf)/sizeof(level_tmap_buf[0]));
#if defined(DXX_BUILD_DESCENT_I)
PHYSFSX_printf(my_file, "\nTextures used in [%s]\n", Registered_level_names[i]);
#elif defined(DXX_BUILD_DESCENT_II)
PHYSFSX_printf(my_file, "\nTextures used in [%s]\n", Adam_level_names[i]);
#endif
2006-03-20 17:12:09 +00:00
say_used_tmaps(my_file, temp_tmap_buf);
2016-05-22 17:49:30 +00:00
merge_buffers(perm_tmap_buf, temp_tmap_buf);
2006-03-20 17:12:09 +00:00
}
PHYSFSX_printf(my_file, "\n\nUsed textures in all (including registered) mines:\n");
2006-03-20 17:12:09 +00:00
say_used_tmaps(my_file, perm_tmap_buf);
PHYSFSX_printf(my_file, "\nUnused textures in all (including registered) mines:\n");
2006-03-20 17:12:09 +00:00
say_unused_tmaps(my_file, perm_tmap_buf);
}
}
2006-03-20 17:12:09 +00:00
#endif