home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / dumpmine.c < prev    next >
C/C++ Source or Header  |  1998-06-08  |  33KB  |  1,060 lines

  1. /*
  2.  * $Source: f:/miner/source/main/rcs/dumpmine.c $
  3.  * $Revision: 2.1 $
  4.  * $Author: mike $
  5.  * $Date: 1995/04/06 12:21:50 $
  6.  * 
  7.  * Functions to dump text description of mine.
  8.  * An editor-only function, called at mine load time.
  9.  * To be read by a human to verify the correctness and completeness of a mine.
  10.  * 
  11.  * $Log: dumpmine.c $
  12.  * Revision 2.1  1995/04/06  12:21:50  mike
  13.  * Add texture map information to txm files.
  14.  * 
  15.  * Revision 2.0  1995/02/27  11:26:41  john
  16.  * New version 2.0, which has no anonymous unions, builds with
  17.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  18.  * 
  19.  * Revision 1.24  1995/01/23  15:34:43  mike
  20.  * New diagnostic code, levels.all stuff.
  21.  * 
  22.  * Revision 1.23  1994/12/20  17:56:36  yuan
  23.  * Multiplayer object capability.
  24.  * 
  25.  * Revision 1.22  1994/11/27  23:12:19  matt
  26.  * Made changes for new mprintf calling convention
  27.  * 
  28.  * Revision 1.21  1994/11/23  12:19:04  mike
  29.  * move out level names, stick in gamesave.
  30.  * 
  31.  * Revision 1.20  1994/11/21  16:54:36  mike
  32.  * oops.
  33.  * 
  34.  * 
  35.  * Revision 1.19  1994/11/20  22:12:55  mike
  36.  * Lotsa new stuff in this fine debug file.
  37.  * 
  38.  * Revision 1.18  1994/11/17  14:58:09  mike
  39.  * moved segment validation functions from editor to main.
  40.  * 
  41.  * Revision 1.17  1994/11/15  21:43:02  mike
  42.  * texture usage system.
  43.  * 
  44.  * Revision 1.16  1994/11/15  12:45:59  mike
  45.  * debug code for dumping texture info.
  46.  * 
  47.  * Revision 1.15  1994/11/14  20:47:50  john
  48.  * Attempted to strip out all the code in the game 
  49.  * directory that uses any ui code.
  50.  * 
  51.  * Revision 1.14  1994/10/14  17:33:38  mike
  52.  * Fix error reporting for number of multiplayer objects in mine.
  53.  * 
  54.  * Revision 1.13  1994/10/14  13:37:46  mike
  55.  * Forgot parameter in fprintf, was getting bogus number of excess keys.
  56.  * 
  57.  * Revision 1.12  1994/10/12  08:05:33  mike
  58.  * Detect keys contained in objects for error checking (txm file).
  59.  * 
  60.  * Revision 1.11  1994/10/10  17:02:08  mike
  61.  * fix fix.
  62.  * 
  63.  * Revision 1.10  1994/10/10  17:00:37  mike
  64.  * Add checking for proper number of players.
  65.  * 
  66.  * Revision 1.9  1994/10/03  23:37:19  mike
  67.  * Adapt to clear and rational understanding of matcens as related to fuelcens as related to something that might work.
  68.  * 
  69.  * Revision 1.8  1994/09/30  17:15:29  mike
  70.  * Fix error message, was telling bogus filename.
  71.  * 
  72.  * Revision 1.7  1994/09/30  11:50:55  mike
  73.  * More diagnostics.
  74.  * 
  75.  * Revision 1.6  1994/09/28  17:31:19  mike
  76.  * More error checking.
  77.  * 
  78.  * Revision 1.5  1994/09/28  11:14:05  mike
  79.  * Better checking on bogus walls.
  80.  * 
  81.  * Revision 1.4  1994/09/28  09:23:50  mike
  82.  * Change some Error messages to Warnings.
  83.  * 
  84.  * Revision 1.3  1994/09/27  17:08:31  mike
  85.  * More mine validation stuff.
  86.  * 
  87.  * Revision 1.2  1994/09/27  15:43:22  mike
  88.  * The amazing code to tell you everything and more about our mines!
  89.  * 
  90.  * Revision 1.1  1994/09/27  10:51:15  mike
  91.  * Initial revision
  92.  * 
  93.  * 
  94.  */
  95.  
  96.  
  97. #pragma off (unreferenced)
  98. static char rcsid[] = "$Id: dumpmine.c 2.1 1995/04/06 12:21:50 mike Exp $";
  99. #pragma on (unreferenced)
  100.  
  101. #include <stdio.h>
  102. //#include <stdlib.h>
  103. //#include <math.h>
  104. #include <string.h>
  105. #include <stdarg.h>
  106.  
  107. #include "mono.h"
  108. #include "key.h"
  109. #include "gr.h"
  110. #include "palette.h"
  111.  
  112. #include "inferno.h"
  113. #ifdef EDITOR
  114. #include "editor\editor.h"
  115. #endif
  116. #include "error.h"
  117. #include "object.h"
  118. //#include "game.h"
  119. //#include "screens.h"
  120. #include "wall.h"
  121. #include "gamemine.h"
  122. #include "robot.h"
  123. #include "player.h"
  124. #include "newmenu.h"
  125. #include "textures.h"
  126.  
  127. //#include "cflib.h"
  128. //#include "nocfile.h"
  129. #include "bm.h"
  130. #include "menu.h"
  131. #include "switch.h"
  132. #include "fuelcen.h"
  133. #include "powerup.h"
  134. #include "hostage.h"
  135. //#include "weapon.h"
  136. //#include "newdemo.h"
  137. #include "gameseq.h"
  138. //#include "automap.h"
  139. #include "polyobj.h"
  140. //#include "text.h"
  141. //#include "gamefont.h"
  142. #include "gamesave.h"
  143.  
  144.  
  145. #ifdef EDITOR
  146.  
  147. extern ubyte bogus_data[64*64];
  148. extern grs_bitmap bogus_bitmap;
  149.  
  150. //    --------------------------------------------------------------------------------
  151. char    *object_types(int objnum)
  152. {
  153.     int    type = Objects[objnum].type;
  154.  
  155.     Assert((type >= 0) && (type < MAX_OBJECT_TYPES));
  156.     return    &Object_type_names[type];
  157. }
  158.  
  159. //    --------------------------------------------------------------------------------
  160. char    *object_ids(int objnum)
  161. {
  162.     int    type = Objects[objnum].type;
  163.     int    id = Objects[objnum].id;
  164.  
  165.     switch (type) {
  166.         case OBJ_ROBOT:
  167.             return &Robot_names[id];
  168.             break;
  169.         case OBJ_POWERUP:
  170.             return &Powerup_names[id];
  171.             break;
  172.     }
  173.  
  174.     return    NULL;
  175. }
  176.  
  177. void err_printf(FILE *my_file, char * format, ... )
  178. {
  179.     va_list    args;
  180.     char        message[256];
  181.  
  182.     va_start(args, format );
  183.     vsprintf(message,format,args);
  184.     va_end(args);
  185.  
  186.     mprintf((1, "%s", message));
  187.     fprintf(my_file, "%s", message);
  188.     Errors_in_mine++;
  189. }
  190.  
  191. void warning_printf(FILE *my_file, char * format, ... )
  192. {
  193.     va_list    args;
  194.     char        message[256];
  195.  
  196.     va_start(args, format );
  197.     vsprintf(message,format,args);
  198.     va_end(args);
  199.  
  200.     mprintf((0, "%s", message));
  201.     fprintf(my_file, "%s", message);
  202. }
  203.  
  204. //    -----------------------------------------------------------------------------------------------------------
  205. void write_exit_text(FILE *my_file)
  206. {
  207.     int    i, j, count;
  208.  
  209.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  210.     fprintf(my_file, "Exit stuff\n");
  211.  
  212.     //    ---------- Find exit triggers ----------
  213.     count=0;
  214.     for (i=0; i<Num_triggers; i++)
  215.         if (Triggers[i].flags & TRIGGER_EXIT) {
  216.             int    count2;
  217.  
  218.             fprintf(my_file, "Trigger %2i, is an exit trigger with %i links.\n", i, Triggers[i].num_links);
  219.             count++;
  220.             if (Triggers[i].num_links != 0)
  221.                 err_printf(my_file, "Error: Exit triggers must have 0 links, this one has %i links.\n", Triggers[i].num_links);
  222.  
  223.             //    Find wall pointing to this trigger.
  224.             count2 = 0;
  225.             for (j=0; j<Num_walls; j++)
  226.                 if (Walls[j].trigger == i) {
  227.                     count2++;
  228.                     fprintf(my_file, "Exit trigger %i is in segment %i, on side %i, bound to wall %i\n", i, Walls[j].segnum, Walls[j].sidenum, j);
  229.                 }
  230.             if (count2 == 0)
  231.                 err_printf(my_file, "Error: Trigger %i is not bound to any wall.\n", i);
  232.             else if (count2 > 1)
  233.                 err_printf(my_file, "Error: Trigger %i is bound to %i walls.\n", i, count2);
  234.  
  235.         }
  236.  
  237.     if (count == 0)
  238.         err_printf(my_file, "Error: No exit trigger in this mine.\n");
  239.     else if (count != 1)
  240.         err_printf(my_file, "Error: More than one exit trigger in this mine.\n");
  241.     else
  242.         fprintf(my_file, "\n");
  243.  
  244.     //    ---------- Find exit doors ----------
  245.     count = 0;
  246.     for (i=0; i<=Highest_segment_index; i++)
  247.         for (j=0; j<MAX_SIDES_PER_SEGMENT; j++)
  248.             if (Segments[i].children[j] == -2) {
  249.                 fprintf(my_file, "Segment %3i, side %i is an exit door.\n", i, j);
  250.                 count++;
  251.             }
  252.  
  253.     if (count == 0)
  254.         err_printf(my_file, "Error: No external wall in this mine.\n");
  255.     else if (count != 1) {
  256.         warning_printf(my_file, "Warning: %i external walls in this mine.\n", count);
  257.         warning_printf(my_file, "(If %i are secret exits, then no problem.)\n", count-1); 
  258.     } else
  259.         fprintf(my_file, "\n");
  260. }
  261.  
  262. //    -----------------------------------------------------------------------------------------------------------
  263. void write_key_text(FILE *my_file)
  264. {
  265.     int    i;
  266.     int    red_count, blue_count, gold_count;
  267.     int    red_count2, blue_count2, gold_count2;
  268.     int    blue_segnum=-1, blue_sidenum=-1, red_segnum=-1, red_sidenum=-1, gold_segnum=-1, gold_sidenum=-1;
  269.     int    connect_side;
  270.  
  271.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  272.     fprintf(my_file, "Key stuff:\n");
  273.  
  274.     red_count = 0;
  275.     blue_count = 0;
  276.     gold_count = 0;
  277.  
  278.     for (i=0; i<Num_walls; i++) {
  279.         if (Walls[i].keys & KEY_BLUE) {
  280.             fprintf(my_file, "Wall %i (seg=%i, side=%i) is keyed to the blue key.\n", i, Walls[i].segnum, Walls[i].sidenum);
  281.             if (blue_segnum == -1) {
  282.                 blue_segnum = Walls[i].segnum;
  283.                 blue_sidenum = Walls[i].sidenum;
  284.                 blue_count++;
  285.             } else {
  286.                 connect_side = find_connect_side(&Segments[Walls[i].segnum], &Segments[blue_segnum]);
  287.                 if (connect_side != blue_sidenum) {
  288.                     warning_printf(my_file, "Warning: This blue door at seg %i, is different than the one at seg %i, side %i\n", Walls[i].segnum, blue_segnum, blue_sidenum);
  289.                     blue_count++;
  290.                 }
  291.             }
  292.         }
  293.         if (Walls[i].keys & KEY_RED) {
  294.             fprintf(my_file, "Wall %i (seg=%i, side=%i) is keyed to the red key.\n", i, Walls[i].segnum, Walls[i].sidenum);
  295.             if (red_segnum == -1) {
  296.                 red_segnum = Walls[i].segnum;
  297.                 red_sidenum = Walls[i].sidenum;
  298.                 red_count++;
  299.             } else {
  300.                 connect_side = find_connect_side(&Segments[Walls[i].segnum], &Segments[red_segnum]);
  301.                 if (connect_side != red_sidenum) {
  302.                     warning_printf(my_file, "Warning: This red door at seg %i, is different than the one at seg %i, side %i\n", Walls[i].segnum, red_segnum, red_sidenum);
  303.                     red_count++;
  304.                 }
  305.             }
  306.         }
  307.         if (Walls[i].keys & KEY_GOLD) {
  308.             fprintf(my_file, "Wall %i (seg=%i, side=%i) is keyed to the gold key.\n", i, Walls[i].segnum, Walls[i].sidenum);
  309.             if (gold_segnum == -1) {
  310.                 gold_segnum = Walls[i].segnum;
  311.                 gold_sidenum = Walls[i].sidenum;
  312.                 gold_count++;
  313.             } else {
  314.                 connect_side = find_connect_side(&Segments[Walls[i].segnum], &Segments[gold_segnum]);
  315.                 if (connect_side != gold_sidenum) {
  316.                     warning_printf(my_file, "Warning: This gold door at seg %i, is different than the one at seg %i, side %i\n", Walls[i].segnum, gold_segnum, gold_sidenum);
  317.                     gold_count++;
  318.                 }
  319.             }
  320.         }
  321.     }
  322.  
  323.     if (blue_count > 1)
  324.         warning_printf(my_file, "Warning: %i doors are keyed to the blue key.\n", blue_count);
  325.  
  326.     if (red_count > 1)
  327.         warning_printf(my_file, "Warning: %i doors are keyed to the red key.\n", red_count);
  328.  
  329.     if (gold_count > 1)
  330.         warning_printf(my_file, "Warning: %i doors are keyed to the gold key.\n", gold_count);
  331.  
  332.     red_count2 = 0;
  333.     blue_count2 = 0;
  334.     gold_count2 = 0;
  335.  
  336.     for (i=0; i<=Highest_object_index; i++) {
  337.         if (Objects[i].type == OBJ_POWERUP)
  338.             if (Objects[i].id == POW_KEY_BLUE) {
  339.                 fprintf(my_file, "The BLUE key is object %i in segment %i\n", i, Objects[i].segnum);
  340.                 blue_count2++;
  341.             }
  342.         if (Objects[i].type == OBJ_POWERUP)
  343.             if (Objects[i].id == POW_KEY_RED) {
  344.                 fprintf(my_file, "The RED key is object %i in segment %i\n", i, Objects[i].segnum);
  345.                 red_count2++;
  346.             }
  347.         if (Objects[i].type == OBJ_POWERUP)
  348.             if (Objects[i].id == POW_KEY_GOLD) {
  349.                 fprintf(my_file, "The GOLD key is object %i in segment %i\n", i, Objects[i].segnum);
  350.                 gold_count2++;
  351.             }
  352.  
  353.         if (Objects[i].contains_count) {
  354.             if (Objects[i].contains_type == OBJ_POWERUP) {
  355.                 switch (Objects[i].contains_id) {
  356.                     case POW_KEY_BLUE:
  357.                         fprintf(my_file, "The BLUE key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum);
  358.                         blue_count2 += Objects[i].contains_count;
  359.                         break;
  360.                     case POW_KEY_GOLD:
  361.                         fprintf(my_file, "The GOLD key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum);
  362.                         gold_count2 += Objects[i].contains_count;
  363.                         break;
  364.                     case POW_KEY_RED:
  365.                         fprintf(my_file, "The RED key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum);
  366.                         red_count2 += Objects[i].contains_count;
  367.                         break;
  368.                     default:
  369.                         break;
  370.                 }
  371.             }
  372.         }
  373.     }
  374.  
  375.     if (blue_count)
  376.         if (blue_count2 == 0)
  377.             err_printf(my_file, "Error: There is a door keyed to the blue key, but no blue key!\n");
  378.  
  379.     if (red_count)
  380.         if (red_count2 == 0)
  381.             err_printf(my_file, "Error: There is a door keyed to the red key, but no red key!\n");
  382.  
  383.     if (gold_count)
  384.         if (gold_count2 == 0)
  385.             err_printf(my_file, "Error: There is a door keyed to the gold key, but no gold key!\n");
  386.  
  387.     if (blue_count2 > 1)
  388.         err_printf(my_file, "Error: There are %i blue keys!\n", blue_count2);
  389.  
  390.     if (red_count2 > 1)
  391.         err_printf(my_file, "Error: There are %i red keys!\n", red_count2);
  392.  
  393.     if (gold_count2 > 1)
  394.         err_printf(my_file, "Error: There are %i gold keys!\n", gold_count2);
  395. }
  396.  
  397. //    ------------------------------------------------------------------------------------------
  398. void write_control_center_text(FILE *my_file)
  399. {
  400.     int    i, count, objnum, count2;
  401.  
  402.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  403.     fprintf(my_file, "Control Center stuff:\n");
  404.  
  405.     count = 0;
  406.     for (i=0; i<=Highest_segment_index; i++)
  407.         if (Segments[i].special == SEGMENT_IS_CONTROLCEN) {
  408.             count++;
  409.             fprintf(my_file, "Segment %3i is a control center.\n", i);
  410.             objnum = Segments[i].objects;
  411.             count2 = 0;
  412.             while (objnum != -1) {
  413.                 if (Objects[objnum].type == OBJ_CNTRLCEN)
  414.                     count2++;
  415.                 objnum = Objects[objnum].next;
  416.             }
  417.             if (count2 == 0)
  418.                 fprintf(my_file, "No control center object in control center segment.\n");
  419.             else if (count2 != 1)
  420.                 fprintf(my_file, "%i control center objects in control center segment.\n", count2);
  421.         }
  422.  
  423.     if (count == 0)
  424.         err_printf(my_file, "Error: No control center in this mine.\n");
  425.     else if (count != 1)
  426.         err_printf(my_file, "Error: More than one control center in this mine.\n");
  427. }
  428.  
  429. //    ------------------------------------------------------------------------------------------
  430. void write_fuelcen_text(FILE *my_file)
  431. {
  432.     int    i;
  433.  
  434.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  435.     fprintf(my_file, "Fuel Center stuff: (Note: This means fuel, repair, materialize, control centers!)\n");
  436.  
  437.     for (i=0; i<Num_fuelcenters; i++) {
  438.         fprintf(my_file, "Fuelcenter %i: Type=%i (%s), segment = %3i\n", i, Station[i].Type, Special_names[Station[i].Type], Station[i].segnum);
  439.         if (Segments[Station[i].segnum].special != Station[i].Type)
  440.             err_printf(my_file, "Error: Conflicting data: Segment %i has special type %i (%s), expected to be %i\n", Station[i].segnum, Segments[Station[i].segnum].special, Special_names[Segments[Station[i].segnum].special], Station[i].Type);
  441.     }
  442. }
  443.  
  444. //    ------------------------------------------------------------------------------------------
  445. void write_segment_text(FILE *my_file)
  446. {
  447.     int    i, objnum;
  448.  
  449.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  450.     fprintf(my_file, "Segment stuff:\n");
  451.  
  452.     for (i=0; i<=Highest_segment_index; i++) {
  453.  
  454.         fprintf(my_file, "Segment %4i: ", i);
  455.         if (Segments[i].special != 0)
  456.             fprintf(my_file, "special = %3i (%s), value = %3i ", Segments[i].special, Special_names[Segments[i].special], Segments[i].value);
  457.  
  458.         if (Segments[i].matcen_num != -1)
  459.             fprintf(my_file, "matcen = %3i, ", Segments[i].matcen_num);
  460.         
  461.         fprintf(my_file, "\n");
  462.     }
  463.  
  464.     for (i=0; i<=Highest_segment_index; i++) {
  465.         int    depth;
  466.  
  467.         objnum = Segments[i].objects;
  468.         fprintf(my_file, "Segment %4i: ", i);
  469.         depth=0;
  470.         if (objnum != -1) {
  471.             fprintf(my_file, "Objects: ");
  472.             while (objnum != -1) {
  473.                 fprintf(my_file, "[%8s %8s %3i] ", object_types(objnum), object_ids(objnum), objnum);
  474.                 objnum = Objects[objnum].next;
  475.                 if (depth++ > 30) {
  476.                     fprintf(my_file, "\nAborted after %i links\n", depth);
  477.                     break;
  478.                 }
  479.             }
  480.         }
  481.         fprintf(my_file, "\n");
  482.     }
  483. }
  484.  
  485. //    ------------------------------------------------------------------------------------------
  486. //    This routine is bogus.  It assumes that all centers are matcens, which is not true.  The setting of segnum is bogus.
  487. void write_matcen_text(FILE *my_file)
  488. {
  489.     int    i, j, k;
  490.  
  491.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  492.     fprintf(my_file, "Materialization centers:\n");
  493.     for (i=0; i<Num_robot_centers; i++) {
  494.         int    trigger_count=0, segnum, fuelcen_num;
  495.  
  496.         fprintf(my_file, "FuelCenter[%02i].Segment = %04i  ", i, Station[i].segnum);
  497.         fprintf(my_file, "Segment[%04i].matcen_num = %02i  ", Station[i].segnum, Segments[Station[i].segnum].matcen_num);
  498.  
  499.         fuelcen_num = RobotCenters[i].fuelcen_num;
  500.         if (Station[fuelcen_num].Type != SEGMENT_IS_ROBOTMAKER)
  501.             err_printf(my_file, "Error: Matcen %i corresponds to Station %i, which has type %i (%s).\n", i, fuelcen_num, Station[fuelcen_num].Type, Special_names[Station[fuelcen_num].Type]);
  502.  
  503.         segnum = Station[fuelcen_num].segnum;
  504.  
  505.         //    Find trigger for this materialization center.
  506.         for (j=0; j<Num_triggers; j++) {
  507.             if (Triggers[j].flags & TRIGGER_MATCEN) {
  508.                 for (k=0; k<Triggers[j].num_links; k++)
  509.                     if (Triggers[j].seg[k] == segnum) {
  510.                         fprintf(my_file, "Trigger = %2i  ", j );
  511.                         trigger_count++;
  512.                     }
  513.             }
  514.         }
  515.         fprintf(my_file, "\n");
  516.  
  517.         if (trigger_count == 0)
  518.             err_printf(my_file, "Error: Matcen %i in segment %i has no trigger!\n", i, segnum);
  519.  
  520.     }
  521. }
  522.  
  523. //    ------------------------------------------------------------------------------------------
  524. void write_wall_text(FILE *my_file)
  525. {
  526.     int    i, j;
  527.     byte    wall_flags[MAX_WALLS];
  528.  
  529.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  530.     fprintf(my_file, "Walls:\n");
  531.     for (i=0; i<Num_walls; i++) {
  532.         int    segnum, sidenum;
  533.  
  534.         fprintf(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,
  535.             Walls[i].segnum, Walls[i].sidenum, Walls[i].linked_wall, Wall_names[Walls[i].type], Walls[i].flags, Walls[i].hps >> 16, Walls[i].trigger, Walls[i].clip_num, Walls[i].keys, Walls[i].state);
  536.  
  537.         segnum = Walls[i].segnum;
  538.         sidenum = Walls[i].sidenum;
  539.  
  540.         if (Segments[segnum].sides[sidenum].wall_num != i)
  541.             err_printf(my_file, "Error: Wall %i points at segment %i, side %i, but that segment doesn't point back (it's wall_num = %i)\n", i, segnum, sidenum, Segments[segnum].sides[sidenum].wall_num);
  542.     }
  543.  
  544.     for (i=0; i<MAX_WALLS; i++)
  545.         wall_flags[i] = 0;
  546.  
  547.     for (i=0; i<=Highest_segment_index; i++) {
  548.         segment    *segp = &Segments[i];
  549.         for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
  550.             side    *sidep = &segp->sides[j];
  551.             if (sidep->wall_num != -1)
  552.                 if (wall_flags[sidep->wall_num])
  553.                     err_printf(my_file, "Error: Wall %i appears in two or more segments, including segment %i, side %i.\n", sidep->wall_num, i, j);
  554.                 else
  555.                     wall_flags[sidep->wall_num] = 1;
  556.         }
  557.     }
  558.  
  559. }
  560.  
  561. //typedef struct trigger {
  562. //    byte        type;
  563. //    short        flags;
  564. //    fix        value;
  565. //    fix        time;
  566. //    byte        link_num;
  567. //    short     num_links;
  568. //    short     seg[MAX_WALLS_PER_LINK];
  569. //    short        side[MAX_WALLS_PER_LINK];
  570. //    } trigger;
  571.  
  572. //    ------------------------------------------------------------------------------------------
  573. void write_player_text(FILE *my_file)
  574. {
  575.     int    i, num_players=0;
  576.  
  577.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  578.     fprintf(my_file, "Players:\n");
  579.     for (i=0; i<=Highest_object_index; i++) {
  580.         if (Objects[i].type == OBJ_PLAYER) {
  581.             num_players++;
  582.             fprintf(my_file, "Player %2i is object #%3i in segment #%3i.\n", Objects[i].id, i, Objects[i].segnum);
  583.         }
  584.     }
  585.  
  586. #ifdef SHAREWARE    
  587.     if (num_players != MAX_PLAYERS)
  588.         err_printf(my_file, "Error: %i player objects.  %i are required.\n", num_players, MAX_PLAYERS);
  589. #endif
  590. #ifndef SHAREWARE    
  591.     if (num_players > MAX_MULTI_PLAYERS)
  592.         err_printf(my_file, "Error: %i player objects.  %i are required.\n", num_players, MAX_PLAYERS);
  593. #endif
  594.  
  595.  
  596. }
  597.  
  598. //    ------------------------------------------------------------------------------------------
  599. void write_trigger_text(FILE *my_file)
  600. {
  601.     int    i, j, w;
  602.  
  603.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  604.     fprintf(my_file, "Triggers:\n");
  605.     for (i=0; i<Num_triggers; i++) {
  606.         fprintf(my_file, "Trigger %03i: type=%3i flags=%04x, value=%08x, time=%8x, linknum=%i, num_links=%i ", i, 
  607.             Triggers[i].type, Triggers[i].flags, Triggers[i].value, Triggers[i].time, Triggers[i].link_num, Triggers[i].num_links);
  608.  
  609.         for (j=0; j<Triggers[i].num_links; j++)
  610.             fprintf(my_file, "[%03i:%i] ", Triggers[i].seg[j], Triggers[i].side[j]);
  611.  
  612.         //    Find which wall this trigger is connected to.
  613.         for (w=0; w<Num_walls; w++)
  614.             if (Walls[w].trigger == i)
  615.                 break;
  616.  
  617.         if (w == Num_walls)
  618.             err_printf(my_file, "\nError: Trigger %i is not connected to any wall, so it can never be triggered.\n", i);
  619.         else
  620.             fprintf(my_file, "Attached to seg:side = %i:%i, wall %i\n", Walls[w].segnum, Walls[w].sidenum, Segments[Walls[w].segnum].sides[Walls[w].sidenum].wall_num);
  621.  
  622.     }
  623.  
  624. }
  625.  
  626. //    ------------------------------------------------------------------------------------------
  627. void write_game_text_file(char *filename)
  628. {
  629.     char    my_filename[128];
  630.     int    namelen;
  631.     FILE    * my_file;
  632.  
  633.     Errors_in_mine = 0;
  634.  
  635.     // mprintf((0, "Writing text file for mine [%s]\n", filename));
  636.  
  637.     namelen = strlen(filename);
  638.  
  639.     Assert (namelen > 4);
  640.  
  641.     Assert (filename[namelen-4] == '.');
  642.  
  643.     strcpy(my_filename, filename);
  644.     strcpy( &my_filename[namelen-4], ".txm");
  645.  
  646.     // mprintf((0, "Writing text file [%s]\n", my_filename));
  647.  
  648.     my_file = fopen( my_filename, "wt" );
  649.  
  650.     if (!my_file)    {
  651.         char  ErrorMessage[200];
  652.  
  653.         sprintf( ErrorMessage, "ERROR: Unable to open output file %s\n", my_file );
  654.         stop_time();
  655.         gr_palette_load(gr_palette);
  656.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  657.         start_time();
  658.  
  659.         return;
  660.     }
  661.  
  662.     dump_used_textures_level(my_file, 0);
  663.     say_totals(my_file, Gamesave_current_filename);
  664.  
  665.     fprintf(my_file, "\nNumber of segments:   %4i\n", Highest_segment_index+1);
  666.     fprintf(my_file, "Number of objects:    %4i\n", Highest_object_index+1);
  667.     fprintf(my_file, "Number of walls:      %4i\n", Num_walls);
  668.     fprintf(my_file, "Number of open doors: %4i\n", Num_open_doors);
  669.     fprintf(my_file, "Number of triggers:   %4i\n", Num_triggers);
  670.     fprintf(my_file, "Number of matcens:    %4i\n", Num_robot_centers);
  671.     fprintf(my_file, "\n");
  672.  
  673.     write_segment_text(my_file);
  674.  
  675.     write_fuelcen_text(my_file);
  676.  
  677.     write_matcen_text(my_file);
  678.  
  679.     write_player_text(my_file);
  680.  
  681.     write_wall_text(my_file);
  682.  
  683.     write_trigger_text(my_file);
  684.  
  685.     write_exit_text(my_file);
  686.  
  687.     //    ---------- Find control center segment ----------
  688.     write_control_center_text(my_file);
  689.  
  690.     //    ---------- Show keyed walls ----------
  691.     write_key_text(my_file);
  692.  
  693.     fclose(my_file);
  694.  
  695. }
  696.  
  697. // -- //    ---------------
  698. // -- //    Note: This only works for a loaded level because the objects array must be valid.
  699. // -- void determine_used_textures_robots(int *tmap_buf)
  700. // -- {
  701. // --     int    i, objnum;
  702. // --     polymodel    *po;
  703. // -- 
  704. // --     Assert(N_polygon_models);
  705. // -- 
  706. // --     for (objnum=0; objnum <= Highest_object_index; objnum++) {
  707. // --         int    model_num;
  708. // -- 
  709. // --         if (Objects[objnum].render_type == RT_POLYOBJ) {
  710. // --             model_num = Objects[objnum].rtype.pobj_info.model_num;
  711. // -- 
  712. // --             po=&Polygon_models[model_num];
  713. // -- 
  714. // --             for (i=0;i<po->n_textures;i++)    {
  715. // --                 int    tli;
  716. // -- 
  717. // --                 tli = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]];
  718. // --                 Assert((tli>=0) && (tli<= Num_tmaps));
  719. // --                 tmap_buf[tli]++;
  720. // --             }
  721. // --         }
  722. // --     }
  723. // -- 
  724. // -- }
  725.  
  726. //    -----------------------------------------------------------------------------
  727. void determine_used_textures_level(int load_level_flag, int shareware_flag, int level_num, int *tmap_buf, int *wall_buf, byte *level_tmap_buf, int max_tmap)
  728. {
  729.     int    segnum, sidenum;
  730.     int    i, j;
  731.  
  732.     for (i=0; i<max_tmap; i++)
  733.         tmap_buf[i] = 0;
  734.  
  735.     if (load_level_flag) {
  736.         if (shareware_flag)
  737.             load_level(Shareware_level_names[level_num]);
  738.         else
  739.             load_level(Registered_level_names[level_num]);
  740.     }
  741.  
  742.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  743.         segment    *segp = &Segments[segnum];
  744.  
  745.         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  746.             side    *sidep = &segp->sides[sidenum];
  747.  
  748.             if (sidep->wall_num != -1) {
  749.                 int clip_num = Walls[sidep->wall_num].clip_num;
  750.                 if (clip_num != -1) {
  751.  
  752.                     int num_frames = WallAnims[clip_num].num_frames;
  753.  
  754.                     wall_buf[clip_num] = 1;
  755.  
  756.                     for (j=0; j<num_frames; j++) {
  757.                         int    tmap_num;
  758.  
  759.                         tmap_num = WallAnims[clip_num].frames[j];
  760.                         tmap_buf[tmap_num]++;
  761.                         if (level_tmap_buf[tmap_num] == -1)
  762.                             level_tmap_buf[tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
  763.                     }
  764.                 }
  765.             }
  766.  
  767.             if (sidep->tmap_num >= 0)
  768.                 if (sidep->tmap_num < max_tmap) {
  769.                     tmap_buf[sidep->tmap_num]++;
  770.                     if (level_tmap_buf[sidep->tmap_num] == -1)
  771.                         level_tmap_buf[sidep->tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
  772.                 } else
  773.                     Int3();    //    Error, bogus texture map.  Should not be greater than max_tmap.
  774.  
  775.             if ((sidep->tmap_num2 & 0x3fff) != 0)
  776.                 if ((sidep->tmap_num2 & 0x3fff) < max_tmap) {
  777.                     tmap_buf[sidep->tmap_num2 & 0x3fff]++;
  778.                     if (level_tmap_buf[sidep->tmap_num2 & 0x3fff] == -1)
  779.                         level_tmap_buf[sidep->tmap_num2 & 0x3fff] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
  780.                 } else
  781.                     Int3();    //    Error, bogus texture map.  Should not be greater than max_tmap.
  782.         }
  783.     }
  784. }
  785.  
  786. //    -----------------------------------------------------------------------------
  787. void merge_buffers(int *dest, int *src, int num)
  788. {
  789.     int    i;
  790.  
  791.     for (i=0; i<num; i++)
  792.         if (src[i])
  793.             dest[i] += src[i];
  794. }
  795.  
  796. //    -----------------------------------------------------------------------------
  797. void say_used_tmaps(FILE *my_file, int *tb)
  798. {
  799.     int    i;
  800.     int    count = 0;
  801.  
  802.     for (i=0; i<Num_tmaps; i++)
  803.         if (tb[i]) {
  804.             fprintf(my_file, "[%3i %8s (%4i)] ", i, TmapInfo[i].filename, tb[i]);
  805.             if (count++ >= 4) {
  806.                 fprintf(my_file, "\n");
  807.                 count = 0;
  808.             }
  809.         }
  810. }
  811.  
  812. //    -----------------------------------------------------------------------------
  813. void say_used_once_tmaps(FILE *my_file, int *tb, byte *tb_lnum)
  814. {
  815.     int    i;
  816.     char    *level_name;
  817.  
  818.     for (i=0; i<Num_tmaps; i++)
  819.         if (tb[i] == 1) {
  820.             int    level_num = tb_lnum[i];
  821.             if (level_num >= NUM_SHAREWARE_LEVELS) {
  822.                 Assert((level_num - NUM_SHAREWARE_LEVELS >= 0) && (level_num - NUM_SHAREWARE_LEVELS < NUM_REGISTERED_LEVELS));
  823.                 level_name = Registered_level_names[level_num - NUM_SHAREWARE_LEVELS];
  824.             } else {
  825.                 Assert((level_num >= 0) && (level_num < NUM_SHAREWARE_LEVELS));
  826.                 level_name = Shareware_level_names[level_num];
  827.             }
  828.  
  829.             fprintf(my_file, "Texture %3i %8s used only once on level %s\n", i, TmapInfo[i].filename, level_name);
  830.         }
  831. }
  832.  
  833. //    -----------------------------------------------------------------------------
  834. void say_unused_tmaps(FILE *my_file, int *tb)
  835. {
  836.     int    i;
  837.     int    count = 0;
  838.  
  839.     for (i=0; i<Num_tmaps; i++)
  840.         if (!tb[i]) {
  841.             if (GameBitmaps[Textures[i].index].bm_data == &bogus_data)
  842.                 fprintf(my_file, "U");
  843.             else
  844.                 fprintf(my_file, " ");
  845.  
  846.             fprintf(my_file, "[%3i %8s] ", i, TmapInfo[i].filename);
  847.             if (count++ >= 4) {
  848.                 fprintf(my_file, "\n");
  849.                 count = 0;
  850.             }
  851.         }
  852. }
  853.  
  854. //    -----------------------------------------------------------------------------
  855. void say_unused_walls(FILE *my_file, int *tb)
  856. {
  857.     int    i;
  858.  
  859.     for (i=0; i<Num_wall_anims; i++)
  860.         if (!tb[i])
  861.             fprintf(my_file, "Wall %3i is unused.\n", i);
  862. }
  863.  
  864. //    -------------------------------------------------------------------------------------------------
  865. say_totals(FILE *my_file, char *level_name)
  866. {
  867.     int    i, objnum;
  868.     int    total_robots = 0;
  869.     int    objects_processed = 0;
  870.  
  871.     int    used_objects[MAX_OBJECTS];
  872.  
  873.     fprintf(my_file, "\nLevel %s\n", level_name);
  874.  
  875.     for (i=0; i<MAX_OBJECTS; i++)
  876.         used_objects[i] = 0;
  877.  
  878.     while (objects_processed < Highest_object_index+1) {
  879.         int    j, objtype, objid, objcount, cur_obj_val, min_obj_val, min_objnum;
  880.  
  881.         //    Find new min objnum.
  882.         min_obj_val = 0x7fff0000;
  883.         min_objnum = -1;
  884.  
  885.         for (j=0; j<=Highest_object_index; j++) {
  886.             if (!used_objects[j]) {
  887.                 cur_obj_val = Objects[j].type * 1000 + Objects[j].id;
  888.                 if (cur_obj_val < min_obj_val) {
  889.                     min_objnum = j;
  890.                     min_obj_val = cur_obj_val;
  891.                 }
  892.             }
  893.         }
  894.         if (min_objnum == -1)
  895.             break;
  896.  
  897.         objcount = 0;
  898.  
  899.         objtype = Objects[min_objnum].type;
  900.         objid = Objects[min_objnum].id;
  901.  
  902.         for (i=0; i<=Highest_object_index; i++) {
  903.             if (!used_objects[i]) {
  904.  
  905.                 if (((Objects[i].type == objtype) && (Objects[i].id == objid)) ||
  906.                         ((Objects[i].type == objtype) && (objtype == OBJ_PLAYER)) ||
  907.                         ((Objects[i].type == objtype) && (objtype == OBJ_COOP)) ||
  908.                         ((Objects[i].type == objtype) && (objtype == OBJ_HOSTAGE))) {
  909.                     if (Objects[i].type == OBJ_ROBOT)
  910.                         total_robots++;
  911.                     used_objects[i] = 1;
  912.                     objcount++;
  913.                     objects_processed++;
  914.                 }
  915.             }
  916.         }
  917.  
  918.         if (objcount) {
  919.             fprintf(my_file, "Object: ");
  920.             fprintf(my_file, "%8s %8s %3i\n", object_types(min_objnum), object_ids(min_objnum), objcount);
  921.         }
  922.     }
  923.  
  924.     fprintf(my_file, "Total robots = %3i\n", total_robots);
  925. }
  926.  
  927. //    -----------------------------------------------------------------------------
  928. void say_totals_all(void)
  929. {
  930.     int    i;
  931.     FILE    *my_file;
  932.  
  933.     my_file = fopen( "levels.all", "wt" );
  934.  
  935.     if (!my_file)    {
  936.         char  ErrorMessage[200];
  937.  
  938.         sprintf( ErrorMessage, "ERROR: Unable to open output file levels.all\n");
  939.         stop_time();
  940.         gr_palette_load(gr_palette);
  941.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  942.         start_time();
  943.  
  944.         return;
  945.     }
  946.  
  947.     for (i=0; i<NUM_SHAREWARE_LEVELS; i++) {
  948.         mprintf((0, "Level %i\n", i+1));
  949.         load_level(Shareware_level_names[i]);
  950.         say_totals(my_file, Shareware_level_names[i]);
  951.     }
  952.  
  953.     for (i=0; i<NUM_REGISTERED_LEVELS; i++) {
  954.         mprintf((0, "Level %i\n", i+1+NUM_SHAREWARE_LEVELS));
  955.         load_level(Registered_level_names[i]);
  956.         say_totals(my_file, Registered_level_names[i]);
  957.     }
  958.  
  959.     fclose(my_file);
  960.  
  961. }
  962.  
  963. void dump_used_textures_level(FILE *my_file, int level_num)
  964. {
  965.     int    i;
  966.     int    temp_tmap_buf[MAX_TEXTURES];
  967.     int    perm_tmap_buf[MAX_TEXTURES];
  968.     byte    level_tmap_buf[MAX_TEXTURES];
  969.     int    temp_wall_buf[MAX_WALL_ANIMS];
  970.     int    perm_wall_buf[MAX_WALL_ANIMS];
  971.  
  972.     for (i=0; i<MAX_TEXTURES; i++) {
  973.         perm_tmap_buf[i] = 0;
  974.         level_tmap_buf[i] = -1;
  975.     }
  976.  
  977.     for (i=0; i<MAX_WALL_ANIMS; i++) {
  978.         perm_wall_buf[i] = 0;
  979.     }
  980.  
  981.     determine_used_textures_level(0, 1, level_num, temp_tmap_buf, temp_wall_buf, level_tmap_buf, MAX_TEXTURES);
  982. // --     determine_used_textures_robots(temp_tmap_buf);
  983.     fprintf(my_file, "\nTextures used in [%s]\n", Gamesave_current_filename);
  984.     say_used_tmaps(my_file, temp_tmap_buf);
  985. }
  986.  
  987. //    -----------------------------------------------------------------------------
  988. void dump_used_textures_all(void)
  989. {
  990.     FILE    *my_file;
  991.     int    i;
  992.     int    temp_tmap_buf[MAX_TEXTURES];
  993.     int    perm_tmap_buf[MAX_TEXTURES];
  994.     byte    level_tmap_buf[MAX_TEXTURES];
  995.     int    temp_wall_buf[MAX_WALL_ANIMS];
  996.     int    perm_wall_buf[MAX_WALL_ANIMS];
  997.  
  998. say_totals_all();
  999.  
  1000.     my_file = fopen( "textures.dmp", "wt" );
  1001.  
  1002.     if (!my_file)    {
  1003.         char  ErrorMessage[200];
  1004.  
  1005.         sprintf( ErrorMessage, "ERROR: Unable to open output file textures.dmp\n");
  1006.         stop_time();
  1007.         gr_palette_load(gr_palette);
  1008.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  1009.         start_time();
  1010.  
  1011.         return;
  1012.     }
  1013.  
  1014.     for (i=0; i<MAX_TEXTURES; i++) {
  1015.         perm_tmap_buf[i] = 0;
  1016.         level_tmap_buf[i] = -1;
  1017.     }
  1018.  
  1019.     for (i=0; i<MAX_WALL_ANIMS; i++) {
  1020.         perm_wall_buf[i] = 0;
  1021.     }
  1022.  
  1023.     for (i=0; i<NUM_SHAREWARE_LEVELS; i++) {
  1024.         determine_used_textures_level(1, 1, i, temp_tmap_buf, temp_wall_buf, level_tmap_buf, MAX_TEXTURES);
  1025.         fprintf(my_file, "\nTextures used in [%s]\n", Shareware_level_names[i]);
  1026.         say_used_tmaps(my_file, temp_tmap_buf);
  1027.         merge_buffers(perm_tmap_buf, temp_tmap_buf, MAX_TEXTURES);
  1028.         merge_buffers(perm_wall_buf, temp_wall_buf, MAX_WALL_ANIMS);
  1029.     }
  1030.  
  1031.     fprintf(my_file, "\n\nUsed textures in all shareware mines:\n");
  1032.     say_used_tmaps(my_file, perm_tmap_buf);
  1033.  
  1034.     fprintf(my_file, "\nUnused textures in all shareware mines:\n");
  1035.     say_unused_tmaps(my_file, perm_tmap_buf);
  1036.  
  1037.     fprintf(my_file, "\nTextures used exactly once in all shareware mines:\n");
  1038.     say_used_once_tmaps(my_file, perm_tmap_buf, level_tmap_buf);
  1039.  
  1040.     fprintf(my_file, "\nWall anims (eg, doors) unused in all shareware mines:\n");
  1041.     say_unused_walls(my_file, perm_wall_buf);
  1042.  
  1043.     for (i=0; i<NUM_REGISTERED_LEVELS; i++) {
  1044.         determine_used_textures_level(1, 0, i, temp_tmap_buf, temp_wall_buf, level_tmap_buf, MAX_TEXTURES);
  1045.         fprintf(my_file, "\nTextures used in [%s]\n", Registered_level_names[i]);
  1046.         say_used_tmaps(my_file, temp_tmap_buf);
  1047.         merge_buffers(perm_tmap_buf, temp_tmap_buf, MAX_TEXTURES);
  1048.     }
  1049.  
  1050.     fprintf(my_file, "\n\nUsed textures in all (including registered) mines:\n");
  1051.     say_used_tmaps(my_file, perm_tmap_buf);
  1052.  
  1053.     fprintf(my_file, "\nUnused textures in all (including registered) mines:\n");
  1054.     say_unused_tmaps(my_file, perm_tmap_buf);
  1055.  
  1056.     fclose(my_file);
  1057. }
  1058.  
  1059. #endif
  1060.