Lately I’ve been in the mood for non-digital pen drawings. The problem I have with those drawings is that there is no ‘undo’. For lettering that’s not a big deal. I think the ‘post-production’ digital lettering has a charm of its own.
But shading or colouring is more problematic. I like the quick sloppy strokes I do by hand but they’re hardly ever good in one take (technically they’re never good, but I don’t go for technically good). And messing up means doing it all over again.
I could make copies, but that’s a hassle too.
Two days ago I came up with another idea: I had a plastic wrapping lying about and I have some whiteboard markers. I can wrap the plastic around the drawing and colour with the markers on the plastic. It turns out that works very well!
Colouring gives a sort of watercolour effect, which I like and wiping works great. At the moment I only have a few standard harsh colours, but I’m planning to buy more (especially greys).
Here are some pictures ‘ behind the scenes’ :
This part I’ll be writing about ripping the music from the game (‘hacking, ‘cracking’, ‘ripping’ the vocabulary of the scene sounds a bit like a pro-wrestling pre-match-rant, doesn’t it?).
One of the reasons the C64 was so popular, was because of the great soundchip and the music that was produced for it. Hackers ripped the music so it could be played on it’s own or as part of a demo. By adding some metadata, the C64 standalone music program can even be converted to a SID file (named after the C64 sound chip) and played by programs developed for modern PC’s.
Ripping music means: extracting the code that plays the music and the accompanying music data and putting it in a single package, so it can be played by itself, without the game.
As it is a game from 1985, the music has been ripped already a long time ago by others. You can find it as part of the High Voltage Sid collection (you can do a search for ‘willow pattern’ on their site).
I use a lot of text to explain stuff. To accompany the stream of words I offer a link to the files that are the result of this ‘session’:
Files included are the assembly code (kickassembler format), the resulting basic-executable program and the music data as binary that is used in the code. Also a resulting SID file is made.
It’s only a few months ago I ripped the music, so I could use some modern tools. The tools I’ve used for this are Vice, an IDE with Assembler a Hex Editor (I’m using HxD editor) and a tool I made myself in Excel.
Finding the beginning of the thread
Most music routines on a C64 have the same basic idea. At regular intervals a counter is decreased . When the counter reaches zero a new musical’event like ‘play a note’ is read and the counter gets the value for the time till the next musical event. There can be all kinds of other things going on, but this is the general method.
The best way to get a regular interval in C64 assembly is by using a Interrupt.
Interrupts are ways of the ‘outside world’ (outside for the CPU that is, so a signal from another chip for instance) to interrupt the regular flow of an executing program. The CPU has a special bit on its status register to deal with interrupts.
A simplified way to describe the working of the CPU of a C64:
- read a instruction from memory and execute it
- alter the current memory position based on that instruction
- read the next instruction from that address
But before each instruction-read the CPU checks if the interrupt bit in the CPU’s status register is set. If so, the normal flow is suspended and the CPU starts executing from the address that is coded in a certain part of memory (the interrupt pointer).
A commonly used type of Interrupt for the C64 has its pointer in address $0314/$0315. Scanning memory for the two following bytes $14 and $03 (the C64 is ‘little endian)’ can give you locations where that memory is used or set.
Or you can see what the current values are of that pointer. In Willow Pattern Adventure (WPA) it points to location $0E00.
Where does it lead to, what does it do?
Interrupts can be used for several types of functionality. Music is one, updating graphics or scanning the keyboard another. WPA has a pretty simple interrupt: it is only used for the music.
If I import all 64k of memory to my Excel program I can trace what parts of memory are used by giving it the start address ($0E00). It will trace the code, take all jumps and all subroutines. Every address tracked will be designated as code, the rest of memory as data.
That way you’ll end up with a very comprehensive view of the code, every byte that has nothing to do with the music is not disassembled but rendered as bytes.
Here’s the beginning of the code, remember this will be called about every 50th of a second (one tick) on a PAL system.
JSR L0F66 ; this subroutine is called every tick: it slightly changes the frequency of the notes played: vibrato DEC L0ED5 ; this is the counter I mentioned before BEQ L0E0B ; if the counter reaches zero goto L0E0B, the main music player routine, to get a new note JMP $EA31 ; return to the standard normal C64 Kernal Interrupt routine which does things like checking the keyboard L0E0B LDA #0C ; set the counter to a standard value. Unusual: the same amount of time between all events! STA L0ED5 ; it is used so you can have the same piece of music in different speeds by changing this value LDA $FA ; [.....]
I now have the routine that plays the music. But I also need the routine that does the initial sound setup. It is likely to be the same part where the interrupt pointer is set.
Using the Vice Monitor I find a few promising parts of memory:
The second address is where the pointer is set to $EA31 which is the standard C64 Interrupt address. I can ignore that. The first address is where the interrupt is set to $0E00 and looks like a small subroutine where some sound things are set and the interrupt pointer.
Now I need to know where the music data is stored.
I can see in the code that indirect addressing is used for reading from memory:
L0E3A LDA(FA),Y ; an address between parenthesis means A is not read from $FA but the address referenced in $FA/$FB with Y value addded to it BEQ L0E57 ; if the note value is zero, no new note is played, a pretty wasteful method, specially because it still uses two bytes STA L0ECF ; the note is also stored for vibrato purposes STA $D400 ; store note value in low frequency register of Voice 1 of the SID-Chip
You could look up the current value in memory but it could change to all values.
I use a plugin for Vice, ICU64. It can show what parts of memory are updated in real time. This is a graphic representation of the memory. Bytes that are read or written to, light up and fade out.
The opening screen is a static screen, so probably all that changes is the music. I guess the green parts are the music data. It moves at a constant speed which is what you would expect from the music routine: I saw in the code it reads notes at a constant interval of n-ticks.
You can zoom in on the green dots and read the actual addresses.
The in-game music is different, so probably occupies a different part of memory, but you can use the same method for that. Just start the game and watch the memory.
Now I have all parts for making a standalone musicplayer. I save the memory containing the music as binary data and export the code as a text file. My Excel program can automatically create labels for addresses used in my code so I can easily relocate the code.
Putting it together
- I import the code in my IDE Relaunch64
- change the assembly to KickAssembler format, which I now use
- import the music data binary
- add a basic loader
- create some code that calls the setup routine.
The result is a single file program that can be started from basic and plays the music. But I would like to hear the intro and in-game music, so I add some code that if you run the setup again, the other music starts to play.
The beginning of the code now looks like this:
.pc = $0801 //start of the memory for a basic program .var music1_speed=$0e//$10 //some variables .var music2_speed=$0a//$0c :BasicUpstart($0810) // a way to easily add a basic program that runs machine code from address in parenthesis .pc = $0810 ldx #$00 lda l0f4e //if this address is two, change to zero cmp #$02 beq !+ ldx #$02 //otherwise set to two !: stx l0f4e //this address controls which music is played jsr r0edb // call music setup rts //return from subroutine, back to basic
This all works and can easily be incorporated into another program like an intro.
I know cracking a game is not so special anymore and I’m not too sure if my home-made SID tunes will impress anyone. Also the Willow Pattern tune uses very few computer cycles, which might be useful if I use it in my intro.
But using the same music for the intro and the game sounds a bit lame.
What can I do to make it just a bit special?
I’ll just reverse the music! Really, I have no idea why I came up with that but at least it probably has not been done before.
I have to make a few adjustments to the code:
- The startaddress of the tunes must now point to the end of the tunes
- The pointer must now count backwards
- The routine uses a byte of ’01’ as a sign the end of the music is reached, The ’01’ must come at the beginning.
This all worked pretty well. But to give it that ‘real backwards feeling’ I also have to reverse the way the notes sound.
Sound is synthesized on a C64 using the ADSR Attack Decay Sustain Release technique.
A certain note increases to maximum volume during an Attack phase, drops to a Sustain level in the Decay phase and when triggered will drop to volume 0 in the Release phase. Those four values can be set for each note.
The original tune has a pretty ‘staccato’ sound, caused by an attack time of 0. Almost immediately the note goes to maximum volume.
To create a ‘backwards’ effect you can make a note slowly ‘swell’ to maximum volume.
It does have the disadvantage that notes take longer to be heard. In the backwards tune some notes disappear. But since it doesn’t really resemble the original tune anymore that doesn’t matter much.
Well, that’s almost it for now. As a finalcz touch I would like to convert the tune to .SID format so it could be played with a SID player on a modern PC. Not that the reversed tune sounds that great, but I never made a SID before.
The changes in the code are easy: you have to have an initialization routine that is called with the song number in the A register.
This will do:
[... I removed the basic loader, that will not be used ...] .pc = $1000 / I relocate it to address $1000, not strictly neccesary. asl //a*2, multiply the A register by two because the original routine uses 0 and 2 as song numbers sta l0f4e // store that value in the memory that is already used in the original code for song number jsr r0edb // call the already existing initialization rts //... done!
Now I have to add some meta data to the file. On hvsc.com there is a good description of the file format, so with a Hex editor and that description the file is changed in a jiffy.
I’ve added the resulting SID file to the dropbox folder that is linked in the beginning of this post (so long ago!)
Not sure what I’ll be focussing on next time. I think I will be writing about trainer functionality.
So here’s some background about the project:
First of all: The Commodore 64: it was the computer I grew up with. I loved it. It was quite popular and there were thousands of games. There is an EMORMOUS amount of information about this computer so I won’t go into that here.
You also had hackers, people (often very young), that managed to circumvent the copy protection (‘cracking’) and distributed the cracked games.
The hacker scene was very competitive and they were always trying to be the first to
crack a game or impress by putting a nice intro or trainer-function in the game (they even hacked a game of mine!). In the beginning the intros were simple but the competetiveness brought out the best in the young crackers and after a while you could have intros that had better graphics, sound and programming than the game itself.
Cracking was (and is) illegal and so there was always a air of mystery surrounding hackers. For me hackers were cool!
I wanted to be one, but didn’t know where to start, didn’t know anyone in the scene , I didn’t even know anyone who had a C64 (my brother had the contacts).
Baby steps in the kiddy pool
Logically I didn’t know much about the tools of the ‘trade’, but we had an expansion you could fit into a slot for the C64: the Power cartridge.
It had all kinds of cool things, like build-in speedloaders, BASIC expansion, a machine code monitor and a way of saving the complete state of the computer to disk.
Those last two options were what made it possible for me to crack a game:
At one point my brother borrowed an original game for copying purposes. It had some copy protection, but with the cartridge you could load the game and then save the state of the computer. Loading that state meant you could always resume from that point. Such a state could not be distributed as a crack, because you needed that same cartridge to load such a state.
But if you opened the machine code monitor you could save parts of memory like regular files and try to find a start address. Then you could load those files, call the starting address (‘SYS’ to start a piece of machine code from BASIC) and maybe if you had all relevant pieces of memory loaded the game would run.
The game in question was not very well protected: you could see the BASIC SYS command in memory and calling that after a reset would run the game. So the challenge was to find the relevant pieces of memory.
To combine those pieces to one part and adding an intro and a music was a big ask for me. With the help of my brother we made some kind of multi-piece loader. It used a weird feature of Commodore BASIC where if you loaded a piece of memory from a running BASIC program, the BASIC program would start from the beginning after loading but with all values of the variables intact .
Even to the standards of hacks then it was a bad hack. But a good starting point for this project!
The game I talk about is The Willow Pattern Adventure A week ago I bought an original of this game. Seemed only reasonable to know what I talk about, and try to repeat the hack I did 30 years ago. You can see a screenshot of the packaging here.
Although I hacked the game, I must admit that I didn’t play it that much at the time. It looked nice and had some OK music, but we had hundreds of games and this game was quite tough! You had no map and the game was also very unforgiving: you could easily make a mistake which made it impossible to finish the game. And it wasn’t some kind of casual game, you had to invest a lot of time even if you played flawless.
But worst of all were the Giants. You had to jump from stone to stone while giants would try to grab you. And being hit or falling not only meant losing a life, it could also mean losing a sword, which could make the game unfinishable:
Jump jump jump jump, phew!, kill a samurai (5), oh no another samurai! now I must go back to get another sword, jump jump jump jump, try to get a sword, die, try again, pick up the sword, jump jump jump DIE LOSE SWORD END OF GAME!.
It didn’t take much of this for me to give up and try something else.
It’s almost the end of the second part. Still not much code, but the next parts will be better (or worse for non-coders).
I will leave with a nice little cheat I discovered during this project. It helps to avoid the grabbing hands of the Giants. Just follow these steps (4):
- Load game, start game
- Reset the computer (without turning it off!).
- from BASIC type : POKE 3123,24
- then type SYS 2096, voilá!
What is does is change this piece of code
1 2 3
L0C30 LDA LD01E ; Sprite to Sprite Collision Detect MOS 6566 VIDEO INTERFACE CONTROLLER (VIC) LSR ; BCS L0C37 ;
1 2 3
L0C30 LDA LD01E ; Sprite to Sprite Collision Detect MOS 6566 VIDEO INTERFACE CONTROLLER (VIC) CLC ; BCS L0C37 ;
What the code does is read some memory, $D01E where the video chip registers if a sprite hits another sprite. If that sprite is hit, the corresponding bit (in this case the first) is set to one.
LSR, shifts that first bit into the Carry bit of the CPU’s status register. The next instruction BCS is a conditional jump if the carry-bit is set (in this case if a collision has occured).
By changing LSR to CLC, you don’t shift the first bit, but instead always clear the carry bit (which is what CLC does), so the jump is never taken: a hit is now never registered.
(1) quote from the book ‘Only you can save mankind’ by Terry Pratchett. And pretty accurate: those screenshots always were from a version for a more advanced computer.
(2) pimped commodore taken from http://www.remix64.com/board/viewtopic.php?t=4619
(3) picture by Grass
(4) If you’re playing on an emulator you can change memory without resetting. In VICE open monitor with ALT-M, then type ‘> 0C33 18’ then leave the monitor with ‘x’.
(5) Yes, it was a game set in China that had Samurai.
Thirty years ago I cracked a game. This is a first post of a series about trying to improve on that piece of (in this case relatively harmless) criminal activity.
Not sure if it will interest anyone or if anyone except bots is reading this blog, but I’ll just pretend there is an interested audience and start (‘oh yes, please do!)’.
About two years ago I posted some pictures I made on the Commodore 64 in the 80’s. In the caption of one picture I mentioned that I made that picture for a game I hacked.
At that time there were people reading my blog, because I got a reaction from an admin of the Commodore64 Scene Database, a site dedicated to preserving everything the so-called commodore-scene made.
He wanted to put my pictures and the crack I mentioned on their site. I agreed for the pictures, but it seemed that time had corrupted the disk of the crack and I refrained from posting the crack.
After a while I took another look at the crack and noticed that the corrupted data was just a small patch of about 32 bytes that were supposed to be the value of 255 in stead of 0. I corrected the file and now the crack was like it used to be.
But I still didn’t post it on CSDB, because I was a bit apprehensive about it. The level of programming in the scene was pretty high in the 80’s and the standards has only got higher since then.
The crack by me was crudely done and together with my brother we made some multi-part mess, part basic, part assembly, with a naive (unintentionally) racist picture and music stolen from a demo (which just spells ‘LOSER’ in big capital letters, hack something that has already been hacked).
But in the back of my mind I had the idea, that if I could make a different version I could upload it with the original crack as a sort of then-and-now-package.
But the newer version would have meet the following criteria:
- all parts contained in one file
- have some original intro
- have some trainer options
- have original music
A few weeks ago I decided I that a piece of programming I worked on would work as an original-enough intro to the game. So finally I have accepted my own challenge:
I shall recreate this hack to the level I find acceptable to post on CSDB!
(insert lightning flash and rolling thunder)
To be honest: I had already met most criteria when I decided to blog about it, but it is not entirely finished and already I’ve come up with some stretch goals.
In the next part I shall write some more about the background. But the series will be code centered and I don’t want to end this post without code.
Here is the code of the music routine I ripped from the game (it’s auto-labelled and auto-commented by a disassembler I made and I omitted some data ):
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
JSR L0F66 ; DEC L0ED5 ; BEQ L0E0B ; JMP $EA31 ; L0E0B LDA #0C ; STA L0ED5 ; LDA $FA ; STA L0ED6 ; LDA $FB ; STA L0ED7 ; L0E1A LDA L0ECD ; STA $FA ; LDA L0ECE ; STA $FB ; LDY #00 ; LDA(FA),Y ; CMP #01 ; BNE L0E3A ; LDA L0ED8 ; STA L0ECD ; LDA L0ED9 ; STA L0ECE ; BNE L0E1A ; L0E3A LDA(FA),Y ; BEQ L0E57 ; STA L0ECF ; STA $D400 ; Voice 1: Frequency Control - Low-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) INY ; LDA(FA),Y ; STA L0ED0 ; STA $D401 ; Voice 1: Frequency Control - High-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA #40 ; STA $D404 ; Voice 1: Control Register 7 Select Random Noise Waveform, 1 = On 6 Select Pulse Waveform, 1 = On 5 Select Sawtooth Waveform, 1 = On 4 Select Triangle Waveform, 1 = On 3 Test Bit: 1 = Disable Oscillator 1 2 Ring Modulate Osc. 1 with Osc. 3 Output, 1 = On 1 Synchronize Osc. 1 with Osc. 3 Frequency, 1 = On 0 Gate Bit: 1 = Start Att/Dec/Sus, 0 = Start Release MOS 6581 SOUND INTERFACE DEVICE (SID) LDA #41 ; STA $D404 ; Voice 1: Control Register 7 Select Random Noise Waveform, 1 = On 6 Select Pulse Waveform, 1 = On 5 Select Sawtooth Waveform, 1 = On 4 Select Triangle Waveform, 1 = On 3 Test Bit: 1 = Disable Oscillator 1 2 Ring Modulate Osc. 1 with Osc. 3 Output, 1 = On 1 Synchronize Osc. 1 with Osc. 3 Frequency, 1 = On 0 Gate Bit: 1 = Start Att/Dec/Sus, 0 = Start Release MOS 6581 SOUND INTERFACE DEVICE (SID) L0E57 LDY #00 ; CLC L ; LDA $FA ; ADC #02 ; STA $FA ; LDA $FB ; ADC #00 ; STA $FB ; LDA(FA),Y ; BEQ L0E83 ; STA L0ED1 ; STA $D407 ; Voice 2: Frequency Control - Low-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) INY ; LDA(FA),Y ; STA L0ED2 ; STA $D408 ; Voice 2: Frequency Control - High-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA #40 ; STA $D40B ; Voice 2: Control Register 7 Select Random Noise Waveform, 1 = On 6 Select Pulse Waveform, 1 = On 5 Select Sawtooth Waveform, 1 = On 4 Select Triangle Waveform, 1 = On 3 Test Bit: 1 = Disable Oscillator 1 2 Ring Modulate Osc. 2 with Osc. 1 Output, 1 = On 1 Synchronize Osc. 2 with Osc. 1 Frequency, 1 = On 0 Gate Bit: 1 = Start Att/Dec/Sus, 0 = Start Release MOS 6581 SOUND INTERFACE DEVICE (SID) LDA #41 ; STA $D40B ; Voice 2: Control Register 7 Select Random Noise Waveform, 1 = On 6 Select Pulse Waveform, 1 = On 5 Select Sawtooth Waveform, 1 = On 4 Select Triangle Waveform, 1 = On 3 Test Bit: 1 = Disable Oscillator 1 2 Ring Modulate Osc. 2 with Osc. 1 Output, 1 = On 1 Synchronize Osc. 2 with Osc. 1 Frequency, 1 = On 0 Gate Bit: 1 = Start Att/Dec/Sus, 0 = Start Release MOS 6581 SOUND INTERFACE DEVICE (SID) L0E83 LDY #00 ; CLC L ; LDA $FA ; ADC #02 ; STA $FA ; LDA $FB ; ADC #00 ; STA $FB ; LDA(FA),Y ; BEQ L0EAF ; STA L0ED3 ; STA $D40E ; Voice 3: Frequency Control - Low-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) INY ; LDA(FA),Y ; STA L0ED4 ; STA $D40F ; Voice 3: Frequency Control - High-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA #40 ; STA $D412 ; Voice 3: Control Register 7 Select Random Noise Waveform, 1 = On 6 Select Pulse Waveform, 1 = On 5 Select Sawtooth Waveform, 1 = On 4 Select Triangle Waveform, 1 = On 3 Test Bit: 1 = Disable Oscillator 1 2 Ring Modulate Osc. 2 with Osc. 1 Output, 1 = On 1 Synchronize Osc. 2 with Osc. 1 Frequency, 1 = On 0 Gate Bit: 1 = Start Att/Dec/Sus, 0 = Start Release MOS 6581 SOUND INTERFACE DEVICE (SID) LDA #41 ; STA $D412 ; Voice 3: Control Register 7 Select Random Noise Waveform, 1 = On 6 Select Pulse Waveform, 1 = On 5 Select Sawtooth Waveform, 1 = On 4 Select Triangle Waveform, 1 = On 3 Test Bit: 1 = Disable Oscillator 1 2 Ring Modulate Osc. 2 with Osc. 1 Output, 1 = On 1 Synchronize Osc. 2 with Osc. 1 Frequency, 1 = On 0 Gate Bit: 1 = Start Att/Dec/Sus, 0 = Start Release MOS 6581 SOUND INTERFACE DEVICE (SID) L0EAF LDA L0ECD ; CLC L ; ADC #06 ; STA L0ECD ; LDA L0ECE ; ADC #00 ; STA L0ECE ; LDA L0ED6 ; STA $FA ; LDA L0ED7 ; STA $FB ; JMP $EA31 ; L0F66 CLC L ; LDA L0ECF ; ADC L0FC7 ; STA $D400 ; Voice 1: Frequency Control - Low-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA L0ED0 ; ADC #00 ; STA $D401 ; Voice 1: Frequency Control - High-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) CLC ; LDA L0ED1 ; ADC L0FC7 ; STA $D407 ; Voice 2: Frequency Control - Low-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA L0ED2 ; ADC #00 ; STA $D408 ; Voice 2: Frequency Control - High-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) CLC ; LDA L0ED3 ; ADC L0FC7 ; STA $D40E ; Voice 3: Frequency Control - Low-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA L0ED4 ; ADC #00 ; STA $D40F ; Voice 3: Frequency Control - High-Byte MOS 6581 SOUND INTERFACE DEVICE (SID) LDA L0FC8 ; BPL L0FB4 ; LDA L0FC7 ; SEC ; SBC #10 ; STA L0FC7 ; CMP #00 ; BNE L0FB3 ; LDA #00 ; STA L0FC8 ; L0FB3 RTS ; L0FB4 LDA L0FC7 ; CLC L ; ADC #10 ; STA L0FC7 ; CMP #40 ; BNE L0FC6 ; LDA #80 ; STA L0FC8 ; L0FC6 RTS ; .BYTE #$20, #$80, #$00, #$00, #$00, #$00, #$00, #$00 ; .BYTE #$00, #$00, #$00, #$00, #$00, #$00, #$00, #$00 ; .BYTE #$00, #$00, #$00, #$00, #$00, #$00, #$00, #$00 ; .BYTE #$00, #$00, #$00, #$00, #$00, #$00, #$00, #$00 ; .BYTE #$00, #$00, #$00, #$00, #$00, #$00, #$00, #$00 ; .BYTE #$00, #$00, #$00, #$00, #$00, #$00, #$00, #$00 ; .BYTE #$00, #$00, #$00, #$00, #$00, #$00, #$00, #$00 ;
I really wanted to do something different this time. This is the result.
Not really a surprise, I’m a bit preoccupied with retro games lately.
The picture uses 3-pixel wide lettering, which is bit tricky to do (and read maybe).
My signature is even done in 2-pixel wide lettering. There are cases when you need that! Maybe I’ll provide an example of that in the near future.
So here a post with some more simple animations I made many years ago, probably with corel painter.
of the last one I also made an avi animation where I added some audio
it’s fun to see how much difference a little sound makes
The tool I used for adding the sound, also added a Platypus icon to the animation.
It was someone’s birthday today and I thought I would quickly put a drawing on his timeline. I came up with two ideas and the one he didn’t get was this one:
I don’t usually don’t to sexually tinted cartoons, because a lot of them aren’t funny, but this is more pun than sexual, I think (not sure about funny).
The one he DID get was maybe even worse (the pun, that is).
Oh , alright you can see that one as well. But it is VERY small:
While looking through my old drawings I also came across this animation I made with Corel Painter, also on the subject of birthdays:
I have some more animations. Maybe I’ll convert them to gif and post them here.
You’ll probably have to reload the page to see the animation, I didn’t make it loop.