mirror of https://github.com/stella-emu/stella.git
Add players.
This commit is contained in:
parent
87b24a5bba
commit
ac4520917e
|
@ -20,7 +20,7 @@
|
|||
#include "Missile.hxx"
|
||||
#include "DrawCounterDecodes.hxx"
|
||||
|
||||
enum Count {
|
||||
enum Count : Int8 {
|
||||
renderCounterOffset = -4
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include "Player.hxx"
|
||||
#include "DrawCounterDecodes.hxx"
|
||||
|
||||
enum Count : Int8 {
|
||||
renderCounterOffset = -5
|
||||
};
|
||||
|
||||
namespace TIA6502tsCore {
|
||||
|
||||
Player::Player(uInt32 collisionMask)
|
||||
: myCollisionMask(collisionMask)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void Player::reset()
|
||||
{
|
||||
myDecodes = DrawCounterDecodes::get().playerDecodes()[0];
|
||||
myHmmClocks = 0;
|
||||
myCounter = 0;
|
||||
myIsMoving = false;
|
||||
myWidth = 1;
|
||||
myIsRendering = false;
|
||||
myRenderCounter = 0;
|
||||
myPatternOld = 0;
|
||||
myPatternNew = 0;
|
||||
myPattern = 0;
|
||||
myIsReflected = 0;
|
||||
myIsDelaying = false;
|
||||
}
|
||||
|
||||
void Player::grp(uInt8 pattern)
|
||||
{
|
||||
myPatternNew = pattern;
|
||||
|
||||
if (!myIsDelaying) updatePattern();
|
||||
}
|
||||
|
||||
void Player::hmp(uInt8 value)
|
||||
{
|
||||
myHmmClocks = (value >> 4) ^ 0x8;
|
||||
}
|
||||
|
||||
void Player::nusiz(uInt8 value)
|
||||
{
|
||||
const uInt8 masked = value & 0x07;
|
||||
const uInt8 oldWidth = myWidth;
|
||||
|
||||
if (masked == 5) {
|
||||
myWidth = 16;
|
||||
} else if (masked == 7) {
|
||||
myWidth = 32;
|
||||
} else {
|
||||
myWidth = 8;
|
||||
}
|
||||
|
||||
myDecodes = DrawCounterDecodes::get().playerDecodes()[masked];
|
||||
|
||||
if (myIsRendering && myRenderCounter >= myWidth)
|
||||
myIsRendering = false;
|
||||
|
||||
if (oldWidth != myWidth) updatePattern();
|
||||
}
|
||||
|
||||
void Player::resp(bool hblank)
|
||||
{
|
||||
myCounter = hblank ? 159 : 157;
|
||||
}
|
||||
|
||||
void Player::refp(uInt8 value)
|
||||
{
|
||||
const bool oldIsReflected = myIsReflected;
|
||||
|
||||
myIsReflected = (value & 0x08) > 0;
|
||||
|
||||
if (myIsReflected != oldIsReflected) updatePattern();
|
||||
}
|
||||
|
||||
void Player::vdelp(uInt8 value)
|
||||
{
|
||||
const bool oldIsDelaying = myIsDelaying;
|
||||
|
||||
myIsDelaying = (value & 0x01) > 0;
|
||||
|
||||
if (myIsDelaying != oldIsDelaying) updatePattern();
|
||||
}
|
||||
|
||||
void Player::setColor(uInt8 color)
|
||||
{
|
||||
myColor = color;
|
||||
}
|
||||
|
||||
void Player::startMovement()
|
||||
{
|
||||
myIsMoving = true;
|
||||
}
|
||||
|
||||
bool Player::movementTick(uInt32 clock, bool apply)
|
||||
{
|
||||
if (clock == myHmmClocks) {
|
||||
myIsMoving = false;
|
||||
}
|
||||
|
||||
if (myIsMoving && apply) {
|
||||
render();
|
||||
tick();
|
||||
}
|
||||
|
||||
return myIsMoving;
|
||||
}
|
||||
|
||||
void Player::render()
|
||||
{
|
||||
collision = (
|
||||
myIsRendering &&
|
||||
myRenderCounter >= 0 &&
|
||||
(myPattern & (1 << (myWidth - myRenderCounter - 1)))
|
||||
) ? 0 : myCollisionMask;
|
||||
}
|
||||
|
||||
void Player::tick()
|
||||
{
|
||||
if (myDecodes[myCounter]) {
|
||||
myIsRendering = true;
|
||||
myRenderCounter = Count::renderCounterOffset;
|
||||
} else if (myIsRendering && ++myRenderCounter >= myWidth) {
|
||||
myIsRendering = false;
|
||||
}
|
||||
|
||||
if (++myCounter >= 160) myCounter = 0;
|
||||
}
|
||||
|
||||
uInt8 Player::getPixel(uInt8 colorIn) const
|
||||
{
|
||||
return collision ? colorIn : myColor;
|
||||
}
|
||||
|
||||
void Player::shufflePatterns()
|
||||
{
|
||||
const uInt8 oldPatternOld = myPatternOld;
|
||||
|
||||
myPatternOld = myPatternNew;
|
||||
|
||||
if (myIsDelaying && oldPatternOld != myPatternOld) updatePattern();
|
||||
}
|
||||
|
||||
uInt8 Player::getRespClock() const
|
||||
{
|
||||
switch (myWidth) {
|
||||
case 8:
|
||||
return myCounter - 3;
|
||||
|
||||
case 16:
|
||||
return myCounter - 6;
|
||||
|
||||
case 32:
|
||||
return myCounter - 10;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid width");
|
||||
}
|
||||
}
|
||||
|
||||
void Player::updatePattern()
|
||||
{
|
||||
const uInt32 pattern = myIsDelaying ? myPatternOld : myPatternNew;
|
||||
|
||||
switch (myWidth) {
|
||||
case 8:
|
||||
if (myIsReflected) {
|
||||
myPattern =
|
||||
((pattern & 0x01) << 7) |
|
||||
((pattern & 0x02) << 5) |
|
||||
((pattern & 0x04) << 3) |
|
||||
((pattern & 0x08) << 1) |
|
||||
((pattern & 0x10) >> 1) |
|
||||
((pattern & 0x20) >> 3) |
|
||||
((pattern & 0x40) >> 5) |
|
||||
((pattern & 0x80) >> 7);
|
||||
} else {
|
||||
myPattern = pattern;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 16:
|
||||
if (myIsReflected) {
|
||||
myPattern =
|
||||
((3 * (pattern & 0x01)) << 14) |
|
||||
((3 * (pattern & 0x02)) << 11) |
|
||||
((3 * (pattern & 0x04)) << 8) |
|
||||
((3 * (pattern & 0x08)) << 5) |
|
||||
((3 * (pattern & 0x10)) << 2) |
|
||||
((3 * (pattern & 0x20)) >> 1) |
|
||||
((3 * (pattern & 0x40)) >> 4) |
|
||||
((3 * (pattern & 0x80)) >> 7);
|
||||
} else {
|
||||
myPattern =
|
||||
((3 * (pattern & 0x01))) |
|
||||
((3 * (pattern & 0x02)) << 1) |
|
||||
((3 * (pattern & 0x04)) << 2) |
|
||||
((3 * (pattern & 0x08)) << 3) |
|
||||
((3 * (pattern & 0x10)) << 4) |
|
||||
((3 * (pattern & 0x20)) << 5) |
|
||||
((3 * (pattern & 0x40)) << 6) |
|
||||
((3 * (pattern & 0x80)) << 7);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 32:
|
||||
if (myIsReflected) {
|
||||
myPattern =
|
||||
((0xF * (pattern & 0x01)) << 28) |
|
||||
((0xF * (pattern & 0x02)) << 23) |
|
||||
((0xF * (pattern & 0x04)) << 18) |
|
||||
((0xF * (pattern & 0x08)) << 13) |
|
||||
((0xF * (pattern & 0x10)) << 8) |
|
||||
((0xF * (pattern & 0x20)) << 3) |
|
||||
((0xF * (pattern & 0x40)) >> 2) |
|
||||
((0xF * (pattern & 0x80)) >> 7);
|
||||
} else {
|
||||
myPattern =
|
||||
((0xF * (pattern & 0x01))) |
|
||||
((0xF * (pattern & 0x02)) << 3) |
|
||||
((0xF * (pattern & 0x04)) << 6) |
|
||||
((0xF * (pattern & 0x08)) << 9) |
|
||||
((0xF * (pattern & 0x10)) << 12) |
|
||||
((0xF * (pattern & 0x20)) << 15) |
|
||||
((0xF * (pattern & 0x40)) << 18) |
|
||||
((0xF * (pattern & 0x80)) << 21);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace TIA6502tsCore
|
|
@ -0,0 +1,107 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#ifndef TIA_6502TS_CORE_PLAYER
|
||||
#define TIA_6502TS_CORE_PLAYER
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
namespace TIA6502tsCore {
|
||||
|
||||
class Player {
|
||||
|
||||
public:
|
||||
|
||||
Player(uInt32 collisionMask);
|
||||
|
||||
public:
|
||||
|
||||
void reset();
|
||||
|
||||
void grp(uInt8 value);
|
||||
|
||||
void hmp(uInt8 value);
|
||||
|
||||
void nusiz(uInt8 value);
|
||||
|
||||
void resp(bool hblank);
|
||||
|
||||
void refp(uInt8 value);
|
||||
|
||||
void vdelp(uInt8 value);
|
||||
|
||||
void setColor(uInt8 color);
|
||||
|
||||
void startMovement();
|
||||
|
||||
bool movementTick(uInt32 clock, bool apply);
|
||||
|
||||
void render();
|
||||
|
||||
void tick();
|
||||
|
||||
uInt8 getPixel(uInt8 colorIn) const;
|
||||
|
||||
void shufflePatterns();
|
||||
|
||||
uInt8 getRespClock() const;
|
||||
|
||||
public:
|
||||
|
||||
uInt32 collision;
|
||||
|
||||
private:
|
||||
|
||||
void updatePattern();
|
||||
|
||||
private:
|
||||
|
||||
uInt32 myCollisionMask;
|
||||
uInt8 myColor;
|
||||
|
||||
uInt8 myHmmClocks;
|
||||
uInt8 myCounter;
|
||||
bool myIsMoving;
|
||||
uInt8 myWidth;
|
||||
|
||||
bool myIsRendering;
|
||||
Int8 myRenderCounter;
|
||||
|
||||
const uInt8* myDecodes;
|
||||
|
||||
uInt8 myPatternOld;
|
||||
uInt8 myPatternNew;
|
||||
uInt32 myPattern;
|
||||
|
||||
|
||||
bool myIsReflected;
|
||||
bool myIsDelaying;
|
||||
|
||||
private:
|
||||
|
||||
Player(const Player&) = delete;
|
||||
Player(Player&&) = delete;
|
||||
Player& operator=(const Player&) = delete;
|
||||
Player& operator=(Player&&) = delete;
|
||||
|
||||
};
|
||||
|
||||
} // namespace TIA6502tsCore
|
||||
|
||||
#endif // TIA_6502TS_CORE_PLAYER
|
|
@ -41,6 +41,11 @@ enum Delay: uInt8 {
|
|||
hmclr = 2
|
||||
};
|
||||
|
||||
enum DummyRegisters: uInt8 {
|
||||
shuffleP0 = 0xF0,
|
||||
shuffleP1 = 0xF1
|
||||
};
|
||||
|
||||
namespace TIA6502tsCore {
|
||||
|
||||
TIA::TIA(Console& console, Sound& sound, Settings& settings)
|
||||
|
@ -50,7 +55,9 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
|
|||
myDelayQueue(10, 20),
|
||||
myPlayfield(CollisionMask::playfield),
|
||||
myMissile0(CollisionMask::missile0),
|
||||
myMissile1(CollisionMask::missile1)
|
||||
myMissile1(CollisionMask::missile1),
|
||||
myPlayer0(CollisionMask::player0),
|
||||
myPlayer1(CollisionMask::player1)
|
||||
{
|
||||
myFrameManager.setHandlers(
|
||||
[this] () {
|
||||
|
@ -87,6 +94,8 @@ void TIA::reset()
|
|||
myPlayfield.reset();
|
||||
myMissile0.reset();
|
||||
myMissile1.reset();
|
||||
myPlayer0.reset();
|
||||
myPlayer1.reset();
|
||||
|
||||
mySound.reset();
|
||||
myDelayQueue.reset();
|
||||
|
@ -185,6 +194,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
value &= 0xFE;
|
||||
myPlayfield.setColorP0(value);
|
||||
myMissile0.setColor(value);
|
||||
myPlayer0.setColor(value);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -193,6 +203,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
value &= 0xFE;
|
||||
myPlayfield.setColorP1(value);
|
||||
myMissile1.setColor(value);
|
||||
myPlayer1.setColor(value);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -251,12 +262,14 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
case NUSIZ0:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile0.nusiz(value);
|
||||
myPlayer0.nusiz(value);
|
||||
|
||||
break;
|
||||
|
||||
case NUSIZ1:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile1.nusiz(value);
|
||||
myPlayer1.nusiz(value);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -273,6 +286,62 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
case HMCLR:
|
||||
myDelayQueue.push(HMCLR, value, Delay::hmclr);
|
||||
|
||||
case GRP0:
|
||||
myDelayQueue.push(GRP0, value, Delay::grp);
|
||||
myDelayQueue.push(DummyRegisters::shuffleP1, value, Delay::shufflePlayer);
|
||||
|
||||
break;
|
||||
|
||||
case GRP1:
|
||||
myDelayQueue.push(GRP1, value, Delay::grp);
|
||||
myDelayQueue.push(DummyRegisters::shuffleP0, value, Delay::shufflePlayer);
|
||||
|
||||
break;
|
||||
|
||||
case RESP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.resp(myHstate == HState::blank);
|
||||
|
||||
break;
|
||||
|
||||
case RESP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.resp(myHstate == HState::blank);
|
||||
|
||||
break;
|
||||
|
||||
case REFP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.refp(value);
|
||||
|
||||
break;
|
||||
|
||||
case REFP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.refp(value);
|
||||
|
||||
break;
|
||||
|
||||
case VDELP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.vdelp(value);
|
||||
|
||||
break;
|
||||
|
||||
case VDELP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.vdelp(value);
|
||||
|
||||
break;
|
||||
|
||||
case HMP0:
|
||||
myDelayQueue.push(HMP0, value, Delay::hmp);
|
||||
|
||||
break;
|
||||
|
||||
case HMP1:
|
||||
myDelayQueue.push(HMP1, value, Delay::hmp);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -466,6 +535,8 @@ void TIA::tickMovement()
|
|||
|
||||
m = myMissile0.movementTick(myMovementClock, apply) || m;
|
||||
m = myMissile1.movementTick(myMovementClock, apply) || m;
|
||||
m = myPlayer0.movementTick(myMovementClock, apply) || m;
|
||||
m = myPlayer1.movementTick(myMovementClock, apply) || m;
|
||||
|
||||
myMovementInProgress = m;
|
||||
myCollisionUpdateRequired = m;
|
||||
|
@ -497,7 +568,7 @@ void TIA::tickHframe()
|
|||
myPlayfield.tick(x);
|
||||
|
||||
if (lineNotCached)
|
||||
renderSprites(x);
|
||||
renderSprites();
|
||||
|
||||
tickSprites();
|
||||
|
||||
|
@ -506,16 +577,21 @@ void TIA::tickHframe()
|
|||
if (++myHctr >= 228) nextLine();
|
||||
}
|
||||
|
||||
void TIA::renderSprites(uInt32 x)
|
||||
void TIA::renderSprites()
|
||||
{
|
||||
myPlayer0.render();
|
||||
myPlayer1.render();
|
||||
myMissile0.render();
|
||||
myMissile1.render();
|
||||
|
||||
}
|
||||
|
||||
void TIA::tickSprites()
|
||||
{
|
||||
myMissile0.tick();
|
||||
myMissile1.tick();
|
||||
myPlayer0.tick();
|
||||
myPlayer1.tick();
|
||||
}
|
||||
|
||||
void TIA::nextLine()
|
||||
|
@ -543,10 +619,14 @@ void TIA::renderPixel(uInt32 x, uInt32 y, bool lineNotCached)
|
|||
if (myPriority == Priority::normal) {
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
} else {
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
color = myPlayfield.getPixel(color);
|
||||
}
|
||||
|
||||
|
@ -579,6 +659,8 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
|
|||
|
||||
myMissile0.startMovement();
|
||||
myMissile1.startMovement();
|
||||
myPlayer0.startMovement();
|
||||
myPlayer1.startMovement();
|
||||
|
||||
break;
|
||||
|
||||
|
@ -616,6 +698,44 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
|
|||
myLinesSinceChange = 0;
|
||||
myMissile0.hmm(0);
|
||||
myMissile1.hmm(0);
|
||||
myPlayer0.hmp(0);
|
||||
myPlayer1.hmp(0);
|
||||
|
||||
break;
|
||||
|
||||
case GRP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.grp(value);
|
||||
|
||||
break;
|
||||
|
||||
case GRP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.grp(value);
|
||||
|
||||
break;
|
||||
|
||||
case DummyRegisters::shuffleP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.shufflePatterns();
|
||||
|
||||
break;
|
||||
|
||||
case DummyRegisters::shuffleP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.shufflePatterns();
|
||||
|
||||
break;
|
||||
|
||||
case HMP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.hmp(value);
|
||||
|
||||
break;
|
||||
|
||||
case HMP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.hmp(value);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "FrameManager.hxx"
|
||||
#include "Playfield.hxx"
|
||||
#include "Missile.hxx"
|
||||
#include "Player.hxx"
|
||||
|
||||
class Console;
|
||||
|
||||
|
@ -138,7 +139,7 @@ class TIA : public AbstractTIA {
|
|||
|
||||
void updateCollision();
|
||||
|
||||
void renderSprites(uInt32 x);
|
||||
void renderSprites();
|
||||
|
||||
void tickSprites();
|
||||
|
||||
|
@ -190,6 +191,8 @@ class TIA : public AbstractTIA {
|
|||
Playfield myPlayfield;
|
||||
Missile myMissile0;
|
||||
Missile myMissile1;
|
||||
Player myPlayer0;
|
||||
Player myPlayer1;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ MODULE_OBJS := \
|
|||
src/emucore/tia/core_6502ts/FrameManager.o \
|
||||
src/emucore/tia/core_6502ts/Playfield.o \
|
||||
src/emucore/tia/core_6502ts/DrawCounterDecodes.o \
|
||||
src/emucore/tia/core_6502ts/Missile.o
|
||||
src/emucore/tia/core_6502ts/Missile.o \
|
||||
src/emucore/tia/core_6502ts/Player.o
|
||||
|
||||
|
||||
MODULE_DIRS += \
|
||||
|
|
Loading…
Reference in New Issue