finalize revision 0.032
[SwashRL.git] / src / iomain.d
blob1f05ca505b0d6a6af01d49ac2a02fd41bc3f2855
1 /*
2 * Copyright (c) 2015-2020 Philip Pavlick. See '3rdparty.txt' for other
3 * licenses. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the SwashRL project nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 // iomain.d: Defines functions related to program output (graphics, &c)
31 import global;
33 // This interface is the skeleton for all of the different display modes.
35 // The various input/output modules for SwashRL are stored in classes which
36 // inherit from this interface. The interface itself defines certain
37 // functions which are universal to all of the other modules.
38 interface SwashIO
41 // SECTION 1: ////////////////////////////////////////////////////////////////
42 // Setup & Cleanup //
43 //////////////////////////////////////////////////////////////////////////////
45 // Performs final cleanup functions for the input/output module, to close
46 // the display before exiting the program.
47 void cleanup();
49 // Used to determine if the "close window" button has been pressed.
51 // This is only useful for the SDL interfaces, because the curses interface
52 // works in the terminal.
54 // The function is used to instruct the mainloop to close the program in the
55 // event that the player is trapped in an input loop.
56 bool window_closed();
58 // SECTION 2: ////////////////////////////////////////////////////////////////
59 // Input //
60 //////////////////////////////////////////////////////////////////////////////
62 // Gets a character input from the user and returns it.
63 char get_key();
65 // Outputs a question to the user and returns a `char` result based on their
66 // answer.
67 char ask( string question, char[] options = ['y', 'n'],
68 bool assume_lower = false );
70 // SECTION 3: ////////////////////////////////////////////////////////////////
71 // Output //
72 //////////////////////////////////////////////////////////////////////////////
74 // General Output //////////////////////////////////////////////////////////
76 // Clears the screen.
77 void clear_screen();
79 // Refreshes the screen to reflect the changes made by the below `display`
80 // functions.
81 void refresh_screen();
83 // Outputs a text character at the given coordinates.
84 void put_char( uint y, uint x, char c,
85 Colors color = Colors.Default );
87 // The central display function: displays a given symbol at the given
88 // coordinates. Equivalent to `mvputch` in curses.
89 void display( uint y, uint x, Symbol s, bool center = true );
91 // The Message Line ////////////////////////////////////////////////////////
93 // Clears the current message off the message line.
94 void clear_message_line();
96 // Outputs all of the messages in the message queue.
97 void read_messages();
99 // Gives the player a menu containing their message history.
100 void read_message_history();
102 // The Status Bar //////////////////////////////////////////////////////////
104 // Refreshes the status bar.
105 void refresh_status_bar( Player* u );
107 // SECTION 4: ////////////////////////////////////////////////////////////////
108 // Global Input Functions //
109 //////////////////////////////////////////////////////////////////////////////
111 // Player Movement / Commands //////////////////////////////////////////////
113 // Takes in a `char` input from the player and returns a movement flag
114 // appropriate to the input.
115 final uint get_command()
117 char c = get_key();
119 // First check if `c' is contained in the player's keymap (see `keymap.d')
120 uint* cmd = (c in Keymaps[Current_keymap]);
122 // If so, return the appropriate command:
123 if( cmd !is null )
124 { return Keymaps[Current_keymap].get( c, MOVE_UNKNOWN );
127 // If not, check the standard prompts:
128 switch( c )
131 // Number pad keys:
132 case '7':
133 return MOVE_NW;
134 case '8':
135 return MOVE_NN;
136 case '9':
137 return MOVE_NE;
138 case '6':
139 return MOVE_EE;
140 case '3':
141 return MOVE_SE;
142 case '2':
143 return MOVE_SS;
144 case '1':
145 return MOVE_SW;
146 case '4':
147 return MOVE_WW;
148 case '5':
149 return MOVE_WAIT;
151 // If it's not in any of the standard controls or the number pad
152 // controls, check the "admin keys":
153 case 'Q':
154 return MOVE_QUIT;
155 case 'v':
156 return MOVE_GETVERSION;
157 case '@':
158 return MOVE_ALTKEYS;
159 case '?':
160 return MOVE_HELP;
162 default:
163 // Handle the default case outside this switch statement
164 break;
166 } // switch( c )
168 // If none of the above command prompts match, default to the "command
169 // not recognized" response.
170 return MOVE_UNKNOWN;
172 } // int get_command
174 // Inventory / Equipment Screen ////////////////////////////////////////////
176 // Display the inventory screen and allow the user to move items from their
177 // bag into an equipment slot.
178 final bool manage_inventory( Player* u )
180 import std.ascii: toLower;
182 // Whether to communicate to the calling function to refresh the screen
183 // after managing the inventory. Depending on what goes down in here, it
184 // may be beneficial to let this function draw the screen itself so it can
185 // display its own error messages.
186 bool refnow = true;
188 // `grab` and `line` here perform much the same functions they do in
189 // `control_inventory`
190 char grab = '\0';
191 int line = -1;
196 // Clear the screen and display a new menu with the items in the
197 // bag
198 display_inventory( u );
200 // `last_i_sym` is the character that comes _after_ the last
201 // item in the inventory. This variable is used to determine
202 // which characters not to accept when the player requests
203 // an item.
204 char last_i_sym = 'a';
205 foreach( size_t slot_temp; INVENT_BAG .. u.inventory.items.length )
207 last_i_sym++;
208 if( !Item_here( u.inventory.items[slot_temp] ) )
210 // If the _first_ inventory slot is empty, just exit the inventory
211 // screen and go back to the equipment screen; there's nothing left
212 // to be done here.
213 if( slot_temp == INVENT_BAG )
215 display_equipment_screen( u, -1, "Your bag is empty." );
216 return false;
219 break;
223 // In the meantime, `grab` will tell us which item has been
224 // selected.
225 grab = get_key();
227 if( grab == 'Q' || grab == ' ' ) return true;
229 // Check the player's grasp; if they do not have an open hand, they can
230 // not take any more items out of their inventory.
231 if( !check_grasp( u.inventory ) )
233 display_equipment_screen( u, -1, "You do not have a free grasp." );
234 return false;
237 if( toLower( grab ) >= last_i_sym || grab < 'a' )
239 display_equipment_screen( u, -1,
240 "You do not have that item." );
241 return false;
243 else
245 line = (grab - 'a') + INVENT_BAG;
246 int hand = 0;
247 // Decide which hand to place the item in. As with picking up
248 // items off the floor, weapons will prefer to go into the
249 // weapon-hand, but other objects will favor the off-hand,
250 // except when the favored hand is already taken.
251 if( !Item_here( u.inventory.items[INVENT_WEAPON] ) &&
252 (u.inventory.items[line].type & ITEM_WEAPON
253 || Item_here( u.inventory.items[INVENT_OFFHAND] ))
255 { hand = INVENT_WEAPON;
257 else
258 { hand = INVENT_OFFHAND;
261 // Transfer the item to the hand...
262 u.inventory.items[hand] = u.inventory.items[line];
263 u.inventory.items[line] = No_item;
264 // Now we shuffle all the items in the inventory up one to
265 // overwrite the item we've just removed from the bag.
266 int I;
267 for( I = (line + 1); I <= (24 + INVENT_LAST_SLOT); I++ )
269 if( !Item_here( u.inventory.items[I] ) ) break;
270 else
272 u.inventory.items[I - 1] = u.inventory.items[I];
273 u.inventory.items[I] = No_item;
277 // Don't break this do loop just because we were successful in
278 // extracting an item; the player might want to take out more than one
279 // item.
280 // Besides, in future implementations, we might want to allow the
281 // player to remove a certain _number_ of a stacking item, and
282 // breaking here makes it more of a hassle to correct a mistake if
283 // they decide they want more stuff.
284 //break;
285 } /* else from if( toLower( grab ) >= I_sym || grab < 'a' ) */
287 } while( grab != 'Q' && grab != ' ' );
289 return refnow;
291 } // final bool manage_inventory( Player* )
293 // Controls the equipment screen and returns the number of turns spent based
294 // on how many items are swapped around.
295 final uint manage_equipment( Player* u )
297 import std.ascii: toLower;
298 import std.format : format;
300 // the inventory slot letter the player has selected
301 char grab = 0;
302 // `line': the line corresponding to the `grab' slot letter
303 // `grabbed_line': the line corresponding to an item that has been grabbed
304 int line = -1, grabbed_line = -1;
305 // `grabbed': an item that has been grabbed
306 Item grabbed = No_item;
308 // whether to refresh the inventory screen
309 bool refnow = 1;
311 // the number of turns that have passed...
312 uint turns = 0;
314 // clear the screen:
315 clear_screen();
319 if( refnow )
321 refnow = 0;
322 display_equipment_screen( u, grabbed_line );
323 } /* if( refnow ) */
325 // grab an item
326 grab = get_key();
327 if( grab == 'Q' || grab == ' ' )
328 { break;
331 // this line is here to clear error messages
332 foreach( count; 1 .. 79 )
333 { put_char( 21, count, ' ' );
336 grab = toLower( grab );
337 switch( grab )
339 case 't':
340 display_equipment_screen( u, -1, "You do not have a tail." );
341 refresh_screen();
342 line = -1;
343 break;
344 case 'i':
345 // The player has chosen to access an item in their bag
346 // If the player already has an item selected, attempt to place that
347 // item in the bag.
348 if( grabbed_line > -1 )
350 // First we need to check if the bag is full.
351 bool bag_full = true;
352 size_t I = 0;
353 for( I = 0; I < 24; I++ )
355 if( !Item_here( u.inventory.items[INVENT_BAG + I] ) )
357 bag_full = false;
358 break;
361 // If the bag is full, complain to the user and discard the swap
362 if( bag_full )
364 grabbed_line = -1;
365 line = -1;
366 display_equipment_screen( u, -1,
367 "Your bag can not contain any more items." );
368 refnow = false;
369 // Go back to the start of the loop
370 continue;
372 // If the bag is NOT full, append the item to the end of their bag
373 // and remove it from the equipment slot it came from
374 else
376 grabbed = u.inventory.items[grabbed_line];
377 u.inventory.items[grabbed_line] = No_item;
378 u.inventory.items[INVENT_BAG + I] = grabbed;
380 // Make a note to refresh the screen, discard all swaps, and go
381 // back to the start of the loop:
382 refnow = true;
383 grabbed_line = line = -1;
384 grabbed = No_item;
385 continue;
387 } /* if( grabbed_line != -1 ) */
388 // If the player does NOT have an item already selected, they are
389 // trying to REMOVE an item from their bag...
390 else
392 // If the player does not have a free grasp, let them know.
393 if( !check_grasp( u.inventory ) )
395 display_equipment_screen( u, grabbed_line,
396 "You do not have a free grasp to reach into your bag." );
397 refnow = false;
398 // Discard all swaps and go back to the start of the loop...
399 grabbed_line = line = -1;
400 continue;
402 else
404 // Pass control over to the inventory management function.
405 // Note that we're letting `manage_inventory` decide whether or
406 // not to refresh the equipment screen now. This is because in
407 // some circumstances the function will redraw the equipment
408 // screen for us.
409 refnow = manage_inventory( u );
411 // Also reset the `line` and `grabbed_line` variables _after_
412 // managing the inventory so that we don't end up anomalously
413 // grabbing a new item right out the gate
414 grabbed_line = line = -1;
416 // Reset `grab` so that a press of 'Q' or SPACE doesn't kick
417 // the user out of the equipment screen as well as the inventory
418 // screen.
419 grab = '\0';
421 // Go back to the start of the loop
422 continue;
424 } /* else from if( !check_grasp( u.inventory ) ) */
426 } /* else from if( grabbed_line != -1 ) */
428 /* end of case 'i'; there's no `break` statement here because all of
429 * the above `if` statements have `continue` statements that would
430 * render it unreachable and frankly the warnings get on my nerves
433 case 'w': line = 0; break;
434 case 'o': line = 1; break;
435 case 'q': line = 2; break;
436 case 'h': line = 3; break;
437 case 'c': line = 4; break;
438 case 'p': line = 5; break;
439 case 'b': line = 6; break;
440 case 'l': line = 7; break;
441 case 'r': line = 8; break;
442 case 'n': line = 9; break;
443 case 'g': line = 10; break;
444 case 'k': line = 11; break;
445 case 'f': line = 12; break;
446 default: break;
447 } // switch( grab )
449 if( line == -1 )
450 { continue;
452 else
454 // if we haven't grabbed an item yet...
455 if( grabbed.sym.ch == '\0' )
457 // ...confirm the slot is not empty...
458 if( u.inventory.items[line].sym.ch == '\0' )
460 display_equipment_screen( u, -1, "There is no item there." );
461 line = -1;
463 else
465 // ...grab the item...
466 grabbed = u.inventory.items[line];
467 display_equipment_screen( u, line );
469 // ...and save that line so we can swap the items later.
470 grabbed_line = line;
472 } /* if( grabbed.sym.ch == '\0' ) */
473 // if we have already grabbed an item...
474 else
476 bool confirm_swap = false;
477 // ...check to see if the player can equip the item in this slot
478 switch( line )
480 case INVENT_HELMET:
481 if( grabbed.type & ITEM_WEAPON )
483 // Don't use `display_equipment_screen` here because we need
484 // to be able to format this message and we're going to end up
485 // quitting the equipment screen immediately anyway.
486 put_line( 21, 1,
487 "You stab yourself in the head with a %s and die instantly.",
488 grabbed.name );
489 seppuku:
490 refresh_screen();
491 get_key();
492 u.hp = 0;
493 return 0;
495 goto case INVENT_CUIRASS;
496 // fall through to next case
497 case INVENT_CUIRASS:
498 if( grabbed.type & ITEM_WEAPON )
500 // See above comment at `case INVENT_HELMET` for why we're not
501 // using `display_equipment_screen`
502 put_line( 21, 1,
503 "You slice into your gut with a %s and commit seppuku.",
504 grabbed.name );
505 goto seppuku;
507 goto default;
508 // fall through to next case
509 default:
510 // confirm the player can swap this item to this slot
511 confirm_swap = check_equip( grabbed, line );
512 break;
513 } /* switch( line ) */
515 if( !confirm_swap )
517 // if we can't equip that item here, discard the swap
518 display_equipment_screen( u, -1,
519 format( "You can not equip a %s there.", grabbed.name )
521 discard_swap:
522 grabbed_line = -1;
523 grabbed.sym.ch = '\0';
524 //get_key();
525 //refnow = true;
526 continue;
528 else
530 // check again in the opposite direction
531 if( !check_equip( u.inventory.items[line], grabbed_line ) )
533 display_equipment_screen( u, -1,
534 format( "You can not swap the %s and the %s.",
535 u.inventory.items[line].name,
536 grabbed.name )
538 goto discard_swap;
541 // ...swap the inventory items...
542 u.inventory.items[grabbed_line] = u.inventory.items[line];
543 // if the new slot is not empty, the player expends a turn moving
544 // that item
545 if( u.inventory.items[line].sym.ch != '\0' )
546 { turns += 1;
548 u.inventory.items[line] = grabbed;
549 // ...remove the grabbed item...
550 grabbed.sym.ch = '\0';
551 grabbed_line = line = -1;
552 // ...clear the screen...
553 clear_screen();
554 // ...and make a note to refresh the inventory screen.
555 refnow = true;
557 // the player expends a turn moving an inventory item
558 turns += 1;
559 } /* if( grabbed.sym.ch != '\0' ) */
560 } /* if( line != -1 ) */
561 } while( grab != 'Q' && grab != ' ' );
563 return turns;
564 } // uint manage_equipment( Player* )
566 deprecated("control_inventory has been superceded by manage_equipment to prevent ambiguity. Please use this function instead.")
567 final uint control_inventory( Player* u )
569 return manage_equipment( u );
572 // SECTION 5: ////////////////////////////////////////////////////////////////
573 // Global Output Functions //
574 //////////////////////////////////////////////////////////////////////////////
576 // General Output //////////////////////////////////////////////////////////
578 // Prints a string at the given coordinates. Equivalent to `mvprint` in
579 // curses. If `color` is given, the output line will be in the given color.
580 final void put_colored_line( T... )( uint y, uint x, Colors color, T args )
582 import std.string: format;
583 string output = format( args );
585 foreach( c; 0 .. cast(uint)output.length )
586 { put_char( y, x + c, output[c], color );
590 final void put_line( T... )( uint y, uint x, T args )
591 { put_colored_line( y, x, Colors.Default, args );
594 // The Help Screen /////////////////////////////////////////////////////////
596 // Displays the "help" screen and waits for the player to clear it.
597 final void help_screen()
599 clear_screen();
601 put_line( 1, 1, "To move: on numpad: on Dvorak:" );
602 put_line( 2, 1, " y k u 7 8 9 f t g" );
603 put_line( 3, 1, " \\|/ \\|/ \\|/" );
604 put_line( 4, 1, " h-*-l 4-*-6 d-*-l" );
605 put_line( 5, 1, " /|\\ /|\\ /|\\" );
606 put_line( 6, 1, " b j n 1 2 3 x h b" );
608 put_line( 8, 1, ". to wait" );
609 put_line( 10, 1, "e to manage equipment" );
610 put_line( 11, 1, "i for inventory" );
611 put_line( 12, 1, ", to pick up an item" );
612 put_line( 13, 1, "d to drop an item (or p to put down an item, on Dvorak)" );
613 put_line( 14, 1, "P to read message history" );
614 put_line( 15, 1, "SPACE clears the message line" );
616 put_line( 17, 1, "? this help screen" );
617 put_line( 18, 1, "Q Quit" );
618 put_line( 19, 1, "v check the version number" );
619 put_line( 20, 1, "@ change keyboard layout" );
621 put_line( 22, 1, "Press any key to continue..." );
623 refresh_screen();
625 // wait for the player to clear the screen
626 get_key();
627 } // void help_screen()
629 // Map Output //////////////////////////////////////////////////////////////
631 // Uses `display` to draw the player.
632 final void display_player( Player u )
634 // if the player is wearing a "festive hat," display them in a special
635 // color
636 if( u.inventory.items[INVENT_HELMET].name == "festive hat" )
638 display( u.y + 1, u.x, symdata( u.sym.ch, Colors.Festive_Player ), true );
640 else display( u.y + 1, u.x, u.sym, true );
643 // Uses `display` to draw the given monster.
644 final void display_mon( Monst m )
645 { display( m.y + 1, m.x, m.sym );
648 // Uses `display_mon` to display all monsters on the given map.
649 final void display_map_mons( Map to_display )
651 size_t d = to_display.m.length;
652 Monst mn;
653 foreach( c; 0 .. d )
655 mn = to_display.m[c];
657 if( No_shadows || to_display.v[mn.y][mn.x] )
658 { display_mon( mn );
661 } /* foreach( c; 0 .. d ) */
664 // Uses `display` to draw all of the map tiles and items on the given map.
665 final void display_map( Map to_display )
667 foreach( y; 0 .. MAP_Y )
669 foreach( x; 0 .. MAP_X )
671 Symbol output = to_display.t[y][x].sym;
672 Color_Pair initial_color = CLR[output.color];
674 static if( COLOR )
676 static if( FOLIAGE )
678 // If there is mold growing on this tile, change the tile's color
679 // to green (unless there's also water)
680 if( to_display.t[y][x].hazard & SPECIAL_MOLD )
682 if( !(to_display.t[y][x].hazard & HAZARD_WATER ) )
684 if( initial_color.get_inverted() )
685 { output.color = Colors.Inverted_Green;
687 else
688 { output.color = Colors.Green;
693 static if( BLOOD )
695 // If there is blood spattered on this tile, change the tile's
696 // color to red (unless there's also water?)
697 if( to_display.t[y][x].hazard & SPECIAL_BLOOD )
699 if( !(to_display.t[y][x].hazard & HAZARD_WATER) )
701 if( initial_color.get_inverted() )
702 { output.color = Colors.Inverted_Red;
704 else
705 { output.color = Colors.Red;
710 } // static if( COLOR )
712 if( to_display.i[y][x].sym.ch != '\0' )
713 { output = to_display.i[y][x].sym;
716 if( !No_shadows && !to_display.v[y][x] )
718 static if( !COLOR )
719 output = SYM_SHADOW;
720 else
722 if( to_display.t[y][x].seen )
724 if( initial_color.get_inverted() )
725 { output.color = Colors.Inverted_Dark_Gray;
727 else
728 { output.color = Colors.Dark_Gray;
731 else
733 output = SYM_SHADOW;
738 display( y + 1, x, output );
739 } /* foreach( x; 0 .. MAP_X ) */
740 } /* foreach( y; 0 .. MAP_Y ) */
743 // Uses `display_map` and `display_map_mons` to display all map tiles,
744 // items, and monsters.
745 final void display_map_all( Map to_display )
747 display_map( to_display );
748 display_map_mons( to_display );
751 // Uses `display_map_all` and `display_player` to draw the full play area
752 // including the map, items, monsters, and player.
753 final void display_map_and_player( Map to_display, Player u )
755 display_map_all( to_display );
756 display_player( u );
759 // The Inventory / Equipment Screens ///////////////////////////////////////
761 // Displays the equipment screen.
762 final void display_equipment_screen( Player* u, int grabbed = -1,
763 string msg = "" )
766 clear_screen();
768 string snam; // the name of the slot
769 char schr; // the character that represents the slot
771 foreach( count; 0 .. INVENT_LAST_SLOT )
773 // This switch statement of doom sets up the name and selection
774 // button for each inventory slot
775 switch( count )
777 default: snam = "bag"; schr = '\0'; break;
779 case INVENT_WEAPON: snam = "Weapon-hand"; schr = 'w'; break;
780 case INVENT_OFFHAND: snam = "Off-hand"; schr = 'o'; break;
781 case INVENT_QUIVER: snam = "Quiver"; schr = 'q'; break;
782 case INVENT_HELMET: snam = "Helmet"; schr = 'h'; break;
783 case INVENT_CUIRASS: snam = "Cuirass"; schr = 'c'; break;
784 case INVENT_PAULDRONS: snam = "Pauldrons"; schr = 'p'; break;
785 case INVENT_BRACERS: snam = "Bracers/gloves"; schr = 'b'; break;
786 case INVENT_RINGL: snam = "Left ring"; schr = 'l'; break;
787 case INVENT_RINGR: snam = "Right ring"; schr = 'r'; break;
788 case INVENT_NECKLACE: snam = "Necklace"; schr = 'n'; break;
789 case INVENT_GREAVES: snam = "Greaves"; schr = 'g'; break;
790 case INVENT_KILT: snam = "Kilt/skirt"; schr = 'k'; break;
791 case INVENT_FEET: snam = "Feet"; schr = 'f'; break;
792 case INVENT_TAIL: snam = "Tailsheath"; schr = 't'; break;
793 } // switch( count )
795 if( schr == '\0' )
796 { break;
799 put_line( 1 + count, 1, " %c) %s: %s", schr, snam,
800 u.inventory.items[count].sym.ch == '\0'
801 ? "EMPTY" : u.inventory.items[count].name
803 } /* foreach( count; 0 .. INVENT_LAST_SLOT ) */
805 put_line( 16, 1, "i) Bag" );
807 if( grabbed <= -1 )
809 put_line( 18, 1, "Press a letter to \"grab\" that item" );
810 put_line( 19, 1, "or \'i\' to take an item out of your bag" );
812 else
814 put_line( grabbed + 1, 1, "GRABBED:" );
815 put_line( 18, 1,
816 "Press a letter to move the grabbed item into a new equipment slot" );
817 put_line( 19, 1, "or \'i\' to put it in your bag" );
820 put_line( 20, 1, "Press \'Q\' or SPACE to exit this screen" );
822 if( msg != "" ) put_line( 22, 1, msg );
824 refresh_screen();
826 } // final void display_equipment_screen( Player*(, int, string) )
828 // Displays the inventory screen.
829 final void display_inventory( Player* u )
832 clear_screen();
834 // The symbol of the current item
835 char slot_char = 'a';
837 foreach( slot_index; 0 .. 24 )
839 // Inform the player of each item, up to 24 (one per line)
840 if( Item_here( u.inventory.items[INVENT_BAG + slot_index] ) )
842 put_line( slot_index, 0, "%c) %s", slot_char,
843 u.inventory.items[INVENT_BAG + slot_index].name );
844 slot_char++;
846 else break;
849 refresh_screen();
851 } // final void display_inventory( Player* )
853 debug
856 // Section 6: //////////////////////////////////////////////////////////////
857 // Debug Output //
858 ////////////////////////////////////////////////////////////////////////////
860 // Output a screen which will display various color pairs for test purposes
861 final void color_test_screen()
863 clear_screen();
865 put_colored_line( 1, 1,
866 Colors.Default, "Default" );
867 put_colored_line( 3, 1,
868 Colors.Black, "Black" );
869 put_colored_line( 5, 1,
870 Colors.Red, "Red" );
871 put_colored_line( 7, 1,
872 Colors.Green, "Green" );
873 put_colored_line( 9, 1,
874 Colors.Dark_Blue, "Dark_Blue" );
875 put_colored_line( 11, 1,
876 Colors.Brown, "Brown" );
877 put_colored_line( 13, 1,
878 Colors.Magenta, "Magenta" );
879 put_colored_line( 15, 1,
880 Colors.Cyan, "Cyan" );
881 put_colored_line( 17, 1,
882 Colors.Gray, "Gray" );
883 put_colored_line( 19, 1,
884 Colors.Dark_Gray, "Dark_Gray" );
885 put_colored_line( 21, 1,
886 Colors.Lite_Red, "Lite_Red" );
887 put_colored_line( 23, 1,
888 Colors.Lite_Green, "Lite_Green" );
889 put_colored_line( 1, 21,
890 Colors.Blue, "Blue" );
891 put_colored_line( 3, 21,
892 Colors.Yellow, "Yellow" );
893 put_colored_line( 5, 21,
894 Colors.Pink, "Pink" );
895 put_colored_line( 7, 21,
896 Colors.Lite_Cyan, "Lite_Cyan" );
897 put_colored_line( 9, 21,
898 Colors.White, "White" );
899 put_colored_line( 11, 21,
900 Colors.Inverted_Black, "Inverted_Black" );
901 put_colored_line( 13, 21,
902 Colors.Inverted_Red, "Inverted_Red" );
903 put_colored_line( 15, 21,
904 Colors.Inverted_Green, "Inverted_Green" );
905 put_colored_line( 17, 21,
906 Colors.Inverted_Dark_Blue, "Inverted_Dark_Blue" );
907 put_colored_line( 19, 21,
908 Colors.Inverted_Brown, "Inverted_Brown" );
909 put_colored_line( 21, 21,
910 Colors.Inverted_Magenta, "Inverted_Magenta" );
911 put_colored_line( 23, 21,
912 Colors.Inverted_Cyan, "Inverted_Cyan" );
913 put_colored_line( 1, 41,
914 Colors.Inverted_Gray, "Inverted_Gray" );
915 put_colored_line( 3, 41,
916 Colors.Inverted_Dark_Gray, "Inverted_Dark_Gray" );
917 put_colored_line( 5, 41,
918 Colors.Inverted_Lite_Red, "Inverted_Lite_Red" );
919 put_colored_line( 7, 41,
920 Colors.Inverted_Lite_Green, "Inverted_Lite_Green" );
921 put_colored_line( 9, 41,
922 Colors.Inverted_Blue, "Inverted_Blue" );
923 put_colored_line( 11, 41,
924 Colors.Inverted_Yellow, "Inverted_Yellow" );
925 put_colored_line( 13, 41,
926 Colors.Inverted_Pink, "Inverted_Pink" );
927 put_colored_line( 15, 41,
928 Colors.Inverted_Lite_Cyan, "Inverted_Lite_Cyan" );
929 put_colored_line( 17, 41,
930 Colors.Inverted_White, "Inverted_White" );
931 put_colored_line( 19, 41,
932 Colors.Error, "Error" );
933 put_colored_line( 21, 41,
934 Colors.Player, "Player" );
935 put_colored_line( 23, 41,
936 Colors.Festive_Player, "Festive_Player" );
937 put_colored_line( 1, 61,
938 Colors.Water, "Water" );
939 put_colored_line( 3, 61,
940 Colors.Lava, "Lava" );
941 put_colored_line( 5, 61,
942 Colors.Acid, "Acid" );
943 put_colored_line( 7, 61,
944 Colors.Copper, "Copper" );
945 put_colored_line( 9, 61,
946 Colors.Silver, "Silver" );
947 put_colored_line( 11, 61,
948 Colors.Gold, "Gold" );
949 put_colored_line( 13, 61,
950 Colors.Roentgenium, "Roentgenium" );
951 put_colored_line( 15, 61,
952 Colors.Money, "Money" );
953 put_colored_line( 17, 61,
954 Colors.Royal, "Royal" );
955 put_colored_line( 19, 61,
956 Colors.Holy, "Holy" );
957 put_colored_line( 21, 61,
958 Colors.Snow, "Snow" );
959 put_colored_line( 23, 61,
960 Colors.Snow_Tree, "Snow_Tree" );
962 refresh_screen();
964 get_key();
965 } // color_test_screen()
966 } // debug
968 } // interface SwashIO
970 // SECTION 7: ////////////////////////////////////////////////////////////////
971 // Importing Further IO Files //
972 //////////////////////////////////////////////////////////////////////////////
974 // Import the classes which expand on this template depending on what display
975 // outputs have been compiled:
977 version( curses )
978 { import iocurses; /* display interface for curses */
981 version( sdl )
982 { import ioterm; /* display interface for sdl terminal */