Ejemplo n.º 1
0
def add_game(page_dict):
  utils.make_page (page_dict,
    '/hexy-classic',
      "Hexy Bondage ⊂ Eli Dupree's website",
      r'''
<style>
html.hexy .bars_outer_box {
  background-color: #878787;
  background-image: url("/media/hexy-background.jpg?rr"); }

div.hexy_content h1{ font-size: 200%; font-weight: bold; padding-top: 0.20em; }
div.hexy_content h2{ font-size: 150%; font-weight: bold; padding-top: 0.30em; }
div.hexy_content p { margin: 0; padding: 0.5em 0; line-height: inherit; }
div.hexy_content a:link { color:blue }
div.hexy_content a:visited { color:purple }

div.hexy_content div.subtitle { font-weight: bold; font-size: 90%; padding-bottom: 0.5em;}
div.hexy_content {
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  max-width: 50em;
  margin: 0 auto; }
div.hexy_content form,div.hexy_content table {
  display: inline; }
div.hexy_content .paynowbutton {
  vertical-align: middle; }
div.hexy_content div.bigbox_outer {
  padding: 0.2em 0.4em; }
div.hexy_content div.bigbox {
  border-radius: 1.4em;
  padding: 0.3em;
  background-color: #ffffff;
  background-color: rgba(255,255,255,0.95); }
div.hexy_content div.bigbox.thankyou {
  padding: 1.0em 0.3em;
  background-color: #ffff00;
  background-color: rgba(255,255,0,0.90); }
div.hexy_content div.bigbox_outer.narrower { display:inline-block; }
div.hexy_content div.bigbox_outer.last { padding-bottom: 0.4em; }
div.hexy_content div.bigbox_outer:first-child { padding-top: 0.4em; }

div.hexy_content div.bigbox_outer.comments {
  font-size: 80%;
  font-family: Times New Roman, Times, serif; }
div.hexy_content div.bigbox.comments {
  padding-bottom: 1.0em; }
div.hexy_content .important_link {
  font-size: 160%; font-weight: bold; }

@media (min-width: 30em) {
  div.hexy_content div.bigbox_outer {
    padding: 0.6em 1.8em; }
  div.hexy_content div.bigbox {
    border-radius: 2.2em;
    padding: 0.7em 1em;
  }
  div.hexy_content div.bigbox.thankyou {
    padding: 1.8em 1em; }
  div.hexy_content div.bigbox_outer.last { padding-bottom: 1.2em; }
  div.hexy_content div.bigbox_outer:first-child { padding-top: 1.2em; }
  div.hexy_content {
    font-size: 1.2em; 
  }
  div.hexy_content div.bigbox_outer.comments {
    font-size: 70%; }
}
@media (min-width: 13em) {
  div.hexy_content a.lesswrap {
    white-space: nowrap;
  }
}
</style>
''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main>
  <div id="content" class="hexy_content">
<div class="bigbox_outer">
<div class="bigbox">
  <h1>Hexy Bondage</h1>
  <div class="subtitle">'''+ blurb +'''</div>
  <p>
Hexy Bondage is a game where in-game actions cause you to be tied up in real life.
  </p>
  <p>
Players take turns placing tiles. Each tile has an icon (hand, foot, torso, crotch, furniture...)
and some paths. The paths can be used to connect icons together. Connections cause
things to happen in real life, like tying your body parts together. A player wins
when their “opponent” is too tied up to reach the board.
  </p>
  <p>In June 2017, I made <a href="/hexy">a web version of Hexy Bondage for players to play together on the same device</a>. The web version is generally better than this printable version. But I'm leaving this older, printable version available in case you find it useful.</p>
  <p><a class=" important_link lesswrap" href="/hexy/hexy-bondage-rules.pdf">Read the full rules (pdf)</a></p>
  <p> <a class=" important_link lesswrap" href="/hexy/hexy-bondage-tiles.pdf">Download printable tiles</a> </p>
  
  <p class="hidden_from_restricted_users">If you like this game, consider <a href="https://www.patreon.com/EliDupree">supporting me on Patreon</a> so that I can continue making awesome things and sharing them for free on the Internet.</p>
</div>
</div>
<div class="bigbox_outer">
<div class="bigbox">
  <h2>Extras:</h2>
  <p>Tile sheets for extra players:
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-green.pdf">green checkers</a>,
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-pink.pdf">pink polka dots</a>,
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-blue.pdf">blue waves</a>,
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-purple.pdf">purple stripes</a></p>
  <p>Black-and-white versions of tiles for extra players:
    <a href="/hexy/hexy-bondage-extra-tiles-checkers.pdf">checkers</a>,
    <a href="/hexy/hexy-bondage-extra-tiles-polkadots.pdf">polka dots</a>,
    <a href="/hexy/hexy-bondage-extra-tiles-waves.pdf">waves</a>,
    <a href="/hexy/hexy-bondage-extra-tiles-stripes.pdf">stripes</a></p>
  <p><a href="/hexy/hexy-bondage-blank-tiles.pdf">Sheet of blank tiles</a></p>
</div>
</div>
<div class="bigbox_outer narrower comments last">
<div class="bigbox narrower comments last">
  '''+blog.comments_section("hexy_classic")+'''
</div>
</div>
  </div>
</main>'''), {"html_class":"hexy", "blurb": blurb + ".", "blurb_image": "/media/hexy-thumbnail.png?rr"}
  )
  
  """
  utils.make_page (page_dict,
    '/hexy-future',
      "Hexy Bondage ⊂ Eli Dupree's website",
      r'''
<style>

.tile {
  transition-duration: 0.6s;
}
.rotation_arrow {
  --arrow-fill: #ffffff;
}
.rotation_arrow:hover {
  --arrow-fill: #ffff00;
}
button {
  font-size: 120%;
  padding: 3px 5px;
  border:2px solid black;
  border-radius:5px;
}

</style>
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main>
  <div id="content">
    <!-- <div id="messages"></div> -->
    
    <!-- <div id="tile_controls"></div> -->
  </div>
  '''+ trimmed_svg+'''
</main>'''), {"html_class":"hexy", "blurb": blurb + ".", "blurb_image": "/media/hexy-thumbnail.png?rr", "after_body":'''

     <script type="text/javascript" src="/media/lodash.min.js?rr"></script>

     <script type="text/javascript">
       window.hexy_tile_ids = ['''+ (",".join (['"'+id+'"' for id in tile_ids])) +''']
     </script>
     
     <!-- <script type="text/javascript" src="/media/hexy.js?rr"></script> -->
     <script type="text/babel" src="/media/hexy-react.js?rr">
'''}
  )
  """
  
  utils.make_page (page_dict,
    '/hexy',
      "Hexy Bondage ⊂ Eli Dupree's website",
      r'''
<style>

html,body {
  background-color: var(--meta-fill);
  --hex-fill: #ffffff;
  --hex-stroke: transparent;
  --meta-stroke: black;
  --meta-fill: #ccc;
}
.game_svg {
  display: block;
  /*margin: 0 auto;*/
  /* prevent it from overflowing its box before being sized */
  width: 0; height: 0;
}
.message_area {
  /*background-color:#ffaaaa;*/
  margin: 0.2em;
  padding: 0.5em;
  border-radius: 1em;
  border: 0.2em solid var(--meta-stroke);
  /*color: var(--meta-stroke);*/
  font-family: Arial, Helvetica, sans-serif;
  flex-grow: 1;
}
.message_area p {
  margin: 0;
  line-height: 1.10em;
}
.message_area p~p {
  margin-top: 0.5em;
}
.tile {
  /*transition-duration: 0.6s;*/
}
.prompt_options {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.prompt_option {
  font-size: 100%;
  margin: 0.5em;
  white-space: normal;
}

input[type="button"],.fake_button {
  background-color: var(--meta-fill);
  border: 0.2em solid var(--meta-stroke);
  padding: 0.5em;
  border-radius: 1em;
  color: var(--meta-stroke);
  font-family: Arial, Helvetica, sans-serif;
  cursor: pointer;
}
input[type="button"]:hover,.fake_button:hover {
  background-color: var(--meta-stroke);
  border-color: 0.2em solid var(--meta-fill);
  color: var(--meta-fill);
}

.board_container {
  width: 100%;
  overflow: auto;
}
.non_board_container {
  display: flex;
  font-size: 3vh;
}
.buttons_area {
  display: flex;
  flex-direction: column;
}
.buttons_area input[type="button"] {
  display: block;
  font-size: 100%;
  padding: 0.3em;
  margin: 0.2em;}


#menu_wrapper {
  position: fixed;
  left: 0; right: 0; top: 0; bottom: 0;
}
#menu {
  position: fixed;
  left: 5%; right: 5%; top: 8%; bottom: 5%;
  border: 1.5vh solid black; border-radius: 6vh;
  box-shadow: 10px 5px 15px #fff;
  background-color: white;
  --meta-stroke: black;
  --meta-fill: white;
  text-align: center;
}
h1 {font-size: 200%;}
h2 {font-size: 150%; margin: 0.5em;}
#menu p {}
#menu ul {text-align: left; line-height: 1.35em;}
#menu_contents {
  padding: 2vh;
  overflow: auto;
}
#menu_navigation {
  padding: 0.8em 0.2em;
  background-color: #aaa;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.modes {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 40em;
  margin: 0 auto;
  text-align: left;
}
.mode_box {
  margin:0.2em;
}
.modes input {
  width:2em; height:2em; vertical-align: middle;
}
.modes label {
  vertical-align: middle; margin-left:0.2em;
}

.players {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.player_options {
  margin: 0.2em;
  border-radius:0.4em;
  padding:0.5em;
  background-color:#ddd;
}
.player_options input[type="text"] {
  width: 6em;
}

.fake_boards {
  display: flex ;
  justify-content: center;
}
.fake_board {
  margin: 0.6em;
  flex-shrink: 0;
}

.connection_type {
  display: inline-block;
  margin: 0.6em;
  max-width: 40em;
  background-color:#ccc;
}
@media screen and (max-width: 400px) {
  .fake_board {
    margin: 0.1em;
    flex-shrink: 0;
  }
  .connection_type {
    margin: 0.6em -0.2em;
  }
}
.connection_type p {
  padding: 0 1.1em;
}
.connection_type .fake_board {
  margin: 0.1em;
}

#comments {
  display: none;
}

.noscript {
  margin: 3em auto;
  padding: 0 1.1em;
  max-width: 40em;
  font-size: 130%;
}

</style>
''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main>
  <div id="content">
    <div class="noscript">This game requires JavaScript to play. To play, enable JavaScript in your browser and reload the page. Alternatively, look at <a href="/hexy-classic">the older printable board game</a>, which doesn't require JavaScript.
    <!-- <div id="messages"></div> -->
    
    <!-- <div id="tile_controls"></div> -->
  </div>
  '''+blog.comments_section("hexy")+'''
  '''+ trimmed_svg+'''
</main>'''), {"html_class":"hexy", "blurb": "A sexual game for two players (or more) to play together on the same device.", "blurb_image": "/media/hexy-thumbnail.png?rr", "after_body":'''

     <script type="text/javascript" src="/media/lodash.min.js?rr"></script>

     <script type="text/javascript">
       window.hexy_tile_ids = ['''+ (",".join (['"'+id+'"' for id in tile_ids])) +''']
     </script>
     
     <script type="text/javascript" src="/media/hexy-3-mechanics.js?rr"></script>
     <script type="text/javascript" src="/media/hexy-3-game-modes.js?rr"></script>
     <script type="text/javascript" src="/media/hexy-3-game-ui.js?rr"></script>
     <script type="text/javascript" src="/media/hexy-3-meta-ui.js?rr"></script>
'''}
  )
Ejemplo n.º 2
0
def add_game(page_dict):
  utils.make_page (page_dict,
    '/games/green-caves',
      "Enter the green caves ⊂ Eli Dupree's website",
      r'''
    <style type="text/css">
html,body { height: 100%; margin: 0; padding: 0; background-color: #50d050 }
div,canvas { margin: 0; padding: 0; }
canvas {width:804px; height:600px; background-color:#4b4; display: block;}
div.green_caves_content {text-align: center;}
div.green_caves_content .comments_section {display: inline-block;}
p {text-align: center; font-size: 120%;}
    </style>''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main>
      <div class="green_caves_content">
    <div style="min-height: 50%;"><div style="min-height: 390px"></div></div><div style=" margin-top:-390px">
      <p>You are surrounded by endless caves.</p>
      <p>'''+ blurb +'''</p>
      <p>Arrow keys or WASD to move. Point and click to shoot. Click in the <strong>timeline</strong> at the right to return to different points in history!</p>
    </div>
    <div style="margin: 0 auto; width:804px; cursor: crosshair"><canvas id="game_canvas" width="804" height="600">
The game should appear here, but it hasn't. Maybe you don't have JavaScript enabled. Or maybe your browser doesn't support WebGL.
    </canvas></div>
  <p class="hidden_from_restricted_users">If you like this game, consider <a href="https://www.patreon.com/EliDupree">supporting me on Patreon</a> so that I can continue making awesome things and sharing them for free on the Internet.</p>
  <p> The current version of this game is part of the <a href="https://github.com/elidupree/Lasercake">Lasercake project</a>, and it is licensed under the GNU AGPL. It was compiled as of <a href="https://github.com/elidupree/Lasercake/commit/38117543a3f4d864d8544980c317eb311b4b83ba">this commit</a>.</p>
    '''+blog.comments_section("green_caves")+'''

    </div>
    
   
</main>''')+''' <script type="text/javascript">
      Module = {};
      window.green_caves = {};
      window.green_caves.holding_mouse_down_ingame = false;
      Module.TOTAL_MEMORY = 100000000; // 100 MB, about six times the default
      Module.memoryInitializerPrefixURL = "/media/";
      Module.onRuntimeInitialized = function(){
"use strict";

var game_canvas = document.getElementById("game_canvas");

var h = GL.createContext(game_canvas, {});
if (h > 0) {
  window.green_caves.gl = true;
  GL.makeContextCurrent(h);
}
else {
  window.green_caves.gl = false;
  window.green_caves.canvas_context = game_canvas.getContext("2d");
}

/*  (function(window){
    var green_caves = {
      window.green_caves.canvas_context: game_canvas.getContext("2d"),
    };
    window.green_caves = green_caves;
  })(window);*/

  var canvas_rect = game_canvas.getBoundingClientRect();
  function update_canvas_rect() {
    canvas_rect = game_canvas.getBoundingClientRect();
    window._set_display_size(canvas_rect.right - canvas_rect.left, canvas_rect.bottom - canvas_rect.top, window.green_caves.gl);
  }
  update_canvas_rect();
  
  function mouse_xy_relative_to_top_left_of_canvas(mouseevent) {
    // bug?- assumes the event target is 'document'
    var mouse_screen_x = mouseevent.clientX;
    var mouse_screen_y = mouseevent.clientY;
    // compute this every time in case the window resizes/scrolls
    update_canvas_rect();
    var canvas_screen_top  = canvas_rect.top;
    var canvas_screen_left = canvas_rect.left;
    var mouse_canvas_x = mouse_screen_x - canvas_screen_left;
    var mouse_canvas_y = mouse_screen_y - canvas_screen_top;
    return { x: mouse_canvas_x, y: mouse_canvas_y };
  }
  
  var now_milliseconds = (function(){
    var now = new Date();
    return now.getTime();
  });
  var update = (function(){
    window._update_to_real_time(now_milliseconds());
  });

  var mousemove_while_mouse_down_ingame = function(e){
    var pos = mouse_xy_relative_to_top_left_of_canvas(e);
    window._mouse_moves(e.timeStamp, pos.x, pos.y);
    // prevent selecting text while aiming
    e.preventDefault();
  };
  document.addEventListener('mousedown', function(e){
    if(e.button == 0 && e.target == game_canvas) {
      // left-click in game area
      // (allow left-clicks elsewhere to do normal things like selecting text)
      window.green_caves.holding_mouse_down_ingame = true;
      document.addEventListener('mousemove', mousemove_while_mouse_down_ingame, false);
      var pos = mouse_xy_relative_to_top_left_of_canvas(e);
      window._mouse_down(e.timeStamp, pos.x, pos.y);
    }
  }, false);
  document.addEventListener('mouseup', function(e){
    if(e.button == 0 && window.green_caves.holding_mouse_down_ingame) {
      // release left-click
      window.green_caves.holding_mouse_down_ingame = false;
      document.removeEventListener('mousemove', mousemove_while_mouse_down_ingame, false);
      var pos = mouse_xy_relative_to_top_left_of_canvas(e);
      window._mouse_up(e.timeStamp, pos.x, pos.y);
    }
  }, false);
  document.addEventListener('keydown', function(e){
    var keycode = (e.keyCode ? e.keyCode : e.which);
    var keystr = String.fromCharCode(keycode);
    if (keycode === 37 || keystr === "A") { _set_left(e.timeStamp, true); e.preventDefault(); }
    if (keycode === 38 || keystr === "W") { _set_up(e.timeStamp, true); e.preventDefault(); }
    if (keycode === 39 || keystr === "D") { _set_right(e.timeStamp, true); e.preventDefault(); }
    if (keycode === 40 || keystr === "S") { _set_down(e.timeStamp, true); e.preventDefault(); }
  }, false);
  document.addEventListener('keyup', function(e){
    var keycode = (e.keyCode ? e.keyCode : e.which);
    var keystr = String.fromCharCode(keycode);
    if (keycode === 37 || keystr === "A") { _set_left(e.timeStamp, false); e.preventDefault(); }
    if (keycode === 38 || keystr === "W") { _set_up(e.timeStamp, false); e.preventDefault(); }
    if (keycode === 39 || keystr === "D") { _set_right(e.timeStamp, false); e.preventDefault(); }
    if (keycode === 40 || keystr === "S") { _set_down(e.timeStamp, false); e.preventDefault(); }
  }, false);
  
  var draw = (function(){
    update_canvas_rect();
    if (window.green_caves.gl) {
      
    }
    else {
      window.green_caves.canvas_context.fillStyle = "black";
      window.green_caves.canvas_context.fillRect(0,0,640,640);
    }
    window._draw(window.green_caves.gl);
  });
  
  var tick_finished = true;
  (function tickloop(){
    setTimeout(tickloop, 10);
    if (tick_finished) {
      tick_finished = false;
      update();
      draw();
      tick_finished = true;
    }
  }());

};
    </script>
    <script type="text/javascript" src="/media/green_caves.js?rr"></script>''', {"blurb": blurb, "blurb_image": "/media/green-caves-screenshot.png?rr"}
  )
Ejemplo n.º 3
0
def add_game(page_dict):
  utils.make_page (page_dict,
    '/hexy',
      "Hexy Bondage ⊂ Eli Dupree's website",
      r'''
<style>
html.hexy .bars_outer_box {
  background-color: #878787;
  background-image: url("/media/hexy-background.jpg?rr"); }

div.hexy_content h1{ font-size: 200%; font-weight: bold; padding-top: 0.20em; }
div.hexy_content h2{ font-size: 150%; font-weight: bold; padding-top: 0.30em; }
div.hexy_content p { margin: 0; padding: 0.5em 0; line-height: inherit; }
div.hexy_content a:link { color:blue }
div.hexy_content a:visited { color:purple }

div.hexy_content div.subtitle { font-weight: bold; font-size: 90%; padding-bottom: 0.5em;}
div.hexy_content {
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  max-width: 50em;
  margin: 0 auto; }
div.hexy_content form,div.hexy_content table {
  display: inline; }
div.hexy_content .paynowbutton {
  vertical-align: middle; }
div.hexy_content div.bigbox_outer {
  padding: 0.2em 0.4em; }
div.hexy_content div.bigbox {
  border-radius: 1.4em;
  padding: 0.3em;
  background-color: #ffffff;
  background-color: rgba(255,255,255,0.95); }
div.hexy_content div.bigbox.thankyou {
  padding: 1.0em 0.3em;
  background-color: #ffff00;
  background-color: rgba(255,255,0,0.90); }
div.hexy_content div.bigbox_outer.narrower { display:inline-block; }
div.hexy_content div.bigbox_outer.last { padding-bottom: 0.4em; }
div.hexy_content div.bigbox_outer:first-child { padding-top: 0.4em; }

div.hexy_content div.bigbox_outer.comments {
  font-size: 80%;
  font-family: Times New Roman, Times, serif; }
div.hexy_content div.bigbox.comments {
  padding-bottom: 1.0em; }
div.hexy_content .important_link {
  font-size: 160%; font-weight: bold; }

@media (min-width: 30em) {
  div.hexy_content div.bigbox_outer {
    padding: 0.6em 1.8em; }
  div.hexy_content div.bigbox {
    border-radius: 2.2em;
    padding: 0.7em 1em;
  }
  div.hexy_content div.bigbox.thankyou {
    padding: 1.8em 1em; }
  div.hexy_content div.bigbox_outer.last { padding-bottom: 1.2em; }
  div.hexy_content div.bigbox_outer:first-child { padding-top: 1.2em; }
  div.hexy_content {
    font-size: 1.2em; 
  }
  div.hexy_content div.bigbox_outer.comments {
    font-size: 70%; }
}
@media (min-width: 13em) {
  div.hexy_content a.lesswrap {
    white-space: nowrap;
  }
}
</style>
''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main>
  <div id="content" class="hexy_content">
<div class="bigbox_outer">
<div class="bigbox">
  <h1>Hexy Bondage</h1>
  <div class="subtitle">'''+ blurb +'''</div>
  <p>
Hexy Bondage is a game where in-game actions cause you to be tied up in real life.
  </p>
  <p>
Players take turns placing tiles. Each tile has an icon (hand, foot, torso, crotch, furniture...)
and some paths. The paths can be used to connect icons together. Connections cause
things to happen in real life, like tying your body parts together. A player wins
when their “opponent” is too tied up to reach the board.
  </p>
  <p><a class=" important_link lesswrap" href="/hexy/hexy-bondage-rules.pdf">Read the full rules (pdf)</a></p>
  <p> <a class=" important_link lesswrap" href="/hexy/hexy-bondage-tiles.pdf">Download printable tiles</a> </p>
  <p class="hidden_from_restricted_users">If you like this game, consider <a href="https://www.patreon.com/EliDupree">supporting me on Patreon</a> so that I can continue making awesome things and sharing them for free on the Internet.</p>
</div>
</div>
<div class="bigbox_outer">
<div class="bigbox">
  <h2>Extras:</h2>
  <p>Tile sheets for extra players:
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-green.pdf">green checkers</a>,
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-pink.pdf">pink polka dots</a>,
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-blue.pdf">blue waves</a>,
    <a class="lesswrap" href="/hexy/hexy-bondage-extra-tiles-purple.pdf">purple stripes</a></p>
  <p>Black-and-white versions of tiles for extra players:
    <a href="/hexy/hexy-bondage-extra-tiles-checkers.pdf">checkers</a>,
    <a href="/hexy/hexy-bondage-extra-tiles-polkadots.pdf">polka dots</a>,
    <a href="/hexy/hexy-bondage-extra-tiles-waves.pdf">waves</a>,
    <a href="/hexy/hexy-bondage-extra-tiles-stripes.pdf">stripes</a></p>
  <p><a href="/hexy/hexy-bondage-blank-tiles.pdf">Sheet of blank tiles</a></p>
</div>
</div>
<div class="bigbox_outer narrower comments last">
<div class="bigbox narrower comments last">
  '''+blog.comments_section("hexy")+'''
</div>
</div>
  </div>
</main>'''), {"html_class":"hexy", "blurb": blurb + ".", "blurb_image": "/media/hexy-thumbnail.png?rr"}
  )
  
  utils.make_page (page_dict,
    '/hexy-future',
      "Hexy Bondage ⊂ Eli Dupree's website",
      r'''
<style>

.tile {
  transition-duration: 0.6s;
}
button {
  font-size: 120%;
  padding: 3px 5px;
  border:2px solid black;
  border-radius:5px;
}

</style>
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main>
  <div id="content">
    <!-- <div id="messages"></div> -->
    
    <!-- <div id="tile_controls"></div> -->
  </div>
  '''+ trimmed_svg+'''
</main>'''), {"html_class":"hexy", "blurb": blurb + ".", "blurb_image": "/media/hexy-thumbnail.png?rr", "after_body":'''

     <script type="text/javascript" src="/media/lodash.min.js?rr"></script>

     <script type="text/javascript">
       window.hexy_tile_ids = ['''+ (",".join (['"'+id+'"' for id in tile_ids])) +''']
     </script>
     
     <!-- <script type="text/javascript" src="/media/hexy.js?rr"></script> -->
     <script type="text/babel" src="/media/hexy-react.js?rr">
'''}
  )
def add_game(page_dict):
  utils.make_page (page_dict,
    '/games/pac-asteroids',
      "Pac-Asteroids ⊂ Eli Dupree's website",
      r'''<style type="text/css">
html,body {background-color: white;}
    </style> 
    <script type="text/javascript">
Math.TAU = Math.PI*2;
$(function(){
  var TILE_SIZE = 20;
  var ARENA_WIDTH = 32;
  var ARENA_HEIGHT = 24;
  var DOT_RADIUS = TILE_SIZE/12;
  var MIN_ASTEROID_RADIUS = DOT_RADIUS * 4;
  var BULLET_SPEED = 6;
  var BULLET_DURATION = (TILE_SIZE * 12 / BULLET_SPEED);
  var PACMAN_RADIUS = TILE_SIZE / 2;

  var game_canvas_context = document.getElementById("game_canvas").getContext("2d");
  var tick_finished = true;
  var ticks = 0, tick_skips = 0;
  var mousedown = false; 
  var you_base_loc = { x: Math.floor(ARENA_WIDTH / 2), y: Math.floor(ARENA_HEIGHT / 2) };
  var mouse_x = 0, mouse_y = 0;
  var wanted_movement = { x: 0, y: 0 };
  var current_movement = { x: 0, y: 0 }, progress = 0;
  var dots = [];
  var asteroids = [];
  var bullets = [];
  var you_have_lost = false;

  var i, j, x, y;

  var draw_all_four = function(real_x, real_y, draw_func){
    var draw_x, draw_y, which_x, which_y;
    for (which_x = 0; which_x < 2; ++which_x) {
      for (which_y = 0; which_y < 2; ++which_y) {
        draw_x = real_x;
        draw_y = real_y;

        if (which_x === 1) {
          if (draw_x > ARENA_WIDTH * TILE_SIZE / 2) { draw_x -= ARENA_WIDTH * TILE_SIZE; }
          else { draw_x += ARENA_WIDTH * TILE_SIZE; }
        }
        if (which_y === 1) {
          if (draw_y > ARENA_HEIGHT * TILE_SIZE / 2) { draw_y -= ARENA_HEIGHT * TILE_SIZE; }
          else { draw_y += ARENA_HEIGHT * TILE_SIZE; }
        }

        draw_func(draw_x, draw_y);
      }
    }
  };

  var tick = function(){
    var you_movement_angle = 0;
    var mouth_open_angle = 0;
    var you_actual_loc;
    var dx, dy, mag;
    var i, j, x, y;
    game_canvas_context.fillStyle = "black";
    game_canvas_context.fillRect(0,0,640,480);
    if (!you_have_lost) {
      progress += (1/8);
      if (progress >= 1 || (current_movement.x === 0 && current_movement.y === 0)) {
        progress = 0;
        you_base_loc.x += current_movement.x;
        you_base_loc.y += current_movement.y;
        if (you_base_loc.x < 0) you_base_loc.x += ARENA_WIDTH;
        if (you_base_loc.y < 0) you_base_loc.y += ARENA_HEIGHT;
        if (you_base_loc.x >= ARENA_WIDTH) you_base_loc.x -= ARENA_WIDTH;
        if (you_base_loc.y >= ARENA_HEIGHT) you_base_loc.y -= ARENA_HEIGHT;
        current_movement.x = wanted_movement.x;
        current_movement.y = wanted_movement.y;
        if (dots[you_base_loc.x][you_base_loc.y]) {
          dots[you_base_loc.x][you_base_loc.y] = false;
          dx = mouse_x - you_base_loc.x*TILE_SIZE;
          dy = mouse_y - you_base_loc.y*TILE_SIZE;
          mag = Math.sqrt(dx*dx + dy*dy);
          if (mag === 0) { dx = 1; dy = 0; mag = 1; }
          bullets.push({ x: you_base_loc.x*TILE_SIZE, y: you_base_loc.y*TILE_SIZE, vx: dx*BULLET_SPEED/mag, vy: dy*BULLET_SPEED/mag, duration: BULLET_DURATION });
        }
      }
    }
    you_actual_loc = { x: TILE_SIZE*(you_base_loc.x + (current_movement.x * progress)),
                       y: TILE_SIZE*(you_base_loc.y + (current_movement.y * progress)) };

    var move_and_wrap = function(thing){
      thing.x += thing.vx;
      thing.y += thing.vy;
      if (thing.x < 0) thing.x += ARENA_WIDTH*TILE_SIZE;
      if (thing.y < 0) thing.y += ARENA_HEIGHT*TILE_SIZE;
      if (thing.x >= ARENA_WIDTH*TILE_SIZE) thing.x -= ARENA_WIDTH*TILE_SIZE;
      if (thing.y >= ARENA_HEIGHT*TILE_SIZE) thing.y -= ARENA_HEIGHT*TILE_SIZE;
    }
    var intersects = function(loc1, rad1, loc2, rad2) {
      var dx, dy;
      dx = Math.abs(loc1.x - loc2.x);
      if (dx > ARENA_WIDTH*TILE_SIZE/2) { dx = ARENA_WIDTH*TILE_SIZE - dx; }
      dy = Math.abs(loc1.y - loc2.y);
      if (dy > ARENA_HEIGHT*TILE_SIZE/2) { dy = ARENA_HEIGHT*TILE_SIZE - dy; }
      return (dx * dx + dy * dy <= (rad1 + rad2) * (rad1 + rad2));
    }
    for (i = 0; i < asteroids.length; i++) {
      move_and_wrap(asteroids[i]);
    }
    for (i = 0; i < bullets.length; i++) {
      bullets[i].duration--;
      if (bullets[i].duration <= 0) {
        bullets.splice(i, 1);
        i--; // so we don't skip the next bullet 
      }
      else {
        move_and_wrap(bullets[i]);
      }
    }
    for (i = 0; i < bullets.length; i++) {
      for (j = 0; j < asteroids.length; j++) {
        if (intersects(bullets[i], DOT_RADIUS, asteroids[j], asteroids[j].radius)) {
          // blargh... this "function" is just to give me a new scope
          (function(){
            var first_vel_dir;
            var vel_mag;
            if (asteroids[j].radius >= MIN_ASTEROID_RADIUS * 2) {
              first_vel_dir = Math.random() * Math.TAU;
              vel_mag = 1 + Math.random()*2;
              asteroids.push({
                radius: asteroids[j].radius / 2,
                x: asteroids[j].x,
                y: asteroids[j].y,
                vx: asteroids[j].vx + Math.cos(first_vel_dir)*vel_mag,
                vy: asteroids[j].vy + Math.sin(first_vel_dir)*vel_mag,
                });
              asteroids.push({
                radius: asteroids[j].radius / 2,
                x: asteroids[j].x,
                y: asteroids[j].y,
                vx: asteroids[j].vx - Math.cos(first_vel_dir)*vel_mag,
                vy: asteroids[j].vy - Math.sin(first_vel_dir)*vel_mag,
                });
            }
          }());
          asteroids.splice(j, 1);
          bullets.splice(i, 1);
          i--; // so we don't skip the next bullet
          break;
        }
      }
    }
    for (i = 0; i < asteroids.length; i++) {
      if (intersects(you_actual_loc, PACMAN_RADIUS, asteroids[i], asteroids[i].radius)) {
        you_have_lost = true;
      }
    }

    game_canvas_context.fillStyle = "yellow";

    if (current_movement.x > 0) you_movement_angle = 0;
    if (current_movement.y > 0) you_movement_angle = Math.TAU / 4;
    if (current_movement.x < 0) you_movement_angle = Math.TAU / 2;
    if (current_movement.y < 0) you_movement_angle = Math.TAU * 3 / 4;
    mouth_open_angle = 0.5 - Math.abs(progress - 0.5);

    draw_all_four(you_actual_loc.x, you_actual_loc.y, function(draw_x, draw_y){
      var EYE_LENGTH = PACMAN_RADIUS / 4;
      var EYE_DISTANCE = PACMAN_RADIUS / 2.8;
      if (you_have_lost) {
        game_canvas_context.beginPath();
        game_canvas_context.arc(draw_x,draw_y,PACMAN_RADIUS,0,Math.TAU,true);
        game_canvas_context.closePath();
        game_canvas_context.fill();

        game_canvas_context.lineWidth = 1.5;
        game_canvas_context.beginPath();
        game_canvas_context.moveTo(draw_x - EYE_DISTANCE - EYE_LENGTH, draw_y - EYE_DISTANCE - EYE_LENGTH);
        game_canvas_context.lineTo(draw_x - EYE_DISTANCE + EYE_LENGTH, draw_y - EYE_DISTANCE + EYE_LENGTH);
        game_canvas_context.moveTo(draw_x - EYE_DISTANCE - EYE_LENGTH, draw_y - EYE_DISTANCE + EYE_LENGTH);
        game_canvas_context.lineTo(draw_x - EYE_DISTANCE + EYE_LENGTH, draw_y - EYE_DISTANCE - EYE_LENGTH);
        game_canvas_context.moveTo(draw_x + EYE_DISTANCE - EYE_LENGTH, draw_y - EYE_DISTANCE - EYE_LENGTH);
        game_canvas_context.lineTo(draw_x + EYE_DISTANCE + EYE_LENGTH, draw_y - EYE_DISTANCE + EYE_LENGTH);
        game_canvas_context.moveTo(draw_x + EYE_DISTANCE - EYE_LENGTH, draw_y - EYE_DISTANCE + EYE_LENGTH);
        game_canvas_context.lineTo(draw_x + EYE_DISTANCE + EYE_LENGTH, draw_y - EYE_DISTANCE - EYE_LENGTH);
        game_canvas_context.stroke();
      }
      else {
        game_canvas_context.beginPath();
        game_canvas_context.arc(draw_x,draw_y,PACMAN_RADIUS,you_movement_angle + mouth_open_angle,you_movement_angle + Math.TAU - mouth_open_angle,false);
        game_canvas_context.lineTo(draw_x,draw_y);
        game_canvas_context.closePath();
        game_canvas_context.fill();
      }
    });
    for (x = 0; x < ARENA_WIDTH; x++) {
      for (y = 0; y < ARENA_WIDTH; y++) {
        if (dots[x][y]) {
          draw_all_four(x*TILE_SIZE, y*TILE_SIZE, function(draw_x, draw_y){
            game_canvas_context.beginPath();
            game_canvas_context.arc(draw_x,draw_y,DOT_RADIUS,0,Math.TAU,true);
            game_canvas_context.closePath();
            game_canvas_context.fill();
          });
        }
      }
    }
    for (i = 0; i < bullets.length; i++) {
      draw_all_four(bullets[i].x, bullets[i].y, function(draw_x, draw_y){
        game_canvas_context.beginPath();
        game_canvas_context.arc(draw_x, draw_y, DOT_RADIUS, 0, Math.TAU, true);
        game_canvas_context.closePath();
        game_canvas_context.fill();
      });
    }
    game_canvas_context.fillStyle = "gray";
    for (i = 0; i < asteroids.length; i++) {
      draw_all_four(asteroids[i].x, asteroids[i].y, function(draw_x, draw_y){
        game_canvas_context.beginPath();
        game_canvas_context.arc(draw_x, draw_y, asteroids[i].radius, 0, Math.TAU, true);
        game_canvas_context.closePath();
        game_canvas_context.fill();
      });
    }

    if (mousedown) {  
      game_canvas_context.beginPath();
      game_canvas_context.arc(mouse_x,mouse_y,15,0,Math.TAU,true);
      game_canvas_context.closePath();
      game_canvas_context.stroke();
    }
  };

  for (x = 0; x < ARENA_WIDTH; x++) {
    dots[x] = [];
    for (y = 0; y < ARENA_HEIGHT; y++) {
      dots[x][y] = true;
    }
  }

  // blargh... this "function" is just to give me a new scope
  (function(){
    var i, loc_rand, vel_dir, vel_mag, x, y;
    for (i = 0; i < 8; ++i) {
      loc_rand = Math.random() * (ARENA_WIDTH + ARENA_HEIGHT) * TILE_SIZE;
      if (loc_rand < ARENA_WIDTH*TILE_SIZE) {
        x = loc_rand; y = 0;
      }
      else {
        x = 0; y = loc_rand - ARENA_WIDTH*TILE_SIZE;
      }
      vel_dir = Math.random() * Math.TAU;
      vel_mag = Math.random() * 3;
      asteroids.push({
        radius: (Math.random() * 1.2 + 0.7) * TILE_SIZE,
        x: x,
        y: y,
        vx: vel_mag * Math.cos(vel_dir),
        vy: vel_mag * Math.sin(vel_dir),
        });
    }
  }());

  $(document).mousedown(function(){
    mousedown = true;
    return false;
  });
  $(document).mouseup(function(){
    mousedown = false;
    return false;
  });
  $(document).mousemove(function(e){
    var offs = $('#game_canvas').offset();
    mouse_x = e.pageX - offs.left;
    mouse_y = e.pageY - offs.top;
    return false;
  });
  $(document).keydown(function(e){
    var keycode = (e.keyCode ? e.keyCode : e.which);
    var keystr = String.fromCharCode(keycode);
    if (keycode === 37 || keystr === "A") { wanted_movement = { x: -1, y: 0 }; }
    if (keycode === 38 || keystr === "W") { wanted_movement = { x: 0, y: -1 }; }
    if (keycode === 39 || keystr === "D") { wanted_movement = { x: 1, y: 0 }; }
    if (keycode === 40 || keystr === "S") { wanted_movement = { x: 0, y: 1 }; }
    return false;
  });



  (function tickloop(){
    setTimeout(tickloop, Math.floor(1000/30));
    if (tick_finished) {
      tick_finished = false;
      tick();
      tick_finished = true;
      ticks += 1;
    }
    else {
      tick_skips += 1;
    }
    $('#info').html('Info:<br/>Control the pac-man with the arrow keys or WASD. Aim with the mouse. Don\'t get hit by the asteroids.<br/>Ticks: '+ticks+'<br/>Ticks skipped: '+tick_skips);
  }());

});
    </script>''',
      '''<a class="skip" href="#content">Skip to content</a>
      '''+bars.bars_wrap({"games":True}, '''<main><div id="content" style=" background-color: white; cursor: crosshair">

    <div style=" width:640px; margin: 0 auto">    <div id="info"></div><canvas id="game_canvas" width="640" height="480">
The game should appear here, but it hasn't. Maybe you don't have JavaScript enabled. Or maybe your browser doesn't support the canvas element.
    </canvas>
    '''+ blog.comments_section ("pac_asteroids") +''' </div>
  </div>
</main>'''), {"jQuery_before": True, "blurb": "A half-baked, unfinished online game.", "blurb_image": "/media/pac-asteroids-thumbnail.png?rr"}
  )