[beast is now as beast once was
von@fugal.net**20071006011344] {
addfile ./Makefile
hunk ./Makefile 1
+CC = g++ -g
+LIB = -lncurses -lpthread
+OBJECTS = main.o map.o row.o console.o sprite.o block.o wall.o player.o beast.o super.o baby.o egg.o
+PROG = beast
+
+$(PROG): $(OBJECTS)
+	$(CC) -o $(PROG) $(OBJECTS) $(LIB)
+
+main.o: main.cc map.h row.h console.h wall.h block.h player.h beast.h super.h baby.h egg.h
+	$(CC) -c main.cc
+
+console.o: console.cc console.h
+	$(CC) -c console.cc
+
+map.o: map.cc map.h console.h row.h
+	$(CC) -c map.cc
+
+row.o: row.cc row.h
+	$(CC) -c row.cc
+
+sprite.o: sprite.cc sprite.h console.h
+	$(CC) -c sprite.cc
+
+block.o: block.cc block.h sprite.h console.h
+	$(CC) -c block.cc
+
+wall.o: wall.cc wall.h sprite.h console.h
+	$(CC) -c wall.cc
+
+point.o: point.cc point.h
+		$(CC) -c point.cc
+
+player.o: player.cc player.h sprite.h main.h
+		$(CC) -c player.cc
+
+beast.o: beast.cc beast.h sprite.h main.h
+		$(CC) -c beast.cc
+
+super.o: super.cc super.h sprite.h main.h
+		$(CC) -c super.cc
+
+baby.o: baby.cc baby.h sprite.h main.h
+		$(CC) -c baby.cc
+
+egg.o: egg.cc egg.h beast.h sprite.h
+	$(CC) -c egg.cc
+
+chartest.o: chartest.cc map.h console.h wall.h sprite.h
+		g++ -c chartest.cc
+
+chartest: chartest.o
+		g++ -o chartest chartest.o console.o map.o wall.o sprite.o row.o -lncurses
+
+clean: 
+		rm beast *.o
addfile ./baby.cc
hunk ./baby.cc 1
+#include "baby.h"
+#include "main.h"
+#include "block.h"
+#include <curses.h>
+
+baby::baby() {
+	setchar(ACS_PLUS);
+	setcol(BRIGHTRED);
+	live = true;
+	settype("baby");
+}
+
+int baby::setpos(int px, int py) {
+	std::string s = "";
+	if (m->spriteat(px, py) == NULL) s = "null";
+	else s = m->spriteat(px, py)->mytype();
+
+	if (s == "null" || s == "player" || s == "block") {
+		x = px; y = py;
+		return 0;
+	}
+	return 1;
+}
+
+void baby::move() {
+	// baby beasts push blocks
+}
addfile ./baby.h
hunk ./baby.h 1
+#ifndef BABY_H
+#define BABY_H
+
+#include "beast.h"
+
+class baby : public beast {
+	public:
+		baby();
+
+		void move();
+		int setpos(int px, int py);
+};
+
+#endif
addfile ./beast.cc
hunk ./beast.cc 1
+#include "beast.h"
+#include "map.h"
+#include "main.h"
+#include "player.h"
+
+beast::beast() {
+	setchar('H');
+	setcol(RED);
+	live = true;
+	settype("beast");
+}
+
+int beast::setpos(int px, int py) {
+	std::string s = "";
+	if (m->spriteat(px, py) == NULL) s = "null";
+	else s = m->spriteat(px, py)->mytype();
+
+	if (s == "null" || s == "player") {
+		x = px; y = py;
+		return 0;
+	}
+	return 1;
+}
+bool beast::isalive() {return live;}
+int beast::squish(int dir) {
+	if (!live) return -1;
+	sprite* s = m->spriteat(x + DIRX[dir], y + DIRY[dir]);
+	if (s == NULL) return -1;
+
+	if (s->mytype() == "block" || s->mytype() == "wall") {
+		live = false;
+		return 5;
+	}
+	return -1;
+}
+
+bool beast::move() {
+	if (!live) return false;
+
+	//int dir = dirclose();
+	int score = -1;
+	int dir = -1;
+	sprite *s;
+	for (int i = 0; i < 8; i++) {
+		//dir = (dir + (i * (-1 * (i % 2)))) % 8;
+		std::string type = "null";
+		if (m->spriteat(x + DIRX[i], y + DIRY[i]) != NULL)
+			type = m->spriteat(x + DIRX[i], y + DIRY[i])->mytype();
+
+		//score[i] = '?';
+		if (type == "null" || type == "player") {
+			int tmpscore = -1;
+			for (int p = 0; p < NUM_PLAYERS; p++) {
+				if (playas[p] == NULL || !playas[p]->isalive()) continue;
+				int dx = playas[p]->getx() - (x + DIRX[i]);
+				int dy = playas[p]->gety() - (y + DIRY[i]);
+				int d = (dx * dx + dy * dy);
+				if (tmpscore == -1 || d < tmpscore) tmpscore = d;
+			}
+			if (type == "player")
+				tmpscore = 0;
+			if (tmpscore < score || score == -1) {
+				score = tmpscore;
+				dir = i;
+				s = m->spriteat(x + DIRX[i], y + DIRY[i]);
+			}
+		}
+	}
+	if (dir == -1) return false;
+	m->setsprite(x, y, NULL);
+	setpos(x + DIRX[dir], y + DIRY[dir]);
+	if (s != NULL && s->mytype() == "player") {
+		((player*)m->spriteat(x, y))->incscore(-5);
+		((player*)m->spriteat(x, y))->setlive(false);
+	}
+	m->setsprite(x, y, this);
+	return true;
+}
+int beast::getx() { return x; }
+int beast::gety() { return y; }
+
+beast::~beast() { }
+//bool live;
+//int x; int y;
addfile ./beast.h
hunk ./beast.h 1
+#ifndef BEAST_H
+#define BEAST_H
+
+#include "sprite.h"
+
+class beast : public sprite {
+  public:
+	beast();
+	~beast();
+
+	bool move();
+	int setpos(int px, int py);
+	bool isalive();
+	int squish(int dir);
+	int getx();
+	int gety();
+
+  protected:
+	bool live;
+	int x, y;
+};
+
+#endif
addfile ./block.cc
hunk ./block.cc 1
+#include <curses.h>
+#include "block.h"
+#include "console.h"
+#include "map.h"
+#include "wall.h"
+#include "main.h"
+#include <assert.h>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+block::block() {
+	setchar('#');
+	setcol(GREEN);
+	settype("block");
+}
+
+// -1 means couldn't be pushed, >=0 means it got pushed
+int block::push(int x, int y, int d) {
+	// the block has no data members storing it's location, so we have to
+	// tell it where it is.
+	// and some dummyproofing...
+	if (m->spriteat(x, y) == NULL) return -1;
+	if (m->spriteat(x, y)->mytype() != "block") return -1;
+	x += DIRX[d]; y += DIRY[d];
+	if (!m->inbounds(x, y)) return -1;
+	sprite* s = m->spriteat(x, y);
+	if (s == NULL) {
+		m->setsprite(x, y, this);
+		return 0;
+	}
+	if (s->mytype() == "block") {
+		return push(x, y, d);
+	}
+	if (s->mytype() == "wall") {
+		if (((wall*)s)->isexplode()) return 0;
+		else return -1;
+	}
+
+	int t = s->squish(d);
+	if (t >= 0) {
+		m->setsprite(x, y, this);
+	}
+	return t;
+}
addfile ./block.h
hunk ./block.h 1
+#ifndef BLOCK_H
+#define BLOCK_H
+
+#include "sprite.h"
+
+using namespace std;
+
+class block : public sprite {
+  public:
+	// pretty simple stuff
+	block();
+	int push(int posx, int posy, int dir);
+  private:
+};
+
+#endif
addfile ./console.cc
hunk ./console.cc 1
+#include <curses.h>
+#include <iostream>
+#include <sstream>
+#include "console.h"
+
+#ifndef CONSOLE_CC
+#define CONSOLE_CC
+
+int console::created = 0;
+int console::deleted = 0;
+
+console::console() {
+  w = NULL;
+  created++;
+}
+console::console(WINDOW *win) {
+  w = win;
+  created++;
+}
+
+console console::operator<<(std::string &s) {
+  str(s);
+  return *this;
+}
+console console::operator<<(char *s) {
+  str(s);
+  return *this;
+}
+console console::operator<<(char c) {
+  ch(c);
+  return *this;
+}
+console console::operator<<(int i) {
+	std::ostringstream s;
+  s << i;
+  str(s.str());
+  return *this;
+}
+
+int console::cattr(int color) {
+  switch(color) {
+    case RED:
+    case GREEN:
+    case BROWN:
+    case BLUE:
+    case PURPLE:
+    case CYAN:
+    case GREY:
+      return COLOR_PAIR(color);
+      break;
+    case BRIGHTRED:
+    case BRIGHTGREEN:
+    case YELLOW:
+    case BRIGHTBLUE:
+    case BRIGHTPURPLE:
+    case BRIGHTCYAN:
+    case WHITE:
+      return COLOR_PAIR(color - 7) | A_BOLD;
+      break;
+  }
+}
+void console::setcol(int c) {
+  if(w == NULL) attrset(cattr(c));
+  else wattrset(w, cattr(c));
+}
+
+void console::ch(char c) {
+  if(w == NULL) addch(c);
+  else waddch(w, c);
+}
+void console::ch(char c, int col) {
+  col = cattr(col);
+  if(w == NULL) {
+    attrset(col);
+    addch(c);
+  }
+  else {
+    wattrset(w, col);
+    waddch(w, c);
+  }
+}
+void console::mvch(int y, int x, char c) {
+  if(w == NULL) mvaddch(y, x, c);
+  else mvwaddch(w, y, x, c);
+}
+void console::mvch(int y, int x, char c, int col) {
+  col = cattr(col);
+  if(w == NULL) {
+    attrset(col);
+    mvaddch(y, x, c);
+  }
+  else {
+    wattrset(w, col);
+    mvwaddch(w, y, x, c);
+  }
+}
+void console::mv(int y, int x) {
+  if(w == NULL) move(y, x);
+  else wmove(w, y, x);
+}
+void console::ch(chtype c, int col) {
+  col = cattr(col);
+  if(w == NULL) addch(c | col);
+  else waddch(w, c | col);
+}
+void console::str(std::string s) {
+  if(w == NULL) addstr(s.c_str());
+  else waddstr(w, s.c_str());
+}
+void console::str(std::string s, int col) {
+  col = cattr(col);
+  if(w == NULL) {
+    attrset(col);
+    addstr(s.c_str());
+  }
+  else {
+    wattrset(w, col);
+    waddstr(w, s.c_str());
+  }
+}
+void console::mvstr(int y, int x, std::string s) {
+  if(w == NULL) mvaddstr(y, x, s.c_str());
+  else mvwaddstr(w, y, x, s.c_str());
+}
+void console::mvstr(int y, int x, std::string s, int col) {
+  col = cattr(col);
+  if(w == NULL) {
+    attrset(col);
+    mvaddstr(y, x, s.c_str());
+  }
+  else {
+    wattrset(w, col);
+    mvwaddstr(w, y, x, s.c_str());
+  }
+}
+void console::clr() {
+  if(w == NULL) clear();
+  else wclear(w);
+}
+
+int console::getwidth() {
+  if(w == NULL) return COLS;
+  int x, y;
+  getmaxyx(w, y, x);
+  return x;
+}
+int console::getheight() {
+  if(w == NULL) return LINES;
+  int x, y;
+  getmaxyx(w, y, x);
+  return y;
+}
+  
+std::string console::input() {
+  char a = getch();
+  std::string inp = "";
+  while(a != '\n') {
+    if(a == 7) {
+      if(inp.length() > 0) {
+	inp = inp.substr(0, inp.length() - 1);
+	int x, y;
+	if(w == NULL) getyx(stdscr, y, x);
+	else getyx(w, y, x);
+	mvch(y, x-1, ' ');
+	if(w == NULL) move(y, x-1);
+	else wmove(w, y, x-1);
+      }
+    }
+    else {
+      inp = inp + a;
+      ch(a);
+    }
+    a = getch();
+  }
+  ch('\n');
+  return inp;
+}
+char console::get() {
+  return getch();
+}
+
+int console::print() {
+	using std::cout;
+	using std::endl;
+  if(created == 0 && deleted == 0) return 0;
+  cout << "--console--" << endl;
+  cout << "  Created: " << created << endl;
+  cout << "  Deleted: " << deleted << endl;
+  cout << endl;
+  return created != deleted;
+}
+
+console::~console() {
+  delete w;
+  deleted++;
+}
+
+#endif
addfile ./console.h
hunk ./console.h 1
+#include <curses.h>
+#include <string>
+#include <sstream>
+
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+enum {BLACK=0, RED, GREEN, BROWN, BLUE, PURPLE, CYAN, GREY,
+      BRIGHTRED,
+      BRIGHTGREEN,
+      YELLOW,
+      BRIGHTBLUE,
+      BRIGHTPURPLE,
+      BRIGHTCYAN,
+      WHITE};
+
+class console {
+  private:
+    WINDOW *w;
+    static int created;
+    static int deleted;
+  public:
+    console();
+    console(WINDOW*);
+    
+    console operator<<(std::string&);
+    console operator<<(char*);
+    console operator<<(int);
+    console operator<<(char);
+
+    static int cattr(int);
+    void setcol(int);
+    
+    void ch(char);
+    void ch(char, int);
+    void mvch(int, int, char);
+    void mvch(int, int, char, int);
+	void ch(chtype c, int col);
+    void str(std::string);
+    void str(std::string, int);
+    void mvstr(int, int, std::string);
+    void mvstr(int, int, std::string, int);
+    void mv(int, int);
+    void clr();
+
+    int getwidth();
+    int getheight();
+    
+	std::string input();
+    char get();
+
+    static int print();
+
+    ~console();
+};
+
+#endif
addfile ./egg.cc
hunk ./egg.cc 1
+#include "egg.h"
+#include "map.h"
+#include <curses.h>
+
+egg::egg() {
+	setchar('8');
+	setcol(RED);
+	live = true;
+	settype("egg");
+	hatchtime = 10;
+}
+
+bool egg::move() {
+	if (!hatchtime) return false;
+	hatchtime--;
+	if (hatchtime < 3) setcol(BRIGHTRED);
+	return true;
+}
+bool egg::hatched() { return !hatchtime; }
addfile ./egg.h
hunk ./egg.h 1
+#ifndef EGG_H
+#define EGG_H
+
+#include "beast.h"
+
+class egg : public beast {
+	public:
+		egg();
+
+		bool move();
+		bool hatched();
+
+	private:
+		int hatchtime;
+};
+
+#endif
addfile ./main.cc
hunk ./main.cc 1
+#include <unistd.h>
+#include <iostream>
+#include <stdlib.h>
+#include <curses.h>
+#include <string>
+#include <pthread.h>
+#include <math.h>
+#include <vector>
+#include "map.h"
+#include "console.h"
+#include "block.h"
+#include "wall.h"
+#include "player.h"
+#include "beast.h"
+#include "super.h"
+#include "baby.h"
+#include "main.h"
+#include "egg.h"
+
+// the map object to use for storing all our game info.
+map* m;
+player* playas[NUM_PLAYERS];
+
+// forward declaration of functions used by threads
+void *level_thread(void *arg);
+void *super_beast_thread(void *arg);
+void *beast_thread(void *arg);
+void *egg_thread(void *arg);
+
+int level = 1;
+
+int main() {
+	using namespace std;
+
+	// various ncurses initialization calls.
+	initscr(); cbreak(); noecho(); start_color();
+	halfdelay(1);
+	keypad(stdscr, true);
+	// initialize colorpair values, brought to you by the ncurses
+	// manpage
+	for(int i = 0; i < COLOR_PAIRS; i++)
+		init_pair(i, i%COLORS, i/COLORS);
+
+	// screenwriting buffer console
+	console *c = new console();
+	m = new map(COLS-1, LINES-1);
+
+	// so far this is all just testing stuff
+	// create some objects and print them to a console
+	block b;
+	wall w;
+
+	// the map object has it's own methods for writing itself to
+	// a console, which is set by the setcon() function
+	m->setcon(c);
+	// different map functions
+	m->scatter(&b, int(COLS*LINES*.5));
+	m->makeborder(&w);
+
+	for (int i = 0; i < NUM_PLAYERS; i++) {
+		playas[i] = new player(i);
+		m->scatter(playas[i]);
+	}
+
+	bool liveplayers;
+	if (NUM_PLAYERS) liveplayers = true;
+
+	level = 1;
+	pthread_t levthread;
+	pthread_create(&levthread, NULL, level_thread, NULL);
+	while (liveplayers) {
+		m->printmap();
+		// refresh is an ncurses function, just redraws the screen
+		refresh();
+
+		liveplayers = false;
+		char ch = getch();
+		for (int i = 0; i < NUM_PLAYERS; i++) {
+			if (playas[i]->isalive()) liveplayers = true;
+			playas[i]->move(ch);
+		}
+	}
+	level = 0;
+
+	//m->printmap();
+	//refresh();
+	//char a;
+	//cin >> a;
+	// weird stuff happens when the program ends if you don't use endwin()
+	refresh();
+	endwin();
+	delete m;
+	delete c;
+
+	int winner[] = {0, 0};
+	for (int i = 0; i < NUM_PLAYERS; i++) {
+		if (playas[i]->getscore() > winner[1]) {
+			winner[0] = i;
+			winner[1] = playas[i]->getscore();
+		}
+		cout << "Player " << i << ": " << playas[i]->getscore() << endl;
+	}
+	cout << "Player " << winner[0] << " winned!" << endl;
+}
+
+void *level_thread(void *arg) {
+
+	for (level = 1; level <= 10; level++) {
+		int beasts = 3 + level*2;
+		int supers = (int)((level-1)*sqrt((double)level/2));
+		int eggs = (int)(((double)level/3)*level/3);
+
+		vector<pthread_t> threads;
+		int i;
+		for (i = 0; i < beasts; i++) {
+			pthread_t newthread;
+			pthread_create(&newthread, NULL, beast_thread, NULL);
+			threads.push_back(newthread);
+		}
+		for (i = 0; i < supers; i++) {
+			pthread_t newthread;
+			pthread_create(&newthread, NULL, super_beast_thread, NULL);
+			threads.push_back(newthread);
+		}
+		for (i = 0; i < eggs; i++) {
+			pthread_t newthread;
+			pthread_create(&newthread, NULL, egg_thread, NULL);
+			threads.push_back(newthread);
+		}
+
+		for (i = 0; i < threads.size(); i++)
+			pthread_join(threads[i], NULL);
+	}
+
+	level = 0;
+}	
+		
+void *beast_thread(void *arg) {
+	beast *b;
+	if (arg) b = (beast*)arg;
+	else {
+		b = new beast();
+		m->scatter(b);
+	}
+
+	while (b->isalive() && level)
+	{
+		usleep(1000000);
+		b->move();
+	}
+
+	delete b;
+
+	return NULL;
+}
+
+void *super_beast_thread(void *arg) {
+	super *b;
+	if (arg) b = (super*)arg;
+	else {
+		b = new super();
+		m->scatter(b);
+	}
+
+	while (b->isalive() && !b->explode() && level)
+	{
+		usleep(1000000);
+		b->move();
+	}
+
+	pthread_t threads[5];
+	bool thread_created[5];
+	if (b->explode()) {
+		int bx = b->getx();
+		int by = b->gety();
+		m->setsprite(bx, by, new block());
+		// spawn new beast threads
+		int j = 0;
+		for (int i = 0; i < 9; i++)
+		{
+			int x = bx + (i % 3) - 1;
+			int y = by + (i / 3) - 1;
+
+			if (i % 2) {
+				string type = "null";
+				if (m->spriteat(x, y))
+					type = m->spriteat(x, y)->mytype();
+				if (type == "block" || type == "null")
+					m->setsprite(x, y, NULL);
+			}
+			else {
+				string type = "null";
+				if (m->spriteat(x, y))
+					type = m->spriteat(x, y)->mytype();
+				if (type == "block" || type == "null") {
+					beast *spawn = new beast();
+					m->setsprite(x, y, NULL);
+					spawn->setpos(x, y);
+					m->setsprite(x, y, spawn);
+
+					if (j < 5) {
+						thread_created[j] = true;
+						pthread_create(&threads[j++], NULL, beast_thread, (void*)spawn);
+					} else thread_created[j++] = false;
+				}
+			}
+		}
+	}
+
+	// wait on sub threads
+	for (int j = 0; j < 5; j++)
+		if (thread_created[j])
+			pthread_join(threads[j], NULL);
+
+	delete b;
+	return NULL;
+}
+
+void *egg_thread(void *arg) {
+	egg *e;
+	if (arg) e = (egg*)arg;
+	else {
+		e = new egg;
+		m->scatter(e);
+	}
+
+	while (e->isalive() && !e->hatched() && level)
+	{
+		usleep(1000000);
+		e->move();
+	}
+
+	pthread_t thread;
+	bool spawned = false;
+	if (e->isalive()) {
+		// spawn new beast thread
+		baby *spawn = new baby;
+		spawn->setpos(e->getx(), e->gety());
+
+		pthread_create(&thread, NULL, beast_thread, (void*)spawn);
+		spawned = true;
+	}
+
+	delete e;
+
+	if (spawned) pthread_join(thread, NULL);
+
+	return NULL;
+}
addfile ./main.h
hunk ./main.h 1
+#ifndef MAIN_H
+#define MAIN_H
+
+#include "map.h"
+#include "player.h"
+
+const int NUM_PLAYERS = 2;
+extern map* m;
+extern player* playas[];
+
+#endif
addfile ./map.cc
hunk ./map.cc 1
+#include "map.h"
+#include <iostream>
+#include <fstream>
+
+#ifndef MAP_CC
+#define MAP_CC
+
+int map::created = 0;
+int map::deleted = 0;
+
+int DIRX[] = {0, 1, 1, 1, 0,-1,-1,-1, 0};
+int DIRY[] = {1, 1, 0,-1,-1,-1, 0, 1, 0};
+
+map::map(int x, int y) {
+	height = y;
+	width = x;
+	for(int i = 0; i < height; i++) {
+		rows.push_back(new row(width));
+	}
+	created++;
+}
+
+void map::makeborder(sprite* s) {
+	for(int i = 0; i < getwidth(); i++) {
+		setsprite(i, 0, s);
+		setsprite(i, height-1, s);
+		setsprite(0, i, s);
+		setsprite(width-1, i, s);
+	}
+}
+void map::scatter(sprite* s, int num) {
+	int x, y;
+	for(int i = 0; i < num; i++) {
+		do {
+			x = (rand()%(width-2)) + 1;
+			y = (rand()%(height-2)) + 1;
+		} while (s->setpos(x, y) != 0);
+		setsprite(x, y, s);
+	}
+}
+
+int map::getwidth() {return width;}
+int map::getheight() {return height;}
+
+void map::extendx(int x) {
+	if(x == 0) return;
+	if(x > 0) width += x; else width -= x;
+	for(int i = 0; i < height; i++) {
+		rows[i]->extend(x);
+	}
+}
+void map::extendy(int y) {
+	if(y == 0) return;
+	if(y < 0) {
+		height -= y;
+		for(int i = y; i < 0; i++) {
+			rows.insert(rows.begin(), new row(width));
+		}
+	} else {
+		height += y;
+		for(int i = 0; i < y; i++) {
+			rows.push_back(new row(width));
+		}
+	}
+}
+
+void map::addrow(int y) {
+	if(y < 0 || y >= height) return;
+	rows.insert(rows.begin() + y, new row(width));
+	height++;
+}
+void map::addcol(int x) {
+	if(x < 0 || x >= width) return;
+	for(int y = 0; y < height; y++) {
+		rows[y]->addspace(x);
+	}
+	width++;
+}
+void map::remrow(int y) {
+	if(y < 0 || y >= height) return;
+	delete rows[y];
+	rows.erase(rows.begin() + y);
+	height--;
+}
+void map::remcol(int x) {
+	if(x < 0 || x >= width) return;
+	for(int y = 0; y < height; y++) {
+		rows[y]->remspace(x);
+	}
+	width--;
+}
+
+sprite* map::spriteat(int x, int y) {
+	if(!inbounds(x, y)) return NULL;
+	return rows[y]->spriteat(x);
+}
+void map::setsprite(int x, int y, sprite* s) {
+	if(!inbounds(x, y)) return;
+	rows[y]->setsprite(x, s);
+}
+
+bool map::inbounds(int x, int y) {
+	if(x < width && x >= 0 && y < height && y >= 0) return true;
+	return false;
+}
+
+void map::setcon(console *con) {c = con;}
+
+void map::printmap() {
+	if(c == NULL) return;
+	c->mv(0,0);
+	int x, y;
+	for(y = 0; y < getheight(); y++) {
+		for(x = 0; x < getwidth(); x++) {
+			sprite* s = spriteat(x, y);
+			if (s == NULL) {
+				c->setcol(BLACK);
+				*c << ' ';
+			}
+			else
+			{
+				c->ch(s->mychar(), s->mycol());
+			}
+		}
+		*c << '\n';
+	}
+	*c << '\n';
+}
+
+bool map::savemap(std::string fname) {
+	std::ofstream file(fname.c_str(), std::ios::out);
+	if(!file) return false;
+
+	int x, y;
+	for(int y = 0; y < height; y++) {
+		for(x = 0; x < width; x++) {
+			file << spriteat(x, y)->mysavechar();
+		}
+		if(y != height) file << '\n';
+	}
+}
+
+int map::print() {
+	using std::cout;
+	using std::endl;
+	if(created == 0 && deleted == 0) return 0;
+	cout << "--map--" << endl;
+	cout << "  Created: " << created << endl;
+	cout << "  Deleted: " << deleted << endl;
+	cout << endl;
+	return created != deleted;
+}
+
+map::~map() {
+	while(rows.size() > 0) {
+		delete rows[0];
+		rows.erase(rows.begin());
+	}
+	deleted++;
+}
+
+#endif
addfile ./map.h
hunk ./map.h 1
+#ifndef MAP_H
+#define MAP_H
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <fstream>
+#include "console.h"
+#include "row.h"
+
+extern int DIRX[];
+extern int DIRY[];
+
+class map {
+  private:
+    static int created;
+    static int deleted;
+
+    console *c;
+    int height;
+    int width;
+	std::vector<row*> rows;
+  public:
+    map(int,int);
+
+    void makeborder(sprite* s);
+    void scatter(sprite* s, int num=1);
+
+    int getwidth();
+    int getheight();
+
+    void extendx(int);
+    void extendy(int);
+
+    void addrow(int);
+    void addcol(int);
+    void remrow(int);
+    void remcol(int);
+    
+    sprite* spriteat(int x, int y);
+    void setsprite(int x, int y, sprite* s);
+
+    bool inboundsx(int x);
+    bool inboundsy(int y);
+    bool inbounds(int x, int y);
+
+    void setcon(console*);
+    void printmap();
+    void printmap(console *c);
+
+    bool savemap(std::string fname);
+	
+    static int print();
+
+    ~map();
+};
+#endif
addfile ./player.cc
hunk ./player.cc 1
+#include "player.h"
+#include "console.h"
+#include "map.h"
+#include "block.h"
+#include "wall.h"
+#include "main.h"
+#include <assert.h>
+
+// colors for each player
+int colors[] = {CYAN, BRIGHTBLUE, PURPLE, BROWN};
+// movement keys for each player
+char keys[][9] = {",.loiujm","xcdewqaz","",""};
+
+player::player(int n) {
+  setchar('*');
+  setcol(colors[n]);
+  resetscore();
+  resetbonus();
+  live = true;
+  player_number = n;
+  settype("player");
+}
+void player::move(char c) {
+	for (int i = 0; i < strlen(keys[player_number]); i++)
+	{
+		if (c == keys[player_number][i])
+			return move(i);
+	}
+}
+void player::move(int dir) {
+  if (!live) return;
+  sprite* s = m->spriteat(x + DIRX[dir], y + DIRY[dir]);
+  if (s == NULL) {
+	m->setsprite(x, y, NULL);
+	int test = setpos(x + DIRX[dir], y + DIRY[dir]);
+	if (test == 0) {
+		m->setsprite(x, y, this);
+		return;
+	}
+	// i did this whith threads in mind. in the unlikely event something
+	// moved into the new x y position between the first test and the
+	// setpos, this player dies and is docked points, 1 is a beast of
+	// any type, 2 is an egg, 3 is a wall
+	switch (test) {
+	  case 1:
+		incscore(-5);
+		live = false;
+		return;
+		// bigger penalty if you somehow run into a moving egg
+	  case 2:
+		incscore(-10);
+		live = false;
+		return;
+		// this should never happen.
+	  case 3:
+		std::cout << "moving walls?" << std::flush;
+		return;
+	}
+	return;
+  }
+  // now if the spot we were trying to move to does contain a sprite...
+  if (s->mytype() == "block") {
+	// push the block, or try, anyway.
+	int p = ((block *)s)->push(x + DIRX[dir], y + DIRY[dir], dir);
+	if (p == -1) return;
+	m->setsprite(x, y, NULL);
+	setpos(x + DIRX[dir], y + DIRY[dir]);
+	m->setsprite(x, y, this);
+	// the block push function will return an appropriate score if
+	// anything got squished.
+	incscore(p);
+	return;
+  }
+  // now, if you just flat out run into something deadly, you lose even
+  // more points.
+  if (s->mytype() == "beast" || s->mytype() == "baby" ||
+	  s->mytype() == "super") {
+	incscore(-10);
+	m->setsprite(x, y, NULL);
+	live = false;
+	return;
+  }
+  if (s->mytype() == "egg") {
+	incscore(-20);
+	live = false;
+	return;
+  }
+  if (s->mytype() == "wall" && ((wall *)s)->isexplode()) {
+	incscore(-20);
+	m->setsprite(x, y, NULL);
+	live = false;
+	return;
+  }
+  return;
+}
+int player::setpos(int px, int py) {
+  std::string s = "";
+  if (m->spriteat(px, py) == NULL) {
+	s = "null";
+  }
+  else s = m->spriteat(px, py)->mytype();
+  if (s == "block" || s == "null") {
+	x = px; y = py;
+	return 0;
+  }
+  // if for some reason we can't move to the specified coordinates, send
+  // back something that tells what was in the way.
+  if (s == "beast" || s == "baby" || s == "super") return 1;
+  if (s == "egg") return 2;
+  if (s == "wall") return 3;
+}
+void player::incscore(int s) {
+  // you don't get points if your dead!
+  if (!live) return;
+  score += s;
+}
+void player::incbonus(int b) {
+  // likewise with bonuses
+  if (!live) return;
+  bonusmult += b;
+}
+void player::resetscore() {
+  score = 0;
+}
+void player::resetbonus() {
+  bonusmult = 1;
+}
+bool player::isalive() {
+  return live;
+}
+void player::setlive(bool dolive) { live = dolive; }
+int player::squish(int dir) {
+  if (!live) return -1;
+
+  sprite* s = m->spriteat(x + DIRX[dir], y + DIRY[dir]);
+  if (s == NULL) return -1;
+
+  if (s->mytype() == "block" || s->mytype() == "wall") {
+	  incscore(-10);
+	  live = false;
+	  return 10;
+  }
+  return -1;
+}
+
+int player::getx() { return x; }
+int player::gety() { return y; }
+
+int player::getscore() {return score;}
+int player::getbonus() {return bonusmult;}
addfile ./player.h
hunk ./player.h 1
+#ifndef PLAYER_H
+#define PLAYER_H
+
+#include "sprite.h"
+
+class player : public sprite {
+  public:
+	player(int playernum = 0);
+
+	// this function takes an input char and checks if that 'key' will
+	// move the player and in what dir, subsequently calls move(int)
+	void move(char c);
+	void move(int dir);
+	// used by the move function and perhaps warping?
+	int setpos(int px, int py);
+	void incscore(int s);
+	void incbonus(int b);
+	void resetscore();
+	void resetbonus();
+	bool isalive();
+	void setlive(bool dolive);
+	int squish(int dir);
+	int getscore();
+	int getbonus();
+	int getx();
+	int gety();
+	
+  private:
+	int bonusmult;
+	int score;
+	bool live;
+	int player_number;
+
+	int x; int y;
+};
+
+#endif
addfile ./point.cc
hunk ./point.cc 1
+#include "point.h"
+
+point::point() {
+  x = 0; y = 0;
+}
+point::point(int X, int Y) {
+  x = X; y = Y;
+}
+
+int point::getx() {return x;}
+int point::gety() {return y;}
+void point::setx(int n) {
+  x = n;
+}
+void point::sety(int n) {
+  y = n;
+}
+double point::dist(point a) {
+  double dx = a.getx() - x;
+  double dy = a.gety() - y;
+  return sqrt(dx*dx + dy*dy);
+}
addfile ./point.h
hunk ./point.h 1
+#ifndef POINT_H
+#define POINT_H
+
+class point {
+  private:
+	int x, y;
+
+  public:
+	point();
+	point(int x, int y);
+	int getx();
+	int gety();
+	void setx(int n);
+	void sety(int n);
+	double dist(point a);
+};
+
+#endif
addfile ./pointer.cc
hunk ./pointer.cc 1
+#include "point.h"
+#include <iostream>
+
+// this was just a test program for class point
+int main() {
+  point a(3,5);
+  point b(7,10);
+  std::cout << a.dist(b) << endl;
+}
addfile ./row.cc
hunk ./row.cc 1
+#include "row.h"
+#include <iostream>
+
+#ifndef ROW_CC
+#define ROW_CC
+
+int row::created = 0;
+int row::deleted = 0;
+
+row::row(int l) {
+  for(int i = 0; i < l; i++) {
+    sprites.push_back(NULL);
+  }
+  created++;
+}
+
+void row::extend(int a) {
+  if(a == 0) return;
+  if(a < 0) {
+    for(int i = a; i < 0; i++) {
+      sprites.insert(sprites.begin(), NULL);
+    }
+  } else {
+    for(int i = 0; i < a; i++) {
+      sprites.push_back(NULL);
+    }
+  }
+}
+void row::addspace(int x) {
+  if(x < 0 || x >= sprites.size()) return;
+  sprites.insert(sprites.begin() + x, NULL);
+}
+void row::remspace(int x) {
+  if(x < 0 || x >= sprites.size()) return;
+  sprites.erase(sprites.begin() + x);
+}
+
+sprite* row::spriteat(int x) {
+  if(!inbounds(x)) return NULL;
+  return sprites[x];
+}
+void row::setsprite(int x, sprite* s) {
+  if(!inbounds(x)) return;
+  sprites[x] = s;
+}
+bool row::inbounds(int x) {
+  if(x < sprites.size() && x >= 0) return true;
+  return false;
+}
+
+int row::print() {
+	using std::cout;
+	using std::endl;
+	if(created == 0 && deleted == 0) return 0;
+	cout << "--row--" << endl;
+	cout << "  Created: " << created << endl;
+	cout << "  Deleted: " << deleted << endl;
+	cout << endl;
+	return created != deleted;
+}
+
+row::~row() {
+  deleted++;
+}
+#endif
addfile ./row.h
hunk ./row.h 1
+#include <vector>
+#include "sprite.h"
+#ifndef ROW_H
+#define ROW_H
+
+class row {
+  private:
+    static int created;
+    static int deleted;
+
+	std::vector<sprite*> sprites;
+  public:
+    row(int);
+    
+    void extend(int);
+    void addspace(int);
+    void remspace(int);
+    
+    sprite* spriteat(int);
+    void setsprite(int, sprite*);
+    bool inbounds(int);
+
+    static int print();
+
+    ~row();
+};
+#endif
addfile ./sprite.cc
hunk ./sprite.cc 1
+#include "sprite.h"
+#include "console.h"
+
+sprite::sprite() {
+  _mychar = ' ';
+  _mysavechar = ' ';
+  _mycol = BLACK;
+}
+sprite::~sprite() {
+}
+chtype sprite::mychar() const {
+  return _mychar;
+}
+int sprite::mycol() const {
+  return _mycol;
+}
+char sprite::mysavechar() const {
+  return _mysavechar;
+}
+std::string sprite::mytype() const {
+  return _mytype;
+}
+void sprite::setchar(chtype c) {
+  _mysavechar = _mychar = c;
+}
+void sprite::setsavechar(char c) {
+  _mysavechar = c;
+}
+void sprite::setcol(int c) {
+  _mycol = c;
+}
+void sprite::settype(std::string s) {
+  _mytype = s;
+}
+
+int sprite::squish(int dir) {
+  return 0;
+}
+int sprite::setpos(int x, int y) {return 0;}
addfile ./sprite.h
hunk ./sprite.h 1
+#ifndef SPRITE_H
+#define SPRITE_H
+
+#include <string>
+#include <curses.h>
+
+class sprite {
+  public:
+	sprite();
+	~sprite();
+	virtual chtype mychar() const;
+	virtual char mysavechar() const;
+	virtual int mycol() const;
+	virtual std::string mytype() const;
+	virtual void setchar(chtype c);
+	virtual void setsavechar(char c);
+	virtual void setcol(int c);
+	virtual int setpos(int x, int y);
+
+	// when something pushes on a block, and it is found that there is
+	// something at the end of the line of blocks, if it is a sprite,
+	// this method will be called, and the object itself will check what
+	// is in the direction dir and decide itself wether it will be
+	// squished. ie, super beast returns nonzero if there is a wall in
+	// <dir> and if explosive walls is set.
+	virtual int squish(int dir);
+	
+  protected:
+	void settype(std::string t);
+	chtype _mychar;
+	
+	// a different savechar in the event you save a map and you want the
+	// chars in the file to be different from what actually gets
+	// displayed on the screen, I actually used this more for the life
+	// program
+	char _mysavechar;
+	int _mycol;
+	std::string _mytype;
+};
+#endif
addfile ./super.cc
hunk ./super.cc 1
+#include "super.h"
+#include "main.h"
+#include "wall.h"
+#include "player.h"
+#include <curses.h>
+
+super::super() {
+	setchar('H');
+	setcol(BRIGHTRED);
+	live = true;
+	settype("super");
+	exp = false;
+	trapped = 0;
+}
+
+int super::squish(int dir) {
+	if (!live) return -1;
+	sprite* s = m->spriteat(x + DIRX[dir], y + DIRY[dir]);
+	if (s == NULL) return -1;
+
+	if (s->mytype() == "wall" && ((wall *)s)->isexplode()) {
+		live = false;
+		return 5;
+	}
+	return -1;
+}
+
+bool super::move() {
+	if (!live) return false;
+
+	//int dir = dirclose();
+	int score = -1;
+	int dir = -1;
+	sprite *s;
+	for (int i = 0; i < 8; i++) {
+		//dir = (dir + (i * (-1 * (i % 2)))) % 8;
+		std::string type = "null";
+		if (m->spriteat(x + DIRX[i], y + DIRY[i]) != NULL)
+			type = m->spriteat(x + DIRX[i], y + DIRY[i])->mytype();
+
+		//score[i] = '?';
+		if (type == "null" || type == "player") {
+			int tmpscore = -1;
+			for (int p = 0; p < NUM_PLAYERS; p++) {
+				if (playas[p] == NULL || !playas[p]->isalive()) continue;
+				int dx = playas[p]->getx() - (x + DIRX[i]);
+				int dy = playas[p]->gety() - (y + DIRY[i]);
+				int d = (dx * dx + dy * dy);
+				if (tmpscore == -1 || d < tmpscore) tmpscore = d;
+			}
+			if (type == "player")
+				tmpscore = 0;
+			if (tmpscore < score || score == -1) {
+				score = tmpscore;
+				dir = i;
+				s = m->spriteat(x + DIRX[i], y + DIRY[i]);
+			}
+		}
+	}
+	if (dir == -1) {
+		if (++trapped == 10)
+			exp = true;
+		return false;
+	}
+	m->setsprite(x, y, NULL);
+	setpos(x + DIRX[dir], y + DIRY[dir]);
+	if (s != NULL && s->mytype() == "player")
+		((player*)m->spriteat(x, y))->setlive(false);
+	m->setsprite(x, y, this);
+	return true;
+	// we might make beast::move return bool so super can call beast's
+	// move and increment a counter if it returns false
+}
+bool super::explode() { return exp; }
addfile ./super.h
hunk ./super.h 1
+#ifndef SUPER_H
+#define SUPER_H
+
+#include "beast.h"
+
+class super : public beast {
+	public:
+		super();
+
+		bool move();
+		int squish(int dir);
+		bool explode();
+	private:
+		bool exp;
+		int trapped;
+};
+
+#endif
addfile ./wall.cc
hunk ./wall.cc 1
+#include "console.h"
+#include "wall.h"
+
+wall::wall(bool explode) {
+  setchar(ACS_BLOCK);
+  setcol(YELLOW);
+  setexplode(explode);
+  settype("wall");
+}
+
+bool wall::isexplode() const {
+  return exp;
+}
+void wall::setexplode(bool e) {
+  exp = e;
+}
addfile ./wall.h
hunk ./wall.h 1
+#include "sprite.h"
+
+class wall : public sprite {
+  public:
+	wall(bool explode = true);
+
+	bool isexplode() const;
+	void setexplode(bool e);
+  private:
+	// default is true
+	bool exp;
+};
}
