Davidebyzero / Snipes

The classic 1982 text-mode game Snipes, ported from the original DOS executable with 100% identical game logic, with replay recording added
64 stars 11 forks source link

Expose character & colors as configuration #12

Open kamelie1706 opened 4 years ago

kamelie1706 commented 4 years ago

This game is the closest thing I found from a game called "Rats" on CTOS (Convergent technology) I would love to be able to set in a config file my own ascii and color schema.

I might try to give a shot. Think about the endless possibilities to tweak the game with:

This would be awesome!

PS: Last but not least, is their an easy way to make it monochrome/green from the command line?

kamelie1706 commented 4 years ago

Basically expose this part of the code in a config file

// generator static const WORD data_1002[] = {SPRITE_SIZE(2,2), 0xFDA, 0xEBF, 0xDC0, 0xCD9}; static const WORD data_100C[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_1016[] = {SPRITE_SIZE(2,2), 0xEDA, 0xEBF, 0xEC0, 0xED9}; static const WORD data_1020[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_102A[] = {SPRITE_SIZE(2,2), 0xDDA, 0xDBF, 0xDC0, 0xDD9}; static const WORD data_1034[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_103E[] = {SPRITE_SIZE(2,2), 0xCDA, 0xCBF, 0xCC0, 0xCD9}; static const WORD data_1048[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_1052[] = {SPRITE_SIZE(2,2), 0xBDA, 0xBBF, 0xBC0, 0xBD9}; static const WORD data_105C[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_1066[] = {SPRITE_SIZE(2,2), 0xADA, 0xABF, 0xAC0, 0xAD9}; static const WORD data_1070[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_107A[] = {SPRITE_SIZE(2,2), 0x9DA, 0x9BF, 0x9C0, 0x9D9}; static const WORD data_1084[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_108E[] = {SPRITE_SIZE(2,2), 0x4DA, 0x4BF, 0x4C0, 0x4D9}; static const WORD data_1098[] = {SPRITE_SIZE(2,2), 0xEFF, 0xEFF, 0xEFF, 0xEFF}; static const WORD data_10A2[] = {data_1002, data_100C, data_1016, data_1020, data_102A, data_1034, data_103E, data_1048, data_1052, data_105C, data_1066, data_1070, data_107A, data_1084, data_108E, data_1098}; // player static const WORD data_10E2[] = {SPRITE_SIZE(2,2), 0xF93, 0xF93, 0xF11, 0xF10}; static const WORD data_10EC[] = {SPRITE_SIZE(2,2), 0xF4F, 0xF4F, 0xF11, 0xF10}; //static const WORD data_10F6[] = {data_10E2, data_10EC}; // ghost static const WORD data_10FE[] = {SPRITE_SIZE(1,1), 0x202}; // snipe static const WORD data_1108[] = {SPRITE_SIZE(2,1), 0x201, 0x218}; static const WORD data_1112[] = {SPRITE_SIZE(2,1), 0x201, 0x21A}; static const WORD data_111C[] = {SPRITE_SIZE(2,1), 0x201, 0x219}; static const WORD data_1126[] = {SPRITE_SIZE(2,1), 0x21B, 0x201}; static const WORD data_1130[] = {data_1108, data_1112, data_1112, data_1112, data_111C, data_1126, data_1126, data_1126}; // player bullet static const WORD data_1150[] = {SPRITE_SIZE(1,1), 0xE09}; static const WORD data_115A[] = {SPRITE_SIZE(1,1), 0xB0F}; static const WORD data_11D4[] = {data_1150, data_115A, data_1150, data_115A}; // snipe bullet static const WORD data_1164[] = {SPRITE_SIZE(1,1), 0xA18}; static const WORD data_116E[] = {SPRITE_SIZE(1,1), 0xA2F}; static const WORD data_1178[] = {SPRITE_SIZE(1,1), 0xA1A}; static const WORD data_1182[] = {SPRITE_SIZE(1,1), 0xA5C}; static const WORD data_118C[] = {SPRITE_SIZE(1,1), 0xA19}; static const WORD data_1196[] = {SPRITE_SIZE(1,1), 0xA2F}; static const WORD data_11A0[] = {SPRITE_SIZE(1,1), 0xA1B}; static const WORD data_11AA[] = {SPRITE_SIZE(1,1), 0xA5C}; static const WORD data_11B4[] = {data_1164, data_116E, data_1178, data_1182, data_118C, data_1196, data_11A0, data_11AA}; // player or generator explosion static const WORD data_12C2[] = {SPRITE_SIZE(2,2), 0xFB0, 0xFB2, 0xFB2, 0xFB0}; static const WORD data_12CC[] = {SPRITE_SIZE(2,2), 0xBB2, 0xBB0, 0xBB0, 0xBB2}; static const WORD data_12D6[] = {SPRITE_SIZE(2,2), 0xCB0, 0xCB2, 0xCB2, 0xCB0}; static const WORD data_12E0[] = {SPRITE_SIZE(2,2), 0x4B2, 0x4B0, 0x4B0, 0x4B2}; static const WORD data_12EA[] = {SPRITE_SIZE(2,2), 0x62A, 0x60F, 0x62A, 0x60F}; static const WORD data_12F4[] = {SPRITE_SIZE(2,2), 0x807, 0x820, 0x807, 0x820}; static const WORD data_12FE[] = {data_12C2, data_12CC, data_12D6, data_12E0, data_12EA, data_12F4}; // snipe explosion static const WORD data_1316[] = {SPRITE_SIZE(2,1), 0xFB0, 0xFB2}; static const WORD data_1320[] = {SPRITE_SIZE(2,1), 0xBB2, 0xBB0}; static const WORD data_132A[] = {SPRITE_SIZE(2,1), 0xCB0, 0xCB2}; static const WORD data_1334[] = {SPRITE_SIZE(2,1), 0x4B2, 0x4B0}; static const WORD data_133E[] = {SPRITE_SIZE(2,1), 0x62A, 0x60F}; static const WORD data_1348[] = {SPRITE_SIZE(2,1), 0x807, 0x820}; static const WORD data_1352[] = {data_1316, data_1320, data_132A, data_1334, data_133E, data_1348}; // ghost explosion static const WORD data_136A[] = {SPRITE_SIZE(1,1), 0xFB2}; static const WORD data_1374[] = {SPRITE_SIZE(1,1), 0xB0F}; static const WORD data_137E[] = {SPRITE_SIZE(1,1), 0xC09}; static const WORD data_1388[] = {SPRITE_SIZE(1,1), 0x407}; static const WORD data_1392[] = {data_136A, data_136A, data_136A, data_1374, data_137E, data_1388};

CyberShadow commented 4 years ago

I'm not the author but I think these are quite firmly part of the game and not subject to configuration.

I think you may be looking for a clone (reimplementation) of Snipes, instead of this project, which attempts to be a faithful reproduction.

kamelie1706 commented 4 years ago

I do not think this is fundamentally incompatible. I am interested to modify the ascii/graphical representation only not the game logic/engine/spirit itself.

By default you could play it as it looks originally or as you imagine it.

CyberShadow commented 4 years ago

You can already create and use a custom font. I think a monochrome mode would be doable.

kamelie1706 commented 4 years ago

Right I did not thought making my own font! I could indeed change a lot of aspect but changing the font will not do what I have in mind ....Ideally I would like to play it with my own characters from linux terminal.

I am sure that you know this but there was another old port called lsnipes without clear active place where the code is today maintained (done in C/GNU licences). https://launchpad.net/ubuntu/natty/amd64/lsnipes/0.9.4-7

Playable in linux terminal and very easy to tweak as all chars where grouped in one hearder called ... char.h

`/*

ifndef _SNIPES_CHARS_H

define _SNIPES_CHARS_H

//#define PLAIN_CHARS

ifdef PLAIN_CHARS

define HIVE_TOPLEFT '['

define HIVE_TOPRIGHT ']'

define HIVE_BOTTOMLEFT '['

define HIVE_BOTTOMRIGHT ']'

define EVILFACE '0'

define GHOSTFACE '@'

define WEAPON_UP '^'

define WEAPON_DOWN 'v'

define WEAPON_LEFT '<'

define WEAPON_RIGHT '>'

define WEAPON_DIAG_POS '/'

define WEAPON_DIAG_NEG '\'

define PLAYER_LEFTFACE '<'

define PLAYER_RIGHTFACE '>'

define PLAYER_BIGEYE 'O'

define PLAYER_SMALLEYE 'o'

define PLAYER_BULLET_1 'o'

define PLAYER_BULLET_2 '*'

define PLAYER_DIE_1 'o'

define PLAYER_DIE_2 '*'

define PLAYER_DIE_3 '#'

define PLAYER_DIE_4 '%'

define VERTICAL_BAR '|'

define BLANK_CHAR ' '

define VERTICAL_WALL_CHAR '|'

define HORIZONTAL_WALL_CHAR '-'

define UPPER_LEFT_CORNER_CHAR '+'

define LOWER_LEFT_CORNER_CHAR '+'

define UPPER_RIGHT_CORNER_CHAR '+'

define LOWER_RIGHT_CORNER_CHAR '+'

define VERTICAL_T_RIGHT_CHAR '*'

define VERTICAL_T_LEFT_CHAR '*'

define HORIZONTAL_T_UP_CHAR '*'

define HORIZONTAL_T_DOWN_CHAR '*'

define FOUR_WAY_INTERSECTION '*'

/**/

else

/**/

define HIVE_TOPLEFT 0xDA

define HIVE_TOPRIGHT 0xBF

define HIVE_BOTTOMLEFT 0xC0

define HIVE_BOTTOMRIGHT 0xD9

define EVILFACE 0x01

define GHOSTFACE 0x02

define WEAPON_UP 0x18

define WEAPON_DOWN 0x19

/ next 2 were 1A /

define WEAPON_LEFT 0x1D

define WEAPON_RIGHT 0x1D

define WEAPON_DIAG_POS '/'

define WEAPON_DIAG_NEG '\'

define PLAYER_LEFTFACE 0x11

define PLAYER_RIGHTFACE 0x10

define PLAYER_BIGEYE 'O'

define PLAYER_SMALLEYE 0x93

define PLAYER_BULLET_1 0x09

define PLAYER_BULLET_2 0x2A

define PLAYER_DIE_1 0x09

define PLAYER_DIE_2 0x2A

define PLAYER_DIE_3 0xB0

define PLAYER_DIE_4 0xB2

define VERTICAL_BAR 0xB3

define BLANK_CHAR ' '

define VERTICAL_WALL_CHAR 0xBA

define HORIZONTAL_WALL_CHAR 0xCD

define UPPER_LEFT_CORNER_CHAR 0xC9

define LOWER_LEFT_CORNER_CHAR 0xC8

define UPPER_RIGHT_CORNER_CHAR 0xBB

define LOWER_RIGHT_CORNER_CHAR 0xBC

define VERTICAL_T_RIGHT_CHAR 0xCC

define VERTICAL_T_LEFT_CHAR 0xB9

define HORIZONTAL_T_UP_CHAR 0xCA

define HORIZONTAL_T_DOWN_CHAR 0xCB

define FOUR_WAY_INTERSECTION 0xCE

endif

endif // _SNIPES_CHARS_H

`

Davidebyzero commented 4 years ago

PS: Last but not least, is their an easy way to make it monochrome/green from the command line?

To make it act like the original 80×25 monochrome mode of the DOS game acted, I'll need to reverse-engineer it from scratch just like I did for the 40×25 color mode. They are completely separate overlay modules. In fact there are two additional modules for the color demo mode and monochrome demo mode, that I also plan on reverse-engineering.

But to make it monochrome while keeping everything else the same as the color version would be a very easy patch. Is that what you'd like?

I am sure that you know this but there was another old port called lsnipes without clear active place where the code is today maintained (done in C/GNU licences).

The goal of lsnipes is very different – it does not make any effort to act exactly like the original DOS game. It does however, apparently have a way of reading multiple keys at once using ncurses, so that should mean this Snipes could be given a Linux console mode, similar to the Windows console mode it already has.

kamelie1706 commented 4 years ago

Yes overall monochrome with a choosen color would be great!

I managed to compile lsnipes but could not really play it. It was just to give some ideas on how the chars were managed and that it was running in a terminal. I started to check your code for the windows console version hoping it would be as simple to rewrite each functions for linux console but was not sure where to start ... probably need to learn more about the overall code logic before jumping there :-D

I will start experimenting changing characters....

The "Rat"/CTOS version looks very close version of snipes but unfortunatly impossible to find binary nor source at this day ... and even very few screenshot! https://flic.kr/p/5XkxY2 https://flic.kr/p/5XpR25 https://flic.kr/p/5XkvD6 https://flic.kr/p/5XpF1L

No wonder it looked the same according to this article ... Rat was actually the game which inspired Snipes Here's the story of Snipes, as told by Major: https://www.networkworld.com/article/2297960/novell-and-the-computer-game-that-changed-networking.html “When SuperSet (Kyle Powell, Dale Neibaur, Mark Hurst and I) bought our first IBM PC in February 1982, there were no good games and hardly any software available for it. The only games were some lame BASIC-language games such as Donkey, written by Bill Gates, where you were driving down the road and had to jump from lane to lane to avoid hitting donkeys.

We wrote Snipes so we could have a 'real’ non-BASIC game to play on the PC. It was based on a game called Rats, which was available on Convergent Technologies’ computers. Snipes was constrained by the limitations of the character-only monochrome IBM screens. It was written in PLM [Programming Language for Microcomputers], which was the only compiler available to us, as the C programming language hadn’t been ported to the PC yet.

We wrote Snipes in the spring of 1982 and sold the single-user version through ComputerLand for about a year. It was one of the first PC games, and got several good reviews. We sold several thousand copies."

And to conclude ... I understand the real orginal version of Snipes was monochrome :-D!

kamelie1706 commented 4 years ago

Back a bit to the code Could you explain the 3 digits hex code?

// ghost
static const WORD data_10FE[] = {SPRITE_SIZE(1,1), 0x202};

ASCII is normally 2 digit hex, I guess the extra digit is for the color?

Sorry for the dummy/noob question :-(