diff --git a/dat/outfit.xml b/dat/outfit.xml
index 5d87879..5a225e2 100644
--- a/dat/outfit.xml
+++ b/dat/outfit.xml
@@ -163,6 +163,7 @@
50
130
100
+ beam_ragnarok
diff --git a/dat/ship.xml b/dat/ship.xml
index e4b8dc8..4dcbdaf 100644
--- a/dat/ship.xml
+++ b/dat/ship.xml
@@ -238,7 +238,8 @@
10
- Ripper MK2
+ Ripper MK2
+ Ragnarok Beam
Headhunter Launcher
Headhunter
diff --git a/gfx/outfit/space/beam_ragnarok.png b/gfx/outfit/space/beam_ragnarok.png
new file mode 100644
index 0000000..50d6245
Binary files /dev/null and b/gfx/outfit/space/beam_ragnarok.png differ
diff --git a/src/opengl.c b/src/opengl.c
index 45f2256..30ce204 100644
--- a/src/opengl.c
+++ b/src/opengl.c
@@ -313,6 +313,10 @@ static GLuint gl_loadSurface(SDL_Surface* surface, int *rw, int* rh) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ /* Always wrap just in case. */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
/* Now lead the texture data up. */
SDL_LockSurface(surface);
glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel,
diff --git a/src/outfit.c b/src/outfit.c
index 12cb330..9efc09f 100644
--- a/src/outfit.c
+++ b/src/outfit.c
@@ -280,6 +280,7 @@ int outfit_isMap(const Outfit* o) {
*/
glTexture* outfit_gfx(const Outfit* o) {
if(outfit_isBolt(o)) return o->u.blt.gfx_space;
+ else if(outfit_isBeam(o)) return o->u.bem.gfx;
else if(outfit_isAmmo(o)) return o->u.amm.gfx_space;
else if(outfit_isTurret(o)) return o->u.blt.gfx_space;
return NULL;
@@ -561,22 +562,32 @@ static void outfit_parseSBolt(Outfit* tmp, const xmlNodePtr parent) {
*/
static void outfit_parseSBeam(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node;
-
+ char str[PATH_MAX] = "\0";
+
node = parent->xmlChildrenNode;
do { /* Load all the data. */
xmlr_float(node, "range", tmp->u.bem.range);
xmlr_float(node, "turn", tmp->u.bem.turn);
xmlr_float(node, "energy", tmp->u.bem.energy);
xmlr_long(node, "delay", tmp->u.bem.delay);
+ xmlr_float(node, "warmup", tmp->u.bem.warmup);
xmlr_float(node, "duration", tmp->u.bem.duration);
- if(xml_isNode(node, "damage"))
+ if(xml_isNode(node, "damage")) {
outfit_parseDamage(&tmp->u.bem.dtype, &tmp->u.bem.damage, node);
+ continue;
+ }
+
+ if(xml_isNode(node, "gfx")) {
+ snprintf(str, strlen(xml_get(node))+sizeof(OUTFIT_GFX)+10,
+ OUTFIT_GFX"space/%s.png", xml_get(node));
+ tmp->u.bem.gfx = gl_newSprite(str, 1, 1);
+ continue;
+ }
} while(xml_nextNode(node));
- tmp->u.bem.colour = &cWhite; /** @todo Make it loadable. */
-
#define MELEMENT(o,s) if(0) WARN("Outfit '%s' missing/invalid '"s"' element", tmp->name)
+ MELEMENT(tmp->u.bem.gfx==NULL, "gfx");
MELEMENT(tmp->u.bem.delay==0, "range");
MELEMENT(tmp->u.bem.duration==0, "duration");
MELEMENT(tmp->u.bem.range==0, "range");
@@ -590,8 +601,8 @@ static void outfit_parseSBeam(Outfit* tmp, const xmlNodePtr parent) {
/* Parse the specific area for a launcher and loads it into Outfit. */
static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node;
+
node = parent->xmlChildrenNode;
-
do {
/* Load the dataz. */
if(xml_isNode(node, "delay")) tmp->u.lau.delay = xml_getInt(node);
diff --git a/src/outfit.h b/src/outfit.h
index 5a96911..e4ba241 100644
--- a/src/outfit.h
+++ b/src/outfit.h
@@ -52,6 +52,7 @@ typedef struct OutfitBoltData_ {
DamageType dtype; /**< Damage type. */
double damage; /**< damage. */
+ /* Sound and graphics. */
glTexture* gfx_space; /**< Graphic. */
int sound; /**< Sound to play. */
int spfx; /**< Special effect on hit. */
@@ -63,14 +64,21 @@ typedef struct OutfitBoltData_ {
* @brief Represents the particular properties of a beam weapon.
*/
typedef struct OutfitBeamData_ {
+ /* Time stuff. */
unsigned int delay; /**< Delay between usage. */
- unsigned int duration; /**< How long the beam lasts active. */
+ double warmup; /**< How long it takes to warm up. */
+ double duration; /**< How long the beam lasts active. */
+
+ /* Beam properties. */
double range; /**< How far it goes. */
double turn; /**< How fast it can turn. Only for turrets. */
glColour* colour; /**< Beam colour. */
double energy; /**< Amount of energy it drains (per second). */
DamageType dtype; /**< Damage type. */
double damage; /**< Damage amount. */
+
+ /* Graphics */
+ glTexture* gfx; /**< Base texture. */
} OutfitBeamData;
/**
diff --git a/src/weapon.c b/src/weapon.c
index 78d7635..5d9a5b3 100644
--- a/src/weapon.c
+++ b/src/weapon.c
@@ -373,16 +373,51 @@ static void weapon_render(const Weapon* w) {
/* Beam weapons. */
case OUTFIT_TYPE_BEAM:
case OUTFIT_TYPE_TURRET_BEAM:
+ gfx = outfit_gfx(w->outfit);
x = w->solid->pos.x - VX(*gl_camera) + gui_xoff;
y = w->solid->pos.y - VY(*gl_camera) + gui_yoff;
- ACOLOUR(*w->outfit->u.bem.colour, 0.8);
- glLineWidth(3.);
- glBegin(GL_LINES);
- glVertex2d(x, y);
- glVertex2d(x + w->outfit->u.bem.range * cos(w->solid->dir),
- y + w->outfit->u.bem.range * sin(w->solid->dir));
+
+ /* Set up the matrix. */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glTranslated(x, y, 0.);
+ glRotated(270. + w->solid->dir / M_PI * 180., 0., 0., 1.);
+
+ /* Preparatives. */
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, gfx->texture);
+ glShadeModel(GL_SMOOTH);
+
+ /* Actual rendering. */
+ glBegin(GL_QUAD_STRIP);
+ COLOUR(cWhite);
+
+ /* Full strength. */
+ glTexCoord2d(0., 0.);
+ glVertex2d(-gfx->sh/2., 0.);
+
+ glTexCoord2d(0., 1.);
+ glVertex2d(+gfx->sh/2., 0.);
+
+ glTexCoord2d(0.8*w->outfit->u.bem.range / gfx->sw, 0.);
+ glVertex2d(+gfx->sh/2., 0.8*w->outfit->u.bem.range);
+
+ /* Fades out. */
+ ACOLOUR(cWhite, 0.);
+
+ glTexCoord2d(w->outfit->u.bem.range / gfx->sw, 0.);
+ glVertex2d(-gfx->sh/2., w->outfit->u.bem.range);
+
+ glTexCoord2d(w->outfit->u.bem.range / gfx->sw, 1.);
+ glVertex2d(+gfx->sh/2., w->outfit->u.bem.range);
glEnd();
- glLineWidth(1.);
+
+ /* Clean up. */
+ glDisable(GL_TEXTURE_2D);
+ glShadeModel(GL_FLAT);
+ glPopMatrix();
+ gl_checkErr();
+
break;
default: