Files
TeslaRel410/BORLAND/BC45/EXAMPLES/OWL/GAMES/METEOR/SPRITE.CPP
T
CydandClaude Fable 5 63312e07f9 source410: literal 4.10 source reconstruction + BC++ 4.52 fleet toolchain archived
- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
  is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
  Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
  (extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
  BT game source (never mixed into CODE/). Round 1-3 state:
  * 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
    (BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
    since 1996.
  * BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
    its binary-recorded line 400 exactly.
  * BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
    (Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
    TeamScore=12 flagged [T4]).
  * MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
    (VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
    the period compiler is the drift detector).
  * Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
    (per-TU verification sweep under authentic OPT.MAK flags).
  * README: corrected roadmap - MECH.HPP is the capstone grown with the mech
    TU reconstructions; BTREG.CPP green = the header-family milestone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 07:33:26 -05:00

312 lines
7.8 KiB
C++

//--------------------------------------------------------------------------
// Turbo Meteor -- Copyright (c) 1995, Borland International
//--------------------------------------------------------------------------
#include "sprite.h"
// adjust - value to convert degrees to radians
//
// pi can be computed as atan(1)*4,
//
// and there are 2*pi radians in 360 degrees so:
//
// adjust = 2*pi/360 = pi/180 = atan(1)*4/180 = atan(1)/45
//
const double adjust = atan(1)/45;
double sinTable[360];
double cosTable[360];
double sind( int angle ) {
return sinTable[(angle+360)%360];
}
double cosd( int angle ) {
return cosTable[(angle+360)%360];
}
void InitSinCosTables() {
int i;
for (i=0;i<360;i++) {
sinTable[i] = sin(adjust*i);
cosTable[i] = cos(adjust*i);
}
}
#pragma startup InitSinCosTables
void SpriteList::Add( Sprite* sprite ) {
count++;
if (root==0) {
root = sprite;
sprite->next = 0;
sprite->owner = this;
return;
}
sprite->next = root;
sprite->owner = this;
root = sprite;
}
void SpriteList::DrawAll( TMemoryDC& dc ) {
Sprite *temp = root;
while (temp!=0) {
temp->Draw( dc );
temp=temp->next;
}
}
int SpriteList::UpdateAll() {
Sprite *previous,
*current = root;
int points = 0;
previous = 0;
while (current!=0) {
// if the object is not condemned, call it's update
// function
if (!(current->condemned)) {
points+=current->Update();
previous = current;
current=current->next;
}
// if the object is condemned, delete it from the
// list
else {
// special case if we're deleting the root node
if (previous==0) {
root = current->next;
delete current;
count--;
current = root;
}
else {
previous->next = current->next;
delete current;
count--;
current=current->next;
}
}
}
return points;
}
// *BBK* should convert this over to use RTTI, this is cheezy
Sprite* SpriteList::CheckForHitMeteor( TPoint& p ) {
Sprite *temp = root;
while (temp!=0) {
if ((strncmp(temp->DebugInfo(),"Meteor",6)==0) && // *BBK* cheezy
(temp->boundingRect.Contains( p )))
return temp;
temp=temp->next;
}
return 0;
}
Meteor::Meteor( TPoint& aOrigin, TSize& aMomentum, int aSize, int aSpawnCount ):
Sprite( TSize( 600,400 ) ) {
origin = aOrigin;
mx = aMomentum.cx;
my = aMomentum.cy;
size = aSize;
spawnCount = aSpawnCount;
for (int i=0;i<10;i++) {
angle[i] = (angle1[i]+random(20)-10)%360;
radius[i] = (radius1[i]+random(10)-5)/(4-size);
}
angularMomentum = random(7)-4;
currentAngle = 0;
count = count1;
}
void Meteor::Hit() {
size--;
if (size>0) {
for (int i=0;i<spawnCount;i++)
owner->Add( new Meteor( origin, TSize( random(10)-5, random(10)-5 ),
size, size ) );
}
condemned=true;
}
void Meteor::Draw( TMemoryDC& dc ) {
TPoint temp;
TPoint points[10];
int i;
temp =TPoint( radius[0]*sind(angle[0]+currentAngle),
radius[0]*cosd(angle[0]+currentAngle) );
ResetBoundingRect();
ExpandBoundingRect( temp+origin );
points[0]=temp+origin;
// dc.MoveTo( origin+temp );
for (i=1;i<=count;i++) {
temp = TPoint( radius[i%count]*sind(angle[i%count]+currentAngle),
radius[i%count]*cosd(angle[i%count]+currentAngle) );
ExpandBoundingRect( temp+origin );
points[i] = temp+origin;
// dc.LineTo( origin+temp );
}
points[count]=points[0];
dc.Polyline( points, count+1 );
}
int Shot::Update() {
// shots die after a fixed amount of time
if (timeToDie>0) {
origin+=TPoint(mx,my);
timeToDie--;
if (timeToDie==0)
condemned = true;
}
Wrap(); // if the shot is off the screen, wrap to other side
// check against all meteors in the list, to see if any are
// colliding with ourself
Sprite* meteor = owner->CheckForHitMeteor( origin );
// if so, tell the meteor it was hit, and mark ourself for
// deletion
if (meteor) {
((Meteor*)meteor)->Hit();
condemned = true;
int size = ((Meteor*)meteor)->GetSize();
switch (size) {
case 0:
return 500;
case 1:
return 50;
case 2:
return 5;
}
}
return 0;
}
const char *Meteor::DebugInfo() {
static char temp[100];
wsprintf(temp,"Meteor(%d)",size);
return temp;
}
const char *Message::DebugInfo() {
static char temp[100];
wsprintf(temp,"Message '%s'",text);
return temp;
}
Message::Message( TPoint& aOrigin, int aBufferLen ):
Sprite( TSize(600,400) ) {
text = new char[ aBufferLen ];
bufferLen = aBufferLen;
origin = aOrigin;
}
void Message::Draw( TMemoryDC& dc ) {
const tw = 6; // text width
const th = 10; // text height
TPoint temp = origin;
int i;
for (i=0;i<strlen(text);i++) {
switch (text[i]) {
case '0':
dc.MoveTo(temp);
dc.LineTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(0,th));
dc.LineTo(temp);
break;
case '1':
dc.MoveTo(temp+TPoint(tw/2,0));
dc.LineTo(temp+TPoint(tw/2,th+1));
break;
case '2':
dc.MoveTo(temp);
dc.LineTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(tw,th/2));
dc.LineTo(temp+TPoint(0,th/2));
dc.LineTo(temp+TPoint(0,th));
dc.LineTo(temp+TPoint(tw+1,th));
break;
case '3':
dc.MoveTo(temp);
dc.LineTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(0-1,th));
dc.MoveTo(temp+TPoint(tw,th/2));
dc.LineTo(temp+TPoint(0-1,th/2));
break;
case '4':
dc.MoveTo(temp);
dc.LineTo(temp+TPoint(0,th/2));
dc.LineTo(temp+TPoint(tw,th/2));
dc.MoveTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(tw,th+1));
break;
case '5':
dc.MoveTo(temp+TPoint(tw,0));
dc.LineTo(temp);
dc.LineTo(temp+TPoint(0,th/2));
dc.LineTo(temp+TPoint(tw,th/2));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(0-1,th));
break;
case '6':
dc.MoveTo(temp+TPoint(tw,0));
dc.LineTo(temp);
dc.LineTo(temp+TPoint(0,th));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(tw,th/2));
dc.LineTo(temp+TPoint(0-1,th/2));
break;
case '7':
dc.MoveTo(temp);
dc.LineTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(tw,th+1));
break;
case '8':
dc.MoveTo(temp);
dc.LineTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(0,th));
dc.LineTo(temp+TPoint(0,0));
dc.MoveTo(temp+TPoint(0,th/2));
dc.LineTo(temp+TPoint(tw,th/2));
break;
case '9':
dc.MoveTo(temp+TPoint(0,th));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(tw,0));
dc.LineTo(temp+TPoint(0,0));
dc.LineTo(temp+TPoint(0,th/2));
dc.LineTo(temp+TPoint(tw,th/2));
break;
case '*': // ship
dc.MoveTo(temp+TPoint(tw/2,0));
dc.LineTo(temp+TPoint(tw,th));
dc.LineTo(temp+TPoint(tw/2,th-(th/4)));
dc.LineTo(temp+TPoint(0,th));
dc.LineTo(temp+TPoint(tw/2,0));
break;
}
temp+=TPoint(tw+tw/2,0);
}
}
Message::~Message() {
delete [] text;
}
// values used to initialize meteors. these values are randomly
// tweaked, so each meteor looks different
//
int angle1[10] = { 0,45,90,135,180,225,270,315,0,0 };
int radius1[10] = { 30,30,30,30,30,30,30,30,0,0 };
int count1 = 8;