package Blacknote::Renderer::Curses; use Blacknote::Logging; use Blacknote::System; use Blacknote::System::Renderers; use Blacknote::Interface; use Blacknote::System::State qw( bnsm_set_player bnsm_get_player bnsm_get_log ); use Blacknote::Message; use Carp qw(croak confess); use Data::Dumper; use base 'Blacknote::System::Renderers::ISimpleRenderer'; use strict; use warnings FATAL => qw(all); use Exporter qw(import); our @EXPORT = qw(render_map render_player stop_render render_windows render_messages render_items render_tile init_rendering); use Curses; use feature 'say'; use constant { MIN_COLS => 80, MIN_LINES => 20, }; # init our $mainwin; sub init_rendering { $mainwin = initscr; if($COLS < MIN_COLS){ croak "Window must be at least ".MIN_COLS()." columns wide"; } if($LINES < MIN_LINES){ croak "Window must be at least ".MIN_LINES()." lines tall"; } keypad($mainwin, 1); curs_set(0); start_color; init_pair(2,COLOR_RED,0); init_pair(3,COLOR_CYAN,0); init_pair(4,COLOR_YELLOW,0); init_pair(5,COLOR_GREEN,0); init_pair(7,COLOR_WHITE,0); noecho; cbreak; } my $DISPLAY_OFFSET_X = 25; my $DISPLAY_OFFSET_Y = 1; my %COLORS = ( white => 7, red => 2, cyan => 3, brown => 4, green => 5, ); sub render_object { my $drawable = shift; implements $drawable, "Blacknote::System::IDrawable"; addch($mainwin, $drawable->y + $DISPLAY_OFFSET_Y, $drawable->x + $DISPLAY_OFFSET_X, ord($drawable->symbol) | COLOR_PAIR($COLORS{$drawable->color() // 'white'})); } sub render_tile { my ($tile) = @_; # FIXME: Make the walls out of ACS_BLOCK instead of '#' my $sym = ord($tile->symbol); $sym = ACS_BLOCK if $sym == ord "#"; addch($mainwin, $tile->y + $DISPLAY_OFFSET_Y, $tile->x + $DISPLAY_OFFSET_X, $sym | COLOR_PAIR($COLORS{$tile->color() || 'white'})); #addch($mainwin, $tile->y + $DISPLAY_OFFSET_Y, $tile->x + $DISPLAY_OFFSET_X, ord($tile->symbol) | COLOR_PAIR($COLORS{$tile->color() || 'white'})); } sub render_map { clear_area(0,0,120,30); my $map = $Blacknote::System::State::MAPDATA; DEBUG Dumper \%Blacknote::System::State::TILE_MAPPING; DEBUG 'map size y: ' . (scalar(@$map)-1); DEBUG 'map size x: ' . (scalar(@{$map->[0]})-1); my $max_y = scalar @$map; my $max_x = scalar @{$map->[0]}; my $offsetx = 10; for my $y( 0 .. $max_y-2 ){ for my $x( 0 .. $max_x-1 ){ #NOTE: insch insert a character before the one at the cursor. addch changes the one at the cursor. my $tileinstance = $map->[$y]->[$x]; render_tile($tileinstance); } } DEBUG "render_map finished"; } sub render_items { for my $container(values %Blacknote::System::State::MAPITEMS){ for my $item(@$container){ $item->isa("Blacknote::System::IItem") or die "Error: $item is not an item"; render_object($item); } } } sub render_player { my $player = bnsm_get_player; if($player){ implements $player, "Blacknote::System::RDrawable"; implements $player, "Blacknote::System::IDrawable"; #addch($player->y, $player->x, ord($player->symbol) | COLOR_PAIR(2) | A_BOLD); #TODO: Properly initialize colors render_object($player); #move $player->y, $player->x; }else{ WARN "Player has not been defined yet"; } } sub render_messages { my $log = bnsm_get_log; my $iter = 1; DEBUG "About to render message log"; my $max_idx = @{$log->get_all_messages} - 1; my $count = 0; addstring $log->y, 0, "-" x $COLS; for(my $msgidx = $max_idx ;; $msgidx--){ # Display messages in reverse order DEBUG "Rendering message[$msgidx]"; addstring($log->y + $iter, $log->x, ' ' x $log->w); addstring($log->y + $iter++, $log->x, $log->get_all_messages->[$msgidx]); $count++; if($count >= 5 || $msgidx <= 0){ last; } } } sub render_stats{} sub clear_area { my ($x,$y,$w,$h)= @_; for my $posy( $y .. $h ){ #for my $posx( $x .. $w){ # addch($mainwin,$posy,$posx,' '); # NOTE: This should dramaticallyi improve preformance addstring($mainwin, $posy, $x, ' ' x $w); #} } } sub render_windows { for my $win(values %Blacknote::System::State::WINDOWS){ return unless defined $win; # implements $win, "Blacknote::System::IWindow"; #NOTE: These should not be checked at compile time for my $y($win->y .. $win->h){ for my $x($win->x .. $win->w){ addch($y,$x,' '); # clear background } } TRACE "[TODO] Draw border"; addstring($win->y, $win->x, $win->title); my $iter = 1; for my $k( sort keys %{$win->{menu_items}} ){ addstring($win->y + $iter++, $win->x + 1, $k . ")" . $win->menu_items->{$k}); } } } sub stop_render { echo; nocbreak; endwin; } CHECK{ WARN "FIXME: Need a better rendering initialization. We should probably move the stuff from INIT and CHECK blocks to the Blacknote::init function"; init_rendering; } 1; .