├── .gitignore ├── LICENCE1 ├── Makefile ├── Music ├── mod.get psyched ├── mod.lose ├── mod.metal heads ├── mod.metallic bop amiga ├── mod.robot attack ├── mod.rushin in ├── mod.soundfx └── mod.win ├── PT2.3A_replay_cia.cpp ├── PT2.3A_replay_cia.h ├── Palette.cpp ├── Palette.h ├── Platform.cpp ├── Platform.h ├── PlatformSDL.cpp ├── PlatformSDL.h ├── README ├── SDL ├── .gitignore ├── animtiles.png ├── c64font.png ├── faces.png ├── gameover.png ├── gamescreen.png ├── health.png ├── introscreen.png ├── items.png ├── keys.png ├── level-a ├── level-b ├── level-c ├── level-d ├── level-e ├── level-f ├── level-g ├── level-h ├── level-i ├── level-j ├── level-k ├── level-l ├── level-m ├── level-n ├── petfont.png ├── setup.sh ├── sprites.png ├── spritesalpha.png ├── spritesmask.png ├── tiles.png └── tilesalpha.png ├── SDL_src └── VC │ ├── SDL2 │ └── .placeholder │ └── SDL2_image │ └── .placeholder ├── Sounds ├── SOUND_BEEP.raw ├── SOUND_BEEP2.raw ├── SOUND_CYCLE_ITEM.raw ├── SOUND_CYCLE_WEAPON.raw ├── SOUND_DOOR_FASTER.raw ├── SOUND_EMP.raw ├── SOUND_ERROR.raw ├── SOUND_FOUND_ITEM.raw ├── SOUND_MAGNET2.raw ├── SOUND_MEDKIT.raw ├── SOUND_MOVE.raw ├── SOUND_PLASMA_FASTER.raw ├── SOUND_SHOCK.raw ├── sounds_dsbarexp.raw └── sounds_dspistol.raw ├── Tiletool ├── .gitignore ├── Tiletool.pro └── main.cpp ├── WindowsProject.sln ├── WindowsProject ├── WindowsProject.vcxproj ├── WindowsProject.vcxproj.user ├── WindowsProject1.vcxproj.filters └── WindowsProject1.vcxproj.user ├── petrobots.cpp ├── petrobots.h ├── tileset.amiga └── tileset.pet /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .DS_Store 3 | petrobots 4 | 5 | SDL_src/VC/SDL2/* 6 | SDL_src/VC/SDL2_image/* 7 | !.placeholder 8 | x64 9 | .vs -------------------------------------------------------------------------------- /LICENCE1: -------------------------------------------------------------------------------- 1 | The source-code is being provided as is. You can study it and modify it but you can't distribute any direct modifications without permission from David Murray. If you think a modification is good, you can contact us 2 | and it MIGHT be able to form part of official builds. 3 | Commerical exploitation is not permitted, again without permission from David Murray. 4 | The source-code CAN be used to adapt the game to run on other systems but any new ports must NOT be distributed without David's permission and it would be appreciated that any new ports would have their source-code be 5 | made avaliable for Github. 6 | Enhanced versions which run on a particular set of source code (like gZDoom) can be freely distributed but the end user must provide the source files from a legally purchased copy of the game themselves - no source files 7 | are to be distributed. Myself and David Murray will not provide any technical support for enhanced versions. 8 | I myself am not responsible for technical issues, especially when it comes to compiling source code as I have no knowledge of it but I can be approached when it comes to testing. 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS :=-g -std=c++11 -fsigned-char -DPLATFORM_NAME=\"sdl\" -DPLATFORM_SCREEN_WIDTH=440 -DPLATFORM_SCREEN_HEIGHT=224 -DPLATFORM_MAP_WINDOW_TILES_WIDTH=16 -DPLATFORM_MAP_WINDOW_TILES_HEIGHT=8 -DPLATFORM_INTRO_OPTIONS=3 -DPLATFORM_DEFAULT_CONTROL=3 -DPLATFORM_MODULE_BASED_AUDIO -DPLATFORM_TILE_BASED_RENDERING -DPLATFORM_IMAGE_BASED_TILES -DPLATFORM_IMAGE_SUPPORT -DPLATFORM_SPRITE_SUPPORT -DPLATFORM_COLOR_SUPPORT -DPLATFORM_CURSOR_SUPPORT -DPLATFORM_CURSOR_SHAPE_SUPPORT -DPLATFORM_FADE_SUPPORT -DPLATFORM_LIVE_MAP_SUPPORT -DOPTIMIZED_MAP_RENDERING 2 | LDFLAGS := 3 | 4 | CXXFLAGS += `pkg-config --cflags sdl2` 5 | CXXFLAGS += `pkg-config --cflags SDL2_image` 6 | LDFLAGS += `pkg-config --libs sdl2` 7 | LDFLAGS += `pkg-config --libs SDL2_image` 8 | 9 | SOURCES := petrobots.cpp Platform.cpp PlatformSDL.cpp PT2.3A_replay_cia.cpp 10 | OBJECTS := $(SOURCES:.cpp=.o) 11 | TARGET := petrobots 12 | 13 | all: $(TARGET) setup 14 | 15 | .cpp.o: 16 | $(CXX) $(CXXFLAGS) -c -o $@ $< 17 | 18 | $(TARGET): $(OBJECTS) 19 | $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) 20 | 21 | setup: 22 | SDL/setup.sh 23 | 24 | clean: 25 | rm -f $(OBJECTS) $(TARGET) 26 | -------------------------------------------------------------------------------- /Music/mod.get psyched: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.get psyched -------------------------------------------------------------------------------- /Music/mod.lose: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.lose -------------------------------------------------------------------------------- /Music/mod.metal heads: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.metal heads -------------------------------------------------------------------------------- /Music/mod.metallic bop amiga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.metallic bop amiga -------------------------------------------------------------------------------- /Music/mod.robot attack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.robot attack -------------------------------------------------------------------------------- /Music/mod.rushin in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.rushin in -------------------------------------------------------------------------------- /Music/mod.soundfx: -------------------------------------------------------------------------------- 1 | soundfx@@@@@@@@@@@@@@@@M.K. -------------------------------------------------------------------------------- /Music/mod.win: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Music/mod.win -------------------------------------------------------------------------------- /PT2.3A_replay_cia.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "PT2.3A_replay_cia.h" 4 | 5 | /************************************************** 6 | * ----- Protracker V2.3A Playroutine ----- * 7 | **************************************************/ 8 | 9 | /* 10 | * CIA Version 1: 11 | * Call mt_init to initialize the song. To end the song and turn 12 | * off all voices, call mt_end. 13 | * 14 | * This playroutine is not very fast, optimized or well commented, 15 | * but all the new commands in PT2.3 should work. 16 | * If it's not good enough, you'll have to change it yourself. 17 | * We'll try to write a faster routine soon... 18 | * 19 | * Changes from V1.0C playroutine: 20 | * - Vibrato depth changed to be compatible with Noisetracker 2.0. 21 | * You'll have to double all vib. depths on old PT modules. 22 | * - Funk Repeat changed to Invert Loop. 23 | * - Period set back earlier when stopping an effect. 24 | * 25 | * Converted from ProTracker_v2.3a_CIA.s by Vesuri/dA JoRMaS. 26 | */ 27 | 28 | void putLong(uint8_t* array, uint32_t offset, uint32_t value) 29 | { 30 | array[offset] = (value & 0xff000000) >> 24; 31 | array[offset + 1] = (value & 0xff0000) >> 16; 32 | array[offset + 2] = (value & 0xff00) >> 8; 33 | array[offset + 3] = value & 0xff; 34 | } 35 | 36 | void putWord(uint8_t* array, uint32_t offset, uint32_t value) 37 | { 38 | array[offset] = (value & 0xff00) >> 8; 39 | array[offset + 1] = value & 0xff; 40 | } 41 | 42 | uint32_t getLong(uint8_t* array, uint32_t offset) 43 | { 44 | return (array[offset] << 24) | (array[offset + 1] << 16) | (array[offset + 2] << 8) | array[offset + 3]; 45 | } 46 | 47 | uint16_t getWord(uint8_t* array, uint32_t offset) { 48 | return (array[offset] << 8) | array[offset + 1]; 49 | } 50 | 51 | AudioChannel::AudioChannel(uint8_t id) : 52 | id(id), 53 | data(0), 54 | length(0), 55 | period(420), 56 | volume(0), 57 | dmaStart(0), 58 | dmaCurrent(0), 59 | dmaEnd(0), 60 | dmacon(false) 61 | { 62 | } 63 | 64 | void AudioChannel::process(int16_t* buffer, uint32_t samples, uint32_t sampleRate, bool add) { 65 | if (!data || !dmacon) { 66 | if (!add) { 67 | for (uint32_t i = 0; i < samples; i++) { 68 | *buffer++ = 0; 69 | } 70 | } 71 | return; 72 | } 73 | 74 | float dmaPerSample = (float)7093789.2 / period / sampleRate / 2; 75 | 76 | if (add) { 77 | for (uint32_t i = 0; i < samples; i++) { 78 | *buffer++ += 32 * dmaStart[(int)dmaCurrent] * volume / 64; 79 | dmaCurrent += dmaPerSample; 80 | if (dmaCurrent >= dmaEnd) { 81 | dmaStart = data; 82 | dmaCurrent -= dmaEnd; 83 | dmaEnd = float(length * 2); 84 | } 85 | } 86 | } else { 87 | for (uint32_t i = 0; i < samples; i++) { 88 | *buffer++ = 32 * dmaStart[(int)dmaCurrent] * volume / 64; 89 | dmaCurrent += dmaPerSample; 90 | if (dmaCurrent >= dmaEnd) { 91 | dmaStart = data; 92 | dmaCurrent -= dmaEnd; 93 | dmaEnd = (float)(length * 2); 94 | } 95 | } 96 | } 97 | } 98 | 99 | void AudioChannel::start() { 100 | dmaStart = data; 101 | dmaCurrent = 0; 102 | dmaEnd = (float)(length * 2); 103 | dmacon = true; 104 | } 105 | 106 | void AudioChannel::stop() { 107 | dmacon = false; 108 | } 109 | 110 | // ---- CIA Interrupt ---- 111 | 112 | bool ciaapra = false; 113 | float ciatar = 0; 114 | float ciataw = 14187; 115 | AudioChannel channel0(0); 116 | AudioChannel channel1(1); 117 | AudioChannel channel2(2); 118 | AudioChannel channel3(3); 119 | AudioChannel channel4(4); 120 | AudioChannel channel5(5); 121 | AudioChannel channel6(6); 122 | AudioChannel channel7(7); 123 | void processAudio(int16_t* outputBuffer, uint32_t outputLength, uint32_t sampleRate) 124 | { 125 | float timerAdvancePerSample = (float)709378.92 / (float)sampleRate; 126 | 127 | int16_t *bufferPosition = outputBuffer; 128 | for (uint32_t samplesLeft = outputLength; samplesLeft > 0;) { 129 | // Number of samples to process before interrupt 130 | uint32_t samplesToProcess = MIN((uint32_t)(ciatar / timerAdvancePerSample) + 1, samplesLeft); 131 | 132 | // Process each audio channel 133 | channel0.process(bufferPosition, samplesToProcess, sampleRate, false); 134 | channel1.process(bufferPosition, samplesToProcess, sampleRate, true); 135 | channel2.process(bufferPosition, samplesToProcess, sampleRate, true); 136 | channel3.process(bufferPosition, samplesToProcess, sampleRate, true); 137 | channel4.process(bufferPosition, samplesToProcess, sampleRate, true); 138 | channel5.process(bufferPosition, samplesToProcess, sampleRate, true); 139 | channel6.process(bufferPosition, samplesToProcess, sampleRate, true); 140 | channel7.process(bufferPosition, samplesToProcess, sampleRate, true); 141 | bufferPosition += samplesToProcess; 142 | 143 | // Run the vertical blank interrupt if required 144 | ciatar -= samplesToProcess * timerAdvancePerSample; 145 | if (ciatar < 0) { 146 | ciatar += ciataw; 147 | mt_music(); 148 | } 149 | 150 | // Samples left 151 | samplesLeft -= samplesToProcess; 152 | } 153 | }; 154 | 155 | // ---- Tempo ---- 156 | 157 | uint16_t RealTempo = 125; 158 | uint32_t TimerValue = 1773447; 159 | 160 | // ---- Playroutine ---- 161 | 162 | void mt_init(uint8_t* songData) 163 | { 164 | mt_end(); 165 | 166 | mt_SongDataPtr = songData; 167 | 168 | uint8_t lastPattern = 0; 169 | for (int position = 952; position < 952 + 128; position++) { 170 | uint8_t pattern = mt_SongDataPtr[position]; 171 | if (pattern > lastPattern) { 172 | lastPattern = pattern; 173 | } 174 | } 175 | 176 | for (int sample = 0, sampleDataOffset = 20, sampleStart = ((lastPattern + 1) << 10) + 1084; sample < 15; sample++, sampleDataOffset += 30) { 177 | if (getWord(mt_SongDataPtr, sampleDataOffset + 28) == 0) { 178 | putWord(mt_SongDataPtr, sampleDataOffset + 28, 1); 179 | } 180 | if (getWord(mt_SongDataPtr, sampleDataOffset + 28) == 1) { 181 | putWord(mt_SongDataPtr, sampleStart, 0); 182 | } 183 | mt_SampleStarts[sample] = (int8_t*)(mt_SongDataPtr + sampleStart); 184 | sampleStart += getWord(mt_SongDataPtr, sampleDataOffset + 22) * 2; 185 | } 186 | 187 | ciaapra = true; 188 | RealTempo = 125; 189 | mt_speed = 6; 190 | mt_counter = 0; 191 | mt_SongPos = 0; 192 | mt_PatternPos = 0; 193 | 194 | ciataw = (float)std::floor(TimerValue / RealTempo); 195 | ciatar = ciataw; 196 | } 197 | 198 | void mt_end() 199 | { 200 | mt_Enable = false; 201 | channel0.volume = 0; 202 | channel1.volume = 0; 203 | channel2.volume = 0; 204 | channel3.volume = 0; 205 | channel4.volume = 0; 206 | channel5.volume = 0; 207 | channel6.volume = 0; 208 | channel7.volume = 0; 209 | channel0.dmacon = false; 210 | channel1.dmacon = false; 211 | channel2.dmacon = false; 212 | channel3.dmacon = false; 213 | channel4.dmacon = false; 214 | channel5.dmacon = false; 215 | channel6.dmacon = false; 216 | channel7.dmacon = false; 217 | } 218 | 219 | void mt_start() 220 | { 221 | mt_Enable = true; 222 | } 223 | 224 | void mt_music() 225 | { 226 | if (!mt_Enable) { 227 | return; 228 | } 229 | mt_counter++; 230 | if (mt_counter < mt_speed) { 231 | mt_NoNewAllChannels(); 232 | mt_NoNewPosYet(); 233 | } else { 234 | mt_counter = 0; 235 | if (mt_PattDelTime2 == 0) { 236 | mt_GetNewNote(); 237 | } else { 238 | mt_NoNewAllChannels(); 239 | } 240 | 241 | mt_PatternPos += 16; 242 | if (mt_PattDelTime != 0) { 243 | mt_PattDelTime2 = mt_PattDelTime; 244 | mt_PattDelTime = 0; 245 | } 246 | if (mt_PattDelTime2 != 0) { 247 | mt_PattDelTime2 -= 1; 248 | if (mt_PattDelTime2 != 0) { 249 | mt_PatternPos -= 16; 250 | } 251 | } 252 | if (mt_PBreakFlag != 0) { 253 | mt_PBreakFlag = 0; 254 | mt_PatternPos = mt_PBreakPos << 4; 255 | mt_PBreakPos = 0; 256 | } 257 | if (mt_PatternPos < 1024) { 258 | mt_NoNewPosYet(); 259 | } else { 260 | mt_NextPosition(); 261 | } 262 | } 263 | } 264 | 265 | void mt_NoNewAllChannels() 266 | { 267 | mt_CheckEfx(channel0, mt_chan1temp); 268 | mt_CheckEfx(channel1, mt_chan2temp); 269 | mt_CheckEfx(channel2, mt_chan3temp); 270 | mt_CheckEfx(channel3, mt_chan4temp); 271 | mt_CheckEfx(channel4, mt_chan5temp); 272 | mt_CheckEfx(channel5, mt_chan6temp); 273 | mt_CheckEfx(channel6, mt_chan7temp); 274 | mt_CheckEfx(channel7, mt_chan8temp); 275 | } 276 | 277 | void mt_GetNewNote() 278 | { 279 | int pattpo = 952; 280 | int patternOffset = (mt_SongDataPtr[pattpo + mt_SongPos] << 10) + mt_PatternPos; 281 | mt_PlayVoice(channel0, mt_chan1temp, mt_SongDataPtr + 1084, patternOffset); 282 | mt_PlayVoice(channel1, mt_chan2temp, mt_SongDataPtr + 1084, patternOffset + 4); 283 | mt_PlayVoice(channel2, mt_chan3temp, mt_SongDataPtr + 1084, patternOffset + 8); 284 | mt_PlayVoice(channel3, mt_chan4temp, mt_SongDataPtr + 1084, patternOffset + 12); 285 | if (mt_chaninputs[0].note != 0) { 286 | mt_PlayVoice(channel4, mt_chan5temp, (uint8_t*)&mt_chaninputs[0], 0); 287 | mt_chaninputs[0].note = 0; 288 | } 289 | if (mt_chaninputs[1].note != 0) { 290 | mt_PlayVoice(channel5, mt_chan6temp, (uint8_t*)&mt_chaninputs[1], 0); 291 | mt_chaninputs[1].note = 0; 292 | } 293 | if (mt_chaninputs[2].note != 0) { 294 | mt_PlayVoice(channel6, mt_chan7temp, (uint8_t*)&mt_chaninputs[2], 0); 295 | mt_chaninputs[2].note = 0; 296 | } 297 | if (mt_chaninputs[3].note != 0) { 298 | mt_PlayVoice(channel7, mt_chan8temp, (uint8_t*)&mt_chaninputs[3], 0); 299 | mt_chaninputs[3].note = 0; 300 | } 301 | channel7.data = mt_chan8temp.n_loopstart; 302 | channel7.length = mt_chan8temp.n_replen; 303 | channel6.data = mt_chan7temp.n_loopstart; 304 | channel6.length = mt_chan7temp.n_replen; 305 | channel5.data = mt_chan6temp.n_loopstart; 306 | channel5.length = mt_chan6temp.n_replen; 307 | channel4.data = mt_chan5temp.n_loopstart; 308 | channel4.length = mt_chan5temp.n_replen; 309 | channel3.data = mt_chan4temp.n_loopstart; 310 | channel3.length = mt_chan4temp.n_replen; 311 | channel2.data = mt_chan3temp.n_loopstart; 312 | channel2.length = mt_chan3temp.n_replen; 313 | channel1.data = mt_chan2temp.n_loopstart; 314 | channel1.length = mt_chan2temp.n_replen; 315 | channel0.data = mt_chan1temp.n_loopstart; 316 | channel0.length = mt_chan1temp.n_replen; 317 | } 318 | 319 | void mt_PlayVoice(AudioChannel& channel, ChanTemp& mt_chantemp, uint8_t* patternData, int patternOffset) 320 | { 321 | int sampledata = 12; 322 | if (mt_chantemp.n_note == 0 && mt_chantemp.n_cmd.word == 0) { 323 | mt_PerNop(channel, mt_chantemp); 324 | } 325 | mt_chantemp.n_note = getWord(patternData, patternOffset); 326 | mt_chantemp.n_cmd.word = getWord(patternData, patternOffset + 2); 327 | int instrument = ((mt_chantemp.n_cmd.word & 0xf000) >> 12) | ((mt_chantemp.n_note & 0xf000) >> 8); 328 | if (instrument != 0) { 329 | int instrumentOffset = sampledata + 30 * instrument; 330 | mt_chantemp.n_start = mt_SampleStarts[instrument - 1]; 331 | mt_chantemp.n_length = getWord(mt_SongDataPtr, instrumentOffset); 332 | mt_chantemp.n_finetune = mt_SongDataPtr[instrumentOffset + 2]; 333 | mt_chantemp.n_volume = mt_SongDataPtr[instrumentOffset + 3]; 334 | 335 | // Get repeat 336 | int repeat = getWord(mt_SongDataPtr, instrumentOffset + 4); 337 | 338 | // Get start 339 | // Add repeat 340 | mt_chantemp.n_loopstart = mt_chantemp.n_start + 2 * repeat; 341 | mt_chantemp.n_wavestart = mt_chantemp.n_start + 2 * repeat; 342 | 343 | // Save replen 344 | mt_chantemp.n_replen = getWord(mt_SongDataPtr, instrumentOffset + 6); 345 | 346 | if (repeat != 0) { 347 | // Get repeat 348 | // Add replen 349 | mt_chantemp.n_length = repeat + mt_chantemp.n_replen; 350 | } 351 | 352 | // Set volume 353 | channel.volume = mt_chantemp.n_volume; 354 | } 355 | 356 | // If no note 357 | uint16_t setPeriod = (mt_chantemp.n_note & 0xfff) != 0; 358 | if (setPeriod) { 359 | if ((mt_chantemp.n_cmd.word & 0xff0) == 0xe50) { 360 | mt_SetFineTune(channel, mt_chantemp); 361 | } else if ((mt_chantemp.n_cmd.word & 0xf00) == 0x300 || (mt_chantemp.n_cmd.word & 0xf00) == 0x500) { 362 | // TonePortamento 363 | mt_SetTonePorta(channel, mt_chantemp); 364 | setPeriod = false; 365 | } else if ((mt_chantemp.n_cmd.word & 0xf00) == 0x900) { 366 | // Sample Offset 367 | mt_CheckMoreEfx(channel, mt_chantemp); 368 | } 369 | } 370 | 371 | if (setPeriod) { 372 | uint16_t note = mt_chantemp.n_note & 0xfff; 373 | 374 | int periodIndex = 0; 375 | for (; note < mt_PeriodTable[periodIndex] && periodIndex < 36; periodIndex++); 376 | mt_chantemp.n_period = mt_PeriodTable[mt_chantemp.n_finetune * 36 + periodIndex]; 377 | 378 | // Notedelay 379 | if ((mt_chantemp.n_cmd.word & 0xff0) != 0x0ed0) { 380 | channel.stop(); 381 | if ((mt_chantemp.n_wavecontrol & (1 << 2)) == 0) { 382 | mt_chantemp.n_vibratopos = 0; 383 | } 384 | if ((mt_chantemp.n_wavecontrol & (1 << 6)) == 0) { 385 | mt_chantemp.n_tremolopos = 0; 386 | } 387 | 388 | // Set start 389 | channel.data = mt_chantemp.n_start; 390 | 391 | // Set length 392 | channel.length = mt_chantemp.n_length; 393 | 394 | // Set period 395 | channel.period = mt_chantemp.n_period; 396 | channel.start(); 397 | } 398 | } 399 | mt_CheckMoreEfx(channel, mt_chantemp); 400 | } 401 | 402 | void mt_NextPosition() 403 | { 404 | mt_PatternPos = mt_PBreakPos << 4; 405 | mt_PBreakPos = 0; 406 | mt_PosJumpFlag = 0; 407 | mt_SongPos = (mt_SongPos + 1) & 0x7f; 408 | if (mt_SongPos >= mt_SongDataPtr[950]) { 409 | mt_SongPos = 0; 410 | } 411 | } 412 | 413 | void mt_NoNewPosYet() 414 | { 415 | if (mt_PosJumpFlag != 0) { 416 | mt_NextPosition(); 417 | } 418 | } 419 | 420 | void mt_CheckEfx(AudioChannel& channel, ChanTemp& mt_chantemp) 421 | { 422 | mt_UpdateFunk(channel, mt_chantemp); 423 | if ((mt_chantemp.n_cmd.word & 0xfff) == 0) { 424 | mt_PerNop(channel, mt_chantemp); 425 | return; 426 | } 427 | switch (mt_chantemp.n_cmd.word & 0xf00) { 428 | case 0x000: 429 | return mt_Arpeggio(channel, mt_chantemp); 430 | case 0x100: 431 | return mt_PortaUp(channel, mt_chantemp); 432 | case 0x200: 433 | return mt_PortaDown(channel, mt_chantemp); 434 | case 0x300: 435 | return mt_TonePortamento(channel, mt_chantemp); 436 | case 0x400: 437 | return mt_Vibrato(channel, mt_chantemp); 438 | case 0x500: 439 | return mt_TonePlusVolSlide(channel, mt_chantemp); 440 | case 0x600: 441 | return mt_VibratoPlusVolSlide(channel, mt_chantemp); 442 | case 0xe00: 443 | return mt_E_Commands(channel, mt_chantemp); 444 | default: 445 | mt_PerNop(channel, mt_chantemp); 446 | if ((mt_chantemp.n_cmd.word & 0xf00) == 0x700) { 447 | mt_Tremolo(channel, mt_chantemp); 448 | } else if ((mt_chantemp.n_cmd.word & 0xf00) == 0xa00) { 449 | mt_VolumeSlide(channel, mt_chantemp); 450 | } 451 | break; 452 | } 453 | } 454 | 455 | void mt_PerNop(AudioChannel& channel, ChanTemp& mt_chantemp) 456 | { 457 | channel.period = mt_chantemp.n_period; 458 | } 459 | 460 | void mt_Arpeggio(AudioChannel& channel, ChanTemp& mt_chantemp) 461 | { 462 | int amount = 0; 463 | 464 | switch (mt_counter % 3) { 465 | case 0: 466 | channel.period = mt_chantemp.n_period; 467 | return; 468 | case 1: 469 | amount = mt_chantemp.n_cmd.byte[0] >> 4; 470 | break; 471 | default: 472 | amount = mt_chantemp.n_cmd.byte[0] & 0x0f; 473 | break; 474 | } 475 | 476 | int periodOffset = mt_chantemp.n_finetune * 36; 477 | int periodIndex = 0; 478 | for (; mt_chantemp.n_period < mt_PeriodTable[periodOffset + periodIndex] && periodIndex < 36; periodIndex++); 479 | if (periodIndex < 36) { 480 | channel.period = mt_PeriodTable[periodOffset + periodIndex + amount]; 481 | } 482 | } 483 | 484 | void mt_FinePortaUp(AudioChannel& channel, ChanTemp& mt_chantemp) 485 | { 486 | if (mt_counter != 0) { 487 | return; 488 | } 489 | mt_LowMask = 0x0f; 490 | mt_PortaUp(channel, mt_chantemp); 491 | } 492 | 493 | void mt_PortaUp(AudioChannel& channel, ChanTemp& mt_chantemp) 494 | { 495 | int amount = mt_chantemp.n_cmd.byte[0] & mt_LowMask; 496 | mt_LowMask = 0xff; 497 | mt_chantemp.n_period -= amount; 498 | if ((mt_chantemp.n_period & 0x0fff) < 113) { 499 | mt_chantemp.n_period &= 0xf000; 500 | mt_chantemp.n_period |= 113; 501 | } 502 | channel.period = mt_chantemp.n_period & 0x0fff; 503 | } 504 | 505 | void mt_FinePortaDown(AudioChannel& channel, ChanTemp& mt_chantemp) 506 | { 507 | if (mt_counter != 0) { 508 | return; 509 | } 510 | mt_LowMask = 0x0f; 511 | mt_PortaDown(channel, mt_chantemp); 512 | } 513 | 514 | void mt_PortaDown(AudioChannel& channel, ChanTemp& mt_chantemp) 515 | { 516 | uint8_t amount = mt_chantemp.n_cmd.byte[0] & mt_LowMask; 517 | mt_LowMask = 0xff; 518 | mt_chantemp.n_period += amount; 519 | if ((mt_chantemp.n_period & 0x0fff) > 856) { 520 | mt_chantemp.n_period &= 0xf000; 521 | mt_chantemp.n_period |= 856; 522 | } 523 | channel.period = mt_chantemp.n_period & 0x0fff; 524 | } 525 | 526 | void mt_SetTonePorta(AudioChannel& channel, ChanTemp& mt_chantemp) 527 | { 528 | uint16_t note = mt_chantemp.n_note & 0xfff; 529 | 530 | // 37? 531 | int periodOffset = mt_chantemp.n_finetune * 36; 532 | int periodIndex = 0; 533 | for (; note < mt_PeriodTable[periodOffset + periodIndex] && periodIndex < 36; periodIndex++); 534 | periodIndex = std::min(periodIndex, 35); 535 | uint8_t finetune = mt_chantemp.n_finetune & 8; 536 | if (finetune != 0 && periodIndex != 0) { 537 | periodIndex--; 538 | } 539 | mt_chantemp.n_wantedperiod = mt_PeriodTable[periodOffset + periodIndex]; 540 | mt_chantemp.n_toneportdirec = 0; 541 | if (mt_chantemp.n_wantedperiod == mt_chantemp.n_period) { 542 | mt_chantemp.n_wantedperiod = 0; 543 | } else if (mt_chantemp.n_wantedperiod < mt_chantemp.n_period) { 544 | mt_chantemp.n_toneportdirec = 1; 545 | } 546 | } 547 | 548 | void mt_TonePortamento(AudioChannel& channel, ChanTemp& mt_chantemp) 549 | { 550 | if (mt_chantemp.n_cmd.byte[0] != 0) { 551 | mt_chantemp.n_toneportspeed = mt_chantemp.n_cmd.byte[0]; 552 | mt_chantemp.n_cmd.byte[0] = 0; 553 | } 554 | mt_TonePortNoChange(channel, mt_chantemp); 555 | } 556 | 557 | void mt_TonePortNoChange(AudioChannel& channel, ChanTemp& mt_chantemp) 558 | { 559 | if (mt_chantemp.n_wantedperiod == 0) { 560 | return; 561 | } 562 | if (mt_chantemp.n_toneportdirec == 0) { 563 | mt_chantemp.n_period += mt_chantemp.n_toneportspeed; 564 | if (mt_chantemp.n_wantedperiod <= mt_chantemp.n_period) { 565 | mt_chantemp.n_period = mt_chantemp.n_wantedperiod; 566 | mt_chantemp.n_wantedperiod = 0; 567 | } 568 | } else { 569 | mt_chantemp.n_period -= mt_chantemp.n_toneportspeed; 570 | if (mt_chantemp.n_wantedperiod >= mt_chantemp.n_period) { 571 | mt_chantemp.n_period = mt_chantemp.n_wantedperiod; 572 | mt_chantemp.n_wantedperiod = 0; 573 | } 574 | } 575 | int16_t period = mt_chantemp.n_period; 576 | if ((mt_chantemp.n_glissfunk & 0x0f) != 0) { 577 | int periodOffset = mt_chantemp.n_finetune * 36; 578 | int periodIndex = 0; 579 | for (; period < mt_PeriodTable[periodOffset + periodIndex] && periodIndex < 36; periodIndex++); 580 | periodIndex = std::min(periodIndex, 35); 581 | period = mt_PeriodTable[periodOffset + periodIndex]; 582 | } 583 | 584 | // Set period 585 | channel.period = period; 586 | } 587 | 588 | void mt_Vibrato(AudioChannel& channel, ChanTemp& mt_chantemp) 589 | { 590 | if (mt_chantemp.n_cmd.byte[0] != 0) { 591 | uint8_t depth = mt_chantemp.n_cmd.byte[0] & 0x0f; 592 | if (depth != 0) { 593 | mt_chantemp.n_vibratocmd &= 0xf0; 594 | mt_chantemp.n_vibratocmd |= depth; 595 | } 596 | uint8_t speed = mt_chantemp.n_cmd.byte[0] & 0xf0; 597 | if (speed != 0) { 598 | mt_chantemp.n_vibratocmd &= 0x0f; 599 | mt_chantemp.n_vibratocmd |= speed; 600 | } 601 | } 602 | mt_Vibrato2(channel, mt_chantemp); 603 | } 604 | 605 | void mt_Vibrato2(AudioChannel& channel, ChanTemp& mt_chantemp) 606 | { 607 | uint8_t pos = (mt_chantemp.n_vibratopos >> 2) & 0x1f; 608 | int value = 255; 609 | switch (mt_chantemp.n_wavecontrol & 0x03) { 610 | case 0: 611 | value = mt_VibratoTable[pos]; 612 | break; 613 | case 1: 614 | pos <<= 3; 615 | value = mt_chantemp.n_vibratopos >= 0 ? pos : 255 - pos; 616 | break; 617 | default: 618 | break; 619 | } 620 | uint8_t depth = mt_chantemp.n_vibratocmd & 0x0f; 621 | value = (value * depth) / 128; 622 | channel.period = 623 | mt_chantemp.n_period + (mt_chantemp.n_vibratopos >= 0 ? value : -value); 624 | mt_chantemp.n_vibratopos = 625 | (mt_chantemp.n_vibratopos + ((mt_chantemp.n_vibratocmd >> 2) & 0x003c)) & 626 | 0xff; 627 | } 628 | 629 | void mt_TonePlusVolSlide(AudioChannel& channel, ChanTemp& mt_chantemp) 630 | { 631 | mt_TonePortNoChange(channel, mt_chantemp); 632 | mt_VolumeSlide(channel, mt_chantemp); 633 | } 634 | 635 | void mt_VibratoPlusVolSlide(AudioChannel& channel, ChanTemp& mt_chantemp) 636 | { 637 | mt_Vibrato2(channel, mt_chantemp); 638 | mt_VolumeSlide(channel, mt_chantemp); 639 | } 640 | 641 | void mt_Tremolo(AudioChannel& channel, ChanTemp& mt_chantemp) 642 | { 643 | if (mt_chantemp.n_cmd.byte[0] != 0) { 644 | uint8_t depth = mt_chantemp.n_cmd.byte[0] & 0x0f; 645 | if (depth != 0) { 646 | mt_chantemp.n_tremolocmd &= 0xf0; 647 | mt_chantemp.n_tremolocmd |= depth; 648 | } 649 | uint8_t speed = mt_chantemp.n_cmd.byte[0] & 0xf0; 650 | if (speed != 0) { 651 | mt_chantemp.n_tremolocmd &= 0x0f; 652 | mt_chantemp.n_tremolocmd |= speed; 653 | } 654 | } 655 | uint8_t pos = (mt_chantemp.n_tremolopos >> 2) & 0x1f; 656 | int value = 255; 657 | switch ((mt_chantemp.n_wavecontrol >> 4) & 0x03) { 658 | case 0: 659 | value = mt_VibratoTable[pos]; 660 | break; 661 | case 1: 662 | pos <<= 3; 663 | value = mt_chantemp.n_vibratopos >= 0 ? pos : 255 - pos; 664 | break; 665 | default: 666 | break; 667 | } 668 | uint8_t depth = mt_chantemp.n_tremolocmd & 0x0f; 669 | value = (value * depth) / 64; 670 | channel.volume = std::min( 671 | 0x40, 672 | std::max( 673 | 0, 674 | mt_chantemp.n_volume + (mt_chantemp.n_tremolopos < 128 ? value : -value) 675 | ) 676 | ); 677 | mt_chantemp.n_tremolopos = 678 | (mt_chantemp.n_tremolopos + ((mt_chantemp.n_tremolocmd >> 2) & 0x003c)) & 679 | 0xff; 680 | } 681 | 682 | void mt_SampleOffset(AudioChannel& channel, ChanTemp& mt_chantemp) 683 | { 684 | if (mt_chantemp.n_cmd.byte[0] != 0) { 685 | mt_chantemp.n_sampleoffset = mt_chantemp.n_cmd.byte[0]; 686 | } 687 | int offset = mt_chantemp.n_sampleoffset << 7; 688 | if (offset >= mt_chantemp.n_length) { 689 | mt_chantemp.n_length = 0x0001; 690 | } else { 691 | mt_chantemp.n_length -= offset; 692 | mt_chantemp.n_start += 2 * offset; 693 | } 694 | } 695 | 696 | void mt_VolumeSlide(AudioChannel& channel, ChanTemp& mt_chantemp) 697 | { 698 | int amount = mt_chantemp.n_cmd.byte[0] >> 4; 699 | if (amount == 0) { 700 | mt_VolSlideDown(channel, mt_chantemp, mt_chantemp.n_cmd.byte[0] & 0x0f); 701 | } else { 702 | mt_VolSlideUp(channel, mt_chantemp, amount); 703 | } 704 | } 705 | 706 | void mt_VolSlideUp(AudioChannel& channel, ChanTemp& mt_chantemp, int amount) 707 | { 708 | mt_chantemp.n_volume += amount; 709 | if (mt_chantemp.n_volume > 64) { 710 | mt_chantemp.n_volume = 0x40; 711 | } 712 | channel.volume = mt_chantemp.n_volume; 713 | } 714 | 715 | void mt_VolSlideDown(AudioChannel& channel, ChanTemp& mt_chantemp, int amount) 716 | { 717 | mt_chantemp.n_volume -= amount; 718 | if (mt_chantemp.n_volume < 0) { 719 | mt_chantemp.n_volume = 0; 720 | } 721 | channel.volume = mt_chantemp.n_volume; 722 | } 723 | 724 | void mt_PositionJump(AudioChannel& channel, ChanTemp& mt_chantemp) 725 | { 726 | mt_SongPos = mt_chantemp.n_cmd.byte[0] - 1; 727 | mt_PBreakPos = 0; 728 | mt_PosJumpFlag = 0xff; 729 | } 730 | 731 | void mt_VolumeChange(AudioChannel& channel, ChanTemp& mt_chantemp) 732 | { 733 | mt_chantemp.n_volume = std::min(mt_chantemp.n_cmd.byte[0], (uint8_t)0x40); 734 | channel.volume = mt_chantemp.n_volume; 735 | } 736 | 737 | void mt_PatternBreak(AudioChannel& channel, ChanTemp& mt_chantemp) 738 | { 739 | int position = (mt_chantemp.n_cmd.byte[0] >> 4) * 10 + (mt_chantemp.n_cmd.byte[0] & 0x0f); 740 | mt_PBreakPos = position <= 63 ? position : 0; 741 | mt_PosJumpFlag = 0xff; 742 | } 743 | 744 | void mt_SetSpeed(AudioChannel& channel, ChanTemp& mt_chantemp) 745 | { 746 | if (mt_chantemp.n_cmd.byte[0] == 0) { 747 | mt_end(); 748 | } else if (mt_chantemp.n_cmd.byte[0] >= 32) { 749 | RealTempo = mt_chantemp.n_cmd.byte[0]; 750 | ciataw = (float)std::floor(TimerValue / RealTempo); 751 | } else { 752 | mt_counter = 0; 753 | mt_speed = mt_chantemp.n_cmd.byte[0]; 754 | } 755 | } 756 | 757 | void mt_CheckMoreEfx(AudioChannel& channel, ChanTemp& mt_chantemp) 758 | { 759 | mt_UpdateFunk(channel, mt_chantemp); 760 | switch (mt_chantemp.n_cmd.word & 0xf00) { 761 | case 0x900: 762 | return mt_SampleOffset(channel, mt_chantemp); 763 | case 0xb00: 764 | return mt_PositionJump(channel, mt_chantemp); 765 | case 0xd00: 766 | return mt_PatternBreak(channel, mt_chantemp); 767 | case 0xe00: 768 | return mt_E_Commands(channel, mt_chantemp); 769 | case 0xf00: 770 | return mt_SetSpeed(channel, mt_chantemp); 771 | case 0xc00: 772 | return mt_VolumeChange(channel, mt_chantemp); 773 | default: 774 | return mt_PerNop(channel, mt_chantemp); 775 | } 776 | } 777 | 778 | void mt_E_Commands(AudioChannel& channel, ChanTemp& mt_chantemp) 779 | { 780 | switch (mt_chantemp.n_cmd.byte[0] & 0xf0) { 781 | case 0x00: 782 | return mt_FilterOnOff(channel, mt_chantemp); 783 | case 0x10: 784 | return mt_FinePortaUp(channel, mt_chantemp); 785 | case 0x20: 786 | return mt_FinePortaDown(channel, mt_chantemp); 787 | case 0x30: 788 | return mt_SetGlissControl(channel, mt_chantemp); 789 | case 0x40: 790 | return mt_SetVibratoControl(channel, mt_chantemp); 791 | case 0x50: 792 | return mt_SetFineTune(channel, mt_chantemp); 793 | case 0x60: 794 | return mt_JumpLoop(channel, mt_chantemp); 795 | case 0x70: 796 | return mt_SetTremoloControl(channel, mt_chantemp); 797 | case 0x90: 798 | return mt_RetrigNote(channel, mt_chantemp); 799 | case 0xa0: 800 | return mt_VolumeFineUp(channel, mt_chantemp); 801 | case 0xb0: 802 | return mt_VolumeFineDown(channel, mt_chantemp); 803 | case 0xc0: 804 | return mt_NoteCut(channel, mt_chantemp); 805 | case 0xd0: 806 | return mt_NoteDelay(channel, mt_chantemp); 807 | case 0xe0: 808 | return mt_PatternDelay(channel, mt_chantemp); 809 | case 0xf0: 810 | return mt_FunkIt(channel, mt_chantemp); 811 | default: 812 | break; 813 | } 814 | } 815 | 816 | void mt_FilterOnOff(AudioChannel& channel, ChanTemp& mt_chantemp) 817 | { 818 | ciaapra = !!mt_chantemp.n_cmd.byte[0]; 819 | } 820 | 821 | void mt_SetGlissControl(AudioChannel& channel, ChanTemp& mt_chantemp) 822 | { 823 | mt_chantemp.n_glissfunk &= 0xf0; 824 | mt_chantemp.n_glissfunk |= mt_chantemp.n_cmd.byte[0] & 0x0f; 825 | } 826 | 827 | void mt_SetVibratoControl(AudioChannel& channel, ChanTemp& mt_chantemp) 828 | { 829 | mt_chantemp.n_wavecontrol &= 0xf0; 830 | mt_chantemp.n_wavecontrol |= mt_chantemp.n_cmd.byte[0] & 0x0f; 831 | } 832 | 833 | void mt_SetFineTune(AudioChannel& channel, ChanTemp& mt_chantemp) 834 | { 835 | mt_chantemp.n_finetune = mt_chantemp.n_cmd.byte[0] & 0x0f; 836 | } 837 | 838 | void mt_JumpLoop(AudioChannel& channel, ChanTemp& mt_chantemp) 839 | { 840 | if (mt_counter != 0) { 841 | return; 842 | } 843 | uint8_t count = mt_chantemp.n_cmd.byte[0] & 0x0f; 844 | if (count != 0) { 845 | if (mt_chantemp.n_loopcount > 0) { 846 | mt_chantemp.n_loopcount--; 847 | if (mt_chantemp.n_loopcount == 0) { 848 | return; 849 | } 850 | } else { 851 | mt_chantemp.n_loopcount = count; 852 | } 853 | mt_PBreakPos = mt_chantemp.n_pattpos; 854 | mt_PBreakFlag = 0xff; 855 | } else { 856 | mt_chantemp.n_pattpos = mt_PatternPos >> 4; 857 | } 858 | } 859 | 860 | void mt_SetTremoloControl(AudioChannel& channel, ChanTemp& mt_chantemp) 861 | { 862 | mt_chantemp.n_wavecontrol &= 0x0f; 863 | mt_chantemp.n_wavecontrol |= (mt_chantemp.n_cmd.byte[0] & 0x0f) << 4; 864 | } 865 | 866 | void mt_RetrigNote(AudioChannel& channel, ChanTemp& mt_chantemp) 867 | { 868 | uint8_t tick = mt_chantemp.n_cmd.byte[0] & 0x0f; 869 | if (tick == 0) { 870 | return; 871 | } 872 | if (mt_counter == 0) { 873 | if ((mt_chantemp.n_note & 0x0fff) != 0) { 874 | return; 875 | } 876 | } 877 | if (mt_counter % tick != 0) { 878 | return; 879 | } 880 | mt_DoRetrig(channel, mt_chantemp); 881 | } 882 | 883 | void mt_DoRetrig(AudioChannel& channel, ChanTemp& mt_chantemp) 884 | { 885 | // Channel DMA off 886 | channel.stop(); 887 | 888 | // Set sampledata pointer 889 | channel.data = mt_chantemp.n_start; 890 | 891 | // Set length 892 | channel.length = mt_chantemp.n_length; 893 | 894 | channel.start(); 895 | 896 | channel.data = mt_chantemp.n_loopstart; 897 | channel.length = mt_chantemp.n_replen; 898 | channel.period = mt_chantemp.n_period; 899 | } 900 | 901 | void mt_VolumeFineUp(AudioChannel& channel, ChanTemp& mt_chantemp) 902 | { 903 | if (mt_counter != 0) { 904 | return; 905 | } 906 | mt_VolSlideUp(channel, mt_chantemp, mt_chantemp.n_cmd.byte[0] & 0x0f); 907 | } 908 | 909 | void mt_VolumeFineDown(AudioChannel& channel, ChanTemp& mt_chantemp) 910 | { 911 | if (mt_counter != 0) { 912 | return; 913 | } 914 | mt_VolSlideDown(channel, mt_chantemp, mt_chantemp.n_cmd.byte[0] & 0x0f); 915 | } 916 | 917 | void mt_NoteCut(AudioChannel& channel, ChanTemp& mt_chantemp) 918 | { 919 | if (mt_counter != (mt_chantemp.n_cmd.byte[0] & 0x0f)) { 920 | return; 921 | } 922 | mt_chantemp.n_volume = 0; 923 | channel.volume = 0; 924 | } 925 | 926 | void mt_NoteDelay(AudioChannel& channel, ChanTemp& mt_chantemp) 927 | { 928 | if (mt_counter != (mt_chantemp.n_cmd.byte[0] & 0x0f)) { 929 | return; 930 | } 931 | if (mt_chantemp.n_note == 0) { 932 | return; 933 | } 934 | mt_DoRetrig(channel, mt_chantemp); 935 | } 936 | 937 | void mt_PatternDelay(AudioChannel& channel, ChanTemp& mt_chantemp) 938 | { 939 | if (mt_counter != 0) { 940 | return; 941 | } 942 | if (mt_PattDelTime2 == 0) { 943 | mt_PattDelTime = (mt_chantemp.n_cmd.byte[0] & 0x0f) + 1; 944 | } 945 | } 946 | 947 | void mt_FunkIt(AudioChannel& channel, ChanTemp& mt_chantemp) 948 | { 949 | if (mt_counter != 0) { 950 | return; 951 | } 952 | uint8_t amount = (mt_chantemp.n_cmd.byte[0] & 0x0f) << 4; 953 | mt_chantemp.n_glissfunk &= 0x0f; 954 | mt_chantemp.n_glissfunk |= amount; 955 | if (amount != 0) { 956 | mt_UpdateFunk(channel, mt_chantemp); 957 | } 958 | } 959 | 960 | void mt_UpdateFunk(AudioChannel& channel, ChanTemp& mt_chantemp) 961 | { 962 | int speed = mt_chantemp.n_glissfunk >> 4; 963 | if (speed == 0) { 964 | return; 965 | } 966 | uint8_t funk = mt_FunkTable[speed]; 967 | mt_chantemp.n_funkoffset += funk; 968 | if ((mt_chantemp.n_funkoffset & (1 << 7)) != 0) { 969 | return; 970 | } 971 | mt_chantemp.n_funkoffset = 0; 972 | int8_t* offset = mt_chantemp.n_loopstart + mt_chantemp.n_replen * 2; 973 | mt_chantemp.n_wavestart++; 974 | if (mt_chantemp.n_wavestart >= offset) { 975 | mt_chantemp.n_wavestart = mt_chantemp.n_loopstart; 976 | } 977 | *mt_chantemp.n_wavestart = -1 - *mt_chantemp.n_wavestart; 978 | } 979 | 980 | uint8_t mt_FunkTable[] = { 981 | 0, 982 | 5, 983 | 6, 984 | 7, 985 | 8, 986 | 10, 987 | 11, 988 | 13, 989 | 16, 990 | 19, 991 | 22, 992 | 26, 993 | 32, 994 | 43, 995 | 64, 996 | 128 997 | }; 998 | 999 | uint8_t mt_VibratoTable[] = { 1000 | 0, 1001 | 24, 1002 | 49, 1003 | 74, 1004 | 97, 1005 | 120, 1006 | 141, 1007 | 161, 1008 | 180, 1009 | 197, 1010 | 212, 1011 | 224, 1012 | 235, 1013 | 244, 1014 | 250, 1015 | 253, 1016 | 255, 1017 | 253, 1018 | 250, 1019 | 244, 1020 | 235, 1021 | 224, 1022 | 212, 1023 | 197, 1024 | 180, 1025 | 161, 1026 | 141, 1027 | 120, 1028 | 97, 1029 | 74, 1030 | 49, 1031 | 24 1032 | }; 1033 | 1034 | uint16_t mt_PeriodTable[] = { 1035 | // Tuning 0, Normal 1036 | 856, 1037 | 808, 1038 | 762, 1039 | 720, 1040 | 678, 1041 | 640, 1042 | 604, 1043 | 570, 1044 | 538, 1045 | 508, 1046 | 480, 1047 | 453, 1048 | 428, 1049 | 404, 1050 | 381, 1051 | 360, 1052 | 339, 1053 | 320, 1054 | 302, 1055 | 285, 1056 | 269, 1057 | 254, 1058 | 240, 1059 | 226, 1060 | 214, 1061 | 202, 1062 | 190, 1063 | 180, 1064 | 170, 1065 | 160, 1066 | 151, 1067 | 143, 1068 | 135, 1069 | 127, 1070 | 120, 1071 | 113, 1072 | // Tuning 1 1073 | 850, 1074 | 802, 1075 | 757, 1076 | 715, 1077 | 674, 1078 | 637, 1079 | 601, 1080 | 567, 1081 | 535, 1082 | 505, 1083 | 477, 1084 | 450, 1085 | 425, 1086 | 401, 1087 | 379, 1088 | 357, 1089 | 337, 1090 | 318, 1091 | 300, 1092 | 284, 1093 | 268, 1094 | 253, 1095 | 239, 1096 | 225, 1097 | 213, 1098 | 201, 1099 | 189, 1100 | 179, 1101 | 169, 1102 | 159, 1103 | 150, 1104 | 142, 1105 | 134, 1106 | 126, 1107 | 119, 1108 | 113, 1109 | // Tuning 2 1110 | 844, 1111 | 796, 1112 | 752, 1113 | 709, 1114 | 670, 1115 | 632, 1116 | 597, 1117 | 563, 1118 | 532, 1119 | 502, 1120 | 474, 1121 | 447, 1122 | 422, 1123 | 398, 1124 | 376, 1125 | 355, 1126 | 335, 1127 | 316, 1128 | 298, 1129 | 282, 1130 | 266, 1131 | 251, 1132 | 237, 1133 | 224, 1134 | 211, 1135 | 199, 1136 | 188, 1137 | 177, 1138 | 167, 1139 | 158, 1140 | 149, 1141 | 141, 1142 | 133, 1143 | 125, 1144 | 118, 1145 | 112, 1146 | // Tuning 3 1147 | 838, 1148 | 791, 1149 | 746, 1150 | 704, 1151 | 665, 1152 | 628, 1153 | 592, 1154 | 559, 1155 | 528, 1156 | 498, 1157 | 470, 1158 | 444, 1159 | 419, 1160 | 395, 1161 | 373, 1162 | 352, 1163 | 332, 1164 | 314, 1165 | 296, 1166 | 280, 1167 | 264, 1168 | 249, 1169 | 235, 1170 | 222, 1171 | 209, 1172 | 198, 1173 | 187, 1174 | 176, 1175 | 166, 1176 | 157, 1177 | 148, 1178 | 140, 1179 | 132, 1180 | 125, 1181 | 118, 1182 | 111, 1183 | // Tuning 4 1184 | 832, 1185 | 785, 1186 | 741, 1187 | 699, 1188 | 660, 1189 | 623, 1190 | 588, 1191 | 555, 1192 | 524, 1193 | 495, 1194 | 467, 1195 | 441, 1196 | 416, 1197 | 392, 1198 | 370, 1199 | 350, 1200 | 330, 1201 | 312, 1202 | 294, 1203 | 278, 1204 | 262, 1205 | 247, 1206 | 233, 1207 | 220, 1208 | 208, 1209 | 196, 1210 | 185, 1211 | 175, 1212 | 165, 1213 | 156, 1214 | 147, 1215 | 139, 1216 | 131, 1217 | 124, 1218 | 117, 1219 | 110, 1220 | // Tuning 5 1221 | 826, 1222 | 779, 1223 | 736, 1224 | 694, 1225 | 655, 1226 | 619, 1227 | 584, 1228 | 551, 1229 | 520, 1230 | 491, 1231 | 463, 1232 | 437, 1233 | 413, 1234 | 390, 1235 | 368, 1236 | 347, 1237 | 328, 1238 | 309, 1239 | 292, 1240 | 276, 1241 | 260, 1242 | 245, 1243 | 232, 1244 | 219, 1245 | 206, 1246 | 195, 1247 | 184, 1248 | 174, 1249 | 164, 1250 | 155, 1251 | 146, 1252 | 138, 1253 | 130, 1254 | 123, 1255 | 116, 1256 | 109, 1257 | // Tuning 6 1258 | 820, 1259 | 774, 1260 | 730, 1261 | 689, 1262 | 651, 1263 | 614, 1264 | 580, 1265 | 547, 1266 | 516, 1267 | 487, 1268 | 460, 1269 | 434, 1270 | 410, 1271 | 387, 1272 | 365, 1273 | 345, 1274 | 325, 1275 | 307, 1276 | 290, 1277 | 274, 1278 | 258, 1279 | 244, 1280 | 230, 1281 | 217, 1282 | 205, 1283 | 193, 1284 | 183, 1285 | 172, 1286 | 163, 1287 | 154, 1288 | 145, 1289 | 137, 1290 | 129, 1291 | 122, 1292 | 115, 1293 | 109, 1294 | // Tuning 7 1295 | 814, 1296 | 768, 1297 | 725, 1298 | 684, 1299 | 646, 1300 | 610, 1301 | 575, 1302 | 543, 1303 | 513, 1304 | 484, 1305 | 457, 1306 | 431, 1307 | 407, 1308 | 384, 1309 | 363, 1310 | 342, 1311 | 323, 1312 | 305, 1313 | 288, 1314 | 272, 1315 | 256, 1316 | 242, 1317 | 228, 1318 | 216, 1319 | 204, 1320 | 192, 1321 | 181, 1322 | 171, 1323 | 161, 1324 | 152, 1325 | 144, 1326 | 136, 1327 | 128, 1328 | 121, 1329 | 114, 1330 | 108, 1331 | // Tuning -8 1332 | 907, 1333 | 856, 1334 | 808, 1335 | 762, 1336 | 720, 1337 | 678, 1338 | 640, 1339 | 604, 1340 | 570, 1341 | 538, 1342 | 508, 1343 | 480, 1344 | 453, 1345 | 428, 1346 | 404, 1347 | 381, 1348 | 360, 1349 | 339, 1350 | 320, 1351 | 302, 1352 | 285, 1353 | 269, 1354 | 254, 1355 | 240, 1356 | 226, 1357 | 214, 1358 | 202, 1359 | 190, 1360 | 180, 1361 | 170, 1362 | 160, 1363 | 151, 1364 | 143, 1365 | 135, 1366 | 127, 1367 | 120, 1368 | // Tuning -7 1369 | 900, 1370 | 850, 1371 | 802, 1372 | 757, 1373 | 715, 1374 | 675, 1375 | 636, 1376 | 601, 1377 | 567, 1378 | 535, 1379 | 505, 1380 | 477, 1381 | 450, 1382 | 425, 1383 | 401, 1384 | 379, 1385 | 357, 1386 | 337, 1387 | 318, 1388 | 300, 1389 | 284, 1390 | 268, 1391 | 253, 1392 | 238, 1393 | 225, 1394 | 212, 1395 | 200, 1396 | 189, 1397 | 179, 1398 | 169, 1399 | 159, 1400 | 150, 1401 | 142, 1402 | 134, 1403 | 126, 1404 | 119, 1405 | // Tuning -6 1406 | 894, 1407 | 844, 1408 | 796, 1409 | 752, 1410 | 709, 1411 | 670, 1412 | 632, 1413 | 597, 1414 | 563, 1415 | 532, 1416 | 502, 1417 | 474, 1418 | 447, 1419 | 422, 1420 | 398, 1421 | 376, 1422 | 355, 1423 | 335, 1424 | 316, 1425 | 298, 1426 | 282, 1427 | 266, 1428 | 251, 1429 | 237, 1430 | 223, 1431 | 211, 1432 | 199, 1433 | 188, 1434 | 177, 1435 | 167, 1436 | 158, 1437 | 149, 1438 | 141, 1439 | 133, 1440 | 125, 1441 | 118, 1442 | // Tuning -5 1443 | 887, 1444 | 838, 1445 | 791, 1446 | 746, 1447 | 704, 1448 | 665, 1449 | 628, 1450 | 592, 1451 | 559, 1452 | 528, 1453 | 498, 1454 | 470, 1455 | 444, 1456 | 419, 1457 | 395, 1458 | 373, 1459 | 352, 1460 | 332, 1461 | 314, 1462 | 296, 1463 | 280, 1464 | 264, 1465 | 249, 1466 | 235, 1467 | 222, 1468 | 209, 1469 | 198, 1470 | 187, 1471 | 176, 1472 | 166, 1473 | 157, 1474 | 148, 1475 | 140, 1476 | 132, 1477 | 125, 1478 | 118, 1479 | // Tuning -4 1480 | 881, 1481 | 832, 1482 | 785, 1483 | 741, 1484 | 699, 1485 | 660, 1486 | 623, 1487 | 588, 1488 | 555, 1489 | 524, 1490 | 494, 1491 | 467, 1492 | 441, 1493 | 416, 1494 | 392, 1495 | 370, 1496 | 350, 1497 | 330, 1498 | 312, 1499 | 294, 1500 | 278, 1501 | 262, 1502 | 247, 1503 | 233, 1504 | 220, 1505 | 208, 1506 | 196, 1507 | 185, 1508 | 175, 1509 | 165, 1510 | 156, 1511 | 147, 1512 | 139, 1513 | 131, 1514 | 123, 1515 | 117, 1516 | // Tuning -3 1517 | 875, 1518 | 826, 1519 | 779, 1520 | 736, 1521 | 694, 1522 | 655, 1523 | 619, 1524 | 584, 1525 | 551, 1526 | 520, 1527 | 491, 1528 | 463, 1529 | 437, 1530 | 413, 1531 | 390, 1532 | 368, 1533 | 347, 1534 | 328, 1535 | 309, 1536 | 292, 1537 | 276, 1538 | 260, 1539 | 245, 1540 | 232, 1541 | 219, 1542 | 206, 1543 | 195, 1544 | 184, 1545 | 174, 1546 | 164, 1547 | 155, 1548 | 146, 1549 | 138, 1550 | 130, 1551 | 123, 1552 | 116, 1553 | // Tuning -2 1554 | 868, 1555 | 820, 1556 | 774, 1557 | 730, 1558 | 689, 1559 | 651, 1560 | 614, 1561 | 580, 1562 | 547, 1563 | 516, 1564 | 487, 1565 | 460, 1566 | 434, 1567 | 410, 1568 | 387, 1569 | 365, 1570 | 345, 1571 | 325, 1572 | 307, 1573 | 290, 1574 | 274, 1575 | 258, 1576 | 244, 1577 | 230, 1578 | 217, 1579 | 205, 1580 | 193, 1581 | 183, 1582 | 172, 1583 | 163, 1584 | 154, 1585 | 145, 1586 | 137, 1587 | 129, 1588 | 122, 1589 | 115, 1590 | // Tuning -1 1591 | 862, 1592 | 814, 1593 | 768, 1594 | 725, 1595 | 684, 1596 | 646, 1597 | 610, 1598 | 575, 1599 | 543, 1600 | 513, 1601 | 484, 1602 | 457, 1603 | 431, 1604 | 407, 1605 | 384, 1606 | 363, 1607 | 342, 1608 | 323, 1609 | 305, 1610 | 288, 1611 | 272, 1612 | 256, 1613 | 242, 1614 | 228, 1615 | 216, 1616 | 203, 1617 | 192, 1618 | 181, 1619 | 171, 1620 | 161, 1621 | 152, 1622 | 144, 1623 | 136, 1624 | 128, 1625 | 121, 1626 | 114 1627 | }; 1628 | 1629 | ChanTemp mt_chan1temp; 1630 | ChanTemp mt_chan2temp; 1631 | ChanTemp mt_chan3temp; 1632 | ChanTemp mt_chan4temp; 1633 | ChanTemp mt_chan5temp; 1634 | ChanTemp mt_chan6temp; 1635 | ChanTemp mt_chan7temp; 1636 | ChanTemp mt_chan8temp; 1637 | 1638 | int8_t* mt_SampleStarts[31] = {0}; 1639 | 1640 | uint8_t* mt_SongDataPtr = 0; 1641 | uint8_t mt_speed = 6; 1642 | uint8_t mt_counter = 0; 1643 | uint8_t mt_SongPos = 0; 1644 | uint8_t mt_PBreakPos = 0; 1645 | uint8_t mt_PosJumpFlag = 0; 1646 | uint8_t mt_PBreakFlag = 0; 1647 | uint8_t mt_LowMask = 0; 1648 | uint8_t mt_PattDelTime = 0; 1649 | uint8_t mt_PattDelTime2 = 0; 1650 | bool mt_Enable = false; 1651 | uint16_t mt_PatternPos = 0; 1652 | ChanInput mt_chaninputs[4]; 1653 | /* End of File */ 1654 | -------------------------------------------------------------------------------- /PT2.3A_replay_cia.h: -------------------------------------------------------------------------------- 1 | #ifndef _PT23A_REPLAY_CIA_H 2 | #define _PT23A_REPLAY_CIA_H 3 | 4 | #include "Platform.h" 5 | 6 | struct AudioChannel { 7 | public: 8 | AudioChannel(uint8_t id); 9 | void process(int16_t* buffer, uint32_t samples, uint32_t sampleRate, bool add); 10 | void start(); 11 | void stop(); 12 | 13 | uint8_t id; 14 | int8_t* data; 15 | uint16_t length; 16 | uint16_t period; 17 | uint16_t volume; 18 | int8_t* dmaStart; 19 | float dmaCurrent; 20 | float dmaEnd; 21 | bool dmacon; 22 | }; 23 | 24 | struct SampleData { 25 | char name[22]; 26 | uint16_t length; 27 | int8_t finetune; 28 | uint8_t volume; 29 | uint16_t repeatPoint; 30 | uint16_t repeatLength; 31 | }; 32 | 33 | union Cmd { 34 | uint16_t word; 35 | uint8_t byte[2]; 36 | }; 37 | 38 | struct ChanTemp { 39 | uint16_t n_note; 40 | Cmd n_cmd; 41 | int8_t* n_start; 42 | uint16_t n_length; 43 | int8_t* n_loopstart; 44 | uint16_t n_replen; 45 | int16_t n_period; 46 | uint8_t n_finetune; 47 | int8_t n_volume; 48 | uint16_t n_dmabit; 49 | uint8_t n_toneportdirec; 50 | uint8_t n_toneportspeed; 51 | uint16_t n_wantedperiod; 52 | uint8_t n_vibratocmd; 53 | int8_t n_vibratopos; 54 | uint8_t n_tremolocmd; 55 | uint8_t n_tremolopos; 56 | uint8_t n_wavecontrol; 57 | uint8_t n_glissfunk; 58 | uint8_t n_sampleoffset; 59 | uint8_t n_pattpos; 60 | uint8_t n_loopcount; 61 | uint8_t n_funkoffset; 62 | int8_t* n_wavestart; 63 | uint16_t n_padding; 64 | }; 65 | 66 | struct ChanInput { 67 | uint16_t note; 68 | uint16_t cmd; 69 | }; 70 | 71 | void putLong(uint8_t* array, uint32_t offset, uint32_t value); 72 | void putWord(uint8_t* array, uint32_t offset, uint32_t value); 73 | uint32_t getLong(uint8_t* array, uint32_t offset); 74 | uint16_t getWord(uint8_t* array, uint32_t offset); 75 | 76 | extern AudioChannel channel0; 77 | extern AudioChannel channel1; 78 | extern AudioChannel channel2; 79 | extern AudioChannel channel3; 80 | extern AudioChannel channel4; 81 | extern AudioChannel channel5; 82 | extern AudioChannel channel6; 83 | extern AudioChannel channel7; 84 | extern void processAudio(int16_t* outputBuffer, uint32_t outputLength, uint32_t sampleRate); 85 | 86 | extern void mt_init(uint8_t* songData); 87 | extern void mt_music(); 88 | extern void mt_end(); 89 | extern void mt_start(); 90 | extern void mt_music(); 91 | extern void mt_NoNewAllChannels(); 92 | extern void mt_GetNewNote(); 93 | extern void mt_PlayVoice(AudioChannel& channel, ChanTemp& mt_chantemp, uint8_t* patternData, int patternOffset); 94 | extern void mt_NextPosition(); 95 | extern void mt_NoNewPosYet(); 96 | extern void mt_CheckEfx(AudioChannel& channel, ChanTemp& mt_chantemp); 97 | extern void mt_PerNop(AudioChannel& channel, ChanTemp& mt_chantemp); 98 | extern void mt_Arpeggio(AudioChannel& channel, ChanTemp& mt_chantemp); 99 | extern void mt_FinePortaUp(AudioChannel& channel, ChanTemp& mt_chantemp); 100 | extern void mt_PortaUp(AudioChannel& channel, ChanTemp& mt_chantemp); 101 | extern void mt_FinePortaDown(AudioChannel& channel, ChanTemp& mt_chantemp); 102 | extern void mt_PortaDown(AudioChannel& channel, ChanTemp& mt_chantemp); 103 | extern void mt_SetTonePorta(AudioChannel& channel, ChanTemp& mt_chantemp); 104 | extern void mt_TonePortamento(AudioChannel& channel, ChanTemp& mt_chantemp); 105 | extern void mt_TonePortNoChange(AudioChannel& channel, ChanTemp& mt_chantemp); 106 | extern void mt_Vibrato(AudioChannel& channel, ChanTemp& mt_chantemp); 107 | extern void mt_Vibrato2(AudioChannel& channel, ChanTemp& mt_chantemp); 108 | extern void mt_TonePlusVolSlide(AudioChannel& channel, ChanTemp& mt_chantemp); 109 | extern void mt_VibratoPlusVolSlide(AudioChannel& channel, ChanTemp& mt_chantemp); 110 | extern void mt_Tremolo(AudioChannel& channel, ChanTemp& mt_chantemp); 111 | extern void mt_SampleOffset(AudioChannel& channel, ChanTemp& mt_chantemp); 112 | extern void mt_VolumeSlide(AudioChannel& channel, ChanTemp& mt_chantemp); 113 | extern void mt_VolSlideUp(AudioChannel& channel, ChanTemp& mt_chantemp, int amount); 114 | extern void mt_VolSlideDown(AudioChannel& channel, ChanTemp& mt_chantemp, int amount); 115 | extern void mt_PositionJump(AudioChannel& channel, ChanTemp& mt_chantemp); 116 | extern void mt_VolumeChange(AudioChannel& channel, ChanTemp& mt_chantemp); 117 | extern void mt_PatternBreak(AudioChannel& channel, ChanTemp& mt_chantemp); 118 | extern void mt_SetSpeed(AudioChannel& channel, ChanTemp& mt_chantemp); 119 | extern void mt_CheckMoreEfx(AudioChannel& channel, ChanTemp& mt_chantemp); 120 | extern void mt_E_Commands(AudioChannel& channel, ChanTemp& mt_chantemp); 121 | extern void mt_FilterOnOff(AudioChannel& channel, ChanTemp& mt_chantemp); 122 | extern void mt_SetGlissControl(AudioChannel& channel, ChanTemp& mt_chantemp); 123 | extern void mt_SetVibratoControl(AudioChannel& channel, ChanTemp& mt_chantemp); 124 | extern void mt_SetFineTune(AudioChannel& channel, ChanTemp& mt_chantemp); 125 | extern void mt_JumpLoop(AudioChannel& channel, ChanTemp& mt_chantemp); 126 | extern void mt_SetTremoloControl(AudioChannel& channel, ChanTemp& mt_chantemp); 127 | extern void mt_RetrigNote(AudioChannel& channel, ChanTemp& mt_chantemp); 128 | extern void mt_DoRetrig(AudioChannel& channel, ChanTemp& mt_chantemp); 129 | extern void mt_VolumeFineUp(AudioChannel& channel, ChanTemp& mt_chantemp); 130 | extern void mt_VolumeFineDown(AudioChannel& channel, ChanTemp& mt_chantemp); 131 | extern void mt_NoteCut(AudioChannel& channel, ChanTemp& mt_chantemp); 132 | extern void mt_NoteDelay(AudioChannel& channel, ChanTemp& mt_chantemp); 133 | extern void mt_PatternDelay(AudioChannel& channel, ChanTemp& mt_chantemp); 134 | extern void mt_FunkIt(AudioChannel& channel, ChanTemp& mt_chantemp); 135 | extern void mt_UpdateFunk(AudioChannel& channel, ChanTemp& mt_chantemp); 136 | 137 | extern uint8_t mt_FunkTable[]; 138 | extern uint8_t mt_VibratoTable[]; 139 | extern uint16_t mt_PeriodTable[]; 140 | 141 | extern ChanTemp mt_chan1temp; 142 | extern ChanTemp mt_chan2temp; 143 | extern ChanTemp mt_chan3temp; 144 | extern ChanTemp mt_chan4temp; 145 | extern ChanTemp mt_chan5temp; 146 | extern ChanTemp mt_chan6temp; 147 | extern ChanTemp mt_chan7temp; 148 | extern ChanTemp mt_chan8temp; 149 | extern int8_t* mt_SampleStarts[31]; 150 | extern uint8_t* mt_SongDataPtr; 151 | extern uint8_t mt_speed; 152 | extern uint8_t mt_counter; 153 | extern uint8_t mt_SongPos; 154 | extern uint8_t mt_PBreakPos; 155 | extern uint8_t mt_PosJumpFlag; 156 | extern uint8_t mt_PBreakFlag; 157 | extern uint8_t mt_LowMask; 158 | extern uint8_t mt_PattDelTime; 159 | extern uint8_t mt_PattDelTime2; 160 | extern bool mt_Enable; 161 | extern uint16_t mt_PatternPos; 162 | extern ChanInput mt_chaninputs[4]; 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /Palette.cpp: -------------------------------------------------------------------------------- 1 | #include "Palette.h" 2 | 3 | static uint8_t fadeTable[16][16]; 4 | 5 | void Palette::initialize() 6 | { 7 | for (int fade = 1; fade < 16; fade++) { 8 | for (int value = 0; value < 16; value++) { 9 | fadeTable[fade][value] = (uint8_t)((fade * value) / 15); 10 | } 11 | } 12 | } 13 | 14 | Palette::Palette(const uint16_t* palette, uint16_t colorCount, uint16_t fade, uint16_t fadeBaseColor) : 15 | sourcePalette(0), 16 | currentPalette(0), 17 | fade_(fade), 18 | fadeBaseColor(fadeBaseColor) 19 | { 20 | if (palette) { 21 | setPalette(palette, colorCount); 22 | 23 | if (fade_ != 15) { 24 | update(); 25 | } 26 | } 27 | } 28 | 29 | Palette::~Palette() 30 | { 31 | delete[] sourcePalette; 32 | delete[] currentPalette; 33 | } 34 | 35 | void Palette::setPalette(const uint16_t* palette, uint16_t colorCount) 36 | { 37 | delete[] sourcePalette; 38 | delete[] currentPalette; 39 | 40 | sourcePalette = new uint16_t[colorCount]; 41 | currentPalette = new uint16_t[colorCount]; 42 | colorCount_ = colorCount; 43 | 44 | for (int i = 0; i < colorCount; i++) { 45 | sourcePalette[i] = palette[i]; 46 | currentPalette[i] = palette[i]; 47 | } 48 | } 49 | 50 | void Palette::setFade(uint16_t fade) 51 | { 52 | fade_ = fade; 53 | update(); 54 | } 55 | 56 | uint16_t Palette::fade() const 57 | { 58 | return fade_; 59 | } 60 | 61 | void Palette::setFadeBaseColor(uint16_t fadeBaseColor) 62 | { 63 | this->fadeBaseColor = fadeBaseColor; 64 | } 65 | 66 | uint16_t* Palette::palette() const 67 | { 68 | return currentPalette; 69 | } 70 | 71 | void Palette::update() 72 | { 73 | uint16_t baseR = fadeBaseColor >> 8; 74 | uint16_t baseG = (fadeBaseColor & 0x0f0) >> 4; 75 | uint16_t baseB = fadeBaseColor & 0x00f; 76 | for (uint16_t i = 0; i < colorCount_; i++) { 77 | uint16_t color = sourcePalette[i]; 78 | uint16_t r = color >> 8; 79 | uint16_t g = (color & 0x0f0) >> 4; 80 | uint16_t b = color & 0x00f; 81 | int16_t rDelta = r - baseR; 82 | int16_t gDelta = g - baseG; 83 | int16_t bDelta = b - baseB; 84 | uint16_t fadedR = baseR + (rDelta >= 0 ? fadeTable[fade_][rDelta] : -fadeTable[fade_][-rDelta]); 85 | uint16_t fadedG = baseG + (gDelta >= 0 ? fadeTable[fade_][gDelta] : -fadeTable[fade_][-gDelta]); 86 | uint16_t fadedB = baseB + (bDelta >= 0 ? fadeTable[fade_][bDelta] : -fadeTable[fade_][-bDelta]); 87 | currentPalette[i] = (uint16_t)((fadedR << 8) | (fadedG << 4) | fadedB); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Palette.h: -------------------------------------------------------------------------------- 1 | #ifndef _PALETTE_H 2 | #define _PALETTE_H 3 | 4 | #include "Platform.h" 5 | 6 | class Palette { 7 | public: 8 | static void initialize(); 9 | 10 | Palette(const uint16_t* palette = 0, uint16_t colorCount = 0, uint16_t fade = 15, uint16_t fadeBaseColor = 0x000); 11 | ~Palette(); 12 | 13 | void setPalette(const uint16_t* palette, uint16_t colorCount); 14 | void setFade(uint16_t fade); 15 | __inline uint16_t fade() const; 16 | void setFadeBaseColor(uint16_t fadeBaseColor); 17 | __inline uint16_t* palette() const; 18 | 19 | private: 20 | void update(); 21 | 22 | uint16_t* sourcePalette; 23 | uint16_t* currentPalette; 24 | uint16_t colorCount_; 25 | uint16_t fade_; 26 | uint16_t fadeBaseColor; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /Platform.cpp: -------------------------------------------------------------------------------- 1 | #include "Platform.h" 2 | 3 | Platform::Platform() : 4 | quit(false) 5 | { 6 | } 7 | 8 | Platform::~Platform() 9 | { 10 | } 11 | 12 | void Platform::show() 13 | { 14 | } 15 | 16 | void Platform::chrout(uint8_t) 17 | { 18 | } 19 | 20 | void Platform::keyRepeat() 21 | { 22 | } 23 | 24 | bool Platform::isKeyOrJoystickPressed(bool) 25 | { 26 | return false; 27 | } 28 | 29 | uint16_t Platform::readJoystick(bool) 30 | { 31 | return 0; 32 | } 33 | 34 | void Platform::displayImage(Image) 35 | { 36 | } 37 | 38 | void Platform::updateTiles(uint8_t*, uint8_t*, uint8_t) 39 | { 40 | } 41 | 42 | void Platform::renderTiles(uint8_t, uint8_t, uint16_t, uint16_t, uint8_t, uint8_t) 43 | { 44 | } 45 | 46 | void Platform::renderItem(uint8_t, uint16_t, uint16_t) 47 | { 48 | } 49 | 50 | void Platform::renderKey(uint8_t, uint16_t, uint16_t) 51 | { 52 | } 53 | 54 | void Platform::renderHealth(uint8_t, uint16_t, uint16_t) 55 | { 56 | } 57 | 58 | void Platform::renderFace(uint8_t, uint16_t, uint16_t) 59 | { 60 | } 61 | 62 | void Platform::renderLiveMap(uint8_t*) 63 | { 64 | } 65 | 66 | void Platform::renderLiveMapTile(uint8_t*, uint8_t, uint8_t) 67 | { 68 | } 69 | 70 | void Platform::renderLiveMapUnits(uint8_t*, uint8_t*, uint8_t*, uint8_t*, uint8_t, bool) 71 | { 72 | } 73 | 74 | void Platform::showCursor(uint16_t, uint16_t) 75 | { 76 | } 77 | 78 | void Platform::hideCursor() 79 | { 80 | } 81 | 82 | void Platform::setCursorShape(CursorShape) 83 | { 84 | } 85 | 86 | void Platform::fillRect(uint16_t, uint16_t, uint16_t, uint16_t, uint8_t) 87 | { 88 | } 89 | 90 | void Platform::startShakeScreen() 91 | { 92 | } 93 | 94 | void Platform::shakeScreen() 95 | { 96 | } 97 | 98 | void Platform::stopShakeScreen() 99 | { 100 | } 101 | 102 | void Platform::startFadeScreen(uint16_t, uint16_t) 103 | { 104 | } 105 | 106 | void Platform::fadeScreen(uint16_t, bool) 107 | { 108 | } 109 | 110 | void Platform::stopFadeScreen() 111 | { 112 | } 113 | 114 | void Platform::playNote(uint8_t) 115 | { 116 | } 117 | 118 | void Platform::stopNote() 119 | { 120 | } 121 | 122 | void Platform::loadModule(Module) 123 | { 124 | } 125 | 126 | void Platform::playModule(Module) 127 | { 128 | } 129 | 130 | void Platform::pauseModule() 131 | { 132 | } 133 | 134 | void Platform::stopModule() 135 | { 136 | } 137 | 138 | void Platform::playSample(uint8_t) 139 | { 140 | } 141 | 142 | void Platform::stopSample() 143 | { 144 | } 145 | 146 | void Platform::renderFrame(bool) 147 | { 148 | } 149 | 150 | void Platform::waitForScreenMemoryAccess() 151 | { 152 | } 153 | 154 | void Platform::setHighlightedMenuRow(uint16_t) 155 | { 156 | } 157 | 158 | Platform* platform = 0; 159 | -------------------------------------------------------------------------------- /Platform.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLATFORM_H 2 | #define _PLATFORM_H 3 | 4 | #define SCREEN_WIDTH_IN_CHARACTERS (PLATFORM_SCREEN_WIDTH / 8) 5 | #define SCREEN_HEIGHT_IN_CHARACTERS (PLATFORM_SCREEN_HEIGHT / 8) 6 | 7 | #ifndef PLATFORM_MAP_COUNT 8 | #define PLATFORM_MAP_COUNT 14 9 | #endif 10 | 11 | #ifndef PLATFORM_INTRO_OPTIONS 12 | #define PLATFORM_INTRO_OPTIONS 4 13 | #endif 14 | 15 | #ifndef PLATFORM_DEFAULT_CONTROL 16 | #define PLATFORM_DEFAULT_CONTROL 0 17 | #endif 18 | 19 | #if __cplusplus < 201103L && !defined(_WIN32) 20 | typedef char int8_t; 21 | typedef short int16_t; 22 | typedef long int32_t; 23 | typedef unsigned char uint8_t; 24 | typedef unsigned short uint16_t; 25 | typedef unsigned long uint32_t; 26 | #ifdef _AMIGA 27 | typedef unsigned char bool; 28 | #endif 29 | #define true 1 30 | #define false 0 31 | #define INT32_MAX 0x7fffffff 32 | #define INT32_MIN 0x80000000 33 | #define INT16_MAX 0x7fff 34 | #define INT16_MIN 0x8000 35 | #define INT8_MAX 0x7f 36 | #define INT8_MIN 0x80 37 | #else 38 | #include 39 | #endif 40 | 41 | typedef uint32_t address_t; 42 | 43 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 44 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 45 | #define ABS(a) ((a) >= 0 ? (a) : -(a)) 46 | 47 | class Platform { 48 | public: 49 | Platform(); 50 | virtual ~Platform(); 51 | 52 | enum Map { 53 | Map01, 54 | Map02, 55 | Map03, 56 | Map04, 57 | Map05, 58 | Map06, 59 | Map07, 60 | Map08, 61 | Map09, 62 | Map10, 63 | Map11, 64 | Map12, 65 | Map13, 66 | Map14 67 | }; 68 | 69 | enum Image { 70 | ImageIntro, 71 | ImageGame, 72 | ImageGameOver 73 | }; 74 | 75 | enum Module { 76 | ModuleSoundFX, 77 | ModuleIntro, 78 | ModuleWin, 79 | ModuleLose, 80 | ModuleInGame1, 81 | ModuleInGame2, 82 | ModuleInGame3, 83 | ModuleInGame4 84 | }; 85 | 86 | enum JoystickBits { 87 | JoystickBitRight, 88 | JoystickBitLeft, 89 | JoystickBitDown, 90 | JoystickBitUp, 91 | JoystickBitRed, 92 | JoystickBitBlue, 93 | JoystickBitGreen, 94 | JoystickBitYellow, 95 | JoystickBitPlay, 96 | JoystickBitReverse, 97 | JoystickBitForward, 98 | JoystickBitExtra 99 | }; 100 | 101 | enum JoystickMask { 102 | JoystickRight = (1 << JoystickBitRight), 103 | JoystickLeft = (1 << JoystickBitLeft), 104 | JoystickDown = (1 << JoystickBitDown), 105 | JoystickUp = (1 << JoystickBitUp), 106 | JoystickRed = (1 << JoystickBitRed), 107 | JoystickBlue = (1 << JoystickBitBlue), 108 | JoystickGreen = (1 << JoystickBitGreen), 109 | JoystickYellow = (1 << JoystickBitYellow), 110 | JoystickPlay = (1 << JoystickBitPlay), 111 | JoystickReverse = (1 << JoystickBitReverse), 112 | JoystickForward = (1 << JoystickBitForward), 113 | JoystickExtra = (1 << JoystickBitExtra) 114 | }; 115 | 116 | enum CursorShape { 117 | ShapeUse, 118 | ShapeSearch, 119 | ShapeMove 120 | }; 121 | 122 | virtual uint8_t* standardControls() const = 0; 123 | virtual void setInterrupt(void (*interrupt)(void)) = 0; 124 | virtual void show(); 125 | virtual int framesPerSecond() = 0; 126 | virtual void chrout(uint8_t); 127 | virtual uint8_t readKeyboard() = 0; 128 | virtual void keyRepeat(); 129 | virtual void clearKeyBuffer() = 0; 130 | virtual bool isKeyOrJoystickPressed(bool gamepad); 131 | virtual uint16_t readJoystick(bool gamepad); 132 | virtual void loadMap(Map map, uint8_t* destination) = 0; 133 | virtual uint8_t* loadTileset() = 0; 134 | virtual void displayImage(Image image); 135 | virtual void generateTiles(uint8_t* tileData, uint8_t* tileAttributes) = 0; 136 | virtual void updateTiles(uint8_t* tileData, uint8_t* tiles, uint8_t numTiles); 137 | virtual void renderTile(uint8_t tile, uint16_t x, uint16_t y, uint8_t variant = 0, bool transparent = false) = 0; 138 | virtual void renderTiles(uint8_t backgroundTile, uint8_t foregroundTile, uint16_t x, uint16_t y, uint8_t backgroundVariant = 0, uint8_t foregroundVariant = 0); 139 | virtual void renderItem(uint8_t item, uint16_t x, uint16_t y); 140 | virtual void renderKey(uint8_t key, uint16_t x, uint16_t y); 141 | virtual void renderHealth(uint8_t health, uint16_t x, uint16_t y); 142 | virtual void renderFace(uint8_t face, uint16_t x, uint16_t y); 143 | virtual void renderLiveMap(uint8_t* map); 144 | virtual void renderLiveMapTile(uint8_t* map, uint8_t x, uint8_t y); 145 | virtual void renderLiveMapUnits(uint8_t* map, uint8_t* unitTypes, uint8_t* unitX, uint8_t* unitY, uint8_t playerColor, bool showRobots); 146 | virtual void showCursor(uint16_t x, uint16_t y); 147 | virtual void hideCursor(); 148 | virtual void setCursorShape(CursorShape shape); 149 | virtual void copyRect(uint16_t sourceX, uint16_t sourceY, uint16_t destinationX, uint16_t destinationY, uint16_t width, uint16_t height) = 0; 150 | virtual void clearRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height) = 0; 151 | virtual void fillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t color); 152 | virtual void startShakeScreen(); 153 | virtual void shakeScreen(); 154 | virtual void stopShakeScreen(); 155 | virtual void startFadeScreen(uint16_t color, uint16_t intensity); 156 | virtual void fadeScreen(uint16_t intensity, bool immediate = true); 157 | virtual void stopFadeScreen(); 158 | virtual void writeToScreenMemory(address_t address, uint8_t value) = 0; 159 | virtual void writeToScreenMemory(address_t address, uint8_t value, uint8_t color, uint8_t yOffset) = 0; 160 | virtual void playNote(uint8_t note); 161 | virtual void stopNote(); 162 | virtual void loadModule(Module module); 163 | virtual void playModule(Module module); 164 | virtual void pauseModule(); 165 | virtual void stopModule(); 166 | virtual void playSample(uint8_t sample); 167 | virtual void stopSample(); 168 | virtual void renderFrame(bool waitForNextFrame = false); 169 | virtual void waitForScreenMemoryAccess(); 170 | virtual void setHighlightedMenuRow(uint16_t row); 171 | bool quit; 172 | }; 173 | 174 | extern Platform* platform; 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /PlatformSDL.cpp: -------------------------------------------------------------------------------- 1 | #include "PT2.3A_replay_cia.h" 2 | #include "PlatformSDL.h" 3 | #include 4 | 5 | #define JOYSTICK_AXIS_THRESHOLD 25000 6 | 7 | #ifdef PLATFORM_MODULE_BASED_AUDIO 8 | #define LARGEST_MODULE_SIZE 105654 9 | #define TOTAL_SAMPLE_SIZE 75755 10 | #endif 11 | 12 | #ifdef PLATFORM_SPRITE_SUPPORT 13 | static int8_t tileSpriteMap[256] = { 14 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20 | 0, 1, 49, 50, 57, 58, 59, 60, -1, -1, -1, -1, -1, -1, -1, 48, 21 | -1, -1, -1, 73, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24 | 1, 0, 3, -1, 53, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29 | -1, -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 30 | }; 31 | #endif 32 | static int8_t animTileMap[256] = { 33 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37 | -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 41 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, 42 | -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45 | -1, -1, -1, -1, 8, 10, -1, -1, 12, 14, -1, -1, 20, -1, -1, -1, 46 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 49 | }; 50 | static char MAPNAME[] = "level-a"; 51 | #ifdef PLATFORM_IMAGE_SUPPORT 52 | static const char* imageFilenames[] = { 53 | "introscreen.png", 54 | "gamescreen.png", 55 | "gameover.png" 56 | }; 57 | #endif 58 | #ifdef PLATFORM_MODULE_BASED_AUDIO 59 | static const char* moduleFilenames[] = { 60 | "mod.soundfx", 61 | "mod.metal heads", 62 | "mod.win", 63 | "mod.lose", 64 | "mod.metallic bop amiga", 65 | "mod.get psyched", 66 | "mod.robot attack", 67 | "mod.rushin in" 68 | }; 69 | static const char* sampleFilenames[] = { 70 | "sounds_dsbarexp.raw", 71 | "SOUND_MEDKIT.raw", 72 | "SOUND_EMP.raw", 73 | "SOUND_MAGNET2.raw", 74 | "SOUND_SHOCK.raw", 75 | "SOUND_MOVE.raw", 76 | "SOUND_PLASMA_FASTER.raw", 77 | "sounds_dspistol.raw", 78 | "SOUND_FOUND_ITEM.raw", 79 | "SOUND_ERROR.raw", 80 | "SOUND_CYCLE_WEAPON.raw", 81 | "SOUND_CYCLE_ITEM.raw", 82 | "SOUND_DOOR_FASTER.raw", 83 | "SOUND_BEEP2.raw", 84 | "SOUND_BEEP.raw", 85 | "SquareWave.raw" 86 | }; 87 | #endif 88 | 89 | static uint8_t standardControls[] = { 90 | SDL_SCANCODE_I, // MOVE UP orig: 56 (8) 91 | SDL_SCANCODE_K, // MOVE DOWN orig: 50 (2) 92 | SDL_SCANCODE_J, // MOVE LEFT orig: 52 (4) 93 | SDL_SCANCODE_L, // MOVE RIGHT orig: 54 (6) 94 | SDL_SCANCODE_W, // FIRE UP 95 | SDL_SCANCODE_S, // FIRE DOWN 96 | SDL_SCANCODE_A, // FIRE LEFT 97 | SDL_SCANCODE_D, // FIRE RIGHT 98 | SDL_SCANCODE_F1, // CYCLE WEAPONS 99 | SDL_SCANCODE_F2, // CYCLE ITEMS 100 | SDL_SCANCODE_SPACE, // USE ITEM 101 | SDL_SCANCODE_Z, // SEARCH OBJECT 102 | SDL_SCANCODE_M, // MOVE OBJECT 103 | SDL_SCANCODE_TAB, // LIVE MAP 104 | SDL_SCANCODE_TAB + 0x80, // LIVE MAP ROBOTS 105 | SDL_SCANCODE_ESCAPE, // PAUSE 106 | SDL_SCANCODE_F6, // MUSIC 107 | SDL_SCANCODE_C + 0x80, // CHEAT 108 | SDL_SCANCODE_UP, // CURSOR UP 109 | SDL_SCANCODE_DOWN, // CURSOR DOWN 110 | SDL_SCANCODE_LEFT, // CURSOR LEFT 111 | SDL_SCANCODE_RIGHT, // CURSOR RIGHT 112 | SDL_SCANCODE_SPACE, // SPACE 113 | SDL_SCANCODE_RETURN, // RETURN 114 | SDL_SCANCODE_Y, // YES 115 | SDL_SCANCODE_N // NO 116 | }; 117 | 118 | #define LIVE_MAP_ORIGIN_X ((PLATFORM_SCREEN_WIDTH - 56 - 128 * 3) / 2) 119 | #define LIVE_MAP_ORIGIN_Y ((PLATFORM_SCREEN_HEIGHT - 32 - 64 * 3) / 2) 120 | 121 | uint8_t unitTypes[48]; 122 | uint8_t unitX[48]; 123 | uint8_t unitY[48]; 124 | 125 | static uint16_t joystickButtons[] = { 126 | Platform::JoystickRed, // 0 127 | Platform::JoystickBlue, // 1 128 | Platform::JoystickGreen, // 2 129 | Platform::JoystickYellow, // 3 130 | Platform::JoystickPlay, // 4 131 | 0, // 5 132 | Platform::JoystickExtra, // 6 133 | 0, // 7 134 | 0, // 8 135 | Platform::JoystickReverse, // 9 136 | Platform::JoystickForward, // 10 137 | Platform::JoystickUp, // 11 138 | Platform::JoystickDown, // 12 139 | Platform::JoystickLeft, // 13 140 | Platform::JoystickRight, // 14 141 | 0, // 15 142 | 0 // 16 143 | }; 144 | 145 | PlatformSDL::PlatformSDL() : 146 | interrupt(0), 147 | audioSpec({0}), 148 | audioDeviceID(0), 149 | joystick(0), 150 | window(0), 151 | windowSurface(0), 152 | bufferSurface(0), 153 | fadeSurface(0), 154 | fontSurface(0), 155 | #ifdef PLATFORM_IMAGE_BASED_TILES 156 | tileSurface(0), 157 | #endif 158 | #ifdef PLATFORM_IMAGE_SUPPORT 159 | imageSurfaces(), 160 | itemsSurface(0), 161 | keysSurface(0), 162 | healthSurface(0), 163 | facesSurface(0), 164 | animTilesSurface(0), 165 | palette(0), 166 | #ifdef PLATFORM_SPRITE_SUPPORT 167 | spritesSurface(0), 168 | #endif 169 | #endif 170 | #ifdef PLATFORM_CURSOR_SUPPORT 171 | cursorSurface(0), 172 | cursorRect({0}), 173 | #ifdef PLATFORM_CURSOR_SHAPE_SUPPORT 174 | cursorShape(ShapeUse), 175 | #endif 176 | #endif 177 | framesPerSecond_(60), 178 | #ifdef PLATFORM_MODULE_BASED_AUDIO 179 | moduleData(new uint8_t[LARGEST_MODULE_SIZE]), 180 | loadedModule(ModuleSoundFX), 181 | sampleData(new int8_t[TOTAL_SAMPLE_SIZE]), 182 | effectChannel(0), 183 | #else 184 | audioAngle(0), 185 | audioFrequency(440), 186 | audioVolume(INT16_MAX >> 4), 187 | #endif 188 | #ifdef PLATFORM_IMAGE_SUPPORT 189 | loadedImage(ImageIntro), 190 | #endif 191 | interruptIntervalInSamples(0), 192 | samplesSinceInterrupt(0), 193 | fadeBaseColor(0), 194 | fadeIntensity(0), 195 | joystickStateToReturn(0), 196 | joystickState(0), 197 | pendingState(0), 198 | keyToReturn(0xff), 199 | downKey(0xff), 200 | shift(0) 201 | { 202 | if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { 203 | fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError()); 204 | } 205 | if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0) { 206 | fprintf(stderr, "Error initializing SDL_image: %s\n", IMG_GetError()); 207 | } 208 | 209 | SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); 210 | 211 | SDL_AudioSpec requestedAudioSpec; 212 | SDL_zero(requestedAudioSpec); 213 | requestedAudioSpec.freq = 44100; 214 | requestedAudioSpec.format = AUDIO_S16LSB; 215 | requestedAudioSpec.channels = 1; 216 | requestedAudioSpec.samples = 512; 217 | requestedAudioSpec.callback = audioCallback; 218 | requestedAudioSpec.userdata = this; 219 | audioDeviceID = SDL_OpenAudioDevice(NULL, 0, &requestedAudioSpec, &audioSpec, SDL_AUDIO_ALLOW_ANY_CHANGE); 220 | if (!audioDeviceID) { 221 | fprintf(stderr, "Failed to open audio device: %s\n", SDL_GetError()); 222 | } 223 | 224 | interruptIntervalInSamples = audioSpec.freq / framesPerSecond_; 225 | samplesSinceInterrupt = interruptIntervalInSamples; 226 | SDL_PauseAudioDevice(audioDeviceID, 0); 227 | 228 | joystick = SDL_JoystickOpen(0); 229 | 230 | window = SDL_CreateWindow("Attack of the PETSCII Robots", 0, 0, PLATFORM_SCREEN_WIDTH, PLATFORM_SCREEN_HEIGHT, 0); 231 | windowSurface = SDL_GetWindowSurface(window); 232 | bufferSurface = SDL_CreateRGBSurface(0, PLATFORM_SCREEN_WIDTH, PLATFORM_SCREEN_HEIGHT, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 233 | fadeSurface = SDL_CreateRGBSurface(0, 1, 1, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 234 | #ifdef PLATFORM_COLOR_SUPPORT 235 | fontSurface = IMG_Load("c64font.png"); 236 | #else 237 | fontSurface = IMG_Load("petfont.png"); 238 | #endif 239 | #ifdef PLATFORM_IMAGE_BASED_TILES 240 | tileSurface = IMG_Load("tilesalpha.png"); 241 | #else 242 | for (int i = 0; i < 256; i++) { 243 | tileSurfaces[i] = SDL_CreateRGBSurface(0, 24, 24, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 244 | } 245 | #endif 246 | #ifdef PLATFORM_IMAGE_SUPPORT 247 | for (int i = 0; i < 3; i++) { 248 | imageSurfaces[i] = IMG_Load(imageFilenames[i]); 249 | } 250 | itemsSurface = IMG_Load("items.png"); 251 | keysSurface = IMG_Load("keys.png"); 252 | healthSurface = IMG_Load("health.png"); 253 | facesSurface = IMG_Load("faces.png"); 254 | animTilesSurface = IMG_Load("animtiles.png"); 255 | #ifdef PLATFORM_SPRITE_SUPPORT 256 | spritesSurface = IMG_Load("spritesalpha.png"); 257 | SDL_SetColorKey(spritesSurface, SDL_TRUE, 16); 258 | #endif 259 | #endif 260 | #ifdef PLATFORM_CURSOR_SUPPORT 261 | cursorSurface = SDL_CreateRGBSurface(0, 28, 28, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 262 | #endif 263 | SDL_SetSurfaceBlendMode(fontSurface, SDL_BLENDMODE_NONE); 264 | #ifdef PLATFORM_MODULE_BASED_AUDIO 265 | int sample = 0; 266 | int8_t* destination = sampleData; 267 | soundExplosion = destination; 268 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 269 | soundMedkit = destination; 270 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 271 | soundEMP = destination; 272 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 273 | soundMagnet = destination; 274 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 275 | soundShock = destination; 276 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 277 | soundMove = destination; 278 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 279 | soundPlasma = destination; 280 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 281 | soundPistol = destination; 282 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 283 | soundItemFound = destination; 284 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 285 | soundError = destination; 286 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 287 | soundCycleWeapon = destination; 288 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 289 | soundCycleItem = destination; 290 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 291 | soundDoor = destination; 292 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 293 | soundMenuBeep = destination; 294 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 295 | soundShortBeep = destination; 296 | destination += load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 297 | squareWave = destination; 298 | load(sampleFilenames[sample++], (uint8_t*)destination, TOTAL_SAMPLE_SIZE); 299 | 300 | // Clear the first two bytes of effect samples to enable the 2-byte no-loop loop 301 | *((uint16_t*)soundExplosion) = 0; 302 | *((uint16_t*)soundMedkit) = 0; 303 | *((uint16_t*)soundEMP) = 0; 304 | *((uint16_t*)soundMagnet) = 0; 305 | *((uint16_t*)soundShock) = 0; 306 | *((uint16_t*)soundMove) = 0; 307 | *((uint16_t*)soundPlasma) = 0; 308 | *((uint16_t*)soundPistol) = 0; 309 | *((uint16_t*)soundItemFound) = 0; 310 | *((uint16_t*)soundError) = 0; 311 | *((uint16_t*)soundCycleWeapon) = 0; 312 | *((uint16_t*)soundCycleItem) = 0; 313 | *((uint16_t*)soundDoor) = 0; 314 | *((uint16_t*)soundMenuBeep) = 0; 315 | *((uint16_t*)soundShortBeep) = 0; 316 | #endif 317 | 318 | platform = this; 319 | } 320 | 321 | PlatformSDL::~PlatformSDL() 322 | { 323 | #ifdef PLATFORM_IMAGE_SUPPORT 324 | #ifdef PLATFORM_SPRITE_SUPPORT 325 | SDL_FreeSurface(spritesSurface); 326 | #endif 327 | SDL_FreeSurface(animTilesSurface); 328 | SDL_FreeSurface(facesSurface); 329 | SDL_FreeSurface(healthSurface); 330 | SDL_FreeSurface(keysSurface); 331 | SDL_FreeSurface(itemsSurface); 332 | for (int i = 0; i < 3; i++) { 333 | SDL_FreeSurface(imageSurfaces[i]); 334 | } 335 | #endif 336 | #ifdef PLATFORM_IMAGE_BASED_TILES 337 | SDL_FreeSurface(tileSurface); 338 | #else 339 | for (int i = 0; i < 256; i++) { 340 | SDL_FreeSurface(tileSurfaces[i]); 341 | } 342 | #endif 343 | SDL_FreeSurface(fadeSurface); 344 | SDL_FreeSurface(bufferSurface); 345 | SDL_FreeSurface(fontSurface); 346 | SDL_DestroyWindow(window); 347 | SDL_JoystickClose(joystick); 348 | SDL_CloseAudioDevice(audioDeviceID); 349 | SDL_Quit(); 350 | #ifdef PLATFORM_MODULE_BASED_AUDIO 351 | delete[] sampleData; 352 | delete[] moduleData; 353 | #endif 354 | } 355 | 356 | void PlatformSDL::audioCallback(void* data, uint8_t* stream, int bytes) { 357 | PlatformSDL* platform = (PlatformSDL*)data; 358 | int words = bytes >> 1; 359 | int16_t* output = (int16_t*)stream; 360 | #ifdef PLATFORM_MODULE_BASED_AUDIO 361 | processAudio(output, words, platform->audioSpec.freq); 362 | #else 363 | for (int i = 0; i < words; i++) { 364 | output[i] = platform->audioVolume * (sin(platform->audioAngle) >= 0 ? 1 : -1); 365 | platform->audioAngle += 2 * M_PI * platform->audioFrequency / platform->audioSpec.freq; 366 | } 367 | #endif 368 | platform->samplesSinceInterrupt += words; 369 | while (platform->samplesSinceInterrupt >= platform->interruptIntervalInSamples) { 370 | if (platform->interrupt) { 371 | (*platform->interrupt)(); 372 | } 373 | platform->samplesSinceInterrupt -= platform->interruptIntervalInSamples; 374 | } 375 | } 376 | 377 | 378 | #ifdef PLATFORM_MODULE_BASED_AUDIO 379 | void PlatformSDL::undeltaSamples(uint8_t* module, uint32_t moduleSize) 380 | { 381 | uint8_t numPatterns = 0; 382 | for (int i = 0; i < module[950]; i++) { 383 | numPatterns = MAX(numPatterns, module[952 + i]); 384 | } 385 | numPatterns++; 386 | 387 | int8_t* samplesStart = (int8_t*)(module + 1084 + (numPatterns << 10)); 388 | int8_t* samplesEnd = (int8_t*)(module + moduleSize); 389 | 390 | int8_t sample = 0; 391 | for (int8_t* sampleData = samplesStart; sampleData < samplesEnd; sampleData++) { 392 | int8_t delta = *sampleData; 393 | sample += delta; 394 | *sampleData = sample; 395 | } 396 | } 397 | 398 | void PlatformSDL::setSampleData(uint8_t* module) 399 | { 400 | mt_SampleStarts[15 + 0] = soundExplosion; 401 | mt_SampleStarts[15 + 1] = soundShortBeep; 402 | mt_SampleStarts[15 + 2] = soundMedkit; 403 | mt_SampleStarts[15 + 3] = soundEMP; 404 | mt_SampleStarts[15 + 4] = soundMagnet; 405 | mt_SampleStarts[15 + 5] = soundShock; 406 | mt_SampleStarts[15 + 6] = soundMove; 407 | mt_SampleStarts[15 + 7] = soundShock; 408 | mt_SampleStarts[15 + 8] = soundPlasma; 409 | mt_SampleStarts[15 + 9] = soundPistol; 410 | mt_SampleStarts[15 + 10] = soundItemFound; 411 | mt_SampleStarts[15 + 11] = soundError; 412 | mt_SampleStarts[15 + 12] = soundCycleWeapon; 413 | mt_SampleStarts[15 + 13] = soundCycleItem; 414 | mt_SampleStarts[15 + 14] = soundDoor; 415 | mt_SampleStarts[15 + 15] = soundMenuBeep; 416 | 417 | SampleData* sampleData = (SampleData*)(module + 20); 418 | putWord((uint8_t*)&sampleData[15 + 0].length, 0, (uint16_t)(soundMedkit - soundExplosion) >> 1); 419 | putWord((uint8_t*)&sampleData[15 + 1].length, 0, (uint16_t)(squareWave - soundShortBeep) >> 1); 420 | putWord((uint8_t*)&sampleData[15 + 2].length, 0, (uint16_t)(soundEMP - soundMedkit) >> 1); 421 | putWord((uint8_t*)&sampleData[15 + 3].length, 0, (uint16_t)(soundMagnet - soundEMP) >> 1); 422 | putWord((uint8_t*)&sampleData[15 + 4].length, 0, (uint16_t)(soundShock - soundMagnet) >> 1); 423 | putWord((uint8_t*)&sampleData[15 + 5].length, 0, (uint16_t)(soundMove - soundShock) >> 1); 424 | putWord((uint8_t*)&sampleData[15 + 6].length, 0, (uint16_t)(soundPlasma - soundMove) >> 1); 425 | putWord((uint8_t*)&sampleData[15 + 7].length, 0, (uint16_t)(soundMove - soundShock) >> 1); 426 | putWord((uint8_t*)&sampleData[15 + 8].length, 0, (uint16_t)(soundPistol - soundPlasma) >> 1); 427 | putWord((uint8_t*)&sampleData[15 + 9].length, 0, (uint16_t)(soundItemFound - soundPistol) >> 1); 428 | putWord((uint8_t*)&sampleData[15 + 10].length, 0, (uint16_t)(soundError - soundItemFound) >> 1); 429 | putWord((uint8_t*)&sampleData[15 + 11].length, 0, (uint16_t)(soundCycleWeapon - soundError) >> 1); 430 | putWord((uint8_t*)&sampleData[15 + 12].length, 0, (uint16_t)(soundCycleItem - soundCycleWeapon) >> 1); 431 | putWord((uint8_t*)&sampleData[15 + 13].length, 0, (uint16_t)(soundDoor - soundCycleItem) >> 1); 432 | putWord((uint8_t*)&sampleData[15 + 14].length, 0, (uint16_t)(soundMenuBeep - soundDoor) >> 1); 433 | putWord((uint8_t*)&sampleData[15 + 15].length, 0, (uint16_t)(soundShortBeep - soundMenuBeep) >> 1); 434 | for (int i = 0; i < 16; i++) { 435 | sampleData[15 + i].volume = 64; 436 | } 437 | } 438 | #endif 439 | 440 | uint8_t* PlatformSDL::standardControls() const 441 | { 442 | return ::standardControls; 443 | } 444 | 445 | void PlatformSDL::setInterrupt(void (*interrupt)(void)) 446 | { 447 | this->interrupt = interrupt; 448 | } 449 | 450 | int PlatformSDL::framesPerSecond() 451 | { 452 | return framesPerSecond_; 453 | } 454 | 455 | void PlatformSDL::chrout(uint8_t character) 456 | { 457 | putchar(character == 0x0d ? 0x0a : character); 458 | } 459 | 460 | uint8_t PlatformSDL::readKeyboard() 461 | { 462 | SDL_Event event; 463 | while (SDL_PollEvent(&event)) { 464 | switch (event.type) { 465 | case SDL_QUIT: 466 | quit = true; 467 | break; 468 | case SDL_KEYUP: 469 | case SDL_KEYDOWN: { 470 | bool keyDown = event.type == SDL_KEYDOWN; 471 | uint8_t keyCode = event.key.keysym.scancode & 0x7f; 472 | uint8_t keyCodeWithShift = keyCode | shift; 473 | 474 | if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT || event.key.keysym.scancode == SDL_SCANCODE_RSHIFT) { 475 | if (keyDown) { 476 | shift = 0x80; 477 | downKey |= 0x80; 478 | } else { 479 | shift = 0x00; 480 | if (downKey != 0xff) { 481 | downKey &= 0x7f; 482 | } 483 | } 484 | } else if (keyDown) { 485 | if (downKey != keyCodeWithShift && !event.key.repeat) { 486 | downKey = keyCodeWithShift; 487 | keyToReturn = downKey; 488 | } 489 | } else if (downKey == keyCodeWithShift) { 490 | downKey = 0xff; 491 | } 492 | } 493 | break; 494 | case SDL_JOYBUTTONDOWN: 495 | if (event.jbutton.button < sizeof(joystickButtons) / sizeof(uint16_t)) { 496 | pendingState |= joystickButtons[event.jbutton.button]; 497 | } 498 | break; 499 | case SDL_JOYBUTTONUP: 500 | if (event.jbutton.button < sizeof(joystickButtons) / sizeof(uint16_t)) { 501 | pendingState &= ~joystickButtons[event.jbutton.button]; 502 | } 503 | break; 504 | default: 505 | break; 506 | } 507 | } 508 | 509 | uint8_t result = keyToReturn; 510 | keyToReturn = 0xff; 511 | return result; 512 | } 513 | 514 | void PlatformSDL::keyRepeat() 515 | { 516 | keyToReturn = downKey; 517 | joystickStateToReturn = joystickState; 518 | } 519 | 520 | void PlatformSDL::clearKeyBuffer() 521 | { 522 | SDL_Event event; 523 | while (SDL_PollEvent(&event)); 524 | keyToReturn = 0xff; 525 | downKey = 0xff; 526 | pendingState = 0; 527 | joystickStateToReturn = 0; 528 | } 529 | 530 | bool PlatformSDL::isKeyOrJoystickPressed(bool gamepad) 531 | { 532 | return downKey != 0xff || (joystickState != 0 && joystickState != JoystickPlay); 533 | } 534 | 535 | uint16_t PlatformSDL::readJoystick(bool gamepad) 536 | { 537 | uint16_t state = 0; 538 | int16_t leftStickX = SDL_JoystickGetAxis(joystick, 0); 539 | int16_t leftStickY = SDL_JoystickGetAxis(joystick, 1); 540 | int16_t rightStickX = SDL_JoystickGetAxis(joystick, 2); 541 | int16_t rightStickY = SDL_JoystickGetAxis(joystick, 3); 542 | if (leftStickX < -JOYSTICK_AXIS_THRESHOLD) { 543 | state |= JoystickLeft; 544 | } else if (leftStickX > JOYSTICK_AXIS_THRESHOLD) { 545 | state |= JoystickRight; 546 | } 547 | if (leftStickY < -JOYSTICK_AXIS_THRESHOLD) { 548 | state |= JoystickUp; 549 | } else if (leftStickY > JOYSTICK_AXIS_THRESHOLD) { 550 | state |= JoystickDown; 551 | } 552 | if (rightStickX < -JOYSTICK_AXIS_THRESHOLD) { 553 | state |= JoystickLeft | JoystickPlay; 554 | state &= ~(JoystickRight | JoystickUp | JoystickDown); 555 | pendingState &= ~(JoystickRight | JoystickUp | JoystickDown); 556 | } else if (rightStickX > JOYSTICK_AXIS_THRESHOLD) { 557 | state |= JoystickRight | JoystickPlay; 558 | state &= ~(JoystickLeft | JoystickUp | JoystickDown); 559 | pendingState &= ~(JoystickLeft | JoystickUp | JoystickDown); 560 | } 561 | if (rightStickY < -JOYSTICK_AXIS_THRESHOLD) { 562 | state |= JoystickUp | JoystickPlay; 563 | state &= ~(JoystickDown | JoystickLeft | JoystickRight); 564 | pendingState &= ~(JoystickDown | JoystickLeft | JoystickRight); 565 | } else if (rightStickY > JOYSTICK_AXIS_THRESHOLD) { 566 | state |= JoystickDown | JoystickPlay; 567 | state &= ~(JoystickUp | JoystickLeft | JoystickRight); 568 | pendingState &= ~(JoystickUp | JoystickLeft | JoystickRight); 569 | } 570 | state |= pendingState; 571 | 572 | if (joystickState != state) { 573 | // Don't return Play button press 574 | joystickStateToReturn = state != JoystickPlay ? state : 0; 575 | joystickState = state; 576 | } 577 | 578 | uint16_t result = joystickStateToReturn; 579 | joystickStateToReturn = 0; 580 | return result; 581 | } 582 | 583 | uint32_t PlatformSDL::load(const char* filename, uint8_t* destination, uint32_t size) 584 | { 585 | uint32_t bytesRead = 0; 586 | 587 | FILE* file = fopen(filename, "r"); 588 | if (file) { 589 | bytesRead = (uint32_t)fread(destination, 1, size, file); 590 | 591 | fclose(file); 592 | } 593 | 594 | return bytesRead; 595 | } 596 | 597 | void PlatformSDL::loadMap(Map map, uint8_t* destination) 598 | { 599 | MAPNAME[6] = 'a' + map; 600 | 601 | load(MAPNAME, destination, 8960); 602 | } 603 | 604 | uint8_t* PlatformSDL::loadTileset() 605 | { 606 | uint8_t* tileset = new uint8_t[2818]; 607 | load("tileset.amiga", tileset, 2818); 608 | return tileset; 609 | } 610 | 611 | #ifdef PLATFORM_IMAGE_SUPPORT 612 | void PlatformSDL::displayImage(Image image) 613 | { 614 | SDL_Rect clearRect = { 0, 0, PLATFORM_SCREEN_WIDTH, PLATFORM_SCREEN_HEIGHT }; 615 | SDL_FillRect(bufferSurface, &clearRect, 0xff000000); 616 | 617 | if (image == ImageGame) { 618 | SDL_Rect sourceRect = { 320 - 56, 0, 56, 128 }; 619 | SDL_Rect destinationRect = { PLATFORM_SCREEN_WIDTH - 56, 0, 56, 128 }; 620 | SDL_BlitSurface(imageSurfaces[image], &sourceRect, bufferSurface, &destinationRect); 621 | 622 | sourceRect.y = 128; 623 | for (destinationRect.y = 128; destinationRect.y < (PLATFORM_SCREEN_HEIGHT - 32); destinationRect.y += 40) { 624 | sourceRect.h = MIN(40, PLATFORM_SCREEN_HEIGHT - 32 - destinationRect.y); 625 | destinationRect.h = sourceRect.h; 626 | SDL_BlitSurface(imageSurfaces[image], &sourceRect, bufferSurface, &destinationRect); 627 | } 628 | 629 | sourceRect.y = 168; 630 | sourceRect.h = 32; 631 | destinationRect.y = PLATFORM_SCREEN_HEIGHT - 32; 632 | destinationRect.h = 32; 633 | SDL_BlitSurface(imageSurfaces[image], &sourceRect, bufferSurface, &destinationRect); 634 | 635 | sourceRect.x = 0; 636 | sourceRect.y = 168; 637 | sourceRect.w = 104; 638 | sourceRect.h = 8; 639 | destinationRect.x = 0; 640 | destinationRect.y = PLATFORM_SCREEN_HEIGHT - 32; 641 | destinationRect.w = sourceRect.w; 642 | destinationRect.h = sourceRect.h; 643 | SDL_BlitSurface(imageSurfaces[image], &sourceRect, bufferSurface, &destinationRect); 644 | 645 | sourceRect.x = 104; 646 | for (destinationRect.x = 104; destinationRect.x < (PLATFORM_SCREEN_WIDTH - 56); destinationRect.x += 160) { 647 | sourceRect.w = MIN(160, PLATFORM_SCREEN_WIDTH - 56 - destinationRect.x); 648 | destinationRect.w = sourceRect.w; 649 | SDL_BlitSurface(imageSurfaces[image], &sourceRect, bufferSurface, &destinationRect); 650 | } 651 | } else { 652 | SDL_Rect rect = { 0, 0, 320, 200 }; 653 | SDL_BlitSurface(imageSurfaces[image], &rect, bufferSurface, &rect); 654 | } 655 | 656 | if (imageSurfaces[image]->format->palette == NULL) { 657 | SDL_Color colors[256]; 658 | for (int i = 0; i < 256; i++) 659 | colors[i].r = colors[i].g = colors[i].b = (Uint8)i; 660 | 661 | imageSurfaces[image]->format->palette = new SDL_Palette{ 256, colors }; 662 | } 663 | 664 | palette = imageSurfaces[image]->format->palette; 665 | loadedImage = image; 666 | } 667 | #endif 668 | 669 | void PlatformSDL::generateTiles(uint8_t* tileData, uint8_t* tileAttributes) 670 | { 671 | #ifndef PLATFORM_IMAGE_BASED_TILES 672 | uint8_t* topLeft = tileData; 673 | uint8_t* topMiddle = topLeft + 256; 674 | uint8_t* topRight = topMiddle + 256; 675 | uint8_t* middleLeft = topRight + 256; 676 | uint8_t* middleMiddle = middleLeft + 256; 677 | uint8_t* middleRight = middleMiddle + 256; 678 | uint8_t* bottomLeft = middleRight + 256; 679 | uint8_t* bottomMiddle = bottomLeft + 256; 680 | uint8_t* bottomRight = bottomMiddle + 256; 681 | 682 | SDL_Rect sourceRect, destinationRect; 683 | sourceRect.w = 8; 684 | sourceRect.h = 8; 685 | destinationRect.w = 8; 686 | destinationRect.h = 8; 687 | 688 | for (int tile = 0; tile < 256; tile++) { 689 | uint8_t characters[3][3] = { 690 | { topLeft[tile], topMiddle[tile], topRight[tile] }, 691 | { middleLeft[tile], middleMiddle[tile], middleRight[tile] }, 692 | { bottomLeft[tile], bottomMiddle[tile], bottomRight[tile] } 693 | }; 694 | 695 | for (int y = 0; y < 3; y++) { 696 | for (int x = 0; x < 3; x++) { 697 | sourceRect.x = 0; 698 | sourceRect.y = characters[y][x] << 3; 699 | destinationRect.x = x << 3; 700 | destinationRect.y = y << 3; 701 | SDL_SetSurfaceAlphaMod(fontSurface, ((tileAttributes[tile] & 0x80) == 0 || characters[y][x] != 0x3A) ? 255 : 0); 702 | SDL_BlitSurface(fontSurface, &sourceRect, tileSurfaces[tile], &destinationRect); 703 | } 704 | } 705 | } 706 | #endif 707 | } 708 | 709 | #ifndef PLATFORM_IMAGE_BASED_TILES 710 | void PlatformSDL::updateTiles(uint8_t* tileData, uint8_t* tiles, uint8_t numTiles) 711 | { 712 | uint8_t* topLeft = tileData; 713 | uint8_t* topMiddle = topLeft + 256; 714 | uint8_t* topRight = topMiddle + 256; 715 | uint8_t* middleLeft = topRight + 256; 716 | uint8_t* middleMiddle = middleLeft + 256; 717 | uint8_t* middleRight = middleMiddle + 256; 718 | uint8_t* bottomLeft = middleRight + 256; 719 | uint8_t* bottomMiddle = bottomLeft + 256; 720 | uint8_t* bottomRight = bottomMiddle + 256; 721 | 722 | SDL_Rect sourceRect, destinationRect; 723 | sourceRect.w = 8; 724 | sourceRect.h = 8; 725 | destinationRect.w = 8; 726 | destinationRect.h = 8; 727 | for (int i = 0; i < numTiles; i++) { 728 | uint8_t tile = tiles[i]; 729 | uint8_t characters[3][3] = { 730 | { topLeft[tile], topMiddle[tile], topRight[tile] }, 731 | { middleLeft[tile], middleMiddle[tile], middleRight[tile] }, 732 | { bottomLeft[tile], bottomMiddle[tile], bottomRight[tile] } 733 | }; 734 | 735 | for (int y = 0; y < 3; y++) { 736 | for (int x = 0; x < 3; x++) { 737 | sourceRect.x = 0; 738 | sourceRect.y = characters[y][x] << 3; 739 | destinationRect.x = x << 3; 740 | destinationRect.y = y << 3; 741 | SDL_BlitSurface(fontSurface, &sourceRect, tileSurfaces[tile], &destinationRect); 742 | } 743 | } 744 | } 745 | } 746 | #endif 747 | 748 | SDL_Rect clipRect = { 0, 0, PLATFORM_SCREEN_WIDTH - 56, PLATFORM_SCREEN_HEIGHT - 32 }; 749 | 750 | void PlatformSDL::renderTile(uint8_t tile, uint16_t x, uint16_t y, uint8_t variant, bool transparent) 751 | { 752 | SDL_SetClipRect(bufferSurface, &clipRect); 753 | if (transparent) { 754 | #ifdef PLATFORM_SPRITE_SUPPORT 755 | if (tileSpriteMap[tile] >= 0) { 756 | renderSprite(tileSpriteMap[tile] + variant, x, y); 757 | return; 758 | } 759 | #endif 760 | } else { 761 | #ifdef PLATFORM_IMAGE_BASED_TILES 762 | if (animTileMap[tile] >= 0) { 763 | renderAnimTile(animTileMap[tile] + variant, x, y); 764 | return; 765 | } 766 | #endif 767 | } 768 | 769 | #ifdef PLATFORM_IMAGE_BASED_TILES 770 | SDL_Rect sourceRect, destinationRect; 771 | sourceRect.x = 0; 772 | sourceRect.y = tile * 24; 773 | sourceRect.w = 24; 774 | sourceRect.h = 24; 775 | destinationRect.x = x; 776 | destinationRect.y = y; 777 | destinationRect.w = 24; 778 | destinationRect.h = 24; 779 | SDL_BlitSurface(tileSurface, &sourceRect, bufferSurface, &destinationRect); 780 | #else 781 | SDL_Rect sourceRect, destinationRect; 782 | sourceRect.x = 0; 783 | sourceRect.y = 0; 784 | sourceRect.w = 24; 785 | sourceRect.h = 24; 786 | destinationRect.x = x; 787 | destinationRect.y = y; 788 | destinationRect.w = 24; 789 | destinationRect.h = 24; 790 | SDL_SetSurfaceBlendMode(tileSurfaces[tile], transparent ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE); 791 | SDL_BlitSurface(tileSurfaces[tile], &sourceRect, bufferSurface, &destinationRect); 792 | #endif 793 | SDL_SetClipRect(bufferSurface, 0); 794 | } 795 | 796 | void PlatformSDL::renderTiles(uint8_t backgroundTile, uint8_t foregroundTile, uint16_t x, uint16_t y, uint8_t backgroundVariant, uint8_t foregroundVariant) 797 | { 798 | SDL_SetClipRect(bufferSurface, &clipRect); 799 | SDL_Surface* backgroundSurface = tileSurface; 800 | #ifdef PLATFORM_IMAGE_BASED_TILES 801 | if (animTileMap[backgroundTile] >= 0) { 802 | backgroundTile = animTileMap[backgroundTile] + backgroundVariant; 803 | backgroundSurface = animTilesSurface; 804 | } 805 | #endif 806 | SDL_Rect sourceRect, destinationRect; 807 | sourceRect.x = 0; 808 | sourceRect.w = 24; 809 | sourceRect.h = 24; 810 | destinationRect.w = 24; 811 | destinationRect.h = 24; 812 | #ifdef PLATFORM_IMAGE_BASED_TILES 813 | if (tileSpriteMap[foregroundTile] >= 0) { 814 | uint8_t sprite = tileSpriteMap[foregroundTile] + foregroundVariant; 815 | sourceRect.y = backgroundTile * 24; 816 | destinationRect.x = x; 817 | destinationRect.y = y; 818 | SDL_BlitSurface(backgroundSurface, &sourceRect, bufferSurface, &destinationRect); 819 | 820 | sourceRect.y = sprite * 24; 821 | SDL_BlitSurface(spritesSurface, &sourceRect, bufferSurface, &destinationRect); 822 | } else { 823 | #endif 824 | sourceRect.y = backgroundTile * 24; 825 | destinationRect.x = x; 826 | destinationRect.y = y; 827 | SDL_BlitSurface(backgroundSurface, &sourceRect, bufferSurface, &destinationRect); 828 | 829 | sourceRect.y = foregroundTile * 24; 830 | SDL_BlitSurface(tileSurface, &sourceRect, bufferSurface, &destinationRect); 831 | #ifdef PLATFORM_IMAGE_BASED_TILES 832 | } 833 | #endif 834 | SDL_SetClipRect(bufferSurface, 0); 835 | } 836 | 837 | #ifdef PLATFORM_SPRITE_SUPPORT 838 | void PlatformSDL::renderSprite(uint8_t sprite, uint16_t x, uint16_t y) 839 | { 840 | SDL_SetClipRect(bufferSurface, &clipRect); 841 | SDL_Rect sourceRect, destinationRect; 842 | sourceRect.x = 0; 843 | sourceRect.y = sprite * 24; 844 | sourceRect.w = 24; 845 | sourceRect.h = 24; 846 | destinationRect.x = x; 847 | destinationRect.y = y; 848 | destinationRect.w = 24; 849 | destinationRect.h = 24; 850 | SDL_BlitSurface(spritesSurface, &sourceRect, bufferSurface, &destinationRect); 851 | SDL_SetClipRect(bufferSurface, 0); 852 | } 853 | #endif 854 | 855 | #ifdef PLATFORM_IMAGE_BASED_TILES 856 | void PlatformSDL::renderAnimTile(uint8_t animTile, uint16_t x, uint16_t y) 857 | { 858 | SDL_SetClipRect(bufferSurface, &clipRect); 859 | SDL_Rect sourceRect, destinationRect; 860 | sourceRect.x = 0; 861 | sourceRect.y = animTile * 24; 862 | sourceRect.w = 24; 863 | sourceRect.h = 24; 864 | destinationRect.x = x; 865 | destinationRect.y = y; 866 | destinationRect.w = 24; 867 | destinationRect.h = 24; 868 | SDL_BlitSurface(animTilesSurface, &sourceRect, bufferSurface, &destinationRect); 869 | SDL_SetClipRect(bufferSurface, 0); 870 | } 871 | #endif 872 | 873 | #ifdef PLATFORM_IMAGE_SUPPORT 874 | void PlatformSDL::renderItem(uint8_t item, uint16_t x, uint16_t y) 875 | { 876 | SDL_Rect sourceRect, destinationRect; 877 | sourceRect.x = 0; 878 | sourceRect.y = item * 21; 879 | sourceRect.w = 48; 880 | sourceRect.h = 21; 881 | destinationRect.x = x; 882 | destinationRect.y = y; 883 | destinationRect.w = 48; 884 | destinationRect.h = 21; 885 | SDL_BlitSurface(itemsSurface, &sourceRect, bufferSurface, &destinationRect); 886 | } 887 | 888 | void PlatformSDL::renderKey(uint8_t key, uint16_t x, uint16_t y) 889 | { 890 | SDL_Rect sourceRect, destinationRect; 891 | sourceRect.x = 0; 892 | sourceRect.y = key * 14; 893 | sourceRect.w = 16; 894 | sourceRect.h = 14; 895 | destinationRect.x = x; 896 | destinationRect.y = y; 897 | destinationRect.w = 16; 898 | destinationRect.h = 14; 899 | SDL_BlitSurface(keysSurface, &sourceRect, bufferSurface, &destinationRect); 900 | } 901 | 902 | void PlatformSDL::renderHealth(uint8_t health, uint16_t x, uint16_t y) 903 | { 904 | SDL_Rect sourceRect, destinationRect; 905 | sourceRect.x = 0; 906 | sourceRect.y = health * 51; 907 | sourceRect.w = 48; 908 | sourceRect.h = 51; 909 | destinationRect.x = x; 910 | destinationRect.y = y; 911 | destinationRect.w = 48; 912 | destinationRect.h = 51; 913 | SDL_BlitSurface(healthSurface, &sourceRect, bufferSurface, &destinationRect); 914 | } 915 | 916 | void PlatformSDL::renderFace(uint8_t face, uint16_t x, uint16_t y) 917 | { 918 | SDL_Rect sourceRect, destinationRect; 919 | sourceRect.x = 0; 920 | sourceRect.y = face * 24; 921 | sourceRect.w = 16; 922 | sourceRect.h = 24; 923 | destinationRect.x = x; 924 | destinationRect.y = y; 925 | destinationRect.w = 16; 926 | destinationRect.h = 24; 927 | SDL_BlitSurface(facesSurface, &sourceRect, bufferSurface, &destinationRect); 928 | } 929 | #endif 930 | 931 | #ifdef PLATFORM_LIVE_MAP_SUPPORT 932 | void PlatformSDL::renderLiveMap(uint8_t* map) 933 | { 934 | clearRect(0, 0, PLATFORM_SCREEN_WIDTH - 56, LIVE_MAP_ORIGIN_Y); 935 | clearRect(0, LIVE_MAP_ORIGIN_Y, LIVE_MAP_ORIGIN_X, PLATFORM_SCREEN_HEIGHT - 32 - 2 * LIVE_MAP_ORIGIN_Y); 936 | clearRect(PLATFORM_SCREEN_WIDTH - 56 - LIVE_MAP_ORIGIN_X, LIVE_MAP_ORIGIN_Y, LIVE_MAP_ORIGIN_X, PLATFORM_SCREEN_HEIGHT - 32 - 2 * LIVE_MAP_ORIGIN_Y); 937 | clearRect(0, PLATFORM_SCREEN_HEIGHT - 32 - LIVE_MAP_ORIGIN_Y, PLATFORM_SCREEN_WIDTH - 56, LIVE_MAP_ORIGIN_Y); 938 | 939 | SDL_Rect sourceRect, destinationRect; 940 | sourceRect.w = 24; 941 | sourceRect.h = 24; 942 | destinationRect.w = 3; 943 | destinationRect.h = 3; 944 | 945 | for (int mapY = 0; mapY < 64; mapY++) { 946 | for (int mapX = 0; mapX < 128; mapX++) { 947 | sourceRect.x = 0; 948 | sourceRect.y = *map++ * 24; 949 | destinationRect.x = LIVE_MAP_ORIGIN_X + mapX * 3; 950 | destinationRect.y = LIVE_MAP_ORIGIN_Y + mapY * 3; 951 | SDL_BlitScaled(tileSurface, &sourceRect, bufferSurface, &destinationRect); 952 | } 953 | } 954 | 955 | for (int i = 0; i < 48; i++) { 956 | unitTypes[i] = 255; 957 | } 958 | } 959 | 960 | void PlatformSDL::renderLiveMapTile(uint8_t* map, uint8_t mapX, uint8_t mapY) 961 | { 962 | SDL_Rect sourceRect, destinationRect; 963 | sourceRect.x = 0; 964 | sourceRect.y = map[(mapY << 7) + mapX] * 24; 965 | sourceRect.w = 24; 966 | sourceRect.h = 24; 967 | destinationRect.x = LIVE_MAP_ORIGIN_X + mapX * 3; 968 | destinationRect.y = LIVE_MAP_ORIGIN_Y + mapY * 3; 969 | destinationRect.w = 3; 970 | destinationRect.h = 3; 971 | SDL_BlitScaled(tileSurface, &sourceRect, bufferSurface, &destinationRect); 972 | } 973 | 974 | void PlatformSDL::renderLiveMapUnits(uint8_t* map, uint8_t* unitTypes, uint8_t* unitX, uint8_t* unitY, uint8_t playerColor, bool showRobots) 975 | { 976 | for (int i = 0; i < 48; i++) { 977 | if ((i < 28 || unitTypes[i] == 22) && (unitX[i] != ::unitX[i] || unitY[i] != ::unitY[i] || (i > 0 && (!showRobots || unitTypes[i] == 22 || unitTypes[i] != ::unitTypes[i])) || (i == 0 && playerColor != ::unitTypes[i]))) { 978 | // Remove old dot if any 979 | if (::unitTypes[i] != 255) { 980 | renderLiveMapTile(map, ::unitX[i], ::unitY[i]); 981 | 982 | if (i > 0 && !showRobots) { 983 | ::unitTypes[i] = 255; 984 | } 985 | } 986 | 987 | if (i == 0 || 988 | (unitTypes[i] == 22 && (unitX[i] != unitX[0] || unitY[i] != unitY[0])) || 989 | (showRobots && 990 | (unitTypes[i] == 1 || 991 | (unitTypes[i] >= 2 && unitTypes[i] <= 5) || 992 | (unitTypes[i] >= 17 && unitTypes[i] <= 18) || 993 | unitTypes[i] == 9))) { 994 | // Render new dot 995 | int x = unitX[i]; 996 | int y = unitY[i]; 997 | SDL_Rect clearRect = { LIVE_MAP_ORIGIN_X + x * 3, LIVE_MAP_ORIGIN_Y + y * 3, 3, 3 }; 998 | SDL_Color* color = &palette->colors[(i > 0 || playerColor == 1) ? 1 : 0]; 999 | SDL_FillRect(bufferSurface, &clearRect, SDL_MapRGB(bufferSurface->format, color->r, color->g, color->b)); 1000 | 1001 | ::unitTypes[i] = i == 0 ? playerColor : unitTypes[i]; 1002 | ::unitX[i] = unitX[i]; 1003 | ::unitY[i] = unitY[i]; 1004 | } 1005 | } 1006 | } 1007 | } 1008 | #endif 1009 | 1010 | #ifdef PLATFORM_CURSOR_SUPPORT 1011 | static SDL_Rect cursorSurfaceRect = { 1012 | 0, 0, 28, 28 1013 | }; 1014 | void PlatformSDL::showCursor(uint16_t x, uint16_t y) 1015 | { 1016 | if (cursorRect.h > 0) { 1017 | SDL_BlitSurface(cursorSurface, &cursorSurfaceRect, bufferSurface, &cursorRect); 1018 | } 1019 | cursorRect.x = x * 24 - 2; 1020 | cursorRect.y = y * 24 - 2; 1021 | cursorRect.w = 28; 1022 | cursorRect.h = 28; 1023 | SDL_BlitSurface(bufferSurface, &cursorRect, cursorSurface, &cursorSurfaceRect); 1024 | } 1025 | 1026 | void PlatformSDL::hideCursor() 1027 | { 1028 | if (cursorRect.h > 0) { 1029 | SDL_BlitSurface(cursorSurface, &cursorSurfaceRect, bufferSurface, &cursorRect); 1030 | cursorRect.h = 0; 1031 | } 1032 | } 1033 | 1034 | #ifdef PLATFORM_CURSOR_SHAPE_SUPPORT 1035 | void PlatformSDL::setCursorShape(CursorShape shape) 1036 | { 1037 | cursorShape = shape; 1038 | } 1039 | #endif 1040 | #endif 1041 | 1042 | void PlatformSDL::copyRect(uint16_t sourceX, uint16_t sourceY, uint16_t destinationX, uint16_t destinationY, uint16_t width, uint16_t height) 1043 | { 1044 | SDL_Rect sourceRect, destinationRect; 1045 | sourceRect.x = sourceX; 1046 | sourceRect.y = sourceY; 1047 | sourceRect.w = width; 1048 | sourceRect.h = height; 1049 | destinationRect.x = destinationX; 1050 | destinationRect.y = destinationY; 1051 | destinationRect.w = width; 1052 | destinationRect.h = height; 1053 | SDL_BlitSurface(bufferSurface, &sourceRect, bufferSurface, &destinationRect); 1054 | } 1055 | 1056 | void PlatformSDL::clearRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height) 1057 | { 1058 | SDL_Rect rect; 1059 | rect.x = x; 1060 | rect.y = y; 1061 | rect.w = width; 1062 | rect.h = height; 1063 | SDL_FillRect(bufferSurface, &rect, 0xff000000); 1064 | } 1065 | 1066 | void PlatformSDL::shakeScreen() 1067 | { 1068 | copyRect(8, 0, 0, 0, 256, 168); 1069 | } 1070 | 1071 | #ifdef PLATFORM_FADE_SUPPORT 1072 | void PlatformSDL::startFadeScreen(uint16_t color, uint16_t intensity) 1073 | { 1074 | uint32_t r = (color & 0xf00) >> 8; 1075 | uint32_t g = (color & 0x0f0) << 4; 1076 | uint32_t b = (color & 0x00f) << 16; 1077 | uint32_t bgr = r | g | b; 1078 | fadeBaseColor = bgr | (bgr << 4); 1079 | fadeIntensity = intensity; 1080 | } 1081 | 1082 | void PlatformSDL::fadeScreen(uint16_t intensity, bool immediate) 1083 | { 1084 | if (fadeIntensity != intensity) { 1085 | if (immediate) { 1086 | fadeIntensity = intensity; 1087 | } else { 1088 | int16_t fadeDelta = intensity > fadeIntensity ? 1 : -1; 1089 | do { 1090 | fadeIntensity += fadeDelta; 1091 | 1092 | clearKeyBuffer(); 1093 | 1094 | this->renderFrame(true); 1095 | } while (fadeIntensity != intensity); 1096 | } 1097 | } 1098 | } 1099 | 1100 | void PlatformSDL::stopFadeScreen() 1101 | { 1102 | fadeIntensity = 15; 1103 | } 1104 | #endif 1105 | 1106 | void PlatformSDL::writeToScreenMemory(address_t address, uint8_t value) 1107 | { 1108 | SDL_Rect sourceRect, destinationRect; 1109 | sourceRect.x = 0; 1110 | sourceRect.y = value << 3; 1111 | sourceRect.w = 8; 1112 | sourceRect.h = 8; 1113 | destinationRect.x = (address % SCREEN_WIDTH_IN_CHARACTERS) << 3; 1114 | destinationRect.y = (address / SCREEN_WIDTH_IN_CHARACTERS) << 3; 1115 | destinationRect.w = 8; 1116 | destinationRect.h = 8; 1117 | SDL_SetSurfaceColorMod(fontSurface, 0x77, 0xbb, 0x55); 1118 | SDL_BlitSurface(fontSurface, &sourceRect, bufferSurface, &destinationRect); 1119 | } 1120 | 1121 | void PlatformSDL::writeToScreenMemory(address_t address, uint8_t value, uint8_t color, uint8_t yOffset) 1122 | { 1123 | SDL_Rect sourceRect, destinationRect; 1124 | sourceRect.x = 0; 1125 | sourceRect.y = value << 3; 1126 | sourceRect.w = 8; 1127 | sourceRect.h = 8; 1128 | destinationRect.x = (address % SCREEN_WIDTH_IN_CHARACTERS) << 3; 1129 | destinationRect.y = ((address / SCREEN_WIDTH_IN_CHARACTERS) << 3) + yOffset; 1130 | destinationRect.w = 8; 1131 | destinationRect.h = 8; 1132 | SDL_SetSurfaceColorMod(fontSurface, palette->colors[color].r, palette->colors[color].g, palette->colors[color].b); 1133 | SDL_BlitSurface(fontSurface, &sourceRect, bufferSurface, &destinationRect); 1134 | } 1135 | 1136 | #ifdef PLATFORM_MODULE_BASED_AUDIO 1137 | void PlatformSDL::loadModule(Module module) 1138 | { 1139 | if (loadedModule != module) { 1140 | uint32_t moduleSize = load(moduleFilenames[module], moduleData, LARGEST_MODULE_SIZE); 1141 | undeltaSamples(moduleData, moduleSize); 1142 | setSampleData(moduleData); 1143 | loadedModule = module; 1144 | } 1145 | } 1146 | 1147 | void PlatformSDL::playModule(Module module) 1148 | { 1149 | stopModule(); 1150 | stopSample(); 1151 | 1152 | loadModule(module); 1153 | mt_init(moduleData); 1154 | 1155 | mt_Enable = true; 1156 | } 1157 | 1158 | void PlatformSDL::pauseModule() 1159 | { 1160 | mt_speed = 0; 1161 | mt_music(); 1162 | mt_Enable = false; 1163 | channel0.volume = 0; 1164 | channel1.volume = 0; 1165 | channel2.volume = 0; 1166 | channel3.volume = 0; 1167 | } 1168 | 1169 | void PlatformSDL::stopModule() 1170 | { 1171 | mt_end(); 1172 | } 1173 | 1174 | void PlatformSDL::playSample(uint8_t sample) 1175 | { 1176 | ChanInput* input = &mt_chaninputs[effectChannel < 2 ? effectChannel : (5 - effectChannel)]; 1177 | 1178 | effectChannel++; 1179 | effectChannel &= 3; 1180 | 1181 | putWord((uint8_t*)&input->note, 0, 0x1000 + 320); 1182 | if (sample < 16) { 1183 | putWord((uint8_t*)&input->cmd, 0, sample << 12); 1184 | } else if (sample == 16) { 1185 | putWord((uint8_t*)&input->cmd, 0, 1 << 12); 1186 | } else { 1187 | putWord((uint8_t*)&input->cmd, 0, 15 << 12); 1188 | } 1189 | } 1190 | 1191 | void PlatformSDL::stopSample() 1192 | { 1193 | for (int i = 0; i < 4; i++) { 1194 | mt_chaninputs[i].note = 0; 1195 | mt_chaninputs[i].cmd = 0; 1196 | } 1197 | } 1198 | #else 1199 | static const float noteToFrequency[] = { 1200 | 0, 1201 | 246.94, 1202 | 261.63, 1203 | 277.18, 1204 | 293.66, 1205 | 311.13, 1206 | 329.63, 1207 | 349.23, 1208 | 369.99, 1209 | 392.00, 1210 | 415.30, 1211 | 440.00, 1212 | 466.16, 1213 | 493.88, 1214 | 523.25, 1215 | 554.37, 1216 | 587.33, 1217 | 622.25, 1218 | 659.25, 1219 | 698.46, 1220 | 739.99, 1221 | 783.99, 1222 | 830.61, 1223 | 880.00, 1224 | 932.33, 1225 | 987.77, 1226 | 1046.50, 1227 | 1108.73, 1228 | 1174.66, 1229 | 1244.51, 1230 | 1318.51, 1231 | 1396.91, 1232 | 1479.98, 1233 | 1567.98, 1234 | 1661.22, 1235 | 1760.00, 1236 | 1864.66, 1237 | 1975.53, 1238 | 0 1239 | }; 1240 | 1241 | void PlatformSDL::playNote(uint8_t note) 1242 | { 1243 | audioFrequency = noteToFrequency[note]; 1244 | audioVolume = audioFrequency > 0 ? (INT16_MAX >> 4) : 0; 1245 | audioAngle = 0; 1246 | } 1247 | 1248 | void PlatformSDL::stopNote() 1249 | { 1250 | audioVolume = 0; 1251 | } 1252 | #endif 1253 | 1254 | void PlatformSDL::renderFrame(bool) 1255 | { 1256 | if (cursorRect.h > 0) { 1257 | SDL_Rect rects[4] = { 1258 | { cursorRect.x, cursorRect.y, cursorRect.w, 2 }, 1259 | { cursorRect.x, cursorRect.y + 2, 2, cursorRect.h - 4 }, 1260 | { cursorRect.x + cursorRect.w - 2, cursorRect.y + 2, 2, cursorRect.h - 4 }, 1261 | { cursorRect.x, cursorRect.y + cursorRect.h - 2, cursorRect.w, 2 } 1262 | }; 1263 | SDL_FillRects(bufferSurface, rects, 4, 0xffffffff); 1264 | #ifdef PLATFORM_CURSOR_SHAPE_SUPPORT 1265 | if (cursorShape != ShapeUse) { 1266 | renderSprite(cursorShape == ShapeSearch ? 83 : 84, cursorRect.x + 2, cursorRect.y + 2); 1267 | } 1268 | #endif 1269 | } 1270 | 1271 | SDL_Rect bufferRect = { 0, 0, loadedImage == ImageGame ? PLATFORM_SCREEN_WIDTH : 320, loadedImage == ImageGame ? PLATFORM_SCREEN_HEIGHT : 200 }; 1272 | SDL_Rect windowRect = { 0, 0, PLATFORM_SCREEN_WIDTH, PLATFORM_SCREEN_HEIGHT }; 1273 | SDL_BlitScaled(bufferSurface, &bufferRect, windowSurface, &windowRect); 1274 | if (fadeIntensity != 15) { 1275 | uint32_t intensity = (15 - fadeIntensity) << 24; 1276 | uint32_t abgr = intensity | (intensity << 4) | fadeBaseColor; 1277 | SDL_Rect fadeRect = { 0, 0, 1, 1 }; 1278 | SDL_FillRect(fadeSurface, &fadeRect, abgr); 1279 | SDL_BlitScaled(fadeSurface, &fadeRect, windowSurface, &windowRect); 1280 | } 1281 | SDL_UpdateWindowSurface(window); 1282 | } 1283 | -------------------------------------------------------------------------------- /PlatformSDL.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLATFORMSDL_H 2 | #define _PLATFORMSDL_H 3 | 4 | #define PlatformClass PlatformSDL 5 | 6 | #include 7 | #include 8 | #include "Platform.h" 9 | 10 | class PlatformSDL : public Platform { 11 | public: 12 | PlatformSDL(); 13 | virtual ~PlatformSDL(); 14 | 15 | virtual uint8_t* standardControls() const; 16 | virtual void setInterrupt(void (*interrupt)(void)); 17 | virtual int framesPerSecond(); 18 | virtual void chrout(uint8_t); 19 | virtual uint8_t readKeyboard(); 20 | virtual void keyRepeat(); 21 | virtual void clearKeyBuffer(); 22 | virtual bool isKeyOrJoystickPressed(bool gamepad); 23 | virtual uint16_t readJoystick(bool gamepad); 24 | virtual void loadMap(Map map, uint8_t* destination); 25 | virtual uint8_t* loadTileset(); 26 | #ifdef PLATFORM_IMAGE_SUPPORT 27 | virtual void displayImage(Image image); 28 | #endif 29 | virtual void generateTiles(uint8_t* tileData, uint8_t* tileAttributes); 30 | #ifndef PLATFORM_IMAGE_BASED_TILES 31 | virtual void updateTiles(uint8_t* tileData, uint8_t* tiles, uint8_t numTiles); 32 | #endif 33 | virtual void renderTile(uint8_t tile, uint16_t x, uint16_t y, uint8_t variant, bool transparent); 34 | virtual void renderTiles(uint8_t backgroundTile, uint8_t foregroundTile, uint16_t x, uint16_t y, uint8_t backgroundVariant, uint8_t foregroundVariant); 35 | #ifdef PLATFORM_IMAGE_SUPPORT 36 | virtual void renderItem(uint8_t item, uint16_t x, uint16_t y); 37 | virtual void renderKey(uint8_t key, uint16_t x, uint16_t y); 38 | virtual void renderHealth(uint8_t health, uint16_t x, uint16_t y); 39 | virtual void renderFace(uint8_t face, uint16_t x, uint16_t y); 40 | #endif 41 | #ifdef PLATFORM_LIVE_MAP_SUPPORT 42 | virtual void renderLiveMap(uint8_t* map); 43 | virtual void renderLiveMapTile(uint8_t* map, uint8_t x, uint8_t y); 44 | virtual void renderLiveMapUnits(uint8_t* map, uint8_t* unitTypes, uint8_t* unitX, uint8_t* unitY, uint8_t playerColor, bool showRobots); 45 | #endif 46 | #ifdef PLATFORM_CURSOR_SUPPORT 47 | virtual void showCursor(uint16_t x, uint16_t y); 48 | virtual void hideCursor(); 49 | #ifdef PLATFORM_CURSOR_SHAPE_SUPPORT 50 | virtual void setCursorShape(CursorShape shape); 51 | #endif 52 | #endif 53 | virtual void copyRect(uint16_t sourceX, uint16_t sourceY, uint16_t destinationX, uint16_t destinationY, uint16_t width, uint16_t height); 54 | virtual void clearRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height); 55 | virtual void shakeScreen(); 56 | #ifdef PLATFORM_FADE_SUPPORT 57 | virtual void startFadeScreen(uint16_t color, uint16_t intensity); 58 | virtual void fadeScreen(uint16_t intensity, bool immediate); 59 | virtual void stopFadeScreen(); 60 | #endif 61 | virtual void writeToScreenMemory(address_t address, uint8_t value); 62 | virtual void writeToScreenMemory(address_t address, uint8_t value, uint8_t color, uint8_t yOffset); 63 | #ifdef PLATFORM_MODULE_BASED_AUDIO 64 | virtual void loadModule(Module module); 65 | virtual void playModule(Module module); 66 | virtual void pauseModule(); 67 | virtual void stopModule(); 68 | virtual void playSample(uint8_t sample); 69 | virtual void stopSample(); 70 | #else 71 | virtual void playNote(uint8_t note); 72 | virtual void stopNote(); 73 | #endif 74 | virtual void renderFrame(bool waitForNextFrame); 75 | 76 | private: 77 | uint32_t load(const char* filename, uint8_t* destination, uint32_t size); 78 | #ifdef PLATFORM_MODULE_BASED_AUDIO 79 | void undeltaSamples(uint8_t* module, uint32_t moduleSize); 80 | void setSampleData(uint8_t* module); 81 | #endif 82 | #ifdef PLATFORM_SPRITE_SUPPORT 83 | void renderSprite(uint8_t sprite, uint16_t x, uint16_t y); 84 | #endif 85 | #ifdef PLATFORM_IMAGE_BASED_TILES 86 | void renderAnimTile(uint8_t animTile, uint16_t x, uint16_t y); 87 | #endif 88 | static void audioCallback(void* data, uint8_t* stream, int bytes); 89 | void (*interrupt)(void); 90 | SDL_AudioSpec audioSpec; 91 | SDL_AudioDeviceID audioDeviceID; 92 | SDL_Joystick* joystick; 93 | SDL_Window* window; 94 | SDL_Surface* windowSurface; 95 | SDL_Surface* bufferSurface; 96 | SDL_Surface* fadeSurface; 97 | SDL_Surface* fontSurface; 98 | #ifdef PLATFORM_IMAGE_BASED_TILES 99 | SDL_Surface* tileSurface; 100 | #else 101 | SDL_Surface* tileSurfaces[256]; 102 | #endif 103 | #ifdef PLATFORM_IMAGE_SUPPORT 104 | SDL_Surface* imageSurfaces[3]; 105 | SDL_Surface* itemsSurface; 106 | SDL_Surface* keysSurface; 107 | SDL_Surface* healthSurface; 108 | SDL_Surface* facesSurface; 109 | SDL_Surface* animTilesSurface; 110 | SDL_Palette* palette; 111 | #ifdef PLATFORM_SPRITE_SUPPORT 112 | SDL_Surface* spritesSurface; 113 | #endif 114 | #endif 115 | #ifdef PLATFORM_CURSOR_SUPPORT 116 | SDL_Surface* cursorSurface; 117 | SDL_Rect cursorRect; 118 | #ifdef PLATFORM_CURSOR_SHAPE_SUPPORT 119 | CursorShape cursorShape; 120 | #endif 121 | #endif 122 | int framesPerSecond_; 123 | #ifdef PLATFORM_MODULE_BASED_AUDIO 124 | uint8_t* moduleData; 125 | Module loadedModule; 126 | int8_t* sampleData; 127 | int8_t* soundExplosion; 128 | int8_t* soundMedkit; 129 | int8_t* soundEMP; 130 | int8_t* soundMagnet; 131 | int8_t* soundShock; 132 | int8_t* soundMove; 133 | int8_t* soundPlasma; 134 | int8_t* soundPistol; 135 | int8_t* soundItemFound; 136 | int8_t* soundError; 137 | int8_t* soundCycleWeapon; 138 | int8_t* soundCycleItem; 139 | int8_t* soundDoor; 140 | int8_t* soundMenuBeep; 141 | int8_t* soundShortBeep; 142 | int8_t* squareWave; 143 | uint8_t effectChannel; 144 | #else 145 | float audioAngle; 146 | float audioFrequency; 147 | int16_t audioVolume; 148 | #endif 149 | #ifdef PLATFORM_IMAGE_SUPPORT 150 | Image loadedImage; 151 | #endif 152 | uint16_t interruptIntervalInSamples; 153 | uint16_t samplesSinceInterrupt; 154 | uint32_t fadeBaseColor; 155 | uint16_t fadeIntensity; 156 | uint16_t joystickStateToReturn; 157 | uint16_t joystickState; 158 | uint16_t pendingState; 159 | uint8_t keyToReturn; 160 | uint8_t downKey; 161 | uint8_t shift; 162 | }; 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Attack of the PETSCII Robots SDL 2 | ================================ 3 | Ported by Vesa Halttunen 4 | This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 5 | 6 | About 7 | ----- 8 | - petrobots.cpp is the main game logic ported line by line from the 6502 files PETROBOTS.ASM and BACKGROUND_TASKS.ASM 9 | - Platform.h is essentially an interface with platform specific implementation classes 10 | - Various #defines starting with PLATFORM_ can be used to build a variant with different features using the same platform implementation 11 | - To port to a new platform, create a new PlatformXYZ.cpp/h implementation based on the existing ones and instantiate it in main() (petrobots.cpp) 12 | - If the target platform version will only support a certain feature set, feel free to get rid of the unnecessary PLATFORM_ #ifdefs manually or using a preprocessor 13 | - The SDL version is a generic baseline implementation that should be customized for each actual target platform 14 | 15 | MacOS Building 16 | -------- 17 | brew install sdl2 sdl2_image 18 | make setup 19 | make 20 | cd SDL 21 | ../petrobots 22 | 23 | Windows Building 24 | -------- 25 | download SDL2 VC dev zip's, unzip contents to `SDL_src/VC` directories (SDL2_image and SDL2) 26 | open `WindowsProject.sln` with Visual Studio 2022+, press Build > Build solution. 27 | 28 | Making of 29 | --------- 30 | The first task was to convert the 6502 assembler PET source code to C++ line by line. Even though this won't produce the most elegant high level language code it ensures that the code behaves exactly like the original does. PET KERNAL calls and memory accesses were abstracted to an interface which can be implemented for different platforms. 31 | 32 | To make initial testing and verification of the ported code easier an SDL platform implementation was written first. This allowed the game logic to be tested on a modern operating system. When eveything seemed to work it was time to write an implementation of the platform interface for the Amiga. Since the game shouldn't necessarily require every last drop of the Amiga's resources to run, the interface was implemented in an AmigaOS friendly way, multitasking in it's own AmigaOS screen. 33 | 34 | The first implementation was very naive: each write to the PET screen memory would result in copying the respective bytes from the font to the Amiga bitmap memory using the CPU. This would be highly inefficient on the Amiga, so the next step was to implement tile based rendering. Tiles would be copied in 24x24 pixel blocks using the Amiga's blitter, which on 68000 systems is much faster. Initially the tile bitmaps were generated during startup using the font and the tile data but pre-drawn bitmaps could be used just as well. After adding support for four bitplanes to get 16 colors it was already possible to switch to the tiles provided by the graphics artist. 35 | 36 | Double buffering was implemented to hide artefacts caused by modifying the screen while it's being drawn on display. However, the increase in memory consumption combined with the highly inefficient manner of switching between the buffers in an AmigaOS friendly manner called for a better approach. The bitmaps were made interleaved so that instead of the four bitplanes following each other in memory, the data for each bitplane row follows each other in memory. This way any changes to the screen memory while it's being drawn on display are limited to a small area. Each tile could be copied with a single blit, improving performance. To reduce the amount of memory required, a transparency mask was only generated for tiles requiring one. 37 | 38 | The one channel PET-like sound was replaced with a ProTracker module based sound implementation. Sound effect samples were injected programmatically to each module upon loading. The module player was modified to allow the sound effects to be triggered by the game as if they were notes in the song data. This way there was no need for a separate sound effect player or a need to make the music and sound effect playback routines aware of each other. The songs were modified to leave the fourth channel free for sound effects as often as possible. A separate "no music" module was then added which has no notes at all and allows sound effects to be played on all four channels. This completely transformed the game's audio. 39 | 40 | Support for pre-drawn graphics for the intro screen, game screen and game over screen was added. Then it was time to render the current weapon, item, keys and health using bitmap graphics. Animated player and robot sprites were implemented. Hardware based screen shaking was implemented and hardware sprites were used for the cursor. Palette fading made transitions between different screens a lot smoother. It also allowed the screen to smoothly flash when taking damage or using the EMP. Suddenly the game started to look like an Amiga game! 41 | 42 | In order to fit the game on one disk, assets had to be compressed. A hand written 68000 assembler implementation of deflate was used to decompress gzipped assets. In order to fit the game in memory, these assets had to be loaded on demand. On Amigas with only 512 kilobytes of chip memory there was no way to fit both music and sound effects into memory, so a decision was made to only support sound effects on such systems. On Amigas with more memory in-game music is loaded from disk on demand. Other assets, like the intro screen, intro music, game over screen and game over screen are loaded at startup and kept in memory to make the game over experience more pleasant. 43 | 44 | When the game was mostly complete otherwise, it was time to implement the live map. While simple in principle, Amiga does not make the implementation trivial due to its planar graphics. Instead of modifying a single byte to modify the color of a single pixel, one bit in four different bytes needs to be modified, making single pixel modifications very slow. Various chunky to planar implementations were looked into, but ultimately a custom 68000 assembler chunky to planar routine was written for drawing the entire map and an another custom implementation for manipulating the pixels relevant for each unit. The end result was a map performant enough to be usable also on 68000 systems. 45 | 46 | Last but not least joystick support was implemented. Most Amiga games only support a single button Atari style joystick. However, there are Amiga games that do support the 7 button Amiga CD32 gamepad either natively or via patches, so it made sense to add support for such a pad as well. In this mode all the game commands are available through the gamepad. Getting this code right required digging up some obscure information from forum discussions and such. Atari style joysticks can also have two buttons, so support for the second button was added to the joystick mode. This way most of the game commands are available using such a joystick as well. While not optimal, at least the game is now fully playable using a traditional joystick. 47 | 48 | TODO 49 | ---- 50 | - Add screen and map size getters in Program to allow actual screen size to be determined on startup 51 | -------------------------------------------------------------------------------- /SDL/.gitignore: -------------------------------------------------------------------------------- 1 | *.png 2 | mod.* 3 | tileset.* 4 | level-* 5 | *.raw 6 | -------------------------------------------------------------------------------- /SDL/animtiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/animtiles.png -------------------------------------------------------------------------------- /SDL/c64font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/c64font.png -------------------------------------------------------------------------------- /SDL/faces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/faces.png -------------------------------------------------------------------------------- /SDL/gameover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/gameover.png -------------------------------------------------------------------------------- /SDL/gamescreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/gamescreen.png -------------------------------------------------------------------------------- /SDL/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/health.png -------------------------------------------------------------------------------- /SDL/introscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/introscreen.png -------------------------------------------------------------------------------- /SDL/items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/items.png -------------------------------------------------------------------------------- /SDL/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/keys.png -------------------------------------------------------------------------------- /SDL/level-a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-a -------------------------------------------------------------------------------- /SDL/level-b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-b -------------------------------------------------------------------------------- /SDL/level-c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-c -------------------------------------------------------------------------------- /SDL/level-d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-d -------------------------------------------------------------------------------- /SDL/level-e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-e -------------------------------------------------------------------------------- /SDL/level-f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-f -------------------------------------------------------------------------------- /SDL/level-g: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-g -------------------------------------------------------------------------------- /SDL/level-h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-h -------------------------------------------------------------------------------- /SDL/level-i: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-i -------------------------------------------------------------------------------- /SDL/level-j: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-j -------------------------------------------------------------------------------- /SDL/level-k: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-k -------------------------------------------------------------------------------- /SDL/level-l: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-l -------------------------------------------------------------------------------- /SDL/level-m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-m -------------------------------------------------------------------------------- /SDL/level-n: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/level-n -------------------------------------------------------------------------------- /SDL/petfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/petfont.png -------------------------------------------------------------------------------- /SDL/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ ! -f setup.sh ] 4 | then 5 | cd SDL 6 | fi 7 | 8 | if [ ! -f tileset.amiga ] 9 | then 10 | for file in ../tileset.amiga ../Music/mod.* ../Sounds/*.raw 11 | do 12 | ln -s "$file" 13 | done 14 | fi 15 | -------------------------------------------------------------------------------- /SDL/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/sprites.png -------------------------------------------------------------------------------- /SDL/spritesalpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/spritesalpha.png -------------------------------------------------------------------------------- /SDL/spritesmask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/spritesmask.png -------------------------------------------------------------------------------- /SDL/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/tiles.png -------------------------------------------------------------------------------- /SDL/tilesalpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL/tilesalpha.png -------------------------------------------------------------------------------- /SDL_src/VC/SDL2/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL_src/VC/SDL2/.placeholder -------------------------------------------------------------------------------- /SDL_src/VC/SDL2_image/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/SDL_src/VC/SDL2_image/.placeholder -------------------------------------------------------------------------------- /Sounds/SOUND_BEEP.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_BEEP.raw -------------------------------------------------------------------------------- /Sounds/SOUND_BEEP2.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_BEEP2.raw -------------------------------------------------------------------------------- /Sounds/SOUND_CYCLE_ITEM.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_CYCLE_ITEM.raw -------------------------------------------------------------------------------- /Sounds/SOUND_CYCLE_WEAPON.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_CYCLE_WEAPON.raw -------------------------------------------------------------------------------- /Sounds/SOUND_DOOR_FASTER.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_DOOR_FASTER.raw -------------------------------------------------------------------------------- /Sounds/SOUND_EMP.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_EMP.raw -------------------------------------------------------------------------------- /Sounds/SOUND_ERROR.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_ERROR.raw -------------------------------------------------------------------------------- /Sounds/SOUND_FOUND_ITEM.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_FOUND_ITEM.raw -------------------------------------------------------------------------------- /Sounds/SOUND_MAGNET2.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_MAGNET2.raw -------------------------------------------------------------------------------- /Sounds/SOUND_MEDKIT.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_MEDKIT.raw -------------------------------------------------------------------------------- /Sounds/SOUND_MOVE.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_MOVE.raw -------------------------------------------------------------------------------- /Sounds/SOUND_PLASMA_FASTER.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_PLASMA_FASTER.raw -------------------------------------------------------------------------------- /Sounds/SOUND_SHOCK.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/SOUND_SHOCK.raw -------------------------------------------------------------------------------- /Sounds/sounds_dsbarexp.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/sounds_dsbarexp.raw -------------------------------------------------------------------------------- /Sounds/sounds_dspistol.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/Sounds/sounds_dspistol.raw -------------------------------------------------------------------------------- /Tiletool/.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user 2 | .qmake.stash 3 | Makefile 4 | Tiletool 5 | -------------------------------------------------------------------------------- /Tiletool/Tiletool.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2014-10-07T23:39:45 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core 8 | 9 | TARGET = Tiletool 10 | CONFIG += console 11 | CONFIG -= app_bundle 12 | 13 | TEMPLATE = app 14 | 15 | 16 | SOURCES += main.cpp 17 | -------------------------------------------------------------------------------- /Tiletool/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | QCoreApplication app(argc, argv); 13 | QTextStream standardError(stderr); 14 | 15 | // Parse command line options 16 | QCommandLineParser parser; 17 | parser.setApplicationDescription("Tiletool"); 18 | parser.addHelpOption(); 19 | parser.addVersionOption(); 20 | 21 | QStringList args; 22 | for (int i = 0; i < argc; i++) { 23 | args << argv[i]; 24 | } 25 | QCommandLineOption reverseOption(QStringList() << "r" << "reverse", QCoreApplication::translate("main", "Convert back to 16x16.")); 26 | parser.addOption(reverseOption); 27 | parser.addPositionalArgument("input", QCoreApplication::translate("main", "The name of the image to be converted.")); 28 | parser.addPositionalArgument("output", QCoreApplication::translate("main", "The basename of the converted image.")); 29 | parser.process(args); 30 | 31 | bool reverse = parser.isSet(reverseOption); 32 | 33 | const QStringList positionalArguments = parser.positionalArguments(); 34 | 35 | if (positionalArguments.count() != 2) { 36 | standardError << QCoreApplication::translate("main", "Invalid arguments") << "\n"; 37 | return 1; 38 | } 39 | 40 | QImage inputImage(positionalArguments.first()); 41 | if (inputImage.colorCount() == 0) { 42 | standardError << QCoreApplication::translate("main", "Not a paletted image") << "\n"; 43 | return 1; 44 | } 45 | 46 | standardError << QCoreApplication::translate("main", "Input image:\n"); 47 | standardError << QCoreApplication::translate("main", "Size ") << inputImage.width() << "x" << inputImage.height() << "\n"; 48 | standardError << QCoreApplication::translate("main", "Colors ") << inputImage.colorCount() << "\n"; 49 | 50 | if (reverse) { 51 | QImage outputImage(24 * 16, 24 * 16, inputImage.format()); 52 | outputImage.setColorCount(inputImage.colorCount()); 53 | outputImage.setColorTable(inputImage.colorTable()); 54 | for (int tile = 0; tile < 256; tile++) { 55 | int inputY = tile * 24; 56 | int outputX = (tile % 16) * 24; 57 | int outputY = (tile / 16) * 24; 58 | for (int y = 0; y < 24; y++) { 59 | for (int x = 0; x < 24; x++) { 60 | outputImage.setPixel(outputX + x, outputY + y, inputImage.pixelIndex(x, inputY + y)); 61 | } 62 | } 63 | } 64 | outputImage.save(positionalArguments.at(1)); 65 | 66 | } else { 67 | QImage outputImage(32, 24 * 256, inputImage.format()); 68 | outputImage.setColorCount(inputImage.colorCount()); 69 | outputImage.setColorTable(inputImage.colorTable()); 70 | for (int tile = 0; tile < 256; tile++) { 71 | int inputX = (tile % 16) * 24; 72 | int inputY = (tile / 16) * 24; 73 | int outputY = tile * 24; 74 | for (int y = 0; y < 24; y++) { 75 | for (int x = 0; x < 24; x++) { 76 | outputImage.setPixel(x, outputY + y, inputImage.pixelIndex(inputX + x, inputY + y)); 77 | } 78 | for (int x = 24; x < 32; x++) { 79 | outputImage.setPixel(x, outputY + y, 0); 80 | } 81 | } 82 | } 83 | outputImage.save(positionalArguments.at(1)); 84 | } 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /WindowsProject.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33530.505 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsProject", "WindowsProject\WindowsProject.vcxproj", "{D75A8E04-4A30-42D4-8671-9C2EA7A12B61}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Debug|x64.ActiveCfg = Debug|x64 17 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Debug|x64.Build.0 = Debug|x64 18 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Debug|x86.ActiveCfg = Debug|Win32 19 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Debug|x86.Build.0 = Debug|Win32 20 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Release|x64.ActiveCfg = Release|x64 21 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Release|x64.Build.0 = Release|x64 22 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Release|x86.ActiveCfg = Release|Win32 23 | {D75A8E04-4A30-42D4-8671-9C2EA7A12B61}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6B1C5146-1C1A-4756-A0F4-CDDB217AA0EE} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /WindowsProject/WindowsProject.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {d75a8e04-4a30-42d4-8671-9c2ea7a12b61} 25 | WindowsProject1 26 | 10.0 27 | PETSCIIRobots 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Level3 77 | true 78 | PLATFORM_NAME="sdl";PLATFORM_SCREEN_WIDTH=440;PLATFORM_SCREEN_HEIGHT=224;PLATFORM_MAP_WINDOW_TILES_WIDTH=16;PLATFORM_MAP_WINDOW_TILES_HEIGHT=8;PLATFORM_INTRO_OPTIONS=3;PLATFORM_DEFAULT_CONTROL=3;PLATFORM_MODULE_BASED_AUDIO;PLATFORM_TILE_BASED_RENDERING;PLATFORM_IMAGE_BASED_TILES;PLATFORM_IMAGE_SUPPORT;PLATFORM_SPRITE_SUPPORT;PLATFORM_COLOR_SUPPORT;PLATFORM_CURSOR_SUPPORT;PLATFORM_CURSOR_SHAPE_SUPPORT;PLATFORM_FADE_SUPPORT;PLATFORM_LIVE_MAP_SUPPORT;OPTIMIZED_MAP_RENDERING;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 79 | true 80 | ..\SDL_src\VC\SDL2_image\include;..\SDL_src\VC\SDL2\include;%(AdditionalIncludeDirectories) 81 | 82 | 83 | Console 84 | true 85 | SDL2.lib;SDL2main.lib;SDL2_image.lib;%(AdditionalDependencies) 86 | ..\SDL_src\VC\SDL2\lib\x64;..\SDL_src\VC\SDL2_image\lib\x64;%(AdditionalLibraryDirectories) 87 | 88 | 89 | CP ../SDL_src/VC/SDL2/lib/x64/SDL2.dll ../x64/Debug/ 90 | CP ../SDL_src/VC/SDL2_image/lib/x64/SDL2_image.dll ../x64/Debug/ 91 | 92 | 93 | 94 | 95 | Level3 96 | true 97 | true 98 | true 99 | PLATFORM_NAME="sdl";PLATFORM_SCREEN_WIDTH=440;PLATFORM_SCREEN_HEIGHT=224;PLATFORM_MAP_WINDOW_TILES_WIDTH=16;PLATFORM_MAP_WINDOW_TILES_HEIGHT=8;PLATFORM_INTRO_OPTIONS=3;PLATFORM_DEFAULT_CONTROL=3;PLATFORM_MODULE_BASED_AUDIO;PLATFORM_TILE_BASED_RENDERING;PLATFORM_IMAGE_BASED_TILES;PLATFORM_IMAGE_SUPPORT;PLATFORM_SPRITE_SUPPORT;PLATFORM_COLOR_SUPPORT;PLATFORM_CURSOR_SUPPORT;PLATFORM_CURSOR_SHAPE_SUPPORT;PLATFORM_FADE_SUPPORT;PLATFORM_LIVE_MAP_SUPPORT;OPTIMIZED_MAP_RENDERING;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 100 | true 101 | ..\SDL_src\VC\SDL2_image\include;..\SDL_src\VC\SDL2\include;%(AdditionalIncludeDirectories) 102 | 103 | 104 | Console 105 | true 106 | true 107 | true 108 | SDL2.lib;SDL2main.lib;SDL2_image.lib;%(AdditionalDependencies) 109 | ..\SDL_src\VC\SDL2\lib\x64;..\SDL_src\VC\SDL2_image\lib\x64;%(AdditionalLibraryDirectories) 110 | 111 | 112 | CP ../SDL_src/VC/SDL2/lib/x64/SDL2.dll ../x64/Debug/ 113 | CP ../SDL_src/VC/SDL2_image/lib/x64/SDL2_image.dll ../x64/Debug/ 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | PLATFORM_NAME="sdl";PLATFORM_SCREEN_WIDTH=440;PLATFORM_SCREEN_HEIGHT=224;PLATFORM_MAP_WINDOW_TILES_WIDTH=16;PLATFORM_MAP_WINDOW_TILES_HEIGHT=8;PLATFORM_INTRO_OPTIONS=3;PLATFORM_DEFAULT_CONTROL=3;PLATFORM_MODULE_BASED_AUDIO;PLATFORM_TILE_BASED_RENDERING;PLATFORM_IMAGE_BASED_TILES;PLATFORM_IMAGE_SUPPORT;PLATFORM_SPRITE_SUPPORT;PLATFORM_COLOR_SUPPORT;PLATFORM_CURSOR_SUPPORT;PLATFORM_CURSOR_SHAPE_SUPPORT;PLATFORM_FADE_SUPPORT;PLATFORM_LIVE_MAP_SUPPORT;OPTIMIZED_MAP_RENDERING;_CRT_SECURE_NO_WARNINGS;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 121 | true 122 | ..\SDL_src\VC\SDL2_image\include;..\SDL_src\VC\SDL2\include;%(AdditionalIncludeDirectories) 123 | 124 | 125 | Console 126 | true 127 | SDL2.lib;SDL2main.lib;SDL2_image.lib;%(AdditionalDependencies) 128 | ..\SDL_src\VC\SDL2\lib\x64;..\SDL_src\VC\SDL2_image\lib\x64;%(AdditionalLibraryDirectories) 129 | 130 | 131 | CP ../SDL_src/VC/SDL2/lib/x64/SDL2.dll ../x64/Debug/ 132 | CP ../SDL_src/VC/SDL2_image/lib/x64/SDL2_image.dll ../x64/Debug/ 133 | 134 | 135 | 136 | 137 | Level3 138 | true 139 | true 140 | true 141 | PLATFORM_NAME="sdl";PLATFORM_SCREEN_WIDTH=440;PLATFORM_SCREEN_HEIGHT=224;PLATFORM_MAP_WINDOW_TILES_WIDTH=16;PLATFORM_MAP_WINDOW_TILES_HEIGHT=8;PLATFORM_INTRO_OPTIONS=3;PLATFORM_DEFAULT_CONTROL=3;PLATFORM_MODULE_BASED_AUDIO;PLATFORM_TILE_BASED_RENDERING;PLATFORM_IMAGE_BASED_TILES;PLATFORM_IMAGE_SUPPORT;PLATFORM_SPRITE_SUPPORT;PLATFORM_COLOR_SUPPORT;PLATFORM_CURSOR_SUPPORT;PLATFORM_CURSOR_SHAPE_SUPPORT;PLATFORM_FADE_SUPPORT;PLATFORM_LIVE_MAP_SUPPORT;OPTIMIZED_MAP_RENDERING;_CRT_SECURE_NO_WARNINGS;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 142 | true 143 | ..\SDL_src\VC\SDL2_image\include;..\SDL_src\VC\SDL2\include;%(AdditionalIncludeDirectories) 144 | 145 | 146 | Console 147 | true 148 | true 149 | true 150 | SDL2.lib;SDL2main.lib;SDL2_image.lib;%(AdditionalDependencies) 151 | ..\SDL_src\VC\SDL2\lib\x64;..\SDL_src\VC\SDL2_image\lib\x64;%(AdditionalLibraryDirectories) 152 | 153 | 154 | CP ../SDL_src/VC/SDL2/lib/x64/SDL2.dll ../x64/Debug/ 155 | CP ../SDL_src/VC/SDL2_image/lib/x64/SDL2_image.dll ../x64/Debug/ 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /WindowsProject/WindowsProject.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(projectdir)..\x64\Debug 5 | WindowsLocalDebugger 6 | 7 | 8 | $(projectdir)..\x64\Debug 9 | WindowsLocalDebugger 10 | 11 | 12 | $(projectdir)..\x64\Debug 13 | WindowsLocalDebugger 14 | 15 | 16 | $(projectdir)..\x64\Debug 17 | WindowsLocalDebugger 18 | 19 | -------------------------------------------------------------------------------- /WindowsProject/WindowsProject1.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | 37 | 38 | Resource Files 39 | 40 | 41 | 42 | 43 | Resource Files 44 | 45 | 46 | Resource Files 47 | 48 | 49 | -------------------------------------------------------------------------------- /WindowsProject/WindowsProject1.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /petrobots.h: -------------------------------------------------------------------------------- 1 | #ifndef _PETROBOTS_H 2 | #define _PETROBOTS_H 3 | 4 | #include "Platform.h" 5 | 6 | #define MAP_WINDOW_SIZE (PLATFORM_MAP_WINDOW_TILES_WIDTH * PLATFORM_MAP_WINDOW_TILES_HEIGHT) 7 | #define MAP_WINDOW_WIDTH (PLATFORM_MAP_WINDOW_TILES_WIDTH * 24) 8 | #define MAP_WINDOW_HEIGHT (PLATFORM_MAP_WINDOW_TILES_HEIGHT * 24) 9 | 10 | // MAP FILES CONSIST OF EVERYTHING FROM THIS POINT ON 11 | extern uint8_t MAP_DATA[8960]; 12 | #define UNIT_TYPE MAP_DATA // Unit type 0=none (64 bytes) 13 | #define UNIT_LOC_X (MAP_DATA + 1 * 64) // Unit X location (64 bytes) 14 | #define UNIT_LOC_Y (MAP_DATA + 2 * 64) // Unit X location (64 bytes) 15 | #define UNIT_A (MAP_DATA + 3 * 64) 16 | #define UNIT_B (MAP_DATA + 4 * 64) 17 | #define UNIT_C (MAP_DATA + 5 * 64) 18 | #define UNIT_D (MAP_DATA + 6 * 64) 19 | #define UNIT_HEALTH ((int8_t*)(MAP_DATA + 7 * 64)) // Unit health (0 to 11) (64 bytes) 20 | #define MAP (MAP_DATA + 8 * 64 + 256) // Location of MAP (8K) 21 | // END OF MAP FILE 22 | 23 | extern uint8_t* DESTRUCT_PATH; // Destruct path array (256 bytes) 24 | extern uint8_t* TILE_ATTRIB; // Tile attrib array (256 bytes) 25 | #ifndef PLATFORM_SPRITE_SUPPORT 26 | extern uint8_t* TILE_DATA_TL; // Tile character top-left (256 bytes) 27 | extern uint8_t* TILE_DATA_TM; // Tile character top-middle (256 bytes) 28 | extern uint8_t* TILE_DATA_TR; // Tile character top-right (256 bytes) 29 | extern uint8_t* TILE_DATA_ML; // Tile character middle-left (256 bytes) 30 | extern uint8_t* TILE_DATA_MM; // Tile character middle-middle (256 bytes) 31 | extern uint8_t* TILE_DATA_MR; // Tile character middle-right (256 bytes) 32 | extern uint8_t* TILE_DATA_BL; // Tile character bottom-left (256 bytes) 33 | extern uint8_t* TILE_DATA_BM; // Tile character bottom-middle (256 bytes) 34 | extern uint8_t* TILE_DATA_BR; // Tile character bottom-right (256 bytes) 35 | #endif 36 | 37 | // These arrays can go anywhere in RAM 38 | extern uint8_t UNIT_TIMER_A[64]; // Primary timer for units (64 bytes) 39 | extern uint8_t UNIT_TIMER_B[64]; // Secondary timer for units (64 bytes) 40 | extern uint8_t UNIT_TILE[32]; // Current tile assigned to unit (32 bytes) 41 | extern uint8_t EXP_BUFFER[16]; // Explosion Buffer (16 bytes) 42 | extern uint8_t MAP_PRECALC[MAP_WINDOW_SIZE]; // Stores pre-calculated objects for map window (77 bytes) 43 | extern uint8_t MAP_PRECALC_DIRECTION[MAP_WINDOW_SIZE]; // Stores pre-calculated object directions for map window (77 bytes) 44 | extern uint8_t MAP_PRECALC_TYPE[MAP_WINDOW_SIZE]; // Stores pre-calculated object types for map window (77 bytes) 45 | #ifdef OPTIMIZED_MAP_RENDERING 46 | extern uint8_t PREVIOUS_MAP_BACKGROUND[MAP_WINDOW_SIZE]; 47 | extern uint8_t PREVIOUS_MAP_FOREGROUND[MAP_WINDOW_SIZE]; 48 | extern uint8_t PREVIOUS_MAP_FOREGROUND_VARIANT[MAP_WINDOW_SIZE]; 49 | #endif 50 | 51 | // The following are the locations where the current 52 | // key controls are stored. These must be set before 53 | // the game can start. 54 | extern uint8_t KEY_CONFIG[26]; 55 | 56 | extern uint8_t TILE; // The tile number to be plotted 57 | extern uint8_t DIRECTION; // The direction of the tile to be plotted 58 | extern uint8_t WALK_FRAME; // Player walking animation frame 59 | extern uint8_t DEMATERIALIZE_FRAME; // Dematerialize animation frame 60 | extern uint8_t MAP_X; // Current X location on map 61 | extern uint8_t MAP_Y; // Current Y location on map 62 | extern uint8_t MAP_WINDOW_X; // Top left location of what is displayed in map window 63 | extern uint8_t MAP_WINDOW_Y; // Top left location of what is displayed in map window 64 | extern uint8_t DECNUM; // a decimal number to be displayed onscreen as 3 digits. 65 | extern uint8_t ATTRIB; // Tile attribute value 66 | extern uint8_t UNIT; // Current unit being processed 67 | extern uint8_t TEMP_A; // used within some routines 68 | extern uint8_t TEMP_B; // used within some routines 69 | extern uint8_t TEMP_C; // used within some routines 70 | extern uint8_t TEMP_D; // used within some routines 71 | extern uint8_t CURSOR_X; // For on-screen cursor 72 | extern uint8_t CURSOR_Y; // For on-screen cursor 73 | extern uint8_t CURSOR_ON; // Is cursor active or not? 1=yes 0=no 74 | extern uint8_t REDRAW_WINDOW; // 1=yes 0=no 75 | extern uint8_t MOVE_RESULT; // 1=Move request success, 0=fail. 76 | extern uint8_t UNIT_FIND; // 255=no unit present. 77 | extern uint8_t MOVE_TYPE; // %00000001=WALK %00000010=HOVER 78 | extern uint8_t* CUR_PATTERN; // stores the memory location of the current musical pattern being played. 79 | 80 | //extern uint8_t LSTX; // $97 Current Key Pressed: 255 = No Key 81 | extern uint8_t NDX; // $9E No. of Chars. in Keyboard Buffer (Queue) 82 | extern uint8_t* MAP_SOURCE; // $FD 83 | extern uint8_t SCREEN_MEMORY[SCREEN_WIDTH_IN_CHARACTERS * SCREEN_HEIGHT_IN_CHARACTERS]; // $8000 84 | extern bool quit; 85 | 86 | void INIT_GAME(); 87 | 88 | //extern char MAPNAME[]; 89 | extern const char* LOADMSG1; 90 | extern uint8_t KEYS; // bit0=spade bit2=heart bit3=star 91 | extern uint8_t AMMO_PISTOL; // how much ammo for the pistol 92 | extern uint8_t AMMO_PLASMA; // how many shots of the plasmagun 93 | extern uint8_t INV_BOMBS; // How many bombs do we have 94 | extern uint8_t INV_EMP; // How many EMPs do we have 95 | extern uint8_t INV_MEDKIT; // How many medkits do we have? 96 | extern uint8_t INV_MAGNET; // How many magnets do we have? 97 | extern uint8_t SELECTED_WEAPON; // 0=none 1=pistol 2=plasmagun 98 | extern uint8_t SELECTED_ITEM; // 0=none 1=bomb 2=emp 3=medkit 4=magnet 99 | extern uint8_t SELECT_TIMEOUT; // can only change weapons once it hits zero 100 | extern uint8_t ANIMATE; // 0=DISABLED 1=ENABLED 101 | extern uint8_t BIG_EXP_ACT; // 0=No explosion active 1=big explosion active 102 | extern uint8_t MAGNET_ACT; // 0=no magnet active 1=magnet active 103 | extern uint8_t PLASMA_ACT; // 0=No plasma fire active 1=plasma fire active 104 | extern uint8_t RANDOM; // used for random number generation 105 | extern uint8_t BORDER; // Used for border flash timing 106 | extern uint8_t SCREEN_SHAKE; // 1=shake 0=no shake 107 | extern uint8_t CONTROL; // 0=keyboard 1=custom keys 2=snes 108 | extern uint16_t BORDER_COLOR; // Used for border flash coloring 109 | extern char INTRO_MESSAGE[]; 110 | extern char MSG_CANTMOVE[]; 111 | extern char MSG_BLOCKED[]; 112 | extern char MSG_SEARCHING[]; 113 | extern char MSG_NOTFOUND[]; 114 | extern char MSG_FOUNDKEY[]; 115 | extern char MSG_FOUNDGUN[]; 116 | extern char MSG_FOUNDEMP[]; 117 | extern char MSG_FOUNDBOMB[]; 118 | extern char MSG_FOUNDPLAS[]; 119 | extern char MSG_FOUNDMED[]; 120 | extern char MSG_FOUNDMAG[]; 121 | extern char MSG_MUCHBET[]; 122 | extern char MSG_EMPUSED[]; 123 | extern char MSG_TERMINATED[]; 124 | extern char MSG_TRANS1[]; 125 | extern char MSG_ELEVATOR[]; 126 | extern char MSG_LEVELS[]; 127 | extern char MSG_PAUSED[]; 128 | extern char MSG_MUSICON[]; 129 | extern char MSG_MUSICOFF[]; 130 | extern uint8_t SELECTED_MAP; 131 | extern char MAP_NAMES[]; 132 | #ifndef PLATFORM_MODULE_BASED_AUDIO 133 | // THE FOLLOWING ARE USED BY THE SOUND SYSTEM* 134 | extern uint8_t TEMPO_TIMER; // used for counting down to the next tick 135 | extern uint8_t TEMPO; // How many IRQs between ticks 136 | extern uint8_t DATA_LINE; // used for playback to keep track of which line we are executing. 137 | extern uint8_t ARP_MODE; // 0=no 1=major 2=minor 3=sus4 138 | extern uint8_t CHORD_ROOT; // root note of the chord 139 | extern uint8_t SOUND_EFFECT; // FF=OFF or number of effect in progress 140 | #endif 141 | extern uint8_t MUSIC_ON; // 0=off 1=on 142 | 143 | void DISPLAY_LOAD_MESSAGE1(); 144 | void DISPLAY_LOAD_MESSAGE2(); 145 | 146 | extern char LOAD_MSG2[]; 147 | 148 | void SETUP_INTERRUPT(); 149 | void RUNIRQ(); 150 | 151 | extern uint8_t BGTIMER1; 152 | extern uint8_t BGTIMER2; 153 | extern uint8_t KEYTIMER; // Used for repeat of movement 154 | 155 | void UPDATE_GAME_CLOCK(); 156 | 157 | extern uint8_t HOURS; 158 | extern uint8_t MINUTES; 159 | extern uint8_t SECONDS; 160 | extern uint8_t CYCLES; 161 | extern uint8_t CLOCK_ACTIVE; 162 | #ifdef INACTIVITY_TIMEOUT_GAME 163 | extern uint8_t INACTIVE_SECONDS; 164 | #endif 165 | 166 | void SET_INITIAL_TIMERS(); 167 | void MAIN_GAME_LOOP(); 168 | void AFTER_MOVE_SNES(); 169 | void TOGGLE_MUSIC(); 170 | void START_IN_GAME_MUSIC(); 171 | 172 | #ifdef PLATFORM_MODULE_BASED_AUDIO 173 | extern Platform::Module LEVEL_MUSIC[]; 174 | #else 175 | extern uint8_t LEVEL_MUSIC[]; 176 | #endif 177 | 178 | void CHEATER(); 179 | bool PAUSE_GAME(); 180 | void CLEAR_KEY_BUFFER(); 181 | void USE_ITEM(); 182 | void USE_BOMB(); 183 | void USE_MAGNET(); 184 | bool BOMB_MAGNET_COMMON1(); 185 | void BOMB_MAGNET_COMMON2(); 186 | void USE_EMP(); 187 | void USE_MEDKIT(); 188 | void FIRE_UP(); 189 | void FIRE_UP_PISTOL(); 190 | void FIRE_UP_PLASMA(); 191 | void FIRE_DOWN(); 192 | void FIRE_DOWN_PISTOL(); 193 | void FIRE_DOWN_PLASMA(); 194 | void FIRE_LEFT(); 195 | void FIRE_LEFT_PISTOL(); 196 | void FIRE_LEFT_PLASMA(); 197 | void FIRE_RIGHT(); 198 | void FIRE_RIGHT_PISTOL(); 199 | void FIRE_RIGHT_PLASMA(); 200 | void AFTER_FIRE(int X); 201 | void KEY_REPEAT(bool keyDown); 202 | void AFTER_MOVE(); 203 | 204 | extern uint8_t KEY_FAST; // 0=DEFAULT STATE 205 | 206 | void SEARCH_OBJECT(); 207 | 208 | extern uint8_t SEARCHBAR; // to count how many periods to display. 209 | 210 | void CALC_COORDINATES(); 211 | void USER_SELECT_OBJECT(); 212 | void MOVE_OBJECT(); 213 | 214 | extern uint8_t MOVTEMP_O; // origin tile 215 | extern uint8_t MOVTEMP_D; // destination tile 216 | extern uint8_t MOVTEMP_X; // x-coordinate 217 | extern uint8_t MOVTEMP_Y; // y-coordinate 218 | extern uint8_t MOVTEMP_U; // unit number (255=none) 219 | extern uint8_t MOVTEMP_UX; 220 | extern uint8_t MOVTEMP_UY; 221 | 222 | void CACULATE_AND_REDRAW(); 223 | void MAP_PRE_CALCULATE(); 224 | 225 | #ifdef OPTIMIZED_MAP_RENDERING 226 | void INVALIDATE_PREVIOUS_MAP(); 227 | #endif 228 | void DRAW_MAP_WINDOW(); 229 | 230 | #ifdef PLATFORM_LIVE_MAP_SUPPORT 231 | void TOGGLE_LIVE_MAP(); 232 | void TOGGLE_LIVE_MAP_ROBOTS(); 233 | void DRAW_LIVE_MAP(); 234 | 235 | extern uint8_t LIVE_MAP_ON; 236 | extern uint8_t LIVE_MAP_ROBOTS_ON; 237 | extern uint8_t LIVE_MAP_PLAYER_BLINK; 238 | #endif 239 | 240 | #ifdef PLATFORM_TILE_BASED_RENDERING 241 | void PLOT_TILE(uint16_t destination, uint16_t x, uint16_t y); 242 | void PLOT_TRANSPARENT_TILE(uint16_t destination, uint16_t x, uint16_t y); 243 | #else 244 | void PLOT_TILE(uint16_t destination); 245 | void PLOT_TRANSPARENT_TILE(uint16_t destination); 246 | #endif 247 | #ifndef PLATFORM_CURSOR_SUPPORT 248 | void REVERSE_TILE(); 249 | #endif 250 | void CHECK_FOR_WINDOW_REDRAW(); 251 | void DECWRITE(uint16_t destination, uint8_t color = 10); 252 | 253 | void TILE_LOAD_ROUTINE(); 254 | void MAP_LOAD_ROUTINE(); 255 | void DISPLAY_GAME_SCREEN(); 256 | 257 | extern char INTRO_OPTIONS[]; 258 | 259 | void DISPLAY_INTRO_SCREEN(); 260 | void DISPLAY_ENDGAME_SCREEN(); 261 | 262 | extern char DIFF_LEVEL_WORDS[]; 263 | 264 | void DECOMPRESS_SCREEN(uint8_t* source, uint8_t color = 10); 265 | 266 | extern uint8_t RPT; // repeat value 267 | 268 | void DISPLAY_PLAYER_HEALTH(); 269 | void CYCLE_ITEM(); 270 | void DISPLAY_ITEM(); 271 | void PRESELECT_ITEM(); 272 | void DISPLAY_TIMEBOMB(); 273 | void DISPLAY_EMP(); 274 | void DISPLAY_MEDKIT(); 275 | void DISPLAY_MAGNET(); 276 | void DISPLAY_BLANK_ITEM(); 277 | void CYCLE_WEAPON(); 278 | void DISPLAY_WEAPON(); 279 | void PRESELECT_WEAPON(); 280 | void DISPLAY_PLASMA_GUN(); 281 | void DISPLAY_PISTOL(); 282 | void DISPLAY_BLANK_WEAPON(); 283 | void DISPLAY_KEYS(); 284 | void GAME_OVER(); 285 | void GOM4(); 286 | 287 | extern uint8_t GAMEOVER1[]; 288 | extern uint8_t GAMEOVER2[]; 289 | extern uint8_t GAMEOVER3[]; 290 | 291 | void DISPLAY_WIN_LOSE(); 292 | 293 | extern char WIN_MSG[]; 294 | extern char LOS_MSG[]; 295 | 296 | void PRINT_INTRO_MESSAGE(); 297 | void PRINT_INFO(const char*); 298 | 299 | extern uint8_t PRINTX; 300 | 301 | void SCROLL_INFO(); 302 | void RESET_KEYS_AMMO(); 303 | void INTRO_SCREEN(); 304 | void START_INTRO_MUSIC(); 305 | bool EXEC_COMMAND(); 306 | void CYCLE_CONTROLS(); 307 | 308 | extern char CONTROLTEXT[]; 309 | extern uint8_t CONTROLSTART[]; 310 | 311 | void CYCLE_MAP(); 312 | void DISPLAY_MAP_NAME(); 313 | char* CALC_MAP_NAME(); 314 | void REVERSE_MENU_OPTION(bool reverse); 315 | 316 | extern uint8_t MENUY; // CURRENT MENU SELECTION 317 | typedef uint16_t menu_chart_t; 318 | extern menu_chart_t MENU_CHART[]; 319 | 320 | void CHANGE_DIFFICULTY_LEVEL(); 321 | 322 | extern uint8_t DIFF_LEVEL; // default medium 323 | extern uint8_t ROBOT_FACE[]; 324 | extern uint8_t FACE_LEVEL[]; 325 | 326 | void SET_DIFF_LEVEL(); 327 | void SET_DIFF_EASY(); 328 | void SET_DIFF_HARD(); 329 | 330 | extern uint16_t MAP_CHART[PLATFORM_MAP_WINDOW_TILES_HEIGHT]; 331 | 332 | void EMP_FLASH(); 333 | void ANIMATE_WATER(); 334 | 335 | extern uint8_t WATER_TIMER; 336 | #ifdef PLATFORM_IMAGE_BASED_TILES 337 | extern uint8_t ANIM_STATE; 338 | #else 339 | extern uint8_t WATER_TEMP1; 340 | extern uint8_t HVAC_STATE; 341 | #endif 342 | extern uint8_t CINEMA_STATE; 343 | 344 | void ELEVATOR_SELECT(); 345 | 346 | extern uint8_t ELEVATOR_MAX_FLOOR; 347 | extern uint8_t ELEVATOR_CURRENT_FLOOR; 348 | 349 | void ELEVATOR_INVERT(); 350 | void ELEVATOR_INC(); 351 | void ELEVATOR_DEC(); 352 | void ELEVATOR_FIND_XY(); 353 | void SET_CONTROLS(); 354 | 355 | extern uint8_t STANDARD_CONTROLS[]; 356 | 357 | void SET_CUSTOM_KEYS(); 358 | 359 | extern uint8_t KEYS_DEFINED; // DEFAULT 0 360 | 361 | void PET_SCREEN_SHAKE(); 362 | void PET_BORDER_FLASH(); 363 | 364 | extern uint8_t FLASH_STATE; 365 | #ifndef PLATFORM_IMAGE_SUPPORT 366 | extern uint8_t OUCH1[]; 367 | extern uint8_t OUCH2[]; 368 | extern uint8_t OUCH3[]; 369 | #endif 370 | 371 | void DEMATERIALIZE(); 372 | void ANIMATE_PLAYER(); 373 | void PLAY_SOUND(int); 374 | 375 | #ifndef PLATFORM_MODULE_BASED_AUDIO 376 | extern uint8_t* PATTERN_TEMP; 377 | extern uint8_t DATA_LINE_TEMP; 378 | extern uint8_t TEMPO_TEMP; 379 | 380 | extern uint8_t* SOUND_LIBRARY[]; 381 | 382 | void MUSIC_ROUTINE(); 383 | #endif 384 | void STOP_SONG(); 385 | void BACKGROUND_TASKS(); 386 | 387 | extern void (*AI_ROUTINE_CHART[])(void); 388 | 389 | void DUMMY_ROUTINE(); 390 | void WATER_RAFT_LR(); 391 | void RAFT_DELETE(); 392 | void RAFT_PLOT(); 393 | void MAGNETIZED_ROBOT(); 394 | void GENERATE_RANDOM_NUMBER(); 395 | void MAGNET(); 396 | void DEAD_ROBOT(); 397 | void UP_DOWN_ROLLERBOT(); 398 | void LEFT_RIGHT_ROLLERBOT(); 399 | void ROLLERBOT_FIRE_DETECT(); 400 | void ROLLERBOT_AFTER_FIRE(uint8_t unit, uint8_t tile); 401 | void ROLLERBOT_ANIMATE(); 402 | void TRANSPORTER_PAD(); 403 | void TRANS_PLAYER_PRESENT(); 404 | void TRANS_ACTIVE(); 405 | void TIME_BOMB(); 406 | void BIG_EXP_PHASE1(); 407 | void BEX1_NORTH(); 408 | void BEX1_SOUTH(); 409 | void BEX1_EAST(); 410 | void BEX1_WEST(); 411 | void BEX1_NE(); 412 | void BEX1_NW(); 413 | void BEX1_SE(); 414 | void BEX1_SW(); 415 | void BEX_PART1(); 416 | bool BEX_PART2(); 417 | void BEX_PART3(); 418 | void BEXCEN(); 419 | void BIG_EXP_PHASE2(); 420 | void RESTORE_TILE(); 421 | void TRASH_COMPACTOR(); 422 | void DRAW_TRASH_COMPACTOR(); 423 | extern uint8_t TCPIECE1; 424 | extern uint8_t TCPIECE2; 425 | extern uint8_t TCPIECE3; 426 | extern uint8_t TCPIECE4; 427 | void WATER_DROID(); 428 | void PISTOL_FIRE_UP(); 429 | void PISTOL_FIRE_DOWN(); 430 | void PISTOL_FIRE_LEFT(); 431 | void PISTOL_FIRE_RIGHT(); 432 | void DEACTIVATE_WEAPON(); 433 | void PISTOL_AI_COMMON(); 434 | void ALTER_AI(); 435 | void INFLICT_DAMAGE(); 436 | void SMALL_EXPLOSION(); 437 | void HOVER_ATTACK(); 438 | void CREATE_PLAYER_EXPLOSION(); 439 | void EVILBOT(); 440 | void AI_DOOR(); 441 | extern void (*AIDB[])(void); 442 | void DOOR_OPEN_A(); 443 | void DOOR_OPEN_B(); 444 | void DOOR_OPEN_FULL(); 445 | void DOOR_CLOSE_A(); 446 | void DOOR_CLOSE_B(); 447 | void DOOR_CLOSE_FULL(); 448 | void DRAW_VERTICAL_DOOR(); 449 | void DRAW_HORIZONTAL_DOOR(); 450 | extern uint8_t DOORPIECE1; 451 | extern uint8_t DOORPIECE2; 452 | extern uint8_t DOORPIECE3; 453 | void ROBOT_ATTACK_RANGE(); 454 | void DOOR_CHECK_PROXIMITY(); 455 | extern uint8_t PROX_DETECT; 456 | void ELEVATOR(); 457 | extern void (*ELDB[])(void); 458 | void ELEV_OPEN_A(); 459 | void ELEV_OPEN_B(); 460 | void ELEV_OPEN_FULL(); 461 | void ELEV_CLOSE_A(); 462 | void ELEV_CLOSE_B(); 463 | void ELEV_CLOSE_FULL(); 464 | void ELEVATOR_PANEL(); 465 | void PLOT_TILE_TO_MAP(); 466 | void GET_TILE_FROM_MAP(); 467 | void LEFT_RIGHT_DROID(); 468 | void UP_DOWN_DROID(); 469 | void HOVERBOT_ANIMATE(uint8_t X); 470 | void REQUEST_WALK_RIGHT(); 471 | void REQUEST_WALK_LEFT(); 472 | void REQUEST_WALK_DOWN(); 473 | void REQUEST_WALK_UP(); 474 | void CHECK_FOR_UNIT(); 475 | void CHECK_FOR_HIDDEN_UNIT(); 476 | 477 | #ifndef PLATFORM_IMAGE_SUPPORT 478 | extern uint8_t INTRO_TEXT[]; 479 | extern uint8_t SCR_TEXT[]; 480 | extern uint8_t SCR_ENDGAME[]; 481 | #endif 482 | extern uint8_t SCR_CUSTOM_KEYS[]; 483 | extern char CINEMA_MESSAGE[]; 484 | #ifndef PLATFORM_IMAGE_SUPPORT 485 | extern uint8_t WEAPON1A[]; 486 | extern uint8_t WEAPON1B[]; 487 | extern uint8_t WEAPON1C[]; 488 | extern uint8_t WEAPON1D[]; 489 | extern uint8_t PISTOL1A[]; 490 | extern uint8_t PISTOL1B[]; 491 | extern uint8_t PISTOL1C[]; 492 | extern uint8_t PISTOL1D[]; 493 | extern uint8_t TBOMB1A[]; 494 | extern uint8_t TBOMB1B[]; 495 | extern uint8_t TBOMB1C[]; 496 | extern uint8_t TBOMB1D[]; 497 | extern uint8_t EMP1A[]; 498 | extern uint8_t EMP1B[]; 499 | extern uint8_t EMP1C[]; 500 | extern uint8_t EMP1D[]; 501 | extern uint8_t MAG1A[]; 502 | extern uint8_t MAG1B[]; 503 | extern uint8_t MAG1C[]; 504 | extern uint8_t MAG1D[]; 505 | extern uint8_t MED1A[]; 506 | extern uint8_t MED1B[]; 507 | extern uint8_t MED1C[]; 508 | extern uint8_t MED1D[]; 509 | #endif 510 | #ifndef PLATFORM_MODULE_BASED_AUDIO 511 | extern uint8_t NOTE_FREQ[]; 512 | extern uint8_t NOTE_OCTAVE[]; 513 | extern uint8_t SND_EXPLOSION[]; 514 | extern uint8_t SND_MEDKIT[]; 515 | extern uint8_t SND_EMP[]; 516 | extern uint8_t SND_MAGNET[]; 517 | extern uint8_t SND_SHOCK[]; 518 | extern uint8_t SND_MOVE_OBJ[]; 519 | extern uint8_t SND_PLASMA[]; 520 | extern uint8_t SND_PISTOL[]; 521 | extern uint8_t SND_ITEM_FOUND[]; 522 | extern uint8_t SND_ERROR[]; 523 | extern uint8_t SND_CYCLE_WEAPON[]; 524 | extern uint8_t SND_CYCLE_ITEM[]; 525 | extern uint8_t SND_DOOR[]; 526 | extern uint8_t SND_MENU_BEEP[]; 527 | extern uint8_t SND_SHORT_BEEP[]; 528 | extern uint8_t INTRO_MUSIC[]; 529 | extern uint8_t WIN_MUSIC[]; 530 | extern uint8_t LOSE_MUSIC[]; 531 | extern uint8_t IN_GAME_MUSIC1[]; 532 | extern uint8_t IN_GAME_MUSIC2[]; 533 | extern uint8_t IN_GAME_MUSIC3[]; 534 | #endif 535 | 536 | void convertToPETSCII(char* string); 537 | void writeToScreenMemory(address_t address, uint8_t value, uint8_t color = 10, uint8_t yOffset = 0); 538 | 539 | #endif 540 | -------------------------------------------------------------------------------- /tileset.amiga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/tileset.amiga -------------------------------------------------------------------------------- /tileset.pet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zeropolis79/PETSCIIRobots-SDL/0874d6ef18d57ca5d7c17217388be0d2342b6a7f/tileset.pet --------------------------------------------------------------------------------