-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsourcecode.tex
More file actions
616 lines (464 loc) · 18.4 KB
/
sourcecode.tex
File metadata and controls
616 lines (464 loc) · 18.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
% Created 2022-07-28 Thu 13:44
% Intended LaTeX compiler: pdflatex
\documentclass[11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{graphicx}
\usepackage{longtable}
\usepackage{wrapfig}
\usepackage{rotating}
\usepackage[normalem]{ulem}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{capt-of}
\usepackage{hyperref}
\date{}
\title{}
\hypersetup{
pdfauthor={},
pdftitle={},
pdfkeywords={},
pdfsubject={},
pdfcreator={Emacs 26.3 (Org mode 9.5.4)},
pdflang={English}}
\begin{document}
\tableofcontents
\section{introduction}
\label{sec:org30fbc15}
\section{Basic idea}
\label{sec:orge5f1cb4}
A dungeon crawler set in a modern day office space (with cubicles, cantinas etc.) instead of fighting I need another way of handling engagement.
\section{Actor\hfill{}\textsc{Actor}}
\label{sec:org0c34810}
An actor is anything that is supposed to have sentience and behaviour ingame.
\subsection{"Races"\hfill{}\textsc{Races}}
\label{sec:org79d5564}
\begin{itemize}
\item Zzzombie - the constantly sleepy coworker, never seems to be quite awake nor have they had a good nights sleep in their life.
\item Gobbo - The coworker who handles mails, you're not sure if they've ever had a shower, but the greasy strands of hair makes you think not.
\item Creeps -
\item Emotional vampire
\item Ghost
\item Troglodytes
\end{itemize}
\subsection{Classes\hfill{}\textsc{Class}}
\label{sec:orga7c3347}
\begin{itemize}
\item Financial
\item IT Wizard
\item Assistant
\item Intern
\item Secretary
\item Janitor
\item Manager
\item HR
\item Boss
\end{itemize}
\subsection{Stats\hfill{}\textsc{Stats}}
\label{sec:org1df1ee9}
Stats in an RPG is like\ldots{} something\ldots{} really\ldots{} hmm (ed: come back with a zinger here). Usually the stats in a traditional roguelike might be something akin to - Constitution, Strength, Wisdom, Intelligence etc. basically if you've seen a rulebook for a TTRPG you can probably recognize most of these AND THEY WORK! that's why people use them, they really REALLY work. I'm not choosing differently because I think I can do better, but because, well since the game is already set in a modern office environment, there's little reason to not have some weird quirk with the stats again.
\subsubsection{List of stats to consider:}
\label{sec:orgf5d491d}
\begin{itemize}
\item Neuroticism: how panicked and alert a player is about their surrounding.
\item Openness: how open they can allow themself to be.
\item Reasoning: how good they are at logically deducting things, (maybe reasoning and neuroticism can kindda benefit and be a detriment at the same time)
\item Madness: How mad the character is (remember! you don't have to be mad to work here, but it helps!)
\item Agreeableness: How much other characters like you.
\item Laziness: How much (or little :/ ) energy a character has.
\end{itemize}
I Really REALLY wanted to put "Agility" into this stat list, but not agility as it is traditionally used, but more as in the agile method that is usually claimed by every company under the sun that has too much money and not enough sensible managers/CEOs. Though I feel like that'll be an unnescessary dig at alot of people I have tremendous respect for. (though maybe they don't care what a nobody on the internet does or say\ldots{} I dunno :) )
So that's the N.O.R.M.A.L. stat system (you'd think I'd have picked these words carefully\ldots{} and you'd be right) patent pending yadda yadda.
\subsubsection{In game stats}
\label{sec:org3f9fd3b}
Health
\begin{itemize}
\item Phys-Health
\begin{itemize}
\item is made out of Laziness (the lower the laziness the higher the health), Openness
\end{itemize}
\item Mental-Health
\begin{itemize}
\item is made out of Madness, Reasoning.
\end{itemize}
\item Social-Health
\begin{itemize}
\item Agreeableness, Neuroticism
\end{itemize}
\item HR-cana
\begin{itemize}
\item Is defined by Madness, Agreeableness
\end{itemize}
\item
\end{itemize}
\subsection{Spells}
\label{sec:orgaf3bed3}
A magic system wouldn't really work in a contemporary world. There is however something more arcane and mysterious that I can employ which is: HR guidelines.
\subsection{HR Guidelines}
\label{sec:orgd80c8e5}
The HR guidelines should, like all magic systems. Affect stats in some way.
\section{Code}
\label{sec:org674b2d0}
How neat would it be if we could quit here? alas now we have to try and code this :S
Ah well into the fray.
\begin{verbatim}
from __future__ import annotations
from abc import ABC, abstractmethod
import pygame
import pprint
from pygame.locals import *
import numpy
from collections.abc import Callable
from functools import reduce, cache, wraps, partial
import json
from dataclasses import dataclass, field
import operator
import rx
\end{verbatim}
\section{Globals}
\label{sec:org345a086}
Global variables are frowned upon by virtually everyone and their mom, which is fair, I don't like them either, but I don't have a better idea.
Global variables are the following
\begin{itemize}
\item cell size, i.e. how large the cell that fills the screen surface should be. Then I can later just divide the screenwidth or screenheight of the drawing destination surface by the cell size to know how big the are is. (so I don't draw outside the screen/surface), this is also where I'm placing the filenames for fonts which I might need/want to change.
\end{itemize}
\begin{verbatim}
CELLSIZE = 32
FONTFILE = "terminal8x8_gs_ro.png"
\end{verbatim}
\section{Positional handling\hfill{}\textsc{Position}}
\label{sec:org3ff2447}
Positional functions all tackles different aspect of onscreen positioning. Things lige moving, checking collisions. multiplying a vector tuple so that it uses the correct
\subsection{Cell function\hfill{}\textsc{Coordinate}}
\label{sec:orge37d44c}
The cell function handles converting the direction vectors into coordinates that can be used on the screen
\begin{verbatim}
def Cell(cell : (int, int)) -> (int, int):
return tuple(map(lambda n : n * CELLSIZE, cell))
\end{verbatim}
\subsection{Collision\hfill{}\textsc{Collision}}
\label{sec:orga35f0f7}
The collision function gets two position tuples and checks if they are the same, if they are it returns true if not it returns false
\begin{verbatim}
def collision(xy, _xy):
return xy == _xy
\end{verbatim}
\subsection{Move\hfill{}\textsc{Update}}
\label{sec:orge98f3f6}
Move function is just meant to take tqwo positional arguments, the current position and the destination, and return a new tuple with the new current position. I believe It \textbf{could} theoretically maybe, potentially handle diagonal movement - ish but this is just you grandmas 4 directional moves.
\begin{verbatim}
def move(xy : (int,int), _xy : (int, int)) -> (int, int):
acc = []
for n, _n in zip(xy, _xy):
if n > _n:
n = n - 2
elif n < _n:
n = n + 2
acc.append(n)
return tuple(acc)
\end{verbatim}
\subsection{Vector\hfill{}\textsc{Datacontainer::Coordinate}}
\label{sec:org2cfcb61}
The vector class is basically a copy of a tuple datatype, however it has the added "\uline{\uline{add}}" and "\uline{\uline{sub}}" methods defined. I don't really need (at the moment) to handle more "advanced" features like vector dot product and so on.
\begin{verbatim}
@dataclass(frozen=True)
class Vector:
x : int
y : int
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
\end{verbatim}
\section{Input\hfill{}\textsc{IO}}
\label{sec:orgd7be312}
\subsection{Input player movement}
\label{sec:org6d977e0}
for now I just handle the input through a simple function that checks whether or not a valid key has been pressed. if not it returns a (0,0) vector.
\begin{verbatim}
def getInput(ev):
inputList = { pygame.K_UP : (0,-1),
pygame.K_DOWN : (0,1),
pygame.K_LEFT : (-1, 0),
pygame.K_RIGHT : (1, 0),
}
return inputList.get(ev.key, (0,0))
\end{verbatim}
\subsection{Ressource handler\hfill{}\textsc{File}}
\label{sec:org9dede2f}
Another euqually import (or more important input) is the different ressources. For now it is only a config json file and a tilesheet, I'm interested in, but it could expand to more tilesheets, or even premade levels (or templates). The ressources are being loaded into a file class that holds the different information.
\begin{verbatim}
def loadFiles() -> ConfigFile:
_fontImage = pygame.image.load("terminal8x8_gs_ro.png")
_fontImage.set_colorkey((0,0,0))
with open('conf.json', 'r') as _file:
config = json.load(_file)
return ConfigFile(_fontImage, config)
\end{verbatim}
\subsubsection{File class\hfill{}\textsc{datacontainer}}
\label{sec:orgbd547a6}
The file class is an immutable data container that holds the information needed for the game to function
\begin{verbatim}
@dataclass(frozen=True)
class ConfigFile:
_image : pygame.Surface
_conf : dict
def image(self) -> pygame.Surface:
return self._image
def config(self) -> dict:
return self._conf
\end{verbatim}
\subsubsection{Tilesheet class\hfill{}\textsc{datacontainer}}
\label{sec:org8f74aac}
\begin{verbatim}
@dataclass(frozen=True)
class TileSheet:
_tiles = [pygame.Surface]
def __init__(self,
file : pygame.Surface,
width : int,
height : int,
rows : int,
columns : int):
for x in range(rows):
for y in range(columns):
self._tiles.append(
pygame.transform.scale(
file.subsurface(y * width, x * height, width, height),
(CELLSIZE, CELLSIZE)
)
)
\end{verbatim}
\section{Time}
\label{sec:org801fb4e}
\begin{center}
time where did you go?\ldots{}. aaaand that's all I had time for
\end{center}
In the game there's going to be two kinds of time. Firstly a realtime module that just makes sure we don't call the draw function more than 60 times a second (at most) because let's be honest\ldots{} it's a text based engine so it's kindda dumb to blow up the GPU for \textbf{that}
But the second kind of time is the ingame time. That's based on turns. Every turn everything that can (and should) move, moves.
\subsection{Turn\hfill{}\textsc{datacontainer}}
\label{sec:orgfc4f286}
The turn class is a data container class (get used to be seeing those around btw. ) that takes care of storing whatever information a turn need.
\begin{verbatim}
@dataclass(frozen=Turn)
class Turn:
turn : int
\end{verbatim}
\section{Window handler}
\label{sec:org48075b0}
The window class is where the initializing is going to happen, as well as where the pygame window.
\begin{verbatim}
class Window():
_size = (int, int)
_surface = pygame.Surface
def __init__(self, width, height) -> None:
self._surface = pygame.display.set_mode((width, height), 0, 32)
def surface(self) -> pygame.Surface:
return self._surface
\end{verbatim}
\section{View MIGHT BE REMOVED}
\label{sec:org451206e}
The view holds a surface and a pygame.Rect. The rect is moved around to "slice" a subsurface from the map.
\begin{verbatim}
class View:
_camera : pygame.Rect
_trackingObject = None
def __init__(self,
topx : int,
topy : int,
cameraWidth : int,
cameraHeight : int,
trackingObject = None):
self._camera = pygame.Rect(topx, topy, topx+cameraWidth, topycameraHeight)
if trackingObject is not None:
self._trackingObject = trackingObject
def slice(self, surface : pygame.Surface):
return surface.Subsurface(self._camera)
def trackObject(self, surface : pygame.Surface):
pass
def checkCenterObject(self):
pass
def update(self) -> pygame.Surface:
pass
\end{verbatim}
The view function takes the relevant actor and centers the map on it.
\begin{verbatim}
def View(actor : Actor,
surface : pygame.Surface,
view : pygame.Rect) -> pygame.Surface:
_view = view
_view.center = actor.currxy()
return surface.subsurface(_view)
\end{verbatim}
\section{Drawing\hfill{}\textsc{Onscreen}}
\label{sec:org77386a0}
\subsection{Drawmap\hfill{}\textsc{Map}}
\label{sec:org8b48d21}
Drawmap function is only called to draw the surface of the static map.
\begin{verbatim}
def drawMap(map : str,
pos : [(int, int)],
tiles : [pygame.Surface],
destination :pygame.Surface):
_drawingList : [(pygame.Surface,(int,int))] = []
x = 0
y = 0
for ind, c in enumerate(map):
_drawingList.append((tiles[ord(c)+1], pos[ind]))
destination.blits(_drawingList)
\end{verbatim}
\subsection{Drawing\hfill{}\textsc{Characters}}
\label{sec:org181906c}
The drawing function takes one or more characters and draws them to the screen.
\begin{verbatim}
def drawing(chars : str,
pos : [(int, int)],
tiles : [pygame.Surface],
destination :pygame.Surface):
_drawingList : [(pygame.Surface,(int,int))] = []
x = 0
y = 0
for ind, c in enumerate(chars):
_drawingList.append((tiles[ord(c)+1], pos[ind]))
destination.blits(_drawingList)
\end{verbatim}
\section{Map\hfill{}\textsc{Map}}
\label{sec:orga47f204}
the map is for now just a container class for a premade "dungeon", this is to test whether or not the drawing function can handle the sheer drawing calls. AND that it can handle the various characters.
It's supposed to just have a giant, static (more or less static) image of the map.
\begin{verbatim}
class Map:
_str : str
_pos : [(int,int)] = []
_map : pygame.Surface
def __init__(self, tiles):
# TEMP map
self._str = ""
tempMap = [ "################################",
"# # # #",
"# # # #",
"# # # #",
"# # # #",
"# #",
"# #",
"# y #",
"# Hello #",
"# p #",
"# #",
"# #",
"# #",
"# #",
"# #",
"################################"
]
w = len(tempMap[0]) * CELLSIZE
h = len(tempMap) * CELLSIZE
self._map = pygame.Surface((w, h))
for i, s in enumerate(tempMap):
self._str = self._str + s
for string_i, _ in enumerate(s):
self._pos.append((string_i*CELLSIZE, i*CELLSIZE))
drawMap(self._str, self._pos, tiles, self._map)
def map(self):
return self._map
\end{verbatim}
\section{Actor list\hfill{}\textsc{Actor}}
\label{sec:org5ef3cf5}
The actor list is where a list of actors are being created.
\begin{verbatim}
def makeActors(amount : int, playerIndex : int) -> [Player]:
pass
\end{verbatim}
\section{Game Loop function}
\label{sec:org53aee92}
The Game loop is where the structure of the game is at.
\begin{verbatim}
def GameLoop(window, _map, tiles):
running = True
player = Actor('@',(32,32), (32,32))
currVec = player.currxy()
nxtVec = player.nxtxy()
log = []
cl = pygame.time.Clock()
while(running):
movVec = (0,0)
for event in pygame.event.get():
match event.type:
case pygame.QUIT:
running = False
case pygame.KEYDOWN:
movVec = getInput(event)
if player.arrived():
nxtVec = tuple(map(lambda n, _n: n + ( _n * CELLSIZE), nxtVec, movVec))
currVec = move(player.currxy(), nxtVec)
player = Actor( '@',currVec, nxtVec)
window.surface().blit(_map.map(), (0,0))
drawing(str(player), [player.currxy()], tiles._tiles, window.surface())
pygame.display.flip()
log.append("current vector : " + str(currVec) + "nxtVector : " + str(nxtVec) + "has player arrived: " + str(player.arrived()))
cl.tick_busy_loop(60)
pprint.pprint(_map.map())
\end{verbatim}
\section{{\bfseries\sffamily TODO} Text\hfill{}\textsc{Text}}
\label{sec:orge1c0444}
\subsection{{\bfseries\sffamily TODO} Textprinting\hfill{}\textsc{Onscreen}}
\label{sec:org428af1a}
\subsection{{\bfseries\sffamily TODO} Textformatting}
\label{sec:orgb04070c}
\subsection{{\bfseries\sffamily TODO} Textinput}
\label{sec:org26f1ada}
\section{Actor\hfill{}\textsc{Actor}}
\label{sec:org007a2f5}
The player class is, for now just a place holder, keeping the player char (literally a char value), position and that's it. It does also use a couple of standard operators that I've overloaded to return just a string.
\subsection{Actor class\hfill{}\textsc{Datacontainer}}
\label{sec:org54f1a8e}
\begin{verbatim}
@dataclass(frozen=True)
class Actor:
_c : chr = field(init=True)
xy : (int, int) = field(init=True)
_xy : (int, int) = field(init=True)
def arrived(self) -> bool:
return self.xy == self._xy
def currxy(self):
return self.xy
def nxtxy(self):
return self._xy
def __repr__(self):
return self._c
\end{verbatim}
\subsection{Update Actors}
\label{sec:org5fb9c53}
The update actor function is going to map onto the list of actors in the game.
\begin{verbatim}
def updateActor(lstOfActors : [Actor]) -> [Actor]:
# retLst = []
# #check collision
# lstCollision
# for nxt in lstOfActors:
# lstCollision.append(nxt.
# for actor in lstOfActors:
# currVec = move(actor.currxy(), actor.nxtxy())
pass
\end{verbatim}
\section{Main}
\label{sec:orgb23b180}
In the main function I initialize the different components, like the window, the gameloop function, etc.
\begin{verbatim}
def main():
pygame.init()
pygame.font.init()
# -------
_files = loadFiles()
_tiles = TileSheet(_files.image(), 8, 8, 16, 16)
window = Window(800, 600)
map = Map(_tiles._tiles)
GameLoop(window, map, _tiles)
# -------
pygame.quit()
\end{verbatim}
\begin{verbatim}
if __name__=="__main__":
main()
\end{verbatim}
\end{document}