/* =========================================================================== ARX FATALIS GPL Source Code Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company. This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code'). Arx Fatalis Source Code 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 3 of the License, or (at your option) any later version. Arx Fatalis Source Code 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 Arx Fatalis Source Code. If not, see . In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ ////////////////////////////////////////////////////////////////////////////////////// // @@ @@@ @@@ @@ @@@@@ // // @@@ @@@@@@ @@@ @@ @@@@ @@@ @@@ // // @@@ @@@@@@@ @@@ @@@@ @@@@ @@ @@@@ // // @@@ @@ @@@@ @@@ @@@@@ @@@@@@ @@@ @@@ // // @@@@@ @@ @@@@ @@@ @@@@@ @@@@@@@ @@@ @ @@@ // // @@@@@ @@ @@@@ @@@@@@@@ @@@@ @@@ @@@@@ @@ @@@@@@@ // // @@ @@@ @@ @@@@ @@@@@@@ @@@ @@@ @@@@@@ @@ @@@@ // // @@@ @@@ @@@ @@@@ @@@@@ @@@@@@@@@ @@@@@@@ @@@ @@@@ // // @@@ @@@@ @@@@@@@ @@@@@@ @@@ @@@@ @@@ @@@ @@@ @@@@ // // @@@@@@@@ @@@@@ @@@@@@@@@@ @@@ @@@ @@@ @@@ @@@ @@@@@ // // @@@ @@@@ @@@@ @@@ @@@@@@@ @@@ @@@ @@@@ @@@ @@@@ @@@@@ // //@@@ @@@@ @@@@@ @@@ @@@@@@ @@ @@@ @@@@ @@@@@@@ @@@@@ @@@@@ // //@@@ @@@@@ @@@@@ @@@@ @@@ @@ @@ @@@@ @@@@@@@ @@@@@@@@@ // //@@@ @@@@ @@@@@@@ @@@@ @@ @@ @@@@ @@@@@ @@@@@ // //@@@ @@@@ @@@@@@@ @@@@ @@ @@ @@@@ @@@@@ @@ // //@@@ @@@ @@@ @@@@@ @@ @@@ // // @@@ @@@ @@ @@ STUDIOS // ////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// // ARX_Paths ////////////////////////////////////////////////////////////////////////////////////// // // Description: // ARX Paths Management // // Updates: (date) (person) (update) // // Code: Cyril Meynier // // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved ////////////////////////////////////////////////////////////////////////////////////// #include "ARX_Paths.h" #include "HERMESMain.h" #include "EERIELight.h" #include "ARX_GlobalMods.h" #include "ARX_SOUND.h" #include "ARX_Collisions.h" #include "ARX_Time.h" #include "ARX_Npc.h" #include "ARX_CSpellFx.h" #include "arx_interactive.h" #include "arx_player.h" #include "arx_script.h" #include "arx_particles.h" #include "arx_damages.h" #include "arx_equipment.h" #include "danaedlg.h" #include "EERIEDRAW.h" #include "EERIEPhysicsBox.h" #include #define _CRTDBG_MAP_ALLOC #include extern long CHANGE_LEVEL_ICON; extern long EDITMODE; extern float FrameDiff; bool IsPointInField(EERIE_3D * pos); ARX_PATH ** ARXpaths = NULL; ARX_USE_PATH USE_CINEMATICS_PATH; MASTER_CAMERA_STRUCT MasterCamera; long ARX_PATHS_HIERARCHYMOVE = 0; long nbARXpaths = 0; long USE_CINEMATICS_CAMERA = 0; //************************************************************************************* //************************************************************************************* ARX_PATH * ARX_PATHS_AddNew(EERIE_3D * pos) { char str[64]; char tex[64]; if (ARXpaths == NULL) { ARXpaths = (ARX_PATH **)malloc(sizeof(ARX_PATH *)); nbARXpaths = 1; ARXpaths[0] = ARX_PATHS_Create("NewPath0001", pos); ARX_PATHS_AddPathWay(ARXpaths[0], 0); return ARXpaths[0]; } ARXpaths = (ARX_PATH **)realloc(ARXpaths, sizeof(ARX_PATH *) * (nbARXpaths + 1)); strcpy(tex, "NewPath"); long num = 1; sprintf(str, "%s%04d", tex, num); num++; while (ARX_PATHS_ExistName(str)) { sprintf(str, "%s%04d", tex, num); num++; } ARXpaths[nbARXpaths] = ARX_PATHS_Create(str, pos); ARX_PATHS_AddPathWay(ARXpaths[nbARXpaths], 0); nbARXpaths++; return ARXpaths[nbARXpaths-1]; } //************************************************************************************* //************************************************************************************* void ARX_PATHS_RedrawAll(LPDIRECT3DDEVICE7 pd3dDevice) { ARX_PATHS_FlyingOverAP = NULL; ARX_PATHS_FlyingOverNum = -1; for (long i = 0; i < nbARXpaths; i++) ARX_PATHS_DrawPath(ARXpaths[i], pd3dDevice); } void ARX_PATH_ComputeBB(ARX_PATH * ap) { ap->bbmin.x = ap->bbmin.y = ap->bbmin.z = 9999999999.f; ap->bbmax.x = ap->bbmax.y = ap->bbmax.z = -9999999999.f; for (long i = 0; i < ap->nb_pathways; i++) { ap->bbmin.x = __min(ap->bbmin.x, ap->pos.x + ap->pathways[i].rpos.x); ap->bbmax.x = __max(ap->bbmax.x, ap->pos.x + ap->pathways[i].rpos.x); ap->bbmin.z = __min(ap->bbmin.z, ap->pos.z + ap->pathways[i].rpos.z); ap->bbmax.z = __max(ap->bbmax.z, ap->pos.z + ap->pathways[i].rpos.z); } if (ap->height > 0) { ap->bbmin.y = ap->pos.y - ap->height; ap->bbmax.y = ap->pos.y; } else { ap->bbmin.y = -99999999.f; ap->bbmax.y = 99999999.f; } } void ARX_PATH_ComputeAllBoundingBoxes() { for (long i = 0; i < nbARXpaths; i++) { if (ARXpaths[i]) { ARX_PATH_ComputeBB(ARXpaths[i]); } } } long ARX_PATH_IsPosInZone(ARX_PATH * ap, float x, float y, float z) { if (x < ap->bbmin.x) return 0; if (x > ap->bbmax.x) return 0; if (z < ap->bbmin.z) return 0; if (z > ap->bbmax.z) return 0; if (y < ap->bbmin.y) return 0; if (y > ap->bbmax.y) return 0; register int i, j, c = 0; x -= ap->pos.x; y -= ap->pos.y; z -= ap->pos.z; ARX_PATHWAY * app = ap->pathways; for (i = 0, j = ap->nb_pathways - 1; i < ap->nb_pathways; j = i++) { EERIE_3D * pi = &app[i].rpos; EERIE_3D * pj = &app[j].rpos; if ((((pi->z <= z) && (z < pj->z)) || ((pj->z <= z) && (z < pi->z))) && (x < (pj->x - pi->x) *(z - pi->z) / (pj->z - pi->z) + pi->x)) c = !c; } return c; } ARX_PATH * ARX_PATH_CheckInZone(INTERACTIVE_OBJ * io) { if (ARXpaths) { EERIE_3D curpos; GetItemWorldPosition(io, &curpos); for (long i = 0; i < nbARXpaths; i++) { if ((ARXpaths[i]) && (ARXpaths[i]->height != 0)) { if (ARX_PATH_IsPosInZone(ARXpaths[i], curpos.x, curpos.y, curpos.z)) return ARXpaths[i]; } } } return NULL; } ARX_PATH * ARX_PATH_CheckPlayerInZone() { if (ARXpaths) for (long i = 0; i < nbARXpaths; i++) { if ((ARXpaths[i]) && (ARXpaths[i]->height != 0)) { if (ARX_PATH_IsPosInZone(ARXpaths[i], player.pos.x, player.pos.y + 160.f, player.pos.z)) return ARXpaths[i]; } } return NULL; } long JUST_RELOADED = 0; void ARX_PATH_UpdateAllZoneInOutInside() { if (EDITMODE) return; static long count = 1; char temp[64]; long f = ARX_CLEAN_WARN_CAST_LONG(FrameDiff); if (f < 10) f = 10; if (f > 50) f = 50; if (count >= inter.nbmax) count = 1; if (inter.nbmax > 1) for (long tt = 0; tt < f; tt++) { long i = count; INTERACTIVE_OBJ * io = inter.iobj[i]; if ((count < inter.nbmax) && (io) && (io->ioflags & (IO_NPC | IO_ITEM)) && (io->show != SHOW_FLAG_MEGAHIDE) && (io->show != SHOW_FLAG_DESTROYED) ) { ARX_PATH * p = ARX_PATH_CheckInZone(io); ARX_PATH * op = (ARX_PATH *)io->inzone; if ((op == NULL) && (p == NULL)) goto next; // Not in a zone if (op == p) // Stayed inside Zone OP { if (io->show != io->inzone_show) { io->inzone_show = io->show; goto entering; } } else if ((op != NULL) && (p == NULL)) // Leaving Zone OP { strcpy(temp, op->name); MakeUpcase(temp); SendIOScriptEvent(io, SM_LEAVEZONE, temp, NULL); if (op->controled[0] != 0) { long t = GetTargetByNameTarget(op->controled); if (t >= 0) { char texx[128]; char tex2[128]; strcpy(texx, GetName(io->filename)); sprintf(tex2, "%s_%04d %s", texx, io->ident, temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_LEAVE, tex2, NULL); } } } else if ((op == NULL) && (p != NULL)) // Entering Zone P { io->inzone_show = io->show; entering: ; strcpy(temp, p->name); MakeUpcase(temp); if ((JUST_RELOADED) && ((!stricmp(p->name, "INGOT_MAKER")) || (!stricmp(p->name, "MAULD_USER")))) { ARX_DEAD_CODE(); } else { SendIOScriptEvent(io, SM_ENTERZONE, temp, NULL); if (p->controled[0] != 0) { long t = GetTargetByNameTarget(p->controled); if (t >= 0) { char texx[128]; char tex2[128]; strcpy(texx, GetName(io->filename)); sprintf(tex2, "%s_%04d %s", texx, io->ident, temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_ENTER, tex2, NULL); } } } } else { strcpy(temp, op->name); MakeUpcase(temp); SendIOScriptEvent(io, SM_LEAVEZONE, temp, NULL); if (op->controled[0] != 0) { long t = GetTargetByNameTarget(op->controled); if (t >= 0) { char texx[128]; char tex2[128]; strcpy(texx, GetName(io->filename)); sprintf(tex2, "%s_%04d %s", texx, io->ident, temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_LEAVE, tex2, NULL); } } io->inzone_show = io->show; strcpy(temp, p->name); MakeUpcase(temp); SendIOScriptEvent(io, SM_ENTERZONE, temp, NULL); if (p->controled[0] != 0) { long t = GetTargetByNameTarget(p->controled); if (t >= 0) { char texx[128]; char tex2[128]; strcpy(texx, GetName(io->filename)); sprintf(tex2, "%s_%04d %s", texx, io->ident, temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_ENTER, tex2, NULL); } } } io->inzone = (void *)p; } next: ; count++; if (count >= inter.nbmax) count = 1; } //player check************************************************* if (inter.iobj[0]) { ARX_PATH * p = ARX_PATH_CheckPlayerInZone(); ARX_PATH * op = (ARX_PATH *)player.inzone; if ((op == NULL) && (p == NULL)) goto suite; // Not in a zone if (op == p) // Stayed inside Zone OP { } else if ((op != NULL) && (p == NULL)) // Leaving Zone OP { strcpy(temp, op->name); MakeUpcase(temp); SendIOScriptEvent(inter.iobj[0], SM_LEAVEZONE, temp, NULL); CHANGE_LEVEL_ICON = -1; if (op->controled[0] != 0) { long t = GetTargetByNameTarget(op->controled); if (t >= 0) { char tex2[128]; sprintf(tex2, "PLAYER %s", temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_LEAVE, tex2, NULL); } } } else if ((op == NULL) && (p != NULL)) // Entering Zone P { strcpy(temp, p->name); MakeUpcase(temp); SendIOScriptEvent(inter.iobj[0], SM_ENTERZONE, temp, NULL); if (p->flags & PATH_AMBIANCE && p->ambiance[0]) ARX_SOUND_PlayZoneAmbiance(p->ambiance, ARX_SOUND_PLAY_LOOPED, p->amb_max_vol * DIV100); if (p->flags & PATH_FARCLIP) { desired.flags |= GMOD_ZCLIP; desired.zclip = p->farclip; } if (p->flags & PATH_REVERB) { } if (p->flags & PATH_RGB) { desired.flags |= GMOD_DCOLOR; desired.depthcolor.r = p->rgb.r; desired.depthcolor.g = p->rgb.g; desired.depthcolor.b = p->rgb.b; } if (p->controled[0] != 0) { long t = GetTargetByNameTarget(p->controled); if (t >= 0) { char tex2[128]; sprintf(tex2, "PLAYER %s", temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_ENTER, tex2, NULL); } } } else { strcpy(temp, op->name); MakeUpcase(temp); if (op->controled[0] != 0) { long t = GetTargetByNameTarget(op->controled); if (t >= 0) { char tex2[128]; sprintf(tex2, "PLAYER %s", temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_LEAVE, tex2, NULL); } } strcpy(temp, p->name); MakeUpcase(temp); if (p->controled[0] != 0) { long t = GetTargetByNameTarget(p->controled); if (t >= 0) { char tex2[128]; sprintf(tex2, "PLAYER %s", temp); SendIOScriptEvent(inter.iobj[t], SM_CONTROLLEDZONE_ENTER, tex2, NULL); } } } player.inzone = (void *)p; } suite: ; JUST_RELOADED = 0; } //************************************************************************************* //************************************************************************************* ARX_PATH * ARX_PATHS_Create(char * name, EERIE_3D * pos) { ARX_PATH * ap = (ARX_PATH *)malloc(sizeof(ARX_PATH)); if (ap == NULL) return NULL; memset(ap, 0, sizeof(ARX_PATH)); SAFEstrcpy(ap->name, name, 64); ap->initpos.x = ap->pos.x = pos->x; ap->initpos.y = ap->pos.y = pos->y; ap->initpos.z = ap->pos.z = pos->z; InterTreeViewItemAdd(NULL, name, IOTVTYPE_PATH); return ap; } //************************************************************************************* //************************************************************************************* void ARX_PATH_ClearAllUsePath() { for (long i = 0; i < inter.nbmax; i++) { if (inter.iobj[i] != NULL) if (inter.iobj[i]->usepath != NULL) { free(inter.iobj[i]->usepath); inter.iobj[i]->usepath = NULL; } } } //************************************************************************************* //************************************************************************************* void ARX_PATH_ClearAllControled() { for (long i = 0; i < nbARXpaths; i++) { if (ARXpaths[i]) { ARXpaths[i]->controled[0] = 0; } } } //************************************************************************************* //************************************************************************************* void ARX_PATHS_ChangeName(ARX_PATH * ap, char * newname) { if (ap == NULL) return; InterTreeViewItemRemove(NULL, ap->name, IOTVTYPE_PATH); strcpy(ap->name, newname); InterTreeViewItemAdd(NULL, ap->name, IOTVTYPE_PATH); } //************************************************************************************* //************************************************************************************* ARX_PATH * ARX_PATH_GetAddressByName(char * name) { if ((name) && (name[0]) && (ARXpaths)) for (long i = 0; i < nbARXpaths; i++) { if (ARXpaths[i]) { if (!stricmp(ARXpaths[i]->name, name)) return ARXpaths[i]; } } return NULL; } //************************************************************************************* //************************************************************************************* void ARX_PATH_ReleaseAllPath() { ARX_PATH_ClearAllUsePath(); for (long i = 0; i < nbARXpaths; i++) { if (ARXpaths[i]) { InterTreeViewItemRemove(NULL, ARXpaths[i]->name, IOTVTYPE_PATH); if (ARXpaths[i]->pathways) free(ARXpaths[i]->pathways); ARXpaths[i]->pathways = NULL; free(ARXpaths[i]); ARXpaths[i] = NULL; } } if (ARXpaths) free(ARXpaths); ARXpaths = NULL; nbARXpaths = 0; } //************************************************************************************* //************************************************************************************* ARX_PATH * ARX_PATHS_ExistName(char * name) { if (ARXpaths == NULL) return FALSE; for (long i = 0; i < nbARXpaths; i++) { if (!stricmp(ARXpaths[i]->name, name)) return ARXpaths[i]; } return NULL; } //************************************************************************************* //************************************************************************************* void ARX_PATHS_Delete(ARX_PATH * ap) { ARX_PATH_ClearAllUsePath(); if (ap == NULL) return; InterTreeViewItemRemove(NULL, ap->name, IOTVTYPE_PATH); for (long i = 0; i < nbARXpaths; i++) { if (ap == ARXpaths[i]) { while (i < nbARXpaths) { i++; ARXpaths[i-1] = ARXpaths[i]; } nbARXpaths--; if (nbARXpaths == 0) { free(ARXpaths); ARXpaths = NULL; } else ARXpaths = (ARX_PATH **)realloc(ARXpaths, sizeof(ARX_PATH *) * (nbARXpaths)); break; } } if (ap == ARX_PATHS_SelectedAP) { ARX_PATHS_SelectedAP = NULL; ARX_PATHS_SelectedNum = -1; } free(ap); ap = NULL; } //************************************************************************************* //************************************************************************************* long ARX_PATHS_AddPathWay(ARX_PATH * ap, long insert) { if (ap == NULL) return(NULL); if (insert < 0) insert = 0; else if (insert > ap->nb_pathways) insert = ap->nb_pathways; if (ap->pathways == NULL) { ap->pathways = (ARX_PATHWAY *)malloc(sizeof(ARX_PATHWAY)); memset(ap->pathways, 0, sizeof(ARX_PATHWAY)); ap->nb_pathways = 1; return 1; } ap->pathways = (ARX_PATHWAY *)realloc(ap->pathways, sizeof(ARX_PATHWAY) * (ap->nb_pathways + 1)); memset(&ap->pathways[ap->nb_pathways], 0, sizeof(ARX_PATHWAY)); ap->nb_pathways++; if (insert == ap->nb_pathways - 1) return ap->nb_pathways; for (long i = ap->nb_pathways - 1; i > insert; i--) { memcpy(&ap->pathways[i], &ap->pathways[i-1], sizeof(ARX_PATHWAY)); } memset(&ap->pathways[insert], 0, sizeof(ARX_PATHWAY)); return insert + 1; } //************************************************************************************* //************************************************************************************* long ARX_PATHS_Interpolate(ARX_USE_PATH * aup, EERIE_3D * pos) { ARX_PATH * ap = aup->path; //compute Delta Time float tim = aup->_curtime - aup->_starttime; if (tim < 0) return -1; //set pos to startpos pos->x = 0.f; pos->y = 0.f; pos->z = 0.f; if (tim == 0) return 0; //we start at reference waypoint 0 (time & rpos = 0 for this waypoint). long targetwaypoint = 1; aup->aupflags &= ~ARX_USEPATH_FLAG_FINISHED; if (ap->pathways) { ap->pathways[0]._time = 0; ap->pathways[0].rpos.x = 0; ap->pathways[0].rpos.y = 0; ap->pathways[0].rpos.z = 0; } else return -1; // While we have time left, iterate while (tim > 0) { // Path Ended if (targetwaypoint > ap->nb_pathways - 1) { pos->x += ap->pos.x; pos->y += ap->pos.y; pos->z += ap->pos.z; aup->aupflags |= ARX_USEPATH_FLAG_FINISHED; return -2; } // Manages a Bezier block if (ap->pathways[targetwaypoint-1].flag & PATHWAY_BEZIER) { targetwaypoint += 1; float delta = tim - ap->pathways[targetwaypoint]._time; if (delta >= 0) { tim = delta; if (targetwaypoint < ap->nb_pathways) { pos->x = ap->pathways[targetwaypoint].rpos.x; pos->y = ap->pathways[targetwaypoint].rpos.y; pos->z = ap->pathways[targetwaypoint].rpos.z; } targetwaypoint += 1; } else { float rel; if (targetwaypoint < ap->nb_pathways) { if (ap->pathways[targetwaypoint]._time == 0) return targetwaypoint - 1; else rel = (float)((float)(tim)) / ((float)(ap->pathways[targetwaypoint]._time)); float mul = rel; float mull = mul * mul; pos->x = mul * (ap->pathways[targetwaypoint-1].rpos.x - ap->pathways[targetwaypoint-2].rpos.x) + (ap->pathways[targetwaypoint].rpos.x - ap->pathways[targetwaypoint-1].rpos.x) * mull; pos->y = mul * (ap->pathways[targetwaypoint-1].rpos.y - ap->pathways[targetwaypoint-2].rpos.y) + (ap->pathways[targetwaypoint].rpos.y - ap->pathways[targetwaypoint-1].rpos.y) * mull; pos->z = mul * (ap->pathways[targetwaypoint-1].rpos.z - ap->pathways[targetwaypoint-2].rpos.z) + (ap->pathways[targetwaypoint].rpos.z - ap->pathways[targetwaypoint-1].rpos.z) * mull; pos->x += ap->pos.x + ap->pathways[targetwaypoint-2].rpos.x; pos->y += ap->pos.y + ap->pathways[targetwaypoint-2].rpos.y; pos->z += ap->pos.z + ap->pathways[targetwaypoint-2].rpos.z; } tim = 0; return targetwaypoint - 1; } } else { // Manages a non-Bezier block float delta = tim - ap->pathways[targetwaypoint]._time; if (delta >= 0) { tim = delta; if (targetwaypoint < ap->nb_pathways) { pos->x = ap->pathways[targetwaypoint].rpos.x; pos->y = ap->pathways[targetwaypoint].rpos.y; pos->z = ap->pathways[targetwaypoint].rpos.z; } targetwaypoint++; } else { float rel; if (targetwaypoint < ap->nb_pathways) { if (ap->pathways[targetwaypoint]._time == 0) return targetwaypoint - 1; else rel = (float)((float)(tim)) / ((float)(ap->pathways[targetwaypoint]._time)); pos->x += (ap->pathways[targetwaypoint].rpos.x - pos->x) * rel; pos->y += (ap->pathways[targetwaypoint].rpos.y - pos->y) * rel; pos->z += (ap->pathways[targetwaypoint].rpos.z - pos->z) * rel; } tim = 0; pos->x += ap->pos.x; pos->y += ap->pos.y; pos->z += ap->pos.z; return targetwaypoint - 1; } } } pos->x += ap->pos.x; pos->y += ap->pos.y; pos->z += ap->pos.z; return targetwaypoint; } //************************************************************************************* //************************************************************************************* void ARX_PATHS_ModifyPathWay(ARX_PATH * ap, long num, long mods, EERIE_3D * pos, long flags, unsigned long duration) { if (ap == NULL) return; if (num < 1) return; if (num > ap->nb_pathways) return; long to; if (mods & ARX_PATH_HIERARCHY) to = ap->nb_pathways - 1; else to = num - 1; for (long j = num - 1; j <= to; j++) { if (mods & ARX_PATH_MOD_FLAGS) { ap->pathways[j].flag = flags; } if (mods & ARX_PATH_MOD_POSITION) { if (j == 0) { for (long n = 1; n < ap->nb_pathways - 1; n++) { ap->pathways[n].rpos.x += ap->initpos.x - pos->x;; ap->pathways[n].rpos.y += ap->initpos.y - pos->y;; ap->pathways[n].rpos.z += ap->initpos.z - pos->z;; } ap->pos.x = ap->initpos.x = pos->x; ap->pos.y = ap->initpos.y = pos->y; ap->pos.z = ap->initpos.z = pos->z; ap->pathways[j].rpos.x = 0.f; ap->pathways[j].rpos.y = 0.f; ap->pathways[j].rpos.z = 0.f; } else { ap->pathways[j].rpos.x = pos->x; ap->pathways[j].rpos.y = pos->y; ap->pathways[j].rpos.z = pos->z; } } if (mods & ARX_PATH_MOD_TRANSLATE) { if (j == 0) { ap->initpos.x += pos->x; ap->initpos.y += pos->y; ap->initpos.z += pos->z; ap->pos.x = ap->initpos.x; ap->pos.y = ap->initpos.y; ap->pos.z = ap->initpos.z; for (long n = 1; n <= ap->nb_pathways - 1; n++) { ap->pathways[n].rpos.x -= pos->x; ap->pathways[n].rpos.y -= pos->y; ap->pathways[n].rpos.z -= pos->z; } } else { ap->pathways[j].rpos.x += pos->x; ap->pathways[j].rpos.y += pos->y; ap->pathways[j].rpos.z += pos->z; } } if (mods & ARX_PATH_MOD_TIME) ap->pathways[j]._time = ARX_CLEAN_WARN_CAST_FLOAT(duration); } ARX_PATH_ComputeBB(ap); } //************************************************************************************* //************************************************************************************* void ARX_PATHS_DeletePathWay(ARX_PATH * ap, long del) { if (ap == NULL) return; if (ap->pathways == NULL) return; if (del < 1) return; if (del > ap->nb_pathways) return; for (long i = del - 1; i < ap->nb_pathways - 2; i++) { memcpy(&ap->pathways[i], &ap->pathways[i+1], sizeof(ARX_PATHWAY)); } if ((ARX_PATHS_SelectedNum == del) && (ap == ARX_PATHS_SelectedAP)) { ARX_PATHS_SelectedNum--; if ((ARX_PATHS_SelectedNum == 0) && (ARX_PATHS_SelectedAP->nb_pathways == 0)) ARX_PATHS_SelectedAP = NULL; else ARX_PATHS_SelectedNum = ARX_PATHS_SelectedAP->nb_pathways - 1; } if (ap->nb_pathways == 1) { free(ap->pathways); ap->nb_pathways = 0; ARX_PATHS_Delete(ap); return; } ap->pathways = (ARX_PATHWAY *)realloc(ap->pathways, sizeof(ARX_PATHWAY) * (ap->nb_pathways - 1)); ap->nb_pathways--; } //************************************************************************************* //************************************************************************************* void ARX_PATHS_DrawPathWay(LPDIRECT3DDEVICE7 pd3dDevice, EERIE_3D * pos, float siz, D3DCOLOR color, long height) { D3DTLVERTEX vert; vert.sx = pos->x; vert.sy = pos->y; vert.sz = pos->z; if (height == 0) EERIEDrawSprite(pd3dDevice, &vert, siz, EERIE_DRAW_sphere_particle, color, 2.f); else EERIEDrawSprite(pd3dDevice, &vert, siz, EERIE_DRAW_square_particle, color, 2.f); } ARX_PATH * ARX_PATHS_FlyingOverAP = NULL; long ARX_PATHS_FlyingOverNum = -1; ARX_PATH * ARX_PATHS_SelectedAP = NULL; long ARX_PATHS_SelectedNum = -1; //************************************************************************************* //************************************************************************************* void ARX_PATHS_DrawPath(ARX_PATH * ap, LPDIRECT3DDEVICE7 pd3dDevice) { if (ap == NULL) return; EERIE_3D from, to; long selected; if (ap == ARX_PATHS_SelectedAP) selected = 1; else selected = 0; for (long i = 0; i < ap->nb_pathways - 1; i++) { long flagg = ap->pathways[i].flag; if (ap->height != 0) flagg = PATHWAY_STANDARD; switch (flagg) { case PATHWAY_STANDARD: from.x = ap->pos.x + ap->pathways[i].rpos.x; from.y = ap->pos.y + ap->pathways[i].rpos.y; from.z = ap->pos.z + ap->pathways[i].rpos.z; to.x = ap->pos.x + ap->pathways[i+1].rpos.x; to.y = ap->pos.y + ap->pathways[i+1].rpos.y; to.z = ap->pos.z + ap->pathways[i+1].rpos.z; if (ap->height != 0) { if (selected) { EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFFFFFFF); if (ap->height > 0) { to.y -= ap->height; from.y -= ap->height; EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFFFFFFF); to.y += ap->height; from.y += ap->height; } } else { EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFCCCCCC); if (ap->height > 0) { to.y -= ap->height; from.y -= ap->height; EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFCCCCCC); to.y += ap->height; from.y += ap->height; } } if (i == ap->nb_pathways - 2) { from.x = ap->pos.x; from.y = ap->pos.y; from.z = ap->pos.z; if (selected) { EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFDDDDDD); if (ap->height > 0) { to.y -= ap->height; from.y -= ap->height; EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFDDDDDD); to.y += ap->height; from.y += ap->height; } } else { EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFAAAAAA); if (ap->height > 0) { to.y -= ap->height; from.y -= ap->height; EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFAAAAAA); to.y += ap->height; from.y += ap->height; } } } } else { if (selected) EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFFFFF00); else EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFAAAAAA); } break; case PATHWAY_BEZIER: #define BEZIERPrecision 32 EERIE_3D lastpos, newpos; lastpos.x = ap->pos.x + ap->pathways[i].rpos.x; lastpos.y = ap->pos.y + ap->pathways[i].rpos.y; lastpos.z = ap->pos.z + ap->pathways[i].rpos.z; long time; for (time = 1; time <= (long)BEZIERPrecision; time++) { float mul = (float)time / BEZIERPrecision; float mull = mul * mul; newpos.x = mul * (ap->pathways[i+1].rpos.x - ap->pathways[i].rpos.x) + (ap->pathways[i+2].rpos.x - ap->pathways[i+1].rpos.x) * mull; newpos.y = mul * (ap->pathways[i+1].rpos.y - ap->pathways[i].rpos.y) + (ap->pathways[i+2].rpos.y - ap->pathways[i+1].rpos.y) * mull; newpos.z = mul * (ap->pathways[i+1].rpos.z - ap->pathways[i].rpos.z) + (ap->pathways[i+2].rpos.z - ap->pathways[i+1].rpos.z) * mull; newpos.x += ap->pos.x + ap->pathways[i].rpos.x; newpos.y += ap->pos.y + ap->pathways[i].rpos.y; newpos.z += ap->pos.z + ap->pathways[i].rpos.z; if (selected) EERIEDraw3DLine(pd3dDevice, &lastpos, &newpos, 0xFF00FF00); else EERIEDraw3DLine(pd3dDevice, &lastpos, &newpos, 0xFFAAAAAA); memcpy(&lastpos, &newpos, sizeof(EERIE_3D)); } i++; break; case PATHWAY_BEZIER_CONTROLPOINT: // There MUST be an ERROR. return; break; } } for (int i = 0; i < ap->nb_pathways; i++) { from.x = ap->pos.x + ap->pathways[i].rpos.x; from.y = ap->pos.y + ap->pathways[i].rpos.y; from.z = ap->pos.z + ap->pathways[i].rpos.z; if (ap->height > 0) { to.x = from.x; to.y = from.y - ap->height; to.z = from.z; EERIEDraw3DLine(pd3dDevice, &from, &to, 0xFFAAAAAA); } if ((ARX_PATHS_SelectedNum == (i + 1)) && (ap == ARX_PATHS_SelectedAP)) ARX_PATHS_DrawPathWay(pd3dDevice, &from, 4.f, 0xFF0000FF, ap->height); if (i == 0) { if (selected) ARX_PATHS_DrawPathWay(pd3dDevice, &from, 3.f, 0xFFFF0000, ap->height); else ARX_PATHS_DrawPathWay(pd3dDevice, &from, 3.f, 0xFFAA0000, ap->height); } else switch (ap->pathways[i].flag) { case PATHWAY_STANDARD: if (selected) ARX_PATHS_DrawPathWay(pd3dDevice, &from, 2.4f, 0xFFFFFF00, ap->height); else ARX_PATHS_DrawPathWay(pd3dDevice, &from, 2.4f, 0xFFAAAAAA, ap->height); break; case PATHWAY_BEZIER: if (selected) ARX_PATHS_DrawPathWay(pd3dDevice, &from, 2.4f, 0xFF00FF00, ap->height); else ARX_PATHS_DrawPathWay(pd3dDevice, &from, 2.4f, 0xFFAAAAAA, ap->height); break; } if ((DANAEMouse.x > SPRmins.x) && (DANAEMouse.x < SPRmaxs.x) && (DANAEMouse.y > SPRmins.y) && (DANAEMouse.y < SPRmaxs.y)) { ARX_PATHS_FlyingOverAP = ap; ARX_PATHS_FlyingOverNum = i + 1; } } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // THROWN OBJECTS MANAGEMENT /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// ARX_THROWN_OBJECT Thrown[MAX_THROWN_OBJECTS]; long Thrown_Count = 0; void ARX_THROWN_OBJECT_Kill(long num) { if ((num >= 0) && (num < MAX_THROWN_OBJECTS)) { Thrown[num].flags = 0; Thrown_Count--; if (Thrown[num].pRuban) { delete Thrown[num].pRuban; Thrown[num].pRuban = NULL; } } } void ARX_THROWN_OBJECT_KillAll() { for (long i = 0; i < MAX_THROWN_OBJECTS; i++) { ARX_THROWN_OBJECT_Kill(i); } Thrown_Count = 0; } long ARX_THROWN_OBJECT_GetFree() { unsigned long latest_time = ARXTimeUL(); long latest_obj = -1; for (long i = 0; i < MAX_THROWN_OBJECTS; i++) { if (Thrown[i].flags & ATO_EXIST) { if (Thrown[i].creation_time < latest_time) { latest_obj = i; latest_time = Thrown[i].creation_time; } } else { return i; } } if (latest_obj >= 0) { ARX_THROWN_OBJECT_Kill(latest_obj); return latest_obj; } return -1; } extern EERIE_3DOBJ * arrowobj; long ARX_THROWN_OBJECT_Throw(long type, long source, EERIE_3D * position, EERIE_3D * vect, EERIE_3D * upvect, EERIE_QUAT * quat, float velocity, float damages, float poison) { long num = ARX_THROWN_OBJECT_GetFree(); if (num >= 0) { Thrown[num].damages = damages; Vector_Copy(&Thrown[num].position, position); Vector_Copy(&Thrown[num].initial_position, position); Vector_Copy(&Thrown[num].vector, vect); Vector_Copy(&Thrown[num].upvect, upvect); Quat_Copy(&Thrown[num].quat, quat); Thrown[num].source = source; Thrown[num].obj = NULL; Thrown[num].velocity = velocity; Thrown[num].poisonous = poison; Thrown[num].pRuban = new CRuban(); Thrown[num].pRuban->Create(num, 2000); switch (type) { case ATO_TYPE_ARROW: Thrown[num].obj = arrowobj; break; default: break; } if (Thrown[num].obj) { Thrown[num].creation_time = ARXTimeUL(); Thrown[num].flags |= ATO_EXIST | ATO_MOVING; Thrown_Count++; } if ((source == 0) && (player.equiped[EQUIP_SLOT_WEAPON] != 0) && (ValidIONum(player.equiped[EQUIP_SLOT_WEAPON]))) { INTERACTIVE_OBJ * tio = inter.iobj[player.equiped[EQUIP_SLOT_WEAPON]]; if (tio->ioflags & IO_FIERY) Thrown[num].flags |= ATO_FIERY; } } return num; } float ARX_THROWN_ComputeDamages(long thrownum, long source, long target) { float distance_limit = 1000.f; INTERACTIVE_OBJ * io_target = inter.iobj[target]; INTERACTIVE_OBJ * io_source = inter.iobj[source]; SendIOScriptEvent(io_target, SM_AGGRESSION, "", NULL); float distance = EEDistance3D(&Thrown[thrownum].position, &Thrown[thrownum].initial_position); float distance_modifier = 1.f; if (distance < distance_limit * 2.f) { distance_modifier = distance / distance_limit; if (distance_modifier < 0.5f) distance_modifier = 0.5f; } else distance_modifier = 2.f; float attack, dmgs, backstab, critical, ac; dmgs = 0; backstab = 1.f; critical = FALSE; if (source == 0) { attack = Thrown[thrownum].damages; if (rnd() * 100 <= (float)(player.Full_Attribute_Dexterity - 9) * 2.f + (float)((player.Full_Skill_Projectile) * DIV5)) { if (SendIOScriptEvent(io_source, SM_CRITICAL, "BOW", NULL) != REFUSE) critical = TRUE; } dmgs = attack; if (io_target->_npcdata->npcflags & NPCFLAG_BACKSTAB) { if (rnd() * 100.f <= player.Full_Skill_Stealth) { if (SendIOScriptEvent(io_source, SM_BACKSTAB, "BOW", NULL) != REFUSE) backstab = 1.5f; } } } else { // treat NPC !!! ARX_CHECK_NO_ENTRY(); attack = 0; } float absorb; if (target == 0) { ac = player.Full_armor_class; absorb = player.Full_Skill_Defense * DIV2; } else { ac = ARX_INTERACTIVE_GetArmorClass(io_target); absorb = io_target->_npcdata->absorb; } char wmat[64]; char amat[64]; strcpy(wmat, "DAGGER"); strcpy(amat, "FLESH"); if (io_target->armormaterial) { strcpy(amat, io_target->armormaterial); } if (io_target == inter.iobj[0]) { if (player.equiped[EQUIP_SLOT_ARMOR] > 0) { INTERACTIVE_OBJ * io = inter.iobj[player.equiped[EQUIP_SLOT_ARMOR]]; if ((io) && (io->armormaterial)) { strcpy(amat, io->armormaterial); } } } float power; power = dmgs * DIV20; if (power > 1.f) power = 1.f; power = power * 0.15f + 0.85f; ARX_SOUND_PlayCollision(amat, wmat, power, 1.f, &Thrown[thrownum].position, io_source); dmgs *= backstab; dmgs -= dmgs * (absorb * DIV100); float chance = 100.f - (ac - attack); float dice = rnd() * 100.f; if (dice <= chance) { if (dmgs > 0.f) { if (critical) dmgs *= 1.5f; dmgs *= distance_modifier; return dmgs; } } return 0.f; } EERIEPOLY * CheckArrowPolyCollision(EERIE_3D * start, EERIE_3D * end) { EERIE_TRI pol; EERIE_TRI pol2; Vector_Copy(&pol.v[0], start); Vector_Copy(&pol.v[2], end); pol.v[2].x -= 2.f; pol.v[2].y -= 15.f; pol.v[2].z -= 2.f; Vector_Copy(&pol.v[1], end); long px, pz; F2L(end->x * ACTIVEBKG->Xmul, &px); F2L(end->z * ACTIVEBKG->Zmul, &pz); long ix, ax, iz, az; ix = __max(px - 2, 0); ax = __min(px + 2, ACTIVEBKG->Xsize - 1); iz = __max(pz - 2, 0); az = __min(pz + 2, ACTIVEBKG->Zsize - 1); EERIEPOLY * ep; FAST_BKG_DATA * feg; for (long zz = iz; zz <= az; zz++) for (long xx = ix; xx <= ax; xx++) { feg = &ACTIVEBKG->fastdata[xx][zz]; for (long k = 0; k < feg->nbpolyin; k++) { ep = feg->polyin[k]; if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)) continue; memcpy(&pol2.v[0], &ep->v[0], sizeof(EERIE_3D)); memcpy(&pol2.v[1], &ep->v[1], sizeof(EERIE_3D)); memcpy(&pol2.v[2], &ep->v[2], sizeof(EERIE_3D)); if (Triangles_Intersect(&pol2, &pol)) return ep; if (ep->type & POLY_QUAD) { memcpy(&pol2.v[0], &ep->v[1], sizeof(EERIE_3D)); memcpy(&pol2.v[1], &ep->v[3], sizeof(EERIE_3D)); memcpy(&pol2.v[2], &ep->v[2], sizeof(EERIE_3D)); if (Triangles_Intersect(&pol2, &pol)) return ep; } } } return NULL; } void CheckExp(long i) { if ((Thrown[i].flags & ATO_FIERY) && !(Thrown[i].flags & ATO_UNDERWATER)) { ARX_BOOMS_Add(&Thrown[i].position); LaunchFireballBoom(&Thrown[i].position, 10); DoSphericDamage(&Thrown[i].position, 4.f * 2, 50.f, DAMAGE_AREA, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL, 0); ARX_SOUND_PlaySFX(SND_SPELL_FIRE_HIT, &Thrown[i].position); ARX_NPC_SpawnAudibleSound(&Thrown[i].position, inter.iobj[0]); long id = GetFreeDynLight(); if ((id != -1) && (FrameDiff > 0)) { DynLight[id].exist = 1; DynLight[id].intensity = 3.9f; DynLight[id].fallstart = 400.f; DynLight[id].fallend = 440.f; DynLight[id].rgb.r = (1.f - rnd() * 0.2f); DynLight[id].rgb.g = (0.8f - rnd() * 0.2f); DynLight[id].rgb.b = (0.6f - rnd() * 0.2f); DynLight[id].pos.x = Thrown[i].position.x; DynLight[id].pos.y = Thrown[i].position.y; DynLight[id].pos.z = Thrown[i].position.z; DynLight[id].ex_flaresize = 40.f; DynLight[id].duration = 1500; } } } extern float fZFogEnd; extern long FRAME_COUNT; void ARX_THROWN_OBJECT_Manage(unsigned long time_offset) { if (Thrown_Count <= 0) return; SETZWRITE(GDevice, TRUE); GDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, true); for (long i = 0; i < MAX_THROWN_OBJECTS; i++) { if (Thrown[i].flags & ATO_EXIST) { // Is Object Visible & Near ? float dist = EEDistance3D(&ACTIVECAM->pos, &Thrown[i].position); if (dist > ACTIVECAM->cdepth * fZFogEnd + 50.f) continue; long xx, yy; F2L((Thrown[i].position.x)*ACTIVEBKG->Xmul, &xx); F2L((Thrown[i].position.z)*ACTIVEBKG->Zmul, &yy); if (xx < 0) continue; if (xx >= ACTIVEBKG->Xsize) continue; if (yy < 0) continue; if (yy >= ACTIVEBKG->Zsize) continue; FAST_BKG_DATA * feg = (FAST_BKG_DATA *)&ACTIVEBKG->fastdata[xx][yy]; if (!feg->treat) continue; // Now render object ! if (!Thrown[i].obj) continue; EERIEMATRIX mat; MatrixFromQuat(&mat, &Thrown[i].quat); long ccount = FRAME_COUNT; FRAME_COUNT = 0; DrawEERIEInterMatrix(GDevice, Thrown[i].obj, &mat, &Thrown[i].position, NULL, NULL); if ((Thrown[i].flags & ATO_FIERY) && (Thrown[i].flags & ATO_MOVING) && !(Thrown[i].flags & ATO_UNDERWATER)) { long id = GetFreeDynLight(); if ((id != -1) && (FrameDiff > 0)) { DynLight[id].exist = 1; DynLight[id].intensity = 1.f; DynLight[id].fallstart = 100.f; DynLight[id].fallend = 240.f; DynLight[id].rgb.r = (1.f - rnd() * 0.2f); DynLight[id].rgb.g = (0.8f - rnd() * 0.2f); DynLight[id].rgb.b = (0.6f - rnd() * 0.2f); DynLight[id].pos.x = Thrown[i].position.x; DynLight[id].pos.y = Thrown[i].position.y; DynLight[id].pos.z = Thrown[i].position.z; DynLight[id].ex_flaresize = 40.f; DynLight[id].extras |= EXTRAS_FLARE; DynLight[id].duration = ARX_CLEAN_WARN_CAST_LONG(FrameDiff * 0.5f); } float p = 3.f; while (p > 0.f) { p -= 0.5f; if (Thrown[i].obj) { EERIE_3D pos; long notok = 10; long num = 0; while (notok-- > 0) { F2L((float)(rnd() *(float)Thrown[i].obj->nbfaces), &num); if ((num >= 0) && (num < Thrown[i].obj->nbfaces)) { if (Thrown[i].obj->facelist[num].facetype & POLY_HIDE) continue; notok = -1; } } if (notok < 0) { Vector_Copy(&pos, &Thrown[i].obj->vertexlist3[Thrown[i].obj->facelist[num].vid[0]].v); for (long nn = 0; nn < 2; nn++) { long j = ARX_PARTICLES_GetFree(); if ((j != -1) && (!ARXPausedTimer) && (rnd() < 0.4f)) { ParticleCount++; PARTICLE_DEF * pd = &particle[j]; pd->exist = TRUE; pd->zdec = 0; Vector_Copy(&pd->ov, &pos); pd->move.x = (2.f - 4.f * rnd()); pd->move.y = (2.f - 22.f * rnd()); pd->move.z = (2.f - 4.f * rnd()); pd->siz = 7.f; pd->tolive = 500 + (unsigned long)(rnd() * 1000.f); pd->special = FIRE_TO_SMOKE | ROTATING | MODULATE_ROTATION; pd->tc = fire2;//tc; pd->fparam = 0.1f - rnd() * 0.2f; pd->scale.x = -8.f; pd->scale.y = -8.f; pd->scale.z = -8.f; pd->timcreation = lARXTime; pd->r = 0.71f; pd->g = 0.43f; pd->b = 0.29f; pd->delay = nn * 180; } } } } } } if (Thrown[i].pRuban) { ARX_CHECK_ULONG(FrameDiff); Thrown[i].pRuban->Update(ARX_CLEAN_WARN_CAST_ULONG(FrameDiff)); Thrown[i].pRuban->Render(GDevice); } FRAME_COUNT = ccount; EERIE_3D original_pos; if (Thrown[i].flags & ATO_MOVING) { long need_kill = 0; float mod = (float)time_offset * Thrown[i].velocity; Vector_Copy(&original_pos, &Thrown[i].position); Thrown[i].position.x += Thrown[i].vector.x * mod; float gmod = 1.f - Thrown[i].velocity; if (gmod > 1.f) gmod = 1.f; else if (gmod < 0.f) gmod = 0.f; Thrown[i].position.y += Thrown[i].vector.y * mod + (time_offset * gmod); Thrown[i].position.z += Thrown[i].vector.z * mod; CheckForIgnition(&original_pos, 10.f, 0, 2); EERIE_3D wpos; Vector_Copy(&wpos, &Thrown[i].position); wpos.y += 20.f; EERIEPOLY * ep = EEIsUnderWater(&wpos); if (Thrown[i].flags & ATO_UNDERWATER) { if (ep == NULL) { Thrown[i].flags &= ~ATO_UNDERWATER; ARX_SOUND_PlaySFX(SND_PLOUF, &Thrown[i].position); } } else if (ep != NULL) { Thrown[i].flags |= ATO_UNDERWATER; ARX_SOUND_PlaySFX(SND_PLOUF, &Thrown[i].position); } // Check for collision MUST be done after DRAWING !!!! long nbact = Thrown[i].obj->nbaction; for (long j = 0; j < nbact; j++) { float rad = -1; rad = GetHitValue(Thrown[i].obj->actionlist[j].name); rad *= DIV2; if (rad == -1) continue; EERIE_3D * v0; v0 = &Thrown[i].obj->vertexlist3[Thrown[i].obj->actionlist[j].idx].v; EERIE_3D orgn, dest; dest.x = original_pos.x + Thrown[i].vector.x * 95.f; dest.y = original_pos.y + Thrown[i].vector.y * 95.f; dest.z = original_pos.z + Thrown[i].vector.z * 95.f; orgn.x = original_pos.x - Thrown[i].vector.x * 25.f; orgn.y = original_pos.y - Thrown[i].vector.y * 25.f; orgn.z = original_pos.z - Thrown[i].vector.z * 25.f; EERIEPOLY * ep = CheckArrowPolyCollision(&orgn, &dest); if (ep) { ARX_PARTICLES_Spawn_Spark(v0, 14, 0); CheckExp(i); if (ValidIONum(Thrown[i].source)) ARX_NPC_SpawnAudibleSound(v0, inter.iobj[Thrown[i].source]); Thrown[i].flags &= ~ATO_MOVING; Thrown[i].velocity = 0.f; char weapon_material[64] = "DAGGER"; char bkg_material[64] = "EARTH"; if (ep && ep->tex && ep->tex->m_texName) GetMaterialString(ep->tex->m_texName, bkg_material); if (ValidIONum(Thrown[i].source)) ARX_SOUND_PlayCollision(weapon_material, bkg_material, 1.f, 1.f, v0, inter.iobj[Thrown[i].source]); Vector_Copy(&Thrown[i].position, &original_pos); j = 200; } else if (IsPointInField(v0)) { ARX_PARTICLES_Spawn_Spark(v0, 24, 0); CheckExp(i); if (ValidIONum(Thrown[i].source)) ARX_NPC_SpawnAudibleSound(v0, inter.iobj[Thrown[i].source]); Thrown[i].flags &= ~ATO_MOVING; Thrown[i].velocity = 0.f; char weapon_material[64] = "DAGGER"; char bkg_material[64] = "EARTH"; if (ValidIONum(Thrown[i].source)) ARX_SOUND_PlayCollision(weapon_material, bkg_material, 1.f, 1.f, v0, inter.iobj[Thrown[i].source]); Vector_Copy(&Thrown[i].position, &original_pos); j = 200; need_kill = 1; } else for (float precision = 0.5f; precision <= 6.f; precision += 0.5f) { EERIE_SPHERE sphere; sphere.origin.x = v0->x + Thrown[i].vector.x * precision * 4.5f; sphere.origin.y = v0->y + Thrown[i].vector.y * precision * 4.5f; sphere.origin.z = v0->z + Thrown[i].vector.z * precision * 4.5f; sphere.radius = rad + 3.f; if (CheckEverythingInSphere(&sphere, Thrown[i].source, -1)) { for (long jj = 0; jj < MAX_IN_SPHERE_Pos; jj++) { if ((ValidIONum(EVERYTHING_IN_SPHERE[jj]) && (EVERYTHING_IN_SPHERE[jj] != Thrown[i].source))) { INTERACTIVE_OBJ * target = inter.iobj[EVERYTHING_IN_SPHERE[jj]]; if (target->ioflags & IO_NPC) { EERIE_3D pos; D3DCOLOR color = 0x00000000; long hitpoint = -1; float curdist = 999999.f; for (long ii = 0 ; ii < target->obj->nbfaces ; ii++) { if (target->obj->facelist[ii].facetype & POLY_HIDE) continue; float dist = TRUEEEDistance3D(&sphere.origin, &target->obj->vertexlist3[target->obj->facelist[ii].vid[0]].v); if (dist < curdist) { hitpoint = target->obj->facelist[ii].vid[0]; curdist = dist; } } if (hitpoint >= 0) { color = target->_npcdata->blood_color; Vector_Copy(&pos, &target->obj->vertexlist3[hitpoint].v); } if (Thrown[i].source == 0) { float damages; if ((damages = ARX_THROWN_ComputeDamages(i, Thrown[i].source, EVERYTHING_IN_SPHERE[jj])) > 0.f) { ARX_CHECK(hitpoint >= 0); if (target->ioflags & IO_NPC) { target->_npcdata->SPLAT_TOT_NB = 0; ARX_PARTICLES_Spawn_Blood2(&original_pos, damages, color, hitpoint, target); } ARX_PARTICLES_Spawn_Blood2(&pos, damages, color, hitpoint, target); ARX_DAMAGES_DamageNPC(target, damages, Thrown[i].source, 0, &pos); if (rnd() * 100.f > target->_npcdata->resist_poison) { target->_npcdata->poisonned += Thrown[i].poisonous; } CheckExp(i); } else { ARX_PARTICLES_Spawn_Spark(v0, 14, 0); //dmgs); ARX_NPC_SpawnAudibleSound(v0, inter.iobj[Thrown[i].source]); } } } else // not NPC { if (target->ioflags & IO_FIX) { if (ValidIONum(Thrown[i].source)) ARX_DAMAGES_DamageFIX(target, 0.1f, Thrown[i].source, 0); } ARX_PARTICLES_Spawn_Spark(v0, 14, 0); if (ValidIONum(Thrown[i].source)) ARX_NPC_SpawnAudibleSound(v0, inter.iobj[Thrown[i].source]); CheckExp(i); } // Need to deal damages ! Thrown[i].flags &= ~ATO_MOVING; Thrown[i].velocity = 0.f; need_kill = 1; precision = 500.f; j = 200; } } } } } if (need_kill) ARX_THROWN_OBJECT_Kill(i); } } } } //----------------------------------------------------------------------------- // RUBAN //----------------------------------------------------------------------------- void CRuban::Create(int _iNumThrow, int _iDuration) { iNumThrow = _iNumThrow; key = 1; duration = _iDuration; currduration = 0; nbrubandef = 0; int nb = 2048; while (nb--) { truban[nb].actif = 0; } float col = 0.1f + (rnd() * 0.1f); float size = 2.f + (2.f * rnd()); int taille = 8 + (int)(8.f * rnd()); AddRubanDef(0, size, taille, col, col, col, 0.f, 0.f, 0.f); } //----------------------------------------------------------------------------- void CRuban::AddRubanDef(int origin, float size, int dec, float r, float g, float b, float r2, float g2, float b2) { if (nbrubandef > 255) return; trubandef[nbrubandef].first = -1; trubandef[nbrubandef].origin = origin; trubandef[nbrubandef].size = size; trubandef[nbrubandef].dec = dec; trubandef[nbrubandef].r = r; trubandef[nbrubandef].g = g; trubandef[nbrubandef].b = b; trubandef[nbrubandef].r2 = r2; trubandef[nbrubandef].g2 = g2; trubandef[nbrubandef].b2 = b2; nbrubandef++; } //----------------------------------------------------------------------------- int CRuban::GetFreeRuban() { int nb = 2048; while (nb--) { if (!truban[nb].actif) return nb; } return -1; } //----------------------------------------------------------------------------- void CRuban::AddRuban(int * f, int id, int dec) { int num; num = GetFreeRuban(); if (num >= 0) { truban[num].actif = 1; truban[num].pos.x = Thrown[iNumThrow].position.x; truban[num].pos.y = Thrown[iNumThrow].position.y; truban[num].pos.z = Thrown[iNumThrow].position.z; if (*f < 0) { *f = num; truban[num].next = -1; } else { truban[num].next = *f; *f = num; } int nb = 0, oldnum = 0; while (num != -1) { nb++; oldnum = num; num = truban[num].next; } if (nb > dec) { truban[oldnum].actif = 0; num = *f; nb -= 2; while (nb--) { num = truban[num].next; } truban[num].next = -1; } } } //----------------------------------------------------------------------------- void CRuban::Update(unsigned long _ulTime) { int nb, num; if (ARXPausedTimer) return; num = 0; nb = nbrubandef; while (nb--) { AddRuban(&trubandef[num].first, trubandef[num].origin, trubandef[num].dec); num++; } } //----------------------------------------------------------------------------- void CRuban::DrawRuban(LPDIRECT3DDEVICE7 device, int num, float size, int dec, float r, float g, float b, float r2, float g2, float b2) { int numsuiv; float dsize = size / (float)(dec + 1); int r1 = ((int)(r * 255.f)) << 16; int g1 = ((int)(g * 255.f)) << 16; int b1 = ((int)(b * 255.f)) << 16; int rr2 = ((int)(r2 * 255.f)) << 16; int gg2 = ((int)(g2 * 255.f)) << 16; int bb2 = ((int)(b2 * 255.f)) << 16; int dr = (rr2 - r1) / dec; int dg = (gg2 - g1) / dec; int db = (bb2 - b1) / dec; while (1) { numsuiv = truban[num].next; if ((num >= 0) && (numsuiv >= 0)) { Draw3DLineTex2(device, truban[num].pos, truban[numsuiv].pos, size, RGBA_MAKE(r1 >> 16, g1 >> 16, b1 >> 16, 0), RGBA_MAKE((r1 + dr) >> 16, (g1 + dg) >> 16, (b1 + db) >> 16, 0)); r1 += dr; g1 += dg; b1 += db; size -= dsize; } else { break; } num = numsuiv; } } //----------------------------------------------------------------------------- float CRuban::Render(LPDIRECT3DDEVICE7 device) { SETCULL(device, D3DCULL_NONE); SETALPHABLEND(device, TRUE); device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE); device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); SETTC(device, NULL); for (int i = 0; i < nbrubandef; i++) { this->DrawRuban(device, trubandef[i].first, trubandef[i].size, trubandef[i].dec, trubandef[i].r, trubandef[i].g, trubandef[i].b, trubandef[i].r2, trubandef[i].g2, trubandef[i].b2) ; } SETALPHABLEND(device, FALSE); device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE); device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO); return 0; } extern bool IsValidPos3(EERIE_3D * pos); #define FORCE_THRESHOLD 290.f extern long PHYS_COLLIDER; extern EERIEPOLY * LAST_COLLISION_POLY; extern long CUR_COLLISION_MATERIAL; extern BOOL IsFULLObjectVertexInValidPosition(EERIE_3DOBJ * obj, long flags, long source, long * validd); extern BOOL IsObjectVertexInValidPosition(EERIE_3DOBJ * obj, long kk, long flags, long source); extern float VELOCITY_THRESHOLD; void ARX_ApplySpring(PHYSVERT * phys, long k, long l, float PHYSICS_constant, float PHYSICS_Damp) { EERIE_3D deltaP, deltaV, springforce; PHYSVERT * pv_k = &phys[k]; PHYSVERT * pv_l = &phys[l]; float Dterm, Hterm; float restlength = TRUEEEDistance3D(&pv_k->initpos, &pv_l->initpos); //Computes Spring Magnitude deltaP.x = pv_k->pos.x - pv_l->pos.x; deltaP.y = pv_k->pos.y - pv_l->pos.y; deltaP.z = pv_k->pos.z - pv_l->pos.z; float dist = (float)TRUEsqrt(deltaP.x * deltaP.x + deltaP.y * deltaP.y + deltaP.z * deltaP.z); // Magnitude of delta float divdist = 1.f / dist; Hterm = (dist - restlength) * PHYSICS_constant; deltaV.x = pv_k->velocity.x - pv_l->velocity.x; deltaV.y = pv_k->velocity.y - pv_l->velocity.y; deltaV.z = pv_k->velocity.z - pv_l->velocity.z; // Delta Velocity Vector Dterm = (Vector_DotProduct(&deltaV, &deltaP) * PHYSICS_Damp) * divdist; // Damping Term Dterm = (-(Hterm + Dterm)); divdist *= Dterm; springforce.x = deltaP.x * divdist; // Normalize Distance Vector springforce.y = deltaP.y * divdist; // & Calc Force springforce.z = deltaP.z * divdist; pv_k->force.x += springforce.x; // + force on particle 1 pv_k->force.y += springforce.y; pv_k->force.z += springforce.z; pv_l->force.x -= springforce.x; // - force on particle 2 pv_l->force.y -= springforce.y; pv_l->force.z -= springforce.z; } void ComputeForces(PHYSVERT * phys, long nb) { EERIE_3D PHYSICS_Gravity; PHYSICS_Gravity.x = 0.f; PHYSICS_Gravity.y = 65.f; PHYSICS_Gravity.z = 0.f; float PHYSICS_Damping = 0.5f; float lastmass = 1.f; float div = 1.f; for (long k = 0; k < nb; k++) { PHYSVERT * pv = &phys[k]; // Reset Force pv->force.x = pv->inertia.x; pv->force.y = pv->inertia.y; pv->force.z = pv->inertia.z; // Apply Gravity if (pv->mass > 0.f) { //need to be precomputed... if (lastmass != pv->mass) { div = 1.f / pv->mass; lastmass = pv->mass; } pv->force.x += (PHYSICS_Gravity.x * div); pv->force.y += (PHYSICS_Gravity.y * div); pv->force.z += (PHYSICS_Gravity.z * div); } // Apply Damping pv->force.x += (-PHYSICS_Damping * pv->velocity.x); pv->force.y += (-PHYSICS_Damping * pv->velocity.y); pv->force.z += (-PHYSICS_Damping * pv->velocity.z); } for (int k = 0; k < nb; k++) { // Now Resolves Spring System for (long l = 0; l < nb; l++) { if (l != k) ARX_ApplySpring(phys, l, k, 15.f, 0.99f); //18.f,0.4f); } } } BOOL ARX_INTERACTIVE_CheckFULLCollision(EERIE_3DOBJ * obj, long source); /////////////////////////////////////////////////////////////////////////////// // Function: RK4Integrate // Calculate new Positions and Velocities given a deltatime // DeltaTime that has passed since last iteration /////////////////////////////////////////////////////////////////////////////// void RK4Integrate(EERIE_3DOBJ * obj, float DeltaTime) { /// Local Variables /////////////////////////////////////////////////////////// PHYSVERT * source, *target, *accum1, *accum2, *accum3, *accum4; /////////////////////////////////////////////////////////////////////////////// float halfDeltaT, sixthDeltaT; halfDeltaT = DeltaTime * DIV2; // SOME TIME VALUES I WILL NEED sixthDeltaT = DIV6; PHYSVERT m_TempSys[5][32];//* pv; for (long jj = 0; jj < 4; jj++) { memcpy(&m_TempSys[jj+1][0], obj->pbox->vert, sizeof(PHYSVERT)*obj->pbox->nb_physvert); if (jj == 3) halfDeltaT = DeltaTime; for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) { source = &obj->pbox->vert[kk]; accum1 = &m_TempSys[jj+1][kk]; target = &m_TempSys[0][kk]; accum1->force.x = halfDeltaT * source->force.x * source->mass; accum1->force.y = halfDeltaT * source->force.y * source->mass; accum1->force.z = halfDeltaT * source->force.z * source->mass; accum1->velocity.x = halfDeltaT * source->velocity.x; accum1->velocity.y = halfDeltaT * source->velocity.y; accum1->velocity.z = halfDeltaT * source->velocity.z; // DETERMINE THE NEW VELOCITY FOR THE PARTICLE OVER 1/2 TIME target->velocity.x = source->velocity.x + (accum1->force.x); target->velocity.y = source->velocity.y + (accum1->force.y); target->velocity.z = source->velocity.z + (accum1->force.z); target->mass = source->mass; // SET THE NEW POSITION target->pos.x = source->pos.x + (accum1->velocity.x); target->pos.y = source->pos.y + (accum1->velocity.y); target->pos.z = source->pos.z + (accum1->velocity.z); } ComputeForces(m_TempSys[0], obj->pbox->nb_physvert); // COMPUTE THE NEW FORCES } for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) { source = &obj->pbox->vert[kk]; // CURRENT STATE OF PARTICLE target = &obj->pbox->vert[kk]; accum1 = &m_TempSys[1][kk]; accum2 = &m_TempSys[2][kk]; accum3 = &m_TempSys[3][kk]; accum4 = &m_TempSys[4][kk]; // DETERMINE THE NEW VELOCITY FOR THE PARTICLE USING RK4 FORMULA target->velocity.x = source->velocity.x + ((accum1->force.x + ((accum2->force.x + accum3->force.x) * 2.0f) + accum4->force.x) * sixthDeltaT); target->velocity.y = source->velocity.y + ((accum1->force.y + ((accum2->force.y + accum3->force.y) * 2.0f) + accum4->force.y) * sixthDeltaT); target->velocity.z = source->velocity.z + ((accum1->force.z + ((accum2->force.z + accum3->force.z) * 2.0f) + accum4->force.z) * sixthDeltaT); // DETERMINE THE NEW POSITION FOR THE PARTICLE USING RK4 FORMULA target->pos.x = source->pos.x + ((accum1->velocity.x + ((accum2->velocity.x + accum3->velocity.x) * 2.0f) + accum4->velocity.x) * sixthDeltaT * 1.2f); target->pos.y = source->pos.y + ((accum1->velocity.y + ((accum2->velocity.y + accum3->velocity.y) * 2.0f) + accum4->velocity.y) * sixthDeltaT * 1.2f); target->pos.z = source->pos.z + ((accum1->velocity.z + ((accum2->velocity.z + accum3->velocity.z) * 2.0f) + accum4->velocity.z) * sixthDeltaT * 1.2f); } } bool IsPointInField(EERIE_3D * pos) { for (long i = 0; i < MAX_SPELLS; i++) { if ((spells[i].exist) && (spells[i].type == SPELL_CREATE_FIELD)) { if (ValidIONum(spells[i].longinfo)) { INTERACTIVE_OBJ * pfrm = inter.iobj[spells[i].longinfo]; EERIE_CYLINDER cyl; cyl.height = -35.f; cyl.radius = 35.f; cyl.origin.x = pos->x; cyl.origin.y = pos->y + 17.5f; cyl.origin.z = pos->z; if (CylinderPlatformCollide(&cyl, pfrm) != 0.f) return true; } } } return false; } bool IsObjectInField(EERIE_3DOBJ * obj, long source) { for (long i = 0; i < MAX_SPELLS; i++) { if ((spells[i].exist) && (spells[i].type == SPELL_CREATE_FIELD)) { if (ValidIONum(spells[i].longinfo)) { INTERACTIVE_OBJ * pfrm = inter.iobj[spells[i].longinfo]; EERIE_CYLINDER cyl; cyl.height = -35.f; cyl.radius = 35.f; for (long k = 0; k < obj->pbox->nb_physvert; k++) { PHYSVERT * pv = &obj->pbox->vert[k]; cyl.origin.x = pv->pos.x; cyl.origin.y = pv->pos.y + 17.5f; cyl.origin.z = pv->pos.z; if (CylinderPlatformCollide(&cyl, pfrm) != 0.f) return true; } } } } return false; } BOOL IsObjectVertexCollidingPoly(EERIE_3DOBJ * obj, EERIEPOLY * ep, long k, long * validd); BOOL _IsObjectVertexCollidingPoly(EERIE_3DOBJ * obj, EERIEPOLY * ep, long k, long * validd) { EERIE_3D pol[3]; Vector_Copy(&pol[0], (EERIE_3D *)&ep->v[0]); Vector_Copy(&pol[1], (EERIE_3D *)&ep->v[1]); Vector_Copy(&pol[2], (EERIE_3D *)&ep->v[2]); if (ep->type & POLY_QUAD) { if (IsObjectVertexCollidingTriangle(obj, (EERIE_3D *)&pol, k, validd)) return TRUE; Vector_Copy(&pol[1], (EERIE_3D *)&ep->v[2]); Vector_Copy(&pol[2], (EERIE_3D *)&ep->v[3]); if (IsObjectVertexCollidingTriangle(obj, (EERIE_3D *)&pol, k, validd)) return TRUE; return FALSE; } if (IsObjectVertexCollidingTriangle(obj, (EERIE_3D *)&pol, k, validd)) return TRUE; return FALSE; } BOOL _IsFULLObjectVertexInValidPosition(EERIE_3DOBJ * obj, long flags, long source, long * validd) { BOOL ret = TRUE; long px, pz; float x = obj->pbox->vert[0].pos.x; F2L(x * ACTIVEBKG->Xmul, &px); float z = obj->pbox->vert[0].pos.z; F2L(z * ACTIVEBKG->Zmul, &pz); long ix, iz, ax, az; long n; F2L(obj->pbox->radius * DIV100, &n); n = __min(1, n + 1); ix = __max(px - n, 0); ax = __min(px + n, ACTIVEBKG->Xsize - 1); iz = __max(pz - n, 0); az = __min(pz + n, ACTIVEBKG->Zsize - 1); LAST_COLLISION_POLY = NULL; EERIEPOLY * ep; EERIE_BKG_INFO * eg; float rad = obj->pbox->radius; for (pz = iz; pz <= az; pz++) for (px = ix; px <= ax; px++) { eg = &ACTIVEBKG->Backg[px+pz*ACTIVEBKG->Xsize]; for (long k = 0; k < eg->nbpoly; k++) { ep = &eg->polydata[k]; if ( (ep->area > 190.f) && (!(ep->type & (POLY_WATER))) && (!(ep->type & (POLY_TRANS))) && (!(ep->type & (POLY_NOCOL))) ) { if (EEDistance3D(&ep->center, &obj->pbox->vert[0].pos) > rad + 75.f) continue; for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) { float radd = 4.f; if ( (EEDistance3D(&ep->center, &obj->pbox->vert[kk].pos) <= radd) || (EEDistance3D((EERIE_3D *)&ep->v[0], &obj->pbox->vert[kk].pos) <= radd) || (EEDistance3D((EERIE_3D *)&ep->v[1], &obj->pbox->vert[kk].pos) <= radd) || (EEDistance3D((EERIE_3D *)&ep->v[2], &obj->pbox->vert[kk].pos) <= radd) || (Distance3D((ep->v[0].sx + ep->v[1].sx)*DIV2, (ep->v[0].sy + ep->v[1].sy)*DIV2, (ep->v[0].sz + ep->v[1].sz)*DIV2, obj->pbox->vert[kk].pos.x, obj->pbox->vert[kk].pos.y, obj->pbox->vert[kk].pos.z) <= radd) || (Distance3D((ep->v[2].sx + ep->v[1].sx)*DIV2, (ep->v[2].sy + ep->v[1].sy)*DIV2, (ep->v[2].sz + ep->v[1].sz)*DIV2, obj->pbox->vert[kk].pos.x, obj->pbox->vert[kk].pos.y, obj->pbox->vert[kk].pos.z) <= radd) || (Distance3D((ep->v[0].sx + ep->v[2].sx)*DIV2, (ep->v[0].sy + ep->v[2].sy)*DIV2, (ep->v[0].sz + ep->v[2].sz)*DIV2, obj->pbox->vert[kk].pos.x, obj->pbox->vert[kk].pos.y, obj->pbox->vert[kk].pos.z) <= radd) ) { LAST_COLLISION_POLY = ep; if (ep->type & POLY_METAL) CUR_COLLISION_MATERIAL = MATERIAL_METAL; else if (ep->type & POLY_WOOD) CUR_COLLISION_MATERIAL = MATERIAL_WOOD; else if (ep->type & POLY_STONE) CUR_COLLISION_MATERIAL = MATERIAL_STONE; else if (ep->type & POLY_GRAVEL) CUR_COLLISION_MATERIAL = MATERIAL_GRAVEL; else if (ep->type & POLY_WATER) CUR_COLLISION_MATERIAL = MATERIAL_WATER; else if (ep->type & POLY_EARTH) CUR_COLLISION_MATERIAL = MATERIAL_EARTH; else CUR_COLLISION_MATERIAL = MATERIAL_STONE; return FALSE; } // Last addon for (long kl = 1; kl < obj->pbox->nb_physvert; kl++) { if (kl != kk) { EERIE_3D pos; pos.x = (obj->pbox->vert[kk].pos.x + obj->pbox->vert[kl].pos.x) * DIV2; pos.y = (obj->pbox->vert[kk].pos.y + obj->pbox->vert[kl].pos.y) * DIV2; pos.z = (obj->pbox->vert[kk].pos.z + obj->pbox->vert[kl].pos.z) * DIV2; if ( (EEDistance3D(&ep->center, &pos) <= radd) || (EEDistance3D((EERIE_3D *)&ep->v[0], &pos) <= radd) || (EEDistance3D((EERIE_3D *)&ep->v[1], &pos) <= radd) || (EEDistance3D((EERIE_3D *)&ep->v[2], &pos) <= radd) || (Distance3D((ep->v[0].sx + ep->v[1].sx)*DIV2, (ep->v[0].sy + ep->v[1].sy)*DIV2, (ep->v[0].sz + ep->v[1].sz)*DIV2, pos.x, pos.y, pos.z) <= radd) || (Distance3D((ep->v[2].sx + ep->v[1].sx)*DIV2, (ep->v[2].sy + ep->v[1].sy)*DIV2, (ep->v[2].sz + ep->v[1].sz)*DIV2, pos.x, pos.y, pos.z) <= radd) || (Distance3D((ep->v[0].sx + ep->v[2].sx)*DIV2, (ep->v[0].sy + ep->v[2].sy)*DIV2, (ep->v[0].sz + ep->v[2].sz)*DIV2, pos.x, pos.y, pos.z) <= radd) ) { LAST_COLLISION_POLY = ep; if (ep->type & POLY_METAL) CUR_COLLISION_MATERIAL = MATERIAL_METAL; else if (ep->type & POLY_WOOD) CUR_COLLISION_MATERIAL = MATERIAL_WOOD; else if (ep->type & POLY_STONE) CUR_COLLISION_MATERIAL = MATERIAL_STONE; else if (ep->type & POLY_GRAVEL) CUR_COLLISION_MATERIAL = MATERIAL_GRAVEL; else if (ep->type & POLY_WATER) CUR_COLLISION_MATERIAL = MATERIAL_WATER; else if (ep->type & POLY_EARTH) CUR_COLLISION_MATERIAL = MATERIAL_EARTH; else CUR_COLLISION_MATERIAL = MATERIAL_STONE; return FALSE; } } } } if (_IsObjectVertexCollidingPoly(obj, ep, -1, NULL)) { LAST_COLLISION_POLY = ep; if (ep->type & POLY_METAL) CUR_COLLISION_MATERIAL = MATERIAL_METAL; else if (ep->type & POLY_WOOD) CUR_COLLISION_MATERIAL = MATERIAL_WOOD; else if (ep->type & POLY_STONE) CUR_COLLISION_MATERIAL = MATERIAL_STONE; else if (ep->type & POLY_GRAVEL) CUR_COLLISION_MATERIAL = MATERIAL_GRAVEL; else if (ep->type & POLY_WATER) CUR_COLLISION_MATERIAL = MATERIAL_WATER; else if (ep->type & POLY_EARTH) CUR_COLLISION_MATERIAL = MATERIAL_EARTH; else CUR_COLLISION_MATERIAL = MATERIAL_STONE; return FALSE; } } } } return ret; } BOOL ARX_EERIE_PHYSICS_BOX_Compute_Simple(EERIE_3DOBJ * obj, float framediff, float rubber, long flags, long source) { PHYSVERT * pv; long validd[32]; EERIE_3D oldpos[32]; long COUNT = 0; COUNT++; for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) { pv = &obj->pbox->vert[kk]; oldpos[kk].x = pv->pos.x; oldpos[kk].y = pv->pos.y; oldpos[kk].z = pv->pos.z; pv->inertia.x = 0.f; pv->inertia.y = 0.f; pv->inertia.z = 0.f; if (pv->velocity.x > VELOCITY_THRESHOLD) pv->velocity.x = VELOCITY_THRESHOLD; else if (pv->velocity.x < -VELOCITY_THRESHOLD) pv->velocity.x = -VELOCITY_THRESHOLD; if (pv->velocity.y > VELOCITY_THRESHOLD) pv->velocity.y = VELOCITY_THRESHOLD; else if (pv->velocity.y < -VELOCITY_THRESHOLD) pv->velocity.y = -VELOCITY_THRESHOLD; if (pv->velocity.z > VELOCITY_THRESHOLD) pv->velocity.z = VELOCITY_THRESHOLD; else if (pv->velocity.z < -VELOCITY_THRESHOLD) pv->velocity.z = -VELOCITY_THRESHOLD; validd[kk] = 1; } CUR_COLLISION_MATERIAL = MATERIAL_STONE; RK4Integrate(obj, framediff); PHYS_COLLIDER = -1; EERIE_SPHERE sphere; pv = &obj->pbox->vert[0]; sphere.origin.x = pv->pos.x; sphere.origin.y = pv->pos.y; sphere.origin.z = pv->pos.z; sphere.radius = obj->pbox->radius; long colidd = 0; for (int kk = 0; kk < obj->pbox->nb_physvert; kk += 2) { pv = &obj->pbox->vert[kk]; if (!IsValidPos3(&pv->pos)) { colidd = 1; break; } } if ((!_IsFULLObjectVertexInValidPosition(obj, flags, source, validd)) || ARX_INTERACTIVE_CheckFULLCollision(obj, source) || colidd || (IsObjectInField(obj, source)) ) { colidd = 1; float power = (EEfabs(obj->pbox->vert[0].velocity.x) + EEfabs(obj->pbox->vert[0].velocity.y) + EEfabs(obj->pbox->vert[0].velocity.z)) * DIV100; if (ValidIONum(source) && (inter.iobj[source]->ioflags & IO_BODY_CHUNK)) { } else ARX_TEMPORARY_TrySound(0.4f + power); if (!LAST_COLLISION_POLY) { for (long k = 0; k < obj->pbox->nb_physvert; k++) { pv = &obj->pbox->vert[k]; { pv->velocity.x *= -0.3f; pv->velocity.z *= -0.3f; pv->velocity.y *= -0.4f; } Vector_Copy(&pv->pos, &oldpos[k]); } } else { for (long k = 0; k < obj->pbox->nb_physvert; k++) { pv = &obj->pbox->vert[k]; float t = (LAST_COLLISION_POLY->norm.x) * (pv->velocity.x) + (LAST_COLLISION_POLY->norm.y) * (pv->velocity.y) + (LAST_COLLISION_POLY->norm.z) * (pv->velocity.z); float x = t * LAST_COLLISION_POLY->norm.x; float y = t * LAST_COLLISION_POLY->norm.y; float z = t * LAST_COLLISION_POLY->norm.z; pv->velocity.x = pv->velocity.x - 2.f * x; pv->velocity.y = pv->velocity.y - 2.f * y; pv->velocity.z = pv->velocity.z - 2.f * z; pv->velocity.x *= 0.3f; pv->velocity.z *= 0.3f; pv->velocity.y *= 0.4f; Vector_Copy(&pv->pos, &oldpos[k]); } } } if (colidd) { obj->pbox->stopcount += 1; } else { obj->pbox->stopcount -= 2; if (obj->pbox->stopcount < 0) obj->pbox->stopcount = 0; } return TRUE;//ret; } BOOL ARX_EERIE_PHYSICS_BOX_Compute(EERIE_3DOBJ * obj, float framediff, float rubber, long flags, long source) { return ARX_EERIE_PHYSICS_BOX_Compute_Simple(obj, framediff, rubber, flags, source); } extern void EERIE_PHYSICS_BOX_ComputeForces(EERIE_3DOBJ * obj); long ARX_PHYSICS_BOX_ApplyModel(EERIE_3DOBJ * obj, float framediff, float rubber, long flags, long source) { VELOCITY_THRESHOLD = 400.f; long ret = 0; if ((!obj) || (!obj->pbox)) return ret; if (obj->pbox->active == 2) return ret; if (framediff == 0.f) return ret; PHYSVERT * pv; // Memorizes initpos for (long k = 0; k < obj->pbox->nb_physvert; k++) { pv = &obj->pbox->vert[k]; pv->temp.x = pv->pos.x; pv->temp.y = pv->pos.y; pv->temp.z = pv->pos.z; } float timing = obj->pbox->storedtiming + framediff * rubber * 0.0055f; float t_threshold = 0.18f; if (timing < t_threshold) { obj->pbox->storedtiming = timing; return 1; } else { while (timing >= t_threshold) { ComputeForces(obj->pbox->vert, obj->pbox->nb_physvert); if (!ARX_EERIE_PHYSICS_BOX_Compute(obj, __min(0.11f, timing * 10), rubber, flags, source)) ret = 1; timing -= t_threshold; } obj->pbox->storedtiming = timing; } if (obj->pbox->stopcount < 16) return ret; obj->pbox->active = 2; obj->pbox->stopcount = 0; if (ValidIONum(source)) { inter.iobj[source]->soundcount = 0; inter.iobj[source]->soundtime = ARXTimeUL() + 2000; } return ret; } extern float my_CheckInPoly(float x, float y, float z, EERIEPOLY * mon_ep, EERIE_LIGHT * light); extern float GLOBAL_LIGHT_FACTOR; void ARX_EERIE_LIGHT_Make(EERIEPOLY * ep, float * epr, float * epg, float * epb, EERIE_LIGHT * light, EERIEPOLY * father) { int i; // iterator int nbvert; // number or vertices per face (3 or 4) float distance[4]; // distance from light to each vertex float fRes; // value of light intensity for a given vertex EERIE_3D vLight; // vector (light to vertex) EERIE_3D vNorm; // vector (interpolated normal of vertex) if (ep->type & POLY_IGNORE) return; (ep->type & POLY_QUAD) ? nbvert = 4 : nbvert = 3; // compute light - vertex distance for (i = 0; i < nbvert; i++) { distance[i] = TRUEEEDistance3D(&light->pos, (EERIE_3D *)&ep->v[i]); } for (i = 0; i < nbvert; i++) { fRes = 1.0f; if (distance[i] < light->fallend) { //---------------------- start MODE_NORMALS if (ModeLight & MODE_NORMALS) { vLight.x = light->pos.x - ep->v[i].sx; vLight.y = light->pos.y - ep->v[i].sy; vLight.z = light->pos.z - ep->v[i].sz; TRUEVector_Normalize(&vLight); vNorm.x = ep->nrml[i].x; vNorm.y = ep->nrml[i].y; vNorm.z = ep->nrml[i].z; fRes = Vector_DotProduct(&vLight, &vNorm); if (fRes < 0.0f) { fRes = 0.0f; } } //---------------------- end MODE_NORMALS //---------------------- start MODE_RAYLAUNCH if ((ModeLight & MODE_RAYLAUNCH) && !(light->extras & EXTRAS_NOCASTED)) { EERIE_3D orgn, dest, hit; orgn.x = light->pos.x; orgn.y = light->pos.y; orgn.z = light->pos.z; dest.x = ep->v[i].sx; dest.y = ep->v[i].sy; dest.z = ep->v[i].sz; if (ModeLight & MODE_SMOOTH) fRes *= my_CheckInPoly(ep->v[i].sx, ep->v[i].sy, ep->v[i].sz, ep, light); else fRes *= Visible(&orgn, &dest, ep, &hit); } //---------------------- fin MODE_RAYLAUNCH float fTemp1 = light->intensity * fRes * GLOBAL_LIGHT_FACTOR; float fr, fg, fb; if (distance[i] <= light->fallstart) { fr = light->rgb.r * fTemp1; fg = light->rgb.g * fTemp1; fb = light->rgb.b * fTemp1; } else { float intensity = (light->falldiff - (distance[i] - light->fallstart)) * light->falldiffmul; float fTemp2 = fTemp1 * intensity; fr = light->rgb.r * fTemp2; fg = light->rgb.g * fTemp2; fb = light->rgb.b * fTemp2; } epr[i] += fr; epg[i] += fg; epb[i] += fb; } } } void ARX_PrepareBackgroundNRMLs() { long i, j, k, mai, maj, mii, mij; long i2, j2, k2; EERIE_BKG_INFO * eg; EERIE_BKG_INFO * eg2; EERIEPOLY * ep; EERIEPOLY * ep2; EERIE_3D nrml; EERIE_3D cur_nrml; float count; long nbvert; long nbvert2; for (j = 0; j < ACTIVEBKG->Zsize; j++) for (i = 0; i < ACTIVEBKG->Xsize; i++) { eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize]; for (long l = 0; l < eg->nbpoly; l++) { ep = &eg->polydata[l]; if (ep->type & POLY_QUAD) nbvert = 4; else nbvert = 3; for (k = 0; k < nbvert; k++) { float ttt = 1.f; if (k == 3) { nrml.x = ep->norm2.x; nrml.y = ep->norm2.y; nrml.z = ep->norm2.z; count = 1.f; } else if ((k > 0) && (nbvert > 3)) { nrml.x = (ep->norm.x + ep->norm2.x); nrml.y = (ep->norm.y + ep->norm2.y); nrml.z = (ep->norm.z + ep->norm2.z); count = 2.f; ttt = DIV2; } else { nrml.x = ep->norm.x; nrml.y = ep->norm.y; nrml.z = ep->norm.z; count = 1.f; } cur_nrml.x = nrml.x * ttt; cur_nrml.y = nrml.y * ttt; cur_nrml.z = nrml.z * ttt; mai = i + 4; maj = j + 4; mii = i - 4; mij = j - 4; if (mij < 0) mij = 0; if (mii < 0) mii = 0; if (maj >= ACTIVEBKG->Zsize) maj = ACTIVEBKG->Zsize - 1; if (mai >= ACTIVEBKG->Xsize) mai = ACTIVEBKG->Xsize - 1; for (j2 = mij; j2 < maj; j2++) for (i2 = mii; i2 < mai; i2++) { eg2 = &ACTIVEBKG->Backg[i2+j2*ACTIVEBKG->Xsize]; for (long kr = 0; kr < eg2->nbpoly; kr++) { // continue; ep2 = &eg2->polydata[kr]; if (ep2->type & POLY_QUAD) nbvert2 = 4; else nbvert2 = 3; if (ep != ep2) for (k2 = 0; k2 < nbvert2; k2++) { if ((EEfabs(ep2->v[k2].sx - ep->v[k].sx) < 2.f) && (EEfabs(ep2->v[k2].sy - ep->v[k].sy) < 2.f) && (EEfabs(ep2->v[k2].sz - ep->v[k].sz) < 2.f)) { if (k2 == 3) { if (LittleAngularDiff(&cur_nrml, &ep2->norm2)) { nrml.x += ep2->norm2.x; nrml.y += ep2->norm2.y; nrml.z += ep2->norm2.z; count += 1.f; nrml.x += cur_nrml.x; nrml.y += cur_nrml.y; nrml.z += cur_nrml.z; count += 1.f; } } else if ((k2 > 0) && (nbvert2 > 3)) { EERIE_3D tnrml; tnrml.x = (ep2->norm.x + ep2->norm2.x) * DIV2; tnrml.y = (ep2->norm.y + ep2->norm2.y) * DIV2; tnrml.z = (ep2->norm.z + ep2->norm2.z) * DIV2; if (LittleAngularDiff(&cur_nrml, &tnrml)) { nrml.x += tnrml.x * 2.f; nrml.y += tnrml.y * 2.f; nrml.z += tnrml.z * 2.f; count += 2.f; } } else { if (LittleAngularDiff(&cur_nrml, &ep2->norm)) { nrml.x += ep2->norm.x; nrml.y += ep2->norm.y; nrml.z += ep2->norm.z; count += 1.f; } } } } } } count = 1.f / count; ep->tv[k].sx = nrml.x * count; ep->tv[k].sy = nrml.y * count; ep->tv[k].sz = nrml.z * count; } } } for (j = 0; j < ACTIVEBKG->Zsize; j++) for (i = 0; i < ACTIVEBKG->Xsize; i++) { eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize]; for (long l = 0; l < eg->nbpoly; l++) { ep = &eg->polydata[l]; if (ep->type & POLY_QUAD) nbvert = 4; else nbvert = 3; for (k = 0; k < nbvert; k++) { ep->nrml[k].x = ep->tv[k].sx; ep->nrml[k].y = ep->tv[k].sy; ep->nrml[k].z = ep->tv[k].sz; } float dist = 0.f; for (long ii = 0; ii < nbvert; ii++) { dist = __max(dist, TRUEEEDistance3D((EERIE_3D *)&ep->v[ii], &ep->center)); } ep->v[0].rhw = dist; } } } void EERIE_PHYSICS_BOX_Launch_NOCOL(INTERACTIVE_OBJ * io, EERIE_3DOBJ * obj, EERIE_3D * pos, EERIE_3D * vect, long flags, EERIE_3D * angle) { io->GameFlags |= GFLAG_NO_PHYS_IO_COL; EERIE_PHYSICS_BOX_Launch(obj, pos, vect, flags, angle); }