Update
[anarch.git] / main_pokitto.cpp
blob0bedcd90e402ddc6d07dc5e50e456a321306c600
1 /**
2 @file main_pokitto.cpp
4 This is Pokitto implementation of the game front end, using the official
5 PokittoLib.
7 by Miloslav Ciz (drummyfish), 2019
9 Released under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/)
10 plus a waiver of all other intellectual property. The goal of this work is to
11 be and remain completely in the public domain forever, available for any use
12 whatsoever.
15 #define JOYHAT // compiles the version for Pokitto with joystick hat
17 #if 0
18 // for debug:
19 #define SFG_LOG(s) puts(s);
20 #define SFG_CPU_LOAD(x) printf("CPU: %d\n",x);
21 #endif
23 #if _OSCT == 2
24 // overclock
25 #define SFG_FPS 36
26 #define SFG_DIMINISH_SPRITES 1
27 #define SFG_RAYCASTING_MAX_HITS 6
28 #else
29 #define SFG_FPS 22
30 #define SFG_DIMINISH_SPRITES 0
31 #define SFG_RAYCASTING_MAX_HITS 5
32 #endif
34 #define SFG_CAN_EXIT 0
35 #define SFG_PLAYER_TURN_SPEED 135
37 #ifndef JOYHAT
38 #define SFG_SCREEN_RESOLUTION_X 110
39 #define SFG_SCREEN_RESOLUTION_Y 88
40 #else
41 #define SFG_SCREEN_RESOLUTION_X 88
42 #define SFG_SCREEN_RESOLUTION_Y 110
44 #define SFG_FOV_VERTICAL 350
45 #define SFG_FOV_HORIZONTAL 210
47 #include "JoyHat/JoyHat.h"
48 JoyHat joy;
50 uint16_t rumbleCooldown = 0;
51 uint16_t axisThreshold1, axisThreshold2;
52 #endif
54 #define SFG_RESOLUTION_SCALEDOWN 1
55 #define SFG_DITHERED_SHADOW 0
56 #define SFG_FOG_DIMINISH_STEP 2048
57 #define SFG_RAYCASTING_MAX_STEPS 20
58 #define SFG_RAYCASTING_SUBSAMPLE 2
60 #include "game.h"
61 #include "sounds.h"
63 #include "../PokittoLib/Pokitto/POKITTO_HW/clock_11u6x.h"
64 #include "../PokittoLib/Pokitto/POKITTO_HW/timer_11u6x.h"
66 #include "../PokittoLib/Pokitto/Pokitto.h"
67 #include "PokittoCookie.h"
69 class SaveCookie: public Pokitto::Cookie
71 public:
72 uint8_t data[SFG_SAVE_SIZE];
75 SaveCookie save;
77 Pokitto::Core pokitto;
79 uint8_t *pokittoScreen;
81 void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex)
83 #ifndef JOYHAT
84 pokittoScreen[y * SFG_SCREEN_RESOLUTION_X + x] = colorIndex;
85 #else
86 pokittoScreen[x * SFG_SCREEN_RESOLUTION_Y + (SFG_SCREEN_RESOLUTION_Y - 1 - y)]
87 = colorIndex;
88 #endif
91 uint32_t SFG_getTimeMs()
93 return pokitto.getTime();
96 void SFG_sleepMs(uint16_t timeMs)
100 int8_t SFG_keyPressed(uint8_t key)
102 switch (key)
104 #ifdef JOYHAT
105 case SFG_KEY_UP: return joy.JoyX() < axisThreshold1; break;
106 case SFG_KEY_DOWN: return joy.JoyX() > axisThreshold2; break;
107 case SFG_KEY_RIGHT: return joy.JoyY() > axisThreshold2; break;
108 case SFG_KEY_LEFT: return joy.JoyY() < axisThreshold1; break;
109 case SFG_KEY_JUMP: return pokitto.rightBtn(); break;
110 case SFG_KEY_STRAFE_RIGHT: return pokitto.downBtn(); break;
111 case SFG_KEY_STRAFE_LEFT: return pokitto.upBtn(); break;
112 case SFG_KEY_MAP: return pokitto.leftBtn(); break;
113 case SFG_KEY_PREVIOUS_WEAPON: return joy.Button1(); break;
114 case SFG_KEY_NEXT_WEAPON: return joy.Button2(); break;
115 #else
116 case SFG_KEY_UP: return pokitto.upBtn(); break;
117 case SFG_KEY_DOWN: return pokitto.downBtn(); break;
118 case SFG_KEY_RIGHT: return pokitto.rightBtn(); break;
119 case SFG_KEY_LEFT: return pokitto.leftBtn(); break;
120 #endif
122 case SFG_KEY_A: return pokitto.aBtn(); break;
123 case SFG_KEY_B: return pokitto.bBtn(); break;
124 case SFG_KEY_C: return pokitto.cBtn(); break;
125 default: return 0; break;
129 void SFG_getMouseOffset(int16_t *x, int16_t *y)
133 uint8_t audioBuff[SFG_SFX_SAMPLE_COUNT];
134 uint16_t audioPos = 0;
136 uint8_t musicOn = 0;
138 void SFG_setMusic(uint8_t value)
140 switch (value)
142 case SFG_MUSIC_TURN_ON: musicOn = 1; break;
143 case SFG_MUSIC_TURN_OFF: musicOn = 0; break;
144 case SFG_MUSIC_NEXT:
146 /* Skipping a track takes some time, so turn off music for a while
147 (otherwise noise can be heard). */
148 uint8_t music = musicOn;
149 musicOn = 0;
150 SFG_nextMusicTrack();
151 musicOn = music;
153 break;
154 defaule: break;
158 static inline uint8_t mixSamples(uint8_t sample1, uint8_t sample2)
160 return (sample1 >> 1) + (sample2 >> 1);
163 void onTimer() // for sound
165 if (Chip_TIMER_MatchPending(LPC_TIMER32_0, 1))
167 Chip_TIMER_ClearMatch(LPC_TIMER32_0, 1);
169 Pokitto::dac_write(
170 musicOn ?
171 mixSamples(audioBuff[audioPos],SFG_getNextMusicSample() / 2) :
172 audioBuff[audioPos]
175 audioBuff[audioPos] = 127;
177 audioPos = (audioPos + 1) % SFG_SFX_SAMPLE_COUNT;
181 void timerInit(uint32_t samplingRate)
183 Chip_TIMER_Init(LPC_TIMER32_0);
184 Chip_TIMER_Reset(LPC_TIMER32_0);
185 Chip_TIMER_MatchEnableInt(LPC_TIMER32_0, 1);
186 Chip_TIMER_SetMatch(LPC_TIMER32_0, 1,
187 (Chip_Clock_GetSystemClockRate() / samplingRate));
188 Chip_TIMER_ResetOnMatchEnable(LPC_TIMER32_0, 1);
189 Chip_TIMER_Enable(LPC_TIMER32_0);
191 #define weirdNumber ((IRQn_Type) 18)
192 NVIC_ClearPendingIRQ(weirdNumber);
193 NVIC_SetVector(weirdNumber, (uint32_t) &onTimer);
194 NVIC_EnableIRQ(weirdNumber);
195 #undef weirdNumber
198 void SFG_save(uint8_t data[SFG_SAVE_SIZE])
200 for (uint8_t i = 0; i < SFG_SAVE_SIZE; ++i)
201 save.data[i] = data[i];
203 save.saveCookie();
205 /* ^ This causes sound to stop as it writes something to timer32, we need to
206 reinit the audio: */
208 timerInit(8000);
211 void SFG_processEvent(uint8_t event, uint8_t data)
213 #ifdef JOYHAT
214 switch (event)
216 case SFG_EVENT_VIBRATE:
217 if (rumbleCooldown == 0)
219 joy.Rumble(0.025);
220 rumbleCooldown = 32;
222 break;
224 default: break;
226 #endif
229 uint8_t SFG_load(uint8_t data[SFG_SAVE_SIZE])
231 for (uint8_t i = 0; i < SFG_SAVE_SIZE; ++i)
232 data[i] = save.data[i];
234 return 1;
237 void SFG_playSound(uint8_t soundIndex, uint8_t volume)
239 uint8_t volumeShift = 7 - volume / 32;
240 uint16_t baseLevel = 128 - (128 >> volumeShift);
242 uint16_t pos = audioPos;
244 for (int i = 0; i < SFG_SFX_SAMPLE_COUNT; ++i)
246 audioBuff[pos] = mixSamples(audioBuff[pos],baseLevel +
247 (SFG_GET_SFX_SAMPLE(soundIndex,i) >> volumeShift));
249 pos = (pos < SFG_SFX_SAMPLE_COUNT - 1) ? (pos + 1) : 0;
253 int main()
255 save.begin("ANARCH",sizeof(save),(char*) &save);
257 pokitto.begin();
259 #ifdef JOYHAT
260 axisThreshold1 = joy.joyScale / 4;
261 axisThreshold2 = joy.joyScale - axisThreshold1;
262 #endif
264 uint8_t allZeros = 1;
266 for (uint8_t i = 0; i < SFG_SAVE_SIZE; ++i)
267 if (save.data[i] != 0)
269 allZeros = 0;
270 break;
273 if (allZeros) // 1st time save?
275 SFG_createDefaultSaveData(save.data);
276 save.saveCookie();
279 timerInit(8000);
281 for (uint16_t i = 0; i < SFG_SFX_SAMPLE_COUNT; ++i)
282 audioBuff[i] = 127;
284 pokitto.setFrameRate(255);
285 pokitto.display.setFont(fontTiny);
286 pokitto.display.persistence = 1;
287 pokitto.display.setInvisibleColor(-1);
288 pokitto.display.load565Palette(paletteRGB565);
290 pokittoScreen = pokitto.display.screenbuffer;
292 SFG_init();
294 while (pokitto.isRunning())
296 if (pokitto.update())
297 SFG_mainLoopBody();
299 #ifdef JOYHAT
300 if (rumbleCooldown > 0)
301 rumbleCooldown--;
302 #endif
304 if (SFG_game.state == SFG_GAME_STATE_MENU &&
305 SFG_game.keyStates[SFG_KEY_LEFT] == 255 &&
306 SFG_game.keyStates[SFG_KEY_RIGHT] == 255 &&
307 SFG_game.keyStates[SFG_KEY_B] == 255)
309 // holding L+R+B in menu will erase all saved data
311 save.deleteCookie();
312 pokitto.quit();
315 #if 0
316 pokitto.display.setCursor(0,0);
317 pokitto.display.print(pokitto.fps_counter);
318 #endif
321 return 0;