/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package worm.buildings; import java.util.ArrayList; import java.util.Collections; import net.puppygames.applet.effects.EmitterFeature; import worm.CrystalResource; import worm.Hints; import worm.Res; import worm.SFX; import worm.Worm; import worm.WormGameState; import worm.effects.ElectronZapEffect; import worm.entities.Building; import worm.entities.Factory; import worm.features.LayersFeature; import worm.features.ResearchFeature; import worm.screens.GameScreen; import com.shavenpuppy.jglib.resources.MappedColor; /** * $Id: FactoryBuildingFeature.java,v 1.83 2010/10/16 02:17:16 foo Exp $ * Factories * @author $Author: foo $ * @version $Revision: 1.83 $ */ public class FactoryBuildingFeature extends BuildingFeature { private static final long serialVersionUID = 1L; private static FactoryBuildingFeature instance; private int baseProductionRate; private int minProductionRate; private int productionRatePerCollector; private int productionRatePerWarehouse; private int amountToExtract; private int amountToExtractPerWarehouse; private int maxCollectors; private int maxWarehouses; private static final int WAIT_TIME = 8; private static final float MAX_WIDTH = 0.5f; private static final float MAX_WOBBLE = 16.0f; private static final float WOBBLE_FACTOR = 0.5f; private static final float WIDTH_FACTOR = 0.025f; private static final int BEAM_X_OFFSET = 5; private static final int BEAM_Y_OFFSET = 2; /** Shutdown appearance, for end of level */ private LayersFeature shutdownAppearance; private EmitterFeature beamStartEmitter, beamEndEmitter; /** * Building instances */ private class FactoryBuildingInstance extends Building implements Factory { private static final long serialVersionUID = 1L; private int waitTick, tick; private boolean shutdown, mining; private int extraCollector, extraWarehouse; private CrystalResource crystal; private transient ElectronZapEffect zapEffect; /** * @param feature * @param x * @param y */ protected FactoryBuildingInstance(boolean ghost) { super(FactoryBuildingFeature.this, ghost); } @Override protected void doBuildingSpawn() { createSpecialEffects(); extraCollector = Worm.getGameState().isResearched(ResearchFeature.EXTRACTION) ? productionRatePerCollector / 2 : 0; extraWarehouse = Worm.getGameState().isResearched(ResearchFeature.FINETUNING) ? amountToExtractPerWarehouse / 2 : 0; } private void createSpecialEffects() { } @Override protected void doRemoveSpecialEffects() { removeCrystalEffects(); } @Override public void onEndLevel() { doRemoveSpecialEffects(); shutdown = true; updateAppearance(); } @Override protected void doBuildingTick() { WormGameState gameState = Worm.getGameState(); if (!gameState.isPlaying() || shutdown) { return; } if (waitTick > 0) { waitTick --; return; } if (crystal == null || !crystal.hasRemaining() || !mining) { // If we've got no crystal, or the crystal we had is finished, find another one findCrystal(); if (crystal == null) { SFX.factoryShutdown(); doRemoveSpecialEffects(); shutdown = true; updateAppearance(); return; } else if (!mining) { // Wait waitTick = WAIT_TIME; return; } } if (++tick >= getProductionRate()) { tick = 0; gameState.addMoney(getAmount()); crystal.consume(amountToExtract); } } private int getAmount() { return Math.min(maxWarehouses, getWarehouses()) * amountToExtractPerWarehouse + amountToExtract + extraWarehouse; } private int getProductionRate() { int ret = Math.max ( minProductionRate, baseProductionRate - extraCollector - Math.min(maxCollectors, getCollectors()) * productionRatePerCollector + Math.min(maxWarehouses, getWarehouses()) * productionRatePerWarehouse ); return ret; } @Override public void addCrystals(int n) { super.addCrystals(n); // Maybe wake the factory up if (shutdown && isActive()) { shutdown = false; createSpecialEffects(); updateAppearance(); } } @Override protected void doOnBuild() { Worm.getGameState().addFactories(1); findCrystal(); Worm.getGameState().flagHint(Hints.TIMERSTARTS); } protected void onDestroy() { Worm.getGameState().addFactories(-1); } @Override protected void adjustProximity(Building target, int delta) { target.addFactories(delta); } @Override public boolean canBuild() { calcGhostProximity(); return getCrystals() > 0; } private void removeCrystalEffects() { if (mining && crystal != null) { crystal.addBeams(-1); } mining = false; crystal = null; if (zapEffect != null) { zapEffect.remove(); zapEffect = null; } } private void findCrystal() { removeCrystalEffects(); // Get nearby crystals ArrayList<Building> buildings = new ArrayList<Building>(getNearbyAffectedBuildings()); Collections.shuffle(buildings); int n = buildings.size(); for (int i = 0; i < n; i ++) { Building target = buildings.get(i); if (target instanceof CrystalResource) { CrystalResource cr = (CrystalResource) target; if (cr.hasRemaining()) { waitTick = 0; crystal = cr; if (cr.getBeams() < 4) { cr.addBeams(1); mining = true; zapEffect = new ElectronZapEffect ( false, Res.getFactoryMiningBuffer(), new MappedColor("factoryzap.background"), new MappedColor("factoryzap.foreground"), 128, beamStartEmitter, beamEndEmitter, getX() + BEAM_X_OFFSET, getY() + BEAM_Y_OFFSET, MAX_WIDTH, MAX_WOBBLE, WOBBLE_FACTOR, WIDTH_FACTOR ); zapEffect.setTarget(crystal.getMapX() + crystal.getCollisionX(), crystal.getMapY() + crystal.getCollisionY()); zapEffect.spawn(GameScreen.getInstance()); } cancelUndo(); return; } } } } @Override protected void doRespawn() { super.doRespawn(); findCrystal(); } @Override public boolean isShutdown() { return shutdown; } @Override public boolean isMining() { return !shutdown && crystal != null; } @Override protected boolean isAffectedBy(Building building) { if (building instanceof CrystalResource) { CrystalResource crystalResource = (CrystalResource) building; if (!crystalResource.hasRemaining()) { return false; } } return super.isAffectedBy(building); } } public FactoryBuildingFeature(String name) { super(name); } @Override public Building doSpawn(boolean ghost) { return new FactoryBuildingInstance(ghost); } @Override public boolean isAffectedBy(BuildingFeature feature) { return feature instanceof WarehouseBuildingFeature || feature instanceof CollectorBuildingFeature || feature instanceof ShieldGeneratorBuildingFeature || feature instanceof CloakBuildingFeature || feature instanceof CrystalFeature; } @Override public boolean isFactory() { return true; } @Override public LayersFeature getAppearance(Building building) { FactoryBuildingInstance factory = (FactoryBuildingInstance) building; if (factory.shutdown) { return shutdownAppearance; } else { return super.getAppearance(factory); } } @Override public int getShopValue() { // If player has less than the cost of a factory and has no factories left, always allow them to build something if (Worm.getGameState().getFactories() == 0) { return Math.min(super.getShopValue(), Worm.getGameState().getMoney()); } else { return super.getShopValue(); } } @Override protected void doRegister() { super.doRegister(); instance = this; } public static FactoryBuildingFeature getInstance() { return instance; } public int getRate() { return baseProductionRate; } }