/* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive Copyright (C) 2005-2009 Warzone Resurrection Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Warzone 2100 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Warzone 2100; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "lib/framework/frame.h" #include "map.h" #include "hci.h" #include "mapdisplay.h" #include "display3d.h" #include "lib/ivis_common/ivisdef.h" //ivis matrix code #include "lib/ivis_common/piedef.h" //pie render #include "lib/ivis_opengl/piematrix.h" #include "lib/ivis_common/piepalette.h" #include "miscimd.h" #include "effects.h" #include "bridge.h" /** * @file bridge.c * Bridges - currently unused. * * Handles rendering and placement of bridging sections for * traversing water and ravines?! My guess is this won't make it into * the final game, but we'll see... * Alex McLean, Pumpkin Studios EIDOS Interactive, 1998. * * He was right. It did not make the final game. The code below * is unused. Can it be reused? - Per, 2007 */ /* Returns true or false as to whether a bridge is valid. For it to be true - all intervening points must be lower than the start and end points. We can also check other stuff here like what it's going over. Also, it has to be between a minimum and maximum length and one of the axes must share the same values. */ BOOL bridgeValid(UDWORD startX, UDWORD startY, UDWORD endX, UDWORD endY) { BOOL xBridge, yBridge; UDWORD bridgeLength; UDWORD startHeight, endHeight, sectionHeight; UDWORD i; /* Establish axes allignment */ xBridge = ((startX == endX) ? true : false); yBridge = ((startY == endY) ? true : false); /* At least one axis must be constant */ if (!xBridge && !yBridge) { /* Bridge isn't straight - this shouldn't have been passed in, but better safe than sorry! */ return false; } /* Get the bridge length */ bridgeLength = (xBridge ? abs(startY - endY) : abs(startX - endX)); /* check it's not too long or short */ if (bridgeLength < MINIMUM_BRIDGE_SPAN || bridgeLength > MAXIMUM_BRIDGE_SPAN) { /* Cry out */ return false; } /* Check intervening tiles to see if they're lower so first get the start and end heights */ startHeight = mapTile(startX, startY)->height; endHeight = mapTile(endX, endY)->height; /* Don't whinge about this piece of code please! It's nice and short and is called very infrequently. Could be made slightly faster. */ for (i = (xBridge ? MIN(startY, endY) : MIN(startX, endX)); i < (xBridge ? MAX(startY, endY) : MAX(startX, endX)); i++) { /* Get the height of a bridge section */ sectionHeight = mapTile((xBridge ? startX : startY), i)->height; /* Is it higher than BOTH end points? */ if (sectionHeight > MAX(startHeight, endHeight)) { /* Cry out */ return false; } } /* Everything's just fine */ return(true); } /* This function will actually draw a wall section Slightly different from yer basic structure draw in that it's not alligned to the terrain as bridge sections sit at a height stored in their structure - as they're above the ground and wouldn't be much use if they weren't, bridge wise. */ BOOL renderBridgeSection(STRUCTURE *psStructure) { SDWORD rx, rz; Vector3i dv; /* Bomb out if it's not visible */ if (!psStructure->visible[selectedPlayer]) { return false; } /* Establish where it is in the world */ dv.x = (psStructure->pos.x - player.p.x) - terrainMidX * TILE_UNITS; dv.z = terrainMidY * TILE_UNITS - (psStructure->pos.y - player.p.z); dv.y = psStructure->pos.z; /* Push the indentity matrix */ pie_MatBegin(); /* Translate */ pie_TRANSLATE(dv.x, dv.y, dv.z); /* Get the x,z translation components */ rx = map_round(player.p.x); rz = map_round(player.p.z); /* Translate */ pie_TRANSLATE(rx, 0, -rz); pie_Draw3DShape(psStructure->sDisplay.imd, 0, 0, WZCOL_WHITE, WZCOL_BLACK, 0, 0); pie_MatEnd(); return(true); } /* This will work out all the info you need about the bridge including length - height to set sections at in order to allign to terrain and what you need to alter start and end terrain heights by to establish to connection. */ void getBridgeInfo(UDWORD startX, UDWORD startY, UDWORD endX, UDWORD endY, BRIDGE_INFO *info) { BOOL xBridge, yBridge; UDWORD startHeight, endHeight; BOOL startHigher; /* Copy over the location coordinates */ info->startX = startX; info->startY = startY; info->endX = endX; info->endY = endY; /* Get the heights of the start and end positions */ startHeight = map_TileHeight(startX, startY); endHeight = map_TileHeight(endX, endY); /* Find out which is higher */ startHigher = (startHeight >= endHeight ? true : false); /* If the start position is higher */ if (startHigher) { /* Inform structure */ info->startHighest = true; /* And the end position needs raising */ info->heightChange = startHeight - endHeight; } /* Otherwise, the end position is lower */ else { /* Inform structure */ info->startHighest = false; /* So we need to raise the start position */ info->heightChange = endHeight - startHeight; } /* Establish axes allignment */ /* Only one of these can occur otherwise bridge is one square big */ xBridge = ((startX == endX) ? true : false); yBridge = ((startY == endY) ? true : false); /* Set the bridge's height. Note that when the bridge is built BOTH tile heights need to be set to the agreed value on their bridge trailing edge (x,y) and (x,y+1) is constant X and (x,y) and (x+1,y) if constant Y */ if (startHigher) { info->bridgeHeight = map_TileHeight(startX, startY); } else { info->bridgeHeight = map_TileHeight(endX, endY); } /* We've got a bridge of constant X */ if (xBridge) { info->bConstantX = true; info->bridgeLength = abs(startY - endY); } /* We've got a bridge of constant Y */ else if (yBridge) { info->bConstantX = false; info->bridgeLength = abs(startX - endX); } else { debug( LOG_FATAL, "Weirdy Bridge requested - no axes allignment" ); abort(); } } void testBuildBridge(UDWORD startX, UDWORD startY, UDWORD endX, UDWORD endY) { BRIDGE_INFO bridge; UDWORD i; Vector3i dv; if (bridgeValid(startX, startY, endX, endY)) { getBridgeInfo(startX, startY, endX, endY, &bridge); if (bridge.bConstantX) { for (i = MIN(bridge.startY, bridge.endY); i < (MAX(bridge.startY, bridge.endY) + 1); i++) { dv.x = ((bridge.startX * 128) + 64); dv.z = ((i * 128) + 64); dv.y = bridge.bridgeHeight; addEffect(&dv, EFFECT_SMOKE, SMOKE_TYPE_DRIFTING, false, NULL, 0); // addExplosion(&dv, TYPE_EXPLOSION_SMOKE_CLOUD, NULL); } } else { for (i = MIN(bridge.startX, bridge.endX); i < (MAX(bridge.startX, bridge.endX) + 1); i++) { dv.x = ((i * 128) + 64); dv.z = ((bridge.startY * 128) + 64); dv.y = bridge.bridgeHeight; addEffect(&dv, EFFECT_SMOKE, SMOKE_TYPE_DRIFTING, false, NULL, 0); // addExplosion(&dv, TYPE_EXPLOSION_SMOKE_CLOUD, NULL); } } /* Flatten the start tile */ setTileHeight(bridge.startX, bridge.startY, bridge.bridgeHeight); setTileHeight(bridge.startX, bridge.startY + 1, bridge.bridgeHeight); setTileHeight(bridge.startX + 1, bridge.startY, bridge.bridgeHeight); setTileHeight(bridge.startX + 1, bridge.startY + 1, bridge.bridgeHeight); /* Flatten the end tile */ setTileHeight(bridge.endX, bridge.endY, bridge.bridgeHeight); setTileHeight(bridge.endX, bridge.endY + 1, bridge.bridgeHeight); setTileHeight(bridge.endX + 1, bridge.endY, bridge.bridgeHeight); setTileHeight(bridge.endX + 1, bridge.endY + 1, bridge.bridgeHeight); } else { getBridgeInfo(startX, startY, endX, endY, &bridge); if (bridge.bConstantX) { for (i = MIN(bridge.startY, bridge.endY); i < (MAX(bridge.startY, bridge.endY) + 1); i++) { dv.x = ((bridge.startX * 128) + 64); dv.z = ((i * 128) + 64); dv.y = bridge.bridgeHeight; addEffect(&dv, EFFECT_EXPLOSION, EXPLOSION_TYPE_SMALL, false, NULL, 0); // addExplosion(&dv, TYPE_EXPLOSION_MED, NULL); } } else { for (i = MIN(bridge.startX, bridge.endX); i < (MAX(bridge.startX, bridge.endX) + 1); i++) { dv.x = ((i * 128) + 64); dv.z = ((bridge.startY * 128) + 64); dv.y = bridge.bridgeHeight; addEffect(&dv, EFFECT_EXPLOSION, EXPLOSION_TYPE_SMALL, false, NULL, 0); // addExplosion(&dv, TYPE_EXPLOSION_MED, NULL); } } } }