Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The "@ Walking Around the Screen" Demo

2 views
Skip to first unread message

Fenrir

unread,
Sep 18, 2008, 10:15:09 AM9/18/08
to
#include <stdlib.h>
#include <curses.h>

#define PLAYER_CHAR '@'

class Creature
{
private:
char character;
int x, y;
public:
int getX() { return x; }
int getY() { return y; }

char getChar() { return character; }

void setChar(char _character)
{
character = _character;
}

int move(int _x, int _y)
{
x = _x;
y = _y;
}

void draw()
{
mvaddch(y,x,character);
}
};

bool isValidMove(int x, int y)
{
if(x < COLS && x >= 0 && y < LINES && y >= 0) return true;
return false;
}

int main () {
initscr ();
cbreak ();
noecho ();
start_color ();
keypad (stdscr, TRUE);
curs_set(0);

Creature* player = new Creature();
player->setChar(PLAYER_CHAR);
player->move(COLS/2,LINES/2);
player->draw();

int input;
char* c;

do
{
input=getch();
c = keyname(input);

int pX = player->getX();
int pY = player->getY();
if(input == KEY_UP || input == KEY_A2)
{
pY-=1;
}
else if(input == KEY_DOWN || input == KEY_C2)
{
pY+=1;
}
else if(input == KEY_LEFT || input == KEY_B1)
{
pX-=1;
}
else if(input == KEY_RIGHT || input == KEY_B3)
{
pX+=1;
}
else if(input == KEY_A1)
{
pX-=1;
pY-=1;
}
else if(input == KEY_A3)
{
pX+=1;
pY-=1;
}
else if(input == KEY_C1)
{
pX-=1;
pY+=1;
}
else if(input == KEY_C3)
{
pX+=1;
pY+=1;
}

if(isValidMove(pX,pY))
{
player->move(pX,pY);
}

erase();
player->draw();
} while(*c != 'Q');

erase ();
refresh ();
endwin ();
return 0;
}

What do you think? Is there something that can be done better? Should
I really be worried about that at this point?

Krice

unread,
Sep 18, 2008, 10:25:27 AM9/18/08
to
On 18 syys, 17:15, Fenrir <siliconvik...@gmail.com> wrote:
> #define PLAYER_CHAR '@'

This does nothing and #defines used this way are bad anyway.

> Creature* player = new Creature();

Don't forget delete.

> char* c;

Why c is a pointer?

> Is there something that can be done better?

Yeah, almost everything.

Soyweiser

unread,
Sep 18, 2008, 10:52:38 AM9/18/08
to
On Sep 18, 4:25 pm, Krice <pau...@mbnet.fi> wrote:
> On 18 syys, 17:15, Fenrir <siliconvik...@gmail.com> wrote:
>
> > Creature* player = new Creature();
>
> Don't forget delete.

Not really needed at the moment right? When the program terminates
Creature will be deleted automagically.

>
> > char* c;
>
> Why c is a pointer?

Because the function keyname from curses.h requires this.

> > Is there something that can be done better?
>
> Yeah, almost everything.

Krice how is the development of Kaduria going? Must be going pretty
good right? As you seem to be the all mighty programming god. You
could also try to be nice to people who are just starting out.

To OP:
It looks like an nice start. Are you following the 15 step program
(1)?

I don't know if the drawing function inside the creature class is a
good idea. The same for key handeling in main, I would write different
functions to do that inside the main loop. I assume that the COLS and
LINES variables are from curses.h? (I used curses.h ages ago, so don't
really know that much about it anymore).

And I think you forgot to check the c variable for a null pointer.
Apparently this is the error state of the keyname function. I don't
think that a null crashes your program at the moment, but it is always
nice to be aware of potential errors.

(1): http://roguebasin.roguelikedevelopment.org/index.php?title=How_to_Write_a_Roguelike_in_15_Steps


> Should I really be worried about that at this point?

Nope. I doubt that much of this code will remain later. But it is a
start. Give it a name and release it and you could even call yourself
a developer. (And get laughed at by anyone who looks at your final
product, of course). But it is a nice start.

--
Soyweiser

Derek Ray

unread,
Sep 18, 2008, 11:02:51 AM9/18/08
to
On 2008-09-18, Fenrir <silico...@gmail.com> wrote:
> What do you think?

Does what it says on the tin.

> Is there something that can be done better?

Oh, certainly; a few things.

> Should I really be worried about that at this point?

Nope, not any time soon.

Ignore Krice, he's an armchair programmer whose primary product
is vapourware and blather.

--
Derek

Game info and change log: http://sporkhack.com
Beta Server: telnet://sporkhack.com
IRC: irc.freenode.net, #sporkhack

Message has been deleted

Krice

unread,
Sep 18, 2008, 12:20:25 PM9/18/08
to
On 18 syys, 17:52, Soyweiser <soywei...@gmail.com> wrote:
> When the program terminates Creature will be deleted
> automagically.

It's not deleted, although the memory reserved by the
object is probably released. Only delete keyword will
delete the object. Besides I have run into a serious
crash when I forgot to delete at the exit of program
so it's not only bad style but also a possible cause
of crash.

> > Why c is a pointer?
> Because the function keyname from curses.h requires this.

Don't you think it's a bit weird? Why on earth it's a
pointer? Could someone tell me.

> Krice how is the development of Kaduria going?

Not very good at the moment. I'm still recovering from
a surgery.

Jakub Debski

unread,
Sep 18, 2008, 1:08:45 PM9/18/08
to
Fenrir laid this down on his screen :

> What do you think? Is there something that can be done better? Should
> I really be worried about that at this point?

My concept:

class Creature
{
public:
virtual ACTION GetAction();
virtual DoAction(ACTION);
}

class Monster : Creature;
class Player : Creature;

Monster::GetAction is AI.
Player::GetAction is user input.

Main loop:
for each monster -> DoAction(GetAction());

DoAction can be the same for player and monster.

regards,
Jakub


Fenrir

unread,
Sep 18, 2008, 1:34:48 PM9/18/08
to
On Sep 18, 10:52 am, Soyweiser <soywei...@gmail.com> wrote:
> It looks like an nice start. Are you following the 15 step program
> (1)?

I'm using the 15 step program as a guideline. I probably won't be
doing things exactly as described there.

> I assume that the COLS and LINES variables are from curses.h?

They are.

Jakub Debski wrote:

> My concept:
>
> class Creature
> {
> public:
> virtual ACTION GetAction();
> virtual DoAction(ACTION);
>
>
>
> }
>
>
> class Monster : Creature;
> class Player : Creature;
>
> Monster::GetAction is AI.
> Player::GetAction is user input.
>
>
> Main loop:
> for each monster -> DoAction(GetAction());
>
>
> DoAction can be the same for player and monster.
>
>
> regards,
> Jakub

Cool. Thanks. I'll implement this when I add monsters.


Thank you for all the advice, everyone!

Paul Donnelly

unread,
Sep 18, 2008, 2:11:14 PM9/18/08
to
Krice <pau...@mbnet.fi> writes:

> On 18 syys, 17:52, Soyweiser <soywei...@gmail.com> wrote:
>> When the program terminates Creature will be deleted
>> automagically.
>
> It's not deleted, although the memory reserved by the
> object is probably released. Only delete keyword will
> delete the object. Besides I have run into a serious
> crash when I forgot to delete at the exit of program
> so it's not only bad style but also a possible cause
> of crash.
>
>> > Why c is a pointer?
>> Because the function keyname from curses.h requires this.
>
> Don't you think it's a bit weird? Why on earth it's a
> pointer? Could someone tell me.

Because it's a string -- the key's name.

Sherm Pendley

unread,
Sep 18, 2008, 2:46:58 PM9/18/08
to
Graham <gra...@grahamcox.co.uk> writes:

> the operating system - most modern OSs will clean up unreleased memory
> automatically on a clean termination of the program

Two of the key aspects of modern OS design are virtual memory, and
pre-emptive multitasking. Any modern OS will be able to clean up all
of an app's memory, regardless of internal details like whether a
pointer was freed or not, or whether the app terminated cleanly or
crashed.

The days when we depended on apps to properly release their resources
back to the OS are long gone. The OS can *take* back the resources
given to an app, and doesn't need the app's permission or cooperation
to do so.

> older machine that doesn't do this - Win95 for example didn't I
> believe...

I'll keep that in mind, if I ever decide to take a job writing demo
code at a computer history museum. :-)

sherm--

--
My blog: http://shermspace.blogspot.com
Cocoa programming in Perl: http://camelbones.sourceforge.net

zai...@zaimoni.com

unread,
Sep 18, 2008, 3:07:48 PM9/18/08
to
On Sep 18, 1:46 pm, Sherm Pendley <spamt...@dot-app.org> wrote:
> Graham <gra...@grahamcox.co.uk> writes:
> > the operating system - most modern OSs will clean up unreleased memory
> > automatically on a clean termination of the program
>
> Two of the key aspects of modern OS design are virtual memory, and
> pre-emptive multitasking. Any modern OS will be able to clean up all
> of an app's memory, regardless of internal details like whether a
> pointer was freed or not, or whether the app terminated cleanly or
> crashed.

This is C++, not C. Any modern OS will be able to clean up almost all
memory with trivial destructors, regardless of internal details. [I
don't particularly like exploiting this in my in-development C99
preprocessor, but it works.]

I had to re-engineer "One Main To Rule Them All" to completely avoid
all non-trivial static destructors because their order of invocation
was undefined -- causing a crash-on-close.

Also, the OS will not automatically clean up the curses library on its
own reliably; omitting the endwin call is a crash-on-exit bug on Vista/
PDCurses. (Guess how I found out.)

Brog

unread,
Sep 18, 2008, 3:39:04 PM9/18/08
to
On 18 Sep, 15:52, Soyweiser <soywei...@gmail.com> wrote:
> On Sep 18, 4:25 pm, Krice <pau...@mbnet.fi> wrote:
>
> > On 18 syys, 17:15, Fenrir <siliconvik...@gmail.com> wrote:
>
> > >         Creature* player = new Creature();
>
> > Don't forget delete.
>
> Not really needed at the moment right? When the program terminates
> Creature will be deleted automagically.

Better to match every new with a delete from the start, so that as you
add complexity you will not have to worry about things that you've
already dealt with.
This is where memory leaks come from. As soon as you decide to add
functionality to start a new game when you lose rather than just
quitting.. wham! A Creature's worth of memory leaking with every
game! It's just better practise to always free any memory you've
allocated.

Fenrir

unread,
Sep 18, 2008, 4:12:43 PM9/18/08
to
So should I change my code or move on to dungeon generation? Like
Soyweiser said, much of this code won't remain later.

Martin Read

unread,
Sep 18, 2008, 4:18:03 PM9/18/08
to
Brog <crys...@gmail.com> wrote:
>This is where memory leaks come from. As soon as you decide to add
>functionality to start a new game when you lose rather than just
>quitting.. wham!

execl(argv[0], argv[0], 0);
--
\_\/_/ turbulence is certainty turbulence is friction between you and me
\ / every time we try to impose order we create chaos
\/ -- Killing Joke, "Mathematics of Chaos"

Numeron

unread,
Sep 18, 2008, 9:34:24 PM9/18/08
to
Fenrir wrote:
> What do you think? Is there something that can be done better? Should
> I really be worried about that at this point?

My personal experience at creating roguelikes has gone something like
this:

- I made an attempt which was a spectacular structual mess but at
least it ran and did a few nifty things...

- I made a second attempt in which I had learned from my mistakes, but
it still ended up becoming unusable once it reached a certain
complexity because I hadnt learnt that far ahead yet.

- I entered the 7DRL challenge at the beginning of the year and made a
game Im quite proud of (Crown of the Forest).

- Made 2 basic concept testing programs in preperation for something
larger.

- That something larger is what Im working on right now. Its world
lacks scalability beyond the size it is now and is rather hacky but is
turning out very good.

At each step Ive learned from what has gone before, and once this game
reaches a point Im happy with Ill release it and start on an even
larger, more complex project. I want to push the limits of what I can
do each time because thats how I learn, and I am too full of new ideas
to tolerate refactors. When I finally consider myself ready, I'll make
an attempt at a real epic.

Dont be phased if your program turns into a hairy mess, because if it
turns out unusable beyond a certain point not only will you be able to
do it better next time, youll will probably also be able to write it
in half the time.

-Numeron

kesipyc

unread,
Sep 19, 2008, 3:34:58 AM9/19/08
to
Using C++ You may try to use smart pointers.
This way you will never have to care about freeing memory.

sth like
http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/smart_ptr.htm

Message has been deleted

William McBrine

unread,
Sep 27, 2008, 1:20:11 PM9/27/08
to
On Thu, 18 Sep 2008 12:07:48 -0700, zaimoni wrote:

> Also, the OS will not automatically clean up the curses library on its
> own reliably; omitting the endwin call is a crash-on-exit bug on Vista/
> PDCurses. (Guess how I found out.)

You need to call endwin() to restore the terminal to its normal mode, not
to free memory. In fact, endwin() does not free memory -- for that, you'd
have to use delscreen().

--
09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0 -- pass it on

David Chmelik

unread,
Nov 1, 2008, 8:07:56 PM11/1/08
to
William McBrine wrote:
> On Thu, 18 Sep 2008 12:07:48 -0700, zaimoni wrote:
>
>> Also, the OS will not automatically clean up the curses library on its
>> own reliably[.... ]

>
> You need to call endwin() to restore the terminal to its normal mode, not
> to free memory. In fact, endwin() does not free memory -- for that, you'd
> have to use delscreen().
>

I have done some roguelike proramming since 1996-'7, when
in Ti-BASIC I programmed moving a '@' on a map with doors. I restarted
in Watcom C/C++ about when r.g.r.d. formed. I have done little since
but move to gcc and discuss with the author of Z+Angband porting that to
64-bit POSIX (I/we wrote a simple fix for text-based.) Ncurses.h (I use
Slackware/Slamd64) docs say do

initscr(); cbreak(); noecho();
//and: Most programs would additionally use the sequence:
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
//and at the end
//nocbreak(); //maybe
endwin();

in a curses program. However, when I do that, it freezes until I ^C,
and then its 1st printf() (for character making) shows. I have read
ncurses doc & code (I sometimes use BSD and would read curses, but
cannot find docs ;) Rogue, Larn, [Net]Hack, various
Moria/[Z]Angband/TOME code; searched r.g.r.d. history & FAQ, various
'netsites including roguelikedevelopment.org, but could not figure out
ncurses. The basic init. & end for roguelikes should be added to
r.g.r.d FAQ and (if Björn would,) roguelikedevelopment.org

Maybe my problem is using printf(), not cin. I never had a pure C
course and wanted to try some, though my program is C++: maybe I must
specify C namespace or use C++ stdio.h, etc., but I suspect there is a
POSIX problem (termcap?) or ncurses docs' 'most programs' explanation is
wrong for roguelikes. Can anyone help?

--David Melik

David Chmelik

unread,
Nov 1, 2008, 8:08:55 PM11/1/08
to
William McBrine wrote:
> On Thu, 18 Sep 2008 12:07:48 -0700, zaimoni wrote:
>
>> Also, the OS will not automatically clean up the curses library on its
>> own reliably[.... ]

>
> You need to call endwin() to restore the terminal to its normal mode,
not
> to free memory. In fact, endwin() does not free memory -- for that,
you'd
> have to use delscreen().
>

I have done some roguelike proramming since 1996-'7, when in Ti-BASIC I

Martin Read

unread,
Nov 2, 2008, 7:45:32 AM11/2/08
to
David Chmelik <dchm...@hipplanet.com> wrote:
>Maybe my problem is using printf(), not cin. I never had a pure C
>course and wanted to try some, though my program is C++: maybe I must
>specify C namespace or use C++ stdio.h, etc., but I suspect there is a
>POSIX problem (termcap?) or ncurses docs' 'most programs' explanation is
>wrong for roguelikes. Can anyone help?

You shouldn't use stdin/stdout *or* cin/cout if you're using any
variation of curses as your display library. In a curses program, you
should perform all I/O from/to the user's terminal via the curses I/O
functions (the printw, addstr, getch, getstr and related families as
described in the documentation of the curses implementation you're
using).

Use whatever you like for *file* I/O, of course.

I would suggest looking at the source code of my own game, Martin's
Dungeon Bash - I like to think that its "display.c" module is a lot
easier to read than many such modules :)

David Chmelik

unread,
Nov 3, 2008, 1:24:16 AM11/3/08
to
Martin Reed <mpr...@chiark.greenend.org.uk> wrote:
>>[...] I suspect there is >>a POSIX problem (termcap?) or ncurses
docs' >>'most programs' >>explanation is wrong for roguelikes. Can
anyone >>help?
>
>You shouldn't use stdin/stdout *or* cin/cout if you're using any
>variation of curses as your display library. In a curses program, you
>should perform all I/O from/to the user's terminal via the curses I/O
>functions (the printw, addstr, getch, getstr and related families as
>described in the documentation of the curses implementation you're
>using).[...]

That helped, but not completely. According to docs of ncurses, programs
using it should

initscr(); cbreak();
noecho(); //though it seems bad for roguelikes! (except sometimes,)

//and curses programs maybe should

nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE); //likely necessary in curses-roguelikes
//[...]
echo(); //before some output. The top of 'man ncurses' is unclear!


Your 'Dungeon Bash' is modularized--so slightly hard to read--but small
enough I saw simple ncurses command use. Larger roguelikes use mvaddch
but harder stuff--curses tty windows; you use them: are they useful?
Maybe I realized what to use when you stated it. Printw() works in my
roguelike, but when I made my 'return key value' program use ncurses,
only printf() worked...!

I would like to discuss xterms/konsole/etc.. My program wraps '@' to
screen sides correctly on tty, but not xterms; they seem to return COLS
wrong, and xterms permanently break column calculations when '@' is
moved to col. 0 or some n<COLS. Likely X/KDE uses VESA modes. I would
try VESA tty, but compiling kernels seemed to stop working on the latest
Slamd64, and standard kernel forces 80x25 tty.

I Own The Letter O

unread,
Nov 3, 2008, 6:43:12 AM11/3/08
to
Hi,

I don't use curses so I'm not sure about this but are those KEYxyz
enums or similar. It might save yourself some eyeache if you used a
switch/case rather than consecutive if/else statements.

Martin Read

unread,
Nov 3, 2008, 2:04:02 PM11/3/08
to
David Chmelik <dchm...@hipplanet.com> wrote:
>That helped, but not completely. According to docs of ncurses, programs
>using it should
>
>initscr(); cbreak();
>noecho(); //though it seems bad for roguelikes! (except sometimes,)

It is the norm for roguelikes, since otherwise command keystrokes get
echoed to the screen, which is a nuisance because it means you have to
actively manage the cursor position.

>Your 'Dungeon Bash' is modularized--so slightly hard to read--but small
>enough I saw simple ncurses command use. Larger roguelikes use mvaddch
>but harder stuff--curses tty windows; you use them: are they useful?

ncurses tty windows are very useful indeed.

>Maybe I realized what to use when you stated it. Printw() works in my
>roguelike, but when I made my 'return key value' program use ncurses,
>only printf() worked...!

Are you remembering to use the refresh() family appropriately? The
output functions do not actually output *anything* until you make an
appropriate refresh()/wrefresh() call.

You can use immedok(window, TRUE) to make all updates to a window
instant, but that can hose performance quite badly.

>I would like to discuss xterms/konsole/etc.. My program wraps '@' to
>screen sides correctly on tty, but not xterms; they seem to return COLS
>wrong, and xterms permanently break column calculations when '@' is
>moved to col. 0 or some n<COLS.

This indicates that your use of curses is incorrect.

>Likely X/KDE uses VESA modes.

X uses whatever bitmap graphics mode it is configured to use. xterm and
similar programs know nothing of such hardware-specific features as
"VESA modes".

David Chmelik

unread,
Nov 4, 2008, 3:49:34 AM11/4/08
to
Martin Read wrote:
>> [...]Printw() works in my roguelike, but when I made my 'return key
value'
>> program use ncurses, only printf() worked...!
>
> Are you remembering to use the refresh() family appropriately?[...]

AFAIK. OTOH 'Printw(); refresh();' works in my roguelike. That code
section and my key-value program are at this post's end, since the
latter program is off-topic.

>> [...]xterms; they seem to return COLS wrong, and xterms permanently

break
>> column calculations when '@' is moved to col. 0 or some n<COLS.
>
> This indicates that your use of curses is incorrect.

But it works on 80x25 tty, not in high CxL in xterms: buggy ones? Must
one check videomode and redefine COLS? I know not what is wrong... here
is my code:


//All code in this post is under GPL3
//in main:
#include <ncurses.h>
initscr(); cbreak(); noecho();
//in an object method (function) that does I/O:
#include <ncurses.h>
char line=26, column=57, last_line=26, last_column=57;
int key=27, ext_key=0;
echo();
keypad(stdscr, TRUE);
for(;;){
move(LINES-2,0);
printw("%s","(ll,lc),(l,c)");
move(LINES-1,0);
printw("%i,%i,%i,%i ",line,column,last_line,last_column);
mvaddch(last_line,last_column,' '); //curses.h
mvaddch(line,column,'@'); //curses.h
move(line,column); //curses.h
key=getch();
last_line=line;
last_column=column;

//'Tis odd curses returns extended keys, but...:
if(key==27) {
ext_key==getch();
if(ext_key==27){
move(0,0);
printw("Do you really want to quit? (y/n)");
choice=getch();
if(choice==89||choice==121) return;
else mvaddstr(0,0,"
");
}
}

if(key==259) line=line-1;
if(key==260) column=column-1;
if(key==258) line=line+1;
if(key==261) column=column+1;

//#ifdef DOS
/*if(!key){
if(ext_key==72) line=line-1;
if(ext_key==75) column=column-1;
if(ext_key==80) line=line+1;
if(ext_key==77) column=column+1;
}*/

if(line>LINES-1) line=0;
if(line<0) line=LINES-1;
//Column>115 permanently break in xterm
if(column>COLS-1||column>115) column=27;
if(column<27) column=115;
}

>> Likely X/KDE uses VESA modes.
>
> X uses whatever bitmap graphics mode it is configured to use. xterm and
> similar programs know nothing of such hardware-specific features as
> "VESA modes".

I doubt 'bitmap graphics modes' are videomodes. If a terminal has
higher CxL than 80x25 it is quite likely VESA: higher x*y allow more C*L.


This last part, about my 'return key value' program, is OT but useful
for roguelikes, and may be relevant to this ncurses discussion.


//under GPL3
//moved from DOS to 64-bit Linux
//#include <conio.h> //getch() (DOS; Watcom C/C++)
//#include <stdio.h> //printf()
#include <ncurses.h> //curses; Linux

int main(void)
{
//curses section
initscr(); cbreak(); noecho();
nonl();
//intrflush(stdscr, FALSE); //useful?
flushinp();
//uncomment next line to return values for ncurses
keypad(stdscr, TRUE);

//Watcom or curses section
int key=0, ext_key=0;
for(;;){
noecho(); //curses line
key=getch();
if(key==27) ext_key=getch();
else ext_key=0;

//Watcom output
/*printw("%c(%d)\n",key,key);
if(ext_key) printg("%c(%d))\n", ext_key);*/

//curses output
//refresh(); //tried all combinations of printw(), refresh()
printf("\r%s%i\r\n","key: ",key); //works, but stdio.h was
commented out!
printf("%s%i\r\n","ext. key dec.: ",ext_key);

//refreshes here, but only printf() works!
refresh();
key=0,ext_key=0;
}
endwin();
}


A call in the above main, when still after 'noecho();' leads to this
code that is before the I/O method above that does 'echo();.' It only
works with printw(), though the key-value program above is done
similarly and only works with printf()!


//output some player character data
move(0,0);
printw("%s%s%s%s%s%s","name ","\n\r",str1,"\n\r",str2,"00/00 class
00/00\n\rclass 00/00 class 00/00\n\r mon: / str: /\n\r pnm: /
int: /\n\r noo: / wis: /\n\r arc: / dex: /\n\r
con: /\n\r com: / cha: /\n\rhp: /
THAC0\n\rsmp: / alt.\n\rmp: / throw\n\rcmp: /
fire\n\rAC: shield: tool\n\rcarry spd
run\n\rpsy/magic\n\r\n\r\n\rAU\n\r[picture]");
refresh();

0 new messages