diff options
Diffstat (limited to 'stone_soup/crawl-ref/source/debug.cc')
-rw-r--r-- | stone_soup/crawl-ref/source/debug.cc | 2136 |
1 files changed, 0 insertions, 2136 deletions
diff --git a/stone_soup/crawl-ref/source/debug.cc b/stone_soup/crawl-ref/source/debug.cc deleted file mode 100644 index eb29e8c9d9..0000000000 --- a/stone_soup/crawl-ref/source/debug.cc +++ /dev/null @@ -1,2136 +0,0 @@ -/* - * File: debug.cc - * Summary: Debug and wizard related functions. - * Written by: Linley Henzell and Jesse Jones - * - * Change History (most recent first): - * - * <4> 14/12/99 LRH Added cast_spec_spell_name() - * <3> 5/06/99 JDJ Added TRACE. - * <2> -/--/-- JDJ Added a bunch od debugging macros. - * Old code is now #if WIZARD. - * <1> -/--/-- LRH Created - */ - -#include "AppHdr.h" -#include "debug.h" - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <stdarg.h> -#include <time.h> -#include <ctype.h> - -#ifdef DOS -#include <conio.h> -#endif - -#include "externs.h" - -#include "direct.h" -#include "dungeon.h" -#include "fight.h" -#include "invent.h" -#include "itemname.h" -#include "itemprop.h" -#include "item_use.h" -#include "items.h" -#include "misc.h" -#include "monplace.h" -#include "monstuff.h" -#include "mon-util.h" -#include "mutation.h" -#include "player.h" -#include "randart.h" -#include "religion.h" -#include "skills.h" -#include "skills2.h" -#include "spl-cast.h" -#include "spl-util.h" -#include "stuff.h" -#include "version.h" - -#ifndef WIZARD -#define WIZARD -#endif - -#if DEBUG && WIN -#define MyDebugBreak() _asm {int 3} -#endif - -//----------------------------------- -// Internal Variables -// -#if WIN -static HANDLE sConsole = NULL; -#endif - -// ======================================================================== -// Internal Functions -// ======================================================================== - -//--------------------------------------------------------------- -// -// BreakStrToDebugger -// -//--------------------------------------------------------------- -#if DEBUG -static void BreakStrToDebugger(const char *mesg) -{ - -#if OSX - fprintf(stderr, mesg); -// raise(SIGINT); // this is what DebugStr() does on OS X according to Tech Note 2030 - int* p = NULL; // but this gives us a stack crawl... - *p = 0; -#elif MAC - unsigned char s[50]; - - int len = strlen(mesg); - - if (len > 255) - len = 255; - - s[0] = (Byte) len; - BlockMoveData(mesg, s + 1, len); - - DebugStr(s); - -#elif WIN - MSG msg; // remove pending quit messages so the message box displays - - bool quitting = (bool)::PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); - - char text[2500]; - - int flags = MB_YESNO + // want abort and ignore buttons - // (too bad we can't ditch the retry button...) - MB_ICONERROR + // display the icon for errors - MB_TASKMODAL + // don't let the user do anything else in the app - MB_SETFOREGROUND; // bring the app to the front - - strcpy(text, mesg); - strcat(text, "\nDo you want to drop into the debugger?"); - - int result = MessageBoxA(NULL, text, "Debug Break", flags); - - if (result == IDYES) - MyDebugBreak(); - - if (quitting) - PostQuitMessage(msg.wParam); - -#else - fprintf(stderr, "%s\n", mesg); - abort(); -#endif -} -#endif - - -//--------------------------------------------------------------- -// -// IsDebuggerPresent95 -// -// From March 1999 Windows Developer's Journal. This should only -// be called if we're running on Win 95 (normally I'd add an -// ASSERT, but that's a bit dicy since this is called by ASSERT...) -// -//--------------------------------------------------------------- -#if WIN -static bool IsDebuggerPresent95() -{ - bool present = false; - - const DWORD kDebuggerPresentFlag = 0x000000001; - const DWORD kProcessDatabaseBytes = 190; - const DWORD kOffsetFlags = 8; - - DWORD threadID = GetCurrentThreadId(); - DWORD processID = GetCurrentProcessId(); - DWORD obfuscator = 0; - -#if __MWERKS__ - asm - { - mov ax, fs - mov es, ax - mov eax, 0x18 - mov eax, es:[eax] - sub eax, 0x10 xor eax,[threadID] mov[obfuscator], eax - } - -#else - _asm - { - mov ax, fs - mov es, ax - mov eax, 18 h - mov eax, es:[eax] - sub eax, 10 h xor eax,[threadID] mov[obfuscator], eax - } -#endif - - const DWORD *processDatabase = - reinterpret_cast< const DWORD * >(processID ^ obfuscator); - - if (!IsBadReadPtr(processDatabase, kProcessDatabaseBytes)) - { - DWORD flags = processDatabase[kOffsetFlags]; - - present = (flags & kDebuggerPresentFlag) != 0; - } - - return present; -} -#endif - - -//--------------------------------------------------------------- -// -// IsDebuggerPresent -// -//--------------------------------------------------------------- -#if WIN -bool IsDebuggerPresent() -{ - bool present = false; - - typedef BOOL(WINAPI * IsDebuggerPresentProc) (); - - HINSTANCE kernelH = LoadLibrary("KERNEL32.DLL"); - - if (kernelH != NULL) - { // should never fail - - IsDebuggerPresentProc proc = - (IsDebuggerPresentProc)::GetProcAddress( kernelH, - "IsDebuggerPresent" ); - - if (proc != NULL) // only present in NT and Win 98 - present = proc() != 0; - else - present = IsDebuggerPresent95(); - } - - return present; -} -#endif - - -//--------------------------------------------------------------- -// -// CreateConsoleWindow -// -//--------------------------------------------------------------- -#if WIN -static void CreateConsoleWindow() -{ - ASSERT(sConsole == NULL); - - // Create the console window - if (::AllocConsole()) - { - // Get the console window's handle - sConsole =::GetStdHandle(STD_ERROR_HANDLE); - if (sConsole == INVALID_HANDLE_VALUE) - sConsole = NULL; - - // Set some options - if (sConsole != NULL) - { - VERIFY(::SetConsoleTextAttribute(sConsole, FOREGROUND_GREEN)); - // green text on a black background (there doesn't appear to - // be a way to get black text) - - VERIFY(::SetConsoleTitle("Debug Log")); - - COORD size = { 80, 120 }; - - VERIFY(::SetConsoleScreenBufferSize(sConsole, size)); - } - else - DEBUGSTR(L "Couldn't get the console window's handle!"); - } - else - DEBUGSTR(L "Couldn't allocate the console window!"); -} -#endif - - -#if DEBUG -//--------------------------------------------------------------- -// -// TraceString -// -//--------------------------------------------------------------- -static void TraceString(const char *mesg) -{ - // Write the string to the debug window -#if WIN - if (IsDebuggerPresent()) - { - OutputDebugStringA(mesg); // if you're using CodeWarrior you'll need to enable the "Log System Messages" checkbox to get this working - } - else - { - if (sConsole == NULL) // otherwise we'll use a console window - CreateConsoleWindow(); - - if (sConsole != NULL) - { - unsigned long written; - - VERIFY(WriteConsoleA(sConsole, mesg, strlen(mesg), &written, NULL)); - } - } -#else - fprintf(stderr, "%s", mesg); -#endif - - // Write the string to the debug log - static bool inited = false; - static FILE *file = NULL; - - if (!inited) - { - ASSERT(file == NULL); - - const char *fileName = "DebugLog.txt"; - - file = fopen(fileName, "w"); - ASSERT(file != NULL); - - inited = true; - } - - if (file != NULL) - { - fputs(mesg, file); - fflush(file); // make sure all the output makes it to the file - - } -} -#endif - -#if MAC -#pragma mark - -#endif - -// ======================================================================== -// Global Functions -// ======================================================================== - -//--------------------------------------------------------------- -// -// AssertFailed -// -//--------------------------------------------------------------- -#if DEBUG -void AssertFailed(const char *expr, const char *file, int line) -{ - char mesg[512]; - -#if MAC - sprintf(mesg, "ASSERT(%s) in %s at line %d failed.", expr, file, line); - -#else - const char *fileName = file + strlen(file); // strip off path - - while (fileName > file && fileName[-1] != '\\') - --fileName; - - sprintf(mesg, "ASSERT(%s) in '%s' at line %d failed.", expr, fileName, - line); -#endif - - BreakStrToDebugger(mesg); -} -#endif - - -//--------------------------------------------------------------- -// -// DEBUGSTR -// -//--------------------------------------------------------------- -#if DEBUG -void DEBUGSTR(const char *format, ...) -{ - char mesg[2048]; - - va_list args; - - va_start(args, format); - vsprintf(mesg, format, args); - va_end(args); - - BreakStrToDebugger(mesg); -} -#endif - - -//--------------------------------------------------------------- -// -// TRACE -// -//--------------------------------------------------------------- -#if DEBUG -void TRACE(const char *format, ...) -{ - char mesg[2048]; - - va_list args; - - va_start(args, format); - vsprintf(mesg, format, args); - va_end(args); - - TraceString(mesg); -} -#endif // DEBUG - -//--------------------------------------------------------------- -// -// debug_prompt_for_monster -// -//--------------------------------------------------------------- -#ifdef WIZARD - -static int get_monnum(const char *name) -{ - char search[ITEMNAME_SIZE], - mname[ITEMNAME_SIZE]; - strncpy(search, name, sizeof search); - search[ITEMNAME_SIZE - 1] = 0; - strlwr(search); - - int mon = -1; - for (int i = 0; i < NUM_MONSTERS; i++) - { - moname( i, true, DESC_PLAIN, mname ); - - const char *ptr = strstr( strlwr(mname), search ); - if (ptr != NULL) - { - if (ptr == mname) - { - // we prefer prefixes over partial matches - mon = i; - break; - } - else - mon = i; - } - } - return (mon); -} - -static int debug_prompt_for_monster( void ) -{ - char specs[80]; - - mpr( "(Hint: 'generated' names, eg 'orc zombie', won't work)", MSGCH_PROMPT ); - mpr( "Which monster by name? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return (-1); - - return (get_monnum(specs)); -} -#endif - -//--------------------------------------------------------------- -// -// debug_prompt_for_skill -// -//--------------------------------------------------------------- -#ifdef WIZARD -static int debug_prompt_for_skill( const char *prompt ) -{ - char specs[80]; - - mpr( prompt, MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return (-1); - - int skill = -1; - - for (int i = 0; i < NUM_SKILLS; i++) - { - // avoid the bad values: - if (i == SK_UNUSED_1 || (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING)) - continue; - - char sk_name[80]; - strncpy( sk_name, skill_name(i), sizeof( sk_name ) ); - - char *ptr = strstr( strlwr(sk_name), strlwr(specs) ); - if (ptr != NULL) - { - if (ptr == sk_name && strlen(specs) > 0) - { - // we prefer prefixes over partial matches - skill = i; - break; - } - else - skill = i; - } - } - - return (skill); -} -#endif - -//--------------------------------------------------------------- -// -// debug_change_species -// -//--------------------------------------------------------------- -#ifdef WIZARD -void debug_change_species( void ) -{ - char specs[80]; - int i; - - mpr( "What species would you like to be now? " , MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return; - - int sp = -1; - - for (int i = SP_HUMAN; i < NUM_SPECIES; i++) - { - char sp_name[80]; - strncpy( sp_name, species_name(i, you.experience_level), sizeof( sp_name ) ); - - char *ptr = strstr( strlwr(sp_name), strlwr(specs) ); - if (ptr != NULL) - { - if (ptr == sp_name && strlen(specs) > 0) - { - // we prefer prefixes over partial matches - sp = i; - break; - } - else - sp = i; - } - } - - if (sp == -1) - mpr( "That species isn't available." ); - else - { - for (i = 0; i < NUM_SKILLS; i++) - { - you.skill_points[i] *= species_skills( i, sp ); - you.skill_points[i] /= species_skills( i, you.species ); - } - - you.species = sp; - - redraw_screen(); - } -} -#endif -//--------------------------------------------------------------- -// -// debug_prompt_for_int -// -// If nonneg, then it returns a non-negative number or -1 on fail -// If !nonneg, then it returns an integer, and 0 on fail -// -//--------------------------------------------------------------- -#ifdef WIZARD -static int debug_prompt_for_int( const char *prompt, bool nonneg ) -{ - char specs[80]; - - mpr( prompt, MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return (nonneg ? -1 : 0); - - char *end; - int ret = strtol( specs, &end, 10 ); - - if ((ret < 0 && nonneg) || (ret == 0 && end == specs)) - ret = (nonneg ? -1 : 0); - - return (ret); -} -#endif - -/* - Some debugging functions, accessable through keys like %, $, &, ) etc when - a section of code in input() in acr.cc is uncommented. - */ - -//--------------------------------------------------------------- -// -// cast_spec_spell -// -//--------------------------------------------------------------- -#ifdef WIZARD -void cast_spec_spell(void) -{ - int spell = debug_prompt_for_int( "Cast which spell by number? ", true ); - - if (spell == -1) - canned_msg( MSG_OK ); - else - your_spells( spell, 0, false ); -} -#endif - - -//--------------------------------------------------------------- -// -// cast_spec_spell_name -// -//--------------------------------------------------------------- -#ifdef WIZARD -void cast_spec_spell_name(void) -{ - int i = 0; - char specs[80]; - char spname[80]; - - mpr( "Cast which spell by name? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - for (i = 0; i < NUM_SPELLS; i++) - { - strncpy( spname, spell_title(i), sizeof( spname ) ); - - if (strstr( strlwr(spname), strlwr(specs) ) != NULL) - { - your_spells(i, 0, false); - return; - } - } - - mpr((one_chance_in(20)) ? "Maybe you should go back to WIZARD school." - : "I couldn't find that spell."); -} -#endif - - -//--------------------------------------------------------------- -// -// create_spec_monster -// -//--------------------------------------------------------------- -#ifdef WIZARD -void create_spec_monster(void) -{ - int mon = debug_prompt_for_int( "Create which monster by number? ", true ); - - if (mon == -1) - canned_msg( MSG_OK ); - else - create_monster( mon, 0, BEH_SLEEP, you.x_pos, you.y_pos, MHITNOT, 250 ); -} // end create_spec_monster() -#endif - - -//--------------------------------------------------------------- -// -// create_spec_monster_name -// -//--------------------------------------------------------------- -#ifdef WIZARD -void create_spec_monster_name(void) -{ - int mon = debug_prompt_for_monster(); - - if (mon == -1) - { - mpr("I couldn't find that monster."); - - if (one_chance_in(20)) - mpr("Maybe it's hiding."); - } - else - { - create_monster(mon, 0, BEH_SLEEP, you.x_pos, you.y_pos, MHITNOT, 250); - } -} // end create_spec_monster_name() -#endif - - -//--------------------------------------------------------------- -// -// level_travel -// -//--------------------------------------------------------------- -#ifdef WIZARD -void level_travel( int delta ) -{ - int old_level = you.your_level; - int new_level = you.your_level + delta; - - if (delta == 0) - { - new_level = debug_prompt_for_int( "Travel to which level? ", true ) - 1; - } - - if (new_level < 0 || new_level >= 50) - { - mpr( "That level is out of bounds." ); - return; - } - - you.your_level = new_level - 1; - grd[you.x_pos][you.y_pos] = DNGN_STONE_STAIRS_DOWN_I; - down_stairs(true, old_level); - untag_followers(); -} // end level_travel() -#endif - - -//--------------------------------------------------------------- -// -// create_spec_object -// -//--------------------------------------------------------------- -#ifdef WIZARD -void create_spec_object(void) -{ - static int max_subtype[] = - { - NUM_WEAPONS, - NUM_MISSILES, - NUM_ARMOURS, - NUM_WANDS, - NUM_FOODS, - 0, // unknown I - NUM_SCROLLS, - NUM_JEWELLERY, - NUM_POTIONS, - 0, // unknown II - NUM_BOOKS, - NUM_STAVES, - 0, // Orbs -- only one, handled specially - NUM_MISCELLANY, - 0, // corpses -- handled specially - 0, // gold -- handled specially - 0, // "gemstones" -- no items of type - }; - - char specs[80]; - char obj_name[ ITEMNAME_SIZE ]; - char keyin; - - char * ptr; - int best_index; - int mon; - int i; - - int class_wanted = OBJ_UNASSIGNED; - int type_wanted = -1; - int special_wanted = 0; - - int thing_created; - - for (;;) - { - mpr(") - weapons ( - missiles [ - armour / - wands ? - scrolls", - MSGCH_PROMPT); - mpr("= - jewellery ! - potions : - books | - staves 0 - The Orb", - MSGCH_PROMPT); - mpr("} - miscellany X - corpses %% - food $ - gold ESC - exit", - MSGCH_PROMPT); - - mpr("What class of item? ", MSGCH_PROMPT); - - keyin = toupper( get_ch() ); - - if (keyin == ')') - class_wanted = OBJ_WEAPONS; - else if (keyin == '(') - class_wanted = OBJ_MISSILES; - else if (keyin == '[' || keyin == ']') - class_wanted = OBJ_ARMOUR; - else if (keyin == '/' || keyin == '\\') - class_wanted = OBJ_WANDS; - else if (keyin == '?') - class_wanted = OBJ_SCROLLS; - else if (keyin == '=' || keyin == '"') - class_wanted = OBJ_JEWELLERY; - else if (keyin == '!') - class_wanted = OBJ_POTIONS; - else if (keyin == ':') - class_wanted = OBJ_BOOKS; - else if (keyin == '|') - class_wanted = OBJ_STAVES; - else if (keyin == '0' || keyin == 'O') - class_wanted = OBJ_ORBS; - else if (keyin == '}' || keyin == '{') - class_wanted = OBJ_MISCELLANY; - else if (keyin == 'X') - class_wanted = OBJ_CORPSES; - else if (keyin == '%') - class_wanted = OBJ_FOOD; - else if (keyin == '$') - class_wanted = OBJ_GOLD; - else if (keyin == ESCAPE || keyin == ' ' - || keyin == '\r' || keyin == '\n') - { - canned_msg( MSG_OK ); - return; - } - - if (class_wanted != OBJ_UNASSIGNED) - break; - } - - // allocate an item to play with: - thing_created = get_item_slot(); - if (thing_created == NON_ITEM) - { - mpr( "Could not allocate item." ); - return; - } - - // turn item into appropriate kind: - if (class_wanted == OBJ_ORBS) - { - mitm[thing_created].base_type = OBJ_ORBS; - mitm[thing_created].sub_type = ORB_ZOT; - mitm[thing_created].quantity = 1; - } - else if (class_wanted == OBJ_GOLD) - { - int amount = debug_prompt_for_int( "How much gold? ", true ); - if (amount <= 0) - { - canned_msg( MSG_OK ); - return; - } - - mitm[thing_created].base_type = OBJ_GOLD; - mitm[thing_created].sub_type = 0; - mitm[thing_created].quantity = amount; - } - else if (class_wanted == OBJ_CORPSES) - { - mon = debug_prompt_for_monster(); - - if (mon == -1) - { - mpr( "No such monster." ); - return; - } - - mitm[thing_created].base_type = OBJ_CORPSES; - mitm[thing_created].sub_type = CORPSE_BODY; - mitm[thing_created].plus = mon; - mitm[thing_created].plus2 = 0; - mitm[thing_created].special = 210; - mitm[thing_created].colour = mons_colour(mon);; - mitm[thing_created].quantity = 1; - mitm[thing_created].flags = 0; - } - else - { - mpr( "What type of item? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - { - canned_msg( MSG_OK ); - return; - } - - // In order to get the sub-type, we'll fill out the base type... - // then we're going to iterate over all possible subtype values - // and see if we get a winner. -- bwr - mitm[thing_created].base_type = class_wanted; - mitm[thing_created].sub_type = 0; - mitm[thing_created].plus = 0; - mitm[thing_created].plus2 = 0; - mitm[thing_created].special = 0; - mitm[thing_created].flags = 0; - mitm[thing_created].quantity = 1; - set_ident_flags( mitm[thing_created], ISFLAG_IDENT_MASK ); - - if (class_wanted == OBJ_ARMOUR) - { - if (strstr( "naga barding", specs )) - { - mitm[thing_created].sub_type = ARM_NAGA_BARDING; - } - else if (strstr( "centaur barding", specs )) - { - mitm[thing_created].sub_type = ARM_CENTAUR_BARDING; - } - else if (strstr( "wizard's hat", specs )) - { - mitm[thing_created].sub_type = ARM_HELMET; - mitm[thing_created].plus2 = THELM_WIZARD_HAT; - } - else if (strstr( "cap", specs )) - { - mitm[thing_created].sub_type = ARM_HELMET; - mitm[thing_created].plus2 = THELM_CAP; - } - else if (strstr( "helm", specs )) - { - mitm[thing_created].sub_type = ARM_HELMET; - mitm[thing_created].plus2 = THELM_HELM; - } - } - - if (!mitm[thing_created].sub_type) - { - type_wanted = -1; - best_index = 10000; - - for (i = 0; i < max_subtype[ mitm[thing_created].base_type ]; i++) - { - mitm[thing_created].sub_type = i; - item_name( mitm[thing_created], DESC_PLAIN, obj_name ); - - ptr = strstr( strlwr(obj_name), strlwr(specs) ); - if (ptr != NULL) - { - // earliest match is the winner - if (ptr - obj_name < best_index) - { - mpr( obj_name ); - type_wanted = i; - best_index = ptr - obj_name; - } - } - } - - if (type_wanted == -1) - { - // ds -- if specs is a valid int, try using that. - // Since zero is atoi's copout, the wizard - // must enter (subtype + 1). - if (!(type_wanted = atoi(specs))) - { - mpr( "No such item." ); - return; - } - type_wanted--; - } - - mitm[thing_created].sub_type = type_wanted; - } - - switch (mitm[thing_created].base_type) - { - case OBJ_MISSILES: - mitm[thing_created].quantity = 30; - // intentional fall-through - case OBJ_WEAPONS: - case OBJ_ARMOUR: - mpr( "What ego type? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] != '\0') - { - special_wanted = 0; - best_index = 10000; - - for (i = 1; i < 25; i++) - { - mitm[thing_created].special = i; - item_name( mitm[thing_created], DESC_PLAIN, obj_name ); - - ptr = strstr( strlwr(obj_name), strlwr(specs) ); - if (ptr != NULL) - { - // earliest match is the winner - if (ptr - obj_name < best_index) - { - mpr( obj_name ); - special_wanted = i; - best_index = ptr - obj_name; - } - } - } - - mitm[thing_created].special = special_wanted; - } - break; - - case OBJ_BOOKS: - if (mitm[thing_created].sub_type == BOOK_MANUAL) - { - special_wanted = debug_prompt_for_skill( "A manual for which skill? " ); - if (special_wanted != -1) - mitm[thing_created].plus = special_wanted; - else - mpr( "Sorry, no books on that skill today." ); - } - break; - - case OBJ_WANDS: - mitm[thing_created].plus = 24; - break; - - case OBJ_STAVES: - if (item_is_rod( mitm[thing_created] )) - { - mitm[thing_created].plus = MAX_ROD_CHARGE * ROD_CHARGE_MULT; - mitm[thing_created].plus2 = MAX_ROD_CHARGE * ROD_CHARGE_MULT; - } - break; - - case OBJ_MISCELLANY: - // Runes to "demonic", decks have 50 cards, ignored elsewhere? - mitm[thing_created].plus = 50; - break; - - case OBJ_FOOD: - case OBJ_SCROLLS: - case OBJ_POTIONS: - mitm[thing_created].quantity = 12; - break; - - default: - break; - } - } - - item_colour( mitm[thing_created] ); - - move_item_to_grid( &thing_created, you.x_pos, you.y_pos ); - - if (thing_created != NON_ITEM) - { - origin_acquired( mitm[thing_created], AQ_WIZMODE ); - canned_msg( MSG_SOMETHING_APPEARS ); - } -} -#endif - - -//--------------------------------------------------------------- -// -// create_spec_object -// -//--------------------------------------------------------------- -#ifdef WIZARD -void tweak_object(void) -{ - char specs[50]; - char keyin; - - int item = prompt_invent_item( "Tweak which item? ", -1 ); - if (item == PROMPT_ABORT) - { - canned_msg( MSG_OK ); - return; - } - - if (item == you.equip[EQ_WEAPON]) - you.wield_change = true; - - for (;;) - { - void *field_ptr = NULL; - - for (;;) - { - item_name( you.inv[item], DESC_INVENTORY_EQUIP, info ); - mpr( info ); - - mpr( "a - plus b - plus2 c - special d - quantity ESC - exit", - MSGCH_PROMPT ); - mpr( "Which field? ", MSGCH_PROMPT ); - - keyin = tolower( get_ch() ); - - if (keyin == 'a') - field_ptr = &(you.inv[item].plus); - else if (keyin == 'b') - field_ptr = &(you.inv[item].plus2); - else if (keyin == 'c') - field_ptr = &(you.inv[item].special); - else if (keyin == 'd') - field_ptr = &(you.inv[item].quantity); - else if (keyin == ESCAPE || keyin == ' ' - || keyin == '\r' || keyin == '\n') - { - canned_msg( MSG_OK ); - return; - } - - if (keyin >= 'a' && keyin <= 'd') - break; - } - - if (keyin != 'c') - { - const short *const ptr = static_cast< short * >( field_ptr ); - snprintf( info, INFO_SIZE, "Old value: %d (0x%04x)", *ptr, *ptr ); - } - else - { - const long *const ptr = static_cast< long * >( field_ptr ); - snprintf( info, INFO_SIZE, "Old value: %ld (0x%08lx)", *ptr, *ptr ); - } - - mpr( info ); - - mpr( "New value? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return; - - char *end; - int new_value = strtol( specs, &end, 10 ); - - if (new_value == 0 && end == specs) - return; - - if (keyin != 'c') - { - short *ptr = static_cast< short * >( field_ptr ); - *ptr = new_value; - } - else - { - long *ptr = static_cast< long * >( field_ptr ); - *ptr = new_value; - } - } -} -#endif - - -//--------------------------------------------------------------- -// -// stethoscope -// -//--------------------------------------------------------------- -#if DEBUG_DIAGNOSTICS - -static const char *enchant_names[] = -{ - "None", - "Slow", "Haste", "*BUG-3*", "Fear", "Conf", "Invis", - "YPois-1", "YPois-2", "YPois-3", "YPois-4", - "YShug-1", "YShug-2", "YShug-3", "YShug-4", - "YRot-1", "YRot-2", "YRot-3", "YRot-4", - "Summon", "Abj-1", "Abj-2", "Abj-3", "Abj-4", "Abj-5", "Abj-6", - "Corona-1", "Corona-2", "Corona-3", "Corona-4", - "Charm", "YSticky-1", "YSticky-2", "YSticky-3", "YSticky-4", - "*BUG-35*", "*BUG-36*", "*BUG-37*", - "GlowShapeshifter", "Shapeshifter", - "Tele-1", "Tele-2", "Tele-3", "Tele-4", - "*BUG-44*", "*BUG-45*", "*BUG-46*", "*BUG-47*", "*BUG-48*", "*BUG-49*", - "*BUG-50*", "*BUG-51*", "*BUG-52*", "*BUG-53*", "*BUG-54*", "*BUG-55*", - "*BUG-56*", - "Pois-1", "Pois-2", "Pois-3", "Pois-4", - "Sticky-1", "Sticky-2", "Sticky-3", "Sticky-4", - "OldAbj-1", "OldAbj-2", "OldAbj-3", "OldAbj-4", "OldAbj-5", "OldAbj-6", - "OldCreatedFriendly", "SleepWary", "Submerged", "Short Lived", - "*BUG-too big*" -}; - -void stethoscope(int mwh) -{ - struct dist stth; - int steth_x, steth_y; - int i, j; - - if (mwh != RANDOM_MONSTER) - i = mwh; - else - { - mpr( "Which monster?", MSGCH_PROMPT ); - - direction( stth ); - - if (!stth.isValid) - return; - - if (stth.isTarget) - { - steth_x = stth.tx; - steth_y = stth.ty; - } - else - { - steth_x = you.x_pos + stth.dx; - steth_y = you.x_pos + stth.dy; - } - - if (env.cgrid[steth_x][steth_y] != EMPTY_CLOUD) - { - snprintf( info, INFO_SIZE, "cloud type: %d delay: %d", - env.cloud[ env.cgrid[steth_x][steth_y] ].type, - env.cloud[ env.cgrid[steth_x][steth_y] ].decay ); - - mpr( info, MSGCH_DIAGNOSTICS ); - } - - if (mgrd[steth_x][steth_y] == NON_MONSTER) - { - snprintf( info, INFO_SIZE, "item grid = %d", igrd[steth_x][steth_y] ); - mpr( info, MSGCH_DIAGNOSTICS ); - return; - } - - i = mgrd[steth_x][steth_y]; - } - - // print type of monster - snprintf( info, INFO_SIZE, "%s (id #%d; type=%d loc=(%d,%d) align=%s)", - monam( menv[i].number, menv[i].type, true, DESC_CAP_THE ), - i, menv[i].type, - menv[i].x, menv[i].y, - ((menv[i].attitude == ATT_FRIENDLY) ? "friendly" : - (menv[i].attitude == ATT_HOSTILE) ? "hostile" : - (menv[i].attitude == ATT_NEUTRAL) ? "neutral" - : "unknown alignment") ); - - mpr( info, MSGCH_DIAGNOSTICS ); - - // print stats and other info - snprintf( info, INFO_SIZE,"HD=%d HP=%d/%d AC=%d EV=%d MR=%d SP=%d energy=%d num=%d flags=%02x", - menv[i].hit_dice, - menv[i].hit_points, menv[i].max_hit_points, - menv[i].armour_class, menv[i].evasion, - mons_resist_magic( &menv[i] ), - menv[i].speed, menv[i].speed_increment, - menv[i].number, menv[i].flags ); - - mpr( info, MSGCH_DIAGNOSTICS ); - - // print behaviour information - - const int hab = monster_habitat( menv[i].type ); - - snprintf( info, INFO_SIZE, "hab=%s beh=%s(%d) foe=%s(%d) mem=%d target=(%d,%d)", - ((hab == DNGN_DEEP_WATER) ? "water" : - (hab == DNGN_LAVA) ? "lava" - : "floor"), - - ((menv[i].behaviour == BEH_SLEEP) ? "sleep" : - (menv[i].behaviour == BEH_WANDER) ? "wander" : - (menv[i].behaviour == BEH_SEEK) ? "seek" : - (menv[i].behaviour == BEH_FLEE) ? "flee" : - (menv[i].behaviour == BEH_CORNERED) ? "cornered" - : "unknown"), - menv[i].behaviour, - - ((menv[i].foe == MHITYOU) ? "you" : - (menv[i].foe == MHITNOT) ? "none" : - (menv[menv[i].foe].type == -1) ? "unassigned monster" - : monam( menv[menv[i].foe].number, menv[menv[i].foe].type, - true, DESC_PLAIN )), - menv[i].foe, - menv[i].foe_memory, - - menv[i].target_x, menv[i].target_y ); - - mpr( info, MSGCH_DIAGNOSTICS ); - - // print resistances - snprintf( info, INFO_SIZE, "resist: fire=%d cold=%d elec=%d pois=%d neg=%d", - mons_res_fire( &menv[i] ), - mons_res_cold( &menv[i] ), - mons_res_elec( &menv[i] ), - mons_res_poison( &menv[i] ), - mons_res_negative_energy( &menv[i] ) ); - - mpr( info, MSGCH_DIAGNOSTICS ); - - - // print enchantments - strncpy( info, "ench: ", INFO_SIZE ); - for (j = 0; j < 6; j++) - { - if (menv[i].enchantment[j] >= NUM_ENCHANTMENTS) - strncat( info, enchant_names[ NUM_ENCHANTMENTS ], INFO_SIZE ); - else - strncat( info, enchant_names[ menv[i].enchantment[j] ], INFO_SIZE ); - - if (strlen( info ) <= 70) - strncat( info, " ", INFO_SIZE ); - else if (j < 5) - { - mpr( info, MSGCH_DIAGNOSTICS ); - strncpy( info, "ench: ", INFO_SIZE ); - } - } - - mpr( info, MSGCH_DIAGNOSTICS ); - - if (menv[i].type == MONS_PLAYER_GHOST - || menv[i].type == MONS_PANDEMONIUM_DEMON) - { - snprintf( info, INFO_SIZE, "Ghost damage: %d; brand: %d", - ghost.values[ GVAL_DAMAGE ], ghost.values[ GVAL_BRAND ] ); - mpr( info, MSGCH_DIAGNOSTICS ); - } -} // end stethoscope() -#endif - -#if DEBUG_ITEM_SCAN -//--------------------------------------------------------------- -// -// dump_item -// -//--------------------------------------------------------------- -static void dump_item( const char *name, int num, const item_def &item ) -{ - mpr( name, MSGCH_WARN ); - - snprintf( info, INFO_SIZE, " item #%d: base: %d; sub: %d; plus: %d; plus2: %d; special: %ld", - num, item.base_type, item.sub_type, - item.plus, item.plus2, item.special ); - - mpr( info ); - - snprintf( info, INFO_SIZE, " quant: %d; colour: %d; ident: 0x%08lx; ident_type: %d", - item.quantity, item.colour, item.flags, - get_ident_type( item.base_type, item.sub_type ) ); - - mpr( info ); - - snprintf( info, INFO_SIZE, " x: %d; y: %d; link: %d", - item.x, item.y, item.link ); - - mpr( info ); -} - -//--------------------------------------------------------------- -// -// debug_item_scan -// -//--------------------------------------------------------------- -void debug_item_scan( void ) -{ - int i; - char name[256]; - - // unset marks - for (i = 0; i < MAX_ITEMS; i++) - mitm[i].flags &= (~ISFLAG_DEBUG_MARK); - - // First we're going to check all the stacks on the level: - for (int x = 0; x < GXM; x++) - { - for (int y = 0; y < GYM; y++) - { - // These are unlinked monster inventory items -- skip them: - if (x == 0 && y == 0) - continue; - - // Looking for infinite stacks (ie more links than tems allowed) - // and for items which have bad coordinates (can't find their stack) - for (int obj = igrd[x][y]; obj != NON_ITEM; obj = mitm[obj].link) - { - // Check for invalid (zero quantity) items that are linked in - if (!is_valid_item( mitm[obj] )) - { - snprintf( info, INFO_SIZE, "Linked invalid item at (%d,%d)!", x, y); - mpr( info, MSGCH_WARN ); - item_name( mitm[obj], DESC_PLAIN, name ); - dump_item( name, obj, mitm[obj] ); - } - - // Check that item knows what stack it's in - if (mitm[obj].x != x || mitm[obj].y != y) - { - snprintf( info, INFO_SIZE, "Item position incorrect at (%d,%d)!", x, y); - mpr( info, MSGCH_WARN ); - item_name( mitm[obj], DESC_PLAIN, name ); - dump_item( name, obj, mitm[obj] ); - } - - // If we run into a premarked item we're in real trouble, - // this will also keep this from being an infinite loop. - if (mitm[obj].flags & ISFLAG_DEBUG_MARK) - { - snprintf( info, INFO_SIZE, "Potential INFINITE STACK at (%d, %d)", x, y); - mpr( info, MSGCH_WARN ); - break; - } - - mitm[obj].flags |= ISFLAG_DEBUG_MARK; - } - } - } - - // Now scan all the items on the level: - for (i = 0; i < MAX_ITEMS; i++) - { - if (!is_valid_item( mitm[i] )) - continue; - - item_name( mitm[i], DESC_PLAIN, name ); - - // Don't check (-1,-1) player items or (0,0) monster items - if ((mitm[i].x > 0 || mitm[i].y > 0) - && !(mitm[i].flags & ISFLAG_DEBUG_MARK)) - { - mpr( "Unlinked item:", MSGCH_WARN ); - dump_item( name, i, mitm[i] ); - - snprintf( info, INFO_SIZE, "igrd(%d,%d) = %d", mitm[i].x, mitm[i].y, - igrd[ mitm[i].x ][ mitm[i].y ] ); - mpr( info ); - - // Let's check to see if it's an errant monster object: - for (int j = 0; j < MAX_MONSTERS; j++) - { - for (int k = 0; k < NUM_MONSTER_SLOTS; k++) - { - if (menv[j].inv[k] == i) - { - snprintf( info, INFO_SIZE, "Held by monster #%d: %s at (%d,%d)", - j, ptr_monam( &menv[j], DESC_CAP_A ), - menv[j].x, menv[j].y ); - - mpr( info ); - } - } - } - } - - // Current bad items of interest: - // -- armour and weapons with large enchantments/illegal special vals - // - // -- items described as questionable (the class 100 bug) - // - // -- eggplant is an illegal throwing weapon - // - // -- bola is an illegal fixed artefact - // - // -- items described as buggy (typically adjectives out of range) - // (note: covers buggy, bugginess, buggily, whatever else) - // - if (strstr( name, "questionable" ) != NULL - || strstr( name, "eggplant" ) != NULL - || strstr( name, "bola" ) != NULL - || strstr( name, "bugg" ) != NULL) - { - mpr( "Bad item:", MSGCH_WARN ); - dump_item( name, i, mitm[i] ); - } - else if ((mitm[i].base_type == OBJ_WEAPONS - && (abs(mitm[i].plus) > 30 - || abs(mitm[i].plus2) > 30 - || (!is_random_artefact( mitm[i] ) - && (mitm[i].special >= 30 - && mitm[i].special < 181)))) - - || (mitm[i].base_type == OBJ_MISSILES - && (abs(mitm[i].plus) > 25 - || (!is_random_artefact( mitm[i] ) - && mitm[i].special >= 30))) - - || (mitm[i].base_type == OBJ_ARMOUR - && (abs(mitm[i].plus) > 25 - || (!is_random_artefact( mitm[i] ) - && mitm[i].sub_type != ARM_HELMET - && mitm[i].special >= 30)))) - { - mpr( "Bad plus or special value:", MSGCH_WARN ); - dump_item( name, i, mitm[i] ); - } - } - - // Don't want debugging marks interfering with anything else. - for (i = 0; i < MAX_ITEMS; i++) - mitm[i].flags &= (~ISFLAG_DEBUG_MARK); - - // Quickly scan monsters for "program bug"s. - for (i = 0; i < MAX_MONSTERS; i++) - { - const struct monsters *const monster = &menv[i]; - - if (monster->type == -1) - continue; - - moname( monster->type, true, DESC_PLAIN, name ); - - if (strcmp( name, "program bug" ) == 0) - { - mpr( "Program bug detected!", MSGCH_WARN ); - - snprintf( info, INFO_SIZE, - "Buggy monster detected: monster #%d; position (%d,%d)", - i, monster->x, monster->y ); - - mpr( info, MSGCH_WARN ); - } - } -} -#endif - -//--------------------------------------------------------------- -// -// debug_add_skills -// -//--------------------------------------------------------------- -#ifdef WIZARD -void debug_add_skills(void) -{ - int skill = debug_prompt_for_skill( "Which skill (by name)? " ); - - if (skill == -1) - mpr("That skill doesn't seem to exist."); - else - { - mpr("Exercising..."); - exercise(skill, 100); - } -} // end debug_add_skills() -#endif - -//--------------------------------------------------------------- -// -// debug_set_skills -// -//--------------------------------------------------------------- -#ifdef WIZARD -void debug_set_skills(void) -{ - int skill = debug_prompt_for_skill( "Which skill (by name)? " ); - - if (skill == -1) - mpr("That skill doesn't seem to exist."); - else - { - mpr( skill_name(skill) ); - int amount = debug_prompt_for_int( "To what level? ", true ); - - if (amount == -1) - canned_msg( MSG_OK ); - else - { - const int points = (skill_exp_needed( amount + 1 ) - * species_skills( skill, you.species )) / 100; - - you.skill_points[skill] = points + 1; - you.skills[skill] = amount; - - calc_total_skill_points(); - - redraw_skill( you.your_name, player_title() ); - - switch (skill) - { - case SK_FIGHTING: - calc_hp(); - break; - - case SK_SPELLCASTING: - case SK_INVOCATIONS: - case SK_EVOCATIONS: - calc_mp(); - break; - - case SK_DODGING: - you.redraw_evasion = 1; - break; - - case SK_ARMOUR: - you.redraw_armour_class = 1; - you.redraw_evasion = 1; - break; - - default: - break; - } - } - } -} // end debug_add_skills() -#endif - - -//--------------------------------------------------------------- -// -// debug_set_all_skills -// -//--------------------------------------------------------------- -#ifdef WIZARD -void debug_set_all_skills(void) -{ - int i; - int amount = debug_prompt_for_int( "Set all skills to what level? ", true ); - - if (amount < 0) // cancel returns -1 -- bwr - canned_msg( MSG_OK ); - else - { - if (amount > 27) - amount = 27; - - for (i = SK_FIGHTING; i < NUM_SKILLS; i++) - { - if (i == SK_UNUSED_1 - || (i > SK_UNARMED_COMBAT && i < SK_SPELLCASTING)) - { - continue; - } - - const int points = (skill_exp_needed( amount + 1 ) - * species_skills( i, you.species )) / 100; - - you.skill_points[i] = points + 1; - you.skills[i] = amount; - } - - redraw_skill( you.your_name, player_title() ); - - calc_total_skill_points(); - - calc_hp(); - calc_mp(); - - you.redraw_armour_class = 1; - you.redraw_evasion = 1; - } -} // end debug_add_skills() -#endif - - -//--------------------------------------------------------------- -// -// debug_add_mutation -// -//--------------------------------------------------------------- -#ifdef WIZARD -bool debug_add_mutation(void) -{ - bool success = false; - char specs[80]; - - // Yeah, the gaining message isn't too good for this... but - // there isn't an array of simple mutation names. -- bwr - mpr( "Which mutation (by message when getting mutation)? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return (false); - - int mutation = -1; - - for (int i = 0; i < NUM_MUTATIONS; i++) - { - char mut_name[80]; - strncpy( mut_name, mutation_name( i, 1 ), sizeof( mut_name ) ); - - char *ptr = strstr( strlwr(mut_name), strlwr(specs) ); - if (ptr != NULL) - { - // we take the first mutation that matches - mutation = i; - break; - } - } - - if (mutation == -1) - mpr("I can't warp you that way!"); - else - { - snprintf( info, INFO_SIZE, "Found: %s", mutation_name( mutation, 1 ) ); - mpr( info ); - - int levels = debug_prompt_for_int( "How many levels? ", false ); - - if (levels == 0) - { - canned_msg( MSG_OK ); - success = false; - } - else if (levels > 0) - { - for (int i = 0; i < levels; i++) - { - if (mutate( mutation )) - success = true; - } - } - else - { - for (int i = 0; i < -levels; i++) - { - if (delete_mutation( mutation )) - success = true; - } - } - } - - return (success); -} // end debug_add_mutation() -#endif - - -//--------------------------------------------------------------- -// -// debug_get_religion -// -//--------------------------------------------------------------- -#ifdef WIZARD -void debug_get_religion(void) -{ - char specs[80]; - - mpr( "Which god (by name)? ", MSGCH_PROMPT ); - get_input_line( specs, sizeof( specs ) ); - - if (specs[0] == '\0') - return; - - int god = -1; - - for (int i = 1; i < NUM_GODS; i++) - { - char name[80]; - strncpy( name, god_name(i), sizeof( name ) ); - - char *ptr = strstr( strlwr(name), strlwr(specs) ); - if (ptr != NULL) - { - god = i; - break; - } - } - - if (god == -1) - mpr( "That god doesn't seem to be taking followers today." ); - else - { - grd[you.x_pos][you.y_pos] = 179 + god; - god_pitch(god); - } -} // end debug_add_skills() -#endif - - -void error_message_to_player(void) -{ - mpr("Oh dear. There appears to be a bug in the program."); - mpr("I suggest you leave this level then save as soon as possible."); - -} // end error_message_to_player() - -#ifdef WIZARD - -static int create_fsim_monster(int mtype, int hp) -{ - const int mi = - create_monster( mtype, 0, BEH_HOSTILE, you.x_pos, you.y_pos, - MHITNOT, 250 ); - - if (mi == -1) - return (mi); - - monsters *mon = &menv[mi]; - mon->hit_points = mon->max_hit_points = hp; - return (mi); -} - -static skill_type fsim_melee_skill(const item_def *item) -{ - skill_type sk = SK_UNARMED_COMBAT; - if (item) - sk = weapon_skill(*item); - return (sk); -} - -static void fsim_set_melee_skill(int skill, const item_def *item) -{ - you.skills[fsim_melee_skill(item)] = skill; - you.skills[SK_FIGHTING] = skill * 15 / 27; -} - -static void fsim_set_ranged_skill(int skill, const item_def *item) -{ - you.skills[range_skill(*item)] = skill; - you.skills[SK_RANGED_COMBAT] = skill * 15 / 27; -} - -static void fsim_item(FILE *out, - bool melee, - const item_def *weap, - int wskill, unsigned long damage, - long iterations, long hits, - int maxdam, unsigned long time) -{ - double hitdam = hits? double(damage) / hits : 0.0; - int avspeed = (int) (time / iterations); - fprintf(out, " %2d | %3ld%% | %5.2f | %5.2f | %5.2f | %3d | %2ld\n", - wskill, - 100 * hits / iterations, - double(damage) / iterations, - hitdam, - double(damage) * player_speed() / avspeed / iterations, - maxdam, - time / iterations); -} - -static bool fsim_ranged_combat(FILE *out, int wskill, int mi, - const item_def *item, int missile_slot) -{ - monsters &mon = menv[mi]; - unsigned long cumulative_damage = 0L; - unsigned long time_taken = 0L; - long hits = 0L; - int maxdam = 0; - - const int thrown = missile_slot == -1? get_fire_item_index() : missile_slot; - if (thrown == ENDOFPACK || thrown == -1) - { - mprf("No suitable missiles for combat simulation."); - return (false); - } - - fsim_set_ranged_skill(wskill, item); - - no_messages mx; - const long iter_limit = Options.fsim_rounds; - const int hunger = you.hunger; - for (long i = 0; i < iter_limit; ++i) - { - mon.hit_points = mon.max_hit_points; - bolt beam; - you.time_taken = player_speed(); - if (throw_it(beam, thrown, &mon)) - hits++; - you.hunger = hunger; - time_taken += you.time_taken; - - int damage = (mon.max_hit_points - mon.hit_points); - cumulative_damage += damage; - if (damage > maxdam) - maxdam = damage; - } - fsim_item(out, false, item, wskill, cumulative_damage, - iter_limit, hits, maxdam, time_taken); - - return (true); -} - -static bool fsim_melee_combat(FILE *out, int wskill, int mi, - const item_def *item) -{ - monsters &mon = menv[mi]; - unsigned long cumulative_damage = 0L; - unsigned long time_taken = 0L; - long hits = 0L; - int maxdam = 0; - - fsim_set_melee_skill(wskill, item); - - no_messages mx; - const long iter_limit = Options.fsim_rounds; - const int hunger = you.hunger; - for (long i = 0; i < iter_limit; ++i) - { - mon.hit_points = mon.max_hit_points; - you.time_taken = player_speed(); - if (you_attack(mi, true)) - hits++; - - you.hunger = hunger; - time_taken += you.time_taken; - - int damage = (mon.max_hit_points - mon.hit_points); - cumulative_damage += damage; - if (damage > maxdam) - maxdam = damage; - } - fsim_item(out, true, item, wskill, cumulative_damage, iter_limit, hits, - maxdam, time_taken); - - return (true); -} - -static bool debug_fight_simulate(FILE *out, int wskill, int mi, int miss_slot) -{ - int weapon = you.equip[EQ_WEAPON]; - const item_def *iweap = weapon != -1? &you.inv[weapon] : NULL; - - if (iweap && iweap->base_type == OBJ_WEAPONS - && is_range_weapon(*iweap)) - return fsim_ranged_combat(out, wskill, mi, iweap, miss_slot); - else - return fsim_melee_combat(out, wskill, mi, iweap); -} - -static const item_def *fsim_weap_item() -{ - const int weap = you.equip[EQ_WEAPON]; - if (weap == -1) - return NULL; - - return &you.inv[weap]; -} - -static std::string fsim_wskill() -{ - const item_def *iweap = fsim_weap_item(); - return iweap && iweap->base_type == OBJ_WEAPONS - && is_range_weapon(*iweap)? - skill_name( range_skill(*iweap) ) : - iweap? skill_name( fsim_melee_skill(iweap) ) : - skill_name( SK_UNARMED_COMBAT ); -} - -static std::string fsim_weapon(int missile_slot) -{ - char item_buf[ITEMNAME_SIZE]; - if (you.equip[EQ_WEAPON] != -1) - { - const item_def &weapon = you.inv[ you.equip[EQ_WEAPON] ]; - item_name(weapon, DESC_PLAIN, item_buf, true); - - if (is_range_weapon(weapon)) - { - const int missile = - missile_slot == -1? get_fire_item_index() : - missile_slot; - if (missile < ENDOFPACK) - { - std::string base = item_buf; - base += " with "; - in_name(missile, DESC_PLAIN, item_buf, true); - return (base + item_buf); - } - } - } - else - { - strncpy(item_buf, "unarmed", sizeof item_buf); - } - return (item_buf); -} - -static std::string fsim_time_string() -{ - time_t curr_time = time(NULL); - struct tm *ltime = localtime(&curr_time); - if (ltime) - { - char buf[100]; - snprintf(buf, sizeof buf, "%4d%02d%02d/%2d:%02d:%02d", - ltime->tm_year + 1900, - ltime->tm_mon + 1, - ltime->tm_mday, - ltime->tm_hour, - ltime->tm_min, - ltime->tm_sec); - return (buf); - } - return (""); -} - -static void fsim_mon_stats(FILE *o, const monsters &mon) -{ - char buf[ITEMNAME_SIZE]; - fprintf(o, "Monster : %s\n", - moname(mon.type, true, DESC_PLAIN, buf)); - fprintf(o, "HD : %d\n", mon.hit_dice); - fprintf(o, "AC : %d\n", mon.armour_class); - fprintf(o, "EV : %d\n", mon.evasion); -} - -static void fsim_title(FILE *o, int mon, int ms) -{ - char buf[ITEMNAME_SIZE]; - fprintf(o, "Dungeon Crawl Stone Soup version " VERSION "\n\n"); - fprintf(o, "Combat simulation: %s %s vs. %s (%ld rounds) (%s)\n", - species_name(you.species, you.experience_level), - you.class_name, - moname(menv[mon].type, true, DESC_PLAIN, buf), - Options.fsim_rounds, - fsim_time_string().c_str()); - fprintf(o, "Experience: %d\n", you.experience_level); - fprintf(o, "Strength : %d\n", you.strength); - fprintf(o, "Intel. : %d\n", you.intel); - fprintf(o, "Dexterity : %d\n", you.dex); - fprintf(o, "Base speed: %d\n", player_speed()); - fprintf(o, "\n"); - fsim_mon_stats(o, menv[mon]); - fprintf(o, "\n"); - fprintf(o, "Weapon : %s\n", fsim_weapon(ms).c_str()); - fprintf(o, "Skill : %s\n", fsim_wskill().c_str()); - fprintf(o, "\n"); - fprintf(o, "Skill | Accuracy | Av.Dam | Av.HitDam | Eff.Dam | Max.Dam | Av.Time\n"); -} - -static int fsim_stat(int stat) -{ - return (stat < 1 ? 1 : - stat > 60 ? 60 : - stat); -} - -static bool debug_fight_sim(int mindex, int missile_slot) -{ - FILE *ostat = fopen("fight.stat", "a"); - if (!ostat) - { - mprf("Can't write fight.stat: %s", strerror(errno)); - return (false); - } - - bool success = true; - FixedVector<unsigned char, 50> skill_backup = you.skills; - int ystr = you.strength, - yint = you.intel, - ydex = you.dex; - int yxp = you.experience_level; - - for (int i = SK_FIGHTING; i < NUM_SKILLS; ++i) - you.skills[i] = 0; - - you.experience_level = Options.fsim_xl; - if (you.experience_level < 1) - you.experience_level = 1; - if (you.experience_level > 27) - you.experience_level = 27; - - you.strength = fsim_stat(Options.fsim_str); - you.intel = fsim_stat(Options.fsim_int); - you.dex = fsim_stat(Options.fsim_dex); - - fsim_title(ostat, mindex, missile_slot); - for (int wskill = 0; wskill <= 27; ++wskill) - { - mesclr(); - mprf("Calculating average damage for %s at skill %d", - fsim_weapon(missile_slot).c_str(), wskill); - if (!debug_fight_simulate(ostat, wskill, mindex, missile_slot)) - goto done_combat_sim; - - fflush(ostat); - // Not checking in the combat loop itself; that would be more responsive - // for the user, but slow down the sim with all the calls to kbhit(). - if (kbhit() && getch() == 27) - { - success = false; - mprf("Canceling simulation\n"); - goto done_combat_sim; - } - } - you.skills = skill_backup; - you.strength = ystr; - you.intel = yint; - you.dex = ydex; - you.experience_level = yxp; - - mprf("Done fight simulation with %s", fsim_weapon(missile_slot).c_str()); - -done_combat_sim: - fprintf(ostat, "-----------------------------------\n\n"); - fclose(ostat); - - return (success); -} - -int fsim_kit_equip(const std::string &kit) -{ - int missile_slot = -1; - char item_buf[ITEMNAME_SIZE]; - - std::string::size_type ammo_div = kit.find("/"); - std::string weapon = kit; - std::string missile; - if (ammo_div != std::string::npos) - { - weapon = kit.substr(0, ammo_div); - missile = kit.substr(ammo_div + 1); - trim_string(weapon); - trim_string(missile); - } - - for (int i = 0; i < ENDOFPACK; ++i) - { - if (!is_valid_item(you.inv[i])) - continue; - - in_name(i, DESC_PLAIN, item_buf, true); - if (std::string(item_buf).find(weapon) != std::string::npos) - { - if (i != you.equip[EQ_WEAPON]) - { - wield_weapon(true, i, false); - if (i != you.equip[EQ_WEAPON]) - return -100; - } - break; - } - } - - if (!missile.empty()) - { - for (int i = 0; i < ENDOFPACK; ++i) - { - if (!is_valid_item(you.inv[i])) - continue; - - in_name(i, DESC_PLAIN, item_buf, true); - if (std::string(item_buf).find(missile) != std::string::npos) - { - missile_slot = i; - break; - } - } - } - - return (missile_slot); -} - -// Writes statistics about a fight to fight.stat in the current directory. -// For fight purposes, a punching bag is summoned and given lots of hp, and the -// average damage the player does to the p. bag over 10000 hits is noted, -// advancing the weapon skill from 0 to 27, and keeping fighting skill to 2/5 -// of current weapon skill. -void debug_fight_statistics(bool use_defaults) -{ - int punching_bag = get_monnum(Options.fsim_mons.c_str()); - if (punching_bag == -1) - punching_bag = MONS_WORM; - - int mindex = create_fsim_monster(punching_bag, 500); - if (mindex == -1) - { - mprf("Failed to create punching bag"); - return; - } - - if (!use_defaults) - { - debug_fight_sim(mindex, -1); - goto fsim_mcleanup; - } - - for (int i = 0, size = Options.fsim_kit.size(); i < size; ++i) - { - int missile = fsim_kit_equip(Options.fsim_kit[i]); - if (missile == -100) - { - mprf("Aborting sim on %s", Options.fsim_kit[i].c_str()); - goto fsim_mcleanup; - } - if (!debug_fight_sim(mindex, missile)) - break; - } -fsim_mcleanup: - monster_die(&menv[mindex], KILL_DISMISSED, 0); -} -#endif |