Get Cross Platform Game Programming Game Development 1st Edition Steven Goodwin PDF ebook with Full Chapters Now
Get Cross Platform Game Programming Game Development 1st Edition Steven Goodwin PDF ebook with Full Chapters Now
com
https://ebookfinal.com/download/cross-platform-game-
programming-game-development-1st-edition-steven-goodwin/
OR CLICK BUTTON
DOWNLOAD EBOOK
https://ebookfinal.com/download/game-programming-golden-rules-game-
development-series-1st-edition-martin-brownlow/
ebookfinal.com
https://ebookfinal.com/download/opengl-game-programming-prima-tech-s-
game-development-1st-edition-kevin-hawkins/
ebookfinal.com
https://ebookfinal.com/download/beginning-3d-game-development-with-
unity-all-in-one-multi-platform-game-development-2nd-edition-edition-
sue-blackman/
ebookfinal.com
Game Programming Gems 3 Game Programming Gems Series v 3
1st Edition Dante Treglia
https://ebookfinal.com/download/game-programming-gems-3-game-
programming-gems-series-v-3-1st-edition-dante-treglia/
ebookfinal.com
https://ebookfinal.com/download/game-programming-gems-2-game-
programming-gems-series-vol-2-1st-edition-mark-deloura/
ebookfinal.com
https://ebookfinal.com/download/c-game-programming-for-serious-game-
creation-1st-edition-daniel-schuller/
ebookfinal.com
https://ebookfinal.com/download/c-game-programming-for-serious-game-
creation-1st-edition-daniel-schuller-2/
ebookfinal.com
https://ebookfinal.com/download/game-level-design-game-development-
series-1st-edition-ed-byrne/
ebookfinal.com
CROSS-PLATFORM
GAME PROGRAMMING
LIMITED WARRANTY AND DISCLAIMER OF LIABILITY
CHARLES RIVER MEDIA, INC. (“CRM”) AND/OR ANYONE WHO HAS BEEN
INVOLVED IN THE WRITING, CREATION, OR PRODUCTION OF THE ACCOMPA-
NYING CODE (“THE SOFTWARE”) OR THE THIRD-PARTY PRODUCTS CON-
TAINED ON THE CD-ROM OR TEXTUAL MATERIAL IN THE BOOK, CANNOT AND
DO NOT WARRANT THE PERFORMANCE OR RESULTS THAT MAY BE OBTAINED
BY USING THE SOFTWARE OR CONTENTS OF THE BOOK. THE AUTHOR AND
PUBLISHER HAVE USED THEIR BEST EFFORTS TO ENSURE THE ACCURACY AND
FUNCTIONALITY OF THE TEXTUAL MATERIAL AND PROGRAMS CONTAINED
HEREIN. WE HOWEVER, MAKE NO WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, REGARDING THE PERFORMANCE OF THESE PROGRAMS OR CON-
TENTS. THE SOFTWARE IS SOLD “AS IS” WITHOUT WARRANTY (EXCEPT FOR
DEFECTIVE MATERIALS USED IN MANUFACTURING THE DISK OR DUE TO
FAULTY WORKMANSHIP).
STEVEN GOODWIN
No part of this publication may be reproduced in any way, stored in a retrieval system of any
type, or transmitted by any means or media, electronic or mechanical, including, but not limited
to, photocopy, recording, or scanning, without prior permission in writing from the publisher.
Publisher: Jenifer Niles
Cover Design: The Printed Image
CHARLES RIVER MEDIA, INC.
10 Downer Avenue
Hingham, Massachusetts 02043
781-740-0400
781-740-8816 (FAX)
[email protected]
www.charlesriver.com
This book is printed on acid-free paper.
Steven Goodwin. Cross-Platform Game Programming.
ISBN: 1-58450-379-3
eISBN: 1-58450-639-3
All brand names and product names mentioned in this book are trademarks or service
marks of their respective companies. Any omission or misuse (of any kind) of service marks or
trademarks should not be regarded as intent to infringe on the property of others. The publisher
recognizes and respects all marks used by companies, manufacturers, and developers as a means
to distinguish their products.
Library of Congress Cataloging-in-Publication Data
Goodwin, Steven, 1973-
Cross platform game programming / Steven Goodwin.— 1st ed.
p. cm.
Includes bibliographical references and index.
ISBN 1-58450-379-3 (pbk. with cd-rom : alk. paper)
1. Computer games—Programming. 2. Cross-platform software development. I. Title.
QA76.76.C672G66 2005
794.8’1526—dc22
2004029828
Printed in the United States of America
05 7 6 5 4 3 2 First Edition
CHARLES RIVER MEDIA titles are available for site license or bulk purchase by institutions,
user groups, corporations, etc. For additional information, please contact the Special Sales De-
partment at 781-740-0400.
Requests for replacement of a defective CD-ROM must be accompanied by the original disc,
your mailing address, telephone number, date of purchase, and purchase price. Please state the
nature of the problem, and send the information to CHARLES RIVER MEDIA, INC., 10
Downer Avenue, Hingham, Massachusetts 02043. CRM’s sole obligation to the purchaser is to
replace the disc, based on defective materials or faulty workmanship, but not on the operation
or functionality of the product.
To my sister, Angela…
Dedication v
Acknowledgments xvii
Preface xix
1 Introduction 1
Background of Cross-Platform Programming 1
History 2
The Importance of Cross-Platform Development 4
Overview of Cross-Platform Components 7
The Lead Platform 9
Cross-Generation, Cross-Platform Game Programming 9
The Theoretical Process 10
The Development Process 12
Code Is Code 12
Console Limitations 14
Libraries 15
About the Book 17
Coding Style 17
Non-Disclosure Agreements 18
Notes to the Reader 18
Endnotes 19
vii
viii Contents
Abstraction 22
Commonality 24
Limitations 24
Language Limitations 24
Library Limitations 27
Compiler Limitations 27
Platform Limitations 31
Modularization 33
Resource Creation Path 35
Resource Detail 35
Granularity 38
Basic Datatypes 39
Memory Management 39
Audio Code 39
Separation and Isolation 40
Obvious Isolation 40
Singletons 41
Class Structures 43
Divorcing Code 44
Separation by Purpose 46
Separation by Memory 49
Separation for the Present 49
Separation for the Future 50
Succession 52
The pImpl Idiom 53
Debugging and Profiling 53
Programming-Based Bugs 53
Compiler-Based Bugs 54
Execution-Based Bugs 55
Profiling 59
Predictability 60
Contents ix
Randomness 60
Trigonometry 61
Input Stimuli 61
Turn-Around 62
Endnotes 65
3 Memory 67
The Specification 67
Simple Memory 71
The Issues–Datatypes 71
The Issues–A Safety File 74
The Issues–The Report 76
Our Own Memory Manager–Design 81
Hardware Properties 81
Endian 81
Alignment 85
Access 87
Software Properties 87
Fragmentation 87
The Standard Library 89
Our Own Memory Manager–Implementation 90
Conceptual Design 91
Allocating Memory 94
Garbage Collection 97
Releasing Memory 98
Debugging Memory 99
Profiling Memory Usage 102
Allocation Wrappers 102
High-Level Memory Usage 102
Application Memory Usage 104
Using Allocation Within Subsystems 115
Global versus Game 117
x Contents
5 Storage 165
The Four Corners of Storage 165
The Problems 166
Contents xi
6 Debugging 241
Basic Requirements 241
Debugging Methods 242
xii Contents
Endnote 341
Index 445
Acknowledgments
he completion of this book is the result of many people and their inspira-
T tion, experience, ideas, and time. Writing the actual words appears insignif-
icant by comparison.
I would like to thank my readers, editors, and other assorted developers who
have provided invaluable feedback, comments, and suggestions, especially Michael
Braithwaite, Ben Crossman, Dan Evans, Mal Lansell, David Manley, Jerome Muf-
fat-Meridol, and Dave Wall.
To my friends and colleagues that have encouraged my writing: John Hearns,
Anne Mullane, Colin Murphy, Steve Porter, John Southern, and Dean Wilson.
To those with whom I’ve worked, and whose great ideas have found some form
within these words, I thank you: The development teams at Bits Studios, Computer
Artworks (R.I.P.), Criterion and Edcom, and notably Mat Cook, Dominic Giles,
Vlad Kapietsky, Nat Presson, Alan Troth, Mark Walker, and Darren Ward.
I would like to thank Jenifer Niles and all her team at Charles River Media for
this book, and for making me appear competent!
Finally, I would like to thank my close network of family and friends who know
all about me, but seem to like me anyway—especially David Eade, Ed and Margaret
Grabowski (without whom...), Justine Griffith, Phillip Hart, William Siddons,
Fiona Stewart, Maria Thomson, and all of TULS, Lonix, Gllug, 2600, and Slashdot-
London.
And, of course, I want to thank Grandma, Granddad, Shirley and Ken, Juliette
and Dean, Melanie, Mum, Dad, and my sister Angela.
xvii
This page intentionally left blank
Preface
ith nearly every game on the market today being released si-
xix
xx Preface
For those already working in the upper echelons of their company, this book
provides a solid reference of development practices and a detailed breakdown of all
the required cross-platform game components, with a comprehensive task list for
the team. You also get detailed explanations of new technologies, such as multi-
processing and threaded environments, and how they will affect the next genera-
tion of consoles.
For those using middleware, the problem is not over because every program-
mer still needs to be able to handle memory, the filesystem, and gameplay code in
a generic, cross-platform manner to make efficient use of the purchase. Who knew
that in our world the standard libraries are not standard? This book covers the
rarely discussed world of cross-platform game programming and gives you the un-
derstanding to develop your games effectively.
We begin by explaining the 10 basic tenets for development that must be ad-
hered to throughout a project for it to work, whether it involves engine or gameplay
coding. We then cover specific areas in detail, such as the abstraction of a filesys-
tem, the graphics engine, the memory manager, and how to handle different hard-
ware specifications without changing the code. Seemingly general topics (such as
debugging and UI design) take on new meaning and raise different issues when the
platform changes and the old tricks no longer work.
A plethora of new ideas and techniques need to be adopted across the spheres
of memory allocation, file handling, graphics, audio, and networking. These are all
areas of knowledge that were once deemed magic by the knowledgeable few, and
unobtainable by the rest of the populous. They are now available to all, and I hope
to teach you some new tricks in this book.
–Steven Goodwin
1 Introduction
In This Chapter
Background of Cross-Platform Programming
Overview of Cross-Platform Components
The Development Process
About the Book
Non-Disclosure Agreements
Notes to the Reader
Cross-platform development is the art, skill, ability, and general know-how re-
quired to write software that works on multiple platforms. “Working on multiple
platforms” means that the same code will compile, link, run, and behave identically
on whichever platform is targeted. Granted, the compiler and tools will be specific
to each machine, and the underlying Application Programming Interface (API)
may vary, but the code itself will be identical as both the game and engine should
be reusable across each platform; that is, developed once, and deployed often.
To be considered a cross-platform project (as opposed to a port), work must be
carried out concurrently on at least two different target machines using a common
code base that remains live throughout. This is a delicate skill because algorithms,
libraries, compilers, and data structures cannot be changed in an arbitrary fashion
1
2 Cross-Platform Game Programming
as a benign modification to one system could cause catastrophic problems for one
(or more) of the other platforms. This is especially true of the data structures con-
taining game assets, where the effects can range from a nuisance to code break-
down, to fluctuations in the memory footprint and large-scale project delays.
Also, a cross-platform game must act identically on these different machines
once compiled. This is the main difference between a project that can be compiled
and run on different machines, and one that is truly cross-platform. Most of the
available OpenGL® code, for example, will compile and run anywhere, but its run-
time behavior often relies on the target platform and varies according to the oper-
ating system, memory, processor speed, filesystem, byte order, and graphics
capabilities.
History
Before the current crop of games, cross-platform development only occurred
rarely. Usually, a game was written first, and then ported to other platforms. The
amount of work required varied according to the project, but was usually small.
Often, when the same development team carried out the port, a set of libraries
would be rewritten for each machine using common names and calling conven-
tions. Various portions of the game code were then changed, amended, and gener-
ally hacked around to compile or assemble on the new platform. There would be
moderate reuse of the game code, but very little reuse of the engine.
Throughout most of the 1980s, a different programmer (or team) would
rewrite the entire game whenever the game was ported to a new platform. Because
most games of this time were written in assembler, it was rare to find a programmer
expert enough in more than a couple of machine code variations to write both ver-
sions. The newness of the industry also meant that very few conversion tools were
available because these were highly specialized languages. The game engines con-
sisted of highly optimized sprite renderers and animation code that would usually
belong to the conversion programmer himself and tied into the new game with
whatever customizations were needed for that project.
As games became more complex in the 1990s, bringing in a different developer
(or team) for the new platform became a less viable option. Development cycles
were no longer measured in weeks, but months. Publishers didn’t want to wait an-
other six months for the conversions to appear because this prevented any attempt
at a short-term marketing and advertising blitz. This meant both versions of the
game had to be developed in tandem, requiring more code reuse as was demon-
strated within the game development cycles of the Commodore™ Amiga® and
Atari® ST, which shared a common processor in the Motorola® 68000. Software
houses created their own graphics library (now called engines) and developed both
Introduction 3
Technology
From a technical programmers perspective, cross-platform development encour-
ages a modular approach to development. Because it’s not possible to run Nintendo
code on a Sony platform, for example, every individual component must be iso-
lated: processing and presentation, platform-specific and common, game and en-
gine. Each module must then provide a common interface to the rest of game,
hiding the specific details beneath it. This conforms to the traditional view of good
software design. A cross-platform project enforces this distinction that might oth-
erwise become blurred in a single target environment. Whereas modular program-
ming often encourages this method of abstraction and isolation, cross-platform
development requires it.
Under this regime, it’s no longer possible to rely on any internal side effects of
the API. Nor is it possible to surreptitiously add an access function, or make a pri-
vate member variable public, because the implementation details—or information
upon which you rely—might not exist on every platform. Consequently, a very
rigid demarcation must exist between the various components.
Cross-platform code is also more stable and more accurate. This is not a gen-
eralization on the people that write it, but as a consequence of it being written. After
all, if your code compiles without warnings on three different compilers, and runs
identically on three different machines, then it is more likely to have been written
solidly. It can be an illuminating experience to compile code under the GNU™ C
Compiler (gcc) when you’re over-familiar with Microsoft™ Visual C++™. Not be-
cause gcc is better, per se, but because it’s different. An unfamiliar set of warnings
can inspire—as well as exasperate.
Teamwork
Most of the games currently available have been written to work cross-platform.
They are usually available on PS2 and Xbox, at least, with many also appearing on
PC and GameCube. Unfortunately for the majority of the industry, this is a new
field, and developers are the only ones solving these problems when the market
goes cross-platform. Marketing can easily add stickers to boxes claiming “PS2 ver-
sion out now. Xbox due Q4.” Publishers only need to snap their wallets shut and
say, “Give us a GameCube version, too, or else” and they can consider their job
over. For developers, however, it represents a significant amount of extra effort.
Most of this extra effort is unknown (or ignored) by everyone else. Of the three
main departments in a development team— the code, the art, and the design—
cross-platform development directly affects all three.
Even when all the individuals within the team have understood (and solved)
the problems involved, the managerial glue that holds them together has other
problems. The producer must decide where to spend the money; for example,
6 Cross-Platform Game Programming
Management
One particular management problem that is specific to new cross-platform games
is snobbery. Every console manufacturer believes its machine is the best on the
market. They demonstrate this by releasing their first-party games for their own
consoles alone. So while Nintendo is still building machines, Zelda, Mario, and its
other game licenses are only available for the latest Nintendo platform. This makes
good business sense for Nintendo. The “Exclusively on...” flash on the game pack-
aging nurtures a fan base wanting to play that particular Nintendo game on that
particular Nintendo console. It implies that the game is better tailored to the hard-
ware because there were no other considerations during development. Although
this can limit the range of potential consumers, it can benefit the developers be-
cause it increases the selling power of a game if the console manufacturer helps with
advertising features (which the manufacturer should do, because it helps sell the
console too) and more technical support in times of trouble.
However, wanting a cross-platform release can create bad feelings on the part
of the console manufacturers that weren’t approached first. Because the manufac-
turers hold a monopoly on their console and development kits, they can withhold
materials and support that would otherwise be forthcoming.
Finances
Because most development studios are cash strapped, cross-platform development
can help massage the budget by eliminating the need for excessive hardware. Any
game, including those destined for a single console, can benefit here. After all, if a
game works identically on a PS2 and a PC, then the majority of developers can
spend most of their time working with the PC version, while periodically testing
their work on a shared development kit. Exclusive access to development kits is
usually limited to the lead and senior programmers, the console-specific engine
coders, and those in charge of the control system and technical requirements.1 In
many cases, however, the lead programmer handles these last two tasks. For the
other developers that need access to hardware (such as testers), less expensive kits
Introduction 7
are often available from the console manufacturers that do not support the full
range of debugging facilities, but provide adequate preview features so that the
artists and level designers can view their work in position.
In some cases, sharing hardware presents a double saving because there’s less
software to buy in the form of compilers, profilers, and customized debuggers.
These savings depend on whether your toolset supports a roaming license. If you
haven’t encountered these yet, this simply allows you to install the software any-
where you like, but you can only use it on a limited subset of these machines at any
one time. Shared kit is not a recommended way to build games, but frugal devel-
opers should take note anyway.
Growth
From a human resource management point of view, cross-platform development
can profit the company by helping grow the ability of the team much quicker than
usual. Even junior programmers, often consigned to in-house scripting languages
and menial tasks, will understand the ramifications of the various platforms be-
cause their code will be reused on each of them. So what might initially appear to
them as a simple loop with a “pointer to function” callback, will soon be under-
stood as a potential problem involving cache misses.
In the initial stages of development, instruction of this kind will come from the
senior programmers (and this book), but afterwards, programmers will be able to
use this knowledge themselves to write and fix more involved code. They will also
be able to teach the new junior programmers. This continues to increase the aver-
age ability of the team and cultivate an awareness of the project as a whole. The ju-
nior programmers’ knowledge will become very valuable to the team (and the
company) over the forthcoming years as they graduate to lead, and senior, status.
The design of the generic, cross-platform, interfaces that handles the various
modules within the game, such as graphics, audio, or input.
The technical, platform-specific, implementation of the low-level driver that
talks to the hardware to bring the interface to life.
The gameplay code that effectively uses these components.
The balance between each section varies significantly according to the module
in question. An input library, for example, has a simple design and implementa-
tion, but the gameplay mechanics that use it are much more complex. The game-
8 Cross-Platform Game Programming
play mechanics will, for example, have to cope with controller configurations, in
which the sidestep might be assigned to the joystick, a button, or a pressure-
sensitive shoulder control.
Software interface design is a big topic, so we’ll limit our discussions to the spe-
cific design patterns suitable for cross-platform game development. This includes
many multi-layered solutions because even though a graphics renderer is consid-
ered the code that “draws stuff,” it’s wise to separate this into multiple components
to deal with specific jobs. In this example, a renderer can be split into two distinct
cases: one component that determines what objects to draw, and a second compo-
nent to draw them. This moves a lot of common engine code away from the low-
level driver, enabling more code to be reused.
The low-level implementation of the driver is the only part of the game that
should interface with the platform-specific API. Even when this API is middleware,
the interface layer should still exist to prevent the game from accessing any com-
ponent directly as this limits the control the engine can exert on the platform. The
more control the engine has, the greater its opportunity for creating faster games
and the less chance the game has for slowing it down.
One additional distinction to make at this point is between platform-specific
code and platform-dependent code. The former indicates code that is intended for
a single platform, but can be compiled and run anywhere. Dependent code, on the
other hand, requires the underlying API or hardware to be present for it to work.
So if we revisit the example of the input library, code that makes a character side-
step left when the PS2 circle button is pressed is platform-specific. However, the
code that actually polled the controller would be platform-dependent.
Within a cross-platform game, often a complex relationship exists between
these two categories because much of the platform-specific code becomes plat-
form-dependent. This is through workflow problems more than technical ones; if
a programmer needs to change a piece of platform-specific code, he is often likely
to solve it with the idea that “It’s only ever on PS2, so I can just call this PS2-
specific function….” In many cases, this isn’t a valid argument. For example, if
you’re converting data assets on the target machine using platform-dependent
code, it becomes very difficult to move that conversion routine offline into the PC-
oriented tool chain at a later date. Also, platform-specific code is only one step away
from the targeted grail of cross-platform code. Dependent code is two steps. A sim-
ple abstraction can often generalize specific code, which means there’s less code to
write, debug, and maintain. This creates a greater amount of commonality between
platforms, and should be the goal for any developer. Throughout the book, the
terms platform-specific and platform-dependent are used in very specific cases.
However, because this can depend on the precise implementation employed, we
tend to err toward the use of platform-specific.
Introduction 9
cific engine that is then tweaked into a PSP engine. Such tweaking inevitably be-
comes a crowbar.
When converting code between two consoles, it’s often easier to port the whole
game to a PC first, and then back onto the new target.
The Game
The majority of examples within this book have a direct connection with the
process of developing a first-person shooter (FPS). Not because they have any spe-
cial cross-platform qualities, but because the scenarios involving non-player char-
acters (NPCs), explosions, players, and bullets provide a familiar host of good
examples from which we can draw, as most people will have a natural instinct for
the design of at least one FPS without needing any groundwork to be explained.
Naturally, it makes no difference what sort of game you’re writing because the
problems involved in cross-platform game programming are the same within all
genres. Where an FPS doesn’t sensibly support a particular feature or technique,
we’ll indicate a suitable example and include a brief background instead of creating
contrived examples within the example FPS.
Object
Viewer
Exporter
Platform Game
Conversion
Metadata
Editor
Disc
Builder
This conversion process is consequently written as two halves; you have half of
a converter that adapts an image file into generic raw data, and another half to build
a platform-specific asset from the generic resource. Splitting the conversion rou-
tines into two makes it easier to cross onto new platforms, such as Xenon®, because
you only need to add the missing half.
When building assets for a cross-platform pipeline, you need to make a few
considerations over and above that of a single-platform game. We’ll look at these
considerations in Chapter 2.
12 Cross-Platform Game Programming
The Engine
The engine running your game has the greatest scope for variation. Trying to pre-
dict every breed of engine is impossible. All we’ll assume is that you have some form
of code to process the game objects, each derived from a common base class, and a
means for their inter-communication. Throughout the text, we’ll refer to this as an
event system, or message passing system, depending on context. These messages are
assumed to arrive instantaneously.
Any API calls not described within these pages, and all classes referred to, are
similarly theoretical and are assumed to fulfill any basic functionality ascribed to
them. The implementation will conform to the rules of cross-platform develop-
ment (as laid out in Chapter 2), but won’t be described in detail unless a new idea
or concept needs to be presented.
The physical act of developing code has been discussed many times. When applied
to cross-platform development, however, this role changes.
Code Is Code
Writing cross-platform code is somewhat different from writing standards-
compliant code, although the two are not mutually exclusive. Indeed, to write any-
thing that is cross-platform without adhering to standards would be the gentle
equivalent of changing the preprocessor macro of TRUE to 0, or PI to 3. It would be
more true to say that cross-platform code is like writing to standards on steroids.
You have to make sure that the compiler cannot misinterpret any line of code, that
it says exactly what you mean, and that you mean exactly what you say. Running
the code through checkers such as Lint can be very useful here, as can adopting peer
reviews, and compiling with stringent warning settings on alternate compilers.
More complications occur because of buggy compilers, in which certain lan-
guage constructs cause incorrect code to be generated or fail to build entirely.
Granted, this is not as common now as it has been in the past, but it still happens.
There are also places where the C standard states that the behavior of certain code
is “undefined.” Although the compiler might be standards compliant, the three lit-
tle words of “undefined,” “undetermined,” and “unknown” indicate that each
compiler is at liberty to process your code in any way it sees fit. The classic interview
question of “what result does a = a++; give” is a prime example, and should nat-
urally be avoided. This is just one of many similar examples throughout the book.
Chapter 2 highlights some of them, but during the course of development, you’ll
discover your own favorites.
Introduction 13
Standards-compliant code, however, is only half the story. The typical scenario
of a present day developer reveals the other half. Consider for a moment this set up:
“The developer will be experienced with Microsoft Visual C++ or .NET™, run-
ning under Windows 2000™ using the Win32™ API on an Intel machine. The
developer’s PC will have a 128-channel sound card (as standard), a 256-MB
graphics card, a large hard drive (containing an equally large swap file), 2 GB
of RAM and a 19-inch monitor.”
How much of this seems familiar? Most of it, no doubt. This is not an atypical
environment, as the development tools required to build and play modern games
require this amount of processing grunt. In cross-platform games development,
everything presented in that scenario is so far wide of the goal posts, it’s not even in
the same stadium.
Most PC programmers can become spoiled by being able to write clever algo-
rithms that use a lot of memory, are very compute-intensive, or both. They can also
get used to the safety net of a swap file, and never check their memory allocation
function returns safely. On a console, memory can (and sometimes does) run out,
so you still need to keep the game running, even though some particular feature
cannot be allocated. Not only that, with each console having a different amount of
memory (and the game resources using a different memory footprint), you might
run out of memory during different parts of the game on the various consoles. You
need to cope with that, too. And, if you’re developing without a console develop-
ment kit, how do you determine the effect of your code on the real hardware?
A further consideration stems from the fact that Microsoft Developer Studio™
is not the only environment. It compiles code differently from other compilers (in-
cluding .Net), with different resultant code and different warnings and error mes-
sages. Furthermore, the Win32 API is, obviously, not available on the PS2 or
GameCube, and only partially implemented on the Xbox. So, anyone who’s used to
OpenFile should get used to something else.
Another important, but also less obvious problem in this scenario, is the fact
that the byte order of the data on a GameCube is different from the PC. This is
known as endian-ness and makes it more difficult to load binary data (such as
graphical texture images) into memory. A number saved as 0x12345678 on the PC
(which is Little Endian) appears as 0x78563412 when loaded into a GameCube (a
Big Endian machine). Although the endian-ness of a number is of no concern while
it remains within memory, as soon as it is transferred to or from disk, the data
needs to be converted.
Finally, those working on the console-side of cross-platform development
don’t even have the luxury of a monitor to preview their work. Consoles have tele-
vision sockets. That means low resolution (usually a 480 horizontal line maxi-
14 Cross-Platform Game Programming
mum), color bleed, and brightness and contrast settings that can (and will) vary ex-
tensively between make, model, and age of the TV. Although the visuals are nor-
mally a problem assigned to artists, the inability to display more than a few lines of
debugging text onscreen can be prohibitive for the programmer.
Console Limitations
When working on the PC platform (under Windows, Linux™, or BSD™), you have
remarkably few limitations. If the game runs too slowly, buy a faster processor. If
the graphics aren’t good enough, add more polygons, increase the texture sizes, and
upgrade the graphics card. If you can only play five gunshot noises at once, replace
the sound card. In some cases, you can even just postpone the game for six months
until the entry-level PC hits a suitable specification to show off your game at its
best.
Unfortunately, console programmers have none of these benefits. The console
machine you have now is the only version of the machine you need to consider be-
cause it cannot be upgraded2 with more RAM, a different graphics card, or a faster
processor. There’s no swap file to fall back on if memory gets tight or easy upgrade
path to cover hardware bugs. Although these problems are not unique to cross-
platform development, their effect multiplies when you have to simultaneously
consider these effects on different machines. For example:
The memory footprint for the level data might be 12 MB, 20 MB, or 40 MB.
The same code might compile to 4 MB, 6 MB, or 12 MB.
The graphics engine might be bound by fill rate on one platform, and compu-
tation on another.
The CPU might be fast enough to process all the Artificial Intelligence (AI) in
one frame, or it might not.
Any number of other equivalent problems can also occur.
Each console is a finely balanced machine. If it’s lacking in one area, another
area is usually super-charged to compensate. This ensures that each console, when
considered on its own merits, is roughly as good as its competitors. When the same
game needs to run across all platforms, you have to either look for ways to scale
back certain features (perhaps the AI will only think every other frame), or build
everything to run on the lowest common denominator and pad out the game with
bonus code in each particular area where the console is under-used.
Several methods for tackling this problem are covered later in the book. No
matter which method is used, programmers (along with artists and designers)
need to take the initiative, consider the limitations, agree to the confines, and stick
to them.
Introduction 15
The Processor(s)
The processor(s) will always be fixed, but you need to take into account whether
there is one large behemoth CPU that controls everything, or if the work needs to
be split between a lot of smaller, slower chips.
Working with a single CPU means that every game feature will (more than
likely) run in sequence. So if the AI takes a little longer to process, the graphics en-
gine can compensate by using a lower level of detail when rendering the meshes. In
contrast, having separate CPUs running in parallel means the game can only be as
fast as the slowest process. If this is the AI (for example), how does it react if more
enemy characters are being processed? To use the vernacular, does it scale?
Disk Access
Disk access has two main variables: speed and size. If the disk is very slow (in com-
bined terms of latency and transfer rate), but the processor is fast, then it’s a fairly
simple process to store all the data on the disk in a compressed format, and de-
compress it while it’s being read. Conversely, the opposite may be true. Addition-
ally, the disk size might be small (having to reside on a 650-MB CD-ROM, instead
of a 4.7-GB DVD), necessitating the need for compression, but the processor will
then require a larger memory buffer to handle the decompression within a reason-
able time frame. As we said before, this problem may exist on any of the consoles,
but the method for handling it in each specific case will vary depending on the plat-
form. This in turn will have an impact on the tool chain, and the way in which
artists create their work.
Libraries
One beneficial facet of cross-platform development is the ability to use stan-
dard libraries. These might be Open Standards (with a capital “O”) such as
OpenGL or Simple Directmedia Layer (SDL), closed ones such as RenderWare® or
Gamebryo®, or internal ones developed by the in-house technology team or senior
developers. Each library allows multiple platforms to be serviced directly through a
common API, abstracting the hardware—and operating system-specific—details
away from the game code.
Employing such a library prevents you from having to reinvent a lot of wheels,
and there are many examples on the Web of OpenGL code that’s been written for
Unix®, but works flawlessly on Windows, and vice versa. A few years ago, a com-
pany called Loki Entertainment ported Windows games to Linux by modifying ex-
isting DirectX® code to use the SDL API instead. In both of these cases, the
common interface between platforms helped speed up development.
A common API is essential in a cross-platform engine; but it isn’t the only re-
quirement for a cross-platform project. After all, a computer game is more than just
16 Cross-Platform Game Programming
its engine, the engine is not just the graphics code, and the graphics code is not de-
fined by its capability to push polygons. The following paragraph will tackle these
issues in order.
The game engine needs to consider how to access the disk and allocate mem-
ory. These simple tasks take on a new complexity in our world. The sample code for
an OpenGL application might read a text file using the fopen function, for example.
This is part of the C standard library, and not guaranteed to exist on a games con-
sole. Even when it does exist on the consoles for which you’re currently developing,
the function must exist on all of them to be used effectively. Will your publisher
come back after a year and say “It’s going well, here’s some cash, just do another
port?” If so, every instance of fopen will have to be retroactively replaced. Further-
more, fopen is a blocking function, which means it doesn’t exit until it has com-
pleted its task. In a single threaded environment, this means the whole machine
cannot do anything until the file has been opened. If the disk cover is open or the
CD-ROM has been removed, you won’t be able to access the file, and because the
program has been suspended, you won’t be able to print a message onto the screen
saying “Please put the disc back in” either. On its own, the standard library isn’t
powerful enough. It was never intended to be. So we either need to create an ab-
straction layer for the filesystem to hide our use of nonstandard library calls, or
make sure we’re always using threads. In reality, we’ll use an abstracted filesystem
anyway because it provides other benefits. We’ll also often employ an abstracted
thread library because the most common threading library, pthreads, is not avail-
able on consoles since they exist within a different set of standards. Not only that,
but after you have abstracted the basic filesystem, you need to handle the different
conventions for filenames. Windows uses names that appear as, c:\projects\
game\mymesh, whereas Linux might use /home/steev/game/mymesh. Furthermore, file-
names might be case sensitive or limited to a certain number of characters. All
these possibilities need to be considered.
In the same vein, the graphics code is not just about drawing the polygons. The
polygonal mesh data needs to come from somewhere, so most sample code or mag-
azine articles include a list of vertices in an array, hard-coded into the source. In the
real world, this cannot work because the amount of game data easily outstrips avail-
able memory. Instead, you need to write a data-driven component that loads arbi-
trary data from an external package and prepares it for the graphics code. This
again uses the abstracted filesystem, but it also uses platform-specific code to set up
the graphics chip correctly. In addition, we’ll also need some extra cross-platform
resourcing code that allows the game to reference these (platform-specific) poly-
gons from our (common) code, because we must be able to say “draw this object in
this position.”
In theory, you only need a single rendering function to write a 3D graphics en-
gine—DrawOnePolygon—but the overhead of sending each polygon individually to
Introduction 17
the hardware is prohibitively expensive. Instead, each hardware API will have its
own method for storing and referencing groups of polygonal data that has no rele-
vance to the outside world, or any other API. This platform-specific data then needs
to be manipulated in a cross-platform manner for tasks such as collision, move-
ment, and animation. This often requires a duplicate set of structures for each of
render data and collision data. This apparent waste will pay for itself very quickly,
however, with the increased ease by which all platforms can optimize their specific
half of the equation without intruding on the other half.
I
n attempting to deliver as much information as possible, code explanations are
kept to a minimum, all utilizing the same rules and guidelines as follows.
Coding Style
Throughout the text, code samples are given either in their entirety or in frag-
ments. They have been taken from the author’s own engine and chosen to illustrate
the points within the text. The naming conventions used within the code are:
We’ve chosen this naming convention for two reasons. First, and most obvi-
ously, it highlights the cross-platform abstractions that exist within the function
and reminds us of the task at hand. Second, by including uppercase letters in the
18 Cross-Platform Game Programming
name, it cannot conflict with any of the standard C types, functions, or other third-
party library’s features.
Several functions and classes are also prefixed with letters such as PS2, Xbox, or
GC. Again, these are meant to illustrate examples, and no connection with the ac-
tual platform or its API should be inferred.
NON-DISCLOSURE AGREEMENTS
There have been many dissenting voices about the use of NDAs, with them being
called “the scourge of our industry” and “monopolistic.” Many find it strange that
a scientific discipline such as computing should hide behind this cloak, allowing us
to stand only on the shoulders of proverbial giants in our local vicinity. But there is
nothing we can do about this. All consoles have an NDA, and we must abide by it.
To that end, we cannot, and will not, reveal any secrets about the APIs for PlaySta-
tion 2, Xbox, or GameCube. Nor will there be any named functions, macros, or
magic numbers. All the information presented in this book, including the machine
specifications shown in the appendixes, has been gleaned from magazines, press
packs, clean room engineering projects, and numerous Web sites around the world.
These appendixes have been presented separately because a side-by-side compari-
son is both unfair and nonrepresentative. After all, the clock speed of the G5™ and
Intel processors do not reflect their relative power. Where a direct comparison is
not possible or the information is under NDA (or could not be ascertained from a
public source), the entry is left blank.
Any time the workings of a platform need to be explained, imaginary stub
functions will be invented to process the theoretical data, and return theoretical re-
sults. There is no connection, intentional or otherwise, between the name used
here and that of the official version. Wherever possible, samples will use openly
published APIs such as OpenGL and DirectX.
All the examples given within the text are correct at the time of going to press.
However, tools change, compilers are updated, libraries are patched, and new bugs
are added. It is entirely possible that a particular example might fail to work in ex-
actly the same manner as given here. That’s life. This doesn’t negate the point itself,
but reiterates it. Along with the fundamental rules of test, test, and test again. The
principle arguments are exactly the same.
Introduction 19
ENDNOTES
1. All consoles have a list of requirements that the game must fulfill to be
approved by the manufacturer before release. These lists vary between con-
soles, and are private. It dictates criteria such as maximum load time and
the wording for various error messages.
2. Even when the console does support upgrades (such as with broadband
adapters), you still need to work toward the lowest common denominator;
that is, a machine without upgrades.
This page intentionally left blank
2 Top Ten Tips
In This Chapter
Abstraction
Commonality
Limitations
Modularization
Resource Creation Path
Granularity
Separation and Isolation
Debugging and Profiling
Predictability
Turn-Around
Cross-platform development is an issue that affects a game’s entire code base. The
graphics and audio programmers aren’t the only ones that have a job to do. All pro-
grammers working on the game need to always remember that their code will be
compiled, run, and very often debugged on platforms other than the one on which
it was originally written and tested. This might seem obvious, but it’s frequently
overlooked. What difference does it make anyway? Why isn’t it enough to use the
C language?
To explain this, we offer a number of fundamental ideas that need to be ad-
hered to across all code within the cross-platform environment. With so many dif-
ferences between platforms, we need to know how to consider, cover up, or isolate
those differences. Each idea is supplemented with code samples, demonstrating
21
22 Cross-Platform Game Programming
where the methods can be applied. The methods can be applied elsewhere as well;
example-ridden references to the filesystem will contain ideas that are just as
applicable to the audio code, input library, or network code.
ABSTRACTION
If this book were condensed into a single paragraph, line, or word, the word
Abstraction would be on the short list of words to use. It is the cornerstone of every-
thing we do. Abstraction means to generalize, ignoring details and specifics. For
programmers, it’s being able to write code without being concerned about the
hardware, and knowing in advance that the behavior of every platform will be iden-
tical—not similar, but identical. Everything you do needs to be abstracted in some
way and at some level. Even the code you write, although it’s all C, is just an ab-
straction. It abstracts the low-level machine code away, allowing you to write a
more general program. When you declare an integer variable, for instance, you’re
abstracting a datatype. When you read from a file, you’re abstracting the filesystem,
and so on. Some abstractions are simple, consisting of nothing more than a well
placed #define or typedef in a header file. Sometimes they are more complex,
where one function hides a wealth of code behind a simple nomenclature, such as
PlayThemeMusic.
What matters is that when you abstract something, no side effects are intro-
duced in the process. For example, the standard library function qsort hides the
basic implementation details from you, but it doesn’t behave identically on all plat-
forms because each compiler will provide its own implementation of qsort. Be-
cause the language specification isn’t strict enough to prevent side effects, qsort
only has to perform a sort, not necessarily a quicksort. An example of this difference
can be seen if the qsort function is required to sort a list containing two identical
primary keys. In that case, the algorithm (not the qsort callback function) is re-
sponsible for the list’s final order. The strict requirements placed on cross-platform
development mean that functions with side effects are unacceptable.
So what needs to be abstracted?
COMMONALITY
LIMITATIONS
Every part of the game development process involves limitations that you must
overcome. A cross-platform game has more limitations than most, and extends be-
yond the usual questions about polygon counts. You also need to consider the lan-
guage, compiler, and its libraries.
Language Limitations
The first limitation to overcome is the language. If we succumb to these limitations,
we can’t even compile our game, let alone run it to the point of exhaustion. The
language in question is probably C or C++, so we must focus our attention on the
minutiae of C—namely, standard C.
A programming language is usually learned by example. We copy the code
samples in our book of choice, change them, add to them, delete bits from them,
and make them our own. As time goes by, we collect more examples. Rarely do we
Top Ten Tips 25
look behind the scenes of a language to find out what makes it tick and why the ex-
amples work the way they do. When a lot of our work is in a single environment
(perhaps the PC—usually under Microsoft Windows, but more frequently under
Linux), we adapt our coding style to the compiler and platform we are using (often
subconsciously). This might include involuntary use of vendor-specific functions
that appear in the so-called standard libraries (such as _gvct, or stricmp), compiler-
specific extensions (such as the <? operator), or special datatypes (such as qword). In
extreme cases, you might be tempted to write code for a specific compiler to gain
extra speed. It’s imperative that every line of code written for a cross-platform pro-
ject is completely standard to ensure that the code cannot be misinterpreted in any
way, by any compiler.
To illustrate this point, consider these questions concerning language.
Language Questions:
1. How many bytes constitute a long variable?
2. Is a char signed or unsigned, by default?
3. What is the value of a after this code?
int a = 1;
a = a++;
4. What is the value of sizeof(‘a’)?
5. In which directory does the header file live, given the following code?
#include “graphics.h”
Language Answers:
1. Depends on the platform. Usually 4 bytes on a 32-bit machine, but it’s 8 on
the PlayStation 2.
2. Depends on the compiler. You must explicitly state signed or unsigned
when using chars. All font code, for example, should use an unsigned char
to cope with accented characters. Games using Unicode will use their own
(nonchar oriented) datatype.
3. Depends on the compiler. The expression is undefined because the value of
a is changed twice before the sequence point (that is, the semicolon, in this
example). It could be 1 or 2, or, in really perverse compilers, 934537.
4. Depends on the language. If it’s compiling as C, it will be compiler-
dependent, and its result will be identical to sizeof(int). When compiled a
as C++, it will report 1 byte.
5. Depends on the compiler. The double quotes usually mean current direc-
tory, but if used within a header file, the compiler might interpret this as
the directory of the current header file, or the source file where the com-
piler started building. This makes it inadvisable to nest headers in different
directories, although in practice this is difficult to avoid.
26 Cross-Platform Game Programming
As you can see, building the code to see what the compiler does is not good
enough because you’ll ultimately be building the game with more than one com-
piler. Cross-platform programming requires a deeper understanding of the lan-
guage. The only way you can acquire this knowledge is by reading. Your first stop
should be comp.lang.c newsgroup’s excellent FAQ at http://www.faqs.org/faqs/C
faq/faq/index.html. This FAQ contains many good questions and answers concern-
ing how to handle several tricky constructs. Should the phrase “not portably” ap-
pear in the answer, avoid using it, even if it appears to work on your current set of
compilers.
For a more definitive, but slightly drier, coverage of the language, the best doc-
ument to read is the ANSI® standard itself. The ANSI standard is a big, and occa-
sionally unwieldy, document that describes every facet of the C language, and what
each compiler must implement to be considered “ANSI-compliant.” Any compe-
tent programmer can understand most (if not all) of this document. Experienced
programmers with a good working grasp of the language can avoid this step.
The completed ANSI/ISO® standard is not free,1 although the final draft can be
downloaded from the Internet. Some choose to purchase the much less expensive
book entitled The Annotated ANSI C Standard instead;2 although its annotations
are sometimes wrong or misguided. It is, however, an inexpensive way to get the
majority of the standard, but keep in mind that not all of the standard is included.
This might appear like a lot to read, but it’s easier to learn what is legal (and
apply only that knowledge), than it is to learn every extension on every platform
and explicitly avoid them. After all, the legal features constitute a finite set. How-
ever, it is possible to make an educated guess as to what is nonstandard. For in-
stance, any function or macro featuring one or more underscores is probably an
extension (size_t is one notable exception). Those that begin with an underscore
are almost certainly extensions. Any function name in MixedCapitals is probably an
extension, too. This is a sign of Hungarian Notation, which originated from Charles
Simonyi at Microsoft.
In contrast, names that are comprised solely of lowercase alphabetic characters
are likely to be standard, unless they’re the typical gotchas, such as stricmp. If in
doubt, look for the prototype in the header files. It’s very likely such names will be
sandwiched between #ifndef __STRICT_ANSI macros, or similar. The MSDN® has
extensive (and very good) documentation on the standard library. Under .NET,
pressing #F1 on any library function opens the appropriate help page for you and
states whether the function is a Microsoft extension.
As always, prevention is better than cure. Most compilers provide a way to
switch off these extensions, either through a dialog box or a macro that must be de-
fined before including any standard header files. Depending on the compiler, this
can be more trouble than it’s worth because each platform likely needs these exten-
sions to pack structures correctly, or to use specific datatypes that access and con-
Top Ten Tips 27
trol the hardware. With careful modularization, you can limit these occurrences
and compile the game under a strict ANSI compiler.
Although we have concentrated on C here, the same ideas apply to C++.
There’s just more scope in C++ for problems. For example, the construction order
of globally instantiated classes is not fixed, so any interdependencies will not behave
portably (we’ll cover this in Chapter 11, “The Bits We Forget About”). Fortunately
for the game programmer, after the basic architecture has been completed, any
new functions only use a small, well-known subset of C++, such as references, tem-
plates, and the standard template library (STL).
Some of the more complex templating techniques will not work under some com-
pilers. One typical example is partial template specialization, which fails under
Microsoft Visual C++ 6.0.
Library Limitations
For any C compiler to be ANSI-compliant, it must have a set of standard libraries.
C++ also includes the standard template library (STL). All of these are standard,
tested components that can be used without fear in a gaming environment. Unfor-
tunately, a cross-platform gaming environment might raise problems because the
implementation might differ slightly between compilers, as you’ve already seen
with the qsort function.
STL implementations also differ between platforms. Even the versions on PC
and Xbox (despite their heritage) are different from each other. If you are using STL
out-of-the-box for basic single platform work, then the default implementation is
usually good enough because it behaves well enough for end users to consider it
identical to anything they’ve used before.
On the other hand, if you use your own memory management code, you might
need to work around specific issues in STL. The amount of work will increase as ef-
fort is duplicated across each specific implementation and each platform. In these
situations, you might decide to ignore your vendor’s implementation, and use a set
of third-party libraries, such as STLPort (http://www.stlport.org), or those provided by
Boost (http://www.boost.org). This is a case when reinventing the wheel is a good
thing. Only here, someone else has done the reinventing for you. You just need to
test it.
Compiler Limitations
We rarely need to consider compiler limitations because the compiler’s sole job is
to implement the language standard, and we only practice our art according to that
standard. However, you should consider four issues about compiler limitations.
28 Cross-Platform Game Programming
Standard Interpretations
Standards are good, but there are so many to choose from. Although a compiler can
adhere to the letter of the law, it doesn’t necessarily behave according to the spirit.
This might be due to bugs in the compiler, extensions that cannot be switched off,
or undefined behavior that is permitted by the standard. However, before your
project ships, you’ll find at least one really annoying problem that exists between
compilers: variable scope in C++, for example.
The loop counter i exists only between the braces because that is its scope. It in-
crements from 0 to 9, and forces the loop to exit when it reaches 10. This is true of
every compiler.
When the loop terminates at 10, i goes out of scope and it is destroyed. This is
not true of every compiler. Some compilers do not destroy i, allowing it to be used
in another loop later on in the function. This causes problems when another loop
in the same function declares i again—perhaps in another for loop. This produces
a “redeclaration of i” error on some compilers. If the declaration is removed, then
every other compiler will complain that i hasn’t been declared. The solution is
simply to move the declaration outside the for loop.
Under Visual C++, this error can be avoided by using the Disable Language Ex-
tensions option; however, this can cause more problems than it solves because some
of the official header files are not compliant. .NET 2003 does not suffer this prob-
lem because a better option is available in the form of /Zc:forScope.
Creating these workarounds is a nuisance, but that’s par for the course with
cross-platform development. To stop other developers from falling into the same
traps, you should create a small document of these differences, and keep it in your
source control tool. If you work with code reviews, reference that document as
part of your process.
Next are the features that exist in all compilers, but in different forms. For ex-
ample, to distinguish between a release and debug build of the game, the compiler
often predefines a special symbol. A debug build might be indicated with any of the
following:
DEBUG
NRELEASE
_DEBUG
__DEBUG
DEBUG_BUILD
The vendor could also use any other macro it deems appropriate. These macros
could be declared with either
#define DEBUG
or
#define DEBUG 1
Because each platform requires a different compiler, we can’t rely on any par-
ticular standard and so must create a separate header file for each platform-
compiler combination like this:
#if SGX_DEBUG_BUILD
#endif
Title: Wolf Ear the Indian: A story of the great uprising of 1890-91
Language: English
EDWARD S. ELLIS
Author of "Captured by Indians," "A Hunt on Snow Shoes,"
"The Mountain Star," etc. etc.
SEVENTEENTH THOUSAND
CASSELL AND COMPANY, LIMITED
London, New York, Toronto and Melbourne
CONTENTS
CHAPTER I.
"The bullet had passed startlingly near him"
CHAPTER II.
"He's up to some mischief, I'll warrant"
CHAPTER III.
"There are fifty hostiles"
CHAPTER IV.
"We are enemies"
CHAPTER V.
"What will be their next step?"
CHAPTER VI.
"Ay, where were they?"
CHAPTER VII.
"It came like one of them Kansan cyclones"
CHAPTER VIII.
"The bucks were coming up alarmingly fast"
CHAPTER IX.
"He has made his last scout"
CHAPTER X.
"Oh, there is Wolf Ear?"
CHAPTER XI.
"I'm off! Good-bye!"
CHAPTER XII.
What happened to Wolf Ear
LIST OF ILLUSTRATIONS
"I'm off! Good-bye!" ... Frontispiece
"Hurrah!"
[Transcriber's note: the first three illustrations were missing from the source
book.]
WOLF EAR THE INDIAN
CHAPTER I.
Perhaps some of you share the general mistake that the American Indians
are dying out. This is not the fact. There are to-day more red men in the
United States than ever before. In number, they exceed a quarter of a
million, and though they do not increase as fast as the whites, still they are
increasing.
It is true that a great many tribes have disappeared, while others that
were once numerous and powerful have dwindled to a few hundreds; but on
the other hand, tribes that were hardly known a century ago now include
thousands.
The many wars between the United States and the Indians have been
caused, almost without exception, by gross injustice towards the red men.
They have been wronged in every way, until in their rage they turned
against their oppressors. The sad fact at such times is that the ones who
have used them so ill generally escape harm, while the innocent suffer. The
Indian reasons that it is the white race that has wronged him, so he does
them all the injury he can, without caring whether the one whom he slays
has had a hand in his own persecution.
The Indian, like all savages, is very superstitious. He loves to think over
the time, hundreds of years ago, when the red men roamed over the whole
continent from ocean to ocean. He dreams of those days, and believes they
will again return—that the pale faces will be driven into the sea, and the
vast land become the hunting ground of the Indians.
Some years ago this strange faith took a wonderfully strong hold upon
those people. The belief spread that a Messiah was coming in the spring of
1891, who would destroy the pale faces and give all the country back to the
red men. They began holding wild dances, at which the dancers took hold
of hands and leaped and shouted and circled round and round until they
dropped to the ground, senseless and almost dead. These "ghost dances," as
they were called, were carried on to please the new Messiah. When the
dancers recovered, they told strange stories of having visited the other
world. All who listened believed them.
The craze spread like wildfire, and before the Government understood
what was going on, the Indians were making ready for war. They were well
armed, eager to attack the whites. The principal tribe was the Dakota or
Sioux, the most powerful on the American continent.
The leading chief or medicine man was Sitting Bull. He was a bad man
who had made trouble for more than twenty years. He could not endure the
white men, and, when not actively engaged against them, was thinking out
some scheme of evil.
Now, if you will look at your map of the United States, you will notice
that the Missouri River runs across the middle of the new State of South
Dakota. On the southern boundary of the State, a large tract of land,
reaching one-third of the way westward to Wyoming, and with the White
River forming in a general way the northern boundary, makes what is
known as an Indian reservation.
There are many of these in the West. They belong to the Indians, and the
Government has an agency at each, to see that no white people intrude. The
Indians are forbidden to leave these reservations without obtaining
permission, and at the agencies they receive the annuities or supplies paid to
them by the United States Government for the lands elsewhere which they
have given up.
If your map of South Dakota is a complete one, it will show you a small
stream to the westward of Pine Ridge, named Raccoon Creek, a tributary of
Cherry Creek, itself a branch of the Big Cheyenne River.
The family had emigrated thither three years before from Kansas, and all
would have gone well in their new home, but for the illness of Mr.
Kingsland.
Something in the climate disagreed with him, though the rest of the
family throve. He was first brought low with chills and fever, which after
several months' obstinate fight finally left him weak and dispirited. Then,
when he was fairly recovered, the slipping of an axe in his hands so
wounded his foot that he was laid up for fully two months more.
His wife was well fitted to be the helpmate of a pioneer, for she was
hopeful, industrious, strong, and brave. She carefully nursed him, making
light of their afflictions, and declaring that all would soon come right, and
that prosperity would prove the sweeter from having been deferred so long.
Sometimes Hugh Kingsland wondered after all whether he was not the
most fortunate individual in the world in being thus blessed in his family
relations.
And there was another from whom the meed of praise must not be
withheld. That was Brinton, now close upon seventeen years of age. The ill-
fortune to which we have alluded made him in one sense the virtual head of
the family. He was strong, cheerful, and resembled his mother in his
hopeful disposition. The difficulties in which his father was continually
involved brought out the real manhood of his nature. He looked after the
cattle and live stock, galloped across the plains to Hermosa, Fairburn, Rapid
City, and other points for supplies or on other business, or, fording the Big
Cheyenne, White, and smaller streams, crossed the reservation to Pine
Ridge.
The youth was indispensable, and did his work so well, that the father, in
his occasional moments of rallying, remarked that he thought of continuing
to play the sick man, since it was proved that he was of no account.
"I hope you will soon become well," said the red-cheeked lad one
evening, as the group gathered around the fire; "but stay here in the house
as long as you wish, for mother and Edith and I can get along without your
help."
"Yes, husband; don't fret over that. Only become well, and until you do
so, be assured that everything is going along as it should."
"I have never had a doubt of that; but, ah me," he added with a sigh, "this
is tiresome after all, especially when it begins to look as though I shall
never be well again."
"For my part," said Edith very earnestly, "I don't want you to get well,
and I am praying that you will not."
"Why, Edith!" exclaimed the mother reproachfully, while her brother did
not know whether to laugh or be shocked at the odd expression. As for the
father, he laughed more heartily than he had done for weeks.
Edith looked wonderingly in their faces, and felt that some explanation
was due to them.
"I mean to say—that is I don't mean anything bad, but if papa gets well
enough to ride out to look after the cattle, and is working all day, why, I
won't have anyone to tell me stories and read to me and do so many funny
things."
"Your explanation is satisfactory," said her father, smiling. "I shall have
to stay in the house for some weeks—that is certain, and perhaps longer."
"Oh, I am so glad!"
But with the first clapping of the chubby hands, Edith realised that she
was doing wrong again, and she added in a gentler voice—
"If papa feels bad when he is ill then I am sorry for him, and will pray
every night and morning that he may get well."
It was winter time, and the Kingslands in their humble home could not
be ignorant of the alarming state of affairs around them. They had been
urged to come into the agency while it was safe to do so, for the revolt
among the Indians was spreading, and there was no saying when escape
would be cut off. The family had considered the question with the
seriousness due to so important a matter.
Naturally, they were reluctant to abandon their home now, for it would
be virtually throwing away everything they owned in the world; but when it
became a question of life and death, there could be no hesitation.
On the very night, however, that the decision to remove to the agency
was made, Sergeant Victor Parkhurst, who was out on a scout, with a squad
of men from Pine Ridge, called at their home and stated his belief that no
trouble would occur. He said it would be better if the family were at Pine
Ridge, and he offered to escort them thither. But, he added, that in Mr.
Kingsland's feeble condition it would be as well for him to stay where he
was, since he must run great risk by exposure in the depth of winter.
The next caller at the cabin was Nicholas Jackson, who had been a scout
under General Crook, and was now serving General Miles in the same
capacity at Pine Ridge. He brought news of Sitting Bull's death, and assured
the pioneer that every day spent by him and his family away from the
agency increased their peril.
"You shouldn't delay your start a single hour," was his remark, as he
vaulted upon his pony and skurried away.
But with his usual pluck, he chirruped to his pony, lightly jerked his
bridle rein, and the gallant animal was off at a swinging pace, which he was
able to maintain for hours without fatigue. He was heading south-east, over
the faintly marked trail, with which the youth was familiar and which was
so well known to the animal himself that he needed no guidance.
Two hours later, the young horseman reached the border line of Custer
and Washington counties, that is between the county of his own home and
the reservation. This was made by the Big Cheyenne River, which had to be
crossed before Pine Ridge was reached. Brinton reined up his horse and sat
for some minutes, looking down on the stream, in which huge pieces of ice
were floating, though it was not frozen over.
"That isn't very inviting, Jack," he said, "but the ford is shallow and it's
no use waiting."
He was in the act of starting his pony down the bank, when on the heavy
chilly air sounded a dull explosive crack. A nipping of his coat sleeve
showed that the bullet had passed startlingly near him. He turned his head
like a flash, and saw, not more than a hundred feet distant, the figure of a
Sioux buck or young warrior bareback on his horse, which was standing
motionless, while his rider made ready to let fly with another shot from his
Winchester rifle.
CHAPTER II.
The Indian was no older than himself, sitting firmly on the bare back of
his horse, with his blanket wrapped about his shoulders, and several stained
eagle feathers protruding from his hair, as black and coarse as that of his
pony's tail. His dark eyes glittered as they glanced along the barrel of his
rifle, and he aimed straight at the breast of the youth, who instead of
flinging himself over the side of his horse in the attempt to dodge the
deadly missile, sat bolt upright and aimed in turn at the miscreant, who, as
if stirred by the same scorn of personal danger, remained firmly in his seat.
It all depended on who should fire first, and that which we have related
took place, as may be said, in the twinkling of an eye.
But with the weapons poised, the eyes of the two glancing along the
barrels and the fingers on the triggers, neither gun was discharged. Brinton
was on the point of firing, when the Indian abruptly lowered his Winchester,
with the exclamation—
"Hoof! Brinton!"
The white youth had recognised the other at the same instant when
another moment would have been too late. He, too, dropped the stock of his
gun from his shoulder and called out with a surprised expression—
"Wolf Ear!"
The Indian touched his pony with his heel, and the animal moved
forward briskly, until the riders faced each other within arm's length.
"How do you do?" asked the Ogalalla, extending his hand, which
Brinton took with a smile, and the reproving remark—
"I did not expect such a welcome from you, Wolf Ear."
"I did not know it was you, good friend Brinton."
"And suppose you did not; are you the sort of warrior that shoots another
in the back?"
The broad face, with its high cheek bones, coppery skin, low forehead
and Roman nose, changed from the pleasant smile which gave a glimpse of
the even white teeth, to a scowl, that told the ugly feelings that had been
stirred by the questioning remark of the white youth.
"Your people have become my enemies: they have killed Sitting Bull,
Black Bird, Catch-the-Bear, Little Assiniboine, Spotted Horse Bull, Brave
Thunder, and my friend, Crow Foot, who was the favourite son of Sitting
Bull. He was as a brother to me."
"And your people have killed Bull Head, Shave Head, Little Eagle,
Afraid-of-Soldiers, Hawk Man, and others of their own race, who were
wise enough to remain friends of our people. I know of that fight when they
set out to arrest Sitting Bull."
"They had no right to arrest him," said Wolf Ear, with a flash of his black
eyes; "he was in his own tepee (or tent), and harming no one."
"He was doing more harm to his own people as well as ours, than all the
other malcontents together. He was the plotter of mischief; he encouraged
this nonsense about the ghost dances and the coming Messiah, and was
doing all he could to bring about a great war between my people and yours.
His death is the best fortune that could come to the Indians."
"It was murder," said Wolf Ear sullenly, and then, before the other could
frame a reply, his swarthy face lightened up.
"But you and I, Brinton, are friends; I shot at you because I thought you
were someone else; it would have grieved my heart had I done you harm; I
am glad I did not; I offer you my hand."
Young Kingsland could not refuse the proffer, though he was far from
feeling comfortable, despite his narrow escape a moment before.
"I thought you were a civilised Indian, Wolf Ear," he added, as he
relinquished the grasp, and the two once more looked in each other's
countenances; "you told me so when I last saw you."
Wolf Ear, the Ogalalla, was sent to Carlisle, when only eight years old.
Unusually bright, he had made good progress, and won the golden opinions
of his teachers by his gentle, studious deportment, and affection for those
that had been kind to him.
He spoke English as well as the whites, and was a fine scholar. He went
back to his people, when sixteen years old, and did what he could to win
them from their savagery and barbarism.
He and Brinton Kingsland met while hunting at the base of the Black
Hills, and became great friends. The young Ogalalla visited the white youth
at his home on Raccoon Creek, where he was kindly treated by the
Kingslands, and formed a deep affection for little Edith.
But nothing had been seen of Wolf Ear for several months. The home of
his people was some distance away, but that should not have prevented him
from visiting his white friends, who often wondered why he did not show
himself among them.
"You believe in the coming of One to save your people—why should not
we place faith in the coming of our Messiah?" was the pertinent question of
Wolf Ear.
Brinton Kingsland listened, amazed as this expression fell from the lips
of one who had often lamented the superstition of his own race. That he
believed the words he uttered was proven by his earnestness of manner and
the glow of his countenance. The white youth restrained his impulse to
ridicule the strange faith, for that assuredly would have given offence to the
fanatic, who had the right to believe whatever he chose.
"Well, Wolf Ear, I can only say I am sorry that you should have been
carried away by this error——"
"By what right do you call it error?" interrupted the other with a flash of
his eyes.
"We will not discuss it. It will do no good, and is likely to do harm. I
need not be told that you belong to the hostiles, and, if trouble comes, will
fight against the whites."
"Yes, you are right," calmly replied the Ogalalla, compressing his thin
lips and nodding his head a single time.
"Your father and brother, whom I have never seen, would shoot me and
my folk if they had the chance."
"Yes, and so would my mother: she is a warrior too."
"But suppose you and I or my father meet, or you have the chance to
harm my mother and little sister, Edith?"
"Wolf Ear can never raise his hand against them, no matter what harm
they may seek to do him. I do not have to tell you that you and I will always
be friends, whatever may come."
This assurance would have had more weight with young Kingsland
could he have felt certain that Wolf Ear was truthful in declaring that he did
not suspect his identity at the moment of firing at him.
"I believe he meant to take my life," was his thought, "and still meant to
do so, when he raised his Winchester a second time, but as we looked into
each other's face, he weakened. His people are treacherous, and this
pretence of goodwill will not last, or, if it be genuine for the present, it will
soon change."
Brinton said—
"You know where we live, Wolf Ear; I have set out to ride to the
reservation to learn whether it is safe to stay where we are: what is your
judgment in the matter?"
An indefinable expression passed over the broad face before him. The
Ogalalla sat gracefully on his horse, even though he had no saddle. A bit
was in the pony's mouth, the single rein looping around the neck and resting
at the base of the mane, just in front of the rider, who allowed it to lie there,
while the two hands idly held the rifle across the back of the animal and his
own thighs.
"You stayed too long," said he; "you should have left two weeks ago; it
is too late now."
"But you know my father is not well, Wolf Ear," replied Brinton, with a
sickening dread in his heart.
"What has that to do with this?"
"We did not wish to expose him to the severe weather, as we must in the
ride to the agency."
"Then you have gained nothing and will lose all by your delay."
Brinton had no further wish to discuss the ghost dance and the coming of
the new Messiah with the young Ogalalla. All his thoughts were of those
dear ones, miles away, whose dreadful peril he now fully comprehended for
the first time. He saw the mistake that had been made by the delay, and a
faintness came over him at the declaration of Wolf Ear that this delay was
fatal.
His horse was facing the north-west, the direction of his home. There
was no call for longer tarrying.
"Good-bye," he said, giving the Indian a military salute; "I hope we shall
meet ha more pleasant circumstances, when you shall see, Wolf Ear, the
mistake you are making."
Trained in the ways of the white people, the dusky youth raised his hand
to his forehead, and sat motionless on his horse, without speaking, as his
friend dashed across the plain, over the trail which he had followed to the
banks of the Big Cheyenne.
It was not yet noon, and Brinton was hopeful of reaching home long
before the day drew to a close. The chilliness of the air continued, and a few
feathery flakes of snow drifted horizontally on the wind or were whirled
about the head of the young horseman. He glanced up at the leaden sky and
noted that the temperature was falling.
"Like enough we shall have one of those blizzards, when the horses and
cattle freeze to death under shelter and we can only huddle and shiver
around the fire and wait for the tempest to pass. It will be the death of us all,
if we start for the agency and are caught in one of the blizzards, but death
awaits us if we stay. Ah me, what will become of father, ill and weak as he
is?"
The words of Wolf Ear made the youth more circumspect and alert than
when riding away from his home. He continually glanced ahead, on his
right and left and to the rear. The first look in the last direction showed him
the young Ogalalla sitting like a statue on his pony and gazing after him.
Some minutes later, when Brinton turned his head again, he saw him
riding at a rapid pace towards the north, or rather a little west of north, so
that the course of the two slightly diverged.
"They will soon unite, and when they do he will be the fiercest warrior
among them. I wonder——"
To the westward the Black Hills thrust their vast rugged summits against
the wintry sky; to the south, a spur of the same mountains put out toward
the frontier town of Buffalo Gap; to the north-east wound the Big
Cheyenne, on its way to the Missouri, and marking through a part of its
course the southern boundary of the Cheyenne Reservation, while creek,
stream, and river crossed the rolling plain that intervened, and over all
stretched the sunless sky, from which the snow-flakes were eddying and
whirling to the frozen earth below.
But Brinton Kingsland had no eye for any of these things, upon which he
had looked many a time and oft. His thoughts were with those loved ones in
the humble cabin, still miles away, toward the towering mountains, while
his immediate anxiety was about the hostiles that had appeared in his front
and were now circling to the northward as if to meet Wolf Ear, the young
Ogalalla, who was galloping in the face of the biting gale and rapidly
drawing toward them.
The youth did not feel any special alarm for himself, for he was
confident that Jack was as fleet-footed as any of the animals bestrode by the
hostiles, and would leave them behind in a fair race. He noticed that the
Ogalalla was mounted on a superior beast, but he did not believe he could
outspeed Jack.
But it would never do to meet those half-dozen horsemen that had faced
toward him, and were approaching at the same swinging gallop. Brinton
diverged more to the left, thus leaving the trail, and they also changed their
course, as if to head him off.
The fugitive now headed directly away from the horsemen, so that both
parties were pursuing the same line. The youth looked back, at the moment
that several blue puffs of smoke showed over the backs of the horses. The
thudding reports came through the chilly air, and a peculiar whistling sound
overhead left no doubt that the hostiles, great as was the separating space,
had fired at the fugitive, who turned to take a look at Wolf Ear.
That individual discharged his gun the next moment. Brinton heard
nothing of the bullet, but smiled grimly—
"He has changed his mind soon, but they have got to come closer before
they hurt me. He is no great marksman anyway, or he would not have
missed me a little while ago."
It was singular that it did not occur to young Kingsland that it was
possible the Ogalalla had not fired at him at all. Not even when the
horsemen checked their pursuit, and reining up their animals awaited the
coming of the buck, who was riding like a hurricane, could he bring himself
to think of Wolf Ear except as a bitter enemy, who for some subtle purpose
of his own had declared a temporary truce.
"I suppose they think I shall be along this way again pretty soon, and
they can afford to wait till I run into their trap," was the conclusion of
Brinton, who headed his pony once more toward his home, and put him to
his best paces.
"Come, Jack, there's no time to throw away; hard work is before you,
and you must struggle as never before."
The snowfall which seemed for ever impending did not come. The few
scattering flakes still circled and eddied through the air, as if reluctant to
touch the earth, but no perceptible increase appeared in their number. The
nipping air seemed to have become too cold to permit a snow-storm.
Brinton had set out fully prepared for such change of temperature. He
wore a thick woollen cap, whose flaps were drawn down to his ears, while
they were more than met by the heavy coat collar that was turned up, the
garment itself being closely buttoned around his body. His rifle rested
across the pommel of his saddle in front, and his gloved hands scarcely ever
touched the rein which lay loose on his pony's neck. He was a capital
horseman, and, with the understanding between him and his intelligent
beast, could have got along without any bit at all.
Strapped behind him was a substantial lunch, and his keen appetite
would have made it enjoyable, but he did not disturb it. It could wait until
he learned the truth about the folk at home, which he was now rapidly
drawing near.
Over a swell in the prairie, across a small creek, whose icy waters hardly
came above Jack's fetlocks, up a second rise, and then Brinton Kingsland
uttered an exclamation of amazement and sharply checked his animal.
Over another swell, and only a few hundred yards away, two other
horses rode to view, coming directly toward him. Each sustained a heavily
muffled figure, and they were moving at a rapid walk.
Suspecting their identity, he waited a minute, and then started his horse
forward again. A few paces, and despite the arctic temperature, he raised his
cap from his head and called out—
"Hurrah! thank Heaven, you are alive, and have started for the agency."
His father sat on one horse, swathed in heavy clothing, and a blanket
which the faithful wife had fastened around his emaciated and weak form,
while she, with Edith in front, and both also protected against the severe
weather, were on the other animal. He had a rifle across his saddle front,
like the son, and they had brought with them nothing but a small amount of
food, barely enough to last them until they could reach the agency, provided
there was no unexpected delay on the road.
The discovery that they were alive and secure for the time, though the
shadow of a great peril was over all, so delighted the son that he could not
repress the shout of joy, as he rode forward and greeted them, little more
than their eyes and noses showing through the thick coverings.
"What made you leave before I got back?" was the first inquiry of
Brinton, after a few congratulatory words.
"We concluded it was high time to do so," replied the father, showing
more vigour in his voice than the son expected.
"A half-dozen hostiles fired several times at the house, and then, as if
they feared they were not strong enough to capture us and burn the cabin,
rode off for help."
"They are hardly out of sight now; they gave me half a dozen shots, and
I had a short chase with them. But you are off the trail."
"Of course; I have no doubt though," added the father grimly, "that the
Indians will look after the live stock for us."
"Whom do you suppose I saw?" asked Brinton, turning to his mother and
sister.
"A big bear?" ventured Edith from the depths of her wrappings.
"No; he was an old friend of yours—Wolf Ear, who used to come to our
house and have such good times with you."
The excited child flung her arms about in the effort to free herself of the
encumbering wrappings.
"Oh, where is he? Why didn't he come with you? Didn't he want to see
me? I am so sorry; isn't he with you?"
And she peered around, as if she suspected the young Ogalalla was
hiding behind the saddle of her brother.
Brinton smiled, and then gravely shook his head. He said, addressing his
parents more than the little one—
"I was never more astonished than to find that Wolf Ear, despite the
training he has had at Carlisle, has joined the hostiles, and is now an enemy
of those who were such good friends of his."
The youth did not think it wise to tell, in the presence of his sister, the
particulars of their first meeting.
"You grieve me more than I can express," replied the father; "are you
sure you are not mistaken?"
"He said he would not harm any one of us, if the fortunes of war should
give him the chance; but he declares himself the enemy of all others of our
race. He has a twin brother, and he and his father and mother, as Wolf Ear
coolly told me, would be pleased to scalp us. I have no more faith in him
than in them. We parted as friends, but he has joined that very party which
fired on you, and will go back to the house with them."
"He will lead them on our trail and be among the foremost to shoot us
down, every one of us."
"I don't believe it!" called Edith from her wraps, which her mother had
put around her again; "I like Wolf Ear and want to see him."
Brinton did not think it worth while to discuss the matter with his sister,
for a far more important matter pressed upon them.
"It won't do to follow the trail," remarked the father, "since they will be
on the look-out for us. We will bear to the south, so as to strike the
Cheyenne further up stream."
"We can follow it down till we find a place. It may be frozen over nearer
its source. The agency is so far off that we shall have to go into camp before
we can get half-way there."
"How do you feel, father?" abruptly asked his son, glancing keenly at
him. "Are you strong enough to stand this hard ride?"
"I am much stronger than you would suppose; you know a crisis like this
will rouse any man, even if he is a good deal more unwell than I am."
"I am glad to hear you talk that way, but you will be tried hard before we
reach Pine Ridge."
"Give yourself no uneasiness about me; the only thing we are to think
about is how we shall get to the agency without meeting with the hostiles,
who seem to be roaming everywhere."
While they sat talking, at the base of the swell, on the summit of which
the parents had first appeared, all partook of lunch, for it was not likely they
would have a more favourable opportunity before the coming of night.
It was decided to bear still more to the south, with a view of avoiding the
party that was at no great distance. Indeed, less than half an hour had passed
since they vanished from the view of the youth, who believed they were
waiting in the vicinity of the trail for his return, and would attack the whites
the moment they discovered them.
The halt lasted little more than a quarter of an hour, when they resumed
their journey toward the agency, which they hoped, rather than expected, to
reach by the morrow's set of sun. The mother was without any weapon,
though she was quite skilful in the use of a rifle. Her husband said that if he
found himself compelled to yield to weakness, he would turn over his
Winchester to her, believing as he did that she was sure to give a good
account of herself.
They were plentifully supplied with cartridges, but the reader does not
need to be reminded of their almost helpless situation. Kingsland, despite
his brave efforts to keep up, was unable to ride his pony at full speed for
any length of time, while the wife, burdened with the care of Edith, could
not expect to do much better.
But their only safety, it may be said, lay in avoiding the Indians
altogether, and it was to that task that Brinton, as the strongest one of the
party, addressed himself with all the energy and skill of his nature.
The course was up and down continually, though none of the swells in
the prairie was of much height. The youth rode slightly in advance and
never made his way to the top of one of the slight elevations without a
quicker throbbing of the heart and a misgiving which made the situation of
the most trying nature.
It was the dread of the hostiles, with whom Wolf Ear had joined himself,
that led him to make a longer bend to the south than even his father had
contemplated. True, as he well knew, they were not the sole Indians to be
dreaded, but they were the only ones of whom he had positive knowledge.
Others were likely to be encountered at any time, and it may be said that as
they drew nearer the agency, the peril increased.
A half-dozen miles from where the family had been reunited, they
approached a higher elevation than any that had yet been crossed. Brinton
asked the rest to halt at the base, while he dismounted and carefully went to
the top on foot.
It was well he took this precaution, for his friends, who were watching
his crouching figure as he cautiously went up the incline, saw him abruptly
halt and peer over the ridge, in a way which showed he had perceived
something. He remained but a minute, when he hurried back, pale and
excited.
CHAPTER IV.
Brinton Kingsland, after peering over the crest of the elevation for a few
brief moments, turned and hastily descended to where his pony awaited
him. Without touching his bridle, he spoke, and the obedient animal
followed him, while the parents and little sister anxiously listened to the
report of what he learned.
"It's the very party of Indians that we have been trying to get away
from," added the youth to his first explanation; "there are seven of them,
and Wolf Ear is among them."
"Is he?" eagerly asked Edith, from her wrappings on the saddle in front
of her mother "oh, let me see him! Tell him I am here."
"Keep quiet! Don't speak," said her father sternly. "Wolf Ear is with bad
Indians, and is a bad Indian himself"