/* =========================================================================== 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_Interactive ////////////////////////////////////////////////////////////////////////////////////// // // Description: // ARX Interactive Objects Management // // Updates: (date) (person) (update) // // Code: Cyril Meynier // // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved ////////////////////////////////////////////////////////////////////////////////////// #define DIRECTINPUT_VERSION 0x0700 #include #include "ARX_Interactive.h" #include "ARX_PATHS.h" #include "ARX_FTL.h" #include "ARX_Equipment.h" #include "ARX_Sound.h" #include "ARX_Spells.h" #include "ARX_Levels.h" #include "ARX_NPC.h" #include "ARX_Collisions.h" #include "ARX_Changelevel.h" #include "ARX_Particles.h" #include "ARX_Damages.h" #include "ARX_Speech.h" #include "ARX_Script.h" #include "ARX_time.h" #include "ARX_scene.h" #include "ARX_menu2.h" #include "danaedlg.h" #include "HERMESMain.h" #include "EERIEAnim.h" #include "EERIELight.h" #include "EERIEObject.H" #include "EERIEPOLY.H" #include "EERIELinkedObj.h" #include "EERIECollisionSpheres.h" #include "EERIEPhysicsBox.h" #include "EERIEProgressive.h" #include "EERIEClothes.h" #include "EERIEDRAW.h" #include "EERIEMeshTweak.h" #include #define _CRTDBG_MAP_ALLOC #include extern EERIE_CAMERA TCAM[]; extern long FRAME_COUNT; #define BASE_RUBBER 1.5f extern INTERACTIVE_OBJ * CDP_EditIO; extern INTERACTIVE_OBJ * FlyingOverIO; extern INTERACTIVE_OBJ * CAMERACONTROLLER; extern TextureContainer * Movable; extern long NODIRCREATION; extern long SPECIAL_DRAW_INTER_SHADOW; extern long LOOK_AT_TARGET; extern long EXTERNALVIEW; extern long CURRENTLEVEL; extern long EDITMODE; extern long CYRIL_VERSION; extern long FINAL_RELEASE; extern long FOR_EXTERNAL_PEOPLE; extern long NEED_TEST_TEXT; ARX_NODES nodes; INTERACTIVE_OBJ * CURRENTINTER = NULL; INTERACTIVE_OBJECTS inter; float TREATZONE_LIMIT = 1800.f; long HERO_SHOW_1ST = 1; long TreatAllIO = 0; long INTREATZONECOUNT = 0; long NbIOSelected = 0; long LastSelectedIONum = -1; long INTERNMB = -1; long LASTINTERCLICKNB = -1; long FORCE_IO_INDEX = -1; long INTER_DRAW = 0; long INTER_COMPUTE = 0; long ForceIODraw = 0; float STARTED_ANGLE = 0; void Set_DragInter(INTERACTIVE_OBJ * io) { if (io != DRAGINTER) STARTED_ANGLE = player.angle.b; DRAGINTER = io; if (io) { if ((io->obj) && (io->obj->pbox)) { io->obj->pbox->active = 0; } } } //*********************************************************************************************** // ValidIONum // Checks if an IO index number is valid //----------------------------------------------------------------------------------------------- // VERIFIED (Cyril 2001/10/16) //*********************************************************************************************** long ValidIONum(long num) { if ((num < 0) || (num >= inter.nbmax) || (!inter.iobj) || (!inter.iobj[num])) { return 0; } return 1; } long ValidIOAddress(INTERACTIVE_OBJ * io) { if (!io) return 0; for (long i = 0; i < inter.nbmax; i++) { if (inter.iobj[i] == io) return 1; } return 0; } float ARX_INTERACTIVE_fGetPrice(INTERACTIVE_OBJ * io, INTERACTIVE_OBJ * shop) { if ((!io) || (!(io->ioflags & IO_ITEM))) return 0; float durability_ratio = io->durability / io->max_durability; float shop_multiply = 1.f; if (shop) shop_multiply = shop->shop_multiply; return io->_itemdata->price * shop_multiply * durability_ratio; } long ARX_INTERACTIVE_GetPrice(INTERACTIVE_OBJ * io, INTERACTIVE_OBJ * shop) { long lresult; F2L(ARX_INTERACTIVE_fGetPrice(io, shop), &lresult); return lresult; } void ARX_INTERACTIVE_ForceIOLeaveZone(INTERACTIVE_OBJ * io, long flags) { ARX_PATH * op = (ARX_PATH *)io->inzone; if (op) { char temp[256]; strcpy(temp, op->name); MakeUpcase(temp); if (flags & 1) // no need when being destroyed ! 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); } } } } extern long FAST_RELEASE; void ARX_INTERACTIVE_DestroyDynamicInfo(INTERACTIVE_OBJ * io) { if (!io) return; long n = GetInterNum(io); ARX_CHECK_SHORT(n); short sN = ARX_CLEAN_WARN_CAST_SHORT(n); ARX_INTERACTIVE_ForceIOLeaveZone(io, 0); for (long i = 0; i < MAX_EQUIPED; i++) { if ((player.equiped[i]) && (player.equiped[i] == n) && ValidIONum(player.equiped[i])) { ARX_EQUIPMENT_UnEquip(inter.iobj[0], inter.iobj[player.equiped[i]], 1); player.equiped[i] = 0; } } ARX_SPEECH_ReleaseIOSpeech(io); if (!FAST_RELEASE) EERIE_MESH_ReleaseTransPolys(io->obj); ARX_SCRIPT_EventStackClearForIo(io); if (ValidIONum(n)) { for (long i = 0; i < MAX_SPELLS; i++) { if ((spells[i].exist) && (spells[i].caster == n)) { spells[i].tolive = 0; } } } if (io->flarecount) { for (long i = 0; i < MAX_FLARES; i++) { if ((flare[i].exist) && (flare[i].io == io)) flare[i].io = NULL; } } if (io->ioflags & IO_NPC) { // to check again later... long count = 50; while ((io->_npcdata->pathfind.pathwait == 1) && count--) { Sleep(1); } if (io->_npcdata->pathfind.list) free(io->_npcdata->pathfind.list); memset(&io->_npcdata->pathfind, 0, sizeof(IO_PATHFIND)); } if (ValidDynLight(io->dynlight)) { DynLight[io->dynlight].exist = 0; } io->dynlight = -1; if (io->obj) { EERIE_3DOBJ * eobj = io->obj; for (long k = 0; k < eobj->nblinked; k++) { if ((eobj->linked[k].lgroup != -1) && eobj->linked[k].obj) { INTERACTIVE_OBJ * ioo = (INTERACTIVE_OBJ *)eobj->linked[k].io; if ((ioo) && ValidIOAddress(ioo)) { long ll = eobj->linked[k].lidx; EERIE_3D pos, vector; pos.x = io->obj->vertexlist3[ll].v.x; pos.y = io->obj->vertexlist3[ll].v.y; pos.z = io->obj->vertexlist3[ll].v.z; ioo->angle.a = rnd() * 40.f + 340.f; ioo->angle.b = rnd() * 360.f; ioo->angle.g = 0; vector.x = -(float)EEsin(DEG2RAD(ioo->angle.b)) * DIV2; vector.y = EEsin(DEG2RAD(ioo->angle.a)); vector.z = (float)EEcos(DEG2RAD(ioo->angle.b)) * DIV2; ioo->soundtime = 0; ioo->soundcount = 0; EERIE_PHYSICS_BOX_Launch_NOCOL(ioo, ioo->obj, &pos, &vector, 2, &ioo->angle); ioo->show = 1; ioo->no_collide = sN; EERIE_LINKEDOBJ_UnLinkObjectFromObject(io->obj, ioo->obj); } } } } } BOOL ARX_INTERACTIVE_Attach(long n_source, long n_target, char * ap_source, char * ap_target) { if (!ValidIONum(n_source) || !ValidIONum(n_target)) return FALSE; inter.iobj[n_source]->show = SHOW_FLAG_LINKED; EERIE_LINKEDOBJ_UnLinkObjectFromObject(inter.iobj[n_target]->obj, inter.iobj[n_source]->obj); return EERIE_LINKEDOBJ_LinkObjectToObject(inter.iobj[n_target]->obj, inter.iobj[n_source]->obj, ap_target, ap_source, inter.iobj[n_source]); } void ARX_INTERACTIVE_Detach(long n_source, long n_target) { if (!ValidIONum(n_source) || !ValidIONum(n_target)) return; inter.iobj[n_source]->show = SHOW_FLAG_IN_SCENE; EERIE_LINKEDOBJ_UnLinkObjectFromObject(inter.iobj[n_target]->obj, inter.iobj[n_source]->obj); } void ARX_INTERACTIVE_Show_Hide_1st(INTERACTIVE_OBJ * io, long state) { if ((!io) || (HERO_SHOW_1ST == state)) return; HERO_SHOW_1ST = state; long grp = EERIE_OBJECT_GetSelection(io->obj, "1st"); if (grp != -1) { for (long nn = 0; nn < io->obj->nbfaces; nn++) { EERIE_FACE * ef = &io->obj->facelist[nn]; for (long jj = 0; jj < 3; jj++) { if (IsInSelection(io->obj, ef->vid[jj], grp) != -1) { if (state) ef->facetype |= POLY_HIDE; else ef->facetype &= ~POLY_HIDE; break; } } } } ARX_INTERACTIVE_HideGore(inter.iobj[0], 1); } void ARX_INTERACTIVE_RemoveGoreOnIO(INTERACTIVE_OBJ * io) { if ((!io) || (!io->obj) || (!io->obj->texturecontainer)) return; long gorenum = -1; for (long nn = 0; nn < io->obj->nbmaps; nn++) { if (io->obj->texturecontainer[nn] && TextureContainer_Exist(io->obj->texturecontainer[nn]) && strstr(io->obj->texturecontainer[nn]->m_strName, "GORE")) { gorenum = nn; break; } } if (gorenum > -1) for (long nn = 0; nn < io->obj->nbfaces; nn++) { if (io->obj->facelist[nn].texid == gorenum) { io->obj->facelist[nn].facetype |= POLY_HIDE; io->obj->facelist[nn].texid = -1; } } } // flag & 1 == no unhide non-gore void ARX_INTERACTIVE_HideGore(INTERACTIVE_OBJ * io, long flag) { if ((!io) || (!io->obj) || (!io->obj->texturecontainer)) return; if ((io == inter.iobj[0]) && (!flag & 1)) return; long gorenum = -1; for (long nn = 0; nn < io->obj->nbmaps; nn++) { if (io->obj->texturecontainer[nn] && TextureContainer_Exist(io->obj->texturecontainer[nn]) && strstr(io->obj->texturecontainer[nn]->m_strName, "GORE")) { gorenum = nn; break; } } if (gorenum > -1) for (long nn = 0; nn < io->obj->nbfaces; nn++) { //Hide Gore Polys... if (io->obj->facelist[nn].texid == gorenum) io->obj->facelist[nn].facetype |= POLY_HIDE; else if (!flag & 1) io->obj->facelist[nn].facetype &= ~POLY_HIDE; } } extern long GORE_MODE; EERIE_3DOBJ * GetExistingEerie(char * file) { for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i] != NULL) && (!inter.iobj[i]->tweaky) && (inter.iobj[i]->obj)) { if ((!inter.iobj[i]->obj->originaltextures) && (!strcmp(file, inter.iobj[i]->obj->file))) { return inter.iobj[i]->obj; } } } return NULL; } BOOL ForceNPC_Above_Ground(INTERACTIVE_OBJ * io) { if (io && (io->ioflags & IO_NPC) && !(io->ioflags & IO_PHYSICAL_OFF)) { io->physics.cyl.origin.x = io->pos.x; io->physics.cyl.origin.y = io->pos.y; io->physics.cyl.origin.z = io->pos.z; AttemptValidCylinderPos(&io->physics.cyl, io, CFLAG_NO_INTERCOL); { if (EEfabs(io->pos.y - io->physics.cyl.origin.y) < 45.f) { io->pos.y = io->physics.cyl.origin.y; return TRUE; } else return FALSE; } } return FALSE; } EERIE_3DOBJ * TheoToEerie_Fast(char * texpath, char * ficc, long flag, LPDIRECT3DDEVICE7 pd3dDevice) { char fic[256]; char pfic[256]; File_Standardize(ficc, fic); File_Standardize(fic + strlen(Project.workingdir) - 1, pfic); EERIE_3DOBJ * ret = NULL; if ((ret = ARX_FTL_Load(pfic, fic, NULL)) != NULL) { if (!(flag & TTE_NO_PHYSICS_BOX)) EERIE_PHYSICS_BOX_Create(ret); return ret; } if (ret = GetExistingEerie(fic)) { ret = Eerie_Copy(ret); if (!ret) goto alternateway; } else { alternateway: ; long FileSize = 0; unsigned char * adr; if (adr = (unsigned char *)PAK_FileLoadMalloc(fic, &FileSize)) { ret = TheoToEerie(adr, FileSize, texpath, fic, flag, pd3dDevice, flag | TTE_NO_RESTORE); //SLOWLOAD)); if (!ret) { free(adr); return NULL; } EERIE_OBJECT_CenterObjectCoordinates(ret); free(adr); } else return NULL; } if (FASTLOADS) { if ((ret) && (ret->pdata)) { free(ret->pdata); ret->pdata = NULL; } return ret; } if ((ret) && (!(flag & TTE_NO_PDATA))) { CreateNeighbours(ret); EERIEOBJECT_AddProgressiveData(ret); EERIEOBJECT_AddClothesData(ret); KillNeighbours(ret); if (ret->cdata) EERIE_COLLISION_SPHERES_Create(ret); // Must be out of the Neighbours zone if (!(flag & TTE_NO_PHYSICS_BOX)) EERIE_PHYSICS_BOX_Create(ret); ARX_FTL_Save(pfic, fic, ret); } return ret; } //************************************************************************************* // Unlinks all linked objects from all IOs //************************************************************************************* void UnlinkAllLinkedObjects() { for (long i = 0; i < inter.nbmax; i++) { if (inter.iobj[i]) { EERIE_LINKEDOBJ_ReleaseData(inter.iobj[i]->obj); } } } void IO_UnlinkAllLinkedObjects(INTERACTIVE_OBJ * io) { if (io && io->obj) { for (long k = 0; k < io->obj->nblinked; k++) { if (io->obj->linked[k].io) { INTERACTIVE_OBJ * ioo = (INTERACTIVE_OBJ *)io->obj->linked[k].io; if (ValidIOAddress(ioo)) IO_Drop_Item(io, ioo); } } EERIE_LINKEDOBJ_ReleaseData(io->obj); } } // First is always the player TREATZONE_IO * treatio = NULL; long TREATZONE_CUR = 0; long TREATZONE_MAX = 0; void TREATZONE_Clear() { TREATZONE_CUR = 0; } void TREATZONE_Release() { if (treatio) free(treatio); treatio = NULL; TREATZONE_MAX = 0; TREATZONE_CUR = 0; } void TREATZONE_RemoveIO(INTERACTIVE_OBJ * io) { if (treatio) { for (long i = 0; i < TREATZONE_CUR; i++) { if (treatio[i].io == io) { treatio[i].io = NULL; treatio[i].ioflags = 0; treatio[i].show = 0; } } } } // flag & 1 IO_JUST_COLLIDE void TREATZONE_AddIO(INTERACTIVE_OBJ * io, long num, long flag) { if (TREATZONE_MAX == TREATZONE_CUR) { TREATZONE_MAX++; treatio = (TREATZONE_IO *)realloc(treatio, sizeof(TREATZONE_IO) * TREATZONE_MAX); } for (long i = 0; i < TREATZONE_CUR; i++) { if (treatio[i].io == io) return; } treatio[TREATZONE_CUR].io = io; treatio[TREATZONE_CUR].ioflags = io->ioflags; if (flag & 1) treatio[TREATZONE_CUR].ioflags |= IO_JUST_COLLIDE; treatio[TREATZONE_CUR].show = io->show; treatio[TREATZONE_CUR].num = num; TREATZONE_CUR++; } void CheckSetAnimOutOfTreatZone(INTERACTIVE_OBJ * io, long num) { if ((io) && (io->animlayer[num].cur_anim) && !(io->GameFlags & GFLAG_ISINTREATZONE) && (EEDistance3D(&io->pos, &ACTIVECAM->pos) > 2500.f)) { ARX_CHECK_LONG(io->animlayer[num].cur_anim->anims[ io->animlayer[num].altidx_cur ]->anim_time - 1); io->animlayer[num].ctime = ARX_CLEAN_WARN_CAST_LONG(io->animlayer[num].cur_anim->anims[ io->animlayer[num].altidx_cur ]->anim_time - 1); } } long GLOBAL_Player_Room = -1; extern float fZFogEnd; void PrepareIOTreatZone(long flag) { static long status = -1; static EERIE_3D lastpos; if ((flag) || (status == -1)) { status = 0; lastpos.x = ACTIVECAM->pos.x; lastpos.y = ACTIVECAM->pos.y; lastpos.z = ACTIVECAM->pos.z; } else if (status == 3) status = 0; if (EEDistance3D(&ACTIVECAM->pos, &lastpos) > 100.f) { status = 0; lastpos.x = ACTIVECAM->pos.x; lastpos.y = ACTIVECAM->pos.y; lastpos.z = ACTIVECAM->pos.z; } if (status++) return; TREATZONE_Clear(); long Cam_Room = ARX_PORTALS_GetRoomNumForPosition(&ACTIVECAM->pos, 1); GLOBAL_Player_Room = ARX_PORTALS_GetRoomNumForPosition(&player.pos, 1); TREATZONE_AddIO(inter.iobj[0], 0, 0); ARX_CHECK_SHORT(GLOBAL_Player_Room); short sGlobalPlayerRoom = ARX_CLEAN_WARN_CAST_SHORT(GLOBAL_Player_Room); for (long i = 0; i < MAX_EQUIPED; i++) { if ((player.equiped[i] != 0) && ValidIONum(player.equiped[i])) { INTERACTIVE_OBJ * toequip = inter.iobj[player.equiped[i]]; if (toequip) { toequip->room = sGlobalPlayerRoom; toequip->room_flags = 0; } } } if (DRAGINTER) TREATZONE_AddIO(DRAGINTER, GetInterNum(DRAGINTER), 0); TREATZONE_LIMIT = 3200; if (RoomDistance) { TREATZONE_LIMIT += 600; if (CURRENTLEVEL == 4) TREATZONE_LIMIT += 1200; if (ACTIVECAM->cdepth > 3000) TREATZONE_LIMIT += 500; if (ACTIVECAM->cdepth > 4000) TREATZONE_LIMIT += 500; if (ACTIVECAM->cdepth > 6000) TREATZONE_LIMIT += 500; } INTREATZONECOUNT = 0; if (TreatAllIO) { for (long ii = 1; ii < inter.nbmax; ii++) { INTERACTIVE_OBJ * io = inter.iobj[ii]; if (io) { io->GameFlags |= GFLAG_ISINTREATZONE; TREATZONE_AddIO(io, ii, 0); } } return; } char treat; for (int i = 1; i < inter.nbmax; i++) { INTERACTIVE_OBJ * io = inter.iobj[i]; if ((io) && ((io->show == SHOW_FLAG_IN_SCENE) || (io->show == SHOW_FLAG_TELEPORTING) || (io->show == SHOW_FLAG_ON_PLAYER) || (io->show == SHOW_FLAG_HIDDEN))) { if ((io->ioflags & IO_CAMERA) && (!EDITMODE)) treat = 0; else if ((io->ioflags & IO_MARKER) && (!EDITMODE)) treat = 0; else if ((io->ioflags & IO_NPC) && (io->_npcdata->pathfind.flags & PATHFIND_ALWAYS)) { treat = 1; } else { float dist; if (Cam_Room >= 0) { if (io->show == SHOW_FLAG_TELEPORTING) { EERIE_3D pos; GetItemWorldPosition(io, &pos); dist = EEDistance3D(&ACTIVECAM->pos, &pos); } else { if (io->room_flags & 1) UpdateIORoom(io); dist = SP_GetRoomDist(&io->pos, &ACTIVECAM->pos, io->room, Cam_Room); } } else { if (io->show == SHOW_FLAG_TELEPORTING) { EERIE_3D pos; GetItemWorldPosition(io, &pos); dist = EEDistance3D(&ACTIVECAM->pos, &pos); //&io->pos,&pos); } else dist = EEDistance3D(&io->pos, &ACTIVECAM->pos); } if (dist < TREATZONE_LIMIT) treat = 1; else treat = 0; } if (!treat) { if (io == CAMERACONTROLLER) treat = 1; if (io == DRAGINTER) treat = 1; } if (io->GameFlags & GFLAG_ISINTREATZONE) io->GameFlags |= GFLAG_WASINTREATZONE; else io->GameFlags &= ~GFLAG_WASINTREATZONE; if (treat) { INTREATZONECOUNT++; io->GameFlags |= GFLAG_ISINTREATZONE; TREATZONE_AddIO(io, i, 0); if ((io->ioflags & IO_NPC) && (io->_npcdata->weapon)) { INTERACTIVE_OBJ * iooo = (INTERACTIVE_OBJ *)io->_npcdata->weapon; iooo->room = io->room; iooo->room_flags = io->room_flags; } } else io->GameFlags &= ~GFLAG_ISINTREATZONE; EVENT_SENDER = NULL; if ((io->GameFlags & GFLAG_ISINTREATZONE) && (!(io->GameFlags & GFLAG_WASINTREATZONE))) { //coming back; doesn't really matter right now // SendIOScriptEvent(inter.iobj[i],SM_TREATIN,""); } else if ((!(io->GameFlags & GFLAG_ISINTREATZONE)) && (io->GameFlags & GFLAG_WASINTREATZONE)) { //going away; io->GameFlags |= GFLAG_ISINTREATZONE; if (SendIOScriptEvent(io, SM_TREATOUT, "") != REFUSE) { if (io->ioflags & IO_NPC) io->_npcdata->pathfind.flags &= ~PATHFIND_ALWAYS; io->GameFlags &= ~GFLAG_ISINTREATZONE; } } } } long M_TREAT = TREATZONE_CUR; for (int i = 1; i < inter.nbmax; i++) { INTERACTIVE_OBJ * io = inter.iobj[i]; if ((io != NULL) && !(io->GameFlags & GFLAG_ISINTREATZONE) && ((io->show == SHOW_FLAG_IN_SCENE) || (io->show == SHOW_FLAG_TELEPORTING) || (io->show == SHOW_FLAG_ON_PLAYER) || (io->show == SHOW_FLAG_HIDDEN))) // show 5 = ininventory; 15 = destroyed { if ((io->ioflags & IO_CAMERA) || (io->ioflags & IO_ITEM) || (io->ioflags & IO_MARKER)) continue; long toadd = 0; for (long ii = 1; ii < M_TREAT; ii++) { INTERACTIVE_OBJ * ioo = treatio[ii].io; if (ioo) { if (EEDistance3D(&io->pos, &ioo->pos) < 300.f) { toadd = 1; break; } } } if (toadd) TREATZONE_AddIO(io, i, 1); } } } //************************************************************************************* //************************************************************************************* long GetNumNodeByName(char * name) { for (long i = 0; i < nodes.nbmax; i++) { if ((nodes.nodes[i].exist) && (!strcmp(name, nodes.nodes[i].name))) return i; } return -1; } //************************************************************************************* //************************************************************************************* void RestoreNodeNumbers() { for (long i = 0; i < nodes.nbmax; i++) for (long j = 0; j < MAX_LINKS; j++) { if (nodes.nodes[i].lnames[j][0] != 0) { nodes.nodes[i].link[j] = GetNumNodeByName(nodes.nodes[i].lnames[j]); } } } //************************************************************************************* //************************************************************************************* void ClearNode(long i, long first = 0) { nodes.nodes[i].exist = 0; nodes.nodes[i].selected = 0; for (long j = 0; j < MAX_LINKS; j++) { if ((nodes.nodes[i].link[j] != -1) && (!first)) { long k = nodes.nodes[i].link[j]; for (long l = 0; l < MAX_LINKS; l++) if (nodes.nodes[k].link[l] == i) nodes.nodes[k].link[l] = -1; } nodes.nodes[i].lnames[j][0] = 0; nodes.nodes[i].link[j] = -1; } strcpy(nodes.nodes[i].name, ""); nodes.nodes[i].pos.z = nodes.nodes[i].pos.y = nodes.nodes[i].pos.x = 0.f; } //************************************************************************************* //************************************************************************************* void ClearNodes() { static long first = 1; for (long i = 0; i < nodes.nbmax; i++) { ClearNode(i, first); } first = 0; } //************************************************************************************* //************************************************************************************* void SelectNode(long i) { if ((i >= nodes.nbmax) || (i < 0)) return; if (nodes.nodes[i].exist) nodes.nodes[i].selected = 1; } //************************************************************************************* //************************************************************************************* void UnselectAllNodes() { for (long i = 0; i < nodes.nbmax; i++) { if (nodes.nodes[i].exist) nodes.nodes[i].selected = 0; } } //************************************************************************************* //************************************************************************************* void TranslateSelectedNodes(EERIE_3D * trans) { for (long i = 0; i < nodes.nbmax; i++) { if ((nodes.nodes[i].exist) && (nodes.nodes[i].selected)) { nodes.nodes[i].pos.x += trans->x; nodes.nodes[i].pos.y += trans->y; nodes.nodes[i].pos.z += trans->z; } } } //************************************************************************************* //************************************************************************************* BOOL IsLinkedNode(long i, long j) { if ((!nodes.nodes[i].exist) || (!nodes.nodes[j].exist)) return FALSE; for (long k = 0; k < MAX_LINKS; k++) { if (nodes.nodes[i].link[k] == j) return TRUE; } return FALSE; } //************************************************************************************* //************************************************************************************* long CountNodes() { register long count = 0; for (long i = 0; i < nodes.nbmax; i++) { if (nodes.nodes[i].exist) { count++; } } return count; } //************************************************************************************* //************************************************************************************* void AddLink(long i, long j) { if ((!nodes.nodes[i].exist) || (!nodes.nodes[j].exist)) return; for (long k = 0; k < MAX_LINKS; k++) { if (nodes.nodes[i].link[k] == -1) { nodes.nodes[i].link[k] = j; return; } } } //************************************************************************************* //************************************************************************************* void RemoveLink(long i, long j) { if ((!nodes.nodes[i].exist) || (!nodes.nodes[j].exist)) return; for (long k = 0; k < MAX_LINKS; k++) { if (nodes.nodes[i].link[k] == j) { nodes.nodes[i].link[k] = -1; return; } } } //************************************************************************************* //************************************************************************************* void LinkNodeToNode(long i, long j) { if ((!IsLinkedNode(i, j)) || (!IsLinkedNode(j, i))) return; AddLink(i, j); AddLink(j, i); } //************************************************************************************* //************************************************************************************* void UnLinkNodeFromNode(long i, long j) { if ((!IsLinkedNode(i, j)) || (!IsLinkedNode(j, i))) return; RemoveLink(i, j); RemoveLink(j, i); } //************************************************************************************* //************************************************************************************* void ClearSelectedNodes() { for (long i = 0; i < nodes.nbmax; i++) { if ((nodes.nodes[i].exist) && (nodes.nodes[i].selected)) { ClearNode(i, 0); } } } //************************************************************************************* //************************************************************************************* BOOL ExistNodeName(char * name) { for (long i = 0; i < nodes.nbmax; i++) { if ((nodes.nodes[i].exist) && (!strcmp(name, nodes.nodes[i].name))) return TRUE; } return FALSE; } //************************************************************************************* //************************************************************************************* void MakeNodeName(long i) { char name[64]; long o; //float f; sprintf(name, "NODE_%08d", i); while (ExistNodeName(name)) { //f=rnd()*99999999.f; //o=(long)f; F2L(rnd() * 99999999.f, &o); sprintf(name, "NODE_%08d", o); } strcpy(nodes.nodes[i].name, name); } //************************************************************************************* //************************************************************************************* void InitNodes(long nb) { if (nb < 1) nb = 1; nodes.init = 1; nodes.nbmax = nb; nodes.nodes = (ARX_NODE *)malloc(sizeof(ARX_NODE) * nodes.nbmax); //"NODES Structure" memset(nodes.nodes, 0, sizeof(ARX_NODE)*nodes.nbmax); ClearNodes(); } //************************************************************************************* //************************************************************************************* long GetFreeNode() { for (long i = 0; i < nodes.nbmax; i++) { if (!nodes.nodes[i].exist) return i; } return -1; } //************************************************************************************* //************************************************************************************* //----------------------------------------------------------------------------- void ReleaseNode() { if (nodes.nodes) { free((void *)nodes.nodes); nodes.nbmax = 0; nodes.nodes = NULL; } } //************************************************************************************* // Initialises Interactive Objects Main Structure (pointer list) //************************************************************************************* void InitInter(long nb) { if (nb < 10) nb = 10; inter.nbmax = nb; if (inter.init) { free(inter.iobj); inter.iobj = NULL; } inter.init = 1; inter.iobj = (INTERACTIVE_OBJ **)malloc(sizeof(INTERACTIVE_OBJ *) * inter.nbmax); //,"Interactive Objects Structure"); memset(inter.iobj, 0, sizeof(INTERACTIVE_OBJ *)*inter.nbmax); } //************************************************************************************* // Removes an IO loaded by a script command //************************************************************************************* void CleanScriptLoadedIO() { for (long i = 1; i < inter.nbmax; i++) { if (inter.iobj[i] != NULL) { INTERACTIVE_OBJ * io = inter.iobj[i]; if (io->scriptload) { RemoveFromAllInventories(io); ReleaseInter(inter.iobj[i]); inter.iobj[i] = NULL; } else inter.iobj[i]->show = SHOW_FLAG_IN_SCENE; } } } //************************************************************************************* // Restores an IO to its initial status (Game start Status) //************************************************************************************* void RestoreInitialIOStatus() { long i = 0; ARX_INTERACTIVE_HideGore(inter.iobj[0]); ARX_NPC_Behaviour_ResetAll(); if (inter.iobj[0]) inter.iobj[0]->spellcast_data.castingspell = -1; for (i = 1; i < inter.nbmax; i++) { RestoreInitialIOStatusOfIO(inter.iobj[i]); } } void ARX_INTERACTIVE_USEMESH(INTERACTIVE_OBJ * io, char * temp) { if ((!io) || (!temp)) return; char tex[256]; char tex1[256]; char tex2[256]; if (io->ioflags & IO_NPC) sprintf(tex2, "%sGraph\\Obj3D\\Interactive\\NPC\\%s", Project.workingdir, temp); else if (io->ioflags & IO_FIX) sprintf(tex2, "%sGraph\\Obj3D\\Interactive\\FIX_INTER\\%s", Project.workingdir, temp); else if (io->ioflags & IO_ITEM) sprintf(tex2, "%sGraph\\Obj3D\\Interactive\\Items\\%s", Project.workingdir, temp); else tex2[0] = 0; File_Standardize(tex2, tex); if (tex[0] != 0) { if (io->usemesh == NULL) io->usemesh = (char *)malloc(256); else if (!stricmp(io->usemesh, tex)) return; //already tweaked with this mesh ! strcpy(io->usemesh, tex); if (io->obj != NULL) { ReleaseEERIE3DObj(io->obj); io->obj = NULL; } char tex2[256]; sprintf(tex2, "%sGraph\\Obj3D\\Textures\\", Project.workingdir); File_Standardize(tex2, tex1); if (io->ioflags & IO_FIX) io->obj = TheoToEerie_Fast(tex1, tex, TTE_NO_NDATA | TTE_NO_PHYSICS_BOX, GDevice); else if (io->ioflags & IO_NPC) io->obj = TheoToEerie_Fast(tex1, tex, TTE_NO_PHYSICS_BOX | TTE_NPC, GDevice); else io->obj = TheoToEerie_Fast(tex1, tex, 0, GDevice); EERIE_COLLISION_Cylinder_Create(io); } } void ARX_INTERACTIVE_MEMO_TWEAK_CLEAR(INTERACTIVE_OBJ * io) { if (io->Tweaks) free(io->Tweaks); io->Tweaks = NULL; io->Tweak_nb = 0; } void ARX_INTERACTIVE_MEMO_TWEAK(INTERACTIVE_OBJ * io, long type, char * param1, char * param2) { io->Tweaks = (TWEAK_INFO *)realloc(io->Tweaks, sizeof(TWEAK_INFO) * (io->Tweak_nb + 1)); memset(&io->Tweaks[io->Tweak_nb], 0, sizeof(TWEAK_INFO)); io->Tweaks[io->Tweak_nb].type = type; if (param1) strcpy(io->Tweaks[io->Tweak_nb].param1, param1); if (param2) strcpy(io->Tweaks[io->Tweak_nb].param2, param2); io->Tweak_nb++; } void ARX_INTERACTIVE_APPLY_TWEAK_INFO(INTERACTIVE_OBJ * io) { for (long ii = 0; ii < io->Tweak_nb; ii++) { if (io->Tweaks[ii].type == TWEAK_REMOVE) EERIE_MESH_TWEAK_Do(io, TWEAK_REMOVE, NULL); else if (io->Tweaks[ii].type == TWEAK_TYPE_SKIN) EERIE_MESH_TWEAK_Skin(io->obj, io->Tweaks[ii].param1, io->Tweaks[ii].param2); else if (io->Tweaks[ii].type == TWEAK_TYPE_ICON) ARX_INTERACTIVE_TWEAK_Icon(io, io->Tweaks[ii].param1); else if (io->Tweaks[ii].type == TWEAK_TYPE_MESH) ARX_INTERACTIVE_USEMESH(io, io->Tweaks[ii].param1); else { char temp[256]; sprintf(temp, "%s%s", Project.workingdir, io->Tweaks[ii].param1); EERIE_MESH_TWEAK_Do(io, io->Tweaks[ii].type, temp); } } } void ARX_INTERACTIVE_ClearIODynData(INTERACTIVE_OBJ * io) { if (io) { if (ValidDynLight(io->dynlight)) DynLight[io->dynlight].exist = 0; io->dynlight = -1; if (ValidDynLight(io->halo.dynlight)) DynLight[io->halo.dynlight].exist = 0; io->halo.dynlight = -1; if (io->symboldraw) free(io->symboldraw); io->symboldraw = NULL; io->spellcast_data.castingspell = -1; } } void ARX_INTERACTIVE_ClearIODynData_II(INTERACTIVE_OBJ * io) { if (io) { // ARX_SCRIPT_Timer_Clear_For_IO(io); if (ValidDynLight(io->dynlight)) DynLight[io->dynlight].exist = 0; io->dynlight = -1; if (ValidDynLight(io->halo.dynlight)) DynLight[io->halo.dynlight].exist = 0; io->halo.dynlight = -1; if (io->symboldraw) free(io->symboldraw); io->symboldraw = NULL; io->spellcast_data.castingspell = -1; if (io->shop_category) free(io->shop_category); io->shop_category = NULL; if (io->inventory_skin) free(io->inventory_skin); io->inventory_skin = NULL; ARX_INTERACTIVE_MEMO_TWEAK_CLEAR(io); ARX_IOGROUP_Release(io); ARX_INTERACTIVE_HideGore(io); MOLLESS_Clear(io->obj); ARX_SCRIPT_Timer_Clear_For_IO(io); if (io->stepmaterial) free(io->stepmaterial); io->stepmaterial = NULL; if (io->armormaterial) free(io->armormaterial); io->armormaterial = NULL; if (io->weaponmaterial) free(io->weaponmaterial); io->weaponmaterial = NULL; if (io->strikespeech) free(io->strikespeech); io->strikespeech = NULL; if (io->lastanimvertex) free(io->lastanimvertex); io->lastanimvertex = NULL; io->nb_lastanimvertex = 0; for (long j = 0; j < MAX_ANIMS; j++) { EERIE_ANIMMANAGER_ReleaseHandle(io->anims[j]); io->anims[j] = NULL; } ARX_SPELLS_RemoveAllSpellsOn(io); ARX_EQUIPMENT_ReleaseAll(io); if (io->ioflags & IO_NPC) { if (io->_npcdata->pathfind.list) free(io->_npcdata->pathfind.list); io->_npcdata->pathfind.list = NULL; memset(&io->_npcdata->pathfind, 0, sizeof(IO_PATHFIND)); io->_npcdata->pathfind.truetarget = -1; io->_npcdata->pathfind.listnb = -1; ARX_NPC_Behaviour_Reset(io); } if (io->tweakerinfo != NULL) { free(io->tweakerinfo); io->tweakerinfo = NULL; } if (io->inventory != NULL) { INVENTORY_DATA * id = (INVENTORY_DATA *)io->inventory; for (long nj = 0; nj < id->sizey; nj++) for (long ni = 0; ni < id->sizex; ni++) { if (id->slot[ni][nj].io != NULL) { long tmp = GetInterNum(id->slot[ni][nj].io); if (ValidIONum(tmp)) { if (inter.iobj[tmp]->scriptload) { RemoveFromAllInventories(inter.iobj[tmp]); ReleaseInter(inter.iobj[tmp]); inter.iobj[tmp] = NULL; } else inter.iobj[tmp]->show = SHOW_FLAG_KILLED; } id->slot[ni][nj].io = NULL; } } if ((TSecondaryInventory) && (TSecondaryInventory->io == io)) { TSecondaryInventory = NULL; } free(io->inventory); io->inventory = NULL; } io->inventory = NULL; io->GameFlags |= GFLAG_INTERACTIVITY; if (io->tweaky) { ReleaseEERIE3DObj(io->obj); io->obj = io->tweaky; io->tweaky = NULL; } } } void ARX_INTERACTIVE_ClearAllDynData() { long i = 0; ARX_INTERACTIVE_HideGore(inter.iobj[0]); ARX_NPC_Behaviour_ResetAll(); for (i = 1; i < inter.nbmax; i++) { ARX_INTERACTIVE_ClearIODynData(inter.iobj[i]); } } void RestoreIOInitPos(INTERACTIVE_OBJ * io) { if (io) { ARX_INTERACTIVE_Teleport(io, &io->initpos, 0); io->pos.x = io->lastpos.x = io->initpos.x; io->pos.y = io->lastpos.y = io->initpos.y; io->pos.z = io->lastpos.z = io->initpos.z; io->move.x = io->move.y = io->move.z = 0.f; io->lastmove.x = io->lastmove.y = io->lastmove.z = 0.f; io->angle.a = io->initangle.a; io->angle.b = io->initangle.b; io->angle.g = io->initangle.g; } } void RestoreAllIOInitPos() { for (long i = 1; i < inter.nbmax; i++) { RestoreIOInitPos(inter.iobj[i]); } } void ARX_HALO_SetToNative(INTERACTIVE_OBJ * io) { io->halo.color.r = io->halo_native.color.r; io->halo.color.g = io->halo_native.color.g; io->halo.color.b = io->halo_native.color.b; io->halo.radius = io->halo_native.radius; io->halo.flags = io->halo_native.flags; } void RestoreInitialIOStatusOfIO(INTERACTIVE_OBJ * io) { if (io) { ARX_INTERACTIVE_ClearIODynData_II(io); io->shop_multiply = 1.f; ARX_INTERACTIVE_HideGore(io, 1); io->halo_native.color.r = 0.2f; io->halo_native.color.g = 0.5f; io->halo_native.color.b = 1.f; io->halo_native.radius = 45.f; io->halo_native.flags = 0; ARX_HALO_SetToNative(io); io->halo.dynlight = -1; io->level = io->truelevel; Vector_Init(&io->forcedmove); io->ioflags &= ~IO_NO_COLLISIONS; io->ioflags &= ~IO_INVERTED; io->lastspeechflag = 2; //HALO_NEGATIVE; io->no_collide = -1; for (long i = 0; i < MAX_FLARES; i++) { if ((flare[i].exist) && (flare[i].io == io)) { flare[i].io = NULL; } } io->flarecount = 0; io->inzone = NULL; io->speed_modif = 0.f; io->basespeed = 1.f; io->frameloss = 0.f; io->sfx_flag = 0; io->max_durability = io->durability = 100; io->GameFlags &= ~GFLAG_INVISIBILITY; io->GameFlags &= ~GFLAG_MEGAHIDE; io->GameFlags &= ~GFLAG_NOGORE; io->GameFlags &= ~GFLAG_ISINTREATZONE; io->GameFlags &= ~GFLAG_PLATFORM; io->GameFlags &= ~GFLAG_ELEVATOR; io->GameFlags &= ~GFLAG_HIDEWEAPON; io->GameFlags &= ~GFLAG_NOCOMPUTATION; io->GameFlags &= ~GFLAG_INTERACTIVITYHIDE; io->GameFlags &= ~GFLAG_DOOR; io->GameFlags &= ~GFLAG_GOREEXPLODE; io->invisibility = 0.f; io->rubber = BASE_RUBBER; io->scale = 1.f; Vector_Init(&io->move); io->type_flags = 0; io->sound = -1; io->soundtime = 0; io->soundcount = 0; io->material = 11; io->collide_door_time = 0; io->ouch_time = 0; io->dmg_sum = 0; io->ignition = 0.f; io->ignit_light = -1; io->ignit_sound = ARX_SOUND_INVALID_RESOURCE; if ((io->obj) && (io->obj->pbox)) io->obj->pbox->active = 0; io->room = -1; io->room_flags = 1; RestoreIOInitPos(io); ARX_INTERACTIVE_Teleport(io, &io->initpos, 0); io->lastanimtime = 1; io->secretvalue = -1; if (io->damagedata >= 0) damages[io->damagedata].exist = 0; io->damagedata = -1; io->poisonous = 0; io->poisonous_count = 0; for (long count = 0; count < MAX_ANIM_LAYERS; count++) { memset(&io->animlayer[count], 0, sizeof(ANIM_USE)); io->animlayer[count].cur_anim = NULL; io->animlayer[count].next_anim = NULL; } if ((io->obj) && (io->obj->pbox)) { io->obj->pbox->storedtiming = 0; } io->physics.cyl.origin.x = io->pos.x; io->physics.cyl.origin.y = io->pos.y; io->physics.cyl.origin.z = io->pos.z; io->physics.cyl.radius = io->original_radius; io->physics.cyl.height = io->original_height; io->fall = 0; io->show = SHOW_FLAG_IN_SCENE; io->targetinfo = TARGET_NONE; io->spellcast_data.castingspell = -1; io->summoner = -1; io->spark_n_blood = 0; if (io->ioflags & IO_NPC) { io->_npcdata->climb_count = 0; io->_npcdata->vvpos = -99999.f; io->_npcdata->SPLAT_DAMAGES = 0; io->_npcdata->speakpitch = 1.f; io->_npcdata->behavior = BEHAVIOUR_NONE; io->_npcdata->cut = 0; io->_npcdata->cuts = 0; io->_npcdata->poisonned = 0.f; io->_npcdata->blood_color = 0xFFFF0000; io->_npcdata->stare_factor = 1.f; io->_npcdata->weapon = NULL; io->_npcdata->weaponname[0] = 0; io->_npcdata->weaponinhand = 0; io->_npcdata->weapontype = 0; io->_npcdata->weaponinhand = 0; io->_npcdata->fightdecision = 0; io->_npcdata->collid_state = 0; io->_npcdata->collid_time = 0; io->_npcdata->strike_time = 0; io->_npcdata->walk_start_time = 0; io->_npcdata->reachedtarget = 0; io->_npcdata->maxlife = 20.f; io->_npcdata->life = io->_npcdata->maxlife; io->_npcdata->maxmana = 10.f; io->_npcdata->mana = io->_npcdata->mana; io->_npcdata->critical = 5.f; io->infracolor.r = 1.f; io->infracolor.g = 0.f; io->infracolor.b = 0.2f; io->_npcdata->detect = 0; io->_npcdata->movemode = 0; io->_npcdata->reach = 20.f; io->_npcdata->armor_class = 0; io->_npcdata->absorb = 0; io->_npcdata->damages = 20; io->_npcdata->tohit = 50; io->_npcdata->aimtime = 0; io->_npcdata->aiming_start = 0; io->_npcdata->npcflags = 0; io->_npcdata->backstab_skill = 0; io->_npcdata->fDetect = -1; } if (io->ioflags & IO_ITEM) { io->collision = 1; io->_itemdata->count = 1; io->_itemdata->maxcount = 1; io->_itemdata->food_value = 0; io->_itemdata->playerstacksize = 1; io->_itemdata->stealvalue = -1; io->_itemdata->LightValue = -1; } else io->collision = 0; if (io->ioflags & IO_FIX) { memset(io->_fixdata, 0, sizeof(IO_FIXDATA)); io->_fixdata->trapvalue = -1; } } } void ARX_INTERACTIVE_TWEAK_Icon(INTERACTIVE_OBJ * io, char * s1) { if ((!io) || (!s1)) return; char icontochange[HERMES_PATH_SIZE]; sprintf(icontochange, io->filename); RemoveName(icontochange); strcat(icontochange, s1); SetExt(icontochange, ".bmp"); D3DTextr_CreateTextureFromFile(icontochange, Project.workingdir, 0, D3DTEXTR_NO_REFINEMENT, EERIETEXTUREFLAG_LOADSCENE_RELEASE); if (GDevice) D3DTextr_Restore(icontochange, GDevice); TextureContainer * tc; tc = D3DTextr_GetSurfaceContainer(icontochange); if (tc == NULL) { MakeDir(icontochange, "Graph\\Interface\\misc\\Default[Icon].bmp"); D3DTextr_CreateTextureFromFile(icontochange, Project.workingdir, 0, D3DTEXTR_NO_REFINEMENT); if (GDevice) D3DTextr_Restore(icontochange, GDevice); tc = D3DTextr_GetSurfaceContainer(icontochange); } if (tc != NULL) { unsigned long w = tc->m_dwWidth >> 5; unsigned long h = tc->m_dwHeight >> 5; if ((w << 5) != tc->m_dwWidth) io->sizex = (char)(w + 1); else io->sizex = (char)(w); if ((h << 5) != tc->m_dwHeight) io->sizey = (char)(h + 1); else io->sizey = (char)(h); if (io->sizex < 1) io->sizex = 1; else if (io->sizex > 3) io->sizex = 3; if (io->sizey < 1) io->sizey = 1; else if (io->sizey > 3) io->sizey = 3; io->inv = tc; } } //************************************************************************************* // Count IO number ignoring ScriptLoaded IOs //************************************************************************************* long GetNumberInterWithOutScriptLoadForLevel(long level) { register long count = 0; for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i] != NULL) && (!inter.iobj[i]->scriptload) && (inter.iobj[i]->truelevel == level)) count++; } return count; } //************************************************************************************* // Clears All Inter From Memory //************************************************************************************* void FreeAllInter() { for (long i = 1; i < inter.nbmax; i++) //ignoring Player. { if (inter.iobj[i] != NULL) { ReleaseInter(inter.iobj[i]); inter.iobj[i] = NULL; } } inter.nbmax = 1; inter.iobj = (INTERACTIVE_OBJ **)realloc(inter.iobj, sizeof(INTERACTIVE_OBJ *) * inter.nbmax); } //************************************************************************************* // Creates a new free Interactive Object //************************************************************************************* INTERACTIVE_OBJ * CreateFreeInter(long num) { long i; long tocreate = -1; if (num == 0) //used to create player { tocreate = 0; if (inter.iobj[0] != NULL) return NULL; goto create; } if (FORCE_IO_INDEX != -1) tocreate = FORCE_IO_INDEX; else for (i = 1; i < inter.nbmax; i++) // ignoring player { if (!inter.iobj[i]) { tocreate = i; break; } } if (tocreate == -1) { inter.nbmax++; inter.iobj = (INTERACTIVE_OBJ **)realloc(inter.iobj, sizeof(INTERACTIVE_OBJ *) * inter.nbmax); tocreate = inter.nbmax - 1; inter.iobj[tocreate] = NULL; } if (tocreate != -1) { create: ; i = tocreate; INTERACTIVE_OBJ * io; //todo free retry_allocation: ; inter.iobj[i] = (INTERACTIVE_OBJ *)malloc(sizeof(INTERACTIVE_OBJ)); if (!inter.iobj[i]) { if (HERMES_Memory_Emergency_Out(sizeof(INTERACTIVE_OBJ), "Interactive_Object_Alloc")) goto retry_allocation; } memset(inter.iobj[i], 0, sizeof(INTERACTIVE_OBJ)); io = inter.iobj[i]; io->room_flags = 1; io->room = -1; io->no_collide = -1; io->shop_multiply = 1.f; io->Tweaks = NULL; io->Tweak_nb = 0; io->ignition = 0.f; io->ignit_light = -1; io->ignit_sound = ARX_SOUND_INVALID_RESOURCE; if (CURRENTLEVEL == -1) CURRENTLEVEL = GetLevelNumByName(LastLoadedScene); io->truelevel = io->level = (short)CURRENTLEVEL; io->usemesh = NULL; io->lastspeechflag = 2; io->damagedata = -1; io->flarecount = 0; io->rubber = BASE_RUBBER; io->halo_native.color.r = 0.2f; io->halo_native.color.g = 0.5f; io->halo_native.color.b = 1.f; io->halo_native.radius = 45.f; io->halo_native.flags = 0; io->halo_native.dynlight = -1; ARX_HALO_SetToNative(io); io->halo.dynlight = -1; io->symboldraw = NULL; io->dynlight = -1; io->sfx_flag = 0; io->max_durability = io->durability = 100.f; io->speed_modif = 0.f; io->basespeed = 1.f; io->frameloss = 0.f; io->GameFlags |= GFLAG_NEEDINIT; io->poisonous = 0; io->poisonous_count = 0; io->secretvalue = -1; // Already set to 0 by memset io->infracolor.b = 1.f; io->show = SHOW_FLAG_IN_SCENE; io->sound = -1; io->sizex = 1; io->sizey = 1; io->GameFlags |= GFLAG_INTERACTIVITY; io->scale = 1.f; io->stopped = 1; io->changeanim = -1; io->bbox1.x = -1; io->bbox1.y = -1; io->bbox2.x = -1; io->bbox2.y = -1; ARX_SCRIPT_SetMainEvent(io, "MAIN"); io->targetinfo = TARGET_NONE; io->weight = 1.f; memset(io->animlayer, 0, sizeof(ANIM_USE)*MAX_ANIM_LAYERS); FORCE_IO_INDEX = -1; return (io); } FORCE_IO_INDEX = -1; return NULL; } // Be careful with this func... INTERACTIVE_OBJ * CloneIOItem(INTERACTIVE_OBJ * src) { INTERACTIVE_OBJ * dest; dest = AddItem(GDevice, src->filename); if (!dest) return NULL; SendInitScriptEvent(dest); dest->inv = src->inv; dest->sizex = src->sizex; dest->sizey = src->sizey; ReleaseEERIE3DObj(dest->obj); dest->obj = Eerie_Copy(src->obj); CloneLocalVars(dest, src); dest->_itemdata->price = src->_itemdata->price; dest->_itemdata->maxcount = src->_itemdata->maxcount; dest->_itemdata->count = src->_itemdata->count; dest->_itemdata->food_value = src->_itemdata->food_value; dest->_itemdata->stealvalue = src->_itemdata->stealvalue; dest->_itemdata->playerstacksize = src->_itemdata->playerstacksize; dest->_itemdata->LightValue = src->_itemdata->LightValue; if (src->_itemdata->equipitem) { dest->_itemdata->equipitem = (IO_EQUIPITEM *)malloc(sizeof(IO_EQUIPITEM)); memcpy(dest->_itemdata->equipitem, src->_itemdata->equipitem, sizeof(IO_EQUIPITEM)); } strcpy(dest->locname, src->locname); if ((dest->obj->pbox == NULL) && (src->obj->pbox)) { dest->obj->pbox = (PHYSICS_BOX_DATA *)malloc(sizeof(PHYSICS_BOX_DATA)); memcpy(dest->obj->pbox, src->obj->pbox, sizeof(PHYSICS_BOX_DATA)); dest->obj->pbox->vert = (PHYSVERT *)malloc(sizeof(PHYSVERT) * src->obj->pbox->nb_physvert); memcpy(dest->obj->pbox->vert, src->obj->pbox->vert, sizeof(PHYSVERT)*src->obj->pbox->nb_physvert); } return dest; } bool ARX_INTERACTIVE_ConvertToValidPosForIO(INTERACTIVE_OBJ * io, EERIE_3D * target) { EERIE_CYLINDER phys; if (io && (io != inter.iobj[0])) { phys.height = io->original_height * io->scale; phys.radius = io->original_radius * io->scale; } else { phys.height = -200; phys.radius = 50; } phys.origin.x = target->x; phys.origin.y = target->y; phys.origin.z = target->z; long count = 0; float modx, modz; while (count < 600) { modx = -EEsin(count) * (float)count * DIV3; modz = EEcos(count) * (float)count * DIV3; phys.origin.x = target->x + modx; phys.origin.z = target->z + modz; float anything = CheckAnythingInCylinder(&phys, io, CFLAG_JUST_TEST); if (EEfabs(anything) < 150.f) { EERIEPOLY * ep = CheckInPoly(phys.origin.x, phys.origin.y + anything - 20.f, phys.origin.z); EERIEPOLY * ep2 = CheckTopPoly(phys.origin.x, phys.origin.y + anything, phys.origin.z); if (ep && ep2 && (EEfabs((phys.origin.y + anything) - ep->center.y) < 20.f)) { target->x = phys.origin.x; target->y = phys.origin.y + anything; target->z = phys.origin.z; return true; } } count += 5; } return false; } void ARX_INTERACTIVE_TeleportBehindTarget(INTERACTIVE_OBJ * io) { if (!io) return; if (ARX_SCRIPT_GetSystemIOScript(io, "_R_A_T_") < 0) { long num = ARX_SCRIPT_Timer_GetFree(); if (num != -1) { long t = GetInterNum(io); ActiveTimers++; scr_timer[num].es = NULL; scr_timer[num].exist = 1; scr_timer[num].io = io; F2L(rnd() * 3000 + 3000, &scr_timer[num].msecs); scr_timer[num].namelength = 8; scr_timer[num].name = (char *)malloc(8); strcpy(scr_timer[num].name, "_R_A_T_"); scr_timer[num].pos = -1; scr_timer[num].tim = ARXTimeUL(); scr_timer[num].times = 1; inter.iobj[t]->show = SHOW_FLAG_TELEPORTING; AddRandomSmoke(io, 10); ARX_PARTICLES_Add_Smoke(&io->pos, 3, 20); EERIE_3D pos; pos.x = inter.iobj[t]->pos.x; pos.y = inter.iobj[t]->pos.y + inter.iobj[t]->physics.cyl.height * DIV2; pos.z = inter.iobj[t]->pos.z; io->room_flags |= 1; io->room = -1; ARX_PARTICLES_Add_Smoke(&pos, 3, 20); MakeCoolFx(&io->pos); io->GameFlags |= GFLAG_INVISIBILITY; FRAME_COUNT = 0; } } } void ResetVVPos(INTERACTIVE_OBJ * io) { if ((io) && (io->ioflags & IO_NPC)) io->_npcdata->vvpos = io->pos.y; } void ComputeVVPos(INTERACTIVE_OBJ * io) { if (io->ioflags & IO_NPC) { float vvp = io->_npcdata->vvpos; if ((vvp == -99999.f) || (vvp == io->pos.y)) { io->_npcdata->vvpos = io->pos.y; return; } float diff = io->pos.y - vvp; float fdiff = EEfabs(diff); float eediff = fdiff; float mul = 1.f; if (fdiff > 120.f) { fdiff = 120.f; } else { mul = ((fdiff * DIV120) * 0.9f + 0.6f); if ((eediff < 15.f)) { float val = (float)FrameDiff * DIV4 * mul; if (eediff < 10.f) val *= DIV10; else { float ratio = (eediff - 10.f) * DIV5; val = val * ratio + val * (1.f - ratio); } fdiff -= val; } else { fdiff -= (float)FrameDiff * DIV4 * mul; } } if (fdiff > eediff) fdiff = eediff; if (fdiff < 0.f) fdiff = 0.f; if (diff < 0.f) io->_npcdata->vvpos = io->pos.y + fdiff; else io->_npcdata->vvpos = io->pos.y - fdiff; } } long FLAG_ALLOW_CLOTHES = 1; void ARX_INTERACTIVE_Teleport(INTERACTIVE_OBJ * io, EERIE_3D * target, long flags) { if (!io) return; FRAME_COUNT = -1; EERIE_3D translate; io->GameFlags &= ~GFLAG_NOCOMPUTATION; io->room_flags |= 1; io->room = -1; if (io == inter.iobj[0]) { moveto.x = player.pos.x = target->x; moveto.y = player.pos.y = target->y + PLAYER_BASE_HEIGHT; moveto.z = player.pos.z = target->z; } translate.x = target->x - io->pos.x; translate.y = target->y - io->pos.y; translate.z = target->z - io->pos.z; // In case it is being dragged... (except for drag teleport update) if (!flags & 1) { if (io == DRAGINTER) Set_DragInter(NULL); } io->pos.x += translate.x; io->pos.y += translate.y; if (io->ioflags & IO_NPC) io->_npcdata->vvpos = io->pos.y; io->pos.z += translate.z; io->lastpos.x = io->physics.cyl.origin.x = io->pos.x; io->lastpos.y = io->physics.cyl.origin.y = io->pos.y; io->lastpos.z = io->physics.cyl.origin.z = io->pos.z; if (io->obj) { if (io->obj->pbox) { if (io->obj->pbox->active) { for (long i = 0; i < io->obj->pbox->nb_physvert; i++) { io->obj->pbox->vert[i].pos.x += translate.x; io->obj->pbox->vert[i].pos.y += translate.y; io->obj->pbox->vert[i].pos.z += translate.z; } io->obj->pbox->active = 0; } } for (long i = 0; i < io->obj->nbvertex; i++) { io->obj->vertexlist3[i].v.x += translate.x; io->obj->vertexlist3[i].v.y += translate.y; io->obj->vertexlist3[i].v.z += translate.z; } } MOLLESS_Clear(io->obj, 1); ResetVVPos(io); } //************************************************************************************* // Finds IO number by name //************************************************************************************* long GetTargetByNameTarget(char * name) { char temp[256]; if (name == NULL) return -1; if (!stricmp(name, "self")) return -2; if (!stricmp(name, "none")) return -1; if (!stricmp(name, "me")) return -2; if (!stricmp(name, "player")) return 0; ///player is now an io with index 0 for (long i = 0 ; i < inter.nbmax ; i++) { if ((inter.iobj[i] != NULL) && (inter.iobj[i]->ident > -1)) { sprintf(temp, "%s_%04d", GetName(inter.iobj[i]->filename), inter.iobj[i]->ident); if (!stricmp(name, temp)) return i; } } return -1; } extern long TOTAL_BODY_CHUNKS_COUNT; //************************************************************************************* // Releases An Interactive Object from memory //************************************************************************************* void ReleaseInter(INTERACTIVE_OBJ * io) { if (!io) return; if (!FAST_RELEASE) TREATZONE_RemoveIO(io); if (io->ioflags & IO_BODY_CHUNK) { TOTAL_BODY_CHUNKS_COUNT--; if (TOTAL_BODY_CHUNKS_COUNT < 0) TOTAL_BODY_CHUNKS_COUNT = 0; } if (io->ignit_light > -1) { DynLight[io->ignit_light].exist = 0; io->ignit_light = -1; } if (io->ignit_sound != ARX_SOUND_INVALID_RESOURCE) { ARX_SOUND_Stop(io->ignit_sound); io->ignit_sound = ARX_SOUND_INVALID_RESOURCE; } if (io == FlyingOverIO) FlyingOverIO = NULL; if ((MasterCamera.exist & 1) && (MasterCamera.io == io)) MasterCamera.exist = 0; if ((MasterCamera.exist & 2) && (MasterCamera.want_io == io)) MasterCamera.exist = 0; InterTreeViewItemRemove(io); ARX_INTERACTIVE_DestroyDynamicInfo(io); IO_UnlinkAllLinkedObjects(io); // Releases "ToBeDrawn" Transparent Polys linked to this object ! ARX_INTERACTIVE_MEMO_TWEAK_CLEAR(io); ARX_SCRIPT_Timer_Clear_For_IO(io); if ((io->obj) && (!(io->ioflags & IO_CAMERA)) && (!(io->ioflags & IO_MARKER)) && (!(io->ioflags & IO_GOLD))) { ReleaseEERIE3DObj(io->obj); io->obj = NULL; } ARX_SPELLS_RemoveAllSpellsOn(io); if (io->tweakerinfo != NULL) { free(io->tweakerinfo); io->tweakerinfo = NULL; } if (io->tweaky) { ReleaseEERIE3DObj(io->tweaky); io->tweaky = NULL; } for (long iNbBag = 0; iNbBag < 3; iNbBag++) for (long j = 0; j < INVENTORY_Y; j++) for (long i = 0; i < INVENTORY_X; i++) { if (inventory[iNbBag][i][j].io == io) inventory[iNbBag][i][j].io = NULL; } ReleaseScript(&io->script); ReleaseScript(&io->over_script); for (long n = 0; n < MAX_ANIMS; n++) { if (io->anims[n] != NULL) { EERIE_ANIMMANAGER_ReleaseHandle(io->anims[n]); io->anims[n] = NULL; } } if (io->shop_category) free(io->shop_category); if (io->inventory_skin) free(io->inventory_skin); if (io->damagedata >= 0) damages[io->damagedata].exist = 0; ARX_IOGROUP_Release(io); if (io->usemesh) free(io->usemesh); if (ValidDynLight(io->dynlight)) DynLight[io->dynlight].exist = 0; io->dynlight = -1; if (ValidDynLight(io->halo.dynlight)) DynLight[io->halo.dynlight].exist = 0; io->halo.dynlight = -1; if (io->lastanimvertex) free(io->lastanimvertex); if (io->usepath) free(io->usepath); if (io->symboldraw != NULL) { free(io->symboldraw); io->symboldraw = NULL; } if (io->ioflags & IO_NPC) { if (io->_npcdata->ex_rotate != NULL) free(io->_npcdata->ex_rotate); if (io->_npcdata->pathfind.list) free(io->_npcdata->pathfind.list); free(io->_npcdata); } if (io->ioflags & IO_ITEM) { if (io->_itemdata->equipitem) free(io->_itemdata->equipitem); io->_itemdata->equipitem = NULL; } if (io->ioflags & IO_FIX) free(io->_fixdata); if (io->ioflags & IO_ITEM) free(io->_itemdata); if (io->ioflags & IO_CAMERA) { if (io->_camdata) { void * ptr = (void *)ACTIVECAM; if (ptr == io->_camdata) ACTIVECAM = &subj; free(io->_camdata); } io->_camdata = NULL; } if ((TSecondaryInventory) && (TSecondaryInventory->io == io)) { TSecondaryInventory = NULL; } if (io->inventory != NULL) free(io->inventory); if (io->weaponmaterial) free(io->weaponmaterial); if (io->strikespeech) free(io->strikespeech); if (io->stepmaterial) free(io->stepmaterial); if (io->armormaterial) free(io->armormaterial); long ion = GetInterNum(io); if (ion > -1) inter.iobj[ion] = NULL; free(io);// io = NULL; } //*********************************************************************************** // AddInteractive: // Adds an Interactive Object to the Scene // Calls appropriate func depending on object Type (ITEM, NPC or FIX) // Creates an IO Ident for added object if necessary // flags can be IO_IMMEDIATELOAD (1) to FORCE loading //*********************************************************************************** INTERACTIVE_OBJ * AddInteractive(LPDIRECT3DDEVICE7 pd3dDevice, char * file, long id, long flags) { INTERACTIVE_OBJ * io = NULL; char ficc[HERMES_PATH_SIZE]; strcpy(ficc, file); MakeUpcase(ficc); if (IsIn(ficc, "ITEMS")) io = AddItem(pd3dDevice, file, flags); else if (IsIn(ficc, "NPC")) io = AddNPC(pd3dDevice, file, flags); else if (IsIn(ficc, "FIX")) io = AddFix(pd3dDevice, file, flags); else if (IsIn(ficc, "CAMERA")) io = AddCamera(pd3dDevice, file); else if (IsIn(ficc, "MARKER")) io = AddMarker(pd3dDevice, file); if (io) { if ((id == 0) && !(flags & NO_IDENT)) MakeIOIdent(io); else if (id == -1) MakeTemporaryIOIdent(io); else io->ident = id; } return io; } //*********************************************************************************** // SetWeapon: // Links an object designed by path "temp" to the primary attach of interactive object // "io". //*********************************************************************************** void SetWeapon_On(INTERACTIVE_OBJ * io) { if ((!io) && !(io->ioflags & IO_NPC)) return; INTERACTIVE_OBJ * ioo = (INTERACTIVE_OBJ *)io->_npcdata->weapon; if ((ioo) && (ioo->obj)) { EERIE_LINKEDOBJ_UnLinkObjectFromObject(io->obj, ioo->obj); EERIE_LINKEDOBJ_LinkObjectToObject(io->obj, ioo->obj, "PRIMARY_ATTACH", "PRIMARY_ATTACH", ioo); } } void SetWeapon_Back(INTERACTIVE_OBJ * io) { if (!io || !(io->ioflags & IO_NPC)) return; INTERACTIVE_OBJ * ioo = (INTERACTIVE_OBJ *)io->_npcdata->weapon; if ((ioo) && (ioo->obj)) { EERIE_LINKEDOBJ_UnLinkObjectFromObject(io->obj, ioo->obj); if (io->GameFlags & GFLAG_HIDEWEAPON) return; long ni = io->obj->fastaccess.weapon_attach; if (ni >= 0) EERIE_LINKEDOBJ_LinkObjectToObject(io->obj, ioo->obj, "WEAPON_ATTACH", "PRIMARY_ATTACH", ioo); else { ni = io->obj->fastaccess.secondary_attach; if (ni >= 0) EERIE_LINKEDOBJ_LinkObjectToObject(io->obj, ioo->obj, "SECONDARY_ATTACH", "PRIMARY_ATTACH", ioo); } } } void Prepare_SetWeapon(INTERACTIVE_OBJ * io, char * temp) { if (!io || !(io->ioflags & IO_NPC)) return; if (io->_npcdata->weapon) { INTERACTIVE_OBJ * ioo = (INTERACTIVE_OBJ *)io->_npcdata->weapon; EERIE_LINKEDOBJ_UnLinkObjectFromObject(io->obj, ioo->obj); io->_npcdata->weapon = NULL; ReleaseInter(ioo); } char tex[256]; char tex1[256]; char tx[256]; MakeDir(tex1, "Graph\\Obj3D\\Interactive\\Items\\Weapons\\"); sprintf(tx, "%s\\%s\\%s.teo", tex1, temp, temp); File_Standardize(tx, tex); io->_npcdata->weapon = AddItem(GDevice, tex, IO_IMMEDIATELOAD); INTERACTIVE_OBJ * ioo = (INTERACTIVE_OBJ *)io->_npcdata->weapon; if (ioo) { MakeTemporaryIOIdent(ioo); SendIOScriptEvent(ioo, SM_INIT, "", NULL); SendIOScriptEvent(ioo, SM_INITEND, "", NULL); io->_npcdata->weapontype = ioo->type_flags; ioo->show = SHOW_FLAG_LINKED; ioo->scriptload = 2; SetWeapon_Back(io); } } void GetIOScript(INTERACTIVE_OBJ * io, char * texscript) { if (PAK_FileExist(texscript)) { long FileSize = 0; io->script.data = (char *)PAK_FileLoadMallocZero(texscript, &FileSize); if (io->script.data) { io->script.size = FileSize; InitScript(&io->script); } } else { io->script.size = 0; io->script.data = NULL; } } //*********************************************************************************** // Links an Interactive Object to another interactive object using an attach point //*********************************************************************************** void LinkObjToMe(INTERACTIVE_OBJ * io, INTERACTIVE_OBJ * io2, char * attach) { if ((!io) || (!io2)) return; RemoveFromAllInventories(io2); io2->show = SHOW_FLAG_LINKED; EERIE_LINKEDOBJ_LinkObjectToObject(io->obj, io2->obj, attach, attach, io2); } //*********************************************************************************** // AddFix // Adds a FIX INTERACTIVE OBJECT to the Scene //*********************************************************************************** INTERACTIVE_OBJ * AddFix(LPDIRECT3DDEVICE7 pd3dDevice, char * file, long flags) { char tex1[HERMES_PATH_SIZE]; char tex5[HERMES_PATH_SIZE]; char texscript[HERMES_PATH_SIZE]; strcpy(texscript, file); SetExt(texscript, "asl"); sprintf(tex1, file); SetExt(tex1, "teo"); char file2[256]; sprintf(file2, "%sGAME\\%s", Project.workingdir, file + strlen(Project.workingdir)); SetExt(file2, ".FTL"); if (!PAK_FileExist(file2) && !PAK_FileExist(file)) { return NULL; } char texx[HERMES_PATH_SIZE]; sprintf(texx, "AddFix - %s", file); SendConsole(texx, 2, 0, (HWND)g_pD3DApp->m_hWnd); INTERACTIVE_OBJ * io = CreateFreeInter(); if (!io) return NULL; io->_fixdata = (IO_FIXDATA *)malloc(sizeof(IO_FIXDATA)); //"IO FIXdata" memset(io->_fixdata, 0, sizeof(IO_FIXDATA)); io->ioflags = IO_FIX; io->_fixdata->trapvalue = -1; GetIOScript(io, texscript); if (!(flags & NO_ON_LOAD)) SendIOScriptEvent(io, SM_LOAD, "", NULL); io->spellcast_data.castingspell = -1; io->lastpos.x = io->initpos.x = io->pos.x = player.pos.x - (float)EEsin(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.y = io->initpos.y = io->pos.y = player.pos.y; io->lastpos.z = io->initpos.z = io->pos.z = player.pos.z + (float)EEcos(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.x = io->initpos.x = (float)((long)(io->initpos.x / 20)) * 20.f; io->lastpos.z = io->initpos.z = (float)((long)(io->initpos.z / 20)) * 20.f; EERIEPOLY * ep; ep = CheckInPoly(io->pos.x, io->pos.y + PLAYER_BASE_HEIGHT, io->pos.z); if (ep) { float tempo; if (GetTruePolyY(ep, &io->pos, &tempo)) io->lastpos.y = io->initpos.y = io->pos.y = tempo; } ep = CheckInPoly(io->pos.x, player.pos.y, io->pos.z); if (ep) { io->pos.y = __min(ep->v[0].sy, ep->v[1].sy); io->lastpos.y = io->initpos.y = io->pos.y = __min(io->pos.y, ep->v[2].sy); } strcpy(io->filename, tex1); if (!io->obj) { if (flags & NO_MESH) { io->obj = NULL; } else { strcpy(tex5, tex1); sprintf(tex1, "%sGraph\\Obj3D\\Textures\\", Project.workingdir); io->obj = TheoToEerie_Fast(tex1, tex5, TTE_NO_PHYSICS_BOX, GDevice); } } io->infracolor.r = 0.6f; io->infracolor.g = 0.f; io->infracolor.b = 1.f; TextureContainer * tc; tc = MakeTCFromFile_NoRefinement("Graph\\Interface\\misc\\Default[Icon].bmp"); if (tc) { if (!tc->m_pddsSurface) tc->Restore(pd3dDevice); unsigned long w = tc->m_dwWidth >> 5; unsigned long h = tc->m_dwHeight >> 5; if ((w << 5) != tc->m_dwWidth) io->sizex = (char)(w + 1); else io->sizex = (char)(w); if ((h << 5) != tc->m_dwHeight) io->sizey = (char)(h + 1); else io->sizey = (char)(h); if (io->sizex < 1) io->sizex = 1; else if (io->sizex > 3) io->sizex = 3; if (io->sizey < 1) io->sizey = 1; else if (io->sizey > 3) io->sizey = 3; io->inv = tc; } io->collision = 1; if (CheckScriptSyntax_Loading(io) != TRUE) io->ioflags |= IO_FREEZESCRIPT; return io; } //*********************************************************************************** // AddCamera // Adds a CAMERA INTERACTIVE OBJECT to the Scene //*********************************************************************************** INTERACTIVE_OBJ * AddCamera(LPDIRECT3DDEVICE7 pd3dDevice, char * file) { char tex1[HERMES_PATH_SIZE]; char texscript[HERMES_PATH_SIZE]; strcpy(texscript, file); SetExt(texscript, "asl"); sprintf(tex1, file); SetExt(tex1, "teo"); char file2[256]; sprintf(file2, "%sGAME\\%s", Project.workingdir, file + strlen(Project.workingdir)); SetExt(file2, ".FTL"); if (!PAK_FileExist(file2) && !PAK_FileExist(file)) { return NULL; } char texx[HERMES_PATH_SIZE]; sprintf(texx, "AddCamera - %s", file); SendConsole(texx, 2, 0, (HWND)g_pD3DApp->m_hWnd); INTERACTIVE_OBJ * io = CreateFreeInter(); EERIEPOLY * ep; if (!io) return NULL; GetIOScript(io, texscript); io->lastpos.x = io->initpos.x = io->pos.x = player.pos.x - (float)EEsin(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.y = io->initpos.y = io->pos.y = player.pos.y; io->lastpos.z = io->initpos.z = io->pos.z = player.pos.z + (float)EEcos(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.x = io->initpos.x = (float)((long)(io->initpos.x / 20)) * 20.f; io->lastpos.z = io->initpos.z = (float)((long)(io->initpos.z / 20)) * 20.f; float tempo; ep = CheckInPoly(io->pos.x, io->pos.y + PLAYER_BASE_HEIGHT, io->pos.z, &tempo); if (ep) { io->lastpos.y = io->initpos.y = io->pos.y = tempo; } ep = CheckInPoly(io->pos.x, player.pos.y, io->pos.z); if (ep) { io->pos.y = __min(ep->v[0].sy, ep->v[1].sy); io->lastpos.y = io->initpos.y = io->pos.y = __min(io->pos.y, ep->v[2].sy); } io->lastpos.y = io->initpos.y = io->pos.y += PLAYER_BASE_HEIGHT; strcpy(io->filename, tex1); io->obj = cameraobj; io->_camdata = (IO_CAMDATA *)malloc(sizeof(IO_CAMDATA)); memcpy(&io->_camdata->cam, &subj, sizeof(EERIE_CAMERA)); io->_camdata->cam.focal = 350.f; io->ioflags = IO_CAMERA; io->collision = 0; if (CheckScriptSyntax_Loading(io) != TRUE) io->ioflags |= IO_FREEZESCRIPT; return io; } //*********************************************************************************** // AddMarker // Adds a MARKER INTERACTIVE OBJECT to the Scene //*********************************************************************************** INTERACTIVE_OBJ * AddMarker(LPDIRECT3DDEVICE7 pd3dDevice, char * file) { char tex1[HERMES_PATH_SIZE]; char texscript[HERMES_PATH_SIZE]; strcpy(texscript, file); SetExt(texscript, "asl"); sprintf(tex1, file); SetExt(tex1, "teo"); char file2[256]; sprintf(file2, "%sGAME\\%s", Project.workingdir, file + strlen(Project.workingdir)); SetExt(file2, ".FTL"); if (!PAK_FileExist(file2) && !PAK_FileExist(file)) { return NULL; } char texx[HERMES_PATH_SIZE]; sprintf(texx, "AddMarker - %s", file); SendConsole(texx, 2, 0, (HWND)g_pD3DApp->m_hWnd); INTERACTIVE_OBJ * io = CreateFreeInter(); EERIEPOLY * ep; if (!io) return NULL; GetIOScript(io, texscript); io->lastpos.x = io->initpos.x = io->pos.x = player.pos.x - (float)EEsin(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.y = io->initpos.y = io->pos.y = player.pos.y; io->lastpos.z = io->initpos.z = io->pos.z = player.pos.z + (float)EEcos(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.x = io->initpos.x = (float)((long)(io->initpos.x / 20)) * 20.f; io->lastpos.z = io->initpos.z = (float)((long)(io->initpos.z / 20)) * 20.f; ep = CheckInPoly(io->pos.x, io->pos.y + PLAYER_BASE_HEIGHT, io->pos.z); if (ep) { float tempo; if (GetTruePolyY(ep, &io->pos, &tempo)) io->lastpos.y = io->initpos.y = io->pos.y = tempo; } ep = CheckInPoly(io->pos.x, player.pos.y, io->pos.z); if (ep) { io->pos.y = __min(ep->v[0].sy, ep->v[1].sy); io->lastpos.y = io->initpos.y = io->pos.y = __min(io->pos.y, ep->v[2].sy); } io->lastpos.y = io->initpos.y = io->pos.y += PLAYER_BASE_HEIGHT; strcpy(io->filename, tex1); io->obj = markerobj; io->ioflags = IO_MARKER; io->collision = 0; if (CheckScriptSyntax_Loading(io) != TRUE) io->ioflags |= IO_FREEZESCRIPT; return io; } void ShowIOPath(INTERACTIVE_OBJ * io) { for (long i = 0; i < ACTIVEBKG->nbanchors; i++) { _ANCHOR_DATA * ad = &ACTIVEBKG->anchors[i]; ad->flags &= ~1; } if ((io) && (io->ioflags & IO_NPC)) for (long j = 0; j < io->_npcdata->pathfind.listnb; j++) { _ANCHOR_DATA * ad = &ACTIVEBKG->anchors[io->_npcdata->pathfind.list[j]]; ad->flags |= 1; } } //************************************************************************************* // Unselect an IO //************************************************************************************* void UnSelectIO(INTERACTIVE_OBJ * io) { if ((io) && (io->EditorFlags & EFLAG_SELECTED)) { io->EditorFlags &= ~EFLAG_SELECTED; NbIOSelected--; LastSelectedIONum = -1; } } //************************************************************************************* // Select an IO //************************************************************************************* void SelectIO(INTERACTIVE_OBJ * io) { for (long i = 0; i < inter.nbmax; i++) { if ((inter.iobj[i] != NULL) && (inter.iobj[i]->EditorFlags & EFLAG_SELECTED)) { UnSelectIO(inter.iobj[i]); } } if ((io) && (!(io->EditorFlags & EFLAG_SELECTED))) { io->EditorFlags |= EFLAG_SELECTED; NbIOSelected++; EERIE_3D curpos; GetItemWorldPosition(io, &curpos); LastSelectedIONum = GetInterNum(io); ShowIOPath(io); } } //************************************************************************************* // Translate all selected IOs //************************************************************************************* void TranslateSelectedIO(EERIE_3D * op) { for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i]) && (inter.iobj[i]->EditorFlags & EFLAG_SELECTED)) { inter.iobj[i]->initpos.x = inter.iobj[i]->pos.x = inter.iobj[i]->initpos.x + op->x; inter.iobj[i]->initpos.y = inter.iobj[i]->pos.y = inter.iobj[i]->initpos.y + op->y; inter.iobj[i]->initpos.z = inter.iobj[i]->pos.z = inter.iobj[i]->initpos.z + op->z; } } } //************************************************************************************* // Reset all selected IOs rotations //************************************************************************************* void ResetSelectedIORot() { for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i]) && (inter.iobj[i]->EditorFlags & EFLAG_SELECTED)) { inter.iobj[i]->initangle.a = inter.iobj[i]->angle.a = 0.f; inter.iobj[i]->initangle.b = inter.iobj[i]->angle.b = 0.f; inter.iobj[i]->initangle.g = inter.iobj[i]->angle.g = 0.f; } } } //************************************************************************************* // Rotate all selected IOs //************************************************************************************* void RotateSelectedIO(EERIE_3D * op) { for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i]) && (inter.iobj[i]->EditorFlags & EFLAG_SELECTED)) { inter.iobj[i]->initangle.a = inter.iobj[i]->angle.a = inter.iobj[i]->initangle.a + op->a; inter.iobj[i]->initangle.b = inter.iobj[i]->angle.b = inter.iobj[i]->initangle.b + op->b; inter.iobj[i]->initangle.g = inter.iobj[i]->angle.g = inter.iobj[i]->initangle.g + op->g; } } } //************************************************************************************* // Delete All Selected IOs //************************************************************************************* void ARX_INTERACTIVE_DeleteByIndex(long i, long flag) { if ((i < 1) || (i >= inter.nbmax)) return; char temp[HERMES_PATH_SIZE]; char temp2[HERMES_PATH_SIZE]; char temp3[HERMES_PATH_SIZE]; if (inter.iobj[i] != NULL) { //Must "KILL" dir... if (inter.iobj[i]->scriptload == 0) { if (inter.iobj[i]->ident > 0) { sprintf(temp, inter.iobj[i]->filename); strcpy(temp2, GetName(temp)); RemoveName(temp); sprintf(temp, "%s%s_%04d.", temp, temp2, inter.iobj[i]->ident); if (DirectoryExist(temp)) { long _delete = 0; sprintf(temp3, "Really remove Directory & Directory Contents ?\n\n%s", temp); if (flag & FLAG_NOCONFIRM) { _delete = 1; } else if (OKBox(temp3, "WARNING")) { _delete = 1; } if (flag & FLAG_DONTKILLDIR) _delete = 0; if (_delete) { strcat(temp, "\\"); KillAllDirectory(temp); } } } } ReleaseInter(inter.iobj[i]); inter.iobj[i] = NULL; } } void DeleteSelectedIO() { for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i] != NULL) && (inter.iobj[i]->EditorFlags & EFLAG_SELECTED)) { UnSelectIO(inter.iobj[i]); ARX_INTERACTIVE_DeleteByIndex(i, 0); } } } //************************************************************************************* // Snaps to ground all selected IOs //************************************************************************************* void GroundSnapSelectedIO() { for (long i = 1; i < inter.nbmax; i++) { if ((inter.iobj[i] != NULL) && (inter.iobj[i]->EditorFlags & EFLAG_SELECTED)) { INTERACTIVE_OBJ * io = inter.iobj[i]; EERIE_3D ppos; ppos.x = io->pos.x; ppos.y = io->pos.y; ppos.z = io->pos.z; EERIEPOLY * ep = CheckInPoly(ppos.x, ppos.y + PLAYER_BASE_HEIGHT, ppos.z); if (ep) { float ay; if (GetTruePolyY(ep, &io->pos, &ay)) io->initpos.y = io->pos.y = ay; } } } } //*********************************************************************************** // AddNPC // Adds a NPC INTERACTIVE OBJECT to the Scene //*********************************************************************************** INTERACTIVE_OBJ * AddNPC(LPDIRECT3DDEVICE7 pd3dDevice, char * file, long flags) { char tex1[HERMES_PATH_SIZE]; char tex5[HERMES_PATH_SIZE]; char texscript[HERMES_PATH_SIZE]; // creates script filename strcpy(texscript, file); SetExt(texscript, "asl"); // creates teo filename sprintf(tex1, file); SetExt(tex1, "teo"); char file2[256]; sprintf(file2, "%sGAME\\%s", Project.workingdir, file + strlen(Project.workingdir)); SetExt(file2, ".FTL"); if ((!PAK_FileExist(file2)) && (!PAK_FileExist(file)) ) { return NULL; } char texx[HERMES_PATH_SIZE]; sprintf(texx, "AddNPC - %s", file); SendConsole(texx, 2, 0, (HWND)g_pD3DApp->m_hWnd); INTERACTIVE_OBJ * io = CreateFreeInter(); EERIEPOLY * ep; if (io == NULL) return NULL; io->forcedmove.x = 0.f; io->forcedmove.y = 0.f; io->forcedmove.z = 0.f; io->_npcdata = (IO_NPCDATA *)malloc(sizeof(IO_NPCDATA)); //"NPC DATA" memset(io->_npcdata, 0, sizeof(IO_NPCDATA)); io->ioflags = IO_NPC; GetIOScript(io, texscript); io->spellcast_data.castingspell = -1; io->_npcdata->life = io->_npcdata->maxlife = 20.f; io->_npcdata->mana = io->_npcdata->maxmana = 10.f; io->_npcdata->poisonned = 0.f; io->_npcdata->critical = 5.f; io->_npcdata->strike_time = 0; io->_npcdata->walk_start_time = 0; io->_npcdata->reach = 20.f; io->_npcdata->aimtime = 0.f; io->_npcdata->aiming_start = 0; io->_npcdata->npcflags = 0; io->_npcdata->backstab_skill = 0; io->_npcdata->blood_color = 0xFFFF0000; io->_npcdata->stare_factor = 1.f; if (!(flags & NO_ON_LOAD)) SendIOScriptEvent(io, SM_LOAD, "", NULL); io->lastpos.x = io->initpos.x = io->pos.x = player.pos.x - (float)EEsin(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.y = io->initpos.y = io->pos.y = player.pos.y; io->lastpos.z = io->initpos.z = io->pos.z = player.pos.z + (float)EEcos(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.x = io->initpos.x = (float)((long)(io->initpos.x / 20)) * 20.f; io->lastpos.z = io->initpos.z = (float)((long)(io->initpos.z / 20)) * 20.f; ep = CheckInPoly(io->pos.x, io->pos.y + PLAYER_BASE_HEIGHT, io->pos.z); if (ep) { float tempo; if (GetTruePolyY(ep, &io->pos, &tempo)) io->lastpos.y = io->initpos.y = io->pos.y = tempo; } ep = CheckInPoly(io->pos.x, player.pos.y, io->pos.z); if (ep) { io->pos.y = __min(ep->v[0].sy, ep->v[1].sy); io->lastpos.y = io->initpos.y = io->pos.y = __min(io->pos.y, ep->v[2].sy); } strcpy(io->filename, tex1); if (!io->obj) { if (flags & NO_MESH) { io->obj = NULL; } else { strcpy(tex5, tex1); sprintf(tex1, "%sGraph\\Obj3D\\Textures\\", Project.workingdir); io->obj = TheoToEerie_Fast(tex1, tex5, TTE_NO_PHYSICS_BOX | TTE_NPC, GDevice); } } io->_npcdata->speakpitch = 1.f; io->_npcdata->pathfind.listnb = -1; io->_npcdata->behavior = BEHAVIOUR_NONE; io->_npcdata->pathfind.truetarget = -1; if ((!(flags & NO_MESH)) && (flags & IO_IMMEDIATELOAD)) EERIE_COLLISION_Cylinder_Create(io); io->infracolor.r = 1.f; io->infracolor.g = 0.f; io->infracolor.b = 0.2f; io->collision = 1; io->inv = NULL; if (CheckScriptSyntax_Loading(io) != TRUE) io->ioflags |= IO_FREEZESCRIPT; ARX_INTERACTIVE_HideGore(io); return io; } //************************************************************************************* // Reload Scripts (Class & Local) for an IO //************************************************************************************* void ReloadScript(INTERACTIVE_OBJ * io) { char texscript[HERMES_PATH_SIZE]; char tmp2[HERMES_PATH_SIZE]; strcpy(texscript, io->filename); SetExt(texscript, "asl"); ARX_SCRIPT_Timer_Clear_For_IO(io); ReleaseScript(&io->over_script); ReleaseScript(&io->script); if (PAK_FileExist(texscript)) { long FileSize = 0; io->script.data = (char *)PAK_FileLoadMallocZero(texscript, &FileSize); if (io->script.data != NULL) { io->script.size = FileSize; InitScript(&io->script); } } else { io->script.size = 0; io->script.data = NULL; } sprintf(texscript, io->filename); strcpy(tmp2, GetName(texscript)); RemoveName(texscript); sprintf(texscript, "%s%s_%04d\\%s.asl", texscript, tmp2, io->ident, tmp2); if (PAK_FileExist(texscript)) { long FileSize = 0; io->over_script.data = (char *)PAK_FileLoadMallocZero(texscript, &FileSize); if (io->over_script.data != NULL) { io->over_script.size = FileSize; InitScript(&io->over_script); io->over_script.master = (void *)&io->script; } } else { io->over_script.size = 0; io->over_script.data = NULL; } long num = GetInterNum(io); if (ValidIONum(num)) { if (inter.iobj[num] && inter.iobj[num]->script.data) { SendScriptEvent(&inter.iobj[num]->script, SM_INIT, "", inter.iobj[num], NULL); } if (inter.iobj[num] && inter.iobj[num]->over_script.data) { SendScriptEvent(&inter.iobj[num]->over_script, SM_INIT, "", inter.iobj[num], NULL); } if (inter.iobj[num] && inter.iobj[num]->script.data) { SendScriptEvent(&inter.iobj[num]->script, SM_INITEND, "", inter.iobj[num], NULL); } if (inter.iobj[num] && inter.iobj[num]->over_script.data) { SendScriptEvent(&inter.iobj[num]->over_script, SM_INITEND, "", inter.iobj[num], NULL); } } } //************************************************************************************* // Reloads All Scripts for all IOs //************************************************************************************* void ReloadAllScripts() { ARX_SCRIPT_Timer_ClearAll(); for (long i = 0; i < inter.nbmax; i++) { if (inter.iobj[i]) ReloadScript(inter.iobj[i]); } } BOOL ExistTemporaryIdent(INTERACTIVE_OBJ * io, long t); //************************************************************************************* // Creates an unique identifier for an IO //************************************************************************************* void MakeIOIdent(INTERACTIVE_OBJ * io) { char temp[HERMES_PATH_SIZE]; char temp2[HERMES_PATH_SIZE]; long t = 1; if ((NODIRCREATION) || !io) return; while (io->ident == 0) { sprintf(temp, io->filename); strcpy(temp2, GetName(temp)); RemoveName(temp); sprintf(temp, "%s%s_%04d.", temp, temp2, t); if (!DirectoryExist(temp)) { io->ident = t; CreateDirectory(temp, NULL); LogDirCreation(temp); WriteIOInfo(io, temp); } t++; } } //************************************************************************************* // Tells if an ident corresponds to a temporary IO // NEED TO OPEN "if (LAST_CHINSTANCE!=-1) ARX_Changelevel_CurGame_Open();" // And close after seek session //************************************************************************************* BOOL ExistTemporaryIdent(INTERACTIVE_OBJ * io, long t) { if (!io) return FALSE; char name1[256]; char ident[256];; strcpy(name1, GetName(io->filename)); sprintf(ident, "%s_%04d", name1, t); for (long i = 0; i < inter.nbmax; i++) { if (inter.iobj[i]) { if ((inter.iobj[i]->ident == t) && (io != inter.iobj[i])) { char name2[256]; strcpy(name2, GetName(inter.iobj[i]->filename)); if (!stricmp(name1, name2)) { return TRUE; } } } } char file2[256]; strcpy(file2, io->filename); RemoveName(file2); sprintf(file2, "%s%s", file2, ident); if (PAK_DirectoryExist(file2)) return TRUE; if (LAST_CHINSTANCE != -1) { ARX_CHANGELEVEL_MakePath(); if (ARX_Changelevel_CurGame_Seek(ident)) return TRUE; } return FALSE; } //************************************************************************************* // Creates a Temporary IO Ident //************************************************************************************* void MakeTemporaryIOIdent(INTERACTIVE_OBJ * io) { long t = 1; if (!io) return; if (LAST_CHINSTANCE != -1) ARX_Changelevel_CurGame_Open(); while (1) { if (!ExistTemporaryIdent(io, t)) { io->ident = t; if (LAST_CHINSTANCE != -1) ARX_Changelevel_CurGame_Close(); return; // } } t++; } } extern EERIE_3DOBJ * arrowobj; extern long SP_DBG; //*********************************************************************************** // AddItem // Adds an ITEM INTERACTIVE OBJECT to the Scene //*********************************************************************************** INTERACTIVE_OBJ * AddItem(LPDIRECT3DDEVICE7 pd3dDevice, char * fil, long flags) { char tex1[HERMES_PATH_SIZE]; char tex2[HERMES_PATH_SIZE]; char tex5[HERMES_PATH_SIZE]; char texscript[HERMES_PATH_SIZE]; char file[256]; long type = IO_ITEM; MakeUpcase(fil); if (!specialstrcmp(GetName(fil), "GOLD_COIN")) { strcpy(file, fil); RemoveName(file); strcat(file, "GOLD_COIN.asl"); type = IO_ITEM | IO_GOLD; } else strcpy(file, fil); if (IsIn(fil, "MOVABLE")) { type = IO_ITEM | IO_MOVABLE; } strcpy(texscript, file); SetExt(texscript, "asl"); sprintf(tex1, file); SetExt(tex1, "teo"); strcpy(tex2, file); SetExt(tex2, "bmp"); AddToName(tex2, "[Icon]"); char file2[256]; sprintf(file2, "%sGAME\\%s", Project.workingdir, file + strlen(Project.workingdir)); SetExt(file2, ".FTL"); if (!PAK_FileExist(file2) && !PAK_FileExist(file)) { return NULL; } if (!PAK_FileExist(tex2)) return NULL; INTERACTIVE_OBJ * io = CreateFreeInter(); EERIEPOLY * ep; if (io == NULL) return NULL; io->ioflags = type; io->_itemdata = (IO_ITEMDATA *)malloc(sizeof(IO_ITEMDATA)); memset(io->_itemdata, 0, sizeof(IO_ITEMDATA)); io->_itemdata->count = 1; io->_itemdata->maxcount = 1; io->_itemdata->food_value = 0; io->_itemdata->LightValue = -1; if (io->ioflags & IO_GOLD) { io->_itemdata->price = 1; } else { io->_itemdata->price = 10; } io->_itemdata->playerstacksize = 1; GetIOScript(io, texscript); if (!(flags & NO_ON_LOAD)) SendIOScriptEvent(io, SM_LOAD, "", NULL); io->spellcast_data.castingspell = -1; io->lastpos.x = io->initpos.x = io->pos.x = player.pos.x - (float)EEsin(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.y = io->initpos.y = io->pos.y = player.pos.y; io->lastpos.z = io->initpos.z = io->pos.z = player.pos.z + (float)EEcos(DEG2RAD(player.angle.b)) * 140.f; io->lastpos.x = io->initpos.x = (float)((long)(io->initpos.x / 20)) * 20.f; io->lastpos.z = io->initpos.z = (float)((long)(io->initpos.z / 20)) * 20.f; ep = CheckInPoly(io->pos.x, io->pos.y - 60.f, io->pos.z); if (ep) { float tempo; if (GetTruePolyY(ep, &io->pos, &tempo)) io->lastpos.y = io->initpos.y = io->pos.y = tempo; } ep = CheckInPoly(io->pos.x, player.pos.y, io->pos.z); if (ep) { io->pos.y = __min(ep->v[0].sy, ep->v[1].sy); io->lastpos.y = io->initpos.y = io->pos.y = __min(io->pos.y, ep->v[2].sy); } strcpy(io->filename, tex1); if (io->ioflags & IO_GOLD) io->obj = GoldCoinsObj[0]; if (!io->obj) { if (flags & NO_MESH) { io->obj = NULL; } else { strcpy(tex5, tex1); sprintf(tex1, "%sGraph\\Obj3D\\Textures\\", Project.workingdir); io->obj = TheoToEerie_Fast(tex1, tex5, 0, GDevice); } } TextureContainer * tc; if (io->ioflags & IO_MOVABLE) tc = Movable; else if (io->ioflags & IO_GOLD) tc = GoldCoinsTC[0]; else { D3DTextr_CreateTextureFromFile(tex2, Project.workingdir, 0, D3DTEXTR_NO_REFINEMENT , EERIETEXTUREFLAG_LOADSCENE_RELEASE); tc = D3DTextr_GetSurfaceContainer(tex2); } if (tc == NULL) { MakeDir(tex2, "Graph\\Interface\\misc\\Default[Icon].bmp"); D3DTextr_CreateTextureFromFile(tex2, Project.workingdir, 0, D3DTEXTR_NO_REFINEMENT); D3DTextr_Restore(tex2, pd3dDevice); tc = D3DTextr_GetSurfaceContainer(tex2); } if (tc) { if (!tc->m_pddsSurface) tc->Restore(pd3dDevice); unsigned long w = tc->m_dwWidth >> 5; unsigned long h = tc->m_dwHeight >> 5; if ((w << 5) != tc->m_dwWidth) io->sizex = (char)(w + 1); else io->sizex = (char)(w); if ((h << 5) != tc->m_dwHeight) io->sizey = (char)(h + 1); else io->sizey = (char)(h); if (io->sizex < 1) io->sizex = 1; else if (io->sizex > 3) io->sizex = 3; if (io->sizey < 1) io->sizey = 1; else if (io->sizey > 3) io->sizey = 3; io->inv = tc; } io->infracolor.r = 0.2f; io->infracolor.g = 0.2f; io->infracolor.b = 1.f; io->collision = 0; if (CheckScriptSyntax_Loading(io) != TRUE) io->ioflags |= IO_FREEZESCRIPT; return io; } extern float LAST_FZPOS; extern float LAST_FZSCREEN; extern long USE_CEDRIC_ANIM; INTERACTIVE_OBJ * GetFirstInterAtPos(EERIE_S2D * pos, long flag = 0, EERIE_3D * _pRef = NULL, INTERACTIVE_OBJ ** _pTable = NULL, int * _pnNbInTable = NULL); //************************************************************************************* // Returns nearest interactive object found at position x,y //************************************************************************************* INTERACTIVE_OBJ * GetFirstInterAtPos(EERIE_S2D * pos, long flag, EERIE_3D * _pRef, INTERACTIVE_OBJ ** _pTable, int * _pnNbInTable) { float n; float fdist = 9999999999.f; float fdistBB = 9999999999.f; float fMaxDist = flag ? 9999999999.f : 350; INTERACTIVE_OBJ * foundBB = NULL; INTERACTIVE_OBJ * foundPixel = NULL; INTERNMB = -1; bool bPlayerEquiped = false; if (Project.telekinesis) { fMaxDist = 850; } int nStart = 1; int nEnd = inter.nbmax; INTERACTIVE_OBJ ** pTableIO = inter.iobj; if ((flag == 3) && _pTable && _pnNbInTable) { nStart = 0; nEnd = *_pnNbInTable; pTableIO = _pTable; } for (long i = nStart; i < nEnd; i++) { bool bPass = true; INTERACTIVE_OBJ * io = pTableIO[i]; // Is Object Valid ?? if (io == NULL) continue; if (((io->ioflags & IO_CAMERA) || (io->ioflags & IO_MARKER)) && (EDITMODE != 1)) continue; if ((!(io->GameFlags & GFLAG_INTERACTIVITY)) && (!EDITMODE)) continue; // Is Object in TreatZone ?? if ( ((bPlayerEquiped = IsEquipedByPlayer(io)) && (player.Interface & INTER_MAP)) || (io->GameFlags & GFLAG_ISINTREATZONE)) // Is Object Displayed on screen ??? if ((io->show == SHOW_FLAG_IN_SCENE) || (bPlayerEquiped && flag) || (bPlayerEquiped && (player.Interface & INTER_MAP) && (Book_Mode == 0))) //((io->show==9) && (player.Interface & INTER_MAP)) ) { if ((flag == 2) && _pTable && _pnNbInTable && ((*_pnNbInTable) < 256)) { _pTable[ *_pnNbInTable ] = io; (*_pnNbInTable)++; continue; } if ((pos->x >= io->bbox1.x) && (pos->x <= io->bbox2.x) && (pos->y >= io->bbox1.y) && (pos->y <= io->bbox2.y)) { if (flag && _pRef) { float flDistanceToRef = EESquaredDistance3D(&ACTIVECAM->pos, _pRef); float flDistanceToIO = EESquaredDistance3D(&ACTIVECAM->pos, &io->pos); bPass = bPlayerEquiped || (flDistanceToIO < flDistanceToRef); } float fp = EEDistance3D(&io->pos, &player.pos); if ((!flag && (fp <= fMaxDist)) && ((foundBB == NULL) || (fp < fdistBB))) { fdistBB = fp; foundBB = io; INTERNMB = i; } if ((io->ioflags & (IO_CAMERA | IO_MARKER | IO_GOLD)) || (bPlayerEquiped && !flag)) { if (bPlayerEquiped) fp = 0.f; else fp = EEDistance3D(&io->pos, &player.pos); if ((fp < fdistBB) || (foundBB == NULL)) { fdistBB = fp; foundBB = io; foundPixel = io; INTERNMB = i; } goto suite; } long j; for (j = 0; j < io->obj->nbfaces; j++) { if (io->animlayer[0].cur_anim != NULL) { if (USE_CEDRIC_ANIM) n = CEDRIC_PtIn2DPolyProjV2(io->obj, &io->obj->facelist[j] , pos->x, pos->y); else n = -1; } else n = PtIn2DPolyProj(io->obj, &io->obj->facelist[j] , pos->x, pos->y); if (n > 0.f) { if (bPlayerEquiped) fp = 0.f; else fp = EEDistance3D(&io->pos, &player.pos); if ((bPass && (fp <= fMaxDist)) && ((fp < fdist) || (foundPixel == NULL))) { { fdist = fp; foundPixel = io; INTERNMB = i; goto suite; } } } } suite: ; } } } if (foundPixel) return foundPixel; return foundBB; } bool IsEquipedByPlayer(INTERACTIVE_OBJ * io) { if (!io) return FALSE; if ((io->ioflags & IO_ICONIC) && (io->show == SHOW_FLAG_ON_PLAYER)) return true; long num = GetInterNum(io); for (long i = 0; i < MAX_EQUIPED; i++) { if ((player.equiped[i] != 0) && (player.equiped[i] == num)) return true; } return FALSE; } extern long LOOKING_FOR_SPELL_TARGET; INTERACTIVE_OBJ * InterClick(EERIE_S2D * pos, long flag) { LASTINTERCLICKNB = -1; if (IsFlyingOverInventory(pos)) { return NULL; } float dist_Threshold; if (LOOKING_FOR_SPELL_TARGET) dist_Threshold = 550.f; else dist_Threshold = 360.f; INTERACTIVE_OBJ * io = GetFirstInterAtPos(pos); if (io != NULL) { if (io->ioflags & IO_NPC) { if (Distance3D(player.pos.x, player.pos.y, player.pos.z, io->pos.x, io->pos.y, io->pos.z) < dist_Threshold) { LASTINTERCLICKNB = INTERNMB; return io; } } else if ((Project.telekinesis) || (EDITMODE)) { LASTINTERCLICKNB = INTERNMB; return io; } else if (IsEquipedByPlayer(io) || (Distance3D(player.pos.x, player.pos.y, player.pos.z, io->pos.x, io->pos.y, io->pos.z) < dist_Threshold)) { LASTINTERCLICKNB = INTERNMB; return io; } } return NULL; } //************************************************************************************* // Need To upgrade to a more precise collision. //************************************************************************************* long IsCollidingAnyInter(float x, float y, float z, EERIE_3D * size) { EERIE_3D pos; for (long i = 0; i < inter.nbmax; i++) { INTERACTIVE_OBJ * io = inter.iobj[i]; if ((io) && (!(io->ioflags & IO_NO_COLLISIONS)) && (io->collision) && (io->GameFlags & GFLAG_ISINTREATZONE) && (io != CURRENTINTER) && ((io->ioflags & IO_NPC) || (io->ioflags & IO_FIX)) && (io->show == SHOW_FLAG_IN_SCENE) ) { if (io->ioflags & IO_NPC) { if (io->_npcdata->life <= 0.f) goto suitet; } pos.x = x; pos.y = y; pos.z = z; if (IsCollidingInter(io, &pos)) return i; pos.y += size->y; if (IsCollidingInter(io, &pos)) return i; suitet: ; } } return -1; } //************************************************************************************* // To upgrade to a more precise collision. //************************************************************************************* BOOL IsCollidingInter(INTERACTIVE_OBJ * io, EERIE_3D * pos) { long nbv; long idx; EERIE_VERTEX * vlist; if ((!io) || (!io->obj)) return FALSE; if (Distance3D(pos->x, pos->y, pos->z, io->pos.x, io->pos.y, io->pos.z) < 190.f) { vlist = io->obj->vertexlist3; nbv = io->obj->nbvertex; if (io->obj->nbgroups > 4) { for (long i = 0; i < io->obj->nbgroups; i++) { idx = io->obj->grouplist[i].origin; if (Distance3D(pos->x, pos->y, pos->z, vlist[idx].v.x, vlist[idx].v.y, vlist[idx].v.z) <= 50.f) return TRUE; } } else { for (long i = 0; i < nbv; i++) { if (i != io->obj->origin) if (Distance3D(pos->x, pos->y, pos->z, vlist[i].v.x, vlist[i].v.y, vlist[i].v.z) <= 30.f) return TRUE; } } } return FALSE; } void SetYlsideDeath(INTERACTIVE_OBJ * io) { io->sfx_flag = SFX_TYPE_YLSIDE_DEATH; io->sfx_time = ARXTimeUL(); } BOOL ARX_INTERACTIVE_CheckCollision(EERIE_3DOBJ * obj, long kk, long source) { BOOL col = FALSE; float dist; long i, ret; long avoid = -1; INTERACTIVE_OBJ * io_source = NULL; if (ValidIONum(source)) { io_source = inter.iobj[source]; avoid = io_source->no_collide; } for (i = 1; i < inter.nbmax; i++) { INTERACTIVE_OBJ * io = inter.iobj[i]; if ( (io) && (i != avoid) && (!(io->ioflags & (IO_CAMERA | IO_MARKER | IO_ITEM))) && (io->show == SHOW_FLAG_IN_SCENE) && !(io->ioflags & IO_NO_COLLISIONS) && (io->obj) && (io->obj != obj) && (!io->usepath) ) { dist = EEDistance3D(&io->pos, &obj->pbox->vert[0].pos); if ((dist < 450.f) && (In3DBBoxTolerance(&obj->pbox->vert[kk].pos, &io->bbox3D, obj->pbox->radius))) { ret = -1; if ((io->ioflags & IO_NPC) && (io->_npcdata->life > 0.f)) { if (PointInCylinder(&io->physics.cyl, &obj->pbox->vert[kk].pos)) { return TRUE; } } else if (io->ioflags & IO_FIX) { long step; long nbv; nbv = io->obj->nbvertex; if (nbv < 300) step = 1; else if (nbv < 600) step = 2; else if (nbv < 1200) step = 4; else step = 6; EERIE_VERTEX * vlist = io->obj->vertexlist3; EERIE_SPHERE sp; sp.radius = 22.f; for (long ii = 1; ii < nbv; ii += step) { if (ii != io->obj->origin) { sp.origin.x = vlist[ii].v.x; sp.origin.y = vlist[ii].v.y; sp.origin.z = vlist[ii].v.z; if (EEDistance3D(&obj->pbox->vert[kk].pos, &sp.origin) < sp.radius) { if ((io_source) && (io->GameFlags & GFLAG_DOOR)) { if (ARXTime > io->collide_door_time + 500) { EVENT_SENDER = io_source; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io, SM_COLLIDE_DOOR, "", NULL); EVENT_SENDER = io; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io_source, SM_COLLIDE_DOOR, "", NULL); } } return TRUE; col = TRUE; ret = 1; } } } } } } } return col; } BOOL ARX_INTERACTIVE_CheckFULLCollision(EERIE_3DOBJ * obj, long source) { BOOL col = FALSE; float dist; long i, ret; long avoid = -1; INTERACTIVE_OBJ * io_source = NULL; INTERACTIVE_OBJ * io = NULL; if (ValidIONum(source)) { io_source = inter.iobj[source]; avoid = io_source->no_collide; } for (i = 0; i < TREATZONE_CUR; i++) { if ((treatio[i].show != SHOW_FLAG_IN_SCENE) || ((treatio[i].ioflags & IO_NO_COLLISIONS)) || (!treatio[i].io)) continue; io = treatio[i].io; if ((io == io_source) || (!io->obj) || (io == inter.iobj[0])) continue; if (treatio[i].num == avoid) continue; if ((io->ioflags & (IO_CAMERA | IO_MARKER | IO_ITEM)) || (io->usepath)) continue; if ((io->ioflags & IO_NPC) && (io_source) && (io_source->ioflags & IO_NO_NPC_COLLIDE)) continue; dist = EEDistance3D(&io->pos, &obj->pbox->vert[0].pos); if ((dist < 600.f) && (In3DBBoxTolerance(&obj->pbox->vert[0].pos, &io->bbox3D, obj->pbox->radius))) { ret = -1; if ((io->ioflags & IO_NPC) && (io->_npcdata->life > 0.f)) { for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) if (PointInCylinder(&io->physics.cyl, &obj->pbox->vert[kk].pos)) { return TRUE; } } else if (io->ioflags & IO_FIX) { long step; long nbv; nbv = io->obj->nbvertex; EERIE_SPHERE sp; sp.radius = 28.f; if (nbv < 500) { step = 1; sp.radius = 36.f; } else if (nbv < 900) step = 2; else if (nbv < 1500) step = 4; else step = 6; EERIE_VERTEX * vlist = io->obj->vertexlist3; if (io->GameFlags & GFLAG_PLATFORM) { for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) { EERIE_SPHERE sphere; sphere.origin.x = obj->pbox->vert[kk].pos.x; sphere.origin.y = obj->pbox->vert[kk].pos.y; sphere.origin.z = obj->pbox->vert[kk].pos.z; sphere.radius = 30.f; float miny, maxy; miny = io->bbox3D.min.y; maxy = io->bbox3D.max.y; if ((maxy <= sphere.origin.y + sphere.radius) || (miny >= sphere.origin.y)) if (In3DBBoxTolerance(&sphere.origin, &io->bbox3D, sphere.radius)) { if (Distance2D(io->pos.x, io->pos.z, sphere.origin.x, sphere.origin.z) < 440.f + sphere.radius) { EERIEPOLY ep; ep.type = 0; for (long ii = 0; ii < io->obj->nbfaces; ii++) { float cx = 0; float cz = 0; for (long idx = 0 ; idx < 3 ; idx++) { cx += ep.v[idx].sx = io->obj->vertexlist3[ io->obj->facelist[ii].vid[idx] ].v.x; ep.v[idx].sy = io->obj->vertexlist3[ io->obj->facelist[ii].vid[idx] ].v.y; cz += ep.v[idx].sz = io->obj->vertexlist3[ io->obj->facelist[ii].vid[idx] ].v.z; } cx *= DIV3; cz *= DIV3; for (kk = 0; kk < 3; kk++) { ep.v[kk].sx = (ep.v[kk].sx - cx) * 3.5f + cx; ep.v[kk].sz = (ep.v[kk].sz - cz) * 3.5f + cz; } if (PointIn2DPolyXZ(&ep, sphere.origin.x, sphere.origin.z)) { return TRUE; } } } } } } for (long ii = 1; ii < nbv; ii += step) { if (ii != io->obj->origin) { if (0) { for (long jii = 1; jii < nbv; jii += step) { sp.origin.x = (vlist[ii].v.x + vlist[jii].v.x) * DIV2; sp.origin.y = (vlist[ii].v.y + vlist[jii].v.y) * DIV2; sp.origin.z = (vlist[ii].v.z + vlist[jii].v.z) * DIV2; for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) if (EEDistance3D(&obj->pbox->vert[kk].pos, &sp.origin) < sp.radius) { if ((io_source) && (io->GameFlags & GFLAG_DOOR)) { if (ARXTime > io->collide_door_time + 500) { EVENT_SENDER = io_source; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io, SM_COLLIDE_DOOR, "", NULL); EVENT_SENDER = io; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io_source, SM_COLLIDE_DOOR, "", NULL); } } return TRUE; } } } sp.origin.x = vlist[ii].v.x; sp.origin.y = vlist[ii].v.y; sp.origin.z = vlist[ii].v.z; for (long kk = 0; kk < obj->pbox->nb_physvert; kk++) if (EEDistance3D(&obj->pbox->vert[kk].pos, &sp.origin) < sp.radius) { if ((io_source) && (io->GameFlags & GFLAG_DOOR)) { if (ARXTime > io->collide_door_time + 500) { EVENT_SENDER = io_source; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io, SM_COLLIDE_DOOR, "", NULL); EVENT_SENDER = io; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io_source, SM_COLLIDE_DOOR, "", NULL); } } return TRUE; } } } } } } return col; } void UpdateCameras() { ARX_TIME_Get(); for (long i = 1; i < inter.nbmax; i++) { INTERACTIVE_OBJ * io = inter.iobj[i]; if (io) { if (io->usepath) // interpolate & send events { ARX_USE_PATH * aup = (ARX_USE_PATH *)io->usepath; float diff = ARXTime - aup->_curtime; if (aup->aupflags & ARX_USEPATH_FORWARD) { if (aup->aupflags & ARX_USEPATH_FLAG_FINISHED) { } else aup->_curtime += diff; } if (aup->aupflags & ARX_USEPATH_BACKWARD) { aup->_starttime += diff * 2; aup->_curtime += diff; if (aup->_starttime >= aup->_curtime) aup->_curtime = aup->_starttime + 1; } if (aup->aupflags & ARX_USEPATH_PAUSE) { aup->_starttime += diff; aup->_curtime += diff; } long last = ARX_PATHS_Interpolate(aup, &io->pos); if (aup->lastWP != last) { if (last == -2) { char str[16]; sprintf(str, "%d", aup->path->nb_pathways - 1); EVENT_SENDER = NULL; SendIOScriptEvent(io, SM_WAYPOINT, str, NULL); sprintf(str, "WAYPOINT%d", aup->path->nb_pathways - 1); SendIOScriptEvent(io, 0, "", str); SendIOScriptEvent(io, SM_PATHEND, "", NULL); aup->lastWP = last; } else { last--; long _from = aup->lastWP; long _to = last; if (_from > _to) _from = -1; if (_from < 0) _from = -1; long ii = _from + 1; char str[16]; sprintf(str, "%d", ii); EVENT_SENDER = NULL; SendIOScriptEvent(io, SM_WAYPOINT, str, NULL); sprintf(str, "WAYPOINT%d", ii); SendIOScriptEvent(io, 0, "", str); if (ii == aup->path->nb_pathways) { SendIOScriptEvent(io, SM_PATHEND, "", NULL); } aup->lastWP = last + 1; } } if ((io->damager_damages > 0) && (io->show == SHOW_FLAG_IN_SCENE)) { for (long ii = 0; ii < inter.nbmax; ii++) { INTERACTIVE_OBJ * ioo = inter.iobj[ii]; if ((ioo) && (ii != i) && (ioo->show == SHOW_FLAG_IN_SCENE) && (ioo->ioflags & IO_NPC) && (EEDistance3D(&io->pos, &ioo->pos) < 600.f)) { bool Touched = false; for (long ri = 0; ri < io->obj->nbvertex; ri += 3) { for (long rii = 0; rii < ioo->obj->nbvertex; rii += 3) { if (EEDistance3D(&io->obj->vertexlist3[ri].v, &ioo->obj->vertexlist3[rii].v) < 20.f) { Touched = true; ri = 999999; rii = 999999; break; } } } if (Touched) ARX_DAMAGES_DealDamages(ii, io->damager_damages, i, io->damager_type, &ioo->pos); } } } } if (io->ioflags & IO_CAMERA) { inter.iobj[i]->_camdata->cam.pos.x = io->pos.x; inter.iobj[i]->_camdata->cam.pos.y = io->pos.y; inter.iobj[i]->_camdata->cam.pos.z = io->pos.z; if (io->targetinfo != TARGET_NONE) // Follows target { GetTargetPos(io, (unsigned long)inter.iobj[i]->_camdata->cam.smoothing); io->target.x += io->_camdata->cam.translatetarget.x; io->target.y += io->_camdata->cam.translatetarget.y; io->target.z += io->_camdata->cam.translatetarget.z; if ((io->_camdata->cam.lastinfovalid) && (io->_camdata->cam.smoothing != 0.f)) { EERIE_3D smoothtarget; float vv = (float)io->_camdata->cam.smoothing; if (vv > 8000) vv = 8000; vv = (8000 - vv) * DIV4000; float vll = _framedelay * DIV1000 * vv; EERIE_3D oldvector; EERIE_3D newvector; oldvector.x = io->_camdata->cam.lasttarget.x - io->_camdata->cam.lastpos.x; oldvector.y = io->_camdata->cam.lasttarget.y - io->_camdata->cam.lastpos.y; oldvector.z = io->_camdata->cam.lasttarget.z - io->_camdata->cam.lastpos.z; newvector.x = io->target.x - io->_camdata->cam.pos.x; newvector.y = io->target.y - io->_camdata->cam.pos.y; newvector.z = io->target.z - io->_camdata->cam.pos.z; EEDistance3D(&oldvector, &newvector); float f1 = vll; if (f1 > 1.f) f1 = 1.f; float f2 = 1.f - f1; smoothtarget.x = io->target.x * f2 + io->_camdata->cam.lasttarget.x * f1; smoothtarget.y = io->target.y * f2 + io->_camdata->cam.lasttarget.y * f1; smoothtarget.z = io->target.z * f2 + io->_camdata->cam.lasttarget.z * f1; SetTargetCamera(&io->_camdata->cam, smoothtarget.x, smoothtarget.y, smoothtarget.z); io->_camdata->cam.lasttarget.x = smoothtarget.x; io->_camdata->cam.lasttarget.y = smoothtarget.y; io->_camdata->cam.lasttarget.z = smoothtarget.z; io->_camdata->cam.lastinfovalid = TRUE; io->_camdata->cam.lastpos.x = io->_camdata->cam.pos.x; io->_camdata->cam.lastpos.y = io->_camdata->cam.pos.y; io->_camdata->cam.lastpos.z = io->_camdata->cam.pos.z; } else { if ((io->target.x == io->_camdata->cam.pos.x) && (io->target.y == io->_camdata->cam.pos.y) && (io->target.z == io->_camdata->cam.pos.z)) { } else SetTargetCamera(&io->_camdata->cam, io->target.x, io->target.y, io->target.z); io->_camdata->cam.lasttarget.x = io->target.x; io->_camdata->cam.lasttarget.y = io->target.y; io->_camdata->cam.lasttarget.z = io->target.z; io->_camdata->cam.lastinfovalid = TRUE; io->_camdata->cam.lastpos.x = io->_camdata->cam.pos.x; io->_camdata->cam.lastpos.y = io->_camdata->cam.pos.y; io->_camdata->cam.lastpos.z = io->_camdata->cam.pos.z; } io->_camdata->cam.angle.b -= 180.f; io->_camdata->cam.angle.a = -io->_camdata->cam.angle.a; io->angle.a = 0.f; io->angle.b = io->_camdata->cam.angle.b + 90.f; io->angle.g = 0.f; } else // no target... { float tr = DEG2RAD(MAKEANGLE(io->angle.b + 90)); io->target.x = io->pos.x - (float)EEsin(tr) * 20.f; io->target.y = io->pos.y; io->target.z = io->pos.z + (float)EEcos(tr) * 20.f; SetTargetCamera(&io->_camdata->cam, io->target.x, io->target.y, io->target.z); io->_camdata->cam.lasttarget.x = io->target.x; io->_camdata->cam.lasttarget.y = io->target.y; io->_camdata->cam.lasttarget.z = io->target.z; io->_camdata->cam.lastinfovalid = TRUE; io->_camdata->cam.lastpos.x = io->_camdata->cam.pos.x; io->_camdata->cam.lastpos.y = io->_camdata->cam.pos.y; io->_camdata->cam.lastpos.z = io->_camdata->cam.pos.z; } } } } } void ARX_INTERACTIVE_UnfreezeAll() { if (inter.iobj) { for (long i = 0; i < inter.nbmax; i++) { if (inter.iobj[i] != NULL) inter.iobj[i]->ioflags &= ~IO_FREEZESCRIPT; } } } void UpdateIOInvisibility(INTERACTIVE_OBJ * io) { if (io && (io->invisibility <= 1.f)) { if ((io->GameFlags & GFLAG_INVISIBILITY) && (io->invisibility < 1.f)) { io->invisibility += _framedelay * DIV1000; if (io->invisibility > 1.f) io->invisibility = 1.f; } else if ((!(io->GameFlags & GFLAG_INVISIBILITY)) && (io->invisibility != 0.f)) { io->invisibility -= _framedelay * DIV1000; if (io->invisibility < 0.f) io->invisibility = 0.f; } } } extern INTERACTIVE_OBJ * DESTROYED_DURING_RENDERING; //************************************************************************************* // Renders Interactive objects. // Will render objects between distance "from" (included) // to distance "to" (not included) // from camera position. //************************************************************************************* extern CDirectInput * pGetInfoDirectInput; extern TextureContainer TexMetal; extern long FINAL_COMMERCIAL_DEMO; bool bRenderInterList = true; //false; void RenderInter(LPDIRECT3DDEVICE7 pd3dDevice, float from, float to, long flags) { SETTEXTUREWRAPMODE(pd3dDevice, D3DTADDRESS_CLAMP); float val = -0.6f; pd3dDevice->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD)(&val))); EERIE_3D temp; EERIEMATRIX mat; INTER_DRAW = 0; INTER_COMPUTE = 0; float dist; long diff; if (inter.iobj[0] && (inter.iobj[0]->ignition > 0.f)) { ManageIgnition(inter.iobj[0]); } for (long i = 1; i < inter.nbmax; i++) // Player isn't rendered here... { if (i == 379) i = i; INTERACTIVE_OBJ * io = inter.iobj[i]; if ((io) && (io != DRAGINTER) && (io->GameFlags & GFLAG_ISINTREATZONE)) { if ((i == 0) && ((player.Interface & INTER_MAP) && (!(player.Interface & INTER_COMBATMODE))) && (Book_Mode == 0)) continue; if (io->show != SHOW_FLAG_IN_SCENE) continue; if (!ForceIODraw) { if ((Project.hide & HIDE_NPC) && (io->ioflags & IO_NPC)) continue; if ((Project.hide & HIDE_ITEMS) && (io->ioflags & IO_ITEM)) continue; if ((Project.hide & HIDE_FIXINTER) && (io->ioflags & IO_FIX)) continue; } if ((Project.hide & HIDE_CAMERAS) && (io->ioflags & IO_CAMERA)) continue; if (!EDITMODE) { if (io->ioflags & IO_CAMERA) continue; if (io->ioflags & IO_MARKER) continue; } if ((io->obj) && (io->obj->pbox) && (io->obj->pbox->active)) { dist = EEDistance3D(&ACTIVECAM->pos, &io->obj->pbox->vert[0].pos); } else dist = EEDistance3D(&ACTIVECAM->pos, &io->pos); if ((0) && (inter.iobj[i]->stepmaterial)) { free(inter.iobj[i]->stepmaterial); inter.iobj[i]->stepmaterial = NULL; } if ((io) && (io->ioflags & IO_NPC) && (io->_npcdata->pathfind.flags & PATHFIND_ALWAYS)) { } else if ((dist < from) || (dist >= to)) continue; UpdateIOInvisibility(io); io->bbox1.x = 9999; io->bbox2.x = -1; if ((io->obj) && (io->obj->pbox)) EERIE_PHYSICS_BOX_Show(io->obj, &io->pos); if ( (io->obj) && (io->obj->pbox) && (io->obj->pbox->active)) { EERIE_3D tmp; tmp.x = (io->obj->pbox->vert[14].pos.x - io->obj->pbox->vert[13].pos.x); tmp.y = (io->obj->pbox->vert[14].pos.y - io->obj->pbox->vert[13].pos.y); tmp.z = (io->obj->pbox->vert[14].pos.z - io->obj->pbox->vert[13].pos.z); EERIE_3D up; up.x = io->obj->pbox->vert[2].pos.x - io->obj->pbox->vert[1].pos.x; up.y = io->obj->pbox->vert[2].pos.y - io->obj->pbox->vert[1].pos.y; up.z = io->obj->pbox->vert[2].pos.z - io->obj->pbox->vert[1].pos.z; up.x += io->obj->pbox->vert[3].pos.x - io->obj->pbox->vert[4].pos.x; up.y += io->obj->pbox->vert[3].pos.y - io->obj->pbox->vert[4].pos.y; up.z += io->obj->pbox->vert[3].pos.z - io->obj->pbox->vert[4].pos.z; up.x += io->obj->pbox->vert[10].pos.x - io->obj->pbox->vert[9].pos.x; up.y += io->obj->pbox->vert[10].pos.y - io->obj->pbox->vert[9].pos.y; up.z += io->obj->pbox->vert[10].pos.z - io->obj->pbox->vert[9].pos.z; up.x += io->obj->pbox->vert[11].pos.x - io->obj->pbox->vert[12].pos.x; up.y += io->obj->pbox->vert[11].pos.y - io->obj->pbox->vert[12].pos.y; up.z += io->obj->pbox->vert[11].pos.z - io->obj->pbox->vert[12].pos.z; up.x *= DIV4; up.y *= DIV4; up.z *= DIV4; MatrixSetByVectors(&mat, &up, &tmp); mat._14 = mat._24 = mat._34 = 0.f; mat._41 = mat._42 = mat._43 = mat._44 = 0.f; } if (io->animlayer[0].cur_anim) { if (ForceIODraw && (dist > 2200.f)) continue; temp.a = io->angle.a; if (io->ioflags & IO_NPC) temp.b = MAKEANGLE(180.f - io->angle.b); else temp.b = MAKEANGLE(270.f - io->angle.b); temp.g = io->angle.g; if (io->animlayer[0].flags & EA_PAUSED) diff = 0; else diff = ARX_CLEAN_WARN_CAST_LONG(FrameDiff); if ((io == FlyingOverIO) && (!(io->ioflags & IO_NPC)) && io->obj) io->obj->drawflags |= DRAWFLAG_HIGHLIGHT; if (io->targetinfo >= 0) { if ((io->ioflags & IO_NPC) && !(io->_npcdata->behavior & BEHAVIOUR_STARE_AT) && !(io->_npcdata->behavior & BEHAVIOUR_WANDER_AROUND) && !(io->_npcdata->behavior & BEHAVIOUR_LOOK_FOR) && (io->_npcdata->behavior & BEHAVIOUR_FIGHT)) LOOK_AT_TARGET = 1; } EERIE_3D pos; Vector_Copy(&pos, &io->pos); if (io->ioflags & IO_NPC) { ComputeVVPos(io); pos.y = io->_npcdata->vvpos; } long flgs; if (!(EDITMODE) && (ARX_SCENE_PORTAL_Basic_ClipIO(io))) flgs = 4; else flgs = 0; EERIEDrawAnimQuat(pd3dDevice, io->obj, &io->animlayer[0], &temp, &pos, diff, io, flgs); LOOK_AT_TARGET = 0; if (DESTROYED_DURING_RENDERING) continue; if (io->obj) io->obj->drawflags &= ~DRAWFLAG_HIGHLIGHT; } else { if ((!EDITMODE) && (ARX_SCENE_PORTAL_Basic_ClipIO(io))) continue; if (ForceIODraw && (dist > ACTIVECAM->cdepth * fZFogEnd)) continue; temp.a = io->angle.a; if (io->ioflags & IO_NPC) temp.b = MAKEANGLE(180.f - io->angle.b); else temp.b = MAKEANGLE(270.f - io->angle.b); temp.g = io->angle.g; if ((io->ioflags & IO_GOLD) && io->obj) { if (io->_itemdata->price <= 3) { io->obj = GoldCoinsObj[io->_itemdata->price-1]; io->inv = GoldCoinsTC[io->_itemdata->price-1]; } else if (io->_itemdata->price <= 8) { io->obj = GoldCoinsObj[3]; io->inv = GoldCoinsTC[3]; } else if (io->_itemdata->price <= 20) { io->obj = GoldCoinsObj[4]; io->inv = GoldCoinsTC[4]; } else if (io->_itemdata->price <= 50) { io->obj = GoldCoinsObj[5]; io->inv = GoldCoinsTC[5]; } else { io->obj = GoldCoinsObj[6]; io->inv = GoldCoinsTC[6]; } } if ((!(io->ioflags & IO_NPC)) || (EDITMODE)) { if (io->obj) { if ((io == FlyingOverIO) && (!(io->ioflags & IO_NPC))) { io->obj->drawflags |= DRAWFLAG_HIGHLIGHT; } if ((io->obj->pbox) && (io->obj->pbox->active)) { DrawEERIEInterMatrix(pd3dDevice, io->obj, &mat, &io->pos, io, NULL); } else { DrawEERIEInter(pd3dDevice, io->obj, &temp, &io->pos, io); } if (DESTROYED_DURING_RENDERING) continue; io->obj->drawflags &= ~DRAWFLAG_HIGHLIGHT; } } } if ((io->ignition > 0.f) || (io->ioflags & IO_FIERY)) ManageIgnition(io); if ((NEED_TEST_TEXT || EDITMODE) && (!FOR_EXTERNAL_PEOPLE)) { D3DCOLOR color; if ((EDITMODE && (io->EditorFlags & EFLAG_SELECTED))) color = 0xFFFFFF00; else color = 0xFF0000FF; if ((io->bbox1.x != io->bbox2.x) && (io->bbox1.x < DANAESIZX)) { EERIEDraw2DLine(pd3dDevice, io->bbox1.x, io->bbox1.y, io->bbox2.x, io->bbox1.y, 0.01f, color); EERIEDraw2DLine(pd3dDevice, io->bbox2.x, io->bbox1.y, io->bbox2.x, io->bbox2.y, 0.01f, color); EERIEDraw2DLine(pd3dDevice, io->bbox2.x, io->bbox2.y, io->bbox1.x, io->bbox2.y, 0.01f, color); EERIEDraw2DLine(pd3dDevice, io->bbox1.x, io->bbox2.y, io->bbox1.x, io->bbox1.y, 0.01f, color); } } } } SETTEXTUREWRAPMODE(pd3dDevice, D3DTADDRESS_WRAP); val = -0.3f; pd3dDevice->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD)(&val))); } void ARX_INTERACTIVE_DestroyIO(INTERACTIVE_OBJ * ioo) { if (ioo) { if (ioo->show == SHOW_FLAG_DESTROYED) return; ARX_INTERACTIVE_ForceIOLeaveZone(ioo, 0); if (DRAGINTER == ioo) Set_DragInter(NULL); if (FlyingOverIO == ioo) FlyingOverIO = NULL; if (COMBINE == ioo) COMBINE = NULL; if ((ioo->ioflags & IO_ITEM) && (ioo->_itemdata->count > 1)) { ioo->_itemdata->count--; } else { // Kill all spells long numm = GetInterNum(ioo); if (ValidIONum(numm)) ARX_SPELLS_FizzleAllSpellsFromCaster(numm); // Need To Kill timers ARX_SCRIPT_Timer_Clear_By_IO(ioo); ioo->show = SHOW_FLAG_DESTROYED; ioo->GameFlags &= ~GFLAG_ISINTREATZONE; if (!FAST_RELEASE) RemoveFromAllInventories(ioo); if (ioo->obj) { EERIE_3DOBJ * eobj = ioo->obj; while (eobj->nblinked) { long k = 0; if ((eobj->linked[k].lgroup != -1) && eobj->linked[k].obj) { INTERACTIVE_OBJ * iooo = (INTERACTIVE_OBJ *)eobj->linked[k].io; if ((iooo) && ValidIOAddress(iooo)) { EERIE_LINKEDOBJ_UnLinkObjectFromObject(ioo->obj, iooo->obj); ARX_INTERACTIVE_DestroyIO(iooo); } } } } ARX_INTERACTIVE_DestroyDynamicInfo(ioo); if (ioo->scriptload) { long num = GetInterNum(ioo); ReleaseInter(ioo); if (ValidIONum(num)) inter.iobj[num] = NULL; } } } } //************************************************************************************* // //************************************************************************************* BOOL IsSameObject(INTERACTIVE_OBJ * io, INTERACTIVE_OBJ * ioo) { if ((io == NULL) || (ioo == NULL) || (stricmp(io->filename, ioo->filename)) || (io->ioflags & IO_UNIQUE) || (io->durability != ioo->durability) || (io->max_durability != ioo->max_durability)) return FALSE; if ((io->ioflags & IO_ITEM) && (ioo->ioflags & IO_ITEM) && (io->over_script.data == NULL) && (ioo->over_script.data == NULL)) { if ((io->locname) && (ioo->locname)) { if (strcmp(io->locname, ioo->locname) == 0) return TRUE; } else return TRUE; } return FALSE; } BOOL HaveCommonGroup(INTERACTIVE_OBJ * io, INTERACTIVE_OBJ * ioo) { if ((!io) || (!ioo)) return FALSE; for (long i = 0; i < io->nb_iogroups; i++) { for (long k = 0; k < ioo->nb_iogroups; k++) { if (!stricmp(io->iogroups[i].name, ioo->iogroups[k].name)) return TRUE; } } return FALSE; } float ARX_INTERACTIVE_GetArmorClass(INTERACTIVE_OBJ * io) { if (!io) return -1; if (!(io->ioflags & IO_NPC)) return -1; float ac = io->_npcdata->armor_class; for (long i = 0; i < io->nb_spells_on; i++) { long n = io->spells_on[i]; if (spells[n].exist) { switch (spells[n].type) { case SPELL_ARMOR: ac += spells[n].caster_level; break; case SPELL_LOWER_ARMOR: ac -= spells[n].caster_level; break; } } } if (ac < 0) ac = 0; return ac; } void ARX_INTERACTIVE_ActivatePhysics(long t) { if (ValidIONum(t)) { INTERACTIVE_OBJ * io = inter.iobj[t]; if ((io == DRAGINTER) || (io->show != SHOW_FLAG_IN_SCENE)) return; float yy; EERIEPOLY * ep = CheckInPoly(io->pos.x, io->pos.y, io->pos.z, &yy); if ((ep) && (yy - io->pos.y < 10.f)) return; io->obj->pbox->active = 1; io->obj->pbox->stopcount = 0; EERIE_3D pos; pos.x = io->pos.x; pos.z = io->pos.z; pos.y = io->pos.y; io->velocity.x = 0.f; io->velocity.y = 0.f; io->velocity.z = 0.f; io->stopped = 1; EERIE_3D fallvector; fallvector.x = 0.f; fallvector.z = 0.f; fallvector.y = 0.000001f; io->show = SHOW_FLAG_IN_SCENE; io->soundtime = 0; io->soundcount = 0; EERIE_PHYSICS_BOX_Launch(io->obj, &pos, &fallvector); } }