]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Weapons.cpp
42ee250786c0356cf0a2d8c11bdaf75343d41163
[lugaru.git] / Source / Objects / Weapons.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 This file is part of Lugaru.
8
9 Lugaru is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 Lugaru is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "Objects/Weapons.hpp"
24
25 #include "Animation/Animation.hpp"
26 #include "Audio/Sounds.hpp"
27 #include "Audio/openal_wrapper.hpp"
28 #include "Game.hpp"
29 #include "Level/Awards.hpp"
30 #include "Tutorial.hpp"
31
32 extern float multiplier;
33 extern Terrain terrain;
34 extern float gravity;
35 extern int environment;
36 extern int detail;
37 extern FRUSTUM frustum;
38 extern XYZ viewer;
39 extern float realmultiplier;
40 extern int slomo;
41 extern float slomodelay;
42 extern bool cellophane;
43 extern float texdetail;
44 extern GLubyte bloodText[512 * 512 * 3];
45 extern int bloodtoggle;
46 extern bool autoslomo;
47 extern float camerashake;
48 extern float woozy;
49 extern float viewdistance;
50 extern float blackout;
51 extern bool freeze;
52 extern int numthrowkill;
53
54 Model Weapon::throwingknifemodel;
55 Texture Weapon::knifetextureptr;
56 Texture Weapon::lightbloodknifetextureptr;
57 Texture Weapon::bloodknifetextureptr;
58
59 Model Weapon::swordmodel;
60 Texture Weapon::swordtextureptr;
61 Texture Weapon::lightbloodswordtextureptr;
62 Texture Weapon::bloodswordtextureptr;
63
64 Model Weapon::staffmodel;
65 Texture Weapon::stafftextureptr;
66
67 Weapon::Weapon(int t, int o)
68     : owner(o)
69 {
70     setType(t);
71     bloody = 0;
72     blooddrip = 0;
73     blooddripdelay = 0;
74     onfire = 0;
75     flamedelay = 0;
76     damage = 0;
77     position = -1000;
78     tippoint = -1000;
79 }
80
81 void Weapon::setType(int t)
82 {
83     type = t;
84     if (type == sword) {
85         mass = 1.5;
86         tipmass = 1;
87         length = .8;
88     }
89     if (type == staff) {
90         mass = 2;
91         tipmass = 1;
92         length = 1.5;
93     }
94     if (type == knife) {
95         mass = 1;
96         tipmass = 1.2;
97         length = .25;
98     }
99 }
100
101 /* Load weapons models and textures */
102 void Weapon::Load()
103 {
104     LOG("Loading weapon data...");
105
106     knifetextureptr.load("Textures/Knife.png", 0);
107     bloodknifetextureptr.load("Textures/BloodKnife.png", 0);
108     lightbloodknifetextureptr.load("Textures/BloodKnifeLight.png", 0);
109     swordtextureptr.load("Textures/Sword.jpg", 1);
110     bloodswordtextureptr.load("Textures/SwordBlood.jpg", 1);
111     lightbloodswordtextureptr.load("Textures/SwordBloodLight.jpg", 1);
112     stafftextureptr.load("Textures/Staff.jpg", 1);
113
114     throwingknifemodel.load("Models/ThrowingKnife.solid");
115     throwingknifemodel.Scale(.001, .001, .001);
116     throwingknifemodel.Rotate(90, 0, 0);
117     throwingknifemodel.Rotate(0, 90, 0);
118     throwingknifemodel.flat = 0;
119     throwingknifemodel.CalculateNormals(1);
120
121     swordmodel.load("Models/Sword.solid");
122     swordmodel.Scale(.001, .001, .001);
123     swordmodel.Rotate(90, 0, 0);
124     swordmodel.Rotate(0, 90, 0);
125     swordmodel.Rotate(0, 0, 90);
126     swordmodel.flat = 1;
127     swordmodel.CalculateNormals(1);
128
129     staffmodel.load("Models/Staff.solid");
130     staffmodel.Scale(.005, .005, .005);
131     staffmodel.Rotate(90, 0, 0);
132     staffmodel.Rotate(0, 90, 0);
133     staffmodel.Rotate(0, 0, 90);
134     staffmodel.flat = 1;
135     staffmodel.CalculateNormals(1);
136 }
137
138 void Weapon::doStuff(int i)
139 {
140     static int whichpatchx, whichpatchz, whichhit;
141     static XYZ start, end, colpoint, normalrot, footvel, footpoint;
142     static XYZ terrainnormal;
143     static XYZ vel;
144     static XYZ midp;
145     static XYZ newpoint1, newpoint2;
146     static float friction = 3.5;
147     static float elasticity = .4;
148     static XYZ bounceness;
149     static float frictionness;
150     static float closestdistance;
151     static float distance;
152     static XYZ point[3];
153     static XYZ closestpoint;
154     static XYZ closestswordpoint;
155     static float tempmult;
156
157     if (multiplier <= 0) {
158         return;
159     }
160
161     if (owner != -1) {
162         oldowner = owner;
163     }
164     if (damage >= 2 && type == staff && owner != -1) { // the staff breaks
165         emit_sound_at(staffbreaksound, tippoint);
166         XYZ tempvel;
167         for (int j = 0; j < 40; j++) {
168             tempvel.x = float(abs(Random() % 100) - 50) / 20;
169             tempvel.y = float(abs(Random() % 100) - 50) / 20;
170             tempvel.z = float(abs(Random() % 100) - 50) / 20;
171             Sprite::MakeSprite(splintersprite, position + (tippoint - position) * ((float)j - 8) / 32, tempvel * .5, 115 / 255, 73 / 255, 12 / 255, .1, 1);
172         }
173         if (owner != -1) {
174             Person::players[owner]->weaponactive = -1;
175             Person::players[owner]->num_weapons--;
176             if (Person::players[owner]->num_weapons) {
177                 Person::players[owner]->weaponids[0] = Person::players[owner]->weaponids[Person::players[owner]->num_weapons];
178                 if (Person::players[owner]->weaponstuck == Person::players[owner]->num_weapons)
179                     Person::players[owner]->weaponstuck = 0;
180             }
181         }
182         owner = -1;
183         hitsomething = 0;
184         missed = 1;
185         freetime = 0;
186         firstfree = 1;
187         position = 0;
188         physics = 0;
189     }
190     oldposition = position;
191     oldtippoint = tippoint;
192     if (owner == -1 && (velocity.x || velocity.y || velocity.z) && !physics) { // if the weapon is flying
193         position += velocity * multiplier;
194         tippoint += velocity * multiplier;
195         whichpatchx = position.x / (terrain.size / subdivision * terrain.scale);
196         whichpatchz = position.z / (terrain.size / subdivision * terrain.scale);
197         if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
198             for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) { // check for collision
199                 unsigned int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
200                 start = oldtippoint;
201                 end = tippoint;
202                 whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
203                 if (whichhit != -1) {
204                     if (Object::objects[k]->type == treetrunktype) {
205                         Object::objects[k]->model.MakeDecal(breakdecal, DoRotation(colpoint - Object::objects[k]->position, 0, -Object::objects[k]->yaw, 0), .1, 1, Random() % 360);
206                         normalrot = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0);
207                         velocity = 0;
208                         if (type == knife)
209                             position = colpoint - normalrot * .1;
210                         else if (type == sword)
211                             position = colpoint - normalrot * .2;
212                         else if (type == staff)
213                             position = colpoint - normalrot * .2;
214                         XYZ temppoint1, temppoint2;
215                         float distance;
216
217                         temppoint1 = 0;
218                         temppoint2 = normalrot;
219                         distance = findDistance(&temppoint1, &temppoint2);
220                         rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
221                         rotation2 *= 360 / 6.28;
222                         temppoint1.y = 0;
223                         temppoint2.y = 0;
224                         rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
225                         rotation1 *= 360 / 6.28;
226                         if (temppoint1.x > temppoint2.x)
227                             rotation1 = 360 - rotation1;
228
229                         rotation3 = 0;
230                         smallrotation = 90;
231                         smallrotation2 = 0;
232                         bigtilt = 0;
233                         bigtilt2 = 0;
234                         bigrotation = 0;
235
236                         emit_sound_at(knifesheathesound, position, 128.);
237
238                         bloody = 0;
239
240                         Sprite::MakeSprite(cloudimpactsprite, position, velocity, 1, 1, 1, .8, .3);
241                     } else {
242                         physics = 1;
243                         firstfree = 1;
244                         position -= velocity * multiplier;
245                         tippoint -= velocity * multiplier;
246                         tipvelocity = velocity;
247                     }
248                 }
249             }
250         }
251
252         if (velocity.x || velocity.y || velocity.z) {
253             for (unsigned j = 0; j < Person::players.size(); j++) {
254                 footvel = 0;
255                 footpoint = DoRotation((Person::players[j]->jointPos(abdomen) + Person::players[j]->jointPos(neck)) / 2, 0, Person::players[j]->yaw, 0) * Person::players[j]->scale + Person::players[j]->coords;
256                 if (owner == -1 && distsqflat(&position, &Person::players[j]->coords) < 1.5 &&
257                     distsq(&position, &Person::players[j]->coords) < 4 && Person::players[j]->weaponstuck == -1 &&
258                     !Person::players[j]->skeleton.free && (int(j) != oldowner)) {
259                     if ((Person::players[j]->aitype != attacktypecutoff || abs(Random() % 6) == 0 || (Person::players[j]->animTarget != backhandspringanim && Person::players[j]->animTarget != rollanim && Person::players[j]->animTarget != flipanim && Random() % 2 == 0)) && !missed) {
260                         if ((Person::players[j]->creature == wolftype && Random() % 3 != 0 && Person::players[j]->weaponactive == -1 && (Person::players[j]->isIdle() || Person::players[j]->isRun() || Person::players[j]->animTarget == walkanim)) ||
261                             (Person::players[j]->creature == rabbittype && Random() % 2 == 0 && Person::players[j]->aitype == attacktypecutoff && Person::players[j]->weaponactive == -1)) {
262                             emit_sound_at(knifedrawsound, Person::players[j]->coords, 128.);
263
264                             Person::players[j]->animTarget = removeknifeanim;
265                             Person::players[j]->frameTarget = 1;
266                             Person::players[j]->target = 1;
267                             Person::players[j]->takeWeapon(i);
268
269                             Person::players[j]->aitype = attacktypecutoff;
270                         } else {
271                             if (j != 0)
272                                 numthrowkill++;
273                             Person::players[j]->num_weapons++;
274                             Person::players[j]->weaponstuck = Person::players[j]->num_weapons - 1;
275                             if (normaldotproduct(Person::players[j]->facing, velocity) > 0)
276                                 Person::players[j]->weaponstuckwhere = 1;
277                             else
278                                 Person::players[j]->weaponstuckwhere = 0;
279
280                             Person::players[j]->weaponids[Person::players[j]->num_weapons - 1] = i;
281
282                             Person::players[j]->RagDoll(0);
283                             Person::players[j]->jointVel(abdomen) += velocity * 2;
284                             Person::players[j]->jointVel(neck) += velocity * 2;
285                             Person::players[j]->jointVel(rightshoulder) += velocity * 2;
286                             Person::players[j]->jointVel(leftshoulder) += velocity * 2;
287                             if (bloodtoggle && !Tutorial::active)
288                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
289                             if (Tutorial::active)
290                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .8, .3);
291                             footvel = tippoint - position;
292                             Normalise(&footvel);
293                             if (bloodtoggle && !Tutorial::active)
294                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * -1, 1, 0, 0, .6, 1);
295
296                             if (!Tutorial::active) {
297                                 if (Person::players[j]->weaponstuckwhere == 0)
298                                     Person::players[j]->DoBloodBig(2, 205);
299                                 if (Person::players[j]->weaponstuckwhere == 1)
300                                     Person::players[j]->DoBloodBig(2, 200);
301                                 Person::players[j]->damage += 200 / Person::players[j]->armorhigh;
302                                 Person::players[j]->deathbleeding = 1;
303                                 Person::players[j]->bloodloss += (200 + abs((float)(Random() % 40)) - 20) / Person::players[j]->armorhigh;
304                                 owner = j;
305                                 bloody = 2;
306                                 blooddrip = 5;
307                             }
308
309                             emit_sound_at(fleshstabsound, position, 128.);
310
311                             if (Animation::animations[Person::players[0]->animTarget].height == highheight)
312                                 award_bonus(0, ninja);
313                             else
314                                 award_bonus(0, Bullseyebonus);
315                         }
316                     } else {
317                         missed = 1;
318                     }
319                 }
320             }
321         }
322         if (position.y < terrain.getHeight(position.x, position.z)) {
323             if (terrain.getOpacity(position.x, position.z) < .2) {
324                 velocity = 0;
325                 if (terrain.lineTerrain(oldposition, position, &colpoint) != -1) {
326                     position = colpoint * terrain.scale;
327                 } else {
328                     position.y = terrain.getHeight(position.x, position.z);
329                 }
330
331                 terrain.MakeDecal(shadowdecalpermanent, position, .06, .5, 0);
332                 normalrot = terrain.getNormal(position.x, position.z) * -1;
333                 velocity = 0;
334                 glMatrixMode(GL_MODELVIEW);
335                 glPushMatrix();
336                 GLfloat M[16];
337                 glLoadIdentity();
338                 glRotatef(bigrotation, 0, 1, 0);
339                 glRotatef(bigtilt2, 1, 0, 0);
340                 glRotatef(bigtilt, 0, 0, 1);
341                 glRotatef(-rotation1 + 90, 0, 1, 0);
342                 glRotatef(-rotation2 + 90, 0, 0, 1);
343                 glRotatef(-rotation3, 0, 1, 0);
344                 glRotatef(smallrotation, 1, 0, 0);
345                 glRotatef(smallrotation2, 0, 1, 0);
346                 glTranslatef(0, 0, 1);
347                 glGetFloatv(GL_MODELVIEW_MATRIX, M);
348                 tippoint.x = M[12];
349                 tippoint.y = M[13];
350                 tippoint.z = M[14];
351                 glPopMatrix();
352                 position -= tippoint * .15;
353                 XYZ temppoint1, temppoint2;
354
355                 rotation3 = 0;
356                 smallrotation = 90;
357                 smallrotation2 = 0;
358                 bigtilt = 0;
359                 bigtilt2 = 0;
360                 bigrotation = 0;
361
362                 emit_sound_at(knifesheathesound, position, 128.);
363
364                 XYZ terrainlight;
365                 terrainlight = terrain.getLighting(position.x, position.z);
366                 if (environment == snowyenvironment) {
367                     if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
368                         Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
369                 } else if (environment == grassyenvironment) {
370                     if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
371                         Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
372                 } else if (environment == desertenvironment) {
373                     if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
374                         Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
375                 }
376
377                 bloody = 0;
378             } else {
379                 physics = 1;
380                 firstfree = 1;
381                 position -= velocity * multiplier;
382                 tippoint -= velocity * multiplier;
383                 tipvelocity = velocity;
384             }
385         }
386         if (velocity.x != 0 || velocity.z != 0 || velocity.y != 0) {
387             velocity.y += gravity * multiplier;
388
389             XYZ temppoint1, temppoint2;
390             float distance;
391
392             temppoint1 = 0;
393             temppoint2 = velocity;
394             distance = findDistance(&temppoint1, &temppoint2);
395             rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
396             rotation2 *= 360 / 6.28;
397             temppoint1.y = 0;
398             temppoint2.y = 0;
399             rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
400             rotation1 *= 360 / 6.28;
401             rotation3 = 0;
402             smallrotation = 90;
403             smallrotation2 = 0;
404             bigtilt = 0;
405             bigtilt2 = 0;
406             bigrotation = 0;
407             if (temppoint1.x > temppoint2.x)
408                 rotation1 = 360 - rotation1;
409         }
410     }
411
412     //Sword physics
413     XYZ mid;
414     XYZ oldmid;
415     XYZ oldmid2;
416
417     tempmult = multiplier;
418     multiplier /= 10;
419     for (int l = 0; l < 10; l++) {
420         if (owner == -1 && (velocity.x || velocity.y || velocity.z) && physics) {
421             //move
422             position += velocity * multiplier;
423             tippoint += tipvelocity * multiplier;
424
425             //Length constrain
426             midp = (position * mass + tippoint * tipmass) / (mass + tipmass);
427             vel = tippoint - midp;
428             Normalise(&vel);
429             newpoint1 = midp - vel * length * (tipmass / (mass + tipmass));
430             newpoint2 = midp + vel * length * (mass / (mass + tipmass));
431             if (!freeze) {
432                 if (freetime > .04) {
433                     velocity = velocity + (newpoint1 - position) / multiplier;
434                     tipvelocity = tipvelocity + (newpoint2 - tippoint) / multiplier;
435                 }
436             }
437             position = newpoint1;
438             tippoint = newpoint2;
439
440             //Object collisions
441             whichpatchx = (position.x) / (terrain.size / subdivision * terrain.scale);
442             whichpatchz = (position.z) / (terrain.size / subdivision * terrain.scale);
443             if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
444                 for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) {
445                     unsigned int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
446
447                     if (firstfree) {
448                         if (type == staff) {
449                             start = tippoint - (position - tippoint) / 5;
450                             end = position + (position - tippoint) / 30;
451                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
452                             if (whichhit != -1) {
453                                 XYZ diff;
454                                 diff = (colpoint - position);
455                                 Normalise(&diff);
456                                 hitsomething = 1;
457
458                                 tippoint += (colpoint - position) + diff * .05;
459                                 position = colpoint + diff * .05;
460                                 oldtippoint = tippoint;
461                                 oldposition = tippoint;
462                             }
463                         } else {
464                             start = position - (tippoint - position) / 5;
465                             end = tippoint + (tippoint - position) / 30;
466                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
467                             if (whichhit != -1) {
468                                 XYZ diff;
469                                 diff = (colpoint - tippoint);
470                                 Normalise(&diff);
471                                 hitsomething = 1;
472
473                                 position += (colpoint - tippoint) + diff * .05;
474                                 tippoint = colpoint + diff * .05;
475                                 oldposition = position;
476                                 oldtippoint = tippoint;
477                             }
478                         }
479                     }
480
481                     start = oldposition;
482                     end = position;
483                     whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
484                     if (whichhit != -1) {
485                         hitsomething = 1;
486                         position = colpoint;
487                         terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
488                         ReflectVector(&velocity, &terrainnormal);
489                         position += terrainnormal * .002;
490
491                         bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
492                         if (findLengthfast(&velocity) < findLengthfast(&bounceness))
493                             bounceness = 0;
494                         frictionness = abs(normaldotproduct(velocity, terrainnormal));
495                         velocity -= bounceness;
496                         if (1 - friction * frictionness > 0)
497                             velocity *= 1 - friction * frictionness;
498                         else
499                             velocity = 0;
500                         velocity += bounceness * elasticity;
501
502                         if (findLengthfast(&bounceness) > 1) {
503                             int whichsound;
504                             if (type == staff)
505                                 whichsound = footstepsound3 + abs(Random() % 2);
506                             else
507                                 whichsound = clank1sound + abs(Random() % 4);
508                             emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
509                         }
510                     }
511                     start = oldtippoint;
512                     end = tippoint;
513                     whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
514                     if (whichhit != -1) {
515                         hitsomething = 1;
516                         tippoint = colpoint;
517                         terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
518                         ReflectVector(&tipvelocity, &terrainnormal);
519                         tippoint += terrainnormal * .002;
520
521                         bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
522                         if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
523                             bounceness = 0;
524                         frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
525                         tipvelocity -= bounceness;
526                         if (1 - friction * frictionness > 0)
527                             tipvelocity *= 1 - friction * frictionness;
528                         else
529                             tipvelocity = 0;
530                         tipvelocity += bounceness * elasticity;
531
532                         if (findLengthfast(&bounceness) > 1) {
533                             int whichsound;
534                             if (type == staff)
535                                 whichsound = footstepsound3 + abs(Random() % 2);
536                             else
537                                 whichsound = clank1sound + abs(Random() % 4);
538                             emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
539                         }
540                     }
541
542                     if ((Object::objects[k]->type != boxtype && Object::objects[k]->type != platformtype && Object::objects[k]->type != walltype && Object::objects[k]->type != weirdtype) || Object::objects[k]->pitch != 0)
543                         for (int m = 0; m < 2; m++) {
544                             mid = (position * (21 + (float)m * 10) + tippoint * (19 - (float)m * 10)) / 40;
545                             oldmid2 = mid;
546                             oldmid = (oldposition * (21 + (float)m * 10) + oldtippoint * (19 - (float)m * 10)) / 40;
547
548                             start = oldmid;
549                             end = mid;
550                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
551                             if (whichhit != -1) {
552                                 hitsomething = 1;
553                                 mid = colpoint;
554                                 terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
555                                 ReflectVector(&velocity, &terrainnormal);
556
557                                 bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
558                                 if (findLengthfast(&velocity) < findLengthfast(&bounceness))
559                                     bounceness = 0;
560                                 frictionness = abs(normaldotproduct(velocity, terrainnormal));
561                                 velocity -= bounceness;
562                                 if (1 - friction * frictionness > 0)
563                                     velocity *= 1 - friction * frictionness;
564                                 else
565                                     velocity = 0;
566                                 velocity += bounceness * elasticity;
567
568                                 if (findLengthfast(&bounceness) > 1) {
569                                     int whichsound;
570                                     if (type == staff)
571                                         whichsound = footstepsound3 + abs(Random() % 2);
572                                     else
573                                         whichsound = clank1sound + abs(Random() % 4);
574                                     emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
575                                 }
576                                 position += (mid - oldmid2) * (20 / (1 + (float)m * 10));
577                             }
578
579                             mid = (position * (19 - (float)m * 10) + tippoint * (21 + (float)m * 10)) / 40;
580                             oldmid2 = mid;
581                             oldmid = (oldposition * (19 - (float)m * 10) + oldtippoint * (21 + (float)m * 10)) / 40;
582
583                             start = oldmid;
584                             end = mid;
585                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
586                             if (whichhit != -1) {
587                                 hitsomething = 1;
588                                 mid = colpoint;
589                                 terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
590                                 ReflectVector(&tipvelocity, &terrainnormal);
591
592                                 bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
593                                 if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
594                                     bounceness = 0;
595                                 frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
596                                 tipvelocity -= bounceness;
597                                 if (1 - friction * frictionness > 0)
598                                     tipvelocity *= 1 - friction * frictionness;
599                                 else
600                                     tipvelocity = 0;
601                                 tipvelocity += bounceness * elasticity;
602
603                                 if (findLengthfast(&bounceness) > 1) {
604                                     int whichsound;
605                                     if (type == staff)
606                                         whichsound = footstepsound3 + abs(Random() % 2);
607                                     else
608                                         whichsound = clank1sound + abs(Random() % 4);
609                                     emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
610                                 }
611                                 tippoint += (mid - oldmid2) * (20 / (1 + (float)m * 10));
612                             }
613                         }
614                     else {
615                         start = position;
616                         end = tippoint;
617                         whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
618                         if (whichhit != -1) {
619                             hitsomething = 1;
620                             closestdistance = -1;
621                             closestswordpoint = colpoint;
622                             point[0] = DoRotation(Object::objects[k]->model.getTriangleVertex(whichhit, 0), 0, Object::objects[k]->yaw, 0) + Object::objects[k]->position;
623                             point[1] = DoRotation(Object::objects[k]->model.getTriangleVertex(whichhit, 1), 0, Object::objects[k]->yaw, 0) + Object::objects[k]->position;
624                             point[2] = DoRotation(Object::objects[k]->model.getTriangleVertex(whichhit, 2), 0, Object::objects[k]->yaw, 0) + Object::objects[k]->position;
625                             if (DistancePointLine(&closestswordpoint, &point[0], &point[1], &distance, &colpoint)) {
626                                 if (distance < closestdistance || closestdistance == -1) {
627                                     closestpoint = colpoint;
628                                     closestdistance = distance;
629                                 }
630                             }
631                             if (DistancePointLine(&closestswordpoint, &point[1], &point[2], &distance, &colpoint)) {
632                                 if (distance < closestdistance || closestdistance == -1) {
633                                     closestpoint = colpoint;
634                                     closestdistance = distance;
635                                 }
636                             }
637                             if (DistancePointLine(&closestswordpoint, &point[2], &point[0], &distance, &colpoint)) {
638                                 if (distance < closestdistance || closestdistance == -1) {
639                                     closestpoint = colpoint;
640                                     closestdistance = distance;
641                                 }
642                             }
643                             if (closestdistance != -1 && isnormal(closestdistance)) {
644                                 if (DistancePointLine(&closestpoint, &position, &tippoint, &distance, &colpoint)) {
645                                     closestswordpoint = colpoint;
646                                     velocity += (closestpoint - closestswordpoint);
647                                     tipvelocity += (closestpoint - closestswordpoint);
648                                     position += (closestpoint - closestswordpoint);
649                                     tippoint += (closestpoint - closestswordpoint);
650                                 }
651                             }
652                         }
653                     }
654                 }
655             }
656             //Terrain collisions
657             whichhit = terrain.lineTerrain(oldposition, position, &colpoint);
658             if (whichhit != -1 || position.y < terrain.getHeight(position.x, position.z)) {
659                 hitsomething = 1;
660                 if (whichhit != -1)
661                     position = colpoint * terrain.scale;
662                 else
663                     position.y = terrain.getHeight(position.x, position.z);
664
665                 terrainnormal = terrain.getNormal(position.x, position.z);
666                 ReflectVector(&velocity, &terrainnormal);
667                 position += terrainnormal * .002;
668                 bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
669                 if (findLengthfast(&velocity) < findLengthfast(&bounceness))
670                     bounceness = 0;
671                 frictionness = abs(normaldotproduct(velocity, terrainnormal));
672                 velocity -= bounceness;
673                 if (1 - friction * frictionness > 0)
674                     velocity *= 1 - friction * frictionness;
675                 else
676                     velocity = 0;
677                 if (terrain.getOpacity(position.x, position.z) < .2)
678                     velocity += bounceness * elasticity * .3;
679                 else
680                     velocity += bounceness * elasticity;
681
682                 if (findLengthfast(&bounceness) > 1) {
683                     int whichsound;
684                     if (terrain.getOpacity(position.x, position.z) > .2) {
685                         if (type == staff)
686                             whichsound = footstepsound3 + abs(Random() % 2);
687                         else
688                             whichsound = clank1sound + abs(Random() % 4);
689                     } else {
690                         whichsound = footstepsound + abs(Random() % 2);
691                     }
692                     emit_sound_at(whichsound, position,
693                                   findLengthfast(&bounceness) * (terrain.getOpacity(position.x, position.z) > .2 ? 128. : 32.));
694
695                     if (terrain.getOpacity(position.x, position.z) < .2) {
696                         XYZ terrainlight;
697                         terrainlight = terrain.getLighting(position.x, position.z);
698                         if (environment == snowyenvironment) {
699                             if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
700                                 Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
701                         } else if (environment == grassyenvironment) {
702                             if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
703                                 Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
704                         } else if (environment == desertenvironment) {
705                             if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
706                                 Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
707                         }
708                     }
709                 }
710             }
711             whichhit = terrain.lineTerrain(oldtippoint, tippoint, &colpoint);
712             if (whichhit != -1 || tippoint.y < terrain.getHeight(tippoint.x, tippoint.z)) {
713                 if (whichhit != -1)
714                     tippoint = colpoint * terrain.scale;
715                 else
716                     tippoint.y = terrain.getHeight(tippoint.x, tippoint.z);
717
718                 terrainnormal = terrain.getNormal(tippoint.x, tippoint.z);
719                 ReflectVector(&tipvelocity, &terrainnormal);
720                 tippoint += terrainnormal * .002;
721                 bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
722                 if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
723                     bounceness = 0;
724                 frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
725                 tipvelocity -= bounceness;
726                 if (1 - friction * frictionness > 0)
727                     tipvelocity *= 1 - friction * frictionness;
728                 else
729                     tipvelocity = 0;
730                 if (terrain.getOpacity(tippoint.x, tippoint.z) < .2)
731                     tipvelocity += bounceness * elasticity * .3;
732                 else
733                     tipvelocity += bounceness * elasticity;
734
735                 if (findLengthfast(&bounceness) > 1) {
736                     int whichsound;
737                     if (terrain.getOpacity(tippoint.x, tippoint.z) > .2) {
738                         if (type == staff)
739                             whichsound = footstepsound3 + abs(Random() % 2);
740                         else
741                             whichsound = clank1sound + abs(Random() % 4);
742                     } else {
743                         whichsound = footstepsound + abs(Random() % 2);
744                     }
745                     emit_sound_at(whichsound, tippoint,
746                                   findLengthfast(&bounceness) * (terrain.getOpacity(tippoint.x, tippoint.z) > .2 ? 128. : 32.));
747
748                     if (terrain.getOpacity(tippoint.x, tippoint.z) < .2) {
749                         XYZ terrainlight;
750                         terrainlight = terrain.getLighting(tippoint.x, tippoint.z);
751                         if (environment == snowyenvironment) {
752                             if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
753                                 Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
754                         } else if (environment == grassyenvironment) {
755                             if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
756                                 Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
757                         } else if (environment == desertenvironment) {
758                             if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
759                                 Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
760                         }
761                     }
762                 }
763             }
764
765             //Edges
766             mid = position + tippoint;
767             mid /= 2;
768             mid += (position - mid) / 20;
769             oldmid = mid;
770             if (mid.y < terrain.getHeight(mid.x, mid.z)) {
771                 hitsomething = 1;
772                 mid.y = terrain.getHeight(mid.x, mid.z);
773
774                 terrainnormal = terrain.getNormal(mid.x, mid.z);
775                 ReflectVector(&velocity, &terrainnormal);
776                 //mid+=terrainnormal*.002;
777                 bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
778                 if (findLengthfast(&velocity) < findLengthfast(&bounceness))
779                     bounceness = 0;
780                 frictionness = abs(normaldotproduct(velocity, terrainnormal));
781                 velocity -= bounceness;
782                 if (1 - friction * frictionness > 0)
783                     velocity *= 1 - friction * frictionness;
784                 else
785                     velocity = 0;
786                 if (terrain.getOpacity(mid.x, mid.z) < .2)
787                     velocity += bounceness * elasticity * .3;
788                 else
789                     velocity += bounceness * elasticity;
790
791                 if (findLengthfast(&bounceness) > 1) {
792                     int whichsound;
793                     if (terrain.getOpacity(mid.x, mid.z) > .2) {
794                         if (type == staff)
795                             whichsound = footstepsound3 + abs(Random() % 2);
796                         if (type != staff)
797                             whichsound = clank1sound + abs(Random() % 4);
798                     } else {
799                         whichsound = footstepsound + abs(Random() % 2);
800                     }
801                     emit_sound_at(whichsound, mid,
802                                   findLengthfast(&bounceness) * (terrain.getOpacity(position.x, position.z) > .2
803                                                                      ? 128.
804                                                                      : 32.));
805                 }
806                 position += (mid - oldmid) * 20;
807             }
808
809             mid = position + tippoint;
810             mid /= 2;
811             mid += (tippoint - mid) / 20;
812             oldmid = mid;
813             if (mid.y < terrain.getHeight(mid.x, mid.z)) {
814                 hitsomething = 1;
815                 mid.y = terrain.getHeight(mid.x, mid.z);
816
817                 terrainnormal = terrain.getNormal(mid.x, mid.z);
818                 ReflectVector(&tipvelocity, &terrainnormal);
819                 //mid+=terrainnormal*.002;
820                 bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
821                 if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
822                     bounceness = 0;
823                 frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
824                 tipvelocity -= bounceness;
825                 if (1 - friction * frictionness > 0)
826                     tipvelocity *= 1 - friction * frictionness;
827                 else
828                     tipvelocity = 0;
829                 if (terrain.getOpacity(mid.x, mid.z) < .2)
830                     tipvelocity += bounceness * elasticity * .3;
831                 else
832                     tipvelocity += bounceness * elasticity;
833
834                 if (findLengthfast(&bounceness) > 1) {
835                     int whichsound;
836                     if (terrain.getOpacity(mid.x, mid.z) > .2) {
837                         if (type == staff)
838                             whichsound = footstepsound3 + abs(Random() % 2);
839                         if (type != staff)
840                             whichsound = clank1sound + abs(Random() % 4);
841                     } else {
842                         whichsound = footstepsound + abs(Random() % 2);
843                     }
844                     emit_sound_at(whichsound, mid,
845                                   findLengthfast(&bounceness) * (terrain.getOpacity(position.x, position.z) > .2
846                                                                      ? 128.
847                                                                      : 32.));
848                 }
849                 tippoint += (mid - oldmid) * 20;
850             }
851             //Gravity
852             velocity.y += gravity * multiplier;
853             tipvelocity.y += gravity * multiplier;
854
855             //Rotation
856             XYZ temppoint1, temppoint2;
857             float distance;
858
859             temppoint1 = position;
860             temppoint2 = tippoint;
861             distance = findDistance(&temppoint1, &temppoint2);
862             rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
863             rotation2 *= 360 / 6.28;
864             temppoint1.y = 0;
865             temppoint2.y = 0;
866             rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
867             rotation1 *= 360 / 6.28;
868             rotation3 = 0;
869             smallrotation = 90;
870             smallrotation2 = 0;
871             bigtilt = 0;
872             bigtilt2 = 0;
873             bigrotation = 0;
874             if (temppoint1.x > temppoint2.x)
875                 rotation1 = 360 - rotation1;
876
877             //Stop moving
878             if (findLengthfast(&velocity) < .3 && findLengthfast(&tipvelocity) < .3 && hitsomething) {
879                 freetime += multiplier;
880             }
881
882             if (freetime > .4) {
883                 velocity = 0;
884                 tipvelocity = 0;
885             }
886             firstfree = 0;
887         }
888     }
889     multiplier = tempmult;
890     if (blooddrip && bloody) {
891         blooddripdelay -= blooddrip * multiplier / 2;
892         blooddrip -= multiplier;
893         if (blooddrip < 0)
894             blooddrip = 0;
895         if (blooddrip > 5)
896             blooddrip = 5;
897         if (blooddripdelay < 0 && bloodtoggle) {
898             blooddripdelay = 1;
899             XYZ bloodvel;
900             XYZ bloodloc;
901             bloodloc = position + (tippoint - position) * .7;
902             bloodloc.y -= .05;
903             if (bloodtoggle) {
904                 bloodvel = 0;
905                 Sprite::MakeSprite(bloodsprite, bloodloc, bloodvel, 1, 1, 1, .03, 1);
906             }
907         }
908     }
909     if (onfire) {
910         flamedelay -= multiplier;
911         if (onfire && flamedelay <= 0) {
912             flamedelay = .020;
913             flamedelay -= multiplier;
914             normalrot = 0;
915             if (owner != -1) {
916                 normalrot = Person::players[owner]->velocity;
917             }
918             normalrot.y += 1;
919             if (owner != -1) {
920                 if (Person::players[owner]->onterrain) {
921                     normalrot.y = 1;
922                 }
923             }
924             Sprite::MakeSprite(weaponflamesprite, position + tippoint * (((float)abs(Random() % 100)) / 600 + .05), normalrot, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3, 1);
925             Sprite::setLastSpriteSpeed(4);
926             Sprite::setLastSpriteAlivetime(.3);
927         }
928     }
929
930     if (!onfire && owner == -1 && type != staff) {
931         flamedelay -= multiplier;
932         if (flamedelay <= 0) {
933             flamedelay = .020;
934             flamedelay -= multiplier;
935             normalrot = 0;
936             if (Random() % 50 == 0 && distsq(&position, &viewer) > 80) {
937                 XYZ shinepoint;
938                 shinepoint = position + (tippoint - position) * (((float)abs(Random() % 100)) / 100);
939                 Sprite::MakeSprite(weaponshinesprite, shinepoint, normalrot, 1, 1, 1, (.1 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3 * fast_sqrt(findDistance(&shinepoint, &viewer)), 1);
940                 Sprite::setLastSpriteSpeed(4);
941                 Sprite::setLastSpriteAlivetime(.3);
942             }
943         }
944     }
945 }
946
947 void Weapons::DoStuff()
948 {
949     //Move
950     int i = 0;
951     for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
952         weapon->doStuff(i++);
953     }
954 }
955
956 void Weapon::draw()
957 {
958     static XYZ terrainlight;
959     static GLfloat M[16];
960
961     if ((frustum.SphereInFrustum(position.x, position.y, position.z, 1) &&
962          distsq(&viewer, &position) < viewdistance * viewdistance)) {
963         bool draw = false;
964         if (owner == -1) {
965             draw = true;
966             if (velocity.x && !physics)
967                 drawhowmany = 10;
968             else
969                 drawhowmany = 1;
970         } else {
971             if (Person::players[owner]->occluded < 25)
972                 if ((frustum.SphereInFrustum(Person::players[owner]->coords.x, Person::players[owner]->coords.y + Person::players[owner]->scale * 3, Person::players[owner]->coords.z, Person::players[owner]->scale * 8) && distsq(&viewer, &Person::players[owner]->coords) < viewdistance * viewdistance) || Person::players[owner]->skeleton.free == 3)
973                     draw = true;
974             if (
975                 (Person::players[owner]->animTarget == knifeslashstartanim ||
976                  Person::players[owner]->animTarget == swordsneakattackanim ||
977                  (Person::players[owner]->animCurrent == staffhitanim && Person::players[owner]->frameCurrent > 1) ||
978                  (Person::players[owner]->animCurrent == staffhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
979                  (Person::players[owner]->animCurrent == staffspinhitanim && Person::players[owner]->frameCurrent > 1) ||
980                  (Person::players[owner]->animCurrent == staffspinhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
981                  (Person::players[owner]->animCurrent == staffgroundsmashanim && Person::players[owner]->frameCurrent > 1) ||
982                  (Person::players[owner]->animTarget == swordslashanim && Person::players[owner]->frameTarget < 7) ||
983                  Person::players[owner]->animTarget == crouchstabanim ||
984                  Person::players[owner]->animTarget == swordslashreversalanim ||
985                  Person::players[owner]->animTarget == swordslashreversedanim ||
986                  Person::players[owner]->animTarget == knifefollowanim ||
987                  Person::players[owner]->animTarget == swordgroundstabanim ||
988                  Person::players[owner]->animTarget == knifethrowanim) &&
989                 Person::players[owner]->animTarget == lastdrawnanim &&
990                 !Person::players[owner]->skeleton.free) {
991                 drawhowmany = 10;
992             } else {
993                 drawhowmany = 1;
994             }
995             if (Person::players[owner]->animTarget == swordgroundstabanim) {
996                 lastdrawnrotation1 = rotation1;
997                 lastdrawnrotation2 = rotation2;
998                 lastdrawnrotation3 = rotation3;
999                 lastdrawnbigrotation = bigrotation;
1000                 lastdrawnbigtilt = bigtilt;
1001                 lastdrawnbigtilt2 = bigtilt2;
1002                 lastdrawnsmallrotation = smallrotation;
1003                 lastdrawnsmallrotation2 = smallrotation2;
1004             }
1005         }
1006         if (draw) {
1007             terrainlight = terrain.getLighting(position.x, position.z);
1008             if (drawhowmany > 0) {
1009                 glAlphaFunc(GL_GREATER, 0.01);
1010             }
1011             for (int j = drawhowmany; j > 0; j--) {
1012                 glMatrixMode(GL_MODELVIEW);
1013                 glPushMatrix();
1014                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, j / drawhowmany);
1015                 if (owner == -1)
1016                     glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
1017                 else
1018                     glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) - .02 + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
1019                 glRotatef(bigrotation * (((float)(j)) / drawhowmany) + lastdrawnbigrotation * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
1020                 glRotatef(bigtilt2 * (((float)(j)) / drawhowmany) + lastdrawnbigtilt2 * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
1021                 glRotatef(bigtilt * (((float)(j)) / drawhowmany) + lastdrawnbigtilt * (1 - ((float)(j)) / drawhowmany), 0, 0, 1);
1022                 glRotatef(-rotation1 * (((float)(j)) / drawhowmany) - lastdrawnrotation1 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 1, 0);
1023                 glRotatef(-rotation2 * (((float)(j)) / drawhowmany) - lastdrawnrotation2 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 0, 1);
1024                 glRotatef(-rotation3 * (((float)(j)) / drawhowmany) - lastdrawnrotation3 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
1025                 glRotatef(smallrotation * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
1026                 glRotatef(smallrotation2 * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation2 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
1027
1028                 if (owner != -1) {
1029                     if (Person::players[owner]->animTarget == staffhitanim || Person::players[owner]->animCurrent == staffhitanim || Person::players[owner]->animTarget == staffhitreversedanim || Person::players[owner]->animCurrent == staffhitreversedanim) {
1030                         glTranslatef(0, 0, -.3);
1031                     }
1032                     if (Person::players[owner]->animTarget == staffgroundsmashanim || Person::players[owner]->animCurrent == staffgroundsmashanim || Person::players[owner]->animTarget == staffspinhitreversedanim || Person::players[owner]->animCurrent == staffspinhitreversedanim || Person::players[owner]->animTarget == staffspinhitanim || Person::players[owner]->animCurrent == staffspinhitanim) {
1033                         glTranslatef(0, 0, -.1);
1034                     }
1035                 }
1036
1037                 glEnable(GL_LIGHTING);
1038                 switch (type) {
1039                     case knife:
1040                         if (!bloody || !bloodtoggle)
1041                             throwingknifemodel.drawdifftex(knifetextureptr);
1042                         if (bloodtoggle) {
1043                             if (bloody == 1)
1044                                 throwingknifemodel.drawdifftex(lightbloodknifetextureptr);
1045                             if (bloody == 2)
1046                                 throwingknifemodel.drawdifftex(bloodknifetextureptr);
1047                         }
1048                         break;
1049                     case sword:
1050                         if (!bloody || !bloodtoggle)
1051                             swordmodel.drawdifftex(swordtextureptr);
1052                         if (bloodtoggle) {
1053                             if (bloody == 1)
1054                                 swordmodel.drawdifftex(lightbloodswordtextureptr);
1055                             if (bloody == 2)
1056                                 swordmodel.drawdifftex(bloodswordtextureptr);
1057                         }
1058                         break;
1059                     case staff:
1060                         staffmodel.drawdifftex(stafftextureptr);
1061                         break;
1062                 }
1063
1064                 glPopMatrix();
1065             }
1066
1067             lastdrawnposition = position;
1068             lastdrawntippoint = tippoint;
1069             lastdrawnrotation1 = rotation1;
1070             lastdrawnrotation2 = rotation2;
1071             lastdrawnrotation3 = rotation3;
1072             lastdrawnbigrotation = bigrotation;
1073             lastdrawnbigtilt = bigtilt;
1074             lastdrawnbigtilt2 = bigtilt2;
1075             lastdrawnsmallrotation = smallrotation;
1076             lastdrawnsmallrotation2 = smallrotation2;
1077             if (owner != -1)
1078                 lastdrawnanim = Person::players[owner]->animCurrent;
1079         }
1080         if (owner != -1) {
1081             glMatrixMode(GL_MODELVIEW);
1082             glPushMatrix();
1083             glLoadIdentity();
1084             glTranslatef(position.x, position.y - .02, position.z);
1085             glRotatef(bigrotation, 0, 1, 0);
1086             glRotatef(bigtilt2, 1, 0, 0);
1087             glRotatef(bigtilt, 0, 0, 1);
1088             glRotatef(-rotation1 + 90, 0, 1, 0);
1089             glRotatef(-rotation2 + 90, 0, 0, 1);
1090             glRotatef(-rotation3, 0, 1, 0);
1091             glRotatef(smallrotation, 1, 0, 0);
1092             glRotatef(smallrotation2, 0, 1, 0);
1093             glTranslatef(0, 0, length);
1094             glGetFloatv(GL_MODELVIEW_MATRIX, M);
1095             tippoint.x = M[12];
1096             tippoint.y = M[13];
1097             tippoint.z = M[14];
1098             glPopMatrix();
1099         }
1100     }
1101 }
1102
1103 void Weapon::drop(XYZ v, XYZ tv, bool sethitsomething)
1104 {
1105     owner = -1;
1106     velocity = v;
1107     tipvelocity = tv;
1108     missed = 1;
1109     if (sethitsomething) {
1110         hitsomething = 0;
1111     }
1112     freetime = 0;
1113     firstfree = 1;
1114     physics = 1;
1115 }
1116
1117 void Weapon::thrown(XYZ v, bool sethitsomething)
1118 {
1119     drop(v, v, sethitsomething);
1120     missed = 0;
1121     physics = 0;
1122 }
1123
1124 int Weapons::Draw()
1125 {
1126     glAlphaFunc(GL_GREATER, 0.9);
1127     glEnable(GL_TEXTURE_2D);
1128     glEnable(GL_BLEND);
1129     glEnable(GL_CULL_FACE);
1130     glCullFace(GL_FRONT);
1131     glDepthMask(1);
1132
1133     for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
1134         weapon->draw();
1135     }
1136     return 0;
1137 }
1138
1139 Weapons::Weapons()
1140 {
1141 }