text:
var Achicken = Achicken || {};
var socket = io.connect(window.location.href);;
socket.on('greet', function(data) {
	console.log(data);
	socket.emit('respond', {message: 'Hello to you too, server'});
});

Achicken.GameState = {

	init: function(currentLevel) {
		//constants
		this.MAX_DISTANCE_SHOOT = 190;
		this.MAX_SPEED_SHOOT = 1100;
		this.SHOOT_FACTOR = 12;
		this.KILL_DIFF = 25;

		//keep track of the current level
		this.currentLevel = currentLevel ? currentLevel : 'level1';

		//gravity
		this.game.physics.p2.gravity.y = 1000;

		//collision groups - if you want to specify what collides with what
		this.blocksCollisionGroup = this.game.physics.p2.createCollisionGroup();
		this.playerCollisionGroup = this.game.physics.p2.createCollisionGroup();
	},
	create: function() {
		//sky background
		this.sky = this.add.tileSprite(0, 0, this.game.world.width, this.game.world.height, 'sky');
		this.game.world.sendToBack(this.sky);

		this.chickenHUD = this.add.group();

		//blocks
		this.blocks = this.add.group();
		this.blocks.enableBody = true;
		this.blocks.physicsBodyType = Phaser.Physics.P2JS;

		//bodies in p2 -> they get their anchor points set to 0.5
		this.floor = this.add.tileSprite(this.game.world.width/2, this.game.world.height - 24, this.game.world.width, 48, 'floor');
		this.blocks.add(this.floor);

		//specify collision for the floor
		this.floor.body.setCollisionGroup(this.blocksCollisionGroup);
		this.floor.body.collides([this.blocksCollisionGroup, this.playerCollisionGroup]);
		this.floor.body.static = true;

		this.player = this.add.sprite(180, 400, 'chicken');
		this.game.physics.p2.enable(this.player);
		this.player.enableBody = true;
		this.player.physicsBodyType = Phaser.Physics.P2JS;
		this.player.body.setCollisionGroup(this.playerCollisionGroup);
		this.player.body.collides([this.blocksCollisionGroup]);

		this.cursors = this.game.input.keyboard.createCursorKeys();
	},

	update: function() {
		if (this.cursors.left.isDown) {
			this.player.body.applyForce([10, 0], this.player.x, this.player.y);
		}
		if (this.cursors.right.isDown) {
			this.player.body.applyForce([-10, 0], this.player.x, this.player.y);
		}
		if (this.cursors.up.upDuration()) {
			this.player.body.moveUp(200);
		}
	}
};


text:
#pragma once

#include "Packet.h"
#include "message_id.h"
#include <protocol/data/Client.h>

namespace ceema {

    class Acknowledgement : public Packet {
        client_id m_sender;
        message_id m_message;

    public:
        // Creates ACK packet of type ACK_CLIENT (see fromPacket for ACK_SERVER)
        Acknowledgement(client_id const& sender, message_id const& message) : Packet(PacketType::ACK_CLIENT),
                                                                              m_sender(sender), m_message(message) {}
        Acknowledgement(Acknowledgement const&) = default;
        Acknowledgement(Acknowledgement &&) = default;

        Acknowledgement& operator=(Acknowledgement const&) = default;
        Acknowledgement& operator=(Acknowledgement &&) = default;

        client_id const& sender() const {
            return m_sender;
        }

        message_id const& message() const {
            return m_message;
        }

        static Acknowledgement fromPacket(PacketType type, byte_vector const& packet);
        byte_vector toPacket() const;

    private:
        Acknowledgement() : Packet(PacketType::ACK_SERVER) {}

    };

}

redpajama_set_name: RedPajamaGithub


text:
/* $Id$ */

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.manifoldcf.agents.output.elasticsearch.tests;

import org.elasticsearch.node.Node;
import org.junit.After;
import org.junit.Before;

import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;

import static org.elasticsearch.node.NodeBuilder.*;

/**
 *  Base integration tests class for Elastic Search tested against a CMIS repository
 *  @author Piergiorgio Lucidi
 *
 * */
public class BaseITHSQLDB extends org.apache.manifoldcf.crawler.tests.BaseITHSQLDB
{
  protected Node node = null;

  protected String[] getConnectorNames()
  {
    return new String[]{"CMIS"};
  }

  protected String[] getConnectorClasses()
  {
    return new String[]{"org.apache.manifoldcf.crawler.tests.TestingRepositoryConnector"};
  }

  protected String[] getOutputNames()
  {
    return new String[]{"ElasticSearch"};
  }

  protected String[] getOutputClasses()
  {
    return new String[]{"org.apache.manifoldcf.agents.output.elasticsearch.ElasticSearchConnector"};
  }

  @Before
  public void setupElasticSearch()
    throws Exception
  {
    //Initialize ElasticSearch server
    //the default port is 9200
    System.out.println("ElasticSearch is starting...");
    node = nodeBuilder().local(true).node();
    System.out.println("ElasticSearch is started on port 9200");
  }

  @After
  public void cleanUpElasticSearch(){
    if(node!=null)
      node.close();
  }

}


text:
import "./levels.filter";
import "./regex.filter";
import "./start-from.filter";


text:
<!-- =================================================================
     Custom Ore Generation "Flaxbeards Steamcraft" Module: This
     configuration covers copper, mountain copper, zinc, and mountain
     zinc.
     ================================================================= -->

<!-- A mod centered around steam power. Configuration by Reteo. -->

<!-- Is the "Flaxbeards Steamcraft" mod on the system?  Let's find
     out! -->
<IfModInstalled name="Steamcraft">

  <!-- Starting Configuration for Custom Ore Generation. -->
  <ConfigSection>

    <!-- Setup Screen Configuration -->
    <ConfigSection>
      <OptionDisplayGroup name='groupFlaxbeardsSteamcraft' displayName='Flaxbeards Steamcraft' displayState='shown'>
        <Description>
          Distribution options for Flaxbeards Steamcraft Ores.
        </Description>
      </OptionDisplayGroup>
      <OptionChoice name='enableFlaxbeardsSteamcraft' displayName='Handle Flaxbeards Steamcraft Setup?' default='true' displayState='shown_dynamic' displayGroup='groupFlaxbeardsSteamcraft'>
        <Description> Should Custom Ore Generation handle Flaxbeards Steamcraft ore generation? </Description>
        <Choice value=':= ?true' displayValue='Yes' description='Use Custom Ore Generation to handle Flaxbeards Steamcraft ores.'/>
        <Choice value=':= ?false' displayValue='No' description='Flaxbeards Steamcraft ores will be handled by the mod itself.'/>
      </OptionChoice>
      <OptionChoice name='cleanUpFlaxbeardsSteamcraft' displayName='Use Flaxbeards Steamcraft Cleanup?' default='true' displayState='shown_dynamic' displayGroup='groupFlaxbeardsSteamcraft'>
        <Description> Should Custom Ore Generation use the Substitution Pass to remove all instances of Flaxbeards Steamcraft ore from the world?  If the mod's oregen can be turned off in its configuration, then it's recommended to do so, as the substitution pass can slow the game significantly.  If this option is disabled without disabling the mod's own ore generation, you'll end up with two oregens working at once, flooding the world with ore.  Enabled by default to ensure the ores are completely removed. </Description>
        <Choice value=':= ?true' displayValue='Yes' description='Use the substitution pass to clean up Flaxbeards Steamcraft ores.'/>
        <Choice value=':= ?false' displayValue='No' description='Flaxbeards Steamcraft ores do not need to be cleaned up by a substitution pass.'/>
      </OptionChoice>

      <!-- Copper Configuration UI Starting -->
      <ConfigSection>
        <OptionChoice name='flxbCopperDist'  displayState=':= if(?enableFlaxbeardsSteamcraft, "shown", "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Controls how Copper is generated </Description>
          <DisplayName>Flaxbeards Steamcraft Copper</DisplayName>
          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre")) '>

          <Choice value='LayeredVeins' displayValue='Layered Veins'>
            <Description>
              Small, fairly rare motherlodes with 2-4 horizontal veins each.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre")) '>

          <Choice value='StrategicClouds' displayValue='Strategic Clouds'>
            <Description>
              Large irregular clouds filled lightly with ore.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre")) '>

          <Choice value='Vanilla' displayValue='Vanilla'>
            <Description>
              Simulates Vanilla Minecraft.
            </Description>
          </Choice>
          </IfCondition>

          <Choice value='none' displayValue='None' description='Copper is not generated in the world.'/>
        </OptionChoice>
        <OptionNumeric name='flxbCopperFreq' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Frequency multiplier for Flaxbeards Steamcraft Copper distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Copper Freq.</DisplayName>
        </OptionNumeric>
        <OptionNumeric name='flxbCopperSize' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Size multiplier for Flaxbeards Steamcraft Copper distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Copper Size</DisplayName>
        </OptionNumeric>
      </ConfigSection>
      <!-- Copper Configuration UI Complete -->

      <!-- Mountain Copper Configuration UI Starting -->
      <ConfigSection>
        <OptionChoice name='flxbMountainCopperDist'  displayState=':= if(?enableFlaxbeardsSteamcraft, "shown", "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Controls how Mountain Copper is generated </Description>
          <DisplayName>Flaxbeards Steamcraft Mountain Copper</DisplayName>
          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre")) '>

          <Choice value='LayeredVeins' displayValue='Layered Veins'>
            <Description>
              Small, fairly rare motherlodes with 2-4 horizontal veins each.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre")) '>

          <Choice value='StrategicClouds' displayValue='Strategic Clouds'>
            <Description>
              Large irregular clouds filled lightly with ore.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre")) '>

          <Choice value='Vanilla' displayValue='Vanilla'>
            <Description>
              Simulates Vanilla Minecraft.
            </Description>
          </Choice>
          </IfCondition>

          <Choice value='none' displayValue='None' description='Mountain Copper is not generated in the world.'/>
        </OptionChoice>
        <OptionNumeric name='flxbMountainCopperFreq' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Frequency multiplier for Flaxbeards Steamcraft Mountain Copper distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Mountain Copper Freq.</DisplayName>
        </OptionNumeric>
        <OptionNumeric name='flxbMountainCopperSize' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Size multiplier for Flaxbeards Steamcraft Mountain Copper distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Mountain Copper Size</DisplayName>
        </OptionNumeric>
      </ConfigSection>
      <!-- Mountain Copper Configuration UI Complete -->

      <!-- Zinc Configuration UI Starting -->
      <ConfigSection>
        <OptionChoice name='flxbZincDist'  displayState=':= if(?enableFlaxbeardsSteamcraft, "shown", "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Controls how Zinc is generated </Description>
          <DisplayName>Flaxbeards Steamcraft Zinc</DisplayName>
          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre:1")) '>

          <Choice value='LayeredVeins' displayValue='Layered Veins'>
            <Description>
              Small, fairly rare motherlodes with 2-4 horizontal veins each.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre:1")) '>

          <Choice value='StrategicClouds' displayValue='Strategic Clouds'>
            <Description>
              Large irregular clouds filled lightly with ore.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre:1")) '>

          <Choice value='Vanilla' displayValue='Vanilla'>
            <Description>
              Simulates Vanilla Minecraft.
            </Description>
          </Choice>
          </IfCondition>

          <Choice value='none' displayValue='None' description='Zinc is not generated in the world.'/>
        </OptionChoice>
        <OptionNumeric name='flxbZincFreq' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Frequency multiplier for Flaxbeards Steamcraft Zinc distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Zinc Freq.</DisplayName>
        </OptionNumeric>
        <OptionNumeric name='flxbZincSize' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Size multiplier for Flaxbeards Steamcraft Zinc distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Zinc Size</DisplayName>
        </OptionNumeric>
      </ConfigSection>
      <!-- Zinc Configuration UI Complete -->

      <!-- Mountain Zinc Configuration UI Starting -->
      <ConfigSection>
        <OptionChoice name='flxbMountainZincDist'  displayState=':= if(?enableFlaxbeardsSteamcraft, "shown", "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Controls how Mountain Zinc is generated </Description>
          <DisplayName>Flaxbeards Steamcraft Mountain Zinc</DisplayName>
          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre:1")) '>

          <Choice value='LayeredVeins' displayValue='Layered Veins'>
            <Description>
              Small, fairly rare motherlodes with 2-4 horizontal veins each.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre:1")) '>

          <Choice value='StrategicClouds' displayValue='Strategic Clouds'>
            <Description>
              Large irregular clouds filled lightly with ore.
            </Description>
          </Choice>
          </IfCondition>

          <IfCondition condition=':= (?blockExists("Steamcraft:steamcraftOre:1")) '>

          <Choice value='Vanilla' displayValue='Vanilla'>
            <Description>
              Simulates Vanilla Minecraft.
            </Description>
          </Choice>
          </IfCondition>

          <Choice value='none' displayValue='None' description='Mountain Zinc is not generated in the world.'/>
        </OptionChoice>
        <OptionNumeric name='flxbMountainZincFreq' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Frequency multiplier for Flaxbeards Steamcraft Mountain Zinc distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Mountain Zinc Freq.</DisplayName>
        </OptionNumeric>
        <OptionNumeric name='flxbMountainZincSize' default='1'  min='0' max='5' displayState=':= if(?enableFlaxbeardsSteamcraft, if(?advOptions, "shown", "hidden"), "hidden")' displayGroup='groupFlaxbeardsSteamcraft'>
          <Description> Size multiplier for Flaxbeards Steamcraft Mountain Zinc distributions </Description>
          <DisplayName>Flaxbeards Steamcraft Mountain Zinc Size</DisplayName>
        </OptionNumeric>
      </ConfigSection>
      <!-- Mountain Zinc Configuration UI Complete -->

    </ConfigSection>
    <!-- Setup Screen Complete -->

    <IfCondition condition=':= ?enableFlaxbeardsSteamcraft'>

      <!-- Overworld Setup Beginning -->

      <IfCondition condition=':= ?COGActive'>

        <!-- Starting Original "Overworld" Block Removal -->

        <IfCondition condition=':= ?cleanUpFlaxbeardsSteamcraft'>
          <IfCondition condition=':= ?blockExists("minecraft:stone")'>
            <Substitute name='flxbOverworldBlockSubstitute0' block='minecraft:stone'>
              <Description>
                Replace vanilla-generated ore clusters.
              </Description>
              <Comment>
                The global option  deferredPopulationRange must be
                large enough to catch all ore  clusters (>= 32).
              </Comment>
              <Replaces block='Steamcraft:steamcraftOre' weight='1.0' />
              <Replaces block='Steamcraft:steamcraftOre:1' weight='1.0' />
            </Substitute>
          </IfCondition>
        </IfCondition>

        <!-- Original "Overworld" Block Removal Complete -->

        <!-- Adding blocks -->

        <!-- Begin Copper Generation -->

        <!-- Starting LayeredVeins Preset for Copper. -->
        <ConfigSection>
          <IfCondition condition=':= flxbCopperDist = "LayeredVeins"'>
            <Veins name='flxbCopperVeins'  inherits='PresetLayeredVeins' branchType='Bezier' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
              <Description>
                Small, fairly rare motherlodes  with 2-4 horizontal
                veins each.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <Biome name='.*'  />
              <Setting name='MotherlodeFrequency' avg=':= 1.251 * _default_ * flxbCopperFreq ' range=':= 1.251 * _default_ * flxbCopperFreq ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeSize' avg=':= 1.038 * _default_ * flxbCopperSize ' range=':= 1.038 * _default_ * flxbCopperSize ' type='normal' />
              <Setting name='MotherlodeHeight' avg=':= 42.5 ' range=':= 37.5 ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchLength' avg=':= 1.119 * _default_ ' range=':= 1.119 * _default_ ' type='normal' />
              <Setting name='BranchHeightLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='SegmentForkFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentForkLengthMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentLength' avg=':= _default_ * flxbCopperSize ' range=':= _default_ * flxbCopperSize ' type='normal' />
              <Setting name='SegmentAngle' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentPitch' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentRadius' avg=':= 1.058 * _default_ * flxbCopperSize ' range=':= 1.058 * _default_ * flxbCopperSize ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </Veins>
          </IfCondition>
        </ConfigSection>
        <!-- LayeredVeins Preset for Copper is complete. -->

        <!-- Starting StrategicClouds Preset for Copper. -->
        <ConfigSection>
          <IfCondition condition=':= flxbCopperDist = "StrategicClouds"'>
            <Cloud name='flxbCopperCloud'  inherits='PresetStrategicCloud' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
              <Description>
                Large irregular clouds filled  lightly with ore.
                These are  huge, spanning several adjacent  chunks,
                and consequently rather  rare.  They contain a
                sizeable  amount of ore, but it takes some  time and
                effort to mine due to  low density. The intent for
                strategic clouds is that the  player will need to
                actively  search for one and then set up a  semi-
                permanent mining base and  spend some time actually
                mining  the ore.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <Biome name='.*'  />
              <Setting name='CloudRadius' avg=':= 1.195 * _default_ * flxbCopperSize ' range=':= 1.195 * _default_ * flxbCopperSize ' type='normal' />
              <Setting name='CloudThickness' avg=':= 1.195 * _default_ * flxbCopperSize ' range=':= 1.195 * _default_ * flxbCopperSize ' type='normal' scaleTo='base' />
              <Setting name='DistributionFrequency' avg=':= 1.429 * _default_ * flxbCopperFreq ' range=':= 1.429 * _default_ * flxbCopperFreq ' type='normal' scaleTo='base' />
              <Setting name='CloudHeight' avg=':= 42.5 ' range=':= 37.5 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudSizeNoise' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='OreVolumeNoiseCutoff' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Veins name='flxbCopperHintVeins' branchType='Bezier'  inherits='PresetHintVeins' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
                <Description>
                  Single blocks, generously  scattered through all
                  heights  (density is about that of  vanilla iron
                  ore). They will  replace dirt and sandstone  (but
                  not grass or sand), so  they can be found nearer to
                  the surface than most ores.  Intened to be used as a
                  child  distribution for large, rare  strategic
                  deposits that would  otherwise be very difficult  to
                  find.  Note that the  frequency is multiplied by
                  ground level to maintain a  constant density, but
                  not by  ore frequency because it is  assumed that
                  the frequency of  the parent distribution will
                  already be scaled by that.
                </Description>
                <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
                <Replaces block='minecraft:dirt' weight='1.0' />
                <Replaces block='minecraft:sandstone' weight='1.0' />
                <ReplacesOre block='stone' weight='1.0' />
                <Replaces block='minecraft:gravel' weight='1.0' />
                <Setting name='MotherlodeFrequency' avg=':= 1.251 * _default_ * flxbCopperFreq  * 0.1 ' range=':= 1.251 * _default_ * flxbCopperFreq  * 0.1 ' type='normal' scaleTo='base' />
              </Veins>
            </Cloud>
          </IfCondition>
        </ConfigSection>
        <!-- StrategicClouds Preset for Copper is complete. -->

        <!-- Starting Vanilla Preset for Copper. -->
        <ConfigSection>
          <IfCondition condition=':= flxbCopperDist = "Vanilla"'>
            <StandardGen name='flxbCopperStandard'  inherits='PresetStandardGen' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
              <Description>
                A master preset for standardgen  ore distributions.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <Biome name='.*'  />
              <Setting name='Size' avg=':= 3.333 * flxbCopperSize ' range=':= 1.67 * flxbCopperSize ' type='normal' />
              <Setting name='Frequency' avg=':= 6.667 * flxbCopperFreq ' range=':= 3.33 * flxbCopperFreq ' type='normal' scaleTo='base' />
              <Setting name='Height' avg=':= 42.5 ' range=':= 37.5 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </StandardGen>
          </IfCondition>
        </ConfigSection>
        <!-- Vanilla Preset for Copper is complete. -->

        <!-- End Copper Generation -->

        <!-- Begin Mountain Copper Generation -->

        <!-- Starting LayeredVeins Preset for Mountain Copper. -->
        <ConfigSection>
          <IfCondition condition=':= flxbMountainCopperDist = "LayeredVeins"'>
            <Veins name='flxbMountainCopperVeins'  inherits='PresetLayeredVeins' branchType='Bezier' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
              <Description>
                Small, fairly rare motherlodes  with 2-4 horizontal
                veins each.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <BiomeType name='Mountain'  />
              <Setting name='MotherlodeFrequency' avg=':= 1.251 * _default_ * flxbMountainCopperFreq ' range=':= 1.251 * _default_ * flxbMountainCopperFreq ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeSize' avg=':= 1.038 * _default_ * flxbMountainCopperSize ' range=':= 1.038 * _default_ * flxbMountainCopperSize ' type='normal' />
              <Setting name='MotherlodeHeight' avg=':= 191.5 ' range=':= 112.5 ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchLength' avg=':= 1.119 * _default_ ' range=':= 1.119 * _default_ ' type='normal' />
              <Setting name='BranchHeightLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='SegmentForkFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentForkLengthMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentLength' avg=':= _default_ * flxbMountainCopperSize ' range=':= _default_ * flxbMountainCopperSize ' type='normal' />
              <Setting name='SegmentAngle' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentPitch' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentRadius' avg=':= 1.058 * _default_ * flxbMountainCopperSize ' range=':= 1.058 * _default_ * flxbMountainCopperSize ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </Veins>
          </IfCondition>
        </ConfigSection>
        <!-- LayeredVeins Preset for Mountain Copper is  complete. -->

        <!-- Starting StrategicClouds Preset for Mountain  Copper. -->
        <ConfigSection>
          <IfCondition condition=':= flxbMountainCopperDist = "StrategicClouds"'>
            <Cloud name='flxbMountainCopperCloud'  inherits='PresetStrategicCloud' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
              <Description>
                Large irregular clouds filled  lightly with ore.
                These are  huge, spanning several adjacent  chunks,
                and consequently rather  rare.  They contain a
                sizeable  amount of ore, but it takes some  time and
                effort to mine due to  low density. The intent for
                strategic clouds is that the  player will need to
                actively  search for one and then set up a  semi-
                permanent mining base and  spend some time actually
                mining  the ore.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <BiomeType name='Mountain'  />
              <Setting name='CloudRadius' avg=':= 1.195 * _default_ * flxbMountainCopperSize ' range=':= 1.195 * _default_ * flxbMountainCopperSize ' type='normal' />
              <Setting name='CloudThickness' avg=':= 1.195 * _default_ * flxbMountainCopperSize ' range=':= 1.195 * _default_ * flxbMountainCopperSize ' type='normal' scaleTo='base' />
              <Setting name='DistributionFrequency' avg=':= 1.429 * _default_ * flxbMountainCopperFreq ' range=':= 1.429 * _default_ * flxbMountainCopperFreq ' type='normal' scaleTo='base' />
              <Setting name='CloudHeight' avg=':= 191.5 ' range=':= 112.5 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudSizeNoise' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='OreVolumeNoiseCutoff' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Veins name='flxbMountainCopperHintVeins' branchType='Bezier'  inherits='PresetHintVeins' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
                <Description>
                  Single blocks, generously  scattered through all
                  heights  (density is about that of  vanilla iron
                  ore). They will  replace dirt and sandstone  (but
                  not grass or sand), so  they can be found nearer to
                  the surface than most ores.  Intened to be used as a
                  child  distribution for large, rare  strategic
                  deposits that would  otherwise be very difficult  to
                  find.  Note that the  frequency is multiplied by
                  ground level to maintain a  constant density, but
                  not by  ore frequency because it is  assumed that
                  the frequency of  the parent distribution will
                  already be scaled by that.
                </Description>
                <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
                <Replaces block='minecraft:dirt' weight='1.0' />
                <Replaces block='minecraft:sandstone' weight='1.0' />
                <ReplacesOre block='stone' weight='1.0' />
                <Replaces block='minecraft:gravel' weight='1.0' />
                <Setting name='MotherlodeFrequency' avg=':= 1.251 * _default_ * flxbMountainCopperFreq  * 0.1 ' range=':= 1.251 * _default_ * flxbMountainCopperFreq  * 0.1 ' type='normal' scaleTo='base' />
              </Veins>
            </Cloud>
          </IfCondition>
        </ConfigSection>
        <!-- StrategicClouds Preset for Mountain Copper is  complete. -->

        <!-- Starting Vanilla Preset for Mountain Copper. -->
        <ConfigSection>
          <IfCondition condition=':= flxbMountainCopperDist = "Vanilla"'>
            <StandardGen name='flxbMountainCopperStandard'  inherits='PresetStandardGen' drawWireframe='true' wireframeColor='0x60D26B2F' drawBoundBox='false' boundBoxColor='0x60D26B2F'>
              <Description>
                A master preset for standardgen  ore distributions.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <BiomeType name='Mountain'  />
              <Setting name='Size' avg=':= 3.333 * flxbMountainCopperSize ' range=':= 1.67 * flxbMountainCopperSize ' type='normal' />
              <Setting name='Frequency' avg=':= 6.667 * flxbMountainCopperFreq ' range=':= 3.33 * flxbMountainCopperFreq ' type='normal' scaleTo='base' />
              <Setting name='Height' avg=':= 191.5 ' range=':= 112.5 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </StandardGen>
          </IfCondition>
        </ConfigSection>
        <!-- Vanilla Preset for Mountain Copper is complete. -->

        <!-- End Mountain Copper Generation -->

        <!-- Begin Zinc Generation -->

        <!-- Starting LayeredVeins Preset for Zinc. -->
        <ConfigSection>
          <IfCondition condition=':= flxbZincDist = "LayeredVeins"'>
            <Veins name='flxbZincVeins'  inherits='PresetLayeredVeins' branchType='Bezier' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
              <Description>
                Small, fairly rare motherlodes  with 2-4 horizontal
                veins each.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <Biome name='.*'  />
              <Setting name='MotherlodeFrequency' avg=':= 0.936 * _default_ * flxbZincFreq ' range=':= 0.936 * _default_ * flxbZincFreq ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeSize' avg=':= 0.989 * _default_ * flxbZincSize ' range=':= 0.989 * _default_ * flxbZincSize ' type='normal' />
              <Setting name='MotherlodeHeight' avg=':= 40 ' range=':= 35 ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchLength' avg=':= 0.968 * _default_ ' range=':= 0.968 * _default_ ' type='normal' />
              <Setting name='BranchHeightLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='SegmentForkFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentForkLengthMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentLength' avg=':= _default_ * flxbZincSize ' range=':= _default_ * flxbZincSize ' type='normal' />
              <Setting name='SegmentAngle' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentPitch' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentRadius' avg=':= 0.984 * _default_ * flxbZincSize ' range=':= 0.984 * _default_ * flxbZincSize ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </Veins>
          </IfCondition>
        </ConfigSection>
        <!-- LayeredVeins Preset for Zinc is complete. -->

        <!-- Starting StrategicClouds Preset for Zinc. -->
        <ConfigSection>
          <IfCondition condition=':= flxbZincDist = "StrategicClouds"'>
            <Cloud name='flxbZincCloud'  inherits='PresetStrategicCloud' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
              <Description>
                Large irregular clouds filled  lightly with ore.
                These are  huge, spanning several adjacent  chunks,
                and consequently rather  rare.  They contain a
                sizeable  amount of ore, but it takes some  time and
                effort to mine due to  low density. The intent for
                strategic clouds is that the  player will need to
                actively  search for one and then set up a  semi-
                permanent mining base and  spend some time actually
                mining  the ore.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <Biome name='.*'  />
              <Setting name='CloudRadius' avg=':= 1.034 * _default_ * flxbZincSize ' range=':= 1.034 * _default_ * flxbZincSize ' type='normal' />
              <Setting name='CloudThickness' avg=':= 1.034 * _default_ * flxbZincSize ' range=':= 1.034 * _default_ * flxbZincSize ' type='normal' scaleTo='base' />
              <Setting name='DistributionFrequency' avg=':= 1.069 * _default_ * flxbZincFreq ' range=':= 1.069 * _default_ * flxbZincFreq ' type='normal' scaleTo='base' />
              <Setting name='CloudHeight' avg=':= 40 ' range=':= 35 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudSizeNoise' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='OreVolumeNoiseCutoff' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Veins name='flxbZincHintVeins' branchType='Bezier'  inherits='PresetHintVeins' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
                <Description>
                  Single blocks, generously  scattered through all
                  heights  (density is about that of  vanilla iron
                  ore). They will  replace dirt and sandstone  (but
                  not grass or sand), so  they can be found nearer to
                  the surface than most ores.  Intened to be used as a
                  child  distribution for large, rare  strategic
                  deposits that would  otherwise be very difficult  to
                  find.  Note that the  frequency is multiplied by
                  ground level to maintain a  constant density, but
                  not by  ore frequency because it is  assumed that
                  the frequency of  the parent distribution will
                  already be scaled by that.
                </Description>
                <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
                <Replaces block='minecraft:dirt' weight='1.0' />
                <Replaces block='minecraft:sandstone' weight='1.0' />
                <ReplacesOre block='stone' weight='1.0' />
                <Replaces block='minecraft:gravel' weight='1.0' />
                <Setting name='MotherlodeFrequency' avg=':= 0.936 * _default_ * flxbZincFreq  * 0.1 ' range=':= 0.936 * _default_ * flxbZincFreq  * 0.1 ' type='normal' scaleTo='base' />
              </Veins>
            </Cloud>
          </IfCondition>
        </ConfigSection>
        <!-- StrategicClouds Preset for Zinc is complete. -->

        <!-- Starting Vanilla Preset for Zinc. -->
        <ConfigSection>
          <IfCondition condition=':= flxbZincDist = "Vanilla"'>
            <StandardGen name='flxbZincStandard'  inherits='PresetStandardGen' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
              <Description>
                A master preset for standardgen  ore distributions.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <Biome name='.*'  />
              <Setting name='Size' avg=':= 2.667 * flxbZincSize ' range=':= 1.33 * flxbZincSize ' type='normal' />
              <Setting name='Frequency' avg=':= 4.667 * flxbZincFreq ' range=':= 2.33 * flxbZincFreq ' type='normal' scaleTo='base' />
              <Setting name='Height' avg=':= 40 ' range=':= 35 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </StandardGen>
          </IfCondition>
        </ConfigSection>
        <!-- Vanilla Preset for Zinc is complete. -->

        <!-- End Zinc Generation -->

        <!-- Begin Mountain Zinc Generation -->

        <!-- Starting LayeredVeins Preset for Mountain Zinc. -->
        <ConfigSection>
          <IfCondition condition=':= flxbMountainZincDist = "LayeredVeins"'>
            <Veins name='flxbMountainZincVeins'  inherits='PresetLayeredVeins' branchType='Bezier' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
              <Description>
                Small, fairly rare motherlodes  with 2-4 horizontal
                veins each.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <BiomeType name='Mountain'  />
              <Setting name='MotherlodeFrequency' avg=':= 0.936 * _default_ * flxbMountainZincFreq ' range=':= 0.936 * _default_ * flxbMountainZincFreq ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeSize' avg=':= 0.989 * _default_ * flxbMountainZincSize ' range=':= 0.989 * _default_ * flxbMountainZincSize ' type='normal' />
              <Setting name='MotherlodeHeight' avg=':= 184 ' range=':= 105 ' type='normal' scaleTo='base' />
              <Setting name='MotherlodeRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='BranchLength' avg=':= 0.968 * _default_ ' range=':= 0.968 * _default_ ' type='normal' />
              <Setting name='BranchHeightLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='SegmentForkFrequency' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentForkLengthMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentLength' avg=':= _default_ * flxbMountainZincSize ' range=':= _default_ * flxbMountainZincSize ' type='normal' />
              <Setting name='SegmentAngle' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentPitch' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='SegmentRadius' avg=':= 0.984 * _default_ * flxbMountainZincSize ' range=':= 0.984 * _default_ * flxbMountainZincSize ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </Veins>
          </IfCondition>
        </ConfigSection>
        <!-- LayeredVeins Preset for Mountain Zinc is  complete. -->

        <!-- Starting StrategicClouds Preset for Mountain  Zinc. -->
        <ConfigSection>
          <IfCondition condition=':= flxbMountainZincDist = "StrategicClouds"'>
            <Cloud name='flxbMountainZincCloud'  inherits='PresetStrategicCloud' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
              <Description>
                Large irregular clouds filled  lightly with ore.
                These are  huge, spanning several adjacent  chunks,
                and consequently rather  rare.  They contain a
                sizeable  amount of ore, but it takes some  time and
                effort to mine due to  low density. The intent for
                strategic clouds is that the  player will need to
                actively  search for one and then set up a  semi-
                permanent mining base and  spend some time actually
                mining  the ore.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <BiomeType name='Mountain'  />
              <Setting name='CloudRadius' avg=':= 1.034 * _default_ * flxbMountainZincSize ' range=':= 1.034 * _default_ * flxbMountainZincSize ' type='normal' />
              <Setting name='CloudThickness' avg=':= 1.034 * _default_ * flxbMountainZincSize ' range=':= 1.034 * _default_ * flxbMountainZincSize ' type='normal' scaleTo='base' />
              <Setting name='DistributionFrequency' avg=':= 1.069 * _default_ * flxbMountainZincFreq ' range=':= 1.069 * _default_ * flxbMountainZincFreq ' type='normal' scaleTo='base' />
              <Setting name='CloudHeight' avg=':= 184 ' range=':= 105 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudSizeNoise' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='CloudInclination' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreDensity' avg=':= _default_ ' range=':= _default_ ' type='normal' scaleTo='base' />
              <Setting name='OreVolumeNoiseCutoff' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Setting name='OreRadiusMult' avg=':= _default_ ' range=':= _default_ ' type='normal' />
              <Veins name='flxbMountainZincHintVeins' branchType='Bezier'  inherits='PresetHintVeins' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
                <Description>
                  Single blocks, generously  scattered through all
                  heights  (density is about that of  vanilla iron
                  ore). They will  replace dirt and sandstone  (but
                  not grass or sand), so  they can be found nearer to
                  the surface than most ores.  Intened to be used as a
                  child  distribution for large, rare  strategic
                  deposits that would  otherwise be very difficult  to
                  find.  Note that the  frequency is multiplied by
                  ground level to maintain a  constant density, but
                  not by  ore frequency because it is  assumed that
                  the frequency of  the parent distribution will
                  already be scaled by that.
                </Description>
                <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
                <Replaces block='minecraft:dirt' weight='1.0' />
                <Replaces block='minecraft:sandstone' weight='1.0' />
                <ReplacesOre block='stone' weight='1.0' />
                <Replaces block='minecraft:gravel' weight='1.0' />
                <Setting name='MotherlodeFrequency' avg=':= 0.936 * _default_ * flxbMountainZincFreq  * 0.1 ' range=':= 0.936 * _default_ * flxbMountainZincFreq  * 0.1 ' type='normal' scaleTo='base' />
              </Veins>
            </Cloud>
          </IfCondition>
        </ConfigSection>
        <!-- StrategicClouds Preset for Mountain Zinc is  complete. -->

        <!-- Starting Vanilla Preset for Mountain Zinc. -->
        <ConfigSection>
          <IfCondition condition=':= flxbMountainZincDist = "Vanilla"'>
            <StandardGen name='flxbMountainZincStandard'  inherits='PresetStandardGen' drawWireframe='true' wireframeColor='0x60EAEAEA' drawBoundBox='false' boundBoxColor='0x60EAEAEA'>
              <Description>
                A master preset for standardgen  ore distributions.
              </Description>
              <OreBlock block='Steamcraft:steamcraftOre:1' weight='1.0' />
              <ReplacesOre block='stone' weight='1.0' />
              <BiomeType name='Mountain'  />
              <Setting name='Size' avg=':= 2.667 * flxbMountainZincSize ' range=':= 1.33 * flxbMountainZincSize ' type='normal' />
              <Setting name='Frequency' avg=':= 4.667 * flxbMountainZincFreq ' range=':= 2.33 * flxbMountainZincFreq ' type='normal' scaleTo='base' />
              <Setting name='Height' avg=':= 184 ' range=':= 105 ' type='normal' scaleTo='base' />
              <Setting name='ParentRangeLimit' avg=':= _default_ ' range=':= _default_ ' type='normal' />
            </StandardGen>
          </IfCondition>
        </ConfigSection>
        <!-- Vanilla Preset for Mountain Zinc is complete. -->

        <!-- End Mountain Zinc Generation -->

        <!-- Finished adding blocks -->

      </IfCondition>
      <!-- Overworld Setup Complete -->

    </IfCondition>

  </ConfigSection>
  <!-- Configuration for Custom Ore Generation Complete! -->

</IfModInstalled>
<!-- The "Flaxbeards Steamcraft" mod is now configured. -->

<!-- =================================================================
     This file was made using the Sprocket Advanced Configuration
     Generator.  If you wish to make your own configurations for a mod
     not currently supported by Custom Ore Generation, and you don't
     want the hassle of writing XML, you can find the generator script
     at its GitHub page: http://https://github.com/reteo/Sprocket
     ================================================================= -->


text:
const float DEFAULT_SOUND_RADIUS = 36.0f;
// Keep an array of all looping sounds so they can be faded in/out
// OPTIMIZE: Get a handle/pointer to the engine's sound channel instead
//			of searching each frame!
enum soundfadestyle_t
{
	FADE_VOLUME_LINEAR = 0,
	FADE_VOLUME_SINE = 1,
};

// contains a set of data to implement a simple envelope to fade in/out sounds
struct soundfader_t
{
	float m_flCurrent;
	float m_flTarget;
	float m_flRate;
	float m_flStart;
	float m_flFadeT;
	int	m_nType;

	bool IsFading()
	{
		return ( m_flCurrent != m_flTarget ) ? true : false;
	}

	void FadeToValue( float flTarget, float flRate, soundfadestyle_t fadeType )
	{
		m_flStart = m_flCurrent;
		m_flFadeT = 0;
		m_flTarget = flTarget;
		m_flRate = flRate;
		m_nType = fadeType;
	}

	void ForceToTargetValue( float flTarget )
	{
		m_flFadeT = 1.0f;
		m_flCurrent = m_flTarget = flTarget;
		m_flRate = 0;
	}

	void UpdateFade( float flDt )
	{
		m_flFadeT += flDt * m_flRate;
		if ( m_flFadeT >= 1.0f )
		{
			ForceToTargetValue( m_flTarget );
			return;
		}
		float flFactor = m_flFadeT;
		float flDelta = m_flTarget - m_flStart;
		switch ( m_nType )
		{
		case FADE_VOLUME_LINEAR:
			break;
		case FADE_VOLUME_SINE:
			if ( flDelta >= 0 )
			{
				flFactor = sin( m_flFadeT * M_PI * 0.5f );
			}
			else
			{
				flFactor = 1.0f - cos( m_flFadeT * M_PI * 0.5f );
			}
			break;
		}
		m_flCurrent = m_flStart + flDelta * flFactor;
	}
};

struct loopingsound_t
{
	Vector		position;		// position (if !isAmbient)
	const char *pWaveName;		// name of the wave file
	soundfader_t m_volume;
	soundlevel_t soundlevel;	// sound level (if !isAmbient)
	int			pitch;			// pitch shift
	int			id;				// Used to fade out sounds that don't belong to the most current setting
	int			engineGuid;
	float		radius;			// if set, sound plays at full volume inside the radius and fallsoff as you move out of the radius.  Sound will lose directionality as you move inside the radius
	bool		isAmbient;		// Ambient sounds have no spatialization - they play from everywhere
};

ConVar soundscape_fadetime( "soundscape_fadetime", "3.0", FCVAR_CHEAT, "Time to crossfade sound effects between soundscapes" );
ConVar soundscape_message("soundscape_message","0");
ConVar soundscape_radius_debug( "soundscape_radius_debug", "0", FCVAR_CHEAT, "Prints current volume of radius sounds" );

float GetSoundscapeFadeRate()
{
	float flFadeTime = soundscape_fadetime.GetFloat();
	float flFadeRate = 1.0f / (flFadeTime > 0 ? flFadeTime : 3.0f);

	return flFadeRate;
}

#include "tier2/interval.h"

struct randomsound_t
{
	Vector		position;
	float		nextPlayTime;	// time to play a sound from the set
	interval_t	time;
	interval_t	volume;
	interval_t	pitch;
	interval_t	soundlevel;
	float		masterVolume;
	int			waveCount;
	bool		isAmbient;
	bool		isRandom;
	KeyValues	*pWaves;

	void Init()
	{
		memset( this, 0, sizeof(*this) );
	}
};

struct subsoundscapeparams_t
{
	int		recurseLevel;		// test for infinite loops in the script / circular refs
	float	masterVolume;
	float	flFadeRate;
	int		startingPosition;
	int		positionOverride;	// forces all sounds to this position
	int		ambientPositionOverride;	// forces all ambient sounds to this position
	bool	allowDSP;
	bool	wroteSoundMixer;
	bool	wroteDSPVolume;
};

Vector getVectorFromString(const char *pString)
{
	char tempString[128];
	Q_strncpy( tempString, pString, sizeof(tempString) );

	Vector result;
	int i = 0;
	char *token = strtok( tempString, "," );
	while( token )
	{
		result[i] = atof( token );
		token = strtok( NULL, "," );
		i++;
	}
	return result;
}
class C_SoundscapeSystem : public CBaseGameSystemPerFrame
{
public:
	virtual char const *Name() { return "C_SoundScapeSystem"; }

	C_SoundscapeSystem()
	{
		m_nRestoreFrame = -1;
	}

	~C_SoundscapeSystem() {}

	void OnStopAllSounds()
	{
		for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh )
		{
			ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
			GetPerUser(hh).m_params.entIndex = 0;
			GetPerUser(hh).m_params.soundscapeIndex = -1;
			GetPerUser(hh).m_loopingSounds.Purge();
			GetPerUser(hh).m_randomSounds.Purge();
		}
	}

	// IClientSystem hooks, not needed
	virtual void LevelInitPreEntity()
	{
		Shutdown();
		Init();

		TouchSoundFiles();
	}

	virtual void LevelInitPostEntity()
	{
		if ( !m_pSoundMixerVar )
		{
			m_pSoundMixerVar = (ConVar *)cvar->FindVar( "snd_soundmixer" );
		}
		if ( !m_pDSPVolumeVar )
		{
			m_pDSPVolumeVar = (ConVar *)cvar->FindVar( "dsp_volume" );
		}
	}

	// The level is shutdown in two parts
	virtual void LevelShutdownPreEntity() {}
	// Entities are deleted / released here...
	virtual void LevelShutdownPostEntity()
	{
		OnStopAllSounds();
	}

	virtual void OnSave() {}
	virtual void OnRestore()
	{
		m_nRestoreFrame = gpGlobals->framecount;
	}
	virtual void SafeRemoveIfDesired() {}

	// Called before rendering
	virtual void PreRender() { }

	// Called after rendering
	virtual void PostRender() { }

	// IClientSystem hooks used
	virtual bool Init();
	virtual void Shutdown();
	// Gets called each frame
	virtual void Update( float frametime );

	void PrintDebugInfo()
	{
		Msg( "\n------- CLIENT SOUNDSCAPES -------\n" );
		for ( int i=0; i < m_soundscapes.Count(); i++ )
		{
			Msg( "- %d: %s\n", i, m_soundscapes[i]->GetName() );
		}

		Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());

		if ( slot.m_forcedSoundscapeIndex )
		{
			Msg( "- PLAYING DEBUG SOUNDSCAPE: %d [%s]\n", slot.m_forcedSoundscapeIndex, SoundscapeNameByIndex(slot.m_forcedSoundscapeIndex) );
		}
		Msg( "- CURRENT SOUNDSCAPE: %d [%s]\n", slot.m_params.soundscapeIndex, SoundscapeNameByIndex(slot.m_params.soundscapeIndex) );
		Msg( "----------------------------------\n\n" );
	}

	// local functions
	void UpdateAudioParams( audioparams_t &audio );
	void GetAudioParams( audioparams_t &out ) const { out = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()).m_params; }
	int GetCurrentSoundscape()
	{
		Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());

		if ( slot.m_forcedSoundscapeIndex >= 0 )
			return slot.m_forcedSoundscapeIndex;
		return slot.m_params.soundscapeIndex;
	}
	void DevReportSoundscapeName( int index );
	void UpdateLoopingSounds( float frametime );
	int AddLoopingAmbient( const char *pSoundName, float volume, int pitch, float radius, float flFadeRate );
	void UpdateLoopingSound( loopingsound_t &loopSound );
	void StopLoopingSound( loopingsound_t &loopSound );
	int AddLoopingSound( const char *pSoundName, bool isAmbient, float volume,
		soundlevel_t soundLevel, int pitch, const Vector &position, float radius, float flFadeRate );
	int AddRandomSound( const randomsound_t &sound );
	void PlayRandomSound( randomsound_t &sound );
	void UpdateRandomSounds( float gameClock );
	Vector GenerateRandomSoundPosition();

	void ForceSoundscape( const char *pSoundscapeName, float radius );

	int FindSoundscapeByName( const char *pSoundscapeName );
	const char *SoundscapeNameByIndex( int index );
	KeyValues *SoundscapeByIndex( int index );

	// main-level soundscape processing, called on new soundscape
	void StartNewSoundscape( KeyValues *pSoundscape );
	void StartSubSoundscape( KeyValues *pSoundscape, subsoundscapeparams_t &params );

	// root level soundscape keys
	// add a process for each new command here
	// "dsp"
	void ProcessDSP( KeyValues *pDSP );
	// "dsp_player"
	void ProcessDSPPlayer( KeyValues *pDSPPlayer );
	// "fadetime"
	void ProcessSoundscapeFadetime( KeyValues *pKey, subsoundscapeparams_t &params );
	// "playlooping"
	void ProcessPlayLooping( KeyValues *pPlayLooping, const subsoundscapeparams_t &params );
	// "playrandom"
	void ProcessPlayRandom( KeyValues *pPlayRandom, const subsoundscapeparams_t &params );
	// "playsoundscape"
	void ProcessPlaySoundscape( KeyValues *pPlaySoundscape, subsoundscapeparams_t &params );
	// "soundmixer"
	void ProcessSoundMixer( KeyValues *pSoundMixer, subsoundscapeparams_t &params );
	// "dsp_volume"
	void ProcessDSPVolume( KeyValues *pKey, subsoundscapeparams_t &params );

private:

	bool	IsBeingRestored() const
	{
		return gpGlobals->framecount == m_nRestoreFrame ? true : false;
	}

	void	AddSoundScapeFile( const char *filename );

	void		TouchPlayLooping( KeyValues *pAmbient );
	void		TouchPlayRandom( KeyValues *pPlayRandom );
	void		TouchWaveFiles( KeyValues *pSoundScape );
	void		TouchSoundFile( char const *wavefile );

	void		TouchSoundFiles();

	int							m_nRestoreFrame;

	CUtlVector< KeyValues * >	m_SoundscapeScripts;	// The whole script file in memory
	CUtlVector<KeyValues *>		m_soundscapes;			// Lookup by index of each root section
	struct Split_t
	{
		audioparams_t				m_params;				// current player audio params
		CUtlVector<loopingsound_t>	m_loopingSounds;		// list of currently playing sounds
		CUtlVector<randomsound_t>	m_randomSounds;			// list of random sound commands
		float						m_nextRandomTime;		// next time to play a random sound
		int							m_loopingSoundId;		// marks when the sound was issued
		int							m_forcedSoundscapeIndex;// >= 0 if this a "forced" soundscape? i.e. debug mode?
		float						m_forcedSoundscapeRadius;// distance to spatialized sounds
	};

	Split_t						m_PerUser[ MAX_SPLITSCREEN_PLAYERS ];

	Split_t						&GetPerUser( int nSlot )
	{
		return m_PerUser[ nSlot ];
	}

	const Split_t						&GetPerUser( int nSlot ) const
	{
		return m_PerUser[ nSlot ];
	}

	static ConVar *m_pDSPVolumeVar;
	static ConVar *m_pSoundMixerVar;

};

// singleton system
C_SoundscapeSystem g_SoundscapeSystem;
ConVar *C_SoundscapeSystem::m_pDSPVolumeVar = NULL;
ConVar *C_SoundscapeSystem::m_pSoundMixerVar = NULL;

IGameSystem *ClientSoundscapeSystem()
{
	return &g_SoundscapeSystem;
}

C_SoundscapeSystem *GetClientSoundscapeSystem()
{
	return &g_SoundscapeSystem;
}

void Soundscape_OnStopAllSounds()
{
	GetClientSoundscapeSystem()->OnStopAllSounds();
}

// player got a network update
void Soundscape_Update( audioparams_t &audio )
{
	GetClientSoundscapeSystem()->UpdateAudioParams( audio );
}

#define SOUNDSCAPE_MANIFEST_FILE				"scripts/soundscapes_manifest.txt"

void C_SoundscapeSystem::AddSoundScapeFile( const char *filename )
{
	KeyValues *script = new KeyValues( filename );
	if ( filesystem->LoadKeyValues( *script, IFileSystem::TYPE_SOUNDSCAPE, filename, "GAME" ) )
	{
		// parse out all of the top level sections and save their names
		KeyValues *pKeys = script;
		while ( pKeys )
		{
			// save pointers to all sections in the root
			// each one is a soundscape
			if ( pKeys->GetFirstSubKey() )
			{
				m_soundscapes.AddToTail( pKeys );
			}
			pKeys = pKeys->GetNextKey();
		}

		// Keep pointer around so we can delete it at exit
		m_SoundscapeScripts.AddToTail( script );
	}
	else
	{
		script->deleteThis();
	}
}

// parse the script file, setup index table
bool C_SoundscapeSystem::Init()
{
	for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		GetPerUser(hh).m_loopingSoundId = 0;
	}

	const char *mapname = MapName();
	const char *mapSoundscapeFilename = NULL;
	if ( mapname && *mapname )
	{
		mapSoundscapeFilename = VarArgs( "scripts/soundscapes_%s.txt", mapname );
	}

	KeyValues *manifest = new KeyValues( SOUNDSCAPE_MANIFEST_FILE );
	if ( filesystem->LoadKeyValues( *manifest, IFileSystem::TYPE_SOUNDSCAPE, SOUNDSCAPE_MANIFEST_FILE, "GAME" ) )
	{
		for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
		{
			if ( !Q_stricmp( sub->GetName(), "file" ) )
			{
				// Add
				AddSoundScapeFile( sub->GetString() );
				if ( mapSoundscapeFilename && FStrEq( sub->GetString(), mapSoundscapeFilename ) )
				{
					mapSoundscapeFilename = NULL; // we've already loaded the map's soundscape
				}
				continue;
			}

			Warning( "C_SoundscapeSystem::Init:  Manifest '%s' with bogus file type '%s', expecting 'file'\n",
				SOUNDSCAPE_MANIFEST_FILE, sub->GetName() );
		}

		if ( mapSoundscapeFilename && filesystem->FileExists( mapSoundscapeFilename ) )
		{
			AddSoundScapeFile( mapSoundscapeFilename );
		}
	}
	else
	{
		Error( "Unable to load manifest file '%s'\n", SOUNDSCAPE_MANIFEST_FILE );
	}

	manifest->deleteThis();

	return true;
}

int C_SoundscapeSystem::FindSoundscapeByName( const char *pSoundscapeName )
{
	// UNDONE: Bad perf, linear search!
	for ( int i = m_soundscapes.Count()-1; i >= 0; --i )
	{
		if ( !Q_stricmp( m_soundscapes[i]->GetName(), pSoundscapeName ) )
			return i;
	}

	return -1;
}

KeyValues *C_SoundscapeSystem::SoundscapeByIndex( int index )
{
	if ( m_soundscapes.IsValidIndex(index) )
		return m_soundscapes[index];
	return NULL;
}

const char *C_SoundscapeSystem::SoundscapeNameByIndex( int index )
{
	if ( index < m_soundscapes.Count() )
	{
		return m_soundscapes[index]->GetName();
	}

	return NULL;
}

void C_SoundscapeSystem::Shutdown()
{
	for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		for ( int i = GetPerUser(hh).m_loopingSounds.Count() - 1; i >= 0; --i )
		{
			loopingsound_t &sound = GetPerUser(hh).m_loopingSounds[i];

			// sound is done, remove from list.
			StopLoopingSound( sound );
		}

		// These are only necessary so we can use shutdown/init calls
		// to flush soundscape data
		GetPerUser(hh).m_loopingSounds.RemoveAll();
		GetPerUser(hh).m_randomSounds.RemoveAll();
		GetPerUser(hh).m_params.entIndex = 0;
		GetPerUser(hh).m_params.soundscapeIndex = -1;
	}

	m_soundscapes.RemoveAll();

	while ( m_SoundscapeScripts.Count() > 0 )
	{
		KeyValues *kv = m_SoundscapeScripts[ 0 ];
		m_SoundscapeScripts.Remove( 0 );
		kv->deleteThis();
	}
}

// NOTE: This will not flush the server side so you cannot add or remove
// soundscapes from the list, only change their parameters!!!!
CON_COMMAND_F(cl_soundscape_flush, "Flushes the client side soundscapes", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CHEAT)
{
	FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		// save the current soundscape
		audioparams_t tmp;
		GetClientSoundscapeSystem()->GetAudioParams( tmp );

		// kill the system
		GetClientSoundscapeSystem()->Shutdown();

		// restart the system
		GetClientSoundscapeSystem()->Init();

		// reload the soundscape params from the temp copy
		Soundscape_Update( tmp );
	}
}

static int SoundscapeCompletion( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
{
	// Autocomplete can just look at the base system
	ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
	int current = 0;

	const char *cmdname = "playsoundscape";
	char *substring = NULL;
	int substringLen = 0;
	if ( Q_strstr( partial, cmdname ) && strlen(partial) > strlen(cmdname) + 1 )
	{
		substring = (char *)partial + strlen( cmdname ) + 1;
		substringLen = strlen(substring);
	}

	int i = 0;
	const char *pSoundscapeName = GetClientSoundscapeSystem()->SoundscapeNameByIndex( i );
	while ( pSoundscapeName && current < COMMAND_COMPLETION_MAXITEMS )
	{
		if ( !substring || !Q_strncasecmp( pSoundscapeName, substring, substringLen ) )
		{
			Q_snprintf( commands[ current ], sizeof( commands[ current ] ), "%s %s", cmdname, pSoundscapeName );
			current++;
		}
		i++;
		pSoundscapeName = GetClientSoundscapeSystem()->SoundscapeNameByIndex( i );
	}

	return current;
}

void ForceSoundscape( const char *pSoundscapeName, float radius )
{
	GetClientSoundscapeSystem()->ForceSoundscape( pSoundscapeName, radius );
}

CON_COMMAND_F_COMPLETION( playsoundscape, "Forces a soundscape to play", FCVAR_CHEAT, SoundscapeCompletion )
{
	FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		if ( args.ArgC() < 2 )
		{
			GetClientSoundscapeSystem()->DevReportSoundscapeName( GetClientSoundscapeSystem()->GetCurrentSoundscape() );
			continue;
		}
		const char *pSoundscapeName = args[1];
		float radius = args.ArgC() > 2 ? atof( args[2] ) : DEFAULT_SOUND_RADIUS;
		GetClientSoundscapeSystem()->ForceSoundscape( pSoundscapeName, radius );
	}
}

CON_COMMAND_F( stopsoundscape, "Stops all soundscape processing and fades current looping sounds", FCVAR_CHEAT )
{
	FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		GetClientSoundscapeSystem()->StartNewSoundscape( NULL );
	}
}

void C_SoundscapeSystem::ForceSoundscape( const char *pSoundscapeName, float radius )
{
	int index = FindSoundscapeByName( pSoundscapeName );
	if ( index >= 0 )
	{
		int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
		GetPerUser(nSlot).m_forcedSoundscapeIndex = index;
		GetPerUser(nSlot).m_forcedSoundscapeRadius = radius;
		StartNewSoundscape( SoundscapeByIndex(index) );
	}
	else
	{
		DevWarning("Can't find soundscape %s\n", pSoundscapeName );
	}
}

void C_SoundscapeSystem::DevReportSoundscapeName( int index )
{
	const char *pName = "none";
	if ( index >= 0 && index < m_soundscapes.Count() )
	{
		pName = m_soundscapes[index]->GetName();
	}

	if ( soundscape_message.GetBool() )
	{
		Msg( "Soundscape[%d]: %s\n", GET_ACTIVE_SPLITSCREEN_SLOT(), pName  );
	}
}

// This makes all currently playing loops fade toward their target volume
void C_SoundscapeSystem::UpdateLoopingSounds( float frametime )
{
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());
	int fadeCount = slot.m_loopingSounds.Count();
	while ( fadeCount > 0 )
	{
		fadeCount--;
		loopingsound_t &sound = slot.m_loopingSounds[fadeCount];

		bool bUpdateSound = sound.m_volume.IsFading();

		// for radius looping sounds, volume is manually set based on listener's distance
		if ( sound.radius > 0 )
		{
			C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
			if ( pPlayer )
			{
				C_BaseEntity *pEnt = pPlayer->GetSoundscapeListener();
				if ( pEnt )
				{
					float distance = pEnt->GetAbsOrigin().DistTo( sound.position );

					if ( distance > sound.radius * 100.0f )
					{
						// long way away, let sound fade to silence
						sound.m_volume.FadeToValue( 0.01f, 1.0f, FADE_VOLUME_LINEAR );	// HACK: Don't set sound to zero volume else it'll be removed and never started again!
					}
					else
					{
						float flTarget = 1.0f;
						// inside the radius, full volume, outside fade out
						if ( distance >= sound.radius )
						{
							flTarget = 1.0f / ( 1 + 0.5f * ( distance - sound.radius ) / sound.radius );
						}
						sound.m_volume.ForceToTargetValue( flTarget );
					}

					if ( soundscape_radius_debug.GetBool() )
					{
						DevMsg( 1, "Updated looping radius sound %d to vol=%f\n", fadeCount, sound.m_volume.m_flTarget );
					}

					bUpdateSound = true;
				}
			}
		}

		if ( bUpdateSound )
		{
			sound.m_volume.UpdateFade( frametime );
			if ( sound.m_volume.m_flTarget == 0 && sound.m_volume.m_flCurrent == 0 )
			{
				// sound is done, remove from list.
				StopLoopingSound( sound );
				slot.m_loopingSounds.FastRemove( fadeCount );
			}
			else
			{
				// tell the engine about the new volume
				UpdateLoopingSound( sound );
			}
		}
	}
}

void C_SoundscapeSystem::Update( float frametime )
{
	FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		if ( GetPerUser(hh).m_forcedSoundscapeIndex >= 0 )
		{
			// generate fake positional sources
			C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
			if ( pPlayer )
			{
				Vector origin, forward, right;
				pPlayer->EyePositionAndVectors( &origin, &forward, &right, NULL );

				// put the sound origins at the corners of a box around the player
				GetPerUser(hh).m_params.localSound.Set( 0, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (forward-right) );
				GetPerUser(hh).m_params.localSound.Set( 1, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (forward+right) );
				GetPerUser(hh).m_params.localSound.Set( 2, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (-forward-right) );
				GetPerUser(hh).m_params.localSound.Set( 3, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (-forward+right) );
				GetPerUser(hh).m_params.localBits = 0x0007;
			}
		}
		// fade out the old sounds over soundscape_fadetime seconds
		UpdateLoopingSounds( frametime );
		UpdateRandomSounds( gpGlobals->curtime );
	}
}

void C_SoundscapeSystem::UpdateAudioParams( audioparams_t &audio )
{
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());
	if ( slot.m_params.soundscapeIndex == audio.soundscapeIndex && slot.m_params.entIndex == audio.entIndex )
		return;

	slot.m_params = audio;
	slot.m_forcedSoundscapeIndex = -1;
	if ( audio.entIndex > 0 && audio.soundscapeIndex >= 0 && audio.soundscapeIndex < m_soundscapes.Count() )
	{
		DevReportSoundscapeName( audio.soundscapeIndex );
		StartNewSoundscape( m_soundscapes[audio.soundscapeIndex] );
	}
	else
	{
		// bad index (and the soundscape file actually existed...)
		if ( audio.entIndex > 0 &&
			audio.soundscapeIndex != -1 )
		{
			DevMsg(1, "Error: Bad soundscape!\n");
		}
	}
}

// Called when a soundscape is activated (leading edge of becoming the active soundscape)
void C_SoundscapeSystem::StartNewSoundscape( KeyValues *pSoundscape )
{
	int i;

	float flFadeRate = GetSoundscapeFadeRate();
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());

	// Reset the system
	// fade out the current loops
	// save off the count of old looping sounds
	int nOldLoopingSoundMax = slot.m_loopingSounds.Count()-1;
	for ( i = slot.m_loopingSounds.Count()-1; i >= 0; --i )
	{
		slot.m_loopingSounds[i].m_volume.FadeToValue( 0, flFadeRate, FADE_VOLUME_SINE );
		if ( !pSoundscape )
		{
			// if we're cancelling the soundscape, stop the sound immediately
			slot.m_loopingSounds[i].m_volume.ForceToTargetValue( 0 );
		}
	}
	// update ID
	slot.m_loopingSoundId++;

	// clear all random sounds
	slot.m_randomSounds.RemoveAll();
	slot.m_nextRandomTime = gpGlobals->curtime;

	if ( pSoundscape )
	{
		subsoundscapeparams_t params;
		params.allowDSP = true;
		params.wroteSoundMixer = false;
		params.wroteDSPVolume = false;

		params.masterVolume = 1.0;
		params.startingPosition = 0;
		params.recurseLevel = 0;
		params.positionOverride = -1;
		params.ambientPositionOverride = -1;
		params.flFadeRate = flFadeRate;
		StartSubSoundscape( pSoundscape, params );

		if ( !params.wroteDSPVolume )
		{
			m_pDSPVolumeVar->Revert();
		}
		if ( !params.wroteSoundMixer )
		{
			m_pSoundMixerVar->Revert();
		}
		// if we processed a fade rate, update the fade
		// This is a little bit of a hack but since we don't pre-parse soundscapes
		// into structs we can't know if there is a rate change on this soundscape
		if ( params.flFadeRate != flFadeRate )
		{
			for ( i = nOldLoopingSoundMax; i >= 0; --i )
			{
				// if we're still fading out at the old rate, fade at the new rate
				if ( slot.m_loopingSounds[i].m_volume.m_flTarget == 0.0f && slot.m_loopingSounds[i].m_volume.m_flRate == flFadeRate )
				{
					slot.m_loopingSounds[i].m_volume.m_flRate = params.flFadeRate;
				}
			}
		}
	}
}

void C_SoundscapeSystem::StartSubSoundscape( KeyValues *pSoundscape, subsoundscapeparams_t &params )
{
	// Parse/process all of the commands
	KeyValues *pKey = pSoundscape->GetFirstSubKey();
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "dsp" ) )
		{
			if ( params.allowDSP )
			{
				ProcessDSP( pKey );
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "dsp_player" ) )
		{
			if ( params.allowDSP )
			{
				ProcessDSPPlayer( pKey );
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "fadetime" ) )
		{
			// don't allow setting these recursively since they are order dependent
			if ( params.recurseLevel < 1 )
			{
				ProcessSoundscapeFadetime( pKey, params );
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "playlooping" ) )
		{
			ProcessPlayLooping( pKey, params );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "playrandom" ) )
		{
			ProcessPlayRandom( pKey, params );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "playsoundscape" ) )
		{
			ProcessPlaySoundscape( pKey, params );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "Soundmixer" ) )
		{
			if ( params.allowDSP )
			{
				ProcessSoundMixer( pKey, params );
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "dsp_volume" ) )
		{
			if ( params.allowDSP )
			{
				ProcessDSPVolume( pKey, params );
			}
		}
		// add new commands here
		else
		{
			DevMsg( 1, "Soundscape %s:Unknown command %s\n", pSoundscape->GetName(), pKey->GetName() );
		}
		pKey = pKey->GetNextKey();
	}
}

// add a process for each new command here

// change DSP effect
void C_SoundscapeSystem::ProcessDSP( KeyValues *pDSP )
{
	int roomType = pDSP->GetInt();
	CLocalPlayerFilter filter;
	enginesound->SetRoomType( filter, roomType );
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : *pDSPPlayer -
//-----------------------------------------------------------------------------
void C_SoundscapeSystem::ProcessDSPPlayer( KeyValues *pDSPPlayer )
{
	int dspType = pDSPPlayer->GetInt();
	CLocalPlayerFilter filter;
	enginesound->SetPlayerDSP( filter, dspType, false );
}

void C_SoundscapeSystem::ProcessSoundMixer( KeyValues *pSoundMixer, subsoundscapeparams_t &params )
{
	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( !pPlayer || pPlayer->CanSetSoundMixer() )
	{
		m_pSoundMixerVar->SetValue( pSoundMixer->GetString() );
		params.wroteSoundMixer = true;
	}
}

void C_SoundscapeSystem::ProcessDSPVolume( KeyValues *pKey, subsoundscapeparams_t &params )
{
	m_pDSPVolumeVar->SetValue( pKey->GetFloat() );
	params.wroteDSPVolume = true;
}

void C_SoundscapeSystem::ProcessSoundscapeFadetime( KeyValues *pKey, subsoundscapeparams_t &params )
{
	float flFadeTime = pKey->GetFloat();
	if ( flFadeTime > 0.0f )
	{
		params.flFadeRate = 1.0f / flFadeTime;
	}
}

// start a new looping sound
void C_SoundscapeSystem::ProcessPlayLooping( KeyValues *pAmbient, const subsoundscapeparams_t &params )
{
	float volume = 0;
	soundlevel_t soundlevel = ATTN_TO_SNDLVL(ATTN_NORM);
	const char *pSoundName = NULL;
	int pitch = PITCH_NORM;
	int positionIndex = -1;
	bool randomPosition = false;
	bool suppress = false;
	bool useTextOrigin = false;
	Vector textOrigin;
	float radius = 0;

	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());

	KeyValues *pKey = pAmbient->GetFirstSubKey();
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "volume" ) )
		{
			volume = params.masterVolume * RandomInterval( ReadInterval( pKey->GetString() ) );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "pitch" ) )
		{
			pitch = RandomInterval( ReadInterval( pKey->GetString() ) );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "wave" ) )
		{
			pSoundName = pKey->GetString();
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "origin" ) )
		{
			textOrigin = getVectorFromString(pKey->GetString());
			useTextOrigin = true;
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "position" ) )
		{
			if ( !Q_strcasecmp( pKey->GetString(), "random" ) )
			{
				randomPosition = true;
			}
			else
			{
				positionIndex = params.startingPosition + pKey->GetInt();
			}
		//	positionIndex = params.startingPosition + pKey->GetInt();
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "attenuation" ) )
		{
			soundlevel = ATTN_TO_SNDLVL( RandomInterval( ReadInterval( pKey->GetString() ) ) );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "soundlevel" ) )
		{
			if ( !Q_strncasecmp( pKey->GetString(), "SNDLVL_", strlen( "SNDLVL_" ) ) )
			{
				soundlevel = TextToSoundLevel( pKey->GetString() );
			}
			else
			{
				soundlevel = (soundlevel_t)((int)RandomInterval( ReadInterval( pKey->GetString() ) ));
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "suppress_on_restore" ) )
		{
			suppress = Q_atoi( pKey->GetString() ) != 0 ? true : false;
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "radius" ) )
		{
			radius = (float) atof( pKey->GetString() );
		}
		else
		{
			DevMsg( 1, "Ambient %s:Unknown command %s\n", pAmbient->GetName(), pKey->GetName() );
		}
		pKey = pKey->GetNextKey();
	}

	if ( positionIndex < 0 )
	{
		positionIndex = params.ambientPositionOverride;
	}
	else if ( params.positionOverride >= 0 )
	{
		positionIndex = params.positionOverride;
	}

	// Sound is mared as "suppress_on_restore" so don't restart it
	if ( IsBeingRestored() && suppress )
	{
		return;
	}

	if ( volume != 0 && pSoundName != NULL )
	{
		if ( randomPosition )
		{
			AddLoopingSound( pSoundName, false, volume, soundlevel, pitch, GenerateRandomSoundPosition(), radius, params.flFadeRate );
		}
		else if ( useTextOrigin )
		{
			AddLoopingSound( pSoundName, false, volume, soundlevel, pitch, textOrigin, radius, params.flFadeRate );
		}
		else if ( positionIndex < 0 )
		{
			AddLoopingAmbient( pSoundName, volume, pitch, radius, params.flFadeRate );
		}
		else
		{
			if ( positionIndex > 31 || !(slot.m_params.localBits & (1<<positionIndex) ) )
			{
				// suppress sounds if the position isn't available
				//DevMsg( 1, "Bad position %d\n", positionIndex );
				return;
			}
			AddLoopingSound( pSoundName, false, volume, soundlevel, pitch, slot.m_params.localSound[positionIndex], radius, params.flFadeRate );
		}
	}
}

void C_SoundscapeSystem::TouchSoundFile( char const *wavefile )
{
	filesystem->GetFileTime( VarArgs( "sound/%s", PSkipSoundChars( wavefile ) ), "GAME" );
}

// start a new looping sound
void C_SoundscapeSystem::TouchPlayLooping( KeyValues *pAmbient )
{
	KeyValues *pKey = pAmbient->GetFirstSubKey();
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "wave" ) )
		{
			char const *pSoundName = pKey->GetString();

			// Touch the file
			TouchSoundFile( pSoundName );
		}

		pKey = pKey->GetNextKey();
	}
}

Vector C_SoundscapeSystem::GenerateRandomSoundPosition()
{
	float angle = random->RandomFloat( -180, 180 );
	float sinAngle, cosAngle;
	SinCos( angle, &sinAngle, &cosAngle );
	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( pPlayer )
	{
		Vector origin, forward, right;
		pPlayer->EyePositionAndVectors( &origin, &forward, &right, NULL );
		return origin + DEFAULT_SOUND_RADIUS * (cosAngle * right + sinAngle * forward);
	}
	else
	{
		return CurrentViewOrigin() + DEFAULT_SOUND_RADIUS * (cosAngle * CurrentViewRight() + sinAngle * CurrentViewForward());
	}
}

void C_SoundscapeSystem::TouchSoundFiles()
{
	if ( !CommandLine()->FindParm( "-makereslists" ) )
		return;

	int c = m_soundscapes.Count();
	for ( int i = 0; i < c ; ++i )
	{
		TouchWaveFiles( m_soundscapes[ i ] );
	}
}

void C_SoundscapeSystem::TouchWaveFiles( KeyValues *pSoundScape )
{
	KeyValues *pKey = pSoundScape->GetFirstSubKey();
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "playlooping" ) )
		{
			TouchPlayLooping( pKey );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "playrandom" ) )
		{
			TouchPlayRandom( pKey );
		}

		pKey = pKey->GetNextKey();
	}

}

// puts a recurring random sound event into the queue
void C_SoundscapeSystem::TouchPlayRandom( KeyValues *pPlayRandom )
{
	KeyValues *pKey = pPlayRandom->GetFirstSubKey();
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "rndwave" ) )
		{
			KeyValues *pWaves = pKey->GetFirstSubKey();
			while ( pWaves )
			{
				TouchSoundFile( pWaves->GetString() );

				pWaves = pWaves->GetNextKey();
			}
		}

		pKey = pKey->GetNextKey();
	}
}

// puts a recurring random sound event into the queue
void C_SoundscapeSystem::ProcessPlayRandom( KeyValues *pPlayRandom, const subsoundscapeparams_t &params )
{
	randomsound_t sound;
	sound.Init();
	sound.masterVolume = params.masterVolume;
	int positionIndex = -1;
	bool suppress = false;
	bool randomPosition = false;
	bool useTextOrigin = false;
	Vector textOrigin;
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());

	KeyValues *pKey = pPlayRandom->GetFirstSubKey();
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "volume" ) )
		{
			sound.volume = ReadInterval( pKey->GetString() );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "pitch" ) )
		{
			sound.pitch = ReadInterval( pKey->GetString() );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "attenuation" ) )
		{
			interval_t atten = ReadInterval( pKey->GetString() );
			sound.soundlevel.start = ATTN_TO_SNDLVL( atten.start );
			sound.soundlevel.range = ATTN_TO_SNDLVL( atten.start + atten.range ) - sound.soundlevel.start;
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "soundlevel" ) )
		{
			if ( !Q_strncasecmp( pKey->GetString(), "SNDLVL_", strlen( "SNDLVL_" ) ) )
			{
				sound.soundlevel.start = TextToSoundLevel( pKey->GetString() );
				sound.soundlevel.range = 0;
			}
			else
			{
				sound.soundlevel = ReadInterval( pKey->GetString() );
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "time" ) )
		{
			sound.time = ReadInterval( pKey->GetString() );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "rndwave" ) )
		{
			KeyValues *pWaves = pKey->GetFirstSubKey();
			sound.pWaves = pWaves;
			sound.waveCount = 0;
			while ( pWaves )
			{
				sound.waveCount++;
				pWaves = pWaves->GetNextKey();
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "position" ) )
		{
			if ( !Q_strcasecmp( pKey->GetString(), "random" ) )
			{
				randomPosition = true;
			}
			else
			{
				positionIndex = params.startingPosition + pKey->GetInt();
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "origin" ) )
		{
			const char *originString = pKey->GetString();
			textOrigin = getVectorFromString(originString);
			useTextOrigin = true;
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "suppress_on_restore" ) )
		{
			suppress = Q_atoi( pKey->GetString() ) != 0 ? true : false;
		}
		else
		{
			DevMsg( 1, "Random Sound %s:Unknown command %s\n", pPlayRandom->GetName(), pKey->GetName() );
		}

		pKey = pKey->GetNextKey();
	}

	if ( positionIndex < 0 )
	{
		positionIndex = params.ambientPositionOverride;
	}
	else if ( params.positionOverride >= 0 )
	{
		positionIndex = params.positionOverride;
		randomPosition = false; // override trumps random position
	}

	// Sound is mared as "suppress_on_restore" so don't restart it
	if ( IsBeingRestored() && suppress )
	{
		return;
	}

	if ( sound.waveCount != 0 )
	{
		if ( positionIndex < 0 && !randomPosition && !useTextOrigin )
		{
			sound.isAmbient = true;
			AddRandomSound( sound );
		}
		else
		{
			sound.isAmbient = false;
			if ( randomPosition )
			{
				sound.isRandom = true;
			}
			else if ( useTextOrigin )
			{
				sound.position = textOrigin;
			}
			else
			{
				if ( positionIndex > 31 || !(slot.m_params.localBits & (1<<positionIndex) ) )
				{
					// suppress sounds if the position isn't available
					//DevMsg( 1, "Bad position %d\n", positionIndex );
					return;
				}
				sound.position = slot.m_params.localSound[positionIndex];
			}
			AddRandomSound( sound );
		}
	}
}

void C_SoundscapeSystem::ProcessPlaySoundscape( KeyValues *pPlaySoundscape, subsoundscapeparams_t &paramsIn )
{
	subsoundscapeparams_t subParams = paramsIn;

	// sub-soundscapes NEVER set the DSP effects
	subParams.allowDSP = false;
	subParams.recurseLevel++;
	if ( subParams.recurseLevel > MAX_SOUNDSCAPE_RECURSION )
	{
		DevMsg( "Error!  Soundscape recursion overrun!\n" );
		return;
	}
	KeyValues *pKey = pPlaySoundscape->GetFirstSubKey();
	const char *pSoundscapeName = NULL;
	while ( pKey )
	{
		if ( !Q_strcasecmp( pKey->GetName(), "volume" ) )
		{
			subParams.masterVolume = paramsIn.masterVolume * RandomInterval( ReadInterval( pKey->GetString() ) );
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "position" ) )
		{
			subParams.startingPosition = paramsIn.startingPosition + pKey->GetInt();
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "positionoverride" ) )
		{
			if ( paramsIn.positionOverride < 0 )
			{
				subParams.positionOverride = paramsIn.startingPosition + pKey->GetInt();
				// positionoverride is only ever used to make a whole soundscape come from a point in space
				// So go ahead and default ambients there too.
				subParams.ambientPositionOverride = paramsIn.startingPosition + pKey->GetInt();
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "ambientpositionoverride" ) )
		{
			if ( paramsIn.ambientPositionOverride < 0 )
			{
				subParams.ambientPositionOverride = paramsIn.startingPosition + pKey->GetInt();
			}
		}
		else if ( !Q_strcasecmp( pKey->GetName(), "name" ) )
		{
			pSoundscapeName = pKey->GetString();
		}
		else if ( !Q_strcasecmp(pKey->GetName(), "soundlevel") )
		{
			DevMsg(1,"soundlevel not supported on sub-soundscapes\n");
		}
		else
		{
			DevMsg( 1, "Playsoundscape %s:Unknown command %s\n", pSoundscapeName ? pSoundscapeName : pPlaySoundscape->GetName(), pKey->GetName() );
		}
		pKey = pKey->GetNextKey();
	}

	if ( pSoundscapeName )
	{
		KeyValues *pSoundscapeKeys = SoundscapeByIndex( FindSoundscapeByName( pSoundscapeName ) );
		if ( pSoundscapeKeys )
		{
			StartSubSoundscape( pSoundscapeKeys, subParams );
		}
		else
		{
			DevMsg( 1, "Trying to play unknown soundscape %s\n", pSoundscapeName );
		}
	}
}

// special kind of looping sound with no spatialization
int C_SoundscapeSystem::AddLoopingAmbient( const char *pSoundName, float volume, int pitch, float radius, float flFadeRate )
{
	return AddLoopingSound( pSoundName, true, volume, SNDLVL_NORM, pitch, vec3_origin, radius, flFadeRate );
}

// add a looping sound to the list
// NOTE: will reuse existing entry (fade from current volume) if possible
//		this prevents pops
int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, float volume, soundlevel_t soundlevel, int pitch, const Vector &position, float radius, float flFadeRate )
{
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());

	loopingsound_t *pSoundSlot = NULL;
	int soundSlot = slot.m_loopingSounds.Count() - 1;
	bool bForceSoundUpdate = false;
	while ( soundSlot >= 0 )
	{
		loopingsound_t &sound = slot.m_loopingSounds[soundSlot];

		// NOTE: Will always restart/crossfade positional sounds
		if ( sound.id != slot.m_loopingSoundId &&
			sound.pitch == pitch &&
			!Q_strcasecmp( pSoundName, sound.pWaveName ) )
		{
			// Ambient sounds can reuse the slots.
			if ( isAmbient == true &&
				sound.isAmbient == true )
			{
				// reuse this sound
				pSoundSlot = &sound;
				break;
			}
			// Positional sounds can reuse the slots if the positions are the same.
			else if ( isAmbient == sound.isAmbient )
			{
				if ( VectorsAreEqual( position, sound.position, 0.1f ) )
				{
					// reuse this sound
					pSoundSlot = &sound;
					break;
				}
			}
		}
		soundSlot--;
	}

	if ( soundSlot < 0 )
	{
		// can't find the sound in the list, make a new one
		soundSlot = slot.m_loopingSounds.AddToTail();
		if ( isAmbient )
		{
			// start at 0 and fade in
			enginesound->EmitAmbientSound( pSoundName, 0, pitch );
			slot.m_loopingSounds[soundSlot].m_volume.m_flCurrent = 0.0;
		}
		else
		{
			// non-ambients at 0 volume are culled, so start at 0.05
			CLocalPlayerFilter filter;

			EmitSound_t ep;
			ep.m_nChannel = CHAN_STATIC;
			ep.m_pSoundName =  pSoundName;
			ep.m_flVolume = 0.05;
			ep.m_SoundLevel = soundlevel;
			ep.m_nPitch = pitch;
			ep.m_pOrigin = &position;

			C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
			slot.m_loopingSounds[soundSlot].m_volume.m_flCurrent = 0.05;
		}
		slot.m_loopingSounds[soundSlot].engineGuid = enginesound->GetGuidForLastSoundEmitted();
	}

	loopingsound_t &sound = slot.m_loopingSounds[soundSlot];
	// fill out the slot
	sound.pWaveName = pSoundName;
	sound.m_volume.FadeToValue( volume, flFadeRate, FADE_VOLUME_SINE );
	sound.pitch = pitch;
	sound.id = slot.m_loopingSoundId;
	sound.isAmbient = isAmbient;
	sound.position = position;
	sound.radius = radius;
	if ( radius > 0 )
	{
		sound.soundlevel = SNDLVL_NONE;	  // play without attenuation if sound has a radius (volume will be manually set based on distance of listener to the radius)
	}
	else
	{
		sound.soundlevel = soundlevel;
	}

	if (bForceSoundUpdate)
	{
		UpdateLoopingSound(sound);
	}

	return soundSlot;
}

// stop this loop forever
void C_SoundscapeSystem::StopLoopingSound( loopingsound_t &loopSound )
{
	enginesound->StopSoundByGuid( loopSound.engineGuid );
}

// update with new volume
void C_SoundscapeSystem::UpdateLoopingSound( loopingsound_t &loopSound )
{
	if ( enginesound->IsSoundStillPlaying(loopSound.engineGuid) )
	{
		enginesound->SetVolumeByGuid( loopSound.engineGuid, loopSound.m_volume.m_flCurrent );
		return;
	}

	if ( loopSound.isAmbient )
	{
		enginesound->EmitAmbientSound( loopSound.pWaveName, loopSound.m_volume.m_flCurrent, loopSound.pitch, SND_CHANGE_VOL );
	}
	else
	{
		CLocalPlayerFilter filter;

		EmitSound_t ep;
		ep.m_nChannel = CHAN_STATIC;
		ep.m_pSoundName =  loopSound.pWaveName;
		ep.m_flVolume = loopSound.m_volume.m_flCurrent;
		ep.m_SoundLevel = loopSound.soundlevel;
		ep.m_nFlags = SND_CHANGE_VOL;
		ep.m_nPitch = loopSound.pitch;
		ep.m_pOrigin = &loopSound.position;

		C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
	}
	loopSound.engineGuid = enginesound->GetGuidForLastSoundEmitted();
}

// add a recurring random sound event
int C_SoundscapeSystem::AddRandomSound( const randomsound_t &sound )
{
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());
	int index = slot.m_randomSounds.AddToTail( sound );
	slot.m_randomSounds[index].nextPlayTime = gpGlobals->curtime + 0.5 * RandomInterval( sound.time );

	return index;
}

// play a random sound randomly from this parameterization table
void C_SoundscapeSystem::PlayRandomSound( randomsound_t &sound )
{
	Assert( sound.waveCount > 0 );

	int waveId = random->RandomInt( 0, sound.waveCount-1 );
	KeyValues *pWaves = sound.pWaves;
	while ( waveId > 0 && pWaves )
	{
		pWaves = pWaves->GetNextKey();
		waveId--;
	}
	if ( !pWaves )
		return;

	const char *pWaveName = pWaves->GetString();

	if ( !pWaveName )
		return;

	if ( sound.isAmbient )
	{
		enginesound->EmitAmbientSound( pWaveName, sound.masterVolume * RandomInterval( sound.volume ), (int)RandomInterval( sound.pitch ) );
	}
	else
	{
		CLocalPlayerFilter filter;

		EmitSound_t ep;
		ep.m_nChannel = CHAN_STATIC;
		ep.m_pSoundName =  pWaveName;
		ep.m_flVolume = sound.masterVolume * RandomInterval( sound.volume );
		ep.m_SoundLevel = (soundlevel_t)(int)RandomInterval( sound.soundlevel );
		ep.m_nPitch = (int)RandomInterval( sound.pitch );
		if ( sound.isRandom )
		{
			sound.position = GenerateRandomSoundPosition();
		}
		ep.m_pOrigin = &sound.position;

		C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
	}
}

// walk the list of random sound commands and update
void C_SoundscapeSystem::UpdateRandomSounds( float gameTime )
{
	Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT());
	if ( gameTime < slot.m_nextRandomTime )
		return;

	slot.m_nextRandomTime = gameTime + 3600;	// add some big time to check again (an hour)

	for ( int i = slot.m_randomSounds.Count()-1; i >= 0; i-- )
	{
		// time to play?
		if ( gameTime >= slot.m_randomSounds[i].nextPlayTime )
		{
			// UNDONE: add this in to fix range?
			// float dt = m_randomSounds[i].nextPlayTime - gameTime;
			PlayRandomSound( slot.m_randomSounds[i] );

			// now schedule the next occurrance
			// UNDONE: add support for "play once" sounds? FastRemove() here.
			slot.m_randomSounds[i].nextPlayTime = gameTime + RandomInterval( slot.m_randomSounds[i].time );
		}

		// update next time to check the queue
		if ( slot.m_randomSounds[i].nextPlayTime < slot.m_nextRandomTime )
		{
			slot.m_nextRandomTime = slot.m_randomSounds[i].nextPlayTime;
		}
	}
}

CON_COMMAND(cl_soundscape_printdebuginfo, "print soundscapes")
{
	FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
	{
		ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
		GetClientSoundscapeSystem()->PrintDebugInfo();
	}
}

CON_COMMAND(cl_ss_origin, "print origin in script format")
{
	Vector org = MainViewOrigin( GET_ACTIVE_SPLITSCREEN_SLOT() );
	Warning("\"origin\"\t\"%.1f, %.1f, %.1f\"\n", org.x, org.y, org.z );
}


text:
require 'test/unit'
require 'fileutils'
require 'KindleMailer.rb'
class TestKindleMailer < Test::Unit::TestCase

  def setup
    @mailer = KindleMailer.new({})
  end

  def test_constructor_with_nil_credentials
    assert_raise(ArgumentError) { @mailer = KindleMailer.new(nil) }
  end

  def test_send_with_nil_kindle_address
    assert_raise(ArgumentError) { @mailer.send(nil, "file.txt") }
  end

  def test_validate_kindle_address_with_nil_addr
    assert_raise(ArgumentError) { @mailer.validate_kindle_address(nil) }
  end

  def test_validate_kindle_address_with_non_kindle_addr
    assert_raise(ArgumentError) { @mailer.validate_kindle_address("kindlemail@gmail.com") }
  end

  def test_validate_file_path_with_non_existent_file
    assert_raise(ArgumentError) { @mailer.validate_file_path("k") }
  end

  def test_validate_file_path_with_existent_file
    file = File.expand_path("test/file1.txt")
    FileUtils.touch(file)
    assert_nothing_raised { @mailer.validate_file_path(file) }
    FileUtils.rm(file)
  end

  def test_validate_file_path_with_erroneous_file_type
    file = File.expand_path("test/file1.xyz")
    FileUtils.touch(file)
    assert_raise(ArgumentError) { @mailer.validate_file_path(file) }
    FileUtils.rm(file)
  end
end