Browse Source

Add fog of war; add content, update rules

master
Josh Gordon 3 years ago
parent
commit
6c9712cd9c
  1. 11
      Spells/breeze.txt
  2. 10
      Spells/magnetize.txt
  3. 11
      Spells/time_stop.txt
  4. 21
      app/action/Character.cpp
  5. 4
      app/action/Character.h
  6. 49
      app/action/Map.cpp
  7. 12
      app/action/Map.h
  8. BIN
      app/action/action
  9. BIN
      app/action/assets/3.png
  10. 6
      app/action/main.cpp
  11. 2
      app/routes.py
  12. 13
      app/templates/campaign_info.html
  13. 2
      app/templates/marches.html

11
Spells/breeze.txt

@ -0,0 +1,11 @@
Breeze
------
Kind: Evocation 0
Time: 1 action
Components: V,S,M (a paper fan)
Range: 25ft
Duration: 1 hour
Target one creature or object, and you create a light wind that blows against it.
The target gains a +2 bonus to saving throws against heat effects, and spells such as cloudkill.
You may only have one breeze active at a time.

10
Spells/magnetize.txt

@ -0,0 +1,10 @@
Magnetize
---------
Kind: Enchantment 5
Time: 1 action
Components: V,S,M (a small iron rod, unconsumed)
Range: 40ft
Duration: 10 minutes
You cause a metal object to become incredibly magnetic, drawing in any iron containing objects within 10 feet.
Separating an object from the magnet requires a strength check against your spell save DC.

11
Spells/time_stop.txt

@ -0,0 +1,11 @@
Time Stop
---------
Kind: Transmutation 7
Time: 1 action
Range: Self
Components: V (you know what it is), S
Duration: Special
The passage of time comes to a halt for 1d4+1 rounds for everyone except you.
You may act as normal during this time, however any effects you cause to others or the environment do not manifest until time resumes.
The spell ends if you move more than 1,000 feet from where you cast it, relative to the ground.

21
app/action/Character.cpp

@ -9,7 +9,7 @@ void Character::handleEvent(SDL_Event& e) {
case SDLK_RIGHT: vx_ += CHAR_SPEED; break;
}
if(turnTimer.isPaused()) {
printf("Unpause\n");
//printf("Unpause\n");
turnTimer.unpause();
}
} else if(e.type == SDL_KEYUP && e.key.repeat == 0) {
@ -22,7 +22,7 @@ void Character::handleEvent(SDL_Event& e) {
case SDLK_RIGHT: vx_ -= CHAR_SPEED; break;
}
if(!turnTimer.isPaused() && vy_ == 0 && vx_ == 0) {
printf("Pause\n");
//printf("Pause\n");
turnTimer.pause();
}
}
@ -37,10 +37,10 @@ void Character::move(Quad* level) {
if((x_ < 0)
|| (x_ + sprite_.getWidth() > L_W*TILE_SIZE)
|| (level->lookup((x_)/TILE_SIZE,(y_)/TILE_SIZE) == WALL)
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_)/TILE_SIZE) == WALL)//) {
|| (level->lookup((x_)/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE) == WALL)
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE) == WALL)) {
|| (level->lookup((x_)/TILE_SIZE,(y_)/TILE_SIZE)->getTile() == WALL)
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_)/TILE_SIZE)->getTile() == WALL)//) {
|| (level->lookup((x_)/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE)->getTile() == WALL)
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE)->getTile() == WALL)) {
//printf("%d is too far on x, bounds are 0 and %d\n",x_,L_W*TILE_SIZE);
x_ -= vx_;
}
@ -48,10 +48,10 @@ void Character::move(Quad* level) {
y_ += vy_;
if((y_ < 0)
|| (y_ + sprite_.getHeight() > L_H*TILE_SIZE)
|| (level->lookup((x_)/TILE_SIZE,(y_)/TILE_SIZE) == WALL)
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_)/TILE_SIZE) == WALL)
|| (level->lookup((x_)/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE) == WALL)//){
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE) == WALL)) {
|| (level->lookup((x_)/TILE_SIZE,(y_)/TILE_SIZE)->getTile() == WALL)
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_)/TILE_SIZE)->getTile() == WALL)
|| (level->lookup((x_)/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE)->getTile() == WALL)//){
|| (level->lookup((x_ + sprite_.getWidth())/TILE_SIZE,(y_ + sprite_.getHeight())/TILE_SIZE)->getTile() == WALL)) {
//printf("%d is too far on y, bounds are 0 and %d\n",y_,L_H*TILE_SIZE);
y_ -= vy_;
}
@ -71,6 +71,7 @@ void Character::move(Quad* level) {
camera_.y = L_H*TILE_SIZE - camera_.h;
//handle fog of war here
level->reveal(x_/TILE_SIZE,y_/TILE_SIZE,vision);
}
void Character::render(SDL_Rect camera) {

4
app/action/Character.h

@ -29,6 +29,8 @@ private:
Uint32 speed;
Timer turnTimer;
int vision; //1/2 side length of square to reveal on movement
public:
@ -36,7 +38,7 @@ public:
Character(){};
Character(int id,std::string filepath, int x, int y): name(id), x_(x), y_(y), vx_(0), vy_(0), camera_({0,0,S_W,S_H}), speed(30) {
Character(int id,std::string filepath, int x, int y): name(id), x_(x), y_(y), vx_(0), vy_(0), camera_({0,0,S_W,S_H}), speed(30), vision(5) {
sprite_.loadFromFile(filepath);
turnTimer.start();
turnTimer.pause();

49
app/action/Map.cpp

@ -19,6 +19,7 @@ void Quad::init(int w,int h) {
bound = {0,0,i,i};
data = WALL;
tl = tr = bl = br = NULL;
discovered = false;
}
void Quad::boundstring() {
@ -94,9 +95,9 @@ void Quad::insert(int x, int y, Tile t) {
}
}
Tile Quad::lookup(int x, int y) {
Quad* Quad::lookup(int x, int y) {
if(bound.w*bound.h == 1) {
return data;
return this;
}
if(bound.x + bound.w/2 > x) { //left
if(bound.y + bound.h/2 > y) { //top
@ -115,7 +116,26 @@ Tile Quad::lookup(int x, int y) {
return br->lookup(x,y);
}
}
return WALL;
return NULL;
}
void Quad::reveal(int x, int y, int vision) {
int rx,ry;
for(int dx = -vision; dx < vision; ++dx) {
rx = x+dx;
for(int dy = -vision; dy < vision; ++dy) {
ry = y+dy;
if(rx < 0 || ry < 0 || rx >= L_W || ry >= L_H){
printf("Reveal out of bounds\n");
} else {
lookup(rx,ry)->discovered = true;
printf("Revealed (%d,%d)\n",rx,ry);
}
}
}
}
void Quad::print(int spaces) {
@ -172,22 +192,8 @@ void Map::loadFromFile(std::string fpath) {
tiles->insert(x,y,t);
}
}
//maybe pad with walls up to power of two?
/* FILE* f = fopen(fpath.c_str(),"rb");
int w,h;
fread(&w,sizeof(int),1,f);
fread(&h,sizeof(int),1,f);
std::cout << "Width: " << w << " Height: " << h << "\n";
tiles->init(w,h);
std::cout << "Tiles init'd\n";
int t;
for(int i = 0; i < w*h; ++i) {
fread(&t,sizeof(int),1,f);
tiles->insert(i/w,i%w,static_cast<Tile>(t));
//std::cout << "Loading " << t << "\n";
}
fclose(f);*/
numTilesX = image.cols;
numTilesY = image.rows;
}
@ -196,9 +202,12 @@ void Map::render(SDL_Rect camera) {
//std::cout << "Rendering map\n";
for(int x = camera.x/TILE_SIZE; x < 1+(camera.x + camera.w)/TILE_SIZE; ++x){
for(int y = camera.y/TILE_SIZE; y < 1+(camera.y + camera.h)/TILE_SIZE; ++y) {
Tile t = tiles->lookup(x,y);
Quad* q = tiles->lookup(x,y);
//std::cout << "Tile at " << x << "," << y << " is " << t << "\n";
textures[t].render(x*TILE_SIZE - camera.x,y*TILE_SIZE - camera.y);
if(q->isDiscovered())
textures[q->getTile()].render(x*TILE_SIZE - camera.x,y*TILE_SIZE - camera.y);
else
textures[FOG].render(x*TILE_SIZE - camera.x,y*TILE_SIZE - camera.y);
}
}
//exit(1);

12
app/action/Map.h

@ -16,23 +16,24 @@ extern int L_W; //level dimensions
extern int L_H;
extern const int TILE_SIZE;
static const int NUM_TILE_IDs = 3;
static const int NUM_TILE_IDs = 4;
enum Tile {
WALL,
STONE,
GRASS,
FOG,
WATER,
PIT,
UNUSED1,
UNUSED2,
UNUSED3
UNUSED2
};
class Quad {
private:
SDL_Rect bound;
Tile data;
bool discovered;
inline bool inbounds(int,int);
void boundstring();
Quad *tl,*tr,*bl,*br;
@ -42,8 +43,11 @@ public:
//~Quad(){free();}
void free();
void insert(int,int,Tile);
Tile lookup(int,int); //defaults to wall
Quad* lookup(int,int);
void reveal(int,int,int);
void print(int);
bool isDiscovered(){return discovered;}
Tile getTile(){return data;}
};
class Map {

BIN
app/action/action

BIN
app/action/assets/3.png

After

Width: 64  |  Height: 64  |  Size: 4.8 KiB

6
app/action/main.cpp

@ -98,14 +98,14 @@ int main(int argc, char** argv) {
active->resetTurn();
active++;
if(active == characters.end()){
printf("Back to beginning\n");
//printf("Back to beginning\n");
active = characters.begin();
}
else{
printf("Next character\n");
//printf("Next character\n");
}
active->startTurn();
printf("Next turn!\n");
//printf("Next turn!\n");
}
//float avgFPS = frames_total / (fpsTimer.getTicks() / 1000.0f);

2
app/routes.py

@ -185,7 +185,7 @@ def genDungeon():
def about():
return render_template('about.html')
@app.route("/campaign_info")
@app.route("/marches/campaign_info")
def campaign_info():
return render_template('campaign_info.html')

13
app/templates/campaign_info.html

@ -61,6 +61,9 @@ What's most important to keep in mind is that if anyone can do this, it's you.
<p>A Gate is required to teleport into the wilderness.</p>
<p>Short range teleportation such as misty step and dimension door are unaffected by this rule.</p>
</li>
<li><p>Any spells on this website are not available to the players until discovered in the world unless stated otherwise.</p>
<p>Spells written here override official spells, however said spell would be available without needing to be discovered because it was already mentioned in the PHB (example, our version of time stop).</p>
</li>
<li><p>After each session, each player will write up a log (~1 paragraph, can be longer) detailing what their character did/discovered on the mission.</p>
<p>Once the log is written, said player will have one inspiration to use next mission.</p>
</li>
@ -78,7 +81,7 @@ What's most important to keep in mind is that if anyone can do this, it's you.
<li><p><strong>Travel</strong>: The party travels to their destination, advancing world time and dealing with issues that arrive en route (random encounters, adverse conditions, unexpected geographic updates, etc)</p></li>
<li><p><strong>Action</strong>: A normal D&amp;D game occurs</p></li>
<li><p><strong>Return</strong>: The party returns to a civilized area. This is similar to the travel part but less eventful.</p></li>
<li><p><strong>Bookkeeping</strong>: Loot is divided, xp is awarded, and logs are written. Total world time advanced is announced.</p></strong>
<li><p><strong>Bookkeeping</strong>: Loot is divided, xp is awarded, and logs are written. Total world time advanced is announced.</p>
</ol>
<p>Planning will take place electronically, however the rest of the parts will be in person.</p>
</li>
@ -117,7 +120,7 @@ What's most important to keep in mind is that if anyone can do this, it's you.
<h2>Tables</h2>
<h4>Travel time table</h4>
<table id="travel">
<table id="travel"> <!-- Inspired by Oregon Trail -->
<tr>
<th>Pace</th>
<th>Miles per Hour</th>
@ -174,7 +177,7 @@ What's most important to keep in mind is that if anyone can do this, it's you.
</tr>
</table>
<h4>Foraging dc table</h4>
<table id="forTable">
<table id="forTable"> <!-- Inspired by the west marches subreddit -->
<tr>
<th>Amount of food</th>
<th>DC</th>
@ -228,7 +231,7 @@ What's most important to keep in mind is that if anyone can do this, it's you.
</tr>
</table>
<h4>Military construction table</h4>
<table id="milCon">
<table id="milCon"> <!-- Stolen near directly from the west marches subreddit -->
<tr>
<th>Military Building</th>
<th>Sphere of Influence</th>
@ -273,7 +276,7 @@ What's most important to keep in mind is that if anyone can do this, it's you.
</tr>
</table>
<h4>Settlement construction table</h4>
<table id="setCon">
<table id="setCon"> <!-- Inspired mostly by civ5 and the pdf on the west marches subreddit -->
<tr>
<th>Building Type</th>
<th>Cost</th>

2
app/templates/marches.html

@ -6,7 +6,7 @@
<li><a href="marches/worlds/{{w}}">{{w}}</a></li>
{% endfor %}
</ul>
<h2><a href="/campaign_info">The Campaign</a><h2>
<h2><a href="/campaign_info">Rules For The Campaign</a><h2>
<h2>How to join</h2>
<p>There are four ways to join COSI West Marches.</p>
<ol>

Loading…
Cancel
Save