From c09b24125c533f758413cb1ef0ec964b810dd8e7 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Tue, 14 Feb 2012 21:17:26 +0100 Subject: [PATCH 01/70] linux: Fix a crash when getifaddrs returns NULL for an address (#713) --- src/network/C4Network2Client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/C4Network2Client.cpp b/src/network/C4Network2Client.cpp index b5649e9fa..307dd8b6d 100644 --- a/src/network/C4Network2Client.cpp +++ b/src/network/C4Network2Client.cpp @@ -268,6 +268,8 @@ void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP) for(struct ifaddrs* addr = addrs; addr != NULL; addr = addr->ifa_next) { struct sockaddr* ad = addr->ifa_addr; + if(ad == NULL) continue; + if(ad->sa_family == AF_INET && (~addr->ifa_flags & IFF_LOOPBACK)) // Choose only non-loopback IPv4 devices addr_vec.push_back(&reinterpret_cast(ad)->sin_addr); } From 8dae8c111d2a4b12fc80b1ff8c5c619880d776ab Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Wed, 15 Feb 2012 23:04:19 +0100 Subject: [PATCH 02/70] Implement XML loading support for geometry shared between submeshes The new OGRE blender exporter (2.6) creates meshes which make use of this feature. --- src/lib/StdMesh.cpp | 79 +++++---- src/lib/StdMesh.h | 65 +++++--- src/lib/StdMeshLoader.h | 3 +- src/lib/StdMeshLoaderXml.cpp | 307 ++++++++++++++++++++--------------- src/platform/StdGL.cpp | 9 +- 5 files changed, 272 insertions(+), 191 deletions(-) diff --git a/src/lib/StdMesh.cpp b/src/lib/StdMesh.cpp index 724bd242c..8a23d28c4 100644 --- a/src/lib/StdMesh.cpp +++ b/src/lib/StdMesh.cpp @@ -49,8 +49,14 @@ namespace const StdMeshVertex* m_vertices; const StdMeshMatrix& m_global_trans; - StdMeshInstanceFaceOrderingCmpPred(const StdSubMeshInstance& inst, const StdMeshMatrix& global_trans): - m_inst(inst), m_vertices(m_inst.GetVertices()), m_global_trans(global_trans) {} + StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& mesh_inst, const StdSubMeshInstance& sub_inst, const StdMeshMatrix& global_trans): + m_inst(sub_inst), m_global_trans(global_trans) + { + if(sub_inst.GetNumVertices() > 0) + m_vertices = &sub_inst.GetVertices()[0]; + else + m_vertices = &mesh_inst.GetSharedVertices()[0]; + } inline float get_z(const StdMeshVertex& vtx) const { @@ -697,11 +703,16 @@ void StdMeshInstance::AttachedMesh::DenumeratePointers() } StdMeshInstance::StdMeshInstance(const StdMesh& mesh): - Mesh(&mesh), + Mesh(&mesh), SharedVertices(mesh.GetSharedVertices().size()), BoneTransforms(Mesh->GetNumBones(), StdMeshMatrix::Identity()), SubMeshInstances(Mesh->GetNumSubMeshes()), AttachParent(NULL), BoneTransformsDirty(false) { + // Copy initial shared vertices + for (unsigned int i = 0; i < SharedVertices.size(); ++i) + SharedVertices[i] = mesh.GetSharedVertices()[i]; + + // Create submesh instances for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i) { const StdSubMesh& submesh = Mesh->GetSubMesh(i); @@ -1082,34 +1093,14 @@ bool StdMeshInstance::UpdateBoneTransforms() // Compute transformation for each vertex. We could later think about // doing this on the GPU using a vertex shader. This would then probably // need to go to CStdGL::PerformMesh and CStdD3D::PerformMesh. - // (can only work for fixed face ordering though) + // But first, we need to move vertex data to the GPU. + if(!Mesh->GetSharedVertices().empty()) + ApplyBoneTransformToVertices(Mesh->GetSharedVertices(), SharedVertices); for (unsigned int i = 0; i < SubMeshInstances.size(); ++i) { const StdSubMesh& submesh = Mesh->GetSubMesh(i); - std::vector& instance_vertices = SubMeshInstances[i]->Vertices; - assert(submesh.GetNumVertices() == instance_vertices.size()); - for (unsigned int j = 0; j < instance_vertices.size(); ++j) - { - const StdSubMesh::Vertex& vertex = submesh.GetVertex(j); - StdMeshVertex& instance_vertex = instance_vertices[j]; - if (!vertex.BoneAssignments.empty()) - { - instance_vertex.x = instance_vertex.y = instance_vertex.z = 0.0f; - instance_vertex.nx = instance_vertex.ny = instance_vertex.nz = 0.0f; - instance_vertex.u = vertex.u; instance_vertex.v = vertex.v; - - for (unsigned int k = 0; k < vertex.BoneAssignments.size(); ++k) - { - const StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments[k]; - - instance_vertex += assignment.Weight * (BoneTransforms[assignment.BoneIndex] * vertex); - } - } - else - { - instance_vertex = vertex; - } - } + if(!submesh.GetVertices().empty()) + ApplyBoneTransformToVertices(submesh.GetVertices(), SubMeshInstances[i]->Vertices); } } @@ -1156,7 +1147,7 @@ void StdMeshInstance::ReorderFaces(StdMeshMatrix* global_trans) StdSubMeshInstance& inst = *SubMeshInstances[i]; if(inst.CurrentFaceOrdering != StdSubMeshInstance::FO_Fixed) { - StdMeshInstanceFaceOrderingCmpPred pred(inst, global_trans ? *global_trans : StdMeshMatrix::Identity()); + StdMeshInstanceFaceOrderingCmpPred pred(*this, inst, global_trans ? *global_trans : StdMeshMatrix::Identity()); // The usage of timsort instead of std::sort at this point is twofold. // First, it's faster in our case where the array is already sorted in @@ -1312,6 +1303,9 @@ bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node) min = Fix0; max = itofix(1); break; + default: + assert(false); + break; } const C4Real old_value = provider->Value; @@ -1334,8 +1328,6 @@ bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node) // Remove right child as it has less weight StopAnimation(node->LinearInterpolation.ChildRight); } - - } else { @@ -1365,3 +1357,28 @@ bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node) return true; } +void StdMeshInstance::ApplyBoneTransformToVertices(const std::vector& mesh_vertices, std::vector& instance_vertices) +{ + assert(mesh_vertices.size() == instance_vertices.size()); + for (unsigned int j = 0; j < instance_vertices.size(); ++j) + { + const StdSubMesh::Vertex& vertex = mesh_vertices[j]; + StdMeshVertex& instance_vertex = instance_vertices[j]; + if (!vertex.BoneAssignments.empty()) + { + instance_vertex.x = instance_vertex.y = instance_vertex.z = 0.0f; + instance_vertex.nx = instance_vertex.ny = instance_vertex.nz = 0.0f; + instance_vertex.u = vertex.u; instance_vertex.v = vertex.v; + + for (unsigned int k = 0; k < vertex.BoneAssignments.size(); ++k) + { + const StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments[k]; + instance_vertex += assignment.Weight * (BoneTransforms[assignment.BoneIndex] * vertex); + } + } + else + { + instance_vertex = vertex; + } + } +} diff --git a/src/lib/StdMesh.h b/src/lib/StdMesh.h index 2d8ff320a..96f2dd3c1 100644 --- a/src/lib/StdMesh.h +++ b/src/lib/StdMesh.h @@ -127,6 +127,7 @@ public: std::vector BoneAssignments; }; + const std::vector& GetVertices() const { return Vertices; } const Vertex& GetVertex(size_t i) const { return Vertices[i]; } size_t GetNumVertices() const { return Vertices.size(); } @@ -138,7 +139,7 @@ public: private: StdSubMesh(); - std::vector Vertices; + std::vector Vertices; // Empty if we use shared vertices std::vector Faces; const StdMeshMaterial* Material; @@ -154,9 +155,13 @@ class StdMesh public: ~StdMesh(); + typedef StdSubMesh::Vertex Vertex; + const StdSubMesh& GetSubMesh(size_t i) const { return SubMeshes[i]; } size_t GetNumSubMeshes() const { return SubMeshes.size(); } + const std::vector& GetSharedVertices() const { return SharedVertices; } + const StdMeshBone& GetBone(size_t i) const { return *Bones[i]; } size_t GetNumBones() const { return Bones.size(); } const StdMeshBone* GetBoneByName(const StdStrBuf& name) const; @@ -176,6 +181,8 @@ private: StdMesh(const StdMesh& other); // non-copyable StdMesh& operator=(const StdMesh& other); // non-assignable + std::vector SharedVertices; + std::vector SubMeshes; std::vector Bones; // Master Bone Table @@ -202,7 +209,7 @@ public: // Get vertex of instance, with current animation applied. This needs to // go elsewhere if/when we want to calculate this on the hardware. - const StdMeshVertex* GetVertices() const { return &Vertices[0]; } + const std::vector& GetVertices() const { return Vertices; } size_t GetNumVertices() const { return Vertices.size(); } // Get face of instance. The instance faces are the same as the mesh faces, @@ -269,9 +276,10 @@ public: typedef StdSubMeshInstance::FaceOrdering FaceOrdering; - //FaceOrdering GetFaceOrdering() const { return CurrentFaceOrdering; } - void SetFaceOrdering(FaceOrdering ordering); - void SetFaceOrderingForClrModulation(uint32_t clrmod); + enum AttachMeshFlags { + AM_None = 0, + AM_DrawBefore = 1 << 0 + }; // Provider for animation position or weight. class ValueProvider @@ -412,27 +420,6 @@ public: }; }; - AnimationNode* PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight); - AnimationNode* PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight); - void StopAnimation(AnimationNode* node); - - AnimationNode* GetAnimationNodeByNumber(unsigned int number); - AnimationNode* GetRootAnimationForSlot(int slot); - // child bone transforms are dirty (saves matrix inversion for unanimated attach children). - // Set new value providers for a node's position or weight - cannot be in - // class AnimationNode since we need to mark BoneTransforms dirty. - void SetAnimationPosition(AnimationNode* node, ValueProvider* position); - void SetAnimationWeight(AnimationNode* node, ValueProvider* weight); - - // Update animations; call once a frame - // dt is used for texture animation, skeleton animation is updated via value providers - void ExecuteAnimation(float dt); - - enum AttachMeshFlags { - AM_None = 0, - AM_DrawBefore = 1 << 0 - }; - class AttachedMesh { friend class StdMeshInstance; @@ -487,6 +474,29 @@ public: typedef std::vector AttachedMeshList; typedef AttachedMeshList::const_iterator AttachedMeshIter; + //FaceOrdering GetFaceOrdering() const { return CurrentFaceOrdering; } + void SetFaceOrdering(FaceOrdering ordering); + void SetFaceOrderingForClrModulation(uint32_t clrmod); + + AnimationNode* PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight); + AnimationNode* PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight); + void StopAnimation(AnimationNode* node); + + const std::vector& GetSharedVertices() const { return SharedVertices; } + size_t GetNumSharedVertices() const { return SharedVertices.size(); } + + AnimationNode* GetAnimationNodeByNumber(unsigned int number); + AnimationNode* GetRootAnimationForSlot(int slot); + // child bone transforms are dirty (saves matrix inversion for unanimated attach children). + // Set new value providers for a node's position or weight - cannot be in + // class AnimationNode since we need to mark BoneTransforms dirty. + void SetAnimationPosition(AnimationNode* node, ValueProvider* position); + void SetAnimationWeight(AnimationNode* node, ValueProvider* weight); + + // Update animations; call once a frame + // dt is used for texture animation, skeleton animation is updated via value providers + void ExecuteAnimation(float dt); + // Create a new instance and attach it to this mesh. Takes ownership of denumerator AttachedMesh* AttachMesh(const StdMesh& mesh, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation = StdMeshMatrix::Identity(), uint32_t flags = AM_None); // Attach an instance to this instance. Takes ownership of denumerator. If own_child is true deletes instance on detach. @@ -536,9 +546,12 @@ protected: AnimationNodeList::iterator GetStackIterForSlot(int slot, bool create); bool ExecuteAnimationNode(AnimationNode* node); + void ApplyBoneTransformToVertices(const std::vector& mesh_vertices, std::vector& instance_vertices); const StdMesh* Mesh; + std::vector SharedVertices; + AnimationNodeList AnimationNodes; // for simple lookup of animation nodes by their unique number AnimationNodeList AnimationStack; // contains top level nodes only, ordered by slot number std::vector BoneTransforms; diff --git a/src/lib/StdMeshLoader.h b/src/lib/StdMeshLoader.h index e91f8cfec..6385f3b51 100644 --- a/src/lib/StdMeshLoader.h +++ b/src/lib/StdMeshLoader.h @@ -39,7 +39,8 @@ public: class StdMeshLoader { public: -class LoaderException : public std::runtime_error { public: LoaderException(const char *msg) : std::runtime_error(msg) {} }; + class StdMeshXML; + class LoaderException : public std::runtime_error { public: LoaderException(const char *msg) : std::runtime_error(msg) {} }; // filename is only used to show it in error messages. The model is // loaded from src. Throws LoaderException. diff --git a/src/lib/StdMeshLoaderXml.cpp b/src/lib/StdMeshLoaderXml.cpp index ef6838eb3..b17f34781 100644 --- a/src/lib/StdMeshLoaderXml.cpp +++ b/src/lib/StdMeshLoaderXml.cpp @@ -25,7 +25,7 @@ #include // Helper class to load things from an XML file with error checking -class StdMeshXML +class StdMeshLoader::StdMeshXML { public: StdMeshXML(const char* filename, const char* xml_data); @@ -36,6 +36,9 @@ public: TiXmlElement* RequireFirstChild(TiXmlElement* element, const char* child); + void LoadGeometry(StdMesh& mesh, std::vector& vertices, TiXmlElement* boneassignments_elem); + void LoadBoneAssignments(StdMesh& mesh, std::vector& vertices, TiXmlElement* boneassignments_elem); + void Error(const StdStrBuf& message, TiXmlElement* element) const; void Error(const StdStrBuf& message, int row) const; @@ -44,7 +47,7 @@ private: StdStrBuf FileName; }; -StdMeshXML::StdMeshXML(const char* filename, const char* xml_data): +StdMeshLoader::StdMeshXML::StdMeshXML(const char* filename, const char* xml_data): FileName(filename) { Document.Parse(xml_data); @@ -52,14 +55,14 @@ StdMeshXML::StdMeshXML(const char* filename, const char* xml_data): Error(StdStrBuf(Document.ErrorDesc()), Document.ErrorRow()); } -const char* StdMeshXML::RequireStrAttribute(TiXmlElement* element, const char* attribute) const +const char* StdMeshLoader::StdMeshXML::RequireStrAttribute(TiXmlElement* element, const char* attribute) const { const char* value = element->Attribute(attribute); if (!value) Error(FormatString("Element '%s' does not have attribute '%s'", element->Value(), attribute), element); return value; } -int StdMeshXML::RequireIntAttribute(TiXmlElement* element, const char* attribute) const +int StdMeshLoader::StdMeshXML::RequireIntAttribute(TiXmlElement* element, const char* attribute) const { int retval; if (element->QueryIntAttribute(attribute, &retval) != TIXML_SUCCESS) @@ -67,7 +70,7 @@ int StdMeshXML::RequireIntAttribute(TiXmlElement* element, const char* attribute return retval; } -float StdMeshXML::RequireFloatAttribute(TiXmlElement* element, const char* attribute) const +float StdMeshLoader::StdMeshXML::RequireFloatAttribute(TiXmlElement* element, const char* attribute) const { float retval = 0; if (element->QueryFloatAttribute(attribute, &retval) != TIXML_SUCCESS) @@ -75,7 +78,7 @@ float StdMeshXML::RequireFloatAttribute(TiXmlElement* element, const char* attri return retval; } -TiXmlElement* StdMeshXML::RequireFirstChild(TiXmlElement* element, const char* child) +TiXmlElement* StdMeshLoader::StdMeshXML::RequireFirstChild(TiXmlElement* element, const char* child) { TiXmlElement* retval; @@ -95,16 +98,148 @@ TiXmlElement* StdMeshXML::RequireFirstChild(TiXmlElement* element, const char* c return retval; } -void StdMeshXML::Error(const StdStrBuf& message, TiXmlElement* element) const +void StdMeshLoader::StdMeshXML::Error(const StdStrBuf& message, TiXmlElement* element) const { Error(message, element->Row()); } -void StdMeshXML::Error(const StdStrBuf& message, int row) const +void StdMeshLoader::StdMeshXML::Error(const StdStrBuf& message, int row) const { throw StdMeshLoader::LoaderException(FormatString("%s:%u: %s", FileName.getData(), row, message.getData()).getData()); } +void StdMeshLoader::StdMeshXML::LoadGeometry(StdMesh& mesh, std::vector& vertices, TiXmlElement* geometry_elem) +{ + // Check whether mesh has any vertices so far -- we need this later for + // initialization of bounding box and bounding sphere. + bool hasVertices = false; + if(!mesh.SharedVertices.empty()) hasVertices = true; + for(unsigned int i = 0; i < mesh.SubMeshes.size(); ++i) + if(!mesh.SubMeshes[i].Vertices.empty()) + hasVertices = true; + + int VertexCount = RequireIntAttribute(geometry_elem, "vertexcount"); + vertices.resize(VertexCount); + + static const unsigned int POSITIONS = 1; + static const unsigned int NORMALS = 2; + static const unsigned int TEXCOORDS = 4; + + // Individual vertex attributes can be split up in multiple vertex buffers + unsigned int loaded_attributes = 0; + for(TiXmlElement* buffer_elem = geometry_elem->FirstChildElement("vertexbuffer"); buffer_elem != NULL; buffer_elem = buffer_elem->NextSiblingElement("vertexbuffer")) + { + unsigned int attributes = 0; + if(buffer_elem->Attribute("positions")) attributes |= POSITIONS; + if(buffer_elem->Attribute("normals")) attributes |= NORMALS; + if(buffer_elem->Attribute("texture_coords")) attributes |= TEXCOORDS; + + unsigned int i; + TiXmlElement* vertex_elem; + for (vertex_elem = buffer_elem->FirstChildElement("vertex"), i = 0; vertex_elem != NULL && i < vertices.size(); vertex_elem = vertex_elem->NextSiblingElement("vertex"), ++i) + { + if(attributes & POSITIONS) + { + TiXmlElement* position_elem = RequireFirstChild(vertex_elem, "position"); + + vertices[i].x = RequireFloatAttribute(position_elem, "x"); + vertices[i].y = RequireFloatAttribute(position_elem, "y"); + vertices[i].z = RequireFloatAttribute(position_elem, "z"); + + const float d = std::sqrt(vertices[i].x*vertices[i].x + + vertices[i].y*vertices[i].y + + vertices[i].z*vertices[i].z); + + // Construct BoundingBox + StdMeshBox& BoundingBox = mesh.BoundingBox; + if (i == 0 && !hasVertices) + { + // First vertex + BoundingBox.x1 = BoundingBox.x2 = vertices[i].x; + BoundingBox.y1 = BoundingBox.y2 = vertices[i].y; + BoundingBox.z1 = BoundingBox.z2 = vertices[i].z; + mesh.BoundingRadius = d; + } + else + { + BoundingBox.x1 = Min(vertices[i].x, BoundingBox.x1); + BoundingBox.x2 = Max(vertices[i].x, BoundingBox.x2); + BoundingBox.y1 = Min(vertices[i].y, BoundingBox.y1); + BoundingBox.y2 = Max(vertices[i].y, BoundingBox.y2); + BoundingBox.z1 = Min(vertices[i].z, BoundingBox.z1); + BoundingBox.z2 = Max(vertices[i].z, BoundingBox.z2); + mesh.BoundingRadius = Max(mesh.BoundingRadius, d); + } + } + + if(attributes & NORMALS) + { + TiXmlElement* normal_elem = RequireFirstChild(vertex_elem, "normal"); + + vertices[i].nx = RequireFloatAttribute(normal_elem, "x"); + vertices[i].ny = RequireFloatAttribute(normal_elem, "y"); + vertices[i].nz = RequireFloatAttribute(normal_elem, "z"); + } + + if(attributes & TEXCOORDS) + { + TiXmlElement* texcoord_elem = RequireFirstChild(vertex_elem, "texcoord"); + vertices[i].u = RequireFloatAttribute(texcoord_elem, "u"); + vertices[i].v = RequireFloatAttribute(texcoord_elem, "v"); + } + } + + if(vertex_elem != NULL) + Error(FormatString("Too many vertices in vertexbuffer"), buffer_elem); + if(i < vertices.size()) + Error(FormatString("Not enough vertices in vertexbuffer"), buffer_elem); + + loaded_attributes |= attributes; + } + + static const unsigned int REQUIRED_ATTRIBUTES = POSITIONS | NORMALS | TEXCOORDS; + if((loaded_attributes & REQUIRED_ATTRIBUTES) != REQUIRED_ATTRIBUTES) + Error(FormatString("Not all required vertex attributes (positions, normals, texcoords) present in mesh geometry"), geometry_elem); +} + +void StdMeshLoader::StdMeshXML::LoadBoneAssignments(StdMesh& mesh, std::vector& vertices, TiXmlElement* boneassignments_elem) +{ + for (TiXmlElement* vertexboneassignment_elem = boneassignments_elem->FirstChildElement("vertexboneassignment"); vertexboneassignment_elem != NULL; vertexboneassignment_elem = vertexboneassignment_elem->NextSiblingElement("vertexboneassignment")) + { + int BoneID = RequireIntAttribute(vertexboneassignment_elem, "boneindex"); + int VertexIndex = RequireIntAttribute(vertexboneassignment_elem, "vertexindex"); + float weight = RequireFloatAttribute(vertexboneassignment_elem, "weight"); + + if (VertexIndex < 0 || static_cast(VertexIndex) >= vertices.size()) + Error(FormatString("Vertex index in bone assignment (%d) is out of range", VertexIndex), vertexboneassignment_elem); + + StdMeshBone* bone = NULL; + for (unsigned int i = 0; !bone && i < mesh.Bones.size(); ++i) + if (mesh.Bones[i]->ID == BoneID) + bone = mesh.Bones[i]; + + if (!bone) Error(FormatString("There is no such bone with ID %d", BoneID), vertexboneassignment_elem); + + StdSubMesh::Vertex& vertex = vertices[VertexIndex]; + vertex.BoneAssignments.push_back(StdMeshVertexBoneAssignment()); + StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments.back(); + assignment.BoneIndex = bone->Index; + assignment.Weight = weight; + } + + // Normalize vertex bone assignment weights (this is not guaranteed in the + // Ogre file format). + for (unsigned int i = 0; i < vertices.size(); ++i) + { + StdSubMesh::Vertex& vertex = vertices[i]; + float sum = 0.0f; + for (unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j) + sum += vertex.BoneAssignments[j].Weight; + for (unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j) + vertex.BoneAssignments[j].Weight /= sum; + } +} + StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const StdMeshMatManager& manager, StdMeshSkeletonLoader& skel_loader, const char* filename) { StdMeshXML xml(filename ? filename : "", xml_data); @@ -112,13 +247,17 @@ StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const Std std::auto_ptr mesh(new StdMesh); TiXmlElement* mesh_elem = xml.RequireFirstChild(NULL, "mesh"); + + // Load shared geometry, if any + TiXmlElement* sharedgeometry_elem = mesh_elem->FirstChildElement("sharedgeometry"); + if(sharedgeometry_elem != NULL) + xml.LoadGeometry(*mesh, mesh->SharedVertices, sharedgeometry_elem); + TiXmlElement* submeshes_elem = xml.RequireFirstChild(mesh_elem, "submeshes"); TiXmlElement* submesh_elem_base = xml.RequireFirstChild(submeshes_elem, "submesh"); for (TiXmlElement* submesh_elem = submesh_elem_base; submesh_elem != NULL; submesh_elem = submesh_elem->NextSiblingElement("submesh")) { - TiXmlElement* geometry_elem = xml.RequireFirstChild(submesh_elem, "geometry"); - mesh->SubMeshes.push_back(StdSubMesh()); StdSubMesh& submesh = mesh->SubMeshes.back(); @@ -127,88 +266,20 @@ StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const Std if (!submesh.Material) xml.Error(FormatString("There is no such material named '%s'", material), submesh_elem); - int VertexCount = xml.RequireIntAttribute(geometry_elem, "vertexcount"); - submesh.Vertices.resize(VertexCount); - - static const unsigned int POSITIONS = 1; - static const unsigned int NORMALS = 2; - static const unsigned int TEXCOORDS = 4; - - // Individual vertex attributes can be split up in multiple vertex buffers - unsigned int loaded_attributes = 0; - for(TiXmlElement* buffer_elem = geometry_elem->FirstChildElement("vertexbuffer"); buffer_elem != NULL; buffer_elem = buffer_elem->NextSiblingElement("vertexbuffer")) + const char* usesharedvertices = submesh_elem->Attribute("usesharedvertices"); + const std::vector* vertices; + if(!usesharedvertices || strcmp(usesharedvertices, "true") != 0) { - unsigned int attributes = 0; - if(buffer_elem->Attribute("positions")) attributes |= POSITIONS; - if(buffer_elem->Attribute("normals")) attributes |= NORMALS; - if(buffer_elem->Attribute("texture_coords")) attributes |= TEXCOORDS; - - unsigned int i; - TiXmlElement* vertex_elem; - for (vertex_elem = buffer_elem->FirstChildElement("vertex"), i = 0; vertex_elem != NULL && i < submesh.Vertices.size(); vertex_elem = vertex_elem->NextSiblingElement("vertex"), ++i) - { - if(attributes & POSITIONS) - { - TiXmlElement* position_elem = xml.RequireFirstChild(vertex_elem, "position"); - - submesh.Vertices[i].x = xml.RequireFloatAttribute(position_elem, "x"); - submesh.Vertices[i].y = xml.RequireFloatAttribute(position_elem, "y"); - submesh.Vertices[i].z = xml.RequireFloatAttribute(position_elem, "z"); - - const float d = std::sqrt(submesh.Vertices[i].x*submesh.Vertices[i].x - + submesh.Vertices[i].y*submesh.Vertices[i].y - + submesh.Vertices[i].z*submesh.Vertices[i].z); - - // Construct BoundingBox - StdMeshBox &BoundingBox = mesh->BoundingBox; - if (i == 0 && mesh->SubMeshes.size() == 1) - { - // First vertex - BoundingBox.x1 = BoundingBox.x2 = submesh.Vertices[i].x; - BoundingBox.y1 = BoundingBox.y2 = submesh.Vertices[i].y; - BoundingBox.z1 = BoundingBox.z2 = submesh.Vertices[i].z; - mesh->BoundingRadius = d; - } - else - { - BoundingBox.x1 = Min(submesh.Vertices[i].x, BoundingBox.x1); - BoundingBox.x2 = Max(submesh.Vertices[i].x, BoundingBox.x2); - BoundingBox.y1 = Min(submesh.Vertices[i].y, BoundingBox.y1); - BoundingBox.y2 = Max(submesh.Vertices[i].y, BoundingBox.y2); - BoundingBox.z1 = Min(submesh.Vertices[i].z, BoundingBox.z1); - BoundingBox.z2 = Max(submesh.Vertices[i].z, BoundingBox.z2); - mesh->BoundingRadius = Max(mesh->BoundingRadius, d); - } - } - - if(attributes & NORMALS) - { - TiXmlElement* normal_elem = xml.RequireFirstChild(vertex_elem, "normal"); - - submesh.Vertices[i].nx = xml.RequireFloatAttribute(normal_elem, "x"); - submesh.Vertices[i].ny = xml.RequireFloatAttribute(normal_elem, "y"); - submesh.Vertices[i].nz = xml.RequireFloatAttribute(normal_elem, "z"); - } - - if(attributes & TEXCOORDS) - { - TiXmlElement* texcoord_elem = xml.RequireFirstChild(vertex_elem, "texcoord"); - submesh.Vertices[i].u = xml.RequireFloatAttribute(texcoord_elem, "u"); - submesh.Vertices[i].v = xml.RequireFloatAttribute(texcoord_elem, "v"); - } - } - - if(vertex_elem != NULL) - xml.Error(FormatString("Too many vertices in vertexbuffer"), buffer_elem); - if(i < submesh.Vertices.size()) - xml.Error(FormatString("Not enough vertices in vertexbuffer"), buffer_elem); - - loaded_attributes |= attributes; + TiXmlElement* geometry_elem = xml.RequireFirstChild(submesh_elem, "geometry"); + xml.LoadGeometry(*mesh, submesh.Vertices, geometry_elem); + vertices = &submesh.Vertices; + } + else + { + if(mesh->SharedVertices.empty()) + xml.Error(StdCopyStrBuf("Submesh specifies to use shared vertices but there is no shared geometry"), submesh_elem); + vertices = &mesh->SharedVertices; } - - static const unsigned int REQUIRED_ATTRIBUTES = POSITIONS | NORMALS | TEXCOORDS; - if((loaded_attributes & REQUIRED_ATTRIBUTES) != REQUIRED_ATTRIBUTES) - xml.Error(FormatString("Not all required vertex attributes (positions, normals, texcoords) present in mesh geometry"), geometry_elem); TiXmlElement* faces_elem = xml.RequireFirstChild(submesh_elem, "faces"); int FaceCount = xml.RequireIntAttribute(faces_elem, "count"); @@ -225,7 +296,7 @@ StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const Std for (unsigned int j = 0; j < 3; ++j) { - if (v[j] < 0 || static_cast(v[j]) >= submesh.Vertices.size()) + if (v[j] < 0 || static_cast(v[j]) >= vertices->size()) xml.Error(FormatString("Vertex index v%u (%d) is out of range", j+1, v[j]), face_elem); submesh.Faces[i].Vertices[j] = v[j]; } @@ -318,46 +389,22 @@ StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const Std if (bones[i]->Parent == NULL) mesh->AddMasterBone(bones[i]); + // Vertex<->Bone assignments for shared geometry + if(sharedgeometry_elem) + { + TiXmlElement* boneassignments_elem = xml.RequireFirstChild(mesh_elem, "boneassignments"); + xml.LoadBoneAssignments(*mesh, mesh->SharedVertices, boneassignments_elem); + } + // Vertex<->Bone assignments for all vertices (need to go through SubMeshes again...) unsigned int submesh_index = 0; for (TiXmlElement* submesh_elem = submesh_elem_base; submesh_elem != NULL; submesh_elem = submesh_elem->NextSiblingElement("submesh"), ++submesh_index) { StdSubMesh& submesh = mesh->SubMeshes[submesh_index]; - - TiXmlElement* boneassignments_elem = xml.RequireFirstChild(submesh_elem, "boneassignments"); - for (TiXmlElement* vertexboneassignment_elem = boneassignments_elem->FirstChildElement("vertexboneassignment"); vertexboneassignment_elem != NULL; vertexboneassignment_elem = vertexboneassignment_elem->NextSiblingElement("vertexboneassignment")) + if(!submesh.Vertices.empty()) { - int BoneID = xml.RequireIntAttribute(vertexboneassignment_elem, "boneindex"); - int VertexIndex = xml.RequireIntAttribute(vertexboneassignment_elem, "vertexindex"); - float weight = xml.RequireFloatAttribute(vertexboneassignment_elem, "weight"); - - if (VertexIndex < 0 || static_cast(VertexIndex) >= submesh.Vertices.size()) - xml.Error(FormatString("Vertex index in bone assignment (%d) is out of range", VertexIndex), vertexboneassignment_elem); - - StdMeshBone* bone = NULL; - for (unsigned int i = 0; !bone && i < bones.size(); ++i) - if (bones[i]->ID == BoneID) - bone = bones[i]; - - if (!bone) xml.Error(FormatString("There is no such bone with index %d", BoneID), vertexboneassignment_elem); - - StdSubMesh::Vertex& vertex = submesh.Vertices[VertexIndex]; - vertex.BoneAssignments.push_back(StdMeshVertexBoneAssignment()); - StdMeshVertexBoneAssignment& assignment = vertex.BoneAssignments.back(); - assignment.BoneIndex = bone->Index; - assignment.Weight = weight; - } - - // Normalize vertex bone assignment weights (this is not guaranteed in the - // Ogre file format). - for (unsigned int i = 0; i < submesh.Vertices.size(); ++i) - { - StdSubMesh::Vertex& vertex = submesh.Vertices[i]; - float sum = 0.0f; - for (unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j) - sum += vertex.BoneAssignments[j].Weight; - for (unsigned int j = 0; j < vertex.BoneAssignments.size(); ++j) - vertex.BoneAssignments[j].Weight /= sum; + TiXmlElement* boneassignments_elem = xml.RequireFirstChild(submesh_elem, "boneassignments"); + xml.LoadBoneAssignments(*mesh, submesh.Vertices, boneassignments_elem); } } @@ -441,16 +488,18 @@ StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const Std else { // Mesh has no skeleton + // Bone assignements do not make sense then, as the + // actual bones are defined in the skeleton file. for (TiXmlElement* submesh_elem = submesh_elem_base; submesh_elem != NULL; submesh_elem = submesh_elem->NextSiblingElement("submesh")) { TiXmlElement* boneassignments_elem = submesh_elem->FirstChildElement("boneassignments"); if (boneassignments_elem) - { - // Bone assignements do not make sense then, as the - // actual bones are defined in the skeleton file. xml.Error(StdStrBuf("Mesh has bone assignments, but no skeleton"), boneassignments_elem); - } } + + TiXmlElement* boneassignments_elem = mesh_elem->FirstChildElement("boneassignments"); + if (boneassignments_elem) + xml.Error(StdStrBuf("Mesh has bone assignments, but no skeleton"), boneassignments_elem); } // Apply parent transformation to each bone transformation. We need to diff --git a/src/platform/StdGL.cpp b/src/platform/StdGL.cpp index 869f82315..8db62ff95 100644 --- a/src/platform/StdGL.cpp +++ b/src/platform/StdGL.cpp @@ -710,11 +710,12 @@ namespace } } - void RenderSubMeshImpl(const StdSubMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool parity) + void RenderSubMeshImpl(const StdMeshInstance& mesh_instance, const StdSubMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool parity) { const StdMeshMaterial& material = instance.GetMaterial(); assert(material.BestTechniqueIndex != -1); const StdMeshMaterialTechnique& technique = material.Techniques[material.BestTechniqueIndex]; + const StdMeshVertex* vertices = instance.GetVertices().empty() ? &mesh_instance.GetSharedVertices()[0] : &instance.GetVertices()[0]; // Render each pass for (unsigned int i = 0; i < technique.Passes.size(); ++i) @@ -861,7 +862,7 @@ namespace // states that "The texture coordinate state for other client texture units // is not updated, regardless of whether the client texture unit is enabled // or not." - glInterleavedArrays(GL_N3F_V3F, sizeof(StdMeshVertex), &instance.GetVertices()[0].nx); + glInterleavedArrays(GL_N3F_V3F, sizeof(StdMeshVertex), &vertices->nx); glMatrixMode(GL_TEXTURE); GLuint have_texture = 0; @@ -890,7 +891,7 @@ namespace glBindTexture(GL_TEXTURE_2D, have_texture); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(StdMeshVertex), &instance.GetVertices()[0].u); + glTexCoordPointer(2, GL_FLOAT, sizeof(StdMeshVertex), &vertices->u); // Setup texture coordinate transform glLoadIdentity(); @@ -1114,7 +1115,7 @@ namespace // Render each submesh for (unsigned int i = 0; i < mesh.GetNumSubMeshes(); ++i) - RenderSubMeshImpl(instance.GetSubMesh(i), dwModClr, dwBlitMode, dwPlayerColor, parity); + RenderSubMeshImpl(instance, instance.GetSubMesh(i), dwModClr, dwBlitMode, dwPlayerColor, parity); #if 0 // Draw attached bone From ac8edd6e2067bce90bba36cabc1e1aa71211f073 Mon Sep 17 00:00:00 2001 From: Nicolas Hake Date: Thu, 16 Feb 2012 00:34:31 +0100 Subject: [PATCH 03/70] Binary mesh loader: Support animations without tracks --- src/lib/StdMeshLoaderBinaryChunks.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/StdMeshLoaderBinaryChunks.cpp b/src/lib/StdMeshLoaderBinaryChunks.cpp index 8a27cc65d..d94c70f12 100644 --- a/src/lib/StdMeshLoaderBinaryChunks.cpp +++ b/src/lib/StdMeshLoaderBinaryChunks.cpp @@ -417,12 +417,11 @@ namespace Ogre { name = stream->Read(); duration = stream->Read(); - while (Chunk::Peek(stream) == CID_Animation_Track) + while (!stream->AtEof() && Chunk::Peek(stream) == CID_Animation_Track) { Chunk *chunk = Chunk::Read(stream); assert(chunk->GetType() == CID_Animation_Track); tracks.push_back(static_cast(chunk)); - if (stream->AtEof()) break; } } From db9ff85116ab39db0cdbaa47750e0ddc5c870d59 Mon Sep 17 00:00:00 2001 From: Nicolas Hake Date: Thu, 16 Feb 2012 00:45:48 +0100 Subject: [PATCH 04/70] Binary mesh loader: Do not reject meshes with multi texturing We don't support multi texturing in the rendering code, so emit a warning when this happens --- src/game/object/C4DefGraphics.cpp | 4 ++-- src/lib/StdMeshLoaderBinary.cpp | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/game/object/C4DefGraphics.cpp b/src/game/object/C4DefGraphics.cpp index 0d87b520e..9545af43c 100644 --- a/src/game/object/C4DefGraphics.cpp +++ b/src/game/object/C4DefGraphics.cpp @@ -160,9 +160,9 @@ bool C4DefGraphics::LoadMesh(C4Group &hGroup, StdMeshSkeletonLoader& loader) try { if (hGroup.LoadEntry(C4CFN_DefMesh, &buf, &size, 1)) - Mesh = StdMeshLoader::LoadMeshBinary(buf, size, ::MeshMaterialManager, loader); + Mesh = StdMeshLoader::LoadMeshBinary(buf, size, ::MeshMaterialManager, loader, hGroup.GetName()); else if (hGroup.LoadEntry(C4CFN_DefMeshXml, &buf, &size, 1)) - Mesh = StdMeshLoader::LoadMeshXml(buf, size, ::MeshMaterialManager, loader); + Mesh = StdMeshLoader::LoadMeshXml(buf, size, ::MeshMaterialManager, loader, hGroup.GetName()); else return false; delete[] buf; diff --git a/src/lib/StdMeshLoaderBinary.cpp b/src/lib/StdMeshLoaderBinary.cpp index de3fc8ef1..fbf2befff 100644 --- a/src/lib/StdMeshLoaderBinary.cpp +++ b/src/lib/StdMeshLoaderBinary.cpp @@ -33,7 +33,7 @@ namespace { - bool VertexDeclarationIsSane(const boost::ptr_vector &decl) + bool VertexDeclarationIsSane(const boost::ptr_vector &decl, const char *filename) { bool semanticSeen[Ogre::Mesh::ChunkGeometryVertexDeclElement::VDES_MAX + 1] = { false }; BOOST_FOREACH(Ogre::Mesh::ChunkGeometryVertexDeclElement element, decl) @@ -43,6 +43,11 @@ namespace case Ogre::Mesh::ChunkGeometryVertexDeclElement::VDES_Texcoords: // Normally, you can use multiple texture coordinates, but we currently support only one. // So complain if we get multiple sets. + if (semanticSeen[element.semantic]) + { + DebugLogF("[FIXME] %s: Vertex declaration with multiple sets of texture coordinates found; game will only use the first.", filename && *filename ? filename : ""); + } + break; case Ogre::Mesh::ChunkGeometryVertexDeclElement::VDES_Position: case Ogre::Mesh::ChunkGeometryVertexDeclElement::VDES_Normals: case Ogre::Mesh::ChunkGeometryVertexDeclElement::VDES_Diffuse: @@ -93,9 +98,9 @@ namespace } } - std::vector ReadSubmeshGeometry(const Ogre::Mesh::ChunkGeometry &geo) + std::vector ReadSubmeshGeometry(const Ogre::Mesh::ChunkGeometry &geo, const char *filename) { - if (!VertexDeclarationIsSane(geo.vertexDeclaration)) + if (!VertexDeclarationIsSane(geo.vertexDeclaration, filename)) throw Ogre::Mesh::InvalidVertexDeclaration(); // Get maximum size of a vertex according to the declaration @@ -144,6 +149,7 @@ namespace vertex.nx = vertex.ny = vertex.nz = 0; vertex.x = vertex.y = vertex.z = 0; vertex.u = vertex.v = 0; + bool read_tex = false; // Read vertex declaration BOOST_FOREACH(Ogre::Mesh::ChunkGeometryVertexDeclElement element, geo.vertexDeclaration) { @@ -162,8 +168,11 @@ namespace vertex.nz = values[2]; break; case Ogre::Mesh::ChunkGeometryVertexDeclElement::VDES_Texcoords: - vertex.u = values[0]; - vertex.v = values[1]; + if (!read_tex) { + vertex.u = values[0]; + vertex.v = values[1]; + read_tex = true; + } break; default: // We ignore unhandled element semantics. @@ -242,7 +251,7 @@ StdMesh *StdMeshLoader::LoadMeshBinary(const char *src, size_t length, const Std sm.Faces[face].Vertices[2] = csm.faceVertices[face * 3 + 2]; } Ogre::Mesh::ChunkGeometry &geo = *(csm.hasSharedVertices ? cmesh.geometry : csm.geometry); - sm.Vertices = ReadSubmeshGeometry(geo); + sm.Vertices = ReadSubmeshGeometry(geo, filename); // Read bone assignments std::vector &boneAssignments = (csm.hasSharedVertices ? cmesh.boneAssignments : csm.boneAssignments); From 1b5ee016d495d49658900174f00a8cdd979c6b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Brammer?= Date: Thu, 16 Feb 2012 22:58:45 +0100 Subject: [PATCH 05/70] Fix build without OpenGL --- src/C4Prototypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/C4Prototypes.h b/src/C4Prototypes.h index 24677808f..7cbaf8023 100644 --- a/src/C4Prototypes.h +++ b/src/C4Prototypes.h @@ -143,6 +143,7 @@ class C4AbstractApp; class C4Window; class C4Surface; class CStdStream; +class CStdGLCtx; namespace C4GUI { From 3c4e4ec1fdce896b6f6389744c6e9d6782bddad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Brammer?= Date: Tue, 14 Feb 2012 22:48:11 +0100 Subject: [PATCH 06/70] win32: Installer uses English in non-German locales Good thing that one can test this with Wine by changing the LANG environment variable. --- tools/install/oc.nsi | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/install/oc.nsi b/tools/install/oc.nsi index 0a420560c..fc6114f7c 100644 --- a/tools/install/oc.nsi +++ b/tools/install/oc.nsi @@ -65,14 +65,14 @@ FunctionEnd !insertmacro MUI_UNPAGE_INSTFILES ; Language files -!insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "German" ; Additional language strings -LangString MUI_TEXT_USERPATH ${LANG_German} "Benutzerpfad" -LangString MUI_TEXT_USERPATH ${LANG_English} "User Path" +LangString OC_TEXT_USERPATH ${LANG_German} "Benutzerpfad" +LangString OC_TEXT_USERPATH ${LANG_English} "User Path" -!insertmacro MUI_RESERVEFILE_LANGDLL +;!insertmacro MUI_RESERVEFILE_LANGDLL ;ReserveFile "${NSISDIR}\Plugins\*.dll" ; MUI end ------ @@ -132,14 +132,14 @@ Section CreateShortcut "$DESKTOP\OpenClonk.lnk" "$INSTDIR\Clonk.exe" ; Create user path shortcut in program directory - CreateShortCut "$INSTDIR\$(MUI_TEXT_USERPATH).lnk" "%APPDATA%\OpenClonk" + CreateShortCut "$INSTDIR\$(OC_TEXT_USERPATH).lnk" "%APPDATA%\OpenClonk" ; Start menu shortcuts CreateDirectory "$SMPROGRAMS\OpenClonk" CreateShortCut "$SMPROGRAMS\OpenClonk\OpenClonk.lnk" "$INSTDIR\Clonk.exe" CreateShortCut "$SMPROGRAMS\OpenClonk\OpenClonk Editor.lnk" "$INSTDIR\Clonk.exe" "--editor" CreateShortCut "$SMPROGRAMS\OpenClonk\${PRODUCT_WEB_SITE_NAME}.lnk" "$INSTDIR\${PRODUCT_WEB_SITE_NAME}.url" - CreateShortCut "$SMPROGRAMS\OpenClonk\$(MUI_TEXT_USERPATH).lnk" "%APPDATA%\OpenClonk" + CreateShortCut "$SMPROGRAMS\OpenClonk\$(OC_TEXT_USERPATH).lnk" "%APPDATA%\OpenClonk" EndStartMenu: ; Uninstaller info @@ -238,7 +238,7 @@ Section Uninstall Delete "$INSTDIR\uninst.exe" Delete "$INSTDIR\GameExplorer.txt" Delete "$INSTDIR\${PRODUCT_WEB_SITE_NAME}.url" - Delete "$INSTDIR\$(MUI_TEXT_USERPATH).lnk" + Delete "$INSTDIR\$(OC_TEXT_USERPATH).lnk" RMDir "$INSTDIR" From 833d5a6f766a4239f58f4f9ab608de67cff0d6f7 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sat, 18 Feb 2012 22:48:00 +0100 Subject: [PATCH 07/70] SpoutBerryBush: added Place-function to be called on scenario initialization --- .../Vegetation.ocd/SproutBerryBush.ocd/Script.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/SproutBerryBush.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/SproutBerryBush.ocd/Script.c index ea4ffe092..8eeed1ae6 100644 --- a/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/SproutBerryBush.ocd/Script.c +++ b/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/SproutBerryBush.ocd/Script.c @@ -18,6 +18,17 @@ static const SproutBerryBush_water_per_berry = 10; static const SproutBerryBush_max_sprouts = 8; static const SproutBerryBush_evolve_steps_per_new_sprout = 2; +// static function +func Place(int amount) +{ + // place some sprout berries + var bush = PlaceVegetation(SproutBerryBush, 0, LandscapeHeight() / 3, LandscapeWidth(), LandscapeHeight(), 100000); + if(bush) + for (var i = 1; i < amount; i++) + PlaceVegetation(SproutBerryBush, bush->GetX() - 200, bush->GetY() - 200, 400, 400, 100000); + return true; +} + func Construction() { SetCon(100); From 5cbaa697f09575f2c2a30068370e4b09233719f4 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sat, 18 Feb 2012 22:50:18 +0100 Subject: [PATCH 08/70] changed power system to transfer power freely in a base and get rid of power lines power now is either available or not - there is no "produce X power and save it somewhere" anymore --- .../Helpers.ocd/FloatingMessage.ocd/Script.c | 3 + .../Libraries.ocd/Flag.ocd/Script.c | 246 ++++++------ .../Libraries.ocd/Power.ocd/DefCore.txt | 7 + .../Libraries.ocd/Power.ocd/Graphics.png | Bin 0 -> 124 bytes .../Libraries.ocd/Power.ocd/Script.c | 362 ++++++++++++++++++ .../Libraries.ocd/Power.ocd/StringTblDE.txt | 2 + .../Libraries.ocd/Power.ocd/StringTblUS.txt | 2 + .../Libraries.ocd/PowerConsumer.ocd/Script.c | 156 +++----- .../PowerGenerator.ocd/Graphics.png | Bin 141 -> 0 bytes .../Libraries.ocd/PowerGenerator.ocd/Script.c | 133 ------- .../DefCore.txt | 2 +- .../PowerProducer.ocd/Graphics.png | Bin 0 -> 91 bytes .../Libraries.ocd/PowerProducer.ocd/Script.c | 10 + .../Libraries.ocd/Producer.ocd/Script.c | 87 ++--- .../Elevator.ocd/Case.ocd/Script.c | 67 +++- .../Structures.ocd/Elevator.ocd/Script.c | 2 +- .../Structures.ocd/Flagpole.ocd/DefCore.txt | 1 + .../Structures.ocd/Foundry.ocd/Script.c | 2 +- .../Structures.ocd/Idol.ocd/Script.c | 3 + .../Structures.ocd/Pump.ocd/Script.c | 29 +- .../Structures.ocd/Sawmill.ocd/Script.c | 3 +- .../Structures.ocd/SteamEngine.ocd/Script.c | 51 ++- .../Structures.ocd/ToolsWorkshop.ocd/Script.c | 13 +- .../Structures.ocd/WindGenerator.ocd/Script.c | 14 +- .../Structures.ocd/Windmill.ocd/Script.c | 30 +- .../Structures.ocd/WoodenCabin.ocd/Script.c | 1 + 26 files changed, 754 insertions(+), 472 deletions(-) create mode 100644 planet/Objects.ocd/Libraries.ocd/Power.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Libraries.ocd/Power.ocd/Graphics.png create mode 100644 planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c create mode 100644 planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblDE.txt create mode 100644 planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblUS.txt delete mode 100644 planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Graphics.png delete mode 100644 planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Script.c rename planet/Objects.ocd/Libraries.ocd/{PowerGenerator.ocd => PowerProducer.ocd}/DefCore.txt (65%) create mode 100644 planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Graphics.png create mode 100644 planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Script.c diff --git a/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c index 19a5a50b8..7d50c0d9a 100644 --- a/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c +++ b/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c @@ -69,5 +69,8 @@ public func Initialize() SetComDir(COMD_None); SetSpeed(0, -20); alpha=255; + r = 255; + g = 255; + b = 255; return true; } \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c index 1f8918cab..6d02a8892 100644 --- a/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c @@ -14,7 +14,7 @@ public func IsFlagpole(){return true;} global func GetFlagpoleForPosition(int x, int y) { - if(GetType(LibraryFlag_flag_list) != C4V_Array) return NO_OWNER; + if(GetType(LibraryFlag_flag_list) != C4V_Array) return nil; var oldest = nil, oldest_time = 0; @@ -45,6 +45,49 @@ func RefreshAllFlagLinks() { f->ScheduleRefreshLinkedFlags(); } + + // update power balance for power helpers after refreshing the linked flags + Schedule(nil, "Library_Flag->RefreshAllPowerHelpers()", 2, 0); + AddEffect("ScheduleRefreshAllPowerHelpers", 0, 1, 2, nil, Library_Flag); +} + +func FxScheduleRefreshAllPowerHelpersTimer() +{ + Library_Flag->RefreshAllPowerHelpers(); + return -1; +} + +func RefreshAllPowerHelpers() +{ + + // special handling for neutral + var neutral = nil; + for(var obj in Library_Power_power_compounds) + { + if(!obj.neutral) continue; + neutral = obj; + break; + } + + if(neutral) + { + RefreshPowerHelper(neutral); + } + + // same for all helpers - delete / refresh + for(var i = GetLength(Library_Power_power_compounds); --i >= 0;) + { + var obj = Library_Power_power_compounds[i]; + if(GetLength(obj.power_links) == 0 && GetLength(obj.sleeping_links) == 0) + { + obj->RemoveObject(); + Library_Power_power_compounds[i] = Library_Power_power_compounds[GetLength(Library_Power_power_compounds) - 1]; + SetLength(Library_Power_power_compounds, GetLength(Library_Power_power_compounds) - 1); + continue; + } + + obj->CheckPowerBalance(); + } } func RedrawFlagRadius() @@ -89,58 +132,6 @@ func RedrawFlagRadius() } } - // check allied flags - // don't draw inner border - /* - if(draw && GetLength(other_flags)) - { - var own_flags = []; - - for(var f in LibraryFlag_flag_list) - { - if(f->GetOwner() != GetOwner()) continue; - if(f == this) continue; - own_flags[i++] = f; - } - - // sort own flags for age - insert sort okay here since probably 99% sorted already - for(var fi = 1; fi < GetLength(own_flags); ++fi) - { - var ft = own_flags[fi]; - var t = ft->GetFlagConstructionTime(); - for(var ci = fi-1; ci >= 0; ++ci) - { - if(own_flags[ci]->GetFlagConstructionTime() >= t) continue; - - // right position? - if(ci == fi-1) break; - - // move to the right - for(var mi = ci+1;miGetX(),f->GetY())<(FLAG_DISTANCE)) - { - if(GetLifeTime()> f->GetLifeTime() && e->GetLifeTime() < f->GetLifeTime()) - draw=true; - } - } - } - } - } //if(draw) - */ if(!draw) { if(marker_index < GetLength(lflag.range_markers)) @@ -162,63 +153,6 @@ func RedrawFlagRadius() lflag.range_markers[marker_index] = marker; } - // uter Border - /* - for(var i=0; i<10; i++) - { - SetLength(outers,0); - var f=nil; - draw=true; - var x= Sin(i*36 - time, lflag.radius); - var y=-Cos(i*36 - time, lflag.radius); - if(flags) - for(var f in flags) - { - if(Distance(GetX()+x,GetY()+y,f->GetX(),f->GetY())GetLifeTime() < target->GetLifeTime()) - { - outers[GetLength(outers)] = f; - } - else - draw=false; - } - } - if(outers) - { - var newf=nil; - for(var f in outers) - { - var d=0; - if(f->GetLifeTime()>d) - { - d=f->GetLifeTime(); - newf=f; - } - } - } - if(!newf) continue; - var fl=nil; - fl = FindObjects(Find_ID(FlagPole),Find_Exclude(target), Find_Owner(GetOwner()), Find_Distance(FLAG_DISTANCE ,x,y),Sort_Func("GetLifeTime")); - if(fl[0] && draw && flags) - { - draw=false; - for(var f in flags) - { - for(var e in fl) - { - if(Distance(GetX()+x,GetY()+y,f->GetX(),f->GetY())<(FLAG_DISTANCE)) - { - if(GetLifeTime()> f->GetLifeTime() && e->GetLifeTime() < f->GetLifeTime()) - draw=true; - } - } - } - } - if(!draw) - continue; - CreateParticle("Magic",Sin(i*36 - time, FLAG_DISTANCE+1),-Cos(i*36 - time, FLAG_DISTANCE+1),0,0,10+Random(4),newf.color); - }*/ } func RefreshOwnershipOfSurrounding() @@ -232,25 +166,11 @@ func RefreshOwnershipOfSurrounding() obj->~OnOwnerChange(old); } } - -public func Construction() +public func Initialize() { - if(GetType(LibraryFlag_flag_list) != C4V_Array) - LibraryFlag_flag_list = []; - if(GetIndexOf(this, LibraryFlag_flag_list) == -1) LibraryFlag_flag_list[GetLength(LibraryFlag_flag_list)] = this; - - lflag = - { - construction_time = FrameCounter(), - radius = LibraryFlag_standard_radius, - range_markers = [], - linked_flags = [], - energy_producers = [], - energy_consumers = [] - }; - + // redraw RedrawAllFlagRadiuses(); @@ -258,8 +178,23 @@ public func Construction() RefreshOwnershipOfSurrounding(); // linked flags - optimization for power system - RefreshLinkedFlags(); + RefreshAllFlagLinks(); +} + +public func Construction() +{ + if(GetType(LibraryFlag_flag_list) != C4V_Array) + LibraryFlag_flag_list = []; + lflag = + { + construction_time = FrameCounter(), + radius = LibraryFlag_standard_radius, + range_markers = [], + linked_flags = [], + power_helper = nil + }; + return _inherited(...); } @@ -335,10 +270,63 @@ func RefreshLinkedFlags() } } + lflag.linked_flags = current; + + // update flag links for all linked flags - no need for every flag to do that + // meanwhile, adjust power helper. Merge if necessary + // since we don't know whether flag links have been lost we will create a new power helper and possibly remove old ones + var old = lflag.power_helper; + lflag.power_helper = CreateObject(Library_Power, 0, 0, NO_OWNER); + Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = lflag.power_helper; + + // list of helpers yet to merge + var to_merge = [old]; + + // copy from me + lflag.linked_flags = current; for(var other in lflag.linked_flags) { other->CopyLinkedFlags(this, lflag.linked_flags); + + if(GetIndexOf(other.lflag.power_helper, to_merge) == -1) + to_merge[GetLength(to_merge)] = other.lflag.power_helper; + other.lflag.power_helper = lflag.power_helper; + } + + // for every object in to_merge check if it actually (still) belongs to the group + for(var h in to_merge) + { + if(h == nil) + continue; + RefreshPowerHelper(h); + } +} + +func RefreshPowerHelper(h) +{ + // merge both power_links and sleeping_links + for(var o in h.power_links) + { + if(o == nil) continue; // possible + + var actual = Library_Power->GetPowerHelperForObject(o.obj); + if(actual == h) continue; // right one already + // remove from old and add to new + h->RemovePowerLink(o.obj, true); + actual->AddPowerLink(o.obj, o.amount, true); + } + + for(var i = GetLength(h.sleeping_links); --i >= 0;) + { + var o = h.sleeping_links[i]; + var actual = Library_Power->GetPowerHelperForObject(o.obj); + if(actual == h) continue; // right one already + // remove from old one and add to new + actual.sleeping_links[GetLength(actual.sleeping_links)] = o; + + h.sleeping_links[i] = h.sleeping_links[GetLength(h.sleeping_links) - 1]; + SetLength(h.sleeping_links, GetLength(h.sleeping_links) - 1); } } @@ -351,6 +339,10 @@ public func CopyLinkedFlags(object from, array flaglist) StopRefreshLinkedFlags(); } +public func GetPowerHelper(){return lflag.power_helper;} +public func SetPowerHelper(object to){lflag.power_helper = to;} + +public func GetLinkedFlags(){return lflag.linked_flags;} private func ClearFlagMarkers() { diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Power.ocd/DefCore.txt new file mode 100644 index 000000000..cbce74f68 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Power.ocd/DefCore.txt @@ -0,0 +1,7 @@ +[DefCore] +id=Library_Power +Version=4,10,0,0 +Category=C4D_StaticBack +Width=1 +Height=1 +Offset=-1,-1 \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/Graphics.png b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Graphics.png new file mode 100644 index 0000000000000000000000000000000000000000..9bb8607e911791f4c7eaf1b6d31570c3796da97d GIT binary patch literal 124 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}bl_7YEDSN5A6+(L$Y3YW`tfI^%F z9+AZi3|t>Tn9*sC$qb+%OS+@4BLl<6e(pbstUx}ur;B4q#jWH71||juRtCnGzwX=s P3Nv`R`njxgN@xNAq3|1& literal 0 HcmV?d00001 diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c new file mode 100644 index 000000000..a0136a531 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c @@ -0,0 +1,362 @@ +/** + Power + Cares about power management of a base. + + callbacks: + QueryWaivePowerRequest() + OnNotEnoughPower() + OnEnoughPower() + + globals: + MakePowerConsumer(int amount) + MakePowerProducer(int amount) + IsPowerAvailable(int amount) + +*/ + +local Name = "$Name$"; +local Description = "$Description$"; + +static Library_Power_power_compounds; + +// for the helper definitions +local power_links; // producers and consumers +local sleeping_links; +local power_balance; // performance +local neutral; // is "the" neutral helper? + +func Initialize() +{ + power_links = []; + sleeping_links = []; + power_balance = 0; + neutral = false; +} + + +func AddPowerProducer(object p, int a) +{ + return AddPowerLink(p, a); +} + +func AddPowerConsumer(object p, int a) +{ + + // possibly sleeping? + { + for(var i = GetLength(sleeping_links); --i >= 0;) + { + var o = sleeping_links[i]; + if(o.obj != p) continue; + + // did not affect power balance, we can just remove/change the link + if(a == 0) // remove + { + sleeping_links[i] = sleeping_links[GetLength(sleeping_links)]; + SetLength(sleeping_links, GetLength(sleeping_links) - 1); + return true; + } + sleeping_links[i].amount = a; + return true; + } + } + + // not asleep + return AddPowerLink(p, -a); +} + +func RemovePowerLink(object p) +{ + return AddPowerLink(p, 0); +} + +func AddPowerLink(object p, int a, bool surpress_balance_check) +{ + var n = {obj = p, amount = a}; + + var found = false; + var first_empty = -1; + var diff = 0; + for(var i = GetLength(power_links); --i >= 0;) + { + var o = power_links[i]; + if(o == nil) // possible + { + first_empty = i; + continue; + } + + if(o.obj == nil) // removed from outside + { + power_links[i] = nil; + continue; + } + + if(o.obj != p) continue; + found = true; + + diff = a - o.amount; + power_balance += diff; + + if(a == 0) power_links[i] = nil; + else power_links[i] = n; + break; + } + + if(!found) + { + // place to insert? + if(a != 0) + { + if(first_empty != -1) + power_links[first_empty] = n; + else + power_links[GetLength(power_links)] = n; + } + diff = n.amount; + power_balance += diff; + } + + diff = n.amount; + if(diff > 0) + { + var t = CreateObject(FloatingMessage, n.obj->GetX() - GetX(), n.obj->GetY() - GetY(), NO_OWNER); + t->SetMessage(Format("+%d{{Library_PowerConsumer}}", diff)); + t->SetYDir(-10); + } + else if(diff < 0) + { + var t = CreateObject(FloatingMessage, n.obj->GetX() - GetX(), n.obj->GetY() - GetY(), NO_OWNER); + t->SetMessage(Format("%d{{Library_PowerConsumer}}", diff)); + t->SetYDir(-10); + } + if(n.amount < 0) + n.obj->~OnEnoughPower(); // might be reverted soon, though + + if(!surpress_balance_check) + CheckPowerBalance(); + return true; +} + +func CheckPowerBalance() +{ + // special handling for ownerless links + // always sleep + if(neutral) + { + for(var i = GetLength(power_links); --i >= 0;) + { + var o = power_links[i]; + if(o == nil) continue; + if(o.amount > 0) continue; // producer + SleepLink(i); + } + return false; + } + + //Message("@Power: %d", power_balance); + + if(power_balance >= 0) // alrighty + { + // we are good to go + // we could revive sleeping links at this point + + if(GetLength(sleeping_links)) + { + for(var i = GetLength(sleeping_links); --i >= 0;) + { + var o = sleeping_links[i]; + if(o.obj == nil) + { + sleeping_links[i] = sleeping_links[GetLength(sleeping_links)]; + SetLength(sleeping_links, GetLength(sleeping_links) - 1); + continue; + } + if(power_balance + o.amount < 0) continue; + + // found link to revive! + UnsleepLink(i); + + // can not continue since UnsleepLink changes the array + return true; + } + } + + return true; + } + + // something happened + // something evil + + // look for consumer to kick out of system + // best-fit strategy (or volunteers) + + var best_fit = 0xFFFFFF; + var best_volunteer = 0; + var best = -1; + var abs_diff = Abs(power_balance); + for(var i = GetLength(power_links); --i >= 0;) + { + var o = power_links[i]; + if(o == nil) continue; + if(o.amount > 0) continue; // producer + + var d = Abs(((-o.amount) - abs_diff)); + + var v = o.obj->~QueryWaivePowerRequest(); + + if(!best_volunteer) // no volunteers yet + { + if((d < best_fit) || (best == nil) || (v > 0)) + { + best_fit = d; + best = i; + + if(v) + best_volunteer = v; + } + } + else // we already have volunteers + { + if(v < best_volunteer) continue; + best_volunteer = v; + best = i; + } + } + + // total blackout? No consumer active anymore? + if(best == -1) + { + return false; + } + + // has object + SleepLink(best); + + // recurse + // might revive weaker consumer or sleep another one + CheckPowerBalance(); + + return false; +} + +func SleepLink(int index) +{ + if(index < 0 || index >= GetLength(power_links)) + return FatalError("SleepLink() called without valid index!"); + + // only consumers, sleeping producers does not make sense... + var o = power_links[index]; + if(o.amount > 0) return FatalError("SleepLink() trying to sleep producer!"); + + // delete from list + power_links[index] = nil; + power_balance -= o.amount; + sleeping_links[GetLength(sleeping_links)] = o; + + // sadly not enough power anymore + o.obj->~OnNotEnoughPower(); + + return true; +} + +func UnsleepLink(int index) +{ + if(index < 0 || index >= GetLength(sleeping_links)) + return FatalError("UnsleepLink() called without valid index!"); + + var o = sleeping_links[index]; + + // delete + sleeping_links[index] = sleeping_links[GetLength(sleeping_links) - 1]; + SetLength(sleeping_links, GetLength(sleeping_links) - 1); + + return AddPowerLink(o.obj, o.amount); // revives the link +} + +public func IsPowerAvailable(object obj, int amount) +{ + // ignore object for now + return power_balance > amount; +} + +public func Init() +{ + if(GetType(Library_Power_power_compounds) != C4V_Array) + Library_Power_power_compounds = []; +} + +// static +func GetPowerHelperForObject(object who) +{ + var w; + while(w = who->~GetActualPowerConsumer()) + { + if(w == who) break; // nope + who = w; + } + var flag = GetFlagpoleForPosition(who->GetX() - GetX(), who->GetY() - GetY()); + + var helper = nil; + if(!flag) // neutral - needs neutral helper + { + for(var obj in Library_Power_power_compounds) + { + if(!obj.neutral) continue; + helper = obj; + break; + } + + if(helper == nil) // not yet created? + { + helper = CreateObject(Library_Power, 0, 0, NO_OWNER); + helper.neutral = true; + Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = helper; + } + + } + else + { + helper=flag->GetPowerHelper(); + + if(helper == nil) + { + helper = CreateObject(Library_Power, 0, 0, NO_OWNER); + Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = helper; + + // add to all linked flags + flag->SetPowerHelper(helper); + for(var f in flag->GetLinkedFlags()) + { + if(f->GetPowerHelper() != nil) // assert + FatalError("Flags in compound have different power helper!"); + f->SetPowerHelper(helper); + } + } + } + + return helper; +} + +global func MakePowerProducer(int amount) +{ + if(!this) return false; + Library_Power->Init(); + return (Library_Power->GetPowerHelperForObject(this))->AddPowerProducer(this, amount); +} + +global func IsPowerAvailable(int amount) +{ + if(!this) return false; + Library_Power->Init(); + return (Library_Power->GetPowerHelperForObject(this))->IsPowerAvailable(this, amount); +} + +global func MakePowerConsumer(int amount) +{ + if(!this) return false; + Library_Power->Init(); + return (Library_Power->GetPowerHelperForObject(this))->AddPowerConsumer(this, amount); +} + +// helper object \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblDE.txt b/planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblDE.txt new file mode 100644 index 000000000..7210f2d27 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=Energy +Description=Kümmert sich um das Energiemanagement. \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblUS.txt b/planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblUS.txt new file mode 100644 index 000000000..468234fbd --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Power.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=Power +Description=Cares about power management of a base. \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c index c72bee0e2..006abdc32 100644 --- a/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c @@ -1,114 +1,66 @@ /** Power consumer - Should be included by all power consumers. The consumer can check and consume power by calling - the function CheckPower(int power_check, bool no_substract), see below for an explanation. + Cares about showing the "No Power"-symbol + and provides CurrentlyHasPower() + The rest is handled by Library_Power +*/ + +local PowerConsumer_has_power = 0; + + +public func CurrentlyHasPower() +{ + return PowerConsumer_has_power; +} + +// interface to power handling: + +// is the object just a part of a building? +// elevator <-> case for example +public func GetActualPowerConsumer() +{ + return nil; +} + +// how much would you like to withdraw your power request? +// normal objects: not so much, battery: very much! +public func QueryWaivePowerRequest() +{ + return 0; +} + +// the object requested power but there is no power! +public func OnNotEnoughPower() +{ + PowerConsumer_has_power = false; - @author Maikel -*/ - - -/** Determines whether the object is a power consumer. - @return \c true if the object is a power consumer and \c false otherwise. -*/ -public func IsPowerConsumer() -{ - return true; + // show symbol + if(GetEffect("ShowPowerMessage", this)) + FatalError("OnNotEnoughPower() called two times in a row!"); + AddEffect("ShowPowerMessage", this, 1, 10, this); } -/** Determines whether a power line can be connected. - @return \c true if a power line can be connected to this object, \c false otherwise. -*/ -public func CanPowerConnect() // Other name? +// called when consumer was sleeping but power is available again +public func OnEnoughPower() { - return GetCon() >= 100; + PowerConsumer_has_power = true; + + // remove symbol + if(GetEffect("ShowPowerMessage", this)) + RemoveEffect("ShowPowerMessage", this); } -/*-- Power consumption --*/ - -/** Inspects the network connected to the calling consumer for power. - @param power_check amount of power to extract from the network. - @param no_substract determines whether the check should substract power_check. - @return \c true if the amount of power was available in the network, \c false otherwise. -*/ -public func CheckPower(int power_check, bool no_substract) +public func FxShowPowerMessageTimer(target, effect, time) { - // Power consumer only need energy if the rule is active. - if (!FindObject(Find_ID(Rule_EnergyNeed))) - return true; - // Check all power generators connected to this consumer and sort them according to priority. - // TODO: Maybe substract partial amounts from high priority generators. - for (var generator in FindObjects(Find_PowerGenerator(), Sort_GeneratorPriority())) - { - var power = generator->GetPower(); - if (power > power_check) - { - if (!no_substract) - generator->DoPower(-power_check); - RemoveEffect("EnergyNeed", this); - return true; - } - } - if (!GetEffect("EnergyNeed", this)) AddEffect("EnergyNeed", this, 100, 12, this); - return false; + if(effect.Interval < 35*3) + effect.Interval = 35*3; + var t = CreateObject(FloatingMessage, 0, 0, NO_OWNER); + t->SetMessage("{{Library_PowerConsumer}}?"); + t->SetYDir(-10); } -// Finds all power generators connected to consumer (can be nil in local calls). -private func Find_PowerGenerator(object consumer) +func Destruction() { - if (!consumer) - consumer = this; - return [C4FO_Func, "IsPowerGeneratorFor", consumer]; -} - -// Sorts power generators according to GetGeneratorPriority(), highest return value -> first in array. -private func Sort_GeneratorPriority() -{ - return [C4SO_Reverse, [C4SO_Func, "GetGeneratorPriority"]]; -} - -/*-- Effect to show energy need --*/ - -private func FxEnergyNeedStart(object target, effect, int temp) -{ - // Start showing energy need symbol. - target->SetGraphics(nil, Library_PowerConsumer, GFX_Overlay, GFXOV_MODE_Base); - target->SetObjDrawTransform(1000, 0, 0, 0, 1000, -500 * GetID()->GetDefCoreVal("Height", "DefCore"), GFX_Overlay); - effect.show_symbol = true; // Effect is showing symbol. - return 1; -} - -private func FxEnergyNeedTimer(object target, effect, int time) -{ - // Alternate showing of the symbol: timer interval of AddEffect determines alternation time. - if (effect.show_symbol) // Effect was showing symbol. - { - // Do not show symbol. - target->SetGraphics(nil, nil, GFX_Overlay, GFXOV_MODE_Base); - effect.show_symbol = false; - } - else // Effect was not showing symbol. - { - // Do show symbol. - target->SetGraphics(nil, Library_PowerConsumer, GFX_Overlay, GFXOV_MODE_Base); - target->SetObjDrawTransform(1000, 0, 0, 0, 1000, -500 * GetID()->GetDefCoreVal("Height", "DefCore"), GFX_Overlay); - effect.show_symbol = true; - } - return 1; -} - -private func FxEnergyNeedStop(object target, effect, int iReason, bool temp) -{ - // Stop showing energy need symbol. - target->SetGraphics(nil, nil, GFX_Overlay, GFXOV_MODE_Base); - return 1; -} - -private func FxEnergyNeedEffect(string name, object target) -{ - // Only one energy need effect per consumer. - if (name == "EnergyNeed") - return -1; - return 1; -} - - + MakePowerProducer(0); + return _inherited(...); +} \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Graphics.png b/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Graphics.png deleted file mode 100644 index 753695654c8a1413f2e2a51b20165116a5b0ec82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k92}K#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*x37`TN&n2}-D90{Nxdx@v7EBj3@R(=__hQk{gfkM2VE{-7_*OL=~ Z0LW!!V2t~$Wd&q0c)I$ztaD0e0st2;AF%)c diff --git a/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Script.c deleted file mode 100644 index da17b5632..000000000 --- a/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/Script.c +++ /dev/null @@ -1,133 +0,0 @@ -/** - Power generator - Should be included by all power generators. - Explanation of the interface see public funcs below. - - @author Maikel -*/ - - -// Local variable to keep track of the power level inside the generator. -local power; - -/** Determines whether the object is a power generator. - @return \c true if the object is a power generator and \c false otherwise. -*/ -public func IsPowerGenerator() -{ - return true; -} - -/** Determines whether a power line can be connected. - @return \c true if a power line can be connected to this object, \c false otherwise. -*/ -public func CanPowerConnect() // Other name? -{ - return GetCon() >= 100; -} - -/** Determines the power capacity of the generator, i.e. the maximum amount of power it can store. Should be overloaded by the generator. - @return the power capacity. -*/ -public func GetCapacity() -{ - return 0; -} - -/** Determines the generator's priority, consumers preferably drain from generators with the higher priorities. Should be overloaded by the generator. - @return the generator's priority. -*/ -public func GetGeneratorPriority() -{ - return 1; -} - -/*-- Power network --*/ -// Functions to check the power network. - -/** Determines whether the calling object is a power generator for the specified consumer. - @param consumer object for which to check if the generator is connected to it. - @return \c true if the calling generator is connected to the consumer, \c false otherwise. -*/ -public func IsPowerGeneratorFor(object consumer, object next, object old_line, array pwr_list) -{ - if (!next) // Initial call to this function. - { - next = consumer; - pwr_list = []; - } - for (var line in FindObjects(Find_PowerLine(next))) // Check all lines connected to next. - { - if (line == old_line) // Recursive -> Not backwards<->forwards through lines. - continue; - //if (!line->IsConnectedWith(next)) // Power line connected with consumer. - // continue; - var end = line -> GetConnectedObject(next); // What is on the line's other end. - if (!end) // Nothing on the other end. - continue; - if (end == consumer) // End of a recursive loop. - continue; - if (GetIndexOf(end, pwr_list) != -1) // We already know this. - continue; - if (end == this) // Found this object, i.e. the generator. - return true; - pwr_list[GetLength(pwr_list)] = end; - if (IsPowerGeneratorFor(consumer, end, line, pwr_list)) // This building is not found, continue with next end as next building. - return true; - } - return false; -} - -// Finds all power lines connected to line (can be nil in local calls). -private func Find_PowerLine(object line) -{ - if (!line) - line = this; - return [C4FO_Func, "IsConnectedTo", line]; -} - -/*-- Power generation --*/ -// Functions that manipulate the power level. - -/** Determines the power level. - @return the current power level of this object. -*/ -public func GetPower() -{ - return power; -} - -/** Sets the current power level of the calling object. - @param to_power the new power level. - @return nil. -*/ -public func SetPower(int to_power) -{ - power = BoundBy(to_power, 0, GetCapacity()); - return; -} - - -/** Changes the current power level of the calling object. - @param do_power the amount of power to be added. - @return nil. -*/ -public func DoPower(int do_power) -{ - power = BoundBy(power + do_power, 0, GetCapacity()); - return; -} - -/*-- Debug --*/ - -protected func Initialize() -{ - //AddEffect("ShowPower", this, 100, 10, this); - return _inherited(...); -} - -private func FxShowPowerTimer(object target, int num, int time) -{ - Message("Power:%d", target->GetPower()); - return true; -} diff --git a/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/DefCore.txt similarity index 65% rename from planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/DefCore.txt rename to planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/DefCore.txt index 2eb0de5af..99fe1f2ef 100644 --- a/planet/Objects.ocd/Libraries.ocd/PowerGenerator.ocd/DefCore.txt +++ b/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/DefCore.txt @@ -1,4 +1,4 @@ [DefCore] -id=Library_PowerGenerator +id=Library_PowerProducer Version=5,2,0,1 Category=C4D_StaticBack diff --git a/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Graphics.png b/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Graphics.png new file mode 100644 index 0000000000000000000000000000000000000000..a28d190b8aa10a7b8b747a5a8343077d4f2804d8 GIT binary patch literal 91 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}bl&H|6fVg?3oArNM~bhqvgP>|Qt k#WAE}PV$fc|LvI>IQ}sGTRv;S0-ywgr>mdKI;Vst02|>JwEzGB literal 0 HcmV?d00001 diff --git a/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Script.c new file mode 100644 index 000000000..1a2f852f0 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/PowerProducer.ocd/Script.c @@ -0,0 +1,10 @@ +/** + Power producer + Should be included by all power generators. +*/ + +func Destruction() +{ + MakePowerProducer(0); + return _inherited(...); +} diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c index de8218981..cd1a6e11d 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c @@ -336,7 +336,8 @@ protected func FxProcessQueueTimer(object target, proplist effect) private func ProductionTime(id product) { return product->~GetProductionTime(); } private func FuelNeed(id product) { return product->~GetFuelNeed(); } private func LiquidNeed(id product) { return product->~GetLiquidNeed(); } -private func PowerNeed(id product) { return product->~GetPowerNeed(); } + +private func PowerNeed() { return 200; } private func Produce(id product) { @@ -354,7 +355,7 @@ private func Produce(id product) if (!CheckLiquids(product)) return false; // Check need for power. - if (!CheckForPower(product)) + if (!CheckForPower()) return false; // Everything available? Start production. @@ -443,15 +444,9 @@ private func CheckLiquids(id product, bool remove) return true; } -private func CheckForPower(id product) +private func CheckForPower() { - if (PowerNeed() > 0) - { - // At least ten percent of the power need must be in the network. - if (!CheckPower(PowerNeed() / 10, true)) - return false; - } - return true; + return true; // always assume that power is available } private func IsProducing() @@ -463,7 +458,7 @@ private func IsProducing() protected func FxProcessProductionStart(object target, proplist effect, int temporary, id product) { - if (temporary != 0) + if (temporary) return 1; // Set product. @@ -472,47 +467,44 @@ protected func FxProcessProductionStart(object target, proplist effect, int temp // Set production duration to zero. effect.Duration = 0; - // Set energy usage to zero. - effect.Energy = 0; - // Production is active. effect.Active = true; - - //Log("Production started on %i", effect.Product); - + // Callback to the producer. this->~OnProductionStart(effect.Product); + // consume power + if(PowerNeed() > 0) + MakePowerConsumer(PowerNeed()); + return 1; } +func OnNotEnoughPower() +{ + var effect = GetEffect("ProcessProduction", this); + if(effect) + { + effect.Active = false; + this->~OnProductionHold(effect.Product, effect.Duration); + } else FatalError("Producer effect removed when power still active!"); + return _inherited(...); +} + +func OnEnoughPower() +{ + var effect = GetEffect("ProcessProduction", this); + if(effect) + { + effect.Active = true; + this->~OnProductionContinued(effect.Product, effect.Duration); + } else FatalError("Producer effect removed when power still active!"); + return _inherited(...); +} + protected func FxProcessProductionTimer(object target, proplist effect, int time) { - // Check if energy is available. - if (PowerNeed() > 0) - { - var eng = PowerNeed() * (effect.Duration + effect.Interval) / ProductionTime(); - if (CheckPower(eng - effect.Energy)) - { - // Energy available, add to Energy value and continue production. - effect.Energy = eng; - if (!effect.Active) - { - this->~OnProductionContinued(effect.Product, effect.Duration); - effect.Active = true; - } - } - else - { - // Hold production if energy is not available, callback to the producer. - if (effect.Active) - { - this->~OnProductionHold(effect.Product, effect.Duration); - effect.Active = false; - } - return 1; - } - } + if(!effect.Active) return 1; // Add effect interval to production duration. effect.Duration += effect.Interval; @@ -526,10 +518,19 @@ protected func FxProcessProductionTimer(object target, proplist effect, int time return 1; } -protected func FxProcessProductionStop(object target, proplist effect, int reason) +protected func FxProcessProductionStop(object target, proplist effect, int reason, bool temp) { + if(temp) return; + + // no need to consume power anymore + MakePowerConsumer(0); + + if (reason != 0) return 1; + + + // Callback to the producer. //Log("Production finished on %i after %d frames", effect.Product, effect.Duration); this->~OnProductionFinish(effect.Product); diff --git a/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Case.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Case.ocd/Script.c index 642fa3b05..6e9f93c6d 100644 --- a/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Case.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Case.ocd/Script.c @@ -1,5 +1,7 @@ /*-- Elevator case --*/ +#include Library_PowerConsumer + local elevator; func Connect(object connect_to) @@ -7,6 +9,9 @@ func Connect(object connect_to) elevator = connect_to; SetComDir(COMD_None); SetAction("Drive"); + + // request power + MakePowerConsumer(50); } /* Movement behaviour */ @@ -15,6 +20,40 @@ local move_to, // Y-coordinate to move to on its own move_to_delay, // Delay before moving move_to_target; // Target to move to +// for the position +func GetActualPowerConsumer() +{ + return elevator; +} + +// the lift may not need power when not used +func QueryWaivePowerRequest() +{ + if(!movement && !drill) + return 10; + else return 0; +} + +func OnNotEnoughPower() +{ + // Stop movement if moving + Halt(); + movement = 0; + ClearMoveTo(); + if (drill) + { + SetAction("Drive"); + Sound("ElevatorDrilling", nil, nil, nil, -1); + drill = false; + } + return _inherited(...); +} + +func OnEnoughPower() +{ + return _inherited(...); +} + func Movement() // TimerCall { // No elevator?! @@ -24,22 +63,9 @@ func Movement() // TimerCall if (!ActIdle()) SetAction("Idle"); return; } - // Check for power - if (!elevator->CheckPower(1, true)) - { - // Stop movement if moving - Halt(); - movement = 0; - ClearMoveTo(); - if (drill) - { - SetAction("Drive"); - Sound("ElevatorDrilling", nil, nil, nil, -1); - drill = false; - } - return; - } - + + + // Fetch vehicles for (var vehicle in FindObjects(Find_InRect(-5, -5, 10, 10), Find_Category(C4D_Vehicle), Find_NoContainer(), Find_Func("FitsInElevator"))) { @@ -50,7 +76,11 @@ func Movement() // TimerCall vehicle->SetR(); AddEffect("ElevatorControl", vehicle, 30, 5, nil, nil, this); } - + + // no power? + if(!CurrentlyHasPower()) + return; + // Start or stop drilling if (drill && GetAction() == "Drive") { @@ -86,8 +116,6 @@ func Movement() // TimerCall { if (Abs(GetYDir()) == 1) elevator->StartEngine(); SetYDir(GetYDir() + movement); - // Elevator consumes 1 power per frame - elevator->CheckPower(1); return; } } @@ -122,7 +150,6 @@ func Movement() // TimerCall if (move_to > GetY() && GetYDir() < this.RushSpeed) SetYDir(GetYDir() + 1); if (Abs(GetYDir()) == 1) elevator->StartEngine(); - elevator->CheckPower(1); return; } diff --git a/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Script.c index 49e85aa9c..ff2164b9a 100644 --- a/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Elevator.ocd/Script.c @@ -1,6 +1,6 @@ /*-- Elevator --*/ -#include Library_PowerConsumer +#include Library_Ownable local case, rope; diff --git a/planet/Objects.ocd/Structures.ocd/Flagpole.ocd/DefCore.txt b/planet/Objects.ocd/Structures.ocd/Flagpole.ocd/DefCore.txt index db5add571..1ebc2f0a5 100644 --- a/planet/Objects.ocd/Structures.ocd/Flagpole.ocd/DefCore.txt +++ b/planet/Objects.ocd/Structures.ocd/Flagpole.ocd/DefCore.txt @@ -15,3 +15,4 @@ Components=Wood=4;Metal=1 Picture=30,0,80,94 Exclusive=1 Construction=1 +ColorByOwner=1 diff --git a/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c index 0a5c91050..e6ba6ecc6 100644 --- a/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c @@ -5,7 +5,7 @@ Melts iron ore to metal, using some sort of fuel. --*/ - +#include Library_Ownable #include Library_Producer public func Construction() diff --git a/planet/Objects.ocd/Structures.ocd/Idol.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Idol.ocd/Script.c index 91bc421fb..54f4fd760 100644 --- a/planet/Objects.ocd/Structures.ocd/Idol.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Idol.ocd/Script.c @@ -1,2 +1,5 @@ + +#include Library_Ownable + local Name = "$Name$"; local Touchable = 1; diff --git a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c index 99cff22fc..7ed6997ae 100644 --- a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c @@ -5,6 +5,7 @@ Pumps liquids using drain and source pipes. --*/ +#include Library_Ownable #include Library_PowerConsumer @@ -14,6 +15,7 @@ public func IsLiquidPump() { return true; } protected func Initialize() { SetAction("Wait"); + MakePowerConsumer(100); return; } @@ -28,6 +30,27 @@ public func GetSource() { return source_pipe; } public func SetDrain(object pipe) { drain_pipe = pipe; } public func GetDrain() { return drain_pipe; } +func QueryWaivePowerRequest() +{ + // don't need power if not pumping anyway + if(GetAction() == "Wait") + return 50; + return 0; +} + +func OnNotEnoughPower() +{ + if(GetAction() == "Pump") + SetAction("Wait"); + return _inherited(...); +} + +func OnEnoughPower() +{ + OnWaitStart(); + return _inherited(...); +} + protected func OnPumpStart() { if (!ReadyToPump()) @@ -46,9 +69,6 @@ local aMaterials=["", 0]; //contained liquids protected func Pumping() { - // Only proceed if there is enough power available. - if (!CheckPower(2)) - return SetAction("Wait"); // Pump liquids. if (!source_pipe) return SetAction("Wait"); @@ -77,6 +97,9 @@ protected func Pumping() // Returns whether the pump can pump some liquid. private func ReadyToPump() { + // no power? + if(!CurrentlyHasPower()) + return false; // If there is no source pipe, return false. if (!source_pipe) return false; diff --git a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c index 795b1750f..16a8ad118 100644 --- a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c @@ -5,6 +5,7 @@ Cuts trees or other objects into wood. Accepts only objects purely made from wood. --*/ +#include Library_Ownable #include Library_Producer public func Construction() @@ -57,7 +58,7 @@ private func IsProduct(id product_id) return product_id->~IsSawmillProduct(); } private func ProductionTime() { return 100; } -private func PowerNeed(id product) { return 100; } +private func PowerNeed() { return 100; } public func NeedRawMaterial(id rawmat_id) { diff --git a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c index 207ece275..09fc0fd99 100644 --- a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c @@ -1,17 +1,15 @@ /*-- Steam engine --*/ -#include Library_PowerGenerator - -/*-- Power system --*/ - -public func GetCapacity() { return 500; } -public func GetGeneratorPriority() { return 128; } +#include Library_Ownable +#include Library_PowerProducer local iFuelAmount; +local power_seconds; func Construction() { iFuelAmount = 0; + power_seconds = 0; return _inherited(...); } @@ -21,10 +19,6 @@ func ContentsCheck() if(!ActIdle()) return true; - // No need for power? - if(GetPower() >= GetCapacity()) - return true; - // Still has some fuel? if(iFuelAmount) return SetAction("Work"); @@ -48,16 +42,15 @@ func ContentsCheck() } func ConsumeFuel() -{ - // Are we full? Stop - if(GetPower() >= GetCapacity()) - return SetAction("Idle"); +{ + if(iFuelAmount > 0) + { + // every fuel unit gives power for ten seconds + power_seconds += 10; + if(!GetEffect("CreatesPower", this)) + AddEffect("CreatesPower", this, 1, 36, this); + } - // Use up fuel and create power - DoPower(50); - if(iFuelAmount) - iFuelAmount--; - // All used up? if(!iFuelAmount) { @@ -66,6 +59,26 @@ func ConsumeFuel() } } +func FxCreatesPowerStart(target, effect, temp) +{ + if(temp) return; + // fixed amount + MakePowerProducer(100); +} + +func FxCreatesPowerTimer(target, effect) +{ + if(power_seconds == 0) return -1; + --power_seconds; +} + +func FxCreatesPowerStop(target, effect, reason, temp) +{ + if(temp) return; + // fixed amount + MakePowerProducer(0); +} + local ActMap = { Work = { Prototype = Action, diff --git a/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c index bb6ee0f71..87c6913c9 100644 --- a/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c @@ -1,13 +1,15 @@ /*-- Tools workshop --*/ -#include Library_PowerConsumer +#include Library_Ownable #include Library_Producer +local hold_production; public func Initialize() { // SetProperty("MeshTransformation", Trans_Rotate(RandomX(-30,30),0,1,0)); + hold_production = false; return _inherited(...); } @@ -21,7 +23,7 @@ public func IsProduct(id product_id) } private func ProductionTime() { return 150; } -private func PowerNeed(id product) { return 150; } +private func PowerNeed() { return 150; } public func NeedRawMaterial(id rawmat_id) { @@ -32,17 +34,19 @@ public func OnProductionStart(id product) { SetSign(product); AddEffect("Working", this, 100, 1, this); + hold_production = false; return; } public func OnProductionHold(id product) { + hold_production = true; return; } public func OnProductionContinued(id product) { - + hold_production = false; return; } @@ -55,7 +59,8 @@ public func OnProductionFinish(id product) protected func FxWorkingTimer() { - Smoking(); + if(!hold_production) + Smoking(); return 1; } diff --git a/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c index dc3d5347d..05d3a1e94 100644 --- a/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c @@ -1,6 +1,7 @@ /*-- Wind generator --*/ -#include Library_PowerGenerator +#include Library_Ownable +#include Library_PowerProducer public func GetCapacity() { return 500; } public func GetGeneratorPriority() { return 256; } @@ -8,7 +9,7 @@ public func GetGeneratorPriority() { return 256; } /* Initialisierung */ local wind_anim; - +local last_wind; protected func Construction() { SetProperty("MeshTransformation",Trans_Mul(Trans_Rotate(RandomX(-15,15),0,1,0), Trans_Translate(1200,0,0))); @@ -25,8 +26,13 @@ protected func Initialize() func Wind2Turn() { - DoPower(Abs(GetWind()/3)); - + if(GetCon() < 100) return; + + if(last_wind != Abs(GetWind())) + { + last_wind = Abs(GetWind()); + MakePowerProducer(2 * last_wind); + } // Fade linearly in time until next timer call var start = 0; var end = GetAnimationLength("Turn"); diff --git a/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c index f3cb27c15..51d4a6f62 100644 --- a/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c @@ -2,12 +2,16 @@ Windmill Authors: Ringwaul, Clonkonaut - Crushes seeds into flour if there is wind or another power source. + Crushes seeds into flour using power - is an own power producer too --*/ +#include Library_Ownable #include Library_Producer +#include Library_PowerConsumer +#include Library_PowerProducer local wind_anim; +local last_wind; protected func Construction() { @@ -25,6 +29,8 @@ protected func Initialize() func Wind2Turn() { + if(GetCon() < 100) return; + // Fade linearly in time until next timer call var start = 0; var end = GetAnimationLength("Spin"); @@ -33,11 +39,16 @@ func Wind2Turn() start = end; end = 0; } - + + if(last_wind != Abs(GetWind())) + { + last_wind = Abs(GetWind()); + MakePowerProducer(2 * last_wind); + } + // Number of frames for one revolution: the more wind the more revolutions per frame. - var wind = Abs(GetWind()); - if(wind == 0) wind = 1; - var l = 18000/wind; + if(last_wind == 0) last_wind = 1; + var l = 18000/last_wind; // Note ending is irrelevant since this is called again after 35 frames if(l > 0) @@ -50,13 +61,6 @@ func Wind2Turn() } } -// Overloaded from PowerConsumer -// As long as their is wind, the windmill has power -public func CheckPower() -{ - if (Abs(GetWind())) return true; - return inherited(...); -} /*-- Production --*/ @@ -67,7 +71,7 @@ private func IsProduct(id product_id) return product_id->~IsWindmillProduct(); } private func ProductionTime() { return 290; } -private func PowerNeed(id product) { return 100; } +private func PowerNeed() { return 75; } public func NeedRawMaterial(id rawmat_id) { diff --git a/planet/Objects.ocd/Structures.ocd/WoodenCabin.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/WoodenCabin.ocd/Script.c index c096a50fd..39de5b8c3 100644 --- a/planet/Objects.ocd/Structures.ocd/WoodenCabin.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/WoodenCabin.ocd/Script.c @@ -1,5 +1,6 @@ /*-- Wooden Cabin --*/ +#include Library_Ownable #include Library_DoorControl public func Initialize() From 4d1b10a23ae3ce744020bea65da549ca688ee428 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 19 Feb 2012 00:45:10 +0100 Subject: [PATCH 09/70] Removed Cable reel and power line --- .../GoldRush.ocs/Scenario.txt | 8 +- .../BeyondTheRocks.ocf/GoldRush.ocs/Script.c | 16 +--- .../IronPeak.ocs/Scenario.txt | 8 +- .../BeyondTheRocks.ocf/IronPeak.ocs/Script.c | 4 +- .../Tools.ocd/CableReel.ocd/DefCore.txt | 15 ---- .../Tools.ocd/CableReel.ocd/Graphics.png | Bin 6952 -> 0 bytes .../CableReel.ocd/PowerLine.ocd/DefCore.txt | 6 -- .../CableReel.ocd/PowerLine.ocd/Graphics.png | Bin 141 -> 0 bytes .../CableReel.ocd/PowerLine.ocd/Script.c | 62 ---------------- .../PowerLine.ocd/StringTblDE.txt | 2 - .../PowerLine.ocd/StringTblUS.txt | 2 - .../Tools.ocd/CableReel.ocd/Script.c | 70 ------------------ .../Tools.ocd/CableReel.ocd/StringTblDE.txt | 6 -- .../Tools.ocd/CableReel.ocd/StringTblUS.txt | 6 -- planet/Tests.ocf/Settlement.ocs/Script.c | 1 - 15 files changed, 13 insertions(+), 193 deletions(-) delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/DefCore.txt delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Graphics.png delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/DefCore.txt delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/Graphics.png delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/Script.c delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblDE.txt delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblUS.txt delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Script.c delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblDE.txt delete mode 100644 planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblUS.txt diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt index cefcf7ee3..cc17ac872 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt @@ -14,25 +14,25 @@ Rules=Rule_EnergyNeed=1;Rule_TeamAccount=1; [Player1] Wealth=10 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Player2] Wealth=10 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Player3] Wealth=10 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Player4] Wealth=10 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Landscape] diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c index f33f30af4..b8bdb0201 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c @@ -43,20 +43,16 @@ protected func Initialize() workshop->CreateContents(Coal, 10); workshop->CreateContents(Sulphur, 10); var wind = CreateConstruction(WindGenerator, 480, FindHeight(480), NO_OWNER, 100, true); - var line = CreateObject(PowerLine); - line->SetActionTargets(wind, workshop); var sawmill = CreateConstruction(Sawmill, 520, FindHeight(520), NO_OWNER, 100, true); - var line = CreateObject(PowerLine); - line->SetActionTargets(wind, sawmill); CreateConstruction(Elevator, 220, FindHeight(220), NO_OWNER, 100, true)->CreateShaft(100); - + */ // Create a lorry with necessary equipment to start a settlement. var lorry = CreateObject(Lorry, 300, FindHeight(300)); lorry->CreateContents(Wood, 6); lorry->CreateContents(Metal, 4); lorry->CreateContents(Dynamite, 3); lorry->CreateContents(Loam, 3); - */ + return; } @@ -76,6 +72,8 @@ protected func InitializePlayer(int plr) if (flagpole && !GetPlayerName(flagpole->GetOwner())) flagpole->SetOwner(plr); */ + for (var struct in FindObjects(Find_Category(C4D_Structure))) + struct->SetOwner(plr); // Increase wealth goal per player. var goal = FindObject(Find_ID(Goal_Wealth)); @@ -91,15 +89,9 @@ protected func InitializePlayer(int plr) crew->CreateContents(Shovel); // First clonk can construct, others can mine. if (index == 0) - { crew->CreateContents(Hammer); - crew->CreateContents(CableReel); - } else - { crew->CreateContents(Axe); - crew->CreateContents(CableReel); - } index++; } return; diff --git a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt index b9ed1eb99..6e07ec99c 100644 --- a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt +++ b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt @@ -14,25 +14,25 @@ Rules=Rule_EnergyNeed=1;Rule_TeamAccount=1; [Player1] Wealth=40 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Player2] Wealth=40 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Player3] Wealth=40 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Player4] Wealth=40 Crew=Clonk=2 -Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;CableReel=1;Dynamite=1;DynamiteBox=1; +Knowledge=Idol=1;Foundry=1;SteamEngine=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Firestone=1;Barrel=1;Dynamite=1;DynamiteBox=1; HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;Metal=10;Clonk=2;Lorry=1; [Landscape] diff --git a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c index 19583f56f..032d737c5 100644 --- a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c +++ b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c @@ -35,7 +35,6 @@ protected func Initialize() //lorry->CreateContents(Wood, 16); //lorry->CreateContents(Metal, 4); //lorry->CreateContents(Dynamite, 3); - //lorry->CreateContents(CableReel, 3); // TODO: Make sure lorry stays on mountains. // Place some coniferous trees, but only up to 2/3 of the mountain. @@ -163,8 +162,7 @@ protected func InitializePlayer(int plr) { crew->CreateContents(Hammer); crew->CreateContents(Axe); - crew->CreateContents(CableReel); - crew->CreateContents(Dynamite); + crew->CreateContents(Dynamite, 2); } else { diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/DefCore.txt deleted file mode 100644 index c581b1ab9..000000000 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/DefCore.txt +++ /dev/null @@ -1,15 +0,0 @@ -[DefCore] -id=CableReel -Version=5,2,0,1 -Category=C4D_Object -Width=8 -Height=6 -Offset=-4,-3 -Vertices=3 -VertexX=0,2,-2 -VertexY=1,-1,-1 -VertexFriction=50,50,50 -Value=10 -Mass=15 -Components=Metal=1 -Picture=0,6,64,64 diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Graphics.png b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Graphics.png deleted file mode 100644 index 2eedb36aa876258aaa5a647f887e9e4776056385..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6952 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 != CableReel) - line_end = GetActionTarget(1); - - line_end->Message("$TxtLinebroke$"); - return; -} - -local ActMap = { - Connect = { - Prototype = Action, - Name = "Connect", - Procedure = DFA_CONNECT, - NextAction = "Connect", - }, -}; - -local Name = "$Name$"; - diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblDE.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblDE.txt deleted file mode 100644 index 5b460374d..000000000 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblDE.txt +++ /dev/null @@ -1,2 +0,0 @@ -TxtLinebroke=Leitung gerissen -Name=Stromleitung diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblUS.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblUS.txt deleted file mode 100644 index 6be18aa69..000000000 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/PowerLine.ocd/StringTblUS.txt +++ /dev/null @@ -1,2 +0,0 @@ -TxtLinebroke=Line broke -Name=Power line \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Script.c deleted file mode 100644 index fe1cd1da1..000000000 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/Script.c +++ /dev/null @@ -1,70 +0,0 @@ -/*-- Cable reel --*/ - -protected func Hit() -{ - Sound("RockHit?"); -} - -public func IsToolProduct() { return true; } - -/*-- Line connection --*/ - -// Use will connect power line to building at the clonk's position. -protected func ControlUse(object clonk, int x, int y) -{ - // Is there an object which accepts power lines? - var obj = FindObject(Find_AtPoint(), Find_Func("CanPowerConnect")); - // No such object -> message. - if (!obj) - return clonk->Message("$TxtNoNewLine$"); - // Is there a power line connected to this wire roll? - var line = FindObject(Find_PowerLine()); - // There already is a power line. - if (line) - { - if (obj == line->GetActionTarget(0) || obj == line->GetActionTarget(1)) - { - // Power line is already connected to obj -> remove line. - line->RemoveObject(); - Sound("Connect"); - clonk->Message("$TxtLineRemoval$"); - return true; - } - else - { - // Connect existing power line to obj. - if(line->GetActionTarget(0) == this) - line->SetActionTargets(obj, line->GetActionTarget(1)); - else if(line->GetActionTarget(1) == this) - line->SetActionTargets(line->GetActionTarget(0), obj); - else - return; - Sound("Connect"); - clonk->Message("$TxtConnect$", obj->GetName()); - RemoveObject(); - return true; - } - } - else // A new power line needs to be created. - { - line = CreateObject(PowerLine, 0, 0, NO_OWNER); - line->SetActionTargets(this, obj); - Sound("Connect"); - clonk->Message("$TxtConnect$", obj->GetName()); - return true; - } - return true; -} - -// Finds all power lines connected to obj (can be nil in local calls). -private func Find_PowerLine(object obj) -{ - if (!obj) - obj = this; - return [C4FO_Func, "IsConnectedTo", obj]; -} - -local Name = "$Name$"; -local Description = "$Description$"; -local Collectible = 1; -local Rebuy = true; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblDE.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblDE.txt deleted file mode 100644 index 698c82526..000000000 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblDE.txt +++ /dev/null @@ -1,6 +0,0 @@ -TxtConnectLine=Leitung verbinden -TxtNoNewLine=Hier kann keine neue Leitung verlegt werden. -TxtLineRemoval=Stromleitung abgenommen. -TxtConnect=Stromleitung verbunden|mit %s -Name=Kabelspule -Description=Drücke [Benutzen] vor einem Gebäude und ein weiteres Mal vor einem anderen Gebäude, um diese beiden mit einem Stromkabel zu verbinden. \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblUS.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblUS.txt deleted file mode 100644 index 81b3c1f03..000000000 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/CableReel.ocd/StringTblUS.txt +++ /dev/null @@ -1,6 +0,0 @@ -TxtConnectLine=Connect line -TxtNoNewLine=Cannot create a new line here. -TxtLineRemoval=Power line disconnected. -TxtConnect=Power line connected|to %s -Name=Cable reel -Description=Press [Use] in front of a structure and another time in front of another structure to connect both with a power line. \ No newline at end of file diff --git a/planet/Tests.ocf/Settlement.ocs/Script.c b/planet/Tests.ocf/Settlement.ocs/Script.c index 50215eec5..5386dbafa 100644 --- a/planet/Tests.ocf/Settlement.ocs/Script.c +++ b/planet/Tests.ocf/Settlement.ocs/Script.c @@ -22,7 +22,6 @@ protected func InitializePlayer(int plr) var clonk = GetCrew(plr); clonk->CreateContents(Shovel); var lorry = CreateObject(Lorry, clonk->GetX(), clonk->GetY(), plr); - lorry->CreateContents(CableReel, 4); lorry->CreateContents(Pipe, 2); return; } From a334c212d2bca727fc759235ac7ce28deb83c823 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 19 Feb 2012 00:48:48 +0100 Subject: [PATCH 10/70] fixed the foundry needing power --- planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c index e6ba6ecc6..9397280df 100644 --- a/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Foundry.ocd/Script.c @@ -8,6 +8,9 @@ #include Library_Ownable #include Library_Producer +// does not need power +func PowerNeed() { return 0; } + public func Construction() { From e9bf6a3096aa5a1cc7d7b143f56d755de9974bcc Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 19 Feb 2012 00:49:13 +0100 Subject: [PATCH 11/70] fixed the flag when constructed before using the power system --- planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c index 6d02a8892..2f2b2f9c0 100644 --- a/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c @@ -59,6 +59,9 @@ func FxScheduleRefreshAllPowerHelpersTimer() func RefreshAllPowerHelpers() { + // no power helpers created yet + if(GetType(Library_Power_power_compounds) != C4V_Array) + return; // special handling for neutral var neutral = nil; @@ -275,6 +278,7 @@ func RefreshLinkedFlags() // update flag links for all linked flags - no need for every flag to do that // meanwhile, adjust power helper. Merge if necessary // since we don't know whether flag links have been lost we will create a new power helper and possibly remove old ones + Library_Power->Init(); // make sure the power system is set up var old = lflag.power_helper; lflag.power_helper = CreateObject(Library_Power, 0, 0, NO_OWNER); Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = lflag.power_helper; From 85b8e23a8b128031c454b15b5ba519fd53c9d462 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 19 Feb 2012 01:02:17 +0100 Subject: [PATCH 12/70] windmills produces power in steps, steam engine produces more power --- .../Structures.ocd/SteamEngine.ocd/Script.c | 2 +- .../Structures.ocd/WindGenerator.ocd/Script.c | 10 +++++++--- .../Objects.ocd/Structures.ocd/Windmill.ocd/Script.c | 10 +++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c index 09fc0fd99..651508f7d 100644 --- a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c @@ -63,7 +63,7 @@ func FxCreatesPowerStart(target, effect, temp) { if(temp) return; // fixed amount - MakePowerProducer(100); + MakePowerProducer(300); } func FxCreatesPowerTimer(target, effect) diff --git a/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c index 05d3a1e94..62c79dd96 100644 --- a/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/Script.c @@ -28,10 +28,14 @@ func Wind2Turn() { if(GetCon() < 100) return; - if(last_wind != Abs(GetWind())) + var power = Abs(GetWind()); + if(power < 5) power = 0; + else power = Max(((power + 5) / 25), 1) * 50; + + if(last_wind != power) { - last_wind = Abs(GetWind()); - MakePowerProducer(2 * last_wind); + last_wind = power; + MakePowerProducer(last_wind); } // Fade linearly in time until next timer call var start = 0; diff --git a/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c index 51d4a6f62..fd6e0e8e7 100644 --- a/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Windmill.ocd/Script.c @@ -40,10 +40,14 @@ func Wind2Turn() end = 0; } - if(last_wind != Abs(GetWind())) + var power = Abs(GetWind()); + if(power < 5) power = 0; + else power = Max(((power + 5) / 25), 1) * 50; + + if(last_wind != power) { - last_wind = Abs(GetWind()); - MakePowerProducer(2 * last_wind); + last_wind = power; + MakePowerProducer(last_wind); } // Number of frames for one revolution: the more wind the more revolutions per frame. From 2262e1a8a9e7915a279afe1d9421b8b021b3fdfe Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 19 Feb 2012 17:00:29 +0100 Subject: [PATCH 13/70] added general helper for overhead symbols --- .../Helpers.ocd/StatusSymbol.ocd/DefCore.txt | 10 ++ .../Helpers.ocd/StatusSymbol.ocd/Graphics.png | Bin 0 -> 5564 bytes .../Helpers.ocd/StatusSymbol.ocd/Script.c | 138 ++++++++++++++++++ .../StatusSymbol.ocd/StringTblDE.txt | 2 + .../StatusSymbol.ocd/StringTblUS.txt | 2 + 5 files changed, 152 insertions(+) create mode 100644 planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Graphics.png create mode 100644 planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Script.c create mode 100644 planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblDE.txt create mode 100644 planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblUS.txt diff --git a/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/DefCore.txt b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/DefCore.txt new file mode 100644 index 000000000..0304144dd --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/DefCore.txt @@ -0,0 +1,10 @@ +[DefCore] +id=StatusSymbol +Version=4,10,0,0 +Category=C4D_Vehicle | C4D_MouseIgnore +Width=1 +Height=1 +Offset=-1,-1 +Vertices=1 +VertexY=14 +NoGet=1 \ No newline at end of file diff --git a/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Graphics.png b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Graphics.png new file mode 100644 index 0000000000000000000000000000000000000000..d8e8ac9c668b201a74ca9caa3b253bcc1face1c4 GIT binary patch literal 5564 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"Height", "DefCore") / 2; + SetVertex(0, VTX_Y, hgt); + var x = to->GetVertex(0, VTX_X); + SetVertex(0, VTX_X, x); +} + +public func GetStatusSymbolHelper(to) +{ + var obj = FindObject(Find_ID(StatusSymbol), Find_ActionTarget(to)); + if(obj) return obj; + obj = CreateObject(StatusSymbol, 0, 0, to->GetOwner()); + obj->Init(to); + return obj; +} + +global func AddStatusSymbol(ID) +{ + if(!this) return false; + var h = StatusSymbol->GetStatusSymbolHelper(this); + if(!h) return false; + + h->Add(ID); + return true; +} + +global func RemoveStatusSymbol(ID) +{ + if(!this) return false; + var h = StatusSymbol->GetStatusSymbolHelper(this); + if(!h) return false; + h->Remove(ID); + return true; +} + +func Add(what) +{ + Blink(); + var e = -1; + for(var i=0;iMessage(message); +} + +func Blink() +{ + if(GetEffect("Blinking", this)) + RemoveEffect("Blinking", this); + AddEffect("Blinking", this, 1, 36, this); +} + +func FxBlinkingStart(target, effect, temp) +{ + if(temp) return; + effect.cycle = 1; +} + +func FxBlinkingTimer(target, effect) +{ + this.Visibility = this->GetActionTarget().Visibility; + + if(((++effect.cycle) % 2) == 0) + { + this->Message(""); + return 1; + } + this->Message(message); + return 1; +} + \ No newline at end of file diff --git a/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblDE.txt b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblDE.txt new file mode 100644 index 000000000..b065bbc2a --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=StatusSymbol.ocd +Description=Shows a certain state of an object. \ No newline at end of file diff --git a/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblUS.txt b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblUS.txt new file mode 100644 index 000000000..b065bbc2a --- /dev/null +++ b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=StatusSymbol.ocd +Description=Shows a certain state of an object. \ No newline at end of file From 3b093ac0dea6065248a54df68952bde478fae985 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 19 Feb 2012 17:02:29 +0100 Subject: [PATCH 14/70] changed need-power-indicator to the classic blinking symbol power messages fade out a lot faster messages are also shown when a producer/consumer returns to giving/needing 0 power --- .../Helpers.ocd/FloatingMessage.ocd/Script.c | 5 +++-- .../Libraries.ocd/Power.ocd/Script.c | 19 ++++++++++++++----- .../Libraries.ocd/PowerConsumer.ocd/Script.c | 16 ++-------------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c index 7d50c0d9a..535a6aac4 100644 --- a/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c +++ b/planet/Objects.ocd/Helpers.ocd/FloatingMessage.ocd/Script.c @@ -42,8 +42,8 @@ func FadeOut(int speed, step) func FxFadeOutTimer(target, effect) { - if(alpha < 5) return RemoveObject(); alpha -= effect.step; + if(alpha < 5) return RemoveObject(); Update(); return 1; } @@ -60,7 +60,8 @@ func SetColor(int r2, g2, b2, a) func Update() { - this->Message(Format("@%s", RGBa(r, g, b, alpha), msg)); + // the lacking is on purpose + this->Message(Format("@%s", RGBa(255, 255, 255, alpha), RGBa(r, g, b, alpha), msg)); } public func Initialize() diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c index a0136a531..afaddc9aa 100644 --- a/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c @@ -74,6 +74,7 @@ func AddPowerLink(object p, int a, bool surpress_balance_check) { var n = {obj = p, amount = a}; + var before = 0; var found = false; var first_empty = -1; var diff = 0; @@ -98,7 +99,11 @@ func AddPowerLink(object p, int a, bool surpress_balance_check) diff = a - o.amount; power_balance += diff; - if(a == 0) power_links[i] = nil; + if(a == 0) + { + before = power_links[i].amount; + power_links[i] = nil; + } else power_links[i] = n; break; } @@ -118,17 +123,21 @@ func AddPowerLink(object p, int a, bool surpress_balance_check) } diff = n.amount; - if(diff > 0) + if((diff > 0) || ((a == 0) && (before > 0))) { var t = CreateObject(FloatingMessage, n.obj->GetX() - GetX(), n.obj->GetY() - GetY(), NO_OWNER); - t->SetMessage(Format("+%d{{Library_PowerConsumer}}", diff)); + t->SetMessage(Format("+%d{{Library_PowerConsumer}}", diff)); + t->SetColor(0, 255, 0); t->SetYDir(-10); + t->FadeOut(4, 8); } - else if(diff < 0) + else if((diff < 0) || ((a == 0) && (before < 0))) { var t = CreateObject(FloatingMessage, n.obj->GetX() - GetX(), n.obj->GetY() - GetY(), NO_OWNER); - t->SetMessage(Format("%d{{Library_PowerConsumer}}", diff)); + t->SetMessage(Format("%d{{Library_PowerConsumer}}", diff)); + t->SetColor(255, 0, 0); t->SetYDir(-10); + t->FadeOut(4, 8); } if(n.amount < 0) n.obj->~OnEnoughPower(); // might be reverted soon, though diff --git a/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c index 006abdc32..a673533ae 100644 --- a/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c @@ -35,9 +35,7 @@ public func OnNotEnoughPower() PowerConsumer_has_power = false; // show symbol - if(GetEffect("ShowPowerMessage", this)) - FatalError("OnNotEnoughPower() called two times in a row!"); - AddEffect("ShowPowerMessage", this, 1, 10, this); + this->AddStatusSymbol(Library_PowerConsumer); } // called when consumer was sleeping but power is available again @@ -46,17 +44,7 @@ public func OnEnoughPower() PowerConsumer_has_power = true; // remove symbol - if(GetEffect("ShowPowerMessage", this)) - RemoveEffect("ShowPowerMessage", this); -} - -public func FxShowPowerMessageTimer(target, effect, time) -{ - if(effect.Interval < 35*3) - effect.Interval = 35*3; - var t = CreateObject(FloatingMessage, 0, 0, NO_OWNER); - t->SetMessage("{{Library_PowerConsumer}}?"); - t->SetYDir(-10); + this->RemoveStatusSymbol(Library_PowerConsumer); } func Destruction() From afce022761da127fca2e9cdb0ce66e37bcfd36ff Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 19 Feb 2012 17:43:57 +0100 Subject: [PATCH 15/70] Remove testing settlement from Goldrush script --- .../BeyondTheRocks.ocf/GoldRush.ocs/Script.c | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c index b8bdb0201..af4518e93 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c @@ -29,30 +29,6 @@ protected func Initialize() var time = CreateObject(Environment_Time); time->SetTime(600); time->SetCycleSpeed(12); - - // Create a small settlement to test stuff. - /* - var foundry = CreateConstruction(Foundry, 300, FindHeight(300), NO_OWNER, 100, true); - CreateObject(Barrel, 300, FindHeight(300), NO_OWNER)->PutLiquid("Water", 300); - foundry->CreateContents(Coal,3); - foundry->CreateContents(Ore,3); - var flag = CreateConstruction(Flagpole, 360, FindHeight(360), NO_OWNER, 100, true); - var workshop = CreateConstruction(ToolsWorkshop, 420, FindHeight(420), NO_OWNER, 100, true); - workshop->CreateContents(Wood, 10); - workshop->CreateContents(Metal, 10); - workshop->CreateContents(Coal, 10); - workshop->CreateContents(Sulphur, 10); - var wind = CreateConstruction(WindGenerator, 480, FindHeight(480), NO_OWNER, 100, true); - var sawmill = CreateConstruction(Sawmill, 520, FindHeight(520), NO_OWNER, 100, true); - CreateConstruction(Elevator, 220, FindHeight(220), NO_OWNER, 100, true)->CreateShaft(100); - */ - // Create a lorry with necessary equipment to start a settlement. - var lorry = CreateObject(Lorry, 300, FindHeight(300)); - lorry->CreateContents(Wood, 6); - lorry->CreateContents(Metal, 4); - lorry->CreateContents(Dynamite, 3); - lorry->CreateContents(Loam, 3); - return; } @@ -66,15 +42,6 @@ private func FindHeight(int x) protected func InitializePlayer(int plr) { - // first player gets the base to test. - /* - var flagpole = FindObject(Find_ID(Flagpole)); - if (flagpole && !GetPlayerName(flagpole->GetOwner())) - flagpole->SetOwner(plr); - */ - for (var struct in FindObjects(Find_Category(C4D_Structure))) - struct->SetOwner(plr); - // Increase wealth goal per player. var goal = FindObject(Find_ID(Goal_Wealth)); if (goal) From 9dc9ad4ca75a9f7d1a7a2d7b34b4f4dad4423ce0 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 19 Feb 2012 17:45:01 +0100 Subject: [PATCH 16/70] Fix initialization of AlphaToCoverage material property --- src/lib/StdMeshMaterial.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/StdMeshMaterial.cpp b/src/lib/StdMeshMaterial.cpp index 435d01eaa..04333fef9 100644 --- a/src/lib/StdMeshMaterial.cpp +++ b/src/lib/StdMeshMaterial.cpp @@ -839,6 +839,7 @@ StdMeshMaterialPass::StdMeshMaterialPass(): Emissive[0] = Emissive[1] = Emissive[2] = 0.0f; Emissive[3] = 0.0f; Shininess = 0.0f; SceneBlendFactors[0] = SB_One; SceneBlendFactors[1] = SB_Zero; + AlphaToCoverage = false; } void StdMeshMaterialPass::Load(StdMeshMaterialParserCtx& ctx) From f710c68b9a7eb6f070f809a7ff873d32fdc2dc14 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 19 Feb 2012 17:49:02 +0100 Subject: [PATCH 17/70] Reset AlphaToCoverage GL state after having rendered a mesh --- src/platform/StdGL.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/StdGL.cpp b/src/platform/StdGL.cpp index 8db62ff95..457730d8d 100644 --- a/src/platform/StdGL.cpp +++ b/src/platform/StdGL.cpp @@ -1416,6 +1416,7 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); //glDisable(GL_BLEND); glShadeModel(GL_FLAT); From 5341ec1c3df269d3367487ebe9abbbe643067caa Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 19 Feb 2012 17:57:33 +0100 Subject: [PATCH 18/70] removed the ignore_sky parameter of Draw*Map - now always ignores sky --- docs/sdk/script/fn/DrawDefMap.xml | 7 +------ docs/sdk/script/fn/DrawMap.xml | 11 +++-------- src/game/script/C4GameScript.cpp | 10 ++++++---- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/docs/sdk/script/fn/DrawDefMap.xml b/docs/sdk/script/fn/DrawDefMap.xml index 892023510..03fc71041 100644 --- a/docs/sdk/script/fn/DrawDefMap.xml +++ b/docs/sdk/script/fn/DrawDefMap.xml @@ -35,14 +35,9 @@ map_name Name of the map to be used from Landscape.txt. - - bool - ignore_sky - If true, the old material is retained whenever Sky would be drawn. - - Draws a dynamic map within the specified rectangle using a given map specification from Landscape.txt. + Draws a dynamic map within the specified rectangle over the old landscape using a given map specification from Landscape.txt. The Landscape.txt component is usually removed from memory after scenario initialization. To keep it in memory for later use by this command you should specify the option KeepMapCreator=1 in Scenario.txt section [Landscape]. diff --git a/docs/sdk/script/fn/DrawMap.xml b/docs/sdk/script/fn/DrawMap.xml index d0cc9ff2f..b228d98cd 100644 --- a/docs/sdk/script/fn/DrawMap.xml +++ b/docs/sdk/script/fn/DrawMap.xml @@ -35,19 +35,14 @@ map Definition of the dynamic map. The enclosing map { ... } tag must be present. - - bool - ignore_sky - If true, the old material is retained whenever Sky would be drawn. - - Draws a dynamic map within the specified rectangle. This is done using the same evaluation as with Landscape.txt components. + Draws a dynamic map within the specified rectangle over the old landscape. This is done using the same evaluation as with Landscape.txt components. As maximum string length in C4Script is limited by internal buffers you should use DrawDefMap for very complex maps. - DrawMap(0,0,LandscapeWidth(), LandscapeHeight()/2, "map Empty{}"); - Empties the top half of the map. + DrawMap(0,0,LandscapeWidth(), LandscapeHeight()/2, "map Earth{overlay{mat = Earth;};};"); + Fills the top half of the map with earth. DrawDefMap diff --git a/src/game/script/C4GameScript.cpp b/src/game/script/C4GameScript.cpp index 5006e503f..3a82b28b6 100644 --- a/src/game/script/C4GameScript.cpp +++ b/src/game/script/C4GameScript.cpp @@ -1650,16 +1650,18 @@ static long FnDrawMatChunks(C4AulContext *cctx, long tx, long ty, long twdt, lon return ::Landscape.DrawChunks(tx, ty, twdt, thgt, icntx, icnty, FnStringPar(strMaterial), FnStringPar(strTexture), bIFT != 0); } -static long FnDrawMap(C4AulContext *cctx, long iX, long iY, long iWdt, long iHgt, C4String *szMapDef, bool ignoreSky) +static long FnDrawMap(C4AulContext *cctx, long iX, long iY, long iWdt, long iHgt, C4String *szMapDef) { // draw it! - return ::Landscape.DrawMap(iX, iY, iWdt, iHgt, FnStringPar(szMapDef), ignoreSky); + // don't clear the old map before drawing + return ::Landscape.DrawMap(iX, iY, iWdt, iHgt, FnStringPar(szMapDef), true); } -static long FnDrawDefMap(C4AulContext *cctx, long iX, long iY, long iWdt, long iHgt, C4String *szMapDef, bool ignoreSky) +static long FnDrawDefMap(C4AulContext *cctx, long iX, long iY, long iWdt, long iHgt, C4String *szMapDef) { // draw it! - return ::Landscape.DrawDefMap(iX, iY, iWdt, iHgt, FnStringPar(szMapDef), ignoreSky); + // don't clear the old map before drawing + return ::Landscape.DrawDefMap(iX, iY, iWdt, iHgt, FnStringPar(szMapDef), true); } static bool FnCreateParticle(C4AulContext *cthr, C4String *szName, long iX, long iY, long iXDir, long iYDir, long a, long b, C4Object *pObj, bool fBack) From e8e1c4b9d8d3f0d37cd761babf539bf12c41fae8 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 19 Feb 2012 18:31:09 +0100 Subject: [PATCH 19/70] Check only 3 version numbers when checking whether an update exists --- src/gui/C4UpdateDlg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/C4UpdateDlg.cpp b/src/gui/C4UpdateDlg.cpp index 519db0619..850869d6f 100644 --- a/src/gui/C4UpdateDlg.cpp +++ b/src/gui/C4UpdateDlg.cpp @@ -295,7 +295,7 @@ bool C4UpdateDlg::ApplyUpdate(const char *strUpdateFile, bool fDeleteUpdate, C4G bool C4UpdateDlg::IsValidUpdate(const char *szVersion) { - StdStrBuf strVersion; strVersion.Format("%d.%d.%d.%d", C4XVER1, C4XVER2, C4XVER3, C4XVER4); + StdStrBuf strVersion; strVersion.Format("%d.%d.%d", C4XVER1, C4XVER2, C4XVER3); if (szVersion == NULL || strlen(szVersion) == 0) return false; return strcmp(szVersion,strVersion.getData()) != 0; } From 94f552bbb8928a4054672210ad998addd7ec3528 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 19 Feb 2012 19:33:35 +0100 Subject: [PATCH 20/70] Fix earth material initialization to work when texture is given This fixes misplaced InEarth objects when the Material= option in Scenario.txt contains a material-texture combination instead of a material only. --- src/game/landscape/C4Material.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/game/landscape/C4Material.cpp b/src/game/landscape/C4Material.cpp index 3d6e3ac65..a20b72909 100644 --- a/src/game/landscape/C4Material.cpp +++ b/src/game/landscape/C4Material.cpp @@ -672,10 +672,15 @@ bool C4MaterialMap::CrossMapMaterials() // Called after load printf("%s -> %s: %p\n", Map[cnt].Name, Map[cnt2].Name, ppReactionMap[(cnt2+1)*(Num+1) + cnt+1]->pFunc); #endif // Get hardcoded system material indices + const C4TexMapEntry* earth_entry = ::TextureMap.GetEntry(::TextureMap.GetIndexMatTex(Game.C4S.Landscape.Material)); + if(!earth_entry) + { LogFatal(FormatString("Earth material \"%s\" not found!", Game.C4S.Landscape.Material).getData()); return false; } + MVehic = Get("Vehicle"); MCVehic = Mat2PixColDefault(MVehic); MTunnel = Get("Tunnel"); MWater = Get("Water"); - MEarth = Get(Game.C4S.Landscape.Material); + MEarth = Get(earth_entry->GetMaterialName()); + if ((MVehic==MNone) || (MTunnel==MNone)) { LogFatal(LoadResStr("IDS_PRC_NOSYSMATS")); return false; } return true; From 1c4deede8cb6cb5ebe43e715f7fb1afdafeae562 Mon Sep 17 00:00:00 2001 From: Felix Wagner Date: Mon, 20 Feb 2012 11:25:43 +0000 Subject: [PATCH 21/70] Fixed Code never reached warnings --- .../Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c | 12 ------------ .../Libraries.ocd/ElevatorControl.ocd/Script.c | 2 +- .../Experimental.ocd/CableReel.ocd/Script.c | 1 - 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c index 16ae08d49..fbbe61efb 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c @@ -240,18 +240,6 @@ func GetClonkPos() func GetClonkOff() { return Vec_Sub(particles[-1][0],last_point); - var clonk = objects[1][0]; - var speed = [clonk->GetXDir(Rope_Precision), clonk->GetYDir(Rope_Precision)]; - var offset = speed; - offset[0] = offset[0]*1000/Rope_Precision; - offset[1] = offset[1]*1000/Rope_Precision; - if(!ClonkOldSpeed) - { - ClonkOldSpeed = offset; - } - var ret = ClonkOldSpeed; - ClonkOldSpeed = offset; - return ret; } func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments) { diff --git a/planet/Objects.ocd/Libraries.ocd/ElevatorControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ElevatorControl.ocd/Script.c index 237957003..e181a4d00 100644 --- a/planet/Objects.ocd/Libraries.ocd/ElevatorControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ElevatorControl.ocd/Script.c @@ -31,7 +31,7 @@ func ControlStop(object clonk, int control) { var effect = GetEffect("ElevatorControl", this); effect.controlled = nil; - return effect.case->ControlStop(clonk, control);; + return effect.case->ControlStop(clonk, control); } return _inherited(clonk, control); } diff --git a/planet/Tests.ocf/Experimental.ocd/CableReel.ocd/Script.c b/planet/Tests.ocf/Experimental.ocd/CableReel.ocd/Script.c index 89f40ac94..60846dd64 100644 --- a/planet/Tests.ocf/Experimental.ocd/CableReel.ocd/Script.c +++ b/planet/Tests.ocf/Experimental.ocd/CableReel.ocd/Script.c @@ -56,7 +56,6 @@ protected func ControlUse(object clonk, int x, int y) clonk->Message("$TxtConnect$", obj->GetName()); return true; } - return true; } // Finds all power lines connected to obj (can be nil in local calls). From 67efb5c7e1b43cc3524957ddcdc1e8eb9e9f88b8 Mon Sep 17 00:00:00 2001 From: Felix Wagner Date: Mon, 20 Feb 2012 11:29:01 +0000 Subject: [PATCH 22/70] Fixed undefined field [Physicals] --- .../CableCars.ocd/Vehicles.ocd/Lorry.ocd/DefCore.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/DefCore.txt b/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/DefCore.txt index f1336e005..1956ec2f9 100644 --- a/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/DefCore.txt +++ b/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Vehicles.ocd/Lorry.ocd/DefCore.txt @@ -20,7 +20,4 @@ Rotate=30 UprightAttach=0 TimerCall=TurnWheels Timer=1 -BorderBound=1 - -[Physicals] -Float=200 +BorderBound=1 \ No newline at end of file From eb6b7be7ee3d783d37a997c9505c9ac50485803c Mon Sep 17 00:00:00 2001 From: Felix Wagner Date: Mon, 20 Feb 2012 11:58:58 +0000 Subject: [PATCH 23/70] Fixed various unused vars --- .../MoltenMonarch.ocs/System.ocg/King_Club.c | 1 - .../Clouds.ocd/Cloud.ocd/Script.c | 4 ---- .../Environment.ocd/Time.ocd/Script.c | 2 +- .../Goals.ocd/DeathMatch.ocd/Script.c | 1 - .../Goals.ocd/KingOfTheHill.ocd/Script.c | 3 --- .../Goals.ocd/LastManStanding.ocd/Script.c | 1 - .../Objects.ocd/Goals.ocd/Parkour.ocd/Script.c | 2 +- .../Helpers.ocd/ItemSpark.ocd/Script.c | 2 +- .../Items.ocd/Tools.ocd/Axe.ocd/Script.c | 1 - .../Tools.ocd/DynamiteBox.ocd/Script.c | 1 - .../Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c | 2 +- .../Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c | 1 - .../Tools.ocd/JarOfWinds.ocd/Script.c | 18 +++++++++--------- .../Items.ocd/Tools.ocd/Pickaxe.ocd/Script.c | 2 -- .../Tools.ocd/Ropebridge.ocd/Script.c | 5 ----- .../Items.ocd/Weapons.ocd/Club.ocd/Script.c | 1 - .../Libraries.ocd/Base.ocd/Script.c | 2 -- .../ClonkControl.ocd/Crosshair.ocd/Script.c | 1 - .../Libraries.ocd/ClonkControl.ocd/Script.c | 2 -- .../Libraries.ocd/RopePhysics.ocd/Script.c | 10 +++------- .../Rules.ocd/TeamAccount.ocd/Script.c | 2 +- planet/System.ocg/Commits.c | 4 ++-- planet/System.ocg/HitChecks.c | 2 +- planet/System.ocg/Player.c | 4 ++-- planet/System.ocg/PlayerControl.c | 1 - .../LiftTower.ocd/Rope.ocd/Script.c | 11 +++-------- planet/Tests.ocf/Lines.ocs/Script.c | 4 ++-- planet/Tutorial.ocf/Tutorial02.ocs/Script.c | 2 +- .../Tutorial04.ocs/System.ocg/AIMusketAttack.c | 1 - 29 files changed, 28 insertions(+), 65 deletions(-) diff --git a/planet/BackToTheRocks.ocf/MoltenMonarch.ocs/System.ocg/King_Club.c b/planet/BackToTheRocks.ocf/MoltenMonarch.ocs/System.ocg/King_Club.c index d5031ccf1..6f0e8fa22 100644 --- a/planet/BackToTheRocks.ocf/MoltenMonarch.ocs/System.ocg/King_Club.c +++ b/planet/BackToTheRocks.ocf/MoltenMonarch.ocs/System.ocg/King_Club.c @@ -27,7 +27,6 @@ func DoStrike(clonk, angle) var damage=5*1000; if (king_size) damage+=3000; - var f=ApplyShieldFactor(clonk, obj, damage); ApplyWeaponBash(obj, 400, angle); obj->DoEnergy(-damage, true, FX_Call_EngGetPunched, clonk->GetOwner()); } diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c index 116551462..90ba7b885 100644 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c +++ b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c @@ -15,7 +15,6 @@ protected func Initialize() iSearchY = 0; iAcidity=0; iWaitTime = RandomX(130,190); - var iGraphics = RandomX(1,3); DoCon(Random(75)); @@ -36,8 +35,6 @@ protected func Initialize() public func Precipitation() { - var iLaunch; - if (GetTemperature() < 0 && iAcidity == 0) szMat = "Snow"; if (GetTemperature() >= 1 && iAcidity == 0) szMat = "Water"; if (iAcidity >= 1) szMat="Acid"; @@ -82,7 +79,6 @@ public func TimedEvents() protected func Evaporation() //Creates a search line every x-amount(currently five) of pixels to check for water beneath the cloud { - var iSearchX = GetX(); var iPrecision = 5; if(iSize >= 700 || iAcidity >= 100) diff --git a/planet/Objects.ocd/Environment.ocd/Time.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Time.ocd/Script.c index 7170368b4..45baf1989 100644 --- a/planet/Objects.ocd/Environment.ocd/Time.ocd/Script.c +++ b/planet/Objects.ocd/Environment.ocd/Time.ocd/Script.c @@ -69,7 +69,7 @@ protected func Initialize() // Create moon and stars. if (FindObject(Find_ID(Environment_Celestial))) { - var moon=CreateObject(Moon, LandscapeWidth() / 2, LandscapeHeight() / 6); + CreateObject(Moon, LandscapeWidth() / 2, LandscapeHeight() / 6); PlaceStars(); } return; diff --git a/planet/Objects.ocd/Goals.ocd/DeathMatch.ocd/Script.c b/planet/Objects.ocd/Goals.ocd/DeathMatch.ocd/Script.c index 21fb97f51..7503a77b0 100644 --- a/planet/Objects.ocd/Goals.ocd/DeathMatch.ocd/Script.c +++ b/planet/Objects.ocd/Goals.ocd/DeathMatch.ocd/Script.c @@ -59,7 +59,6 @@ protected func JoinPlayer(int plr) { var clonk = GetCrew(plr); clonk->DoEnergy(100000); - var x, y; var pos = FindRelaunchPos(plr); clonk->SetPosition(pos[0], pos[1]); return; diff --git a/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/Script.c b/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/Script.c index 33a3b5949..cc4a717c0 100644 --- a/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/Script.c +++ b/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/Script.c @@ -274,9 +274,6 @@ func RefreshScoreboard() SetScoreboardData(SBRD_Caption,SBRD_Points,Format("{{Sword}} / %d", GetPointLimit()),SBRD_Caption); SetScoreboardData(SBRD_Caption,SBRD_Deaths,"{{Clonk}}",SBRD_Caption); - - var points=GetTeamPoints(); - for(var cnt=0;cntDoEnergy(100000); - var x, y; var pos = FindRelaunchPos(plr); clonk->SetPosition(pos[0], pos[1]); return; diff --git a/planet/Objects.ocd/Goals.ocd/Parkour.ocd/Script.c b/planet/Objects.ocd/Goals.ocd/Parkour.ocd/Script.c index f0a641e88..91a35888d 100644 --- a/planet/Objects.ocd/Goals.ocd/Parkour.ocd/Script.c +++ b/planet/Objects.ocd/Goals.ocd/Parkour.ocd/Script.c @@ -426,7 +426,7 @@ protected func FxIntDirNextCPTimer(object target, effect) // Find nearest CP. var nextcp; for (var cp in FindObjects(Find_ID(ParkourCheckpoint), Find_Func("FindCPMode", PARKOUR_CP_Check | PARKOUR_CP_Finish), Sort_Distance(target->GetX() - GetX(), target->GetY() - GetY()))) - if (!cp->ClearedByPlayer(plr) && (cp->IsActiveForPlayer(plr) || cp->IsActiveForTeam(GetPlayerTeam(plr)))) + if (!cp->ClearedByPlayer(plr) && (cp->IsActiveForPlayer(plr) || cp->IsActiveForTeam(team))) { nextcp = cp; break; diff --git a/planet/Objects.ocd/Helpers.ocd/ItemSpark.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/ItemSpark.ocd/Script.c index c5e78dd13..4e657bbe9 100644 --- a/planet/Objects.ocd/Helpers.ocd/ItemSpark.ocd/Script.c +++ b/planet/Objects.ocd/Helpers.ocd/ItemSpark.ocd/Script.c @@ -102,7 +102,7 @@ func FxCheckStuckTimer(_, effect) func FxSparkleTimer(_, effect) { - var x=RandomX(-4, 4); + //var x=RandomX(-4, 4); //var p="ItemSpark"; //if(Random(2)) p="ItemSparkA"; //CreateParticle(p, x, (4-Abs(x))/2, -x/2, -3, 40, RGBa(50,50,150+Random(100), 200), nil); diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c index bd279cecf..a343b8ef2 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c @@ -306,7 +306,6 @@ func CheckStrike(iTime) var width=10; var height=20; - var angle=0; for(var obj in FindObjects(Find_AtRect(offset_x - width/2, offset_y - height/2, width, height), Find_NoContainer(), diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c index baac24d9d..961620cf3 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c @@ -76,7 +76,6 @@ private func UpdatePicture() var s = 400; var yoffs = 14000; var xoffs = 22000; - var spacing = 14000; SetGraphics(Format("%d", iCount), Icon_Number, 12, GFXOV_MODE_Picture); SetObjDrawTransform(s, 0, xoffs, 0, s, yoffs, 12); diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c index d61dfb069..3fba86440 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c @@ -319,7 +319,7 @@ public func FxIntGrappleControlTimer(object target, fxnum, int time) var angle = rope->GetClonkAngle(); var off = rope->GetClonkOff(); // off = [0,0]; - var pos = rope->GetClonkPos(); + //var pos = rope->GetClonkPos(); //target->SetPosition(pos[0], pos[1], nil, Rope_Precision); target.MyAngle = angle; //angle = 0; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c index fbbe61efb..1d98b93e2 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Rope.ocd/Script.c @@ -159,7 +159,6 @@ local last_point; func UpdateLines() { - var fTimeStep = 1; var oldangle; for(var i=1; i < ParticleCount; i++) { diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/Script.c index fb043c153..90b968f08 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/Script.c @@ -117,22 +117,22 @@ private func FireWeapon(object pClonk,iX,iY) for(var i=10; i<32; i++) { var R = RandomX(-20,20); - var SX = Sin(180 - Angle(0,0,iX,iY) + R,i); - var SY = Cos(180 - Angle(0,0,iX,iY) + R,i); + var SX = Sin(180 - iAngle + R,i); + var SY = Cos(180 - iAngle + R,i); if(!GBackSolid(SX,SY)) { CreateParticle("Air", SX,SY, - Sin(180 - Angle(0,0,iX,iY) + (R),(Amount / 2) + 25), - Cos(180 - Angle(0,0,iX,iY) + (R),(Amount / 2) + 25), + Sin(180 - iAngle + (R),(Amount / 2) + 25), + Cos(180 - iAngle + (R),(Amount / 2) + 25), Max(i + 30, 90) + 75, ); } } - var sinspeed = Sin(180 - Angle(0,0,iX,iY) + (R / 2),(Amount) + 15); - var cosspeed = Cos(180 - Angle(0,0,iX,iY) + (R / 2),(Amount) + 15); + var sinspeed = Sin(180 - iAngle + (R / 2),(Amount) + 15); + var cosspeed = Cos(180 - iAngle + (R / 2),(Amount) + 15); if(pClonk->GetAction() != "Walk") { //Makes the clonk firing it be pushed backwards a bit @@ -144,9 +144,9 @@ private func FireWeapon(object pClonk,iX,iY) for( var obj in FindObjects( Find_Or( - Find_Distance(10,Sin(180 - Angle(0,0,iX,iY),20),Cos(180 - Angle(0,0,iX,iY),20)), - Find_Distance(18,Sin(180 - Angle(0,0,iX,iY),40),Cos(180 - Angle(0,0,iX,iY),40)), - Find_Distance(25,Sin(180 - Angle(0,0,iX,iY),70),Cos(180 - Angle(0,0,iX,iY),70)) + Find_Distance(10,Sin(180 - iAngle,20),Cos(180 - iAngle,20)), + Find_Distance(18,Sin(180 - iAngle,40),Cos(180 - iAngle,40)), + Find_Distance(25,Sin(180 - iAngle,70),Cos(180 - iAngle,70)) ), Find_Not(Find_Category(C4D_Structure)), Find_Not(Find_Func("NoWindjarForce")), diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/Script.c index b96082204..c028e4c89 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/Script.c @@ -89,8 +89,6 @@ protected func DoSwing(object clonk, int ix, int iy) ++iDist; } - var x = Sin(180-angle,iDist-8); - var y = Cos(180-angle,iDist-8); var x2 = Sin(180-angle,iDist); var y2 = Cos(180-angle,iDist); diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/Script.c index aef5c43c8..9d49e8847 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/Script.c @@ -75,10 +75,6 @@ public func MakeBridge(obj1, obj2) func FxIntHangTimer() { TimeStep(); - var iLeft = objects[0][0]->GetX()-GetX(); - var iRight = objects[1][0]->GetX()-GetX(); - var iTop = Min(objects[0][0]->GetY(),objects[1][0]->GetY())-GetY(); - var iDown = segments[GetLength(segments)/2]->GetY()-GetY(); for(var i = 1; i < ParticleCount-1; i++) particles[i][2] = [0,segments[i]->~GetLoadWeight()]; } @@ -138,7 +134,6 @@ func DrawRopeLine2(start, end, i, int index) func UpdateLines() { - var fTimeStep = 1; var oldangle = Angle(particles[1][0][0], particles[1][0][1], particles[0][0][0], particles[0][0][1]); for(var i=1; i < ParticleCount; i++) { diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/Script.c index eee27f715..dcd87af0d 100644 --- a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/Script.c @@ -194,7 +194,6 @@ func DoStrike(clonk, angle) if(obj->GetOCF() & OCF_Alive) { var damage=5*1000; - var f=ApplyShieldFactor(clonk, obj, damage); ApplyWeaponBash(obj, 400, angle); obj->DoEnergy(-damage, true, FX_Call_EngGetPunched, clonk->GetOwner()); } diff --git a/planet/Objects.ocd/Libraries.ocd/Base.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Base.ocd/Script.c index 7757c3435..692eb0441 100644 --- a/planet/Objects.ocd/Libraries.ocd/Base.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Base.ocd/Script.c @@ -317,9 +317,7 @@ func UpdateClonkSellMenus() func OpenSellMenu(object pClonk, int iSelection, bool fNoListUpdate) { // Filled with [idDef, iCount, pObj] arrays - var aList = []; var aArray; - var pObj; var iIndex; if(!fNoListUpdate) UpdateSellList(); diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c index 1d196d646..b82df0628 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c @@ -44,7 +44,6 @@ public func FxMoveTimer() var angle_diff = Normalize(target_angle - angle, -1800, 10); if (angle_diff == 0) angle_diff = 1; - var dir = angle_diff / Abs(angle_diff); angle = angle + angle_diff * analog_strength / 100 / 8; } diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 5cea1667b..577138d57 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -1121,8 +1121,6 @@ public func CanEnter() // Handles enter and exit private func ObjectControlEntrance(int plr, int ctrl) { - var proc = GetProcedure(); - // enter if (ctrl == CON_Enter) { diff --git a/planet/Objects.ocd/Libraries.ocd/RopePhysics.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/RopePhysics.ocd/Script.c index 6e0343f3c..7db116f73 100644 --- a/planet/Objects.ocd/Libraries.ocd/RopePhysics.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/RopePhysics.ocd/Script.c @@ -443,10 +443,9 @@ public func ConstraintLength() { // Satisfy all stick constraints (move the particles to fit the length) var normal_restlength = Rope_SegmentLength*Rope_Precision; - var normal_restlength2 = normal_restlength*normal_restlength; - var restlength, restlength2; - var x1, x2, invmass1, invmass2; - var delta = [0,0], deltaDot, deltalength, diff; + var restlength; + var invmass1, invmass2; + var delta = [0,0], deltaDot, deltalength; // diff for(var i=0; i < ParticleCount-1; i++) { // Keep length @@ -594,9 +593,6 @@ func ForcesOnObjects() if( obj->GetAction() == "Climb") obj->SetAction("Jump"); - var xdist = particles[j][0][0]-obj->GetX(Rope_Precision); - var ydist = particles[j][0][1]-obj->GetY(Rope_Precision); - obj->SetXDir( particles[j][0][0]-particles[j][1][0], Rope_Precision); obj->SetYDir( particles[j][0][1]-particles[j][1][1], Rope_Precision); } diff --git a/planet/Objects.ocd/Rules.ocd/TeamAccount.ocd/Script.c b/planet/Objects.ocd/Rules.ocd/TeamAccount.ocd/Script.c index 036ba051c..f12847df9 100644 --- a/planet/Objects.ocd/Rules.ocd/TeamAccount.ocd/Script.c +++ b/planet/Objects.ocd/Rules.ocd/TeamAccount.ocd/Script.c @@ -58,7 +58,7 @@ protected func OnTeamSwitch(int player, int new_team, int old_team) if (!Hostile(player, GetPlayerByIndex(i))) count++; } - var share = GetWealth(player) / count; + //var share = GetWealth(player) / count; // Add player to new team, i.e. add his wealth. // TODO Implement diff --git a/planet/System.ocg/Commits.c b/planet/System.ocg/Commits.c index d0d628fdf..bdeaa4b29 100644 --- a/planet/System.ocg/Commits.c +++ b/planet/System.ocg/Commits.c @@ -127,8 +127,8 @@ global func PlaceObjects(id id, int amount, string mat_str, int x, int y, int wd { var i, j; var rndx, rndy, obj; - var mtype, mat; - var func, objhgt = id->GetDefCoreVal("Height", "DefCore"); + var mat; + var objhgt = id->GetDefCoreVal("Height", "DefCore"); mat = Material(mat_str); // Some failsavety. diff --git a/planet/System.ocg/HitChecks.c b/planet/System.ocg/HitChecks.c index 78bde9639..e2e6c0fcd 100644 --- a/planet/System.ocg/HitChecks.c +++ b/planet/System.ocg/HitChecks.c @@ -55,7 +55,7 @@ global func FxHitCheckDoCheck(object target, proplist effect) if (live) shooter = target; - if (Distance(oldx, oldy, newx, newy) <= Max(1, Max(Abs(target->GetXDir()), Abs(target->GetYDir()))) * 2) + if (dist <= Max(1, Max(Abs(target->GetXDir()), Abs(target->GetYDir()))) * 2) { // We search for objects along the line on which we moved since the last check // and sort by distance (closer first). diff --git a/planet/System.ocg/Player.c b/planet/System.ocg/Player.c index 946c79dee..bb7b67522 100644 --- a/planet/System.ocg/Player.c +++ b/planet/System.ocg/Player.c @@ -59,8 +59,8 @@ global func GetTaggedTeamName(int team) // Brightens dark colors, to be readable on dark backgrounds. global func MakeColorReadable(int color) { - // Determine alpha. - var a = ((color >> 24 & 255) << 24); + // Determine alpha. Not needed at the moment + //var a = ((color >> 24 & 255) << 24); // Strip alpha. color = color & 16777215; // Calculate brightness: 50% red, 87% green, 27% blue (Max 164 * 255). diff --git a/planet/System.ocg/PlayerControl.c b/planet/System.ocg/PlayerControl.c index 46ad57147..05f3f384a 100644 --- a/planet/System.ocg/PlayerControl.c +++ b/planet/System.ocg/PlayerControl.c @@ -204,7 +204,6 @@ global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool r // Count down from EffectCount, in case effects get deleted var i = GetEffectCount("*Control*", this), iEffect; - var res; while (i--) { iEffect = GetEffect("*Control*", this, i); diff --git a/planet/Tests.ocf/Experimental.ocd/LiftTower.ocd/Rope.ocd/Script.c b/planet/Tests.ocf/Experimental.ocd/LiftTower.ocd/Rope.ocd/Script.c index efc10fab0..599cfb193 100644 --- a/planet/Tests.ocf/Experimental.ocd/LiftTower.ocd/Rope.ocd/Script.c +++ b/planet/Tests.ocf/Experimental.ocd/LiftTower.ocd/Rope.ocd/Script.c @@ -73,7 +73,6 @@ local last_point; func UpdateLines() { - var fTimeStep = 1; var oldangle; for(var i=1; i < ParticleCount; i++) { @@ -188,14 +187,11 @@ func ForcesOnObjects() if( obj->GetAction() == "Climb") obj->SetAction("Jump"); - var xdist = particles[j][0][0]-obj->GetX(Rope_Precision); - var ydist = particles[j][0][1]-obj->GetY(Rope_Precision); - var xdir = BoundBy(particles[j][0][0]-particles[j][1][0], -100, 100); var ydir = particles[j][0][1]-particles[j][1][1]; if (!obj->GetContact(-1)) - ydir = BoundBy(ydir, -100, 100); + ydir = BoundBy(ydir, -50, 50); if (pull_position && pull_frame != FrameCounter() && !Distance(pull_position[0], pull_position[1], obj->GetX(), obj->GetY())) { @@ -218,7 +214,7 @@ func ForcesOnObjects() pull_frame = FrameCounter(); obj->SetXDir( xdir, Rope_Precision); - obj->SetYDir( ydir, Rope_Precision); + obj->SetYDir( obj->GetYDir() + ydir, Rope_Precision); //Log("%v, %v", xdir, ydir); } } @@ -246,8 +242,7 @@ public func DoLength(int dolength) if (obj2->Contained()) obj2 = obj2->Contained(); // Line would be shorter than the distance? Do nothing - if (dolength < 0 && ObjectDistance(obj, obj2) > GetLineLength()/100) return Log("NO!"); - Log("%v, Line length: %v, Segment length: %v", ObjectDistance(obj, obj2), GetLineLength()/100 - Rope_SegmentLength, Rope_SegmentLength); + if (dolength < 0 && ObjectDistance(obj, obj2) > GetLineLength()/100) return; return _inherited(dolength); } diff --git a/planet/Tests.ocf/Lines.ocs/Script.c b/planet/Tests.ocf/Lines.ocs/Script.c index 8a9489374..86b74b197 100644 --- a/planet/Tests.ocf/Lines.ocs/Script.c +++ b/planet/Tests.ocf/Lines.ocs/Script.c @@ -6,8 +6,8 @@ func Initialize() CreateObject(Ropeladder, 328, 564); CreateObject(Ropeladder, 226, 330); - var Rock1 = CreateObject(Rock, 159, 363); - var Rock2 = CreateObject(Rock, 232, 388); + CreateObject(Rock, 159, 363); + CreateObject(Rock, 232, 388); var Anchor1 = CreateObject(Ropebridge_Post, 515, 547); var Anchor2 = CreateObject(Ropebridge_Post, 602, 538); diff --git a/planet/Tutorial.ocf/Tutorial02.ocs/Script.c b/planet/Tutorial.ocf/Tutorial02.ocs/Script.c index 313016d75..0a06b3b80 100644 --- a/planet/Tutorial.ocf/Tutorial02.ocs/Script.c +++ b/planet/Tutorial.ocf/Tutorial02.ocs/Script.c @@ -15,7 +15,7 @@ protected func Initialize() goal->CreateGoalFlag(2950, 280); // Create all objects, vehicles, chests used by the player. - var effect, firestone, chest, powderkeg, ropeladder, grapple, cata, dynamite; + var effect, firestone, chest, powderkeg, grapple, dynamite; // Dynamite box to blast through mine. var dyn1 = CreateObject(Dynamite, 242, 665, NO_OWNER); diff --git a/planet/Tutorial.ocf/Tutorial04.ocs/System.ocg/AIMusketAttack.c b/planet/Tutorial.ocf/Tutorial04.ocs/System.ocg/AIMusketAttack.c index 9c2d6979f..bbed7ac4b 100644 --- a/planet/Tutorial.ocf/Tutorial04.ocs/System.ocg/AIMusketAttack.c +++ b/planet/Tutorial.ocf/Tutorial04.ocs/System.ocg/AIMusketAttack.c @@ -28,7 +28,6 @@ protected func AI_MusketAttack(object clonk, int x, int y, object target) // Shoot a lead shot. var dx = target->GetX() - clonk->GetX(); var dy = target->GetY() - clonk->GetY(); - var dist = Distance(0, 0, dx, dy); ControlUseStart(clonk, dx, dy); ControlUseStop(clonk, dx, dy); From 00518622134245345dc81a6119f9240b695ff51c Mon Sep 17 00:00:00 2001 From: Felix Wagner Date: Mon, 20 Feb 2012 12:04:59 +0000 Subject: [PATCH 24/70] For the sake of Eclipse: fixed various var declarations --- planet/Objects.ocd/Environment.ocd/Earthquake.ocd/Script.c | 6 +++--- .../KingOfTheHill.ocd/KingOfTheHillLocation.ocd/Script.c | 2 +- .../Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/Script.c | 5 ++--- planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c | 2 +- .../Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/Script.c | 3 ++- planet/Tutorial.ocf/Tutorial03.ocs/Script.c | 4 ++-- planet/Tutorial.ocf/Tutorial04.ocs/Script.c | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/planet/Objects.ocd/Environment.ocd/Earthquake.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Earthquake.ocd/Script.c index 9a7c0a0f6..209025778 100644 --- a/planet/Objects.ocd/Environment.ocd/Earthquake.ocd/Script.c +++ b/planet/Objects.ocd/Environment.ocd/Earthquake.ocd/Script.c @@ -100,13 +100,13 @@ protected func FxIntEarthquakeTimer(object target, effect, int time) return FX_OK; // Get strength. var str = effect.strength; - // Shake viewport. - if (!Random(10)) - ShakeViewPort(str, x, y); // Get quake coordinates. var x = effect.x; var y = effect.y; var l = 4 * str; + // Shake viewport. + if (!Random(10)) + ShakeViewPort(str, x, y); // Shake ground & objects. ShakeFree(x, y, Random(str / 2) + str / 5 + 5); for (var obj in FindObjects(Find_NoContainer(), Find_OCF(OCF_Alive), Find_InRect(x - l, y - l, l, l))) diff --git a/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/KingOfTheHillLocation.ocd/Script.c b/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/KingOfTheHillLocation.ocd/Script.c index a94493d51..4e691a154 100644 --- a/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/KingOfTheHillLocation.ocd/Script.c +++ b/planet/Objects.ocd/Goals.ocd/KingOfTheHill.ocd/KingOfTheHillLocation.ocd/Script.c @@ -142,7 +142,7 @@ func CreateStarCircle() if(GetType(stars) != C4V_Array) stars=[]; - for(star in stars) star->RemoveObject(); + for(var star in stars) star->RemoveObject(); stars=[]; var amount=radius / 15; diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/Script.c index 25c011180..514fb3a31 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/Script.c @@ -60,6 +60,8 @@ func FxIntBridgeTimer(clonk, effect) // clonk faces bridge direction var tdir = 0; + // get global drawing coordinates + var x = target_x + GetX(), y = target_y + GetY(); if (x > 0) ++tdir; clonk->SetDir(tdir); @@ -67,9 +69,6 @@ func FxIntBridgeTimer(clonk, effect) var min_dt = 3; if (target_y < -20 && !Abs(target_x*5/target_y)) min_dt=2; - // get global drawing coordinates - var x = target_x + GetX(), y = target_y + GetY(); - // bridge speed by dig physical var speed = clonk.ActMap.Dig.Speed/6; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c index a343b8ef2..b46252707 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Axe.ocd/Script.c @@ -116,8 +116,8 @@ public func ControlUseStart(object clonk, int iX, int iY) return true; var rand = Random(2)+1; - var animation = Format("SwordSlash%d.%s", rand, arm); var arm = "R"; + var animation = Format("SwordSlash%d.%s", rand, arm); var length = 15; carry_bone = "pos_hand2"; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/Script.c index cdd6e3502..e80a32096 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/Script.c @@ -144,6 +144,7 @@ public func ControlUseHolding(object clonk, ix, iy) CreateParticle("Spark1", Sin(xp, Random(distp)), -Cos(yp, Random(distp)), Sin(xp, 10), -Cos(yp, 10), RandomX(30,90), RGB(185,250,250)); } + var target; if(target_object) { radiusparticle = 30; @@ -160,7 +161,7 @@ public func ControlUseHolding(object clonk, ix, iy) { radiusparticle = 60; - var target = FindObject(Find_Exclude(this), + target = FindObject(Find_Exclude(this), Find_NoContainer(), Find_Category(C4D_Object), Find_And(Find_Distance(radius, ix, iy), diff --git a/planet/Tutorial.ocf/Tutorial03.ocs/Script.c b/planet/Tutorial.ocf/Tutorial03.ocs/Script.c index 30d3eb729..a70877d08 100644 --- a/planet/Tutorial.ocf/Tutorial03.ocs/Script.c +++ b/planet/Tutorial.ocf/Tutorial03.ocs/Script.c @@ -144,7 +144,7 @@ protected func OnGuideMessageShown(int plr, int index) { // Show first three targets with the arrow. if (index == 0) - for (target in FindObjects(Find_ID(PracticeTarget), Find_InRect(100, 450, 350, 150))) + for (var target in FindObjects(Find_ID(PracticeTarget), Find_InRect(100, 450, 350, 150))) TutArrowShowTarget(target, RandomX(-45, 45), 24); // Show javelin chest with an arrow. if (index == 1) @@ -173,7 +173,7 @@ protected func OnGuideMessageRemoved(int plr, int index) private func MakeTarget(int x, int y, bool flying) { if (flying == nil) - balloon = false; + var balloon = false; var target = CreateObject(PracticeTarget, x, y, NO_OWNER); if (flying == true) diff --git a/planet/Tutorial.ocf/Tutorial04.ocs/Script.c b/planet/Tutorial.ocf/Tutorial04.ocs/Script.c index aaf56f0fc..25f6d8a28 100644 --- a/planet/Tutorial.ocf/Tutorial04.ocs/Script.c +++ b/planet/Tutorial.ocf/Tutorial04.ocs/Script.c @@ -228,7 +228,7 @@ protected func OnGuideMessageShown(int plr, int index) { // Show first four targets with the arrow. if (index == 0) - for (target in FindObjects(Find_ID(SwordTarget))) + for (var target in FindObjects(Find_ID(SwordTarget))) { var angle = RandomX(-45, 45); if (target->GetY() > 620) From 39e2fd8320f39511aabbccc2bcac4afc777a01ef Mon Sep 17 00:00:00 2001 From: Felix Wagner Date: Mon, 20 Feb 2012 12:06:38 +0000 Subject: [PATCH 25/70] Unused var fix, I forgot to save --- planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/Script.c | 1 - 1 file changed, 1 deletion(-) diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/Script.c index af04b210f..798a8228a 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/Script.c @@ -278,7 +278,6 @@ private func RopeRemoved() /* --------------------- Graphics of segments ---------------------- */ func UpdateLines() { - var fTimeStep = 1; var oldangle; for(var i=1; i < ParticleCount; i++) { From b61a44d7faa6f033026e2353ae46209e109492e7 Mon Sep 17 00:00:00 2001 From: Felix Wagner Date: Mon, 20 Feb 2012 12:27:14 +0000 Subject: [PATCH 26/70] last fixes to make Eclipse happy --- planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c | 2 +- planet/Tests.ocf/AirRace.ocs/Script.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c index 032d737c5..9ac5e8751 100644 --- a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c +++ b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Script.c @@ -57,7 +57,7 @@ protected func Initialize() SetGamma(RGB(0,0,blue), RGB(128-blue,128-blue,128+blue), RGB(255-blue,255-blue,255)); // Some natural disasters. - var earthquakes = CreateObject(Earthquake); + //var earthquakes = CreateObject(Earthquake); // earthquakes->SetChance(30); // TODO: Rockfall. diff --git a/planet/Tests.ocf/AirRace.ocs/Script.c b/planet/Tests.ocf/AirRace.ocs/Script.c index ef23d4ab6..65e0a5151 100644 --- a/planet/Tests.ocf/AirRace.ocs/Script.c +++ b/planet/Tests.ocf/AirRace.ocs/Script.c @@ -126,7 +126,7 @@ protected func OnPlayerRespawn(int plr, object cp) var clonk = GetCrew(plr); var plane = CreateObject(Plane, cp->GetX(), cp->GetY(), plr); clonk->Enter(plane); - plane->CreateContents(Bullet); + //plane->CreateContents(Bullet); // there is no bullet def var mode = cp->GetCPMode(); if (mode & PARKOUR_CP_Start) plane->SetR(90); @@ -163,9 +163,9 @@ private func FindPlaneAngle(object cp) protected func GivePlrBonus(int plr, object cp) { - var plane = GetCursor(plr)->Contained(); - if (plane && plane->GetID() == Plane) - plane->CreateContents(Bullet); + //var plane = GetCursor(plr)->Contained(); + //if (plane && plane->GetID() == Plane) + //plane->CreateContents(Bullet); // there is no bullet def return; } From a9e43a1433cfd3b60740f15f878061c985b0787c Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Tue, 21 Feb 2012 00:02:32 +0100 Subject: [PATCH 27/70] Fix sawmill woodchip and smoke production when off --- .../Structures.ocd/Sawmill.ocd/Script.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c index 16a8ad118..3853ca4f8 100644 --- a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c @@ -84,8 +84,11 @@ public func OnProductionHold(id product) public func OnProductionContinued(id product) { - SpinOn(); - AddEffect("Sawing", this, 100, 1, this); + if (!GetEffect("Sawing", this)) + { + SpinOn(); + AddEffect("Sawing", this, 100, 1, this); + } } public func OnProductionFinish(id product) @@ -122,10 +125,11 @@ public func OnProductEjection(object product) protected func RejectCollect(id id_def, object collect) { // Don't collect wood - if(id_def == Wood) return true; - if(collect->~IsSawmillIngredient() || CheckWoodObject(collect)) return false; - else + if (id_def == Wood) return true; + if (collect->~IsSawmillIngredient() || CheckWoodObject(collect)) + return false; + return true; } /*-- Animation --*/ From bdd053e2dcdd1af65ec2e8a542c297d306bd2f2a Mon Sep 17 00:00:00 2001 From: Sven Eberhardt Date: Tue, 21 Feb 2012 17:12:00 +0100 Subject: [PATCH 28/70] Fix compilation with zlib 1.2.6 Include zlib.h instead of just copying the definition for gzFile --- src/c4group/CStdFile.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/c4group/CStdFile.h b/src/c4group/CStdFile.h index 05fb37b5a..80e6d2957 100644 --- a/src/c4group/CStdFile.h +++ b/src/c4group/CStdFile.h @@ -27,11 +27,10 @@ #include #include // for StdThreadCheck #include +#include // for gzFile const int CStdFileBufSize = 4096; -typedef void* gzFile; - class CStdStream { public: From 6f2d4f629e7c5abd2e883d89a5264d6153a402e6 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Tue, 21 Feb 2012 18:51:29 +0100 Subject: [PATCH 29/70] Sawmill does not accepts trees before it is fully constructed (#715) --- planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c index 3853ca4f8..83996c166 100644 --- a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c @@ -28,7 +28,7 @@ public func Initialize() protected func FindTrees() { var tree = FindObject(Find_AtPoint(), Find_Func("IsTree"), Find_Not(Find_Func("IsStanding"))); - if (!tree) return; + if (!tree || GetCon() < 100) return; Saw(tree); } From 3da02c2b2f688a5d56a80280b657799ec4784d41 Mon Sep 17 00:00:00 2001 From: Charles Spurrill Date: Wed, 22 Feb 2012 22:33:24 -0800 Subject: [PATCH 30/70] (#694) Clonk can recollect boompacks in BoomRace --- planet/BackToTheRocks.ocf/Boomrace.ocs/System.ocg/Clonk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planet/BackToTheRocks.ocf/Boomrace.ocs/System.ocg/Clonk.c b/planet/BackToTheRocks.ocf/Boomrace.ocs/System.ocg/Clonk.c index ec3cd95cc..d1c750a9e 100644 --- a/planet/BackToTheRocks.ocf/Boomrace.ocs/System.ocg/Clonk.c +++ b/planet/BackToTheRocks.ocf/Boomrace.ocs/System.ocg/Clonk.c @@ -11,5 +11,5 @@ protected func RejectCollect(id objid, object obj) public func MaxContentsCount() { - return 1; + return 2; } From d458eca6c445a4fb8881af547900a3361a696595 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Thu, 23 Feb 2012 21:42:15 +0100 Subject: [PATCH 31/70] ownable objects now have the right owner after construction --- planet/Objects.ocd/Libraries.ocd/Ownable.ocd/Script.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/planet/Objects.ocd/Libraries.ocd/Ownable.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Ownable.ocd/Script.c index 48d5c6d44..83b32f6b9 100644 --- a/planet/Objects.ocd/Libraries.ocd/Ownable.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Ownable.ocd/Script.c @@ -12,4 +12,10 @@ public func IsInteractable(object clonk) { if(Hostile(GetOwner(), clonk->GetOwner())) return false; return _inherited(clonk, ...); +} + +func Initialize() +{ + // set right owner + SetOwner(GetOwnerOfPosition(0, 0)); } \ No newline at end of file From 8f13c3c791228b8309ce348c215c02fc895f89a0 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Thu, 23 Feb 2012 21:44:10 +0100 Subject: [PATCH 32/70] fixed Steam Engine to only burn fuel when needed, adjusted fuel values for coal and wood --- .../Helpers.ocd/StatusSymbol.ocd/Script.c | 1 + .../Items.ocd/Resources.ocd/Coal.ocd/Script.c | 2 +- .../Items.ocd/Resources.ocd/Wood.ocd/Script.c | 2 +- .../Libraries.ocd/Power.ocd/Script.c | 48 ++++++++++++- .../Libraries.ocd/PowerConsumer.ocd/Script.c | 10 +++ .../SteamEngine.ocd/Graphics.mesh | Bin 52373 -> 125884 bytes .../Structures.ocd/SteamEngine.ocd/Script.c | 63 +++++++++++------- .../SteamEngine.ocd/steam.skeleton | Bin 1201 -> 4186 bytes 8 files changed, 99 insertions(+), 27 deletions(-) diff --git a/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Script.c b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Script.c index 828996ee5..18d2e8942 100644 --- a/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Script.c +++ b/planet/Objects.ocd/Helpers.ocd/StatusSymbol.ocd/Script.c @@ -19,6 +19,7 @@ local ActMap= NextAction="Be", Length=1, FacetBase=1, + AbortCall = "AttachTargetLost" } }; diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/Script.c index 9eae78f6f..99ca575ee 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/Script.c @@ -14,7 +14,7 @@ protected func Hit(x, y) } public func IsFuel() { return true; } -public func GetFuelAmount() { return 100; } +public func GetFuelAmount() { return 30; } local Collectible = 1; local Name = "$Name$"; diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Wood.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Resources.ocd/Wood.ocd/Script.c index d49238b14..7d3bf9362 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Wood.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Wood.ocd/Script.c @@ -12,7 +12,7 @@ func Incineration() } public func IsFuel() { return true; } -public func GetFuelAmount() { return 50; } +public func GetFuelAmount() { return 15; } public func IsSawmillProduct() { return true; } local Collectible = 1; diff --git a/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c index afaddc9aa..9330c352e 100644 --- a/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Power.ocd/Script.c @@ -6,6 +6,7 @@ QueryWaivePowerRequest() OnNotEnoughPower() OnEnoughPower() + OnRemovedFromPowerSleepingQueue(): called when the object was removed from the sleeping queue globals: MakePowerConsumer(int amount) @@ -52,8 +53,20 @@ func AddPowerConsumer(object p, int a) // did not affect power balance, we can just remove/change the link if(a == 0) // remove { - sleeping_links[i] = sleeping_links[GetLength(sleeping_links)]; + sleeping_links[i] = sleeping_links[GetLength(sleeping_links) - 1]; SetLength(sleeping_links, GetLength(sleeping_links) - 1); + + // message + var diff = 0; + { + var t = CreateObject(FloatingMessage, o.obj->GetX() - GetX(), o.obj->GetY() - GetY(), NO_OWNER); + t->SetMessage(Format("%d{{Library_PowerConsumer}}", diff)); + t->SetColor(255, 0, 0); + t->SetYDir(-10); + t->FadeOut(4, 8); + } + + o.obj->~OnRemovedFromPowerSleepingQueue(); return true; } sleeping_links[i].amount = a; @@ -177,7 +190,7 @@ func CheckPowerBalance() var o = sleeping_links[i]; if(o.obj == nil) { - sleeping_links[i] = sleeping_links[GetLength(sleeping_links)]; + sleeping_links[i] = sleeping_links[GetLength(sleeping_links) - 1]; SetLength(sleeping_links, GetLength(sleeping_links) - 1); continue; } @@ -283,6 +296,23 @@ func UnsleepLink(int index) return AddPowerLink(o.obj, o.amount); // revives the link } +// get requested power of nodes that are currently sleeping +public func GetPendingPowerAmount() +{ + var sum = 0; + for(var i = GetLength(sleeping_links); --i >= 0;) + { + sum += -sleeping_links[i].amount; + } + return sum; +} + +// should always be above zero - otherwise an object would have been deactivated +public func GetPowerBalance() +{ + return power_balance; +} + public func IsPowerAvailable(object obj, int amount) { // ignore object for now @@ -347,6 +377,20 @@ func GetPowerHelperForObject(object who) return helper; } +global func GetPendingPowerAmount() +{ + if(!this) return 0; + Library_Power->Init(); + return (Library_Power->GetPowerHelperForObject(this))->GetPendingPowerAmount(); +} + +global func GetCurrentPowerBalance() +{ + if(!this) return 0; + Library_Power->Init(); + return (Library_Power->GetPowerHelperForObject(this))->GetPowerBalance(); +} + global func MakePowerProducer(int amount) { if(!this) return false; diff --git a/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c index a673533ae..7278e7407 100644 --- a/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/PowerConsumer.ocd/Script.c @@ -30,6 +30,7 @@ public func QueryWaivePowerRequest() } // the object requested power but there is no power! +// should possibly not use MakePowerConsumer/Producer in this callback public func OnNotEnoughPower() { PowerConsumer_has_power = false; @@ -38,7 +39,16 @@ public func OnNotEnoughPower() this->AddStatusSymbol(Library_PowerConsumer); } +// called when the object was deleted from the sleeping queue +// that means, the object had requested power before +public func OnRemovedFromPowerSleepingQueue() +{ + // remove symbol + this->RemoveStatusSymbol(Library_PowerConsumer); +} + // called when consumer was sleeping but power is available again +// should possibly not use MakePowerConsumer/Producer in this callback public func OnEnoughPower() { PowerConsumer_has_power = true; diff --git a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Graphics.mesh b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Graphics.mesh index e41956f597783c4359ea9be0339105922bbf6908..857be44df3d0a729c3f4518d9f0d24c8035e4d87 100644 GIT binary patch literal 125884 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 z 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 literal 52373 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,21, -20, -1, -1, -30); + Sound("Chuff"); //I think a 'chuff' or 'metal clonk' sound could be good here -Ringwaul + } + // Still active? - if(!ActIdle()) + if(!ActIdle()) return true; + // or still warm water in the tank?! + if(GetEffect("CreatesPower", this)) return true; - + + // not needed? + if(GetPendingPowerAmount() == 0) + return false; + // Still has some fuel? if(iFuelAmount) return SetAction("Work"); - var pFuel; // Search for new fuel - if(pFuel = FindObject(Find_Container(this), Find_Func("IsFuel"))) + if(fuel = FindObject(Find_Container(this), Find_Func("IsFuel"))) { - iFuelAmount += pFuel->~GetFuelAmount(); - pFuel->RemoveObject(); + iFuelAmount += fuel->~GetFuelAmount(); + fuel->RemoveObject(); SetAction("Work"); - return 1; + return true; } - //Ejects non fuel items immediately - if(pFuel = FindObject(Find_Container(this), !Find_Func("IsFuel"))) { - pFuel->Exit(-53,21, -20, -1, -1, -30); - Sound("Chuff"); //I think a 'chuff' or 'metal clonk' sound could be good here -Ringwaul - } - - return 0; + return false; } func ConsumeFuel() { if(iFuelAmount > 0) { - // every fuel unit gives power for ten seconds - power_seconds += 10; + // every fuel unit gives power for one second + --iFuelAmount; + power_seconds += 1; if(!GetEffect("CreatesPower", this)) AddEffect("CreatesPower", this, 1, 36, this); } // All used up? - if(!iFuelAmount) + if(!iFuelAmount || ((GetPendingPowerAmount() == 0) && (GetCurrentPowerBalance() >= SteamEngine_produced_power))) { SetAction("Idle"); ContentsCheck(); @@ -63,7 +73,9 @@ func FxCreatesPowerStart(target, effect, temp) { if(temp) return; // fixed amount - MakePowerProducer(300); + MakePowerProducer(SteamEngine_produced_power); + + AddEffect("Smoking", this, 1, 5, this); } func FxCreatesPowerTimer(target, effect) @@ -75,8 +87,17 @@ func FxCreatesPowerTimer(target, effect) func FxCreatesPowerStop(target, effect, reason, temp) { if(temp) return; - // fixed amount + // disable producer MakePowerProducer(0); + + if(GetEffect("Smoking", this)) + RemoveEffect("Smoking", this); +} + +func FxSmokingTimer() +{ + Smoke(20, -15, 10); + return 1; } local ActMap = { @@ -88,10 +109,6 @@ Work = { FlipDir = 1, Length = 20, Delay = 2, - X = 0, - Y = 0, - Wdt = 110, - Hgt = 80, NextAction = "Work", Animation = "Work", EndCall = "ConsumeFuel", diff --git a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/steam.skeleton b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/steam.skeleton index 1c9f2338098ae2ff99a4a166810d7e0b41249821..a465a3a96fd160f8c19add7e6f509fa0b4e0e4e7 100644 GIT binary patch literal 4186 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 From 7c883df228952ccf5c2396a297825d7238072bf7 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Thu, 23 Feb 2012 21:45:13 +0100 Subject: [PATCH 33/70] added building: Power Compensator --- .../BurningBattery.ocd/DefCore.txt | 19 ++ .../BurningBattery.ocd/Graphics.2.png | Bin 0 -> 456 bytes .../BurningBattery.ocd/Script.c | 25 +++ .../BurningBattery.ocd/StringTblDE.txt | 2 + .../BurningBattery.ocd/StringTblUS.txt | 2 + .../ChargeShower.ocd/DefCore.txt | 12 ++ .../ChargeShower.ocd/Graphics.4.png | Bin 0 -> 42185 bytes .../Compensator.ocd/ChargeShower.ocd/Script.c | 73 +++++++ .../ChargeShower.ocd/StringTblDE.txt | 2 + .../ChargeShower.ocd/StringTblUS.txt | 2 + .../Compensator.ocd/Compensator.png | Bin 0 -> 89680 bytes .../Compensator.ocd/Compensator.skeleton | Bin 0 -> 1628 bytes .../Compensator.ocd/DefCore.txt | 20 ++ .../Compensator.ocd/Graphics.mesh | Bin 0 -> 26070 bytes .../Compensator.ocd/Scene.material | 23 +++ .../Structures.ocd/Compensator.ocd/Script.c | 188 ++++++++++++++++++ .../Compensator.ocd/StringTblDE.txt | 2 + .../Compensator.ocd/StringTblUS.txt | 2 + 18 files changed, 372 insertions(+) create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/Graphics.2.png create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/Script.c create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/StringTblDE.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/StringTblUS.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/Graphics.4.png create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/Script.c create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblDE.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblUS.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/Compensator.png create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/Compensator.skeleton create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/Graphics.mesh create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/Scene.material create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/Script.c create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblDE.txt create mode 100644 planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblUS.txt diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/DefCore.txt b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/DefCore.txt new file mode 100644 index 000000000..80f31c3aa --- /dev/null +++ b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/DefCore.txt @@ -0,0 +1,19 @@ +[DefCore] +id=Compensator_BurningBattery +Version=4,10,0,0 +Category=C4D_Object +Width=10 +Height=10 +Offset=-5,-5 +Vertices=1 +VertexX=0 +VertexFriction=20 +Value=1 +Mass=20 +Components=Compensatory_BurningBattery=1 +Projectile=1 +Rotate=1 +NoStabilize=1 +Timer=2 +TimerCall=DoSmoke + diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/Graphics.2.png b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/BurningBattery.ocd/Graphics.2.png new file mode 100644 index 0000000000000000000000000000000000000000..e6cf991fa8997bb1a6164349f092b9f9dc1a68be GIT binary patch literal 456 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 DTR@vB literal 0 HcmV?d00001 diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/Script.c new file mode 100644 index 000000000..4acf6e3ec --- /dev/null +++ b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/Script.c @@ -0,0 +1,73 @@ +/** + ChargeShower + Shows stuff. +*/ + +local Name = "$Name$"; +local Description = "$Description$"; + +local current, to; + +local ActMap = { + Turn = { + Prototype = Action, + Name = "Turn", + Procedure = DFA_ATTACH, + Length=6, + Delay=4, + X = 0, + Y = 0, + Wdt = 11, + Hgt = 19, + NextAction = "Turn" + } + }; + +func AttachTargetLost() +{ + return RemoveObject(); +} + +func To(int i) +{ + to = i; + if(!GetEffect("Adjust", this)) + AddEffect("Adjust", this, 1, 2, this); +} + +func FxAdjustTimer() +{ + if(current == to) + return -1; + + if(current < to) + ++current; + else --current; + + Set(current); + + return 1; +} + +func Set(int i) +{ + SetObjDrawTransform((800 * i)/100, 0, 0, 0, 900, -150); +} + +func Init(to) +{ + var x = GetX() - to->GetX(); + var y = GetY() - to->GetY(); + SetVertexXY(0, -x, -y); + SetAction("Turn", to); + SetPhase(Random(5)); + this.Layer = to.Layer - 1; +} + +public func Initialize() +{ + to=0; + current=0; + Set(to); + return true; +} \ No newline at end of file diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblDE.txt b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblDE.txt new file mode 100644 index 000000000..50d827134 --- /dev/null +++ b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=ChargeShower +Description=Shows stuff. \ No newline at end of file diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblUS.txt b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblUS.txt new file mode 100644 index 000000000..50d827134 --- /dev/null +++ b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/ChargeShower.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=ChargeShower +Description=Shows stuff. \ No newline at end of file diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/Compensator.png b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/Compensator.png new file mode 100644 index 0000000000000000000000000000000000000000..0db92948e9796bc829c2cd586fce61425f32d9a9 GIT binary patch literal 89680 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 z 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 + rightcharge = CreateObject(Compensator_ChargeShower, 6, 10, NO_OWNER); + rightcharge->Init(this); + return _inherited(...); +} + +func OnNotEnoughPower() +{ + // not enough power to sustain a battery - turn off + if(GetEffect("ConsumePower", this)) + RemoveEffect("ConsumePower", this); + + ScheduleCall(this, "UnmakePowerConsumer", 1, 0); + return _inherited(...); +} + +func UnmakePowerConsumer(){MakePowerConsumer(0);} + +// devour energy +func OnEnoughPower() +{ + if(!GetEffect("ConsumePower", this)) + AddEffect("ConsumePower", this, 1, 36, this); + return _inherited(...); +} + +func SetCharge(int to) +{ + power_seconds = BoundBy(to, 0, Compensator_max_seconds); + RefreshAnimationPosition(); +} + +func RefreshAnimationPosition() +{ + var charge = (power_seconds * 100) / Compensator_max_seconds; + /*var current = GetAnimationPosition(anim); + var len = GetAnimationLength("Charge"); + SetAnimationPosition(anim, Anim_Linear(current, current, len - (charge * len) / 100, 35, ANIM_Hold));*/ + leftcharge->To(Min(charge, 50)*2); + rightcharge->To(Max(0, charge-50)*2); +} + +func FxConsumePowerTimer(target, effect, time) +{ + ++power_seconds; + RefreshAnimationPosition(); + // fully charged? + if(power_seconds >= Compensator_max_seconds) + { + MakePowerConsumer(0); + return -1; + } + return 1; +} + +func EnergyCheck() +{ + if(GetCon() < 100) return; + + // consuming - everything is alright + if(GetEffect("ConsumePower", this)) + return true; + // producing - nothing to change either + if(GetEffect("ProducePower", this)) + return true; + + // neutral compensators don't do anything + if(GetOwner() == NO_OWNER) return false; + + // are we needed? + if(power_seconds > 0) + { + var s = GetPendingPowerAmount(); + if(s > 0) + { + // turn on, start the machines! + AddEffect("ProducePower", this, 1, 36, this); + return true; + } + } + + // fully charged + if(power_seconds >= Compensator_max_seconds) + return false; + + // can we leech power? + var p = GetCurrentPowerBalance(); + + // we have some play here? + if(p >= Compensator_power_usage) + { + MakePowerConsumer(Compensator_power_usage); + return true; + } + + return false; +} + +func FxProducePowerStart(target, effect, temp) +{ + if(temp) return; + MakePowerProducer(Compensator_power_usage); + + // todo: effects + AddEffect("Sparkle", this, 1, 1, this); +} + +func FxSparkleTimer(target, effect, time) +{ + effect.Interval *= 2; + if(effect.Interval > 35*3) return -1; + + CreateParticle("StarSpark", RandomX(-3,3), RandomX(-14, -10), RandomX(-5,5), RandomX(-8, 0), 30, RGB(200, 200, 255), this); + CreateParticle("StarSpark", RandomX(-3,3), RandomX(-14, -10), RandomX(-5,5), RandomX(-8, 0), 30, RGB(200, 200, 255), this); +} + +func FxProducePowerTimer(target, effect, time) +{ + --power_seconds; + RefreshAnimationPosition(); + if(power_seconds <= 0) + { + return -1; + } + + // stop when not needed + if((GetCurrentPowerBalance() >= Compensator_power_usage) && GetPendingPowerAmount() == 0) + return -1; + + return 1; +} + +func FxProducePowerStop(target, effect, reason, temp) +{ + if(temp) return; + MakePowerProducer(0); + + if(GetEffect("Sparkle", this)) + RemoveEffect("Sparkle", this); +} + +func Incineration() +{ + if(power_seconds == 0) + return Extinguish(); + + + for(var i = 0; i < 2; ++i) + { + var x = -7 + 14 * i; + var b = CreateObject(Compensator_BurningBattery, x, 6, NO_OWNER); + b->SetController(GetController()); // killtracing + + b->SetSpeed(-30 + 60 * i + RandomX(-10, 10), RandomX(-50, -30)); + } + + Explode(30); +} diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblDE.txt b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblDE.txt new file mode 100644 index 000000000..94a54bc54 --- /dev/null +++ b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=Kompensator +Description=Kann Energie über kurze Zeit puffern. diff --git a/planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblUS.txt b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblUS.txt new file mode 100644 index 000000000..792454958 --- /dev/null +++ b/planet/Objects.ocd/Structures.ocd/Compensator.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=Compensator +Description=Is able to puffer a small amount of energy over some time. From e3d84a550afbbf11366761f3ff2aff5b8d1a19a5 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Thu, 23 Feb 2012 21:45:58 +0100 Subject: [PATCH 34/70] added two particles --- .../ExploSmokeFastFade.ocd/Graphics.png | Bin 0 -> 26274 bytes .../ExploSmokeFastFade.ocd/Particle.txt | 11 +++++++++++ .../Effects.ocd/StarSpark.ocd/Graphics.png | Bin 0 -> 828 bytes .../Effects.ocd/StarSpark.ocd/Particle.txt | 17 +++++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Graphics.png create mode 100644 planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Particle.txt create mode 100644 planet/Objects.ocd/Effects.ocd/StarSpark.ocd/Graphics.png create mode 100644 planet/Objects.ocd/Effects.ocd/StarSpark.ocd/Particle.txt diff --git a/planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Graphics.png b/planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Graphics.png new file mode 100644 index 0000000000000000000000000000000000000000..8c2fd16c7bfaf9f624a0c5980d2bd3bd8ad916ce GIT binary patch literal 26274 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 literal 0 HcmV?d00001 diff --git a/planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Particle.txt b/planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Particle.txt new file mode 100644 index 000000000..da3848d9b --- /dev/null +++ b/planet/Objects.ocd/Effects.ocd/Explosion.ocd/ExploSmokeFastFade.ocd/Particle.txt @@ -0,0 +1,11 @@ +[Particle] +Name=ExploSmokeFastFade +MaxCount=800 +InitFn=StdInit +ExecFn=StdExec +DrawFn=Std +Face=0,0,64,64,-32,-32 +Delay=0 +Repeats=1 +AlphaFade=2 +FadeDelay=1 diff --git a/planet/Objects.ocd/Effects.ocd/StarSpark.ocd/Graphics.png b/planet/Objects.ocd/Effects.ocd/StarSpark.ocd/Graphics.png new file mode 100644 index 0000000000000000000000000000000000000000..20ea95e30afc21ec4bbdf56d2079058c02c96c1e GIT binary patch literal 828 zcmV-C1H=4@P) z000W>0fLJSS^xk7?ny*JRCt`d*ITGnRTKu`m3mUNl02SLGZoVylr)fv#D@x^2tpyd zDIyX`DL#aOB3+4mDk35BrSPE(6tW2@UT3+^ zX6^Pld%}eE59S>6pW`2M%(*gTZS))4oS#)4I1X2q*yneOK!yb+wkJACU@1lvZ0kEo z;3ljn*xoJ~*E3WEGJJqxIs7rk#=W@Q-*TeILMGB02Zt+GHPr=P{{W2{LryOWd3AQ`nup zkKukijqj3e9JXR!6IrKV_&@~8Le_&rScPt!$AkDw)Pf^egIm(LM@xL%ft6_^|0Qx6 zfsrDcS7C0>ek;!4trU?TP!lJkhGjT~mveLGU?aXrvR#&t%|d@w(s3`|Or#d#B6exC z(>RO^_(;@?=g^1VG^ec`=*DX}hZFcEEqp=$_8WGjX#9)^D)_Ekh{lSfdSB>Y)@s;} z#Uc^AsuGxh+wm~gVw2E#uh6uec2>yqJ>JEOST5w8fzefWKNWW-a(^~iaECY*)5XbY zT7*=TU_4$G(Kw}%{k6j4zo%ZqXBrjqe-oI9*KsmATr7&tc^u3wd{oGF3Gawpc?Em0 z1=Ct3Fd1*)bD>xLE|{6fyoayxYufD={3EXFvv@Y=YdTho8c=#o=fN~_nXE`*FXllX zHsG4H;A8k(XntIj=y~`Hh+=O`CE0DPF(;0000 Date: Thu, 23 Feb 2012 22:35:30 +0100 Subject: [PATCH 35/70] Steamengine can now be accessed for contents --- .../Structures.ocd/SteamEngine.ocd/DefCore.txt | 2 +- .../Structures.ocd/SteamEngine.ocd/Script.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/DefCore.txt b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/DefCore.txt index bb49f9402..db8738e8d 100644 --- a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/DefCore.txt +++ b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/DefCore.txt @@ -13,7 +13,7 @@ VertexFriction=50,50,100,100 Value=180 Mass=4000 Components=Rock=6;Metal=3 -Collection=-69,20,20,22 +Collection=-31,9,10,10 Exclusive=1 BlastIncinerate=130 Construction=1 diff --git a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c index e7b79acda..064785ff0 100644 --- a/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/SteamEngine.ocd/Script.c @@ -15,6 +15,21 @@ func Construction() return _inherited(...); } +public func IsContainer() { return true; } + +protected func RejectEntrance(object obj) +{ + if (obj->~IsFuel()) + return false; + return true; +} + +protected func RejectCollect(id item, object obj) +{ + // Just return RejectEntrance for this object. + return RejectEntrance(obj); +} + func ContentsCheck() { //Ejects non fuel items immediately From c96d5048f2542289c897afc09b42851b01c92e7e Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Fri, 24 Feb 2012 00:33:24 +0100 Subject: [PATCH 36/70] Fix a link in the german docs --- docs/de.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de.po b/docs/de.po index c5a5f4573..27742ef59 100644 --- a/docs/de.po +++ b/docs/de.po @@ -15375,7 +15375,7 @@ msgstr "int/array" #: sdk/definition/properties.xml:56(col) msgid "Controls the visibility of the object. See the detailed documentation of possible values." -msgstr "Steuert die Sichtbarkeit des Objekts. Detailierte Dokumentation möglicher Werte" +msgstr "Steuert die Sichtbarkeit des Objekts. Detailierte Dokumentation möglicher Werte" #: sdk/definition/properties.xml:110(col) #: sdk/definition/properties.xml:115(col) From c3b57957c4c53952c65dcca9eb782b0d9ee6f78d Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sat, 25 Feb 2012 16:15:17 +0100 Subject: [PATCH 37/70] Coniferous tree seeds faster, this is needed in for rounds like Goldmine Also some more trees and gold in goldmine. --- .../GoldRush.ocs/Landscape.txt | 1 + planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c | 2 +- .../Trees.ocd/Coniferous.ocd/Script.c | 4 +++- .../Libraries.ocd/Plant.ocd/Script.c | 17 +++++------------ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt index 48f4b4a1d..5993056d2 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt @@ -96,6 +96,7 @@ map Goldmine { RandomSpots & overlay { mat=Gold; tex=gold; }; RandomSpots & overlay { mat=Gold; tex=gold; }; RandomMat & overlay { mat=Gold; tex=gold; }; + RandomMat & overlay { mat=Gold; tex=gold; }; }; // Border of earth and sand. overlay { diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c index af4518e93..2521b9c30 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Script.c @@ -13,7 +13,7 @@ protected func Initialize() goal->SetWealthGoal(400); // Place some trees. - for (var i = 0; i < 12 + Random(4); i++) + for (var i = 0; i < 16 + Random(4); i++) PlaceVegetation(Tree_Coniferous, 0, LandscapeHeight() / 3, LandscapeWidth(), LandscapeHeight(), 1000 * (61 + Random(40))); // place some sprout berries diff --git a/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/Trees.ocd/Coniferous.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/Trees.ocd/Coniferous.ocd/Script.c index e8cbb2863..a608997d3 100644 --- a/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/Trees.ocd/Coniferous.ocd/Script.c +++ b/planet/Objects.ocd/Environment.ocd/Vegetation.ocd/Trees.ocd/Coniferous.ocd/Script.c @@ -3,10 +3,12 @@ #include Library_Plant private func SeedAreaSize() { return 400; } +private func SeedChance() { return 50; } +private func SeedAmount() { return 12; } func Construction() { - StartGrowth(1); + StartGrowth(5); inherited(...); } diff --git a/planet/Objects.ocd/Libraries.ocd/Plant.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Plant.ocd/Script.c index 75f110985..dd627e49f 100644 --- a/planet/Objects.ocd/Libraries.ocd/Plant.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Plant.ocd/Script.c @@ -36,24 +36,17 @@ public func IsPlant() /** Chance to reproduce plant. Chances are one out of return value. Default is 500. @return the chance, higher = less chance. */ -private func SeedChance() -{ - return 500; -} +private func SeedChance() { return 500; } + /** Distance the seeds may travel. Default is 300. @return the maximum distance. */ -private func SeedAreaSize() -{ - return 300; -} +private func SeedAreaSize() { return 300; } + /** The amount of plants allowed within SeedAreaSize. Default is 8. @return the maximum amount of plants. */ -private func SeedAmount() -{ - return 8; -} +private func SeedAmount() { return 8; } /** Automated positioning via RootSurface, make sure to call this if needed (in case Construction is overloaded) */ From 8eb76cef8ce689f06cf194df51dd7b37480b3c45 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 25 Feb 2012 16:54:51 +0100 Subject: [PATCH 38/70] Unify overlay drawing of pictures Instead of having custom code drawing the picture in C4DefGraphics.cpp, re-use C4Def::Draw(). This changeset changes the coordinate system on which draw transformations are applied to sprite picture overlays. The transformation is no longer applied in the frame of the overlay picture but in the frame of the object on which the overlay is drawn. This was already the case before for mesh graphics, so this change unifies the interpretation of draw transformations for sprite and mesh graphics. The Tools Workshop has been changed accordingly so that object is production are properly displayed on the sign. This also fixes the pictures of some objects being off the sign. --- .../Structures.ocd/ToolsWorkshop.ocd/Script.c | 3 +- src/game/object/C4DefGraphics.cpp | 59 ++++++++----------- 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c index 87c6913c9..3bb53b277 100644 --- a/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/ToolsWorkshop.ocd/Script.c @@ -75,9 +75,8 @@ public func SetSign(id def) { if (!def) return SetGraphics("", nil, 1, 4); - var iSize = Max(def->GetDefCoreVal("Picture", "DefCore", 2), def->GetDefCoreVal("Picture", "DefCore", 3)); SetGraphics("", def, 1, 4); - SetObjDrawTransform(200, 0, 460*iSize, 0, 200, 90*iSize, 1); + SetObjDrawTransform(200, 0, 19500, 0, 200, 2500, 1); } local ActMap = { diff --git a/src/game/object/C4DefGraphics.cpp b/src/game/object/C4DefGraphics.cpp index 9545af43c..0c7bd6d69 100644 --- a/src/game/object/C4DefGraphics.cpp +++ b/src/game/object/C4DefGraphics.cpp @@ -646,10 +646,7 @@ void C4GraphicsOverlay::UpdateFacet() case MODE_IngamePicture: case MODE_Picture: // def picture fZoomToShape = true; - if (pSourceGfx->Type == C4DefGraphics::TYPE_Bitmap) - fctBlit.Set(pSourceGfx->GetBitmap(), pDef->PictureRect.x, pDef->PictureRect.y, pDef->PictureRect.Wdt, pDef->PictureRect.Hgt); - else - pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh); + // drawn at runtime break; case MODE_ExtraGraphics: // like ColorByOwner-sfc @@ -695,7 +692,9 @@ bool C4GraphicsOverlay::IsValid(const C4Object *pForObj) const } else if (pSourceGfx) { - if (pSourceGfx->Type == C4DefGraphics::TYPE_Bitmap) + if(eMode == MODE_Picture || eMode == MODE_IngamePicture) + return true; + else if (pSourceGfx->Type == C4DefGraphics::TYPE_Bitmap) return !!fctBlit.Surface; else return !!pMeshInstance; @@ -919,6 +918,26 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP pForObj->pDrawTransform = pPrevTrf; } } + else if(eMode == MODE_Picture || eMode == MODE_IngamePicture) + { + C4Def *pDef = pSourceGfx->pDef; + float twdt, thgt; + if (fZoomToShape) + { + twdt = pForObj->Shape.Wdt; + thgt = pForObj->Shape.Hgt; + } + else + { + twdt = pDef->Shape.Wdt; + thgt = pDef->Shape.Hgt; + } + + C4TargetFacet ccgo; + ccgo.Set(cgo.Surface, offX-twdt/2, offY-thgt/2, twdt, thgt, cgo.TargetX, cgo.TargetY); + C4DrawTransform trf(Transform, offX, offY); + pDef->Draw(ccgo, false, pForObj->Color, NULL, iPhase, 0, &trf); + } else { // no object specified: Draw from fctBlit @@ -937,7 +956,7 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP fctBlit.DrawT(cgo.Surface, offX - fctBlit.Wdt/2 + fctBlit.TargetX, offY - fctBlit.Hgt/2 + fctBlit.TargetY, iPhase, 0, &trf); } - else if(eMode == MODE_Base || eMode == MODE_Action) + else { C4Def *pDef = pSourceGfx->pDef; @@ -958,34 +977,6 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP pDraw->RenderMesh(*pMeshInstance, cgo.Surface, offX - pDef->Shape.Wdt/2.0, offY - pDef->Shape.Hgt/2.0, pDef->Shape.Wdt, pDef->Shape.Hgt, pForObj->Color, &trf); pDraw->SetMeshTransform(NULL); } - else - { - C4Def *pDef = pSourceGfx->pDef; - - float twdt, thgt; - if (fZoomToShape) - { - twdt = pForObj->Shape.Wdt; - thgt = pForObj->Shape.Hgt; - } - else - { - twdt = pDef->Shape.Wdt; - thgt = pDef->Shape.Hgt; - } - - C4Value value; - pDef->GetProperty(P_PictureTransformation, &value); - StdMeshMatrix matrix; - if (C4ValueToMatrix(value, &matrix)) - pDraw->SetMeshTransform(&matrix); - - C4DrawTransform trf(Transform, offX, offY); - pDraw->SetPerspective(true); - pDraw->RenderMesh(*pMeshInstance, cgo.Surface, offX - twdt/2, offY - thgt/2, twdt, thgt, pForObj->Color, &trf); - pDraw->SetPerspective(false); - pDraw->SetMeshTransform(NULL); - } } // cleanup From cebbacd3f4ce3dff1af59f35d942bc63a33a6a61 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 25 Feb 2012 17:04:00 +0100 Subject: [PATCH 39/70] Remove "Picture" DefCore entry in objects having mesh graphics --- planet/Objects.ocd/Clonk.ocd/DefCore.txt | 1 - planet/Objects.ocd/Items.ocd/Tools.ocd/Boompack.ocd/DefCore.txt | 1 - planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/DefCore.txt | 1 - planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/DefCore.txt | 1 - planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/DefCore.txt | 1 - planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/DefCore.txt | 1 - .../Vehicles.ocd/Airship.ocd/AirshipBurnt.ocd/DefCore.txt | 1 - 7 files changed, 7 deletions(-) diff --git a/planet/Objects.ocd/Clonk.ocd/DefCore.txt b/planet/Objects.ocd/Clonk.ocd/DefCore.txt index 9362ef664..9f911da4a 100644 --- a/planet/Objects.ocd/Clonk.ocd/DefCore.txt +++ b/planet/Objects.ocd/Clonk.ocd/DefCore.txt @@ -12,7 +12,6 @@ VertexCNAT=0,4,8,1,2,1,2 VertexFriction=300,300,100,300,300,300,300 Value=25 Mass=50 -Picture=192,100,32,40 Collection=-8,-10,16,27 ContactIncinerate=10 CrewMember=1 diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Boompack.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/Boompack.ocd/DefCore.txt index e5f0d6e65..6913389cb 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Boompack.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Boompack.ocd/DefCore.txt @@ -9,7 +9,6 @@ Vertices=4 VertexX=0,0,-4,4 VertexY=3,-6,10,10 VertexFriction=80,60,60 -Picture=0,0,16,16 Value=12 Mass=20 Components=Blackpowder=3;Wood=1;Metal=1; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/DefCore.txt index a106fd0c8..602c60811 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pickaxe.ocd/DefCore.txt @@ -9,7 +9,6 @@ Vertices=4 VertexX=0,-4,4,0 VertexY=-4,-3,-3,4 VertexFriction=50,100,100,40 -Picture=10,0,64,64 Value=10 Mass=20 Components=Wood=1;Metal=1; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/DefCore.txt index fd09c6d55..59af346e0 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/TeleGlove.ocd/DefCore.txt @@ -9,7 +9,6 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 Value=20 Mass=7 Components=Metal=2;Crystal=2; diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/DefCore.txt index 78a3413bb..425344d79 100644 --- a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Club.ocd/DefCore.txt @@ -9,7 +9,6 @@ Vertices=2 VertexX=0,0 VertexY=-7,7 VertexFriction=50,50 -Picture=10,10,54,54 Value=10 Mass=20 Components=Wood=1;Metal=1; diff --git a/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/DefCore.txt b/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/DefCore.txt index 9c839039f..b7f6f2921 100644 --- a/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/DefCore.txt +++ b/planet/Objects.ocd/Structures.ocd/WindGenerator.ocd/DefCore.txt @@ -14,7 +14,6 @@ VertexFriction=50,50,50,100,100 Value=45 Mass=900 Components=Wood=4;Metal=1 -Picture=30,0,80,94 Exclusive=1 ContactIncinerate=4 BlastIncinerate=60 diff --git a/planet/Objects.ocd/Vehicles.ocd/Airship.ocd/AirshipBurnt.ocd/DefCore.txt b/planet/Objects.ocd/Vehicles.ocd/Airship.ocd/AirshipBurnt.ocd/DefCore.txt index 292123926..d9edcee2a 100644 --- a/planet/Objects.ocd/Vehicles.ocd/Airship.ocd/AirshipBurnt.ocd/DefCore.txt +++ b/planet/Objects.ocd/Vehicles.ocd/Airship.ocd/AirshipBurnt.ocd/DefCore.txt @@ -14,4 +14,3 @@ Value=34 Mass=60 Components=Metal=4;Wood=1; SolidMask=64,0,64,54,0,0 -Picture=128,0,128,128,0,0 \ No newline at end of file From 9d94b1da6ec0c51da73fed266d785c4517e70d75 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 25 Feb 2012 17:35:24 +0100 Subject: [PATCH 40/70] For scaled sprite graphics, don't interpret Picture coordinates as scaled Otherwise an object with a scale of 5 and a picture of 64x64 (such as the Metal and the GoldBar objects) cannot properly set the picture rectangle. --- .../FrostboltScroll.ocd/DefCore.txt | 2 +- .../HardeningScroll.ocd/DefCore.txt | 2 +- .../Scrolls.ocd/WindScroll.ocd/DefCore.txt | 2 +- .../FireballScroll.ocd/DefCore.txt | 2 +- .../TeleportScroll.ocd/DefCore.txt | 2 +- .../Scrolls.ocd/WindScroll.ocd/DefCore.txt | 2 +- .../FireballScroll.ocd/DefCore.txt | 2 +- .../Scrolls.ocd/ThunderScroll.ocd/DefCore.txt | 2 +- .../Scrolls.ocd/WindScroll.ocd/DefCore.txt | 2 +- .../Foodstuff.ocd/Bread.ocd/DefCore.txt | 2 +- .../Resources.ocd/Coal.ocd/DefCore.txt | 2 +- .../Resources.ocd/GoldBar.ocd/DefCore.txt | 2 +- .../Resources.ocd/Ice.ocd/DefCore.txt | 2 +- .../Resources.ocd/Loam.ocd/DefCore.txt | 2 +- .../Resources.ocd/Metal.ocd/DefCore.txt | 2 +- .../Resources.ocd/Ore.ocd/DefCore.txt | 2 +- .../Resources.ocd/Snow.ocd/DefCore.txt | 2 +- .../Resources.ocd/Sulphur.ocd/DefCore.txt | 2 +- .../Tools.ocd/Dynamite.ocd/DefCore.txt | 2 +- .../Tools.ocd/JarOfWinds.ocd/DefCore.txt | 2 +- .../Ropebridge.ocd/BridgePost.ocd/DefCore.txt | 4 +- .../LadderSegment.ocd/DefCore.txt | 2 +- .../Weapons.ocd/Bow.ocd/Arrow.ocd/DefCore.txt | 2 +- .../Arrow.ocd/HelpArrow.ocd/DefCore.txt | 1 - .../Weapons.ocd/IronBomb.ocd/DefCore.txt | 2 +- .../Musket.ocd/Ammo.ocd/DefCore.txt | 2 +- .../Icons.ocd/Acid.ocd/DefCore.txt | 2 +- .../Icons.ocd/Fuel.ocd/DefCore.txt | 2 +- .../Icons.ocd/Lava.ocd/DefCore.txt | 2 +- .../Icons.ocd/Oil.ocd/DefCore.txt | 2 +- .../Icons.ocd/Water.ocd/DefCore.txt | 2 +- .../Structures.ocd/Crossing.ocd/DefCore.txt | 4 +- .../FireGlobe.ocd/DefCore.txt | 2 +- .../Moss_Test.ocs/Moss.ocd/DefCore.txt | 4 +- src/game/object/C4Def.cpp | 11 +++--- src/lib/texture/C4Facet.cpp | 39 +++++++++++++++++++ src/lib/texture/C4Facet.h | 2 + src/platform/StdDDraw2.cpp | 12 ++++-- src/platform/StdDDraw2.h | 3 ++ 39 files changed, 94 insertions(+), 46 deletions(-) diff --git a/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/FrostboltScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/FrostboltScroll.ocd/DefCore.txt index 25fd74e4f..c23daff5d 100644 --- a/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/FrostboltScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/FrostboltScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/HardeningScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/HardeningScroll.ocd/DefCore.txt index 6ccf27fd3..0ff44d148 100644 --- a/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/HardeningScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/HardeningScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt index 05cce8ac0..d333630e5 100644 --- a/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/FrozenFortress.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt index 59a5a6326..7af379dff 100644 --- a/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/TeleportScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/TeleportScroll.ocd/DefCore.txt index 08492301d..00901c5d3 100644 --- a/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/TeleportScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/TeleportScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt index 05cce8ac0..d333630e5 100644 --- a/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/Overcast.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt index 59a5a6326..7af379dff 100644 --- a/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/FireballScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/ThunderScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/ThunderScroll.ocd/DefCore.txt index a7fb29dfa..c1aed6103 100644 --- a/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/ThunderScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/ThunderScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt b/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt index 05cce8ac0..d333630e5 100644 --- a/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt +++ b/planet/BackToTheRocks.ocf/ThunderousSkies.ocs/Scrolls.ocd/WindScroll.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=-3,2,2 VertexFriction=40,40,40 -Picture=0,0,8,8 +Picture=0,0,64,64 Value=25 Mass=2 Rotate=1 diff --git a/planet/Objects.ocd/Items.ocd/Foodstuff.ocd/Bread.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Foodstuff.ocd/Bread.ocd/DefCore.txt index 15d60b43c..0d9f3e401 100644 --- a/planet/Objects.ocd/Items.ocd/Foodstuff.ocd/Bread.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Foodstuff.ocd/Bread.ocd/DefCore.txt @@ -12,4 +12,4 @@ VertexFriction=50,100,100 Value=10 Mass=2 Components=Flour=1 -Picture=8,0,16,16 \ No newline at end of file +Picture=32,0,64,64 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/DefCore.txt index 0b046b500..eae72f611 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Coal.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=3 VertexX=0,2,-2 VertexY=1,-1,-1 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/GoldBar.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/GoldBar.ocd/DefCore.txt index 322b972ea..a054a23ca 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/GoldBar.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/GoldBar.ocd/DefCore.txt @@ -12,6 +12,6 @@ VertexCNAT=1,2,16 VertexFriction=30,30,30 Value=25 Mass=16 -Picture=0,4,13,13 +Picture=0,20,64,64 Components=Nugget=3 Rotate=1 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Ice.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Ice.ocd/DefCore.txt index 6e8a46413..564cdae82 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Ice.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Ice.ocd/DefCore.txt @@ -7,7 +7,7 @@ TimerCall=Check Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=3 VertexX=0,2,-2 VertexY=1,-1,-1 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/DefCore.txt index 79d3b042f..14f9a6ebd 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Loam.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=2 VertexX=0,0 VertexY=3,-3 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Metal.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Metal.ocd/DefCore.txt index 78bb365a6..563dca3e6 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Metal.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Metal.ocd/DefCore.txt @@ -14,4 +14,4 @@ Value=8 Mass=12 Components=Ore=1 Rotate=1 -Picture=0,4,13,13 +Picture=0,20,64,64 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Ore.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Ore.ocd/DefCore.txt index d9a70bfa2..b633f1be8 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Ore.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Ore.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=3 VertexX=0,2,-2 VertexY=1,-1,-1 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Snow.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Snow.ocd/DefCore.txt index 41b066e71..74bfa32bb 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Snow.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Snow.ocd/DefCore.txt @@ -7,7 +7,7 @@ TimerCall=Check Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=3 VertexX=0,2,-2 VertexY=1,-1,-1 diff --git a/planet/Objects.ocd/Items.ocd/Resources.ocd/Sulphur.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Resources.ocd/Sulphur.ocd/DefCore.txt index 9400307ba..a86bea810 100644 --- a/planet/Objects.ocd/Items.ocd/Resources.ocd/Sulphur.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Resources.ocd/Sulphur.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=3 VertexX=0,2,-2 VertexY=1,-1,-1 diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/DefCore.txt index 93a879b04..080091f6d 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=3 Height=10 Offset=-2,-5 -Picture=4,0,16,16 +Picture=16,0,64,64 Vertices=3 VertexX=-2,+2,0 VertexY=5,5,-5 diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/DefCore.txt index dec0db45d..78c6724cd 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/JarOfWinds.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=4 VertexX=-1,3,-1,-5 VertexY=-4,0,4,0 VertexFriction=50,50,50,50 -Picture=0,1,9,9 +Picture=0,0,64,64 Value=14 Mass=15 Components=Rock=6;Metal=1; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/BridgePost.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/BridgePost.ocd/DefCore.txt index 927575aae..2514993e5 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/BridgePost.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropebridge.ocd/BridgePost.ocd/DefCore.txt @@ -2,11 +2,11 @@ id=Ropebridge_Post Version=5,2,0,1 Category=C4D_Structure -Picture=20,0,64,64 +Picture=0,0,96,128 Width=12 Height=16 Offset=-6,-10 Vertices=2 VertexY=5,5 VertexX=-2,2 -Rotate=0 \ No newline at end of file +Rotate=0 diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/LadderSegment.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/LadderSegment.ocd/DefCore.txt index d550dccb8..573632662 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/LadderSegment.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Ropeladder.ocd/LadderSegment.ocd/DefCore.txt @@ -8,4 +8,4 @@ Offset=-3,-7 Vertices=2 VertexX=0,0 VertexY=-5,5 -Picture=0,0,36,32 +Picture=0,0,50,80 diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/DefCore.txt index bf60368b6..224c4ab97 100644 --- a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/DefCore.txt @@ -11,6 +11,6 @@ VertexFriction=120,120,120 Value=15 Mass=8 Components=Wood=3 -Picture=4,0,21,21 +Picture=12,0,64,64 Rotate=1 Float=1 diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/HelpArrow.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/HelpArrow.ocd/DefCore.txt index 4dd93ef55..bad195077 100644 --- a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/HelpArrow.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Bow.ocd/Arrow.ocd/HelpArrow.ocd/DefCore.txt @@ -11,6 +11,5 @@ VertexFriction=120,120,120 Value=15 Mass=15 Components=Wood=5 -Picture=4,0,21,21 Rotate=1 Float=1 diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/IronBomb.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/IronBomb.ocd/DefCore.txt index 3b0cc3ebe..e0f3b27bf 100644 --- a/planet/Objects.ocd/Items.ocd/Weapons.ocd/IronBomb.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/IronBomb.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=6 Height=6 Offset=-3,-3 -Picture=6,0,16,16 +Picture=24,0,64,64 Vertices=3 VertexX=0,3,-3 VertexY=-2,2,2 diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Musket.ocd/Ammo.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Musket.ocd/Ammo.ocd/DefCore.txt index 41a808a5b..62ab9f4ea 100644 --- a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Musket.ocd/Ammo.ocd/DefCore.txt +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Musket.ocd/Ammo.ocd/DefCore.txt @@ -9,7 +9,7 @@ Vertices=3 VertexX=0,-3,3 VertexY=0,1,1 VertexFriction=50 -Picture=8,0,8,8 +Picture=64,0,64,64 Value=10 Mass=5 Components=Metal=1;Blackpowder=1; diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Acid.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Acid.ocd/DefCore.txt index d67d1629b..29e6387cf 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Acid.ocd/DefCore.txt +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Acid.ocd/DefCore.txt @@ -2,7 +2,7 @@ id=Icon_Producer_Acid Version=5,2,0,1 Category=C4D_StaticBack -Picture=0,0,64,64 +Picture=0,0,128,128 Width=64 Height=64 Offset=-32,-32 diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Fuel.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Fuel.ocd/DefCore.txt index 32279c9c5..baf8e7e1b 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Fuel.ocd/DefCore.txt +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Fuel.ocd/DefCore.txt @@ -2,7 +2,7 @@ id=Icon_Producer_Fuel Version=5,2,0,1 Category=C4D_StaticBack -Picture=0,0,64,64 +Picture=0,0,128,128 Width=64 Height=64 Offset=-32,-32 diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Lava.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Lava.ocd/DefCore.txt index 68aabfa5a..6a332e978 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Lava.ocd/DefCore.txt +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Lava.ocd/DefCore.txt @@ -2,7 +2,7 @@ id=Icon_Producer_Lava Version=5,2,0,1 Category=C4D_StaticBack -Picture=0,0,64,64 +Picture=0,0,128,128 Width=64 Height=64 Offset=-32,-32 diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Oil.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Oil.ocd/DefCore.txt index 3b2af3cb8..566d23818 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Oil.ocd/DefCore.txt +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Oil.ocd/DefCore.txt @@ -2,7 +2,7 @@ id=Icon_Producer_Oil Version=5,2,0,1 Category=C4D_StaticBack -Picture=0,0,64,64 +Picture=0,0,128,128 Width=64 Height=64 Offset=-32,-32 diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Water.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Water.ocd/DefCore.txt index 2dedbb617..33389158b 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Water.ocd/DefCore.txt +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Icons.ocd/Water.ocd/DefCore.txt @@ -2,7 +2,7 @@ id=Icon_Producer_Water Version=5,2,0,1 Category=C4D_StaticBack -Picture=0,0,64,64 +Picture=0,0,128,128 Width=64 Height=64 Offset=-32,-32 diff --git a/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/DefCore.txt b/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/DefCore.txt index 24949a753..1d232bdb0 100644 --- a/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/DefCore.txt +++ b/planet/Tests.ocf/CableLorrys.ocs/CableCars.ocd/Structures.ocd/Crossing.ocd/DefCore.txt @@ -12,8 +12,8 @@ VertexFriction=50,100,100 Value=40 Mass=5 #Components=Metal=1 -Picture=0,0,20,20 +Picture=0,0,160,160 Exclusive=1 BlastIncinerate=50 Construction=1 -Collection=-10,-10,20,20 \ No newline at end of file +Collection=-10,-10,20,20 diff --git a/planet/Tests.ocf/Experimental.ocd/FireGlobe.ocd/DefCore.txt b/planet/Tests.ocf/Experimental.ocd/FireGlobe.ocd/DefCore.txt index f158d2d63..8f11d69b7 100644 --- a/planet/Tests.ocf/Experimental.ocd/FireGlobe.ocd/DefCore.txt +++ b/planet/Tests.ocf/Experimental.ocd/FireGlobe.ocd/DefCore.txt @@ -7,7 +7,7 @@ Offset=-5,-5 Vertices=1 VertexY=0 VertexFriction=100 -Picture=0,0,10,10 +Picture=0,0,60,60 Value=8 Mass=1 Rotate=1 diff --git a/planet/Tests.ocf/Moss_Test.ocs/Moss.ocd/DefCore.txt b/planet/Tests.ocf/Moss_Test.ocs/Moss.ocd/DefCore.txt index 43ad70ed8..5c819a78a 100644 --- a/planet/Tests.ocf/Moss_Test.ocs/Moss.ocd/DefCore.txt +++ b/planet/Tests.ocf/Moss_Test.ocs/Moss.ocd/DefCore.txt @@ -5,7 +5,7 @@ Category=C4D_Object Width=8 Height=8 Offset=-4,-4 -Picture=0,0,8,8 +Picture=0,0,64,64 Vertices=3 VertexX=0,2,-2 VertexY=1,-1,-1 @@ -18,4 +18,4 @@ ContactIncinerate=1 BlastIncinerate=1 Rotate=1 Float=1 -Collectible=1 \ No newline at end of file +Collectible=1 diff --git a/src/game/object/C4Def.cpp b/src/game/object/C4Def.cpp index 3694eaa22..f7af88984 100644 --- a/src/game/object/C4Def.cpp +++ b/src/game/object/C4Def.cpp @@ -117,10 +117,6 @@ bool C4Def::LoadDefCore(C4Group &hGroup) hGroup.Rename(C4CFN_DefCore, C4CFN_DefCore ".old"); Save(hGroup);*/ - // Adjust picture rect - if ((PictureRect.Wdt==0) || (PictureRect.Hgt==0)) - PictureRect.Set(0,0,Shape.Wdt,Shape.Hgt); - // Check category if (!GetPlane() && Category & (C4D_SortLimit | C4D_BackgroundOrForeground)) { @@ -510,6 +506,10 @@ bool C4Def::Load(C4Group &hGroup, MainFace.Set(NULL,0,0,Shape.Wdt,Shape.Hgt); } + // Adjust picture rect + if ((PictureRect.Wdt==0) || (PictureRect.Hgt==0)) + PictureRect.Set(0,0,Shape.Wdt*Graphics.Bmp.Bitmap->Scale, Shape.Hgt*Graphics.Bmp.Bitmap->Scale); + // validate TopFace if (TopFace.x<0 || TopFace.y<0 || TopFace.x+TopFace.Wdt>Graphics.Bmp.Bitmap->Wdt || TopFace.y+TopFace.Hgt>Graphics.Bmp.Bitmap->Hgt) { @@ -521,6 +521,7 @@ bool C4Def::Load(C4Group &hGroup, else { TopFace.Default(); + PictureRect.Default(); SolidMask.Default(); } @@ -552,7 +553,7 @@ void C4Def::Draw(C4Facet &cgo, bool fSelected, DWORD iColor, C4Object *pObj, int { case C4DefGraphics::TYPE_Bitmap: fctPicture.Set(graphics->GetBitmap(iColor),fctPicRect.x,fctPicRect.y,fctPicRect.Wdt,fctPicRect.Hgt); - fctPicture.DrawT(cgo,true,iPhaseX,iPhaseY,trans); + fctPicture.DrawTUnscaled(cgo,true,iPhaseX,iPhaseY,trans); break; case C4DefGraphics::TYPE_Mesh: // TODO: Allow rendering of a mesh directly, without instance (to render pose; no animation) diff --git a/src/lib/texture/C4Facet.cpp b/src/lib/texture/C4Facet.cpp index 540d94551..fa12e9a98 100644 --- a/src/lib/texture/C4Facet.cpp +++ b/src/lib/texture/C4Facet.cpp @@ -117,6 +117,45 @@ void C4Facet::DrawT(C4Facet &cgo, bool fAspect, int32_t iPhaseX, int32_t iPhaseY true,pTransform); } +void C4Facet::DrawTUnscaled(C4Surface * sfcTarget, float iX, float iY, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform) +{ + if (!pDraw || !Surface || !sfcTarget || !Wdt || !Hgt) return; + + pDraw->BlitUnscaled(Surface, + float(X+Wdt*iPhaseX),float(Y+Hgt*iPhaseY),float(Wdt),float(Hgt), + sfcTarget, + iX,iY,Wdt,Hgt,true,pTransform); +} + +void C4Facet::DrawTUnscaled(C4Facet &cgo, bool fAspect, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform) +{ + if (!pDraw || !Surface || !cgo.Surface || !Wdt || !Hgt) return; + + // Drawing area + C4Facet ccgo = cgo; + // Adjust for fixed aspect ratio + if (fAspect) + { + // By height + if (100*cgo.Wdt/Wdt<100*cgo.Hgt/Hgt) + { + ccgo.Hgt=Hgt*cgo.Wdt/Wdt; + ccgo.Y+=(cgo.Hgt-ccgo.Hgt)/2; + } + // By width + else if (100*cgo.Hgt/Hgt<100*cgo.Wdt/Wdt) + { + ccgo.Wdt=Wdt*cgo.Hgt/Hgt; + ccgo.X+=(cgo.Wdt-ccgo.Wdt)/2; + } + } + + pDraw->BlitUnscaled(Surface, + float(X+Wdt*iPhaseX),float(Y+Hgt*iPhaseY),float(Wdt),float(Hgt), + ccgo.Surface,ccgo.X,ccgo.Y,ccgo.Wdt,ccgo.Hgt, + true,pTransform); +} + void C4Facet::Draw(C4Facet &cgo, bool fAspect, int32_t iPhaseX, int32_t iPhaseY, bool fTransparent) { // Valid parameter check diff --git a/src/lib/texture/C4Facet.h b/src/lib/texture/C4Facet.h index 6e7bb1b35..fc45f08af 100644 --- a/src/lib/texture/C4Facet.h +++ b/src/lib/texture/C4Facet.h @@ -142,6 +142,8 @@ public: void DrawFullScreen(C4Facet &cgo); void DrawT(C4Surface * sfcTarget, float iX, float iY, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform); // draw with transformation (if pTransform is assigned) void DrawT(C4Facet &cgo, bool fAspect, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform); + void DrawTUnscaled(C4Surface * sfcTarget, float iX, float iY, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform); // interpret source coordinates as unscaled + void DrawTUnscaled(C4Facet &cgo, bool fAspect, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform); void DrawXT(C4Surface * sfcTarget, float iX, float iY, int32_t iWdt, int32_t iHgt, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform); void DrawClr(C4Facet &cgo, bool fAspect=true, DWORD dwClr=0); // set surface color and draw void DrawXClr(C4Surface * sfcTarget, int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, DWORD dwClr); // set surface color and draw diff --git a/src/platform/StdDDraw2.cpp b/src/platform/StdDDraw2.cpp index aaa08bae4..a09f60afb 100644 --- a/src/platform/StdDDraw2.cpp +++ b/src/platform/StdDDraw2.cpp @@ -503,6 +503,14 @@ void C4Draw::Blit8Fast(CSurface8 * sfcSource, int fx, int fy, bool C4Draw::Blit(C4Surface * sfcSource, float fx, float fy, float fwdt, float fhgt, C4Surface * sfcTarget, float tx, float ty, float twdt, float thgt, bool fSrcColKey, const C4BltTransform *pTransform) +{ + return BlitUnscaled(sfcSource, fx * sfcSource->Scale, fy * sfcSource->Scale, fwdt * sfcSource->Scale, fhgt * sfcSource->Scale, + sfcTarget, tx, ty, twdt, thgt, fSrcColKey, pTransform); +} + +bool C4Draw::BlitUnscaled(C4Surface * sfcSource, float fx, float fy, float fwdt, float fhgt, + C4Surface * sfcTarget, float tx, float ty, float twdt, float thgt, + bool fSrcColKey, const C4BltTransform *pTransform) { // safety if (!sfcSource || !sfcTarget || !twdt || !thgt || !fwdt || !fhgt) return false; @@ -524,10 +532,6 @@ bool C4Draw::Blit(C4Surface * sfcSource, float fx, float fy, float fwdt, float f twdt *= Zoom; thgt *= Zoom; } - fx *= sfcSource->Scale; - fy *= sfcSource->Scale; - fwdt *= sfcSource->Scale; - fhgt *= sfcSource->Scale; // emulated blit? if (!sfcTarget->IsRenderTarget()) return Blit8(sfcSource, int(fx), int(fy), int(fwdt), int(fhgt), sfcTarget, int(tx), int(ty), int(twdt), int(thgt), fSrcColKey, pTransform); diff --git a/src/platform/StdDDraw2.h b/src/platform/StdDDraw2.h index aed6d8ab3..c5f7e28f8 100644 --- a/src/platform/StdDDraw2.h +++ b/src/platform/StdDDraw2.h @@ -243,6 +243,9 @@ public: bool Blit(C4Surface * sfcSource, float fx, float fy, float fwdt, float fhgt, C4Surface * sfcTarget, float tx, float ty, float twdt, float thgt, bool fSrcColKey=false, const C4BltTransform *pTransform=NULL); + bool BlitUnscaled(C4Surface * sfcSource, float fx, float fy, float fwdt, float fhgt, + C4Surface * sfcTarget, float tx, float ty, float twdt, float thgt, + bool fSrcColKey=false, const C4BltTransform *pTransform=NULL); bool RenderMesh(StdMeshInstance &instance, C4Surface * sfcTarget, float tx, float ty, float twdt, float thgt, DWORD dwPlayerColor, C4BltTransform* pTransform); // Call PrepareMaterial with Mesh's material before virtual void PerformBlt(C4BltData &rBltData, C4TexRef *pTex, DWORD dwModClr, bool fMod2, bool fExact) = 0; virtual void PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, DWORD dwPlayerColor, C4BltTransform* pTransform) = 0; From 4169a9232c04c308d4ea91ac10532695002e15e5 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sat, 25 Feb 2012 21:57:39 +0100 Subject: [PATCH 41/70] swapped parameters of GetIndexOf --- planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c | 6 +++--- src/script/C4Script.cpp | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c index 2f2b2f9c0..32d0955a5 100644 --- a/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Flag.ocd/Script.c @@ -171,7 +171,7 @@ func RefreshOwnershipOfSurrounding() } public func Initialize() { - if(GetIndexOf(this, LibraryFlag_flag_list) == -1) + if(GetIndexOf(LibraryFlag_flag_list, this) == -1) LibraryFlag_flag_list[GetLength(LibraryFlag_flag_list)] = this; // redraw @@ -264,7 +264,7 @@ func RefreshLinkedFlags() for(var flag in LibraryFlag_flag_list) { if(!IsAllied(flag->GetOwner(), owner)) continue; - if(GetIndexOf(flag, current) != -1) continue; + if(GetIndexOf(current, flag) != -1) continue; if(flag == this) continue; if(ObjectDistance(oldflag, flag) > oldflag->GetFlagRadius() + flag->GetFlagRadius()) continue; @@ -293,7 +293,7 @@ func RefreshLinkedFlags() { other->CopyLinkedFlags(this, lflag.linked_flags); - if(GetIndexOf(other.lflag.power_helper, to_merge) == -1) + if(GetIndexOf(to_merge, other.lflag.power_helper) == -1) to_merge[GetLength(to_merge)] = other.lflag.power_helper; other.lflag.power_helper = lflag.power_helper; } diff --git a/src/script/C4Script.cpp b/src/script/C4Script.cpp index c1e2638ea..404ff6b3d 100644 --- a/src/script/C4Script.cpp +++ b/src/script/C4Script.cpp @@ -380,15 +380,15 @@ static C4Value FnGetLength(C4AulContext *cthr, C4Value *pPars) static C4Value FnGetIndexOf(C4AulContext *cthr, C4Value *pPars) { // find first occurance of first parameter in array - // support GetIndexOf(x, 0) - if (!pPars[1]) return C4VInt(-1); - // if the second param is nonzero, it must be an array - const C4ValueArray * pArray = pPars[1].getArray(); + // support GetIndexOf(0, x) + if (!pPars[0]) return C4VInt(-1); + // if the first param is nonzero, it must be an array + const C4ValueArray * pArray = pPars[0].getArray(); if (!pArray) - throw new C4AulExecError(cthr->Obj, "func \"GetIndexOf\" par 1 cannot be converted to array"); + throw new C4AulExecError(cthr->Obj, "func \"GetIndexOf\" par 0 cannot be converted to array"); int32_t iSize = pArray->GetSize(); for (int32_t i = 0; iGetItem(i)) + if (pPars[1] == pArray->GetItem(i)) // element found return C4VInt(i); // element not found @@ -629,7 +629,7 @@ C4ScriptFnDef C4ScriptFnMap[]= { "GetType", 1 ,C4V_Int ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetType, 0 }, { "GetLength", 1 ,C4V_Int ,{ C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetLength }, - { "GetIndexOf", 1 ,C4V_Int ,{ C4V_Any ,C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetIndexOf }, + { "GetIndexOf", 1 ,C4V_Int ,{ C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0, FnGetIndexOf }, { "eval", 1 ,C4V_Any ,{ C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEval, 0 }, From e0fa05418ce89fbc17b8c43de5daf0ddf95b84c9 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sat, 25 Feb 2012 21:58:05 +0100 Subject: [PATCH 42/70] added more array helper functions --- .../ContentsMenuController.ocd/Script.c | 3 +- planet/System.ocg/Array.c | 146 +++++++++++++++++- 2 files changed, 141 insertions(+), 8 deletions(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c index dbfeff90d..d179abd28 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c @@ -386,7 +386,8 @@ private func UpdateAfterTakenObjects(proplist p_source, object menuItem) // otherwise, update // repair "holes" - var remaining_objects = RemoveHoles(objects); + var remaining_objects = objects[:]; + RemoveHoles(remaining_objects); //Log("%v",remaining_objects); menuItem->SetData(remaining_objects); diff --git a/planet/System.ocg/Array.c b/planet/System.ocg/Array.c index 4b03abf4e..24384e187 100644 --- a/planet/System.ocg/Array.c +++ b/planet/System.ocg/Array.c @@ -1,5 +1,6 @@ /* Global Array helper functions */ +// concatenates two arrays and returns a new array global func Concatenate(array first, array second) { var result = CreateArray(GetLength(first)+GetLength(second)); @@ -11,6 +12,7 @@ global func Concatenate(array first, array second) return result; } +// returns a new array that contains the values of the first array minus the values of the second array global func Subtract(array subject, array subtract) { var diff = []; @@ -31,13 +33,143 @@ global func Subtract(array subject, array subtract) return diff; } +// removes nil values from an array, returns the amount of values removed global func RemoveHoles(array leerdammer) { - // gouda is a cheese with no holes ;-) - var gouda = []; - var hole = nil; - for (var piece in leerdammer) - if (piece != hole) - gouda[GetLength(gouda)] = piece; - return gouda; + var move = 0; + var len = GetLength(leerdammer); + for(var i = 0; i < len; ++i) + { + if(leerdammer[i] == nil) + { + ++move; + continue; + } + leerdammer[i - move] = leerdammer[i]; + } + SetLength(leerdammer, len - move); + // assert IsGouda(leerdammer) + return move; +} + +// removes duplicate entries - returns the number of entries removed +global func RemoveDuplicates(array arr) +{ + var working = []; + var cnt = 0; + + var len = GetLength(arr); + for(var i = 0; i < len; ++i) + { + if(IsValueInArray(working, arr[i])) + { + ++cnt; + continue; + } + working[GetLength(working)] = arr[i]; + } + SetLength(arr, GetLength(working)); + for(var i = GetLength(working); --i >= 0;) + arr[i] = working[i]; + return cnt; +} + + + +// tests whether a value is in an array +global func IsValueInArray(array arr, /*any*/ value) +{ + return GetIndexOf(arr, value) != -1; +} + +// removes a value from an array +global func RemoveArrayValue(array arr, /*any*/ value, bool unstable) +{ + var i = GetIndexOf(arr, value); + if(i == -1) + return false; + if(unstable == true) + return RemoveArrayIndexUnstable(arr, i); + else return RemoveArrayIndex(arr, i); +} + + +// randomly shuffles an array +global func ShuffleArray(array arr) +{ + var len = GetLength(arr); + var working = arr[:]; + + while(--len >= 0) + { + var i = Random(GetLength(working)); + arr[len] = working[i]; + RemoveArrayIndexUnstable(working, i); + } + + return true; +} + +//deletes an index from an array, does not change the order of items in the array +global func RemoveArrayIndex(array arr, int index, bool unstable) +{ + if(unstable == true) + return RemoveArrayIndexUnstable(arr, index); + // move all elements right of index to the left + var len = GetLength(arr); + for(var i = index; i < len - 1; ++i) + arr[i] = arr[i+1]; + SetLength(arr, GetLength(arr) - 1); + return true; +} + +// deletes an array item - might change the order of elements, but is faster +global func RemoveArrayIndexUnstable(array arr, int index) +{ + arr[index] = arr[-1]; + SetLength(arr, GetLength(arr) - 1); + return true; +} + +//inserts an element at the end of an array +global func PushBack(array arr, /*any*/ value) +{ + arr[GetLength(arr)] = value; + return true; +} + +// inserts an element at the beginning of an array +global func PushFront(array arr, /*any*/ value) +{ + SetLength(arr, GetLength(arr) + 1); + + // move elements one to the right + for(var i = GetLength(arr)-1; i > 0;--i) + arr[i] = arr[i-1]; + arr[0] = value; + return true; +} + +// removes the last element from an array and returns it +global func PopBack(array arr) +{ + if(GetLength(arr) == 0) + return nil; + var o = arr[-1]; + SetLength(arr, GetLength(arr) - 1); + return o; +} + +// removes the first element from an array and returns it +// obviously a bit slower than PopBack +global func PopFront(array arr) +{ + var len = GetLength(arr); + if(len == 0) + return nil; + var o = arr[0]; + for(var i = 1; i < len; ++i) + arr[i - 1] = arr[i]; + SetLength(arr, GetLength(arr) - 1); + return o; } \ No newline at end of file From 7f5b7bcdd6db1bd4fbafdcf14b84cc8c7ce8bec2 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 25 Feb 2012 21:56:11 +0100 Subject: [PATCH 43/70] Make a MouseHover callback when the object being hovered by the mouse changes --- src/game/script/C4Script.h | 1 + src/gui/C4MouseControl.cpp | 149 ++++++++++++++++++++----------------- 2 files changed, 83 insertions(+), 67 deletions(-) diff --git a/src/game/script/C4Script.h b/src/game/script/C4Script.h index 3d727af5b..00ae3bd6a 100644 --- a/src/game/script/C4Script.h +++ b/src/game/script/C4Script.h @@ -150,6 +150,7 @@ bool C4ValueToMatrix(const C4ValueArray& array, StdMeshMatrix* matrix); #define PSF_MouseSelection "~MouseSelection" // int iByPlr #define PSF_MouseSelectionAlt "~MouseSelectionAlt" // int iByPlr #define PSF_MouseDragDrop "~MouseDragDrop" // int iPlr, C4Object *source, C4Object *target +#define PSF_MouseHover "~MouseHover" // int iPlr, C4Object* old, C4Object* new, C4Object* drag // Proplist diff --git a/src/gui/C4MouseControl.cpp b/src/gui/C4MouseControl.cpp index f3b2d2c19..1dcb10b13 100644 --- a/src/gui/C4MouseControl.cpp +++ b/src/gui/C4MouseControl.cpp @@ -575,80 +575,95 @@ void C4MouseControl::UpdateCursorTarget() { int32_t iLastCursor = Cursor; - // Scrolling: no other target - if (Scrolling) { TargetObject=NULL; return; } + C4Object* OldTargetObject = TargetObject; - // On target region - if (TargetRegion) + if (Scrolling) { + // Scrolling: no other target + TargetObject=NULL; + } + else if(TargetRegion) + { + // On target region TargetObject=NULL; if (Help) Cursor=C4MC_Cursor_Help; - return; - } - - // Target object - TargetObject=GetTargetObject(); - if (TargetObject && FogOfWar && !(TargetObject->Category & C4D_IgnoreFoW)) TargetObject = NULL; - - // Movement - if (!FogOfWar && !IsPassive()) Cursor=C4MC_Cursor_Crosshair; - - // Target action - if (TargetObject && !IsPassive()) - { - // default cursor for object; also set if not in FoW - Cursor=C4MC_Cursor_Crosshair; - - // select custom region. Can select an object if it does not have the MD_NoClick - // flag set. If we are currently dragging then selection depends on it being a drop target. - bool CanSelect; - if(Drag == C4MC_Drag_Script) - CanSelect = (TargetObject->GetPropertyInt(P_MouseDrag) & C4MC_MD_DropTarget) != 0; - else - CanSelect = (TargetObject->GetPropertyInt(P_MouseDrag) & C4MC_MD_NoClick) == 0; - - if ( (TargetObject->Category & C4D_MouseSelect) && CanSelect) - Cursor=C4MC_Cursor_Select; - else - TargetObject = NULL; - } - - // Help - if (Help) - Cursor=C4MC_Cursor_Help; - // passive cursor - else if (IsPassive()) - Cursor=C4MC_Cursor_Region; - - // Time on target: caption - if (Cursor==iLastCursor) - { - TimeOnTargetObject++; - if (TimeOnTargetObject>=C4MC_Time_on_Target) - { - const char* idCaption = 0; - const char *szName = ""; - bool fDouble = false; - if (TargetObject) szName=TargetObject->GetName(); - // Target caption by cursor - switch (Cursor) - { - case C4MC_Cursor_Select: idCaption="IDS_CON_SELECT"; break; - case C4MC_Cursor_Help: idCaption="IDS_CON_NAME"; break; - } - // Set caption - if (idCaption) if (!KeepCaption) - { - // Caption by cursor - Caption.Format(LoadResStr(idCaption), szName); - if (fDouble) { Caption.AppendChar('|'); Caption.Append(LoadResStr("IDS_CON_DOUBLECLICK")); } - IsHelpCaption = false; - } - } } else - TimeOnTargetObject=0; + { + // Target object + TargetObject=GetTargetObject(); + if (TargetObject && FogOfWar && !(TargetObject->Category & C4D_IgnoreFoW)) TargetObject = NULL; + // Movement + if (!FogOfWar && !IsPassive()) Cursor=C4MC_Cursor_Crosshair; + + // Target action + if (TargetObject && !IsPassive()) + { + // default cursor for object; also set if not in FoW + Cursor=C4MC_Cursor_Crosshair; + + // select custom region. Can select an object if it does not have the MD_NoClick + // flag set. If we are currently dragging then selection depends on it being a drop target. + bool CanSelect; + if(Drag == C4MC_Drag_Script) + CanSelect = (TargetObject->GetPropertyInt(P_MouseDrag) & C4MC_MD_DropTarget) != 0; + else + CanSelect = (TargetObject->GetPropertyInt(P_MouseDrag) & C4MC_MD_NoClick) == 0; + + if ( (TargetObject->Category & C4D_MouseSelect) && CanSelect) + Cursor=C4MC_Cursor_Select; + else + TargetObject = NULL; + } + + // Help + if (Help) + Cursor=C4MC_Cursor_Help; + // passive cursor + else if (IsPassive()) + Cursor=C4MC_Cursor_Region; + + // Time on target: caption + if (Cursor==iLastCursor) + { + TimeOnTargetObject++; + if (TimeOnTargetObject>=C4MC_Time_on_Target) + { + const char* idCaption = 0; + const char *szName = ""; + bool fDouble = false; + if (TargetObject) szName=TargetObject->GetName(); + // Target caption by cursor + switch (Cursor) + { + case C4MC_Cursor_Select: idCaption="IDS_CON_SELECT"; break; + case C4MC_Cursor_Help: idCaption="IDS_CON_NAME"; break; + } + // Set caption + if (idCaption) if (!KeepCaption) + { + // Caption by cursor + Caption.Format(LoadResStr(idCaption), szName); + if (fDouble) { Caption.AppendChar('|'); Caption.Append(LoadResStr("IDS_CON_DOUBLECLICK")); } + IsHelpCaption = false; + } + } + } + else + TimeOnTargetObject=0; + } + + // Make a script callback if the object being hovered changes + if(OldTargetObject != TargetObject) + { + // TODO: This might put a heavy load on the network, depending on the number of + // selectable objects around. If it turns out to be a problem we might want to + // deduce these hover callbacks client-side instead. + // Or, make sure to send this at most once per control frame. + Game.Input.Add(CID_Script, new C4ControlScript( + FormatString("%s(%d,Object(%d),Object(%d),Object(%d))", PSF_MouseHover, (int)Player, OldTargetObject ? (int)(OldTargetObject->Number) : 0, TargetObject ? (int)(TargetObject->Number) : 0, DragObject ? (int)(DragObject->Number) : 0).getData())); + } } int32_t C4MouseControl::UpdateSingleSelection() From 09e0e482908af711207f6c05ffe4cc1eea33931b Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 25 Feb 2012 22:05:47 +0100 Subject: [PATCH 44/70] When starting to drag an object, use the object at mouse down time and not at the time the drag is started, which is a bit later, after the mouse has been moved a few pixels in order. This makes it easier to start dragging when hitting the drag object on an edge. --- src/gui/C4MouseControl.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gui/C4MouseControl.cpp b/src/gui/C4MouseControl.cpp index 1dcb10b13..277abf0d6 100644 --- a/src/gui/C4MouseControl.cpp +++ b/src/gui/C4MouseControl.cpp @@ -785,6 +785,7 @@ void C4MouseControl::LeftUp() { // Update status flag LeftButtonDown=false; + if(!RightButtonDown) DownTarget = NULL; // Ignore left up after double click if (LeftDoubleIgnoreUp) { LeftDoubleIgnoreUp=false; return; } // Evaluate by drag status @@ -857,21 +858,20 @@ void C4MouseControl::DragNone() break; } // check if target object allows scripted dragging - if (fAllowDrag && TargetObject) + if (fAllowDrag && DownTarget) { C4Object *drag_image_obj; C4ID drag_image_id; // Drag only if MD_SOURCE is set and drag image is present - if ( (TargetObject->GetPropertyInt(P_MouseDrag) & C4MC_MD_DragSource) && - TargetObject->GetDragImage(&drag_image_obj, &drag_image_id)) - //if (TargetObject->GetDragImage(&drag_image_obj, &drag_image_id)) + if ( (DownTarget->GetPropertyInt(P_MouseDrag) & C4MC_MD_DragSource) && + DownTarget->GetDragImage(&drag_image_obj, &drag_image_id)) { Drag=C4MC_Drag_Script; if(drag_image_obj) DragImageObject = drag_image_obj; else DragImageDef = C4Id2Def(drag_image_id); - DragObject = TargetObject; + DragObject = DownTarget; } } @@ -921,6 +921,8 @@ void C4MouseControl::RightUp() { // Update status flag RightButtonDown=false; + if(!LeftButtonDown) DownTarget = NULL; + // Evaluate by drag status switch (Drag) { From 8f7f5cc1f1e55c87bbebe34c9ad4f32bacd846a4 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 25 Feb 2012 22:15:39 +0100 Subject: [PATCH 45/70] Allow dragging of objects from FoW if they have C4D_IgnoreFoW set (#720) --- src/gui/C4MouseControl.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/C4MouseControl.cpp b/src/gui/C4MouseControl.cpp index 277abf0d6..9eaef1e51 100644 --- a/src/gui/C4MouseControl.cpp +++ b/src/gui/C4MouseControl.cpp @@ -840,8 +840,6 @@ void C4MouseControl::DragNone() if ( (LeftButtonDown || RightButtonDown) && ((Abs(GameX-DownX)>C4MC_DragSensitivity) || (Abs(GameY-DownY)>C4MC_DragSensitivity)) ) { - // don't begin dragging from FoW; unless it's a menu - if (FogOfWar && DownCursor != C4MC_Cursor_Region) return; bool fAllowDrag = true; switch (DownCursor) { @@ -858,7 +856,7 @@ void C4MouseControl::DragNone() break; } // check if target object allows scripted dragging - if (fAllowDrag && DownTarget) + if (fAllowDrag && DownTarget && (!FogOfWar || (DownTarget->Category & C4D_IgnoreFoW))) { C4Object *drag_image_obj; C4ID drag_image_id; From de677690658a0b4f52dc5ab15e5928d1310ebe42 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 26 Feb 2012 01:01:55 +0100 Subject: [PATCH 46/70] Fix crash when C4Draw::Blit was called with NULL source surface (#721) --- src/game/object/C4Object.cpp | 61 +++++++++++++++++++----------------- src/platform/StdFont.cpp | 1 + 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/game/object/C4Object.cpp b/src/game/object/C4Object.cpp index 2f9856fed..30b06950f 100644 --- a/src/game/object/C4Object.cpp +++ b/src/game/object/C4Object.cpp @@ -2247,37 +2247,40 @@ void C4Object::DrawTopFace(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDraw offX + Shape.GetX(), offY + Shape.GetY() + Shape.Hgt - fctConSign.Hgt, fctConSign.Wdt, fctConSign.Hgt, true); } - // FacetTopFace: Override TopFace.GetX()/GetY() - C4PropList* pActionDef = GetAction(); - if (pActionDef && pActionDef->GetPropertyInt(P_FacetTopFace)) + if(TopFace.Surface) { - int32_t iPhase = Action.Phase; - if (pActionDef->GetPropertyInt(P_Reverse)) iPhase = pActionDef->GetPropertyInt(P_Length) - 1 - Action.Phase; - TopFace.X = pActionDef->GetPropertyInt(P_X) + Def->TopFace.x + pActionDef->GetPropertyInt(P_Wdt) * iPhase; - TopFace.Y = pActionDef->GetPropertyInt(P_Y) + Def->TopFace.y + pActionDef->GetPropertyInt(P_Hgt) * Action.DrawDir; + // FacetTopFace: Override TopFace.GetX()/GetY() + C4PropList* pActionDef = GetAction(); + if (pActionDef && pActionDef->GetPropertyInt(P_FacetTopFace)) + { + int32_t iPhase = Action.Phase; + if (pActionDef->GetPropertyInt(P_Reverse)) iPhase = pActionDef->GetPropertyInt(P_Length) - 1 - Action.Phase; + TopFace.X = pActionDef->GetPropertyInt(P_X) + Def->TopFace.x + pActionDef->GetPropertyInt(P_Wdt) * iPhase; + TopFace.Y = pActionDef->GetPropertyInt(P_Y) + Def->TopFace.y + pActionDef->GetPropertyInt(P_Hgt) * Action.DrawDir; + } + // ensure correct color is set + if (GetGraphics()->Bmp.BitmapClr) GetGraphics()->Bmp.BitmapClr->SetClr(Color); + // color modulation + if (!eDrawMode) PrepareDrawing(); + // Draw top face bitmap + if (Con!=FullCon && Def->GrowthType) + // stretched + pDraw->Blit(TopFace.Surface, + TopFace.X, TopFace.Y, TopFace.Wdt, TopFace.Hgt, + cgo.Surface, + offX + Shape.GetX() + float(Def->TopFace.tx * Con) / FullCon, offY + Shape.GetY() + float(Def->TopFace.ty * Con) / FullCon, + float(TopFace.Wdt * Con) / FullCon, float(TopFace.Hgt * Con) / FullCon, + true, pDrawTransform ? &C4DrawTransform(*pDrawTransform, offX, offY) : NULL); + else + // normal + pDraw->Blit(TopFace.Surface, + TopFace.X,TopFace.Y, + TopFace.Wdt,TopFace.Hgt, + cgo.Surface, + offX + Shape.GetX() + Def->TopFace.tx, offY + Shape.GetY() + Def->TopFace.ty, + TopFace.Wdt, TopFace.Hgt, + true, pDrawTransform ? &C4DrawTransform(*pDrawTransform, offX, offY) : NULL); } - // ensure correct color is set - if (GetGraphics()->Bmp.BitmapClr) GetGraphics()->Bmp.BitmapClr->SetClr(Color); - // color modulation - if (!eDrawMode) PrepareDrawing(); - // Draw top face bitmap - if (Con!=FullCon && Def->GrowthType) - // stretched - pDraw->Blit(TopFace.Surface, - TopFace.X, TopFace.Y, TopFace.Wdt, TopFace.Hgt, - cgo.Surface, - offX + Shape.GetX() + float(Def->TopFace.tx * Con) / FullCon, offY + Shape.GetY() + float(Def->TopFace.ty * Con) / FullCon, - float(TopFace.Wdt * Con) / FullCon, float(TopFace.Hgt * Con) / FullCon, - true, pDrawTransform ? &C4DrawTransform(*pDrawTransform, offX, offY) : NULL); - else - // normal - pDraw->Blit(TopFace.Surface, - TopFace.X,TopFace.Y, - TopFace.Wdt,TopFace.Hgt, - cgo.Surface, - offX + Shape.GetX() + Def->TopFace.tx, offY + Shape.GetY() + Def->TopFace.ty, - TopFace.Wdt, TopFace.Hgt, - true, pDrawTransform ? &C4DrawTransform(*pDrawTransform, offX, offY) : NULL); // end of color modulation if (!eDrawMode) FinishedDrawing(); } diff --git a/src/platform/StdFont.cpp b/src/platform/StdFont.cpp index 9d17987eb..64da6e9bd 100644 --- a/src/platform/StdFont.cpp +++ b/src/platform/StdFont.cpp @@ -865,6 +865,7 @@ void CStdFont::DrawText(C4Surface * sfcDest, float iX, float iY, DWORD dwColor, // regular char // get texture coordinates fctFromBlt = GetCharacterFacet(c); + if(!fctFromBlt.Surface) continue; w2=int(fctFromBlt.Wdt*fZoom); h2=int(fctFromBlt.Hgt*fZoom); pDraw->ActivateBlitModulation(dwColor); } From 7f5f916e762576b03fd82770048d337a1bd749ac Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 26 Feb 2012 01:09:42 +0100 Subject: [PATCH 47/70] Draw only partial set of faces for buildings in construction --- src/game/object/C4Def.cpp | 2 +- src/game/object/C4DefGraphics.cpp | 4 +-- src/game/object/C4Object.cpp | 10 +++--- src/lib/StdMesh.cpp | 59 ++++++++++++++++++++++++------- src/lib/StdMesh.h | 17 ++++++--- src/lib/StdMeshUpdate.cpp | 2 +- src/platform/StdGL.cpp | 31 ++++++++++------ 7 files changed, 88 insertions(+), 37 deletions(-) diff --git a/src/game/object/C4Def.cpp b/src/game/object/C4Def.cpp index f7af88984..b0547478b 100644 --- a/src/game/object/C4Def.cpp +++ b/src/game/object/C4Def.cpp @@ -568,7 +568,7 @@ void C4Def::Draw(C4Facet &cgo, bool fSelected, DWORD iColor, C4Object *pObj, int } else { - dummy.reset(new StdMeshInstance(*graphics->Mesh)); + dummy.reset(new StdMeshInstance(*graphics->Mesh, 1.0f)); instance = dummy.get(); GetProperty(P_PictureTransformation, &value); } diff --git a/src/game/object/C4DefGraphics.cpp b/src/game/object/C4DefGraphics.cpp index 0c7bd6d69..431345507 100644 --- a/src/game/object/C4DefGraphics.cpp +++ b/src/game/object/C4DefGraphics.cpp @@ -595,7 +595,7 @@ void C4GraphicsOverlay::UpdateFacet() if (pSourceGfx->Type == C4DefGraphics::TYPE_Bitmap) fctBlit.Set(pSourceGfx->GetBitmap(), 0, 0, pDef->Shape.Wdt, pDef->Shape.Hgt, pDef->Shape.x+pDef->Shape.Wdt/2, pDef->Shape.y+pDef->Shape.Hgt/2); else - pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh); + pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh, 1.0f); break; case MODE_Action: // graphics of specified action @@ -630,7 +630,7 @@ void C4GraphicsOverlay::UpdateFacet() C4String* AnimationName = action->GetPropertyStr(P_Animation); if (!AnimationName) return; - pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh); + pMeshInstance = new StdMeshInstance(*pSourceGfx->Mesh, 1.0f); const StdMeshAnimation* Animation = pSourceGfx->Mesh->GetAnimationByName(AnimationName->GetData()); if (!Animation) return; diff --git a/src/game/object/C4Object.cpp b/src/game/object/C4Object.cpp index 30b06950f..0fa7ee87d 100644 --- a/src/game/object/C4Object.cpp +++ b/src/game/object/C4Object.cpp @@ -249,7 +249,7 @@ bool C4Object::Init(C4PropList *pDef, C4Object *pCreator, pGraphics = &Def->Graphics; if (pGraphics->Type == C4DefGraphics::TYPE_Mesh) { - pMeshInstance = new StdMeshInstance(*pGraphics->Mesh); + pMeshInstance = new StdMeshInstance(*pGraphics->Mesh, Def->GrowthType ? 1.0f : static_cast(Con)/static_cast(FullCon)); pMeshInstance->SetFaceOrderingForClrModulation(ColorMod); } else @@ -487,7 +487,7 @@ void C4Object::UpdateGraphics(bool fGraphicsChanged, bool fTemp) delete pMeshInstance; if (pGraphics->Type == C4DefGraphics::TYPE_Mesh) { - pMeshInstance = new StdMeshInstance(*pGraphics->Mesh); + pMeshInstance = new StdMeshInstance(*pGraphics->Mesh, Def->GrowthType ? 1.0f : static_cast(Con)/static_cast(FullCon)); pMeshInstance->SetFaceOrderingForClrModulation(ColorMod); } else @@ -1333,7 +1333,9 @@ void C4Object::DoCon(int32_t iChange) // Con Zero Removal if (Con<=0) AssignRemoval(); - + // Mesh Graphics Update + else if(pMeshInstance) + pMeshInstance->SetCompletion(Def->GrowthType ? 1.0f : static_cast(Con)/static_cast(FullCon)); } void C4Object::DoExperience(int32_t change) @@ -2384,7 +2386,7 @@ void C4Object::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers) if(pComp->isCompiler()) { assert(!pMeshInstance); - pMeshInstance = new StdMeshInstance(*pGraphics->Mesh); + pMeshInstance = new StdMeshInstance(*pGraphics->Mesh, Def->GrowthType ? 1.0f : static_cast(Con)/static_cast(FullCon)); } pComp->Value(mkNamingAdapt(mkParAdapt(*pMeshInstance, C4MeshDenumeratorFactory), "Mesh")); diff --git a/src/lib/StdMesh.cpp b/src/lib/StdMesh.cpp index 8a23d28c4..9cf7663e4 100644 --- a/src/lib/StdMesh.cpp +++ b/src/lib/StdMesh.cpp @@ -45,12 +45,13 @@ namespace // Helper to sort faces for FaceOrdering struct StdMeshInstanceFaceOrderingCmpPred { - const StdSubMeshInstance& m_inst; const StdMeshVertex* m_vertices; + StdSubMeshInstance::FaceOrdering m_face_ordering; const StdMeshMatrix& m_global_trans; - StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& mesh_inst, const StdSubMeshInstance& sub_inst, const StdMeshMatrix& global_trans): - m_inst(sub_inst), m_global_trans(global_trans) + StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& mesh_inst, const StdSubMeshInstance& sub_inst, + StdSubMeshInstance::FaceOrdering face_ordering, const StdMeshMatrix& global_trans): + m_face_ordering(face_ordering), m_global_trans(global_trans) { if(sub_inst.GetNumVertices() > 0) m_vertices = &sub_inst.GetVertices()[0]; @@ -77,7 +78,7 @@ namespace int compare(const StdMeshFace& face1, const StdMeshFace& face2) const { // TODO: Need to apply attach matrix in case of attached meshes - switch (m_inst.GetFaceOrdering()) + switch (m_face_ordering) { case StdSubMeshInstance::FO_Fixed: assert(false); @@ -95,7 +96,7 @@ namespace float z1 = std::max(std::max(z11, z12), z13); float z2 = std::max(std::max(z21, z22), z23); - if (m_inst.GetFaceOrdering() == StdSubMeshInstance::FO_FarthestToNearest) + if (m_face_ordering == StdSubMeshInstance::FO_FarthestToNearest) return (z1 < z2 ? -1 : (z1 > z2 ? +1 : 0)); else return (z2 < z1 ? -1 : (z2 > z1 ? +1 : 0)); @@ -421,17 +422,39 @@ void StdMesh::PostInit() std::sort(SubMeshes.begin(), SubMeshes.end(), StdMeshSubMeshVisibilityCmpPred()); } -StdSubMeshInstance::StdSubMeshInstance(const StdSubMesh& submesh): - Vertices(submesh.GetNumVertices()), Faces(submesh.GetNumFaces()), +StdSubMeshInstance::StdSubMeshInstance(StdMeshInstance& instance, const StdSubMesh& submesh, float completion): + Vertices(submesh.GetNumVertices()), Material(NULL), CurrentFaceOrdering(FO_Fixed) { // Copy initial Vertices/Faces for (unsigned int i = 0; i < submesh.GetNumVertices(); ++i) Vertices[i] = submesh.GetVertex(i); + LoadFacesForCompletion(instance, submesh, completion); + + SetMaterial(submesh.GetMaterial()); +} + +void StdSubMeshInstance::LoadFacesForCompletion(StdMeshInstance& instance, const StdSubMesh& submesh, float completion) +{ + // First: Copy all faces + Faces.resize(submesh.GetNumFaces()); for (unsigned int i = 0; i < submesh.GetNumFaces(); ++i) Faces[i] = submesh.GetFace(i); - SetMaterial(submesh.GetMaterial()); + if(completion < 1.0f) + { + // Second: Order by Y position. StdMeshInstanceFaceOrderingCmpPred orders by Z position, + // however we can simply give an appropriate transformation matrix to the face ordering. + // At this point, all vertices are in the OGRE coordinate frame, and Z in OGRE equals + // Y in Clonk, so we are fine without additional transformation. + StdMeshInstanceFaceOrderingCmpPred pred(instance, *this, FO_FarthestToNearest, StdMeshMatrix::Identity()); + g_pred = &pred; + StdMesh_tim_sort(&Faces[0], Faces.size()); + g_pred = NULL; + + // Third: Only use the first few ones + Faces.resize(static_cast(completion * submesh.GetNumFaces() + 0.5)); + } } void StdSubMeshInstance::SetMaterial(const StdMeshMaterial& material) @@ -702,8 +725,8 @@ void StdMeshInstance::AttachedMesh::DenumeratePointers() ChildDenumerator->DenumeratePointers(this); } -StdMeshInstance::StdMeshInstance(const StdMesh& mesh): - Mesh(&mesh), SharedVertices(mesh.GetSharedVertices().size()), +StdMeshInstance::StdMeshInstance(const StdMesh& mesh, float completion): + Mesh(&mesh), SharedVertices(mesh.GetSharedVertices().size()), Completion(completion), BoneTransforms(Mesh->GetNumBones(), StdMeshMatrix::Identity()), SubMeshInstances(Mesh->GetNumSubMeshes()), AttachParent(NULL), BoneTransformsDirty(false) @@ -716,7 +739,7 @@ StdMeshInstance::StdMeshInstance(const StdMesh& mesh): for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i) { const StdSubMesh& submesh = Mesh->GetSubMesh(i); - SubMeshInstances[i] = new StdSubMeshInstance(submesh); + SubMeshInstances[i] = new StdSubMeshInstance(*this, submesh, completion); } } @@ -763,6 +786,16 @@ void StdMeshInstance::SetFaceOrderingForClrModulation(uint32_t clrmod) (*iter)->Child->SetFaceOrderingForClrModulation(clrmod); } +void StdMeshInstance::SetCompletion(float completion) +{ + Completion = completion; + + // TODO: Load all submesh faces and then determine the ones to use from the + // full pool. + for(unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i) + SubMeshInstances[i]->LoadFacesForCompletion(*this, Mesh->GetSubMesh(i), completion); +} + StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight) { const StdMeshAnimation* animation = Mesh->GetAnimationByName(animation_name); @@ -976,7 +1009,7 @@ void StdMeshInstance::ExecuteAnimation(float dt) StdMeshInstance::AttachedMesh* StdMeshInstance::AttachMesh(const StdMesh& mesh, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags) { - StdMeshInstance* instance = new StdMeshInstance(mesh); + StdMeshInstance* instance = new StdMeshInstance(mesh, 1.0f); AttachedMesh* attach = AttachMesh(*instance, denumerator, parent_bone, child_bone, transformation, flags, true); if (!attach) { delete instance; delete denumerator; return NULL; } return attach; @@ -1147,7 +1180,7 @@ void StdMeshInstance::ReorderFaces(StdMeshMatrix* global_trans) StdSubMeshInstance& inst = *SubMeshInstances[i]; if(inst.CurrentFaceOrdering != StdSubMeshInstance::FO_Fixed) { - StdMeshInstanceFaceOrderingCmpPred pred(*this, inst, global_trans ? *global_trans : StdMeshMatrix::Identity()); + StdMeshInstanceFaceOrderingCmpPred pred(*this, inst, inst.CurrentFaceOrdering, global_trans ? *global_trans : StdMeshMatrix::Identity()); // The usage of timsort instead of std::sort at this point is twofold. // First, it's faster in our case where the array is already sorted in diff --git a/src/lib/StdMesh.h b/src/lib/StdMesh.h index 96f2dd3c1..9de6b382e 100644 --- a/src/lib/StdMesh.h +++ b/src/lib/StdMesh.h @@ -205,7 +205,8 @@ public: FO_NearestToFarthest }; - StdSubMeshInstance(const StdSubMesh& submesh); + StdSubMeshInstance(class StdMeshInstance& instance, const StdSubMesh& submesh, float completion); + void LoadFacesForCompletion(class StdMeshInstance& instance, const StdSubMesh& submesh, float completion); // Get vertex of instance, with current animation applied. This needs to // go elsewhere if/when we want to calculate this on the hardware. @@ -271,7 +272,7 @@ class StdMeshInstance friend class StdMeshMaterialUpdate; friend class StdMeshUpdate; public: - StdMeshInstance(const StdMesh& mesh); + StdMeshInstance(const StdMesh& mesh, float completion = 1.0f); ~StdMeshInstance(); typedef StdSubMeshInstance::FaceOrdering FaceOrdering; @@ -478,13 +479,17 @@ public: void SetFaceOrdering(FaceOrdering ordering); void SetFaceOrderingForClrModulation(uint32_t clrmod); + const std::vector& GetSharedVertices() const { return SharedVertices; } + size_t GetNumSharedVertices() const { return SharedVertices.size(); } + + // Set completion of the mesh. For incompleted meshes not all faces will be available. + void SetCompletion(float completion); + float GetCompletion() const { return Completion; } + AnimationNode* PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight); AnimationNode* PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight); void StopAnimation(AnimationNode* node); - const std::vector& GetSharedVertices() const { return SharedVertices; } - size_t GetNumSharedVertices() const { return SharedVertices.size(); } - AnimationNode* GetAnimationNodeByNumber(unsigned int number); AnimationNode* GetRootAnimationForSlot(int slot); // child bone transforms are dirty (saves matrix inversion for unanimated attach children). @@ -550,6 +555,8 @@ protected: const StdMesh* Mesh; + float Completion; // NoSave + std::vector SharedVertices; AnimationNodeList AnimationNodes; // for simple lookup of animation nodes by their unique number diff --git a/src/lib/StdMeshUpdate.cpp b/src/lib/StdMeshUpdate.cpp index 6245e3401..b9cbec202 100644 --- a/src/lib/StdMeshUpdate.cpp +++ b/src/lib/StdMeshUpdate.cpp @@ -104,7 +104,7 @@ void StdMeshUpdate::Update(StdMeshInstance* instance, const StdMesh& new_mesh) c delete instance->SubMeshInstances[i]; instance->SubMeshInstances.resize(new_mesh.GetNumSubMeshes()); for (unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i) - instance->SubMeshInstances[i] = new StdSubMeshInstance(new_mesh.GetSubMesh(i)); + instance->SubMeshInstances[i] = new StdSubMeshInstance(*instance, new_mesh.GetSubMesh(i), instance->GetCompletion()); // Update child bone of attach parent. If the bone does not exist anymore // in the updated mesh, then detach the mesh from its parent diff --git a/src/platform/StdGL.cpp b/src/platform/StdGL.cpp index 457730d8d..852ca9dc7 100644 --- a/src/platform/StdGL.cpp +++ b/src/platform/StdGL.cpp @@ -819,19 +819,28 @@ namespace glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); glFrontFace(parity ? GL_CW : GL_CCW); - switch (pass.CullHardware) + if(mesh_instance.GetCompletion() < 1.0f) { - case StdMeshMaterialPass::CH_Clockwise: - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - break; - case StdMeshMaterialPass::CH_CounterClockwise: - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - break; - case StdMeshMaterialPass::CH_None: + // Backfaces might be visible when completion is < 1.0f since front + // faces might be omitted. glDisable(GL_CULL_FACE); - break; + } + else + { + switch (pass.CullHardware) + { + case StdMeshMaterialPass::CH_Clockwise: + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case StdMeshMaterialPass::CH_CounterClockwise: + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + break; + case StdMeshMaterialPass::CH_None: + glDisable(GL_CULL_FACE); + break; + } } // Overwrite blend mode with default alpha blending when alpha in clrmod From 3c785cbee3dd5a7d086fd414e385c0f4122a4332 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Sun, 26 Feb 2012 01:34:56 +0100 Subject: [PATCH 48/70] Added MovePosition(x,y,precision), which moves an object by x/y. --- planet/System.ocg/Commits.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/planet/System.ocg/Commits.c b/planet/System.ocg/Commits.c index bdeaa4b29..52c465fd3 100644 --- a/planet/System.ocg/Commits.c +++ b/planet/System.ocg/Commits.c @@ -337,3 +337,8 @@ global func FindPosInMat(string sMat, int iXStart, int iYStart, int iWidth, int } return 0; // No location found. } + +global func MovePosition(int x, int y, int prec) +{ + SetPosition(GetX(prec) + x, GetY(prec) + y, nil, prec); +} From 2a5c129c93bf682dffedf09d61dd559132f936fe Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Sun, 26 Feb 2012 01:36:38 +0100 Subject: [PATCH 49/70] Implemented MouseHover-Callback. Calls OnMouseOver(player, draggedObject) in Objects beeing hovered over. Calls OnMouseOut(player, draggedObject) in Objects that stop beeing hovered over. --- planet/System.ocg/PlayerControl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/planet/System.ocg/PlayerControl.c b/planet/System.ocg/PlayerControl.c index 05f3f384a..05ab83bd0 100644 --- a/planet/System.ocg/PlayerControl.c +++ b/planet/System.ocg/PlayerControl.c @@ -464,6 +464,21 @@ global func ObjectComLetGo(int vx, int vy) return true; } +/* Mouse Hovering */ + +// Engine callback when the mouse hovers over an object (entering) or stops hovering over an object (leaving). +// Either leaving, entering or both are set. They can be nil, but never both at the same time. +// dragged is an object being drag(¬ dropped yet) +global func MouseHover(int player, object leaving, object entering, object dragged) +{ + // Leaving the hovering zone should be processed first. + if(leaving) + leaving->~OnMouseOut(player, dragged); + // Then process entering a new hovering zone. + if(entering) + entering->~OnMouseOver(player, dragged); + return true; +} /* Drag & Drop */ From 7e864912df446847d4fd7e4050af7c0a016aaf36 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 26 Feb 2012 14:15:42 +0100 Subject: [PATCH 50/70] Implemented MouseOver in favour of UpdateCursor to show menu infos --- .../HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c | 19 ++++++++++- planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c | 20 +++++++++-- .../ConstructionMenu.ocd/Script.c | 34 +++++++++---------- .../Producer.ocd/ProductionMenu.ocd/Script.c | 33 +++++++++--------- 4 files changed, 68 insertions(+), 38 deletions(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c index 66040df6c..58910c090 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c @@ -52,7 +52,6 @@ public func MouseSelectionAlt(int plr) // Called to determine which object is dragged. public func MouseDrag(int plr) { - //Log("%s->MouseDrag(%d) for owner: %d, menu: %s, dd: %v", GetName(), plr, GetOwner(), item_menu->GetName(), item_menu->IsDragDropMenu()); // Check if the owners match. if (plr != GetOwner()) return; @@ -91,6 +90,24 @@ public func MouseDragDone(self, object target) return item_menu->OnItemDragDone(self, target); } +// Called if the mouse cursor starts hovering over this item. +public func OnMouseOver(int plr, object dragged) +{ + if (plr != GetOwner()) return; + + // Forward command to menu. + return item_menu->OnMouseOverItem(this, dragged); +} + +// Called if the mouse cursor stops hovering over this item. +public func OnMouseOut(int plr, object dragged) +{ + if (plr != GetOwner()) return; + + // Forward command to menu. + return item_menu->OnMouseOutItem(this, dragged); +} + /* Menu item properties */ public func SetMenu(object menu) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c index e01c7ab40..16919edd4 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c @@ -333,7 +333,6 @@ public func OnItemDropped(object drop_item, object on_item) if (!menu_commander) return; // Forward to commander. - // Log("Item dropped %s", drop_item->GetName()); return menu_commander->~OnItemDropped(this, drop_item, on_item); } @@ -342,7 +341,24 @@ public func OnItemDragDone(object drag_item, object on_item) { if (!menu_commander) return; - // Log("Item dragged %s", drag_item->GetName()); // Forward to commander. return menu_commander->~OnItemDragDone(this, drag_item, on_item); } + +// Called if the mouse cursor enters hovering over an item. +public func OnMouseOverItem(object over_item, object dragged_item) +{ + if (!menu_commander) return; + + // Forward to commander. + return menu_commander->~OnMouseOverItem(this, over_item, dragged_item); +} + +// Called if the mouse cursor exits hovering over an item. +public func OnMouseOutItem(object out_item, object dragged_item) +{ + if (!menu_commander) return; + + // Forward to commander. + return menu_commander->~OnMouseOutItem(this, out_item, dragged_item); +} diff --git a/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/ConstructionMenu.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/ConstructionMenu.ocd/Script.c index 442b7e8ab..605109508 100644 --- a/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/ConstructionMenu.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/ConstructionMenu.ocd/Script.c @@ -77,9 +77,7 @@ public func HideConstructionInfo() /* Menu properties */ -public func IsProductionMenu() { return true; } -// UpdateCursor is called -public func CursorUpdatesEnabled() { return true; } +public func IsConstructionMenu() { return true; } public func Close() { @@ -95,21 +93,6 @@ public func HasCommander(object producer) return false; } -// Callback if the mouse is moved -public func UpdateCursor(int dx, int dy) -{ - var item = FindObject(Find_AtPoint(dx, dy), Find_ID(GUI_MenuItem)); - if (!item || item->GetMenu() != this) - { - if (constructinfo_shown) - HideConstructionInfo(); - return; - } - if (item == constructinfo_shown) - return; - ShowConstructionInfo(item); -} - /* Callbacks from the menu items, to be translated into commands for the producer. */ // Called when a click outside the menu has been made. @@ -151,3 +134,18 @@ public func OnItemDragDone(object drag_item, object on_item) return _inherited(drag_item, on_item, ...); } +// Called if the mouse cursor enters hovering over an item. +public func OnMouseOverItem(object over_item, object dragged_item) +{ + ShowConstructionInfo(over_item); + + return _inherited(over_item, dragged_item, ...); +} + +// Called if the mouse cursor exits hovering over an item. +public func OnMouseOutItem(object out_item, object dragged_item) +{ + HideConstructionInfo(); + + return _inherited(out_item, dragged_item, ...); +} \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/ProductionMenu.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/ProductionMenu.ocd/Script.c index 8c7ac9140..62f494f97 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/ProductionMenu.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/ProductionMenu.ocd/Script.c @@ -115,8 +115,6 @@ public func HideProductInfo() /* Menu properties */ public func IsProductionMenu() { return true; } -// UpdateCursor is called -public func CursorUpdatesEnabled() { return true; } public func AddQueueItem(object item) { @@ -217,21 +215,6 @@ public func HasCommander(object producer) return false; } -// Callback if the mouse is moved -public func UpdateCursor(int dx, int dy) -{ - var item = FindObject(Find_AtPoint(dx, dy), Find_ID(GUI_MenuItem)); - if (!item || item->GetMenu() != this) - { - if (productinfo_shown) - HideProductInfo(); - return; - } - if (item == productinfo_shown) - return; - ShowProductInfo(item); -} - /* Callbacks from the menu items, to be translated into commands for the producer. */ // Called when a click outside the menu has been made. @@ -309,3 +292,19 @@ public func OnItemDragDone(object drag_item, object on_item) return _inherited(drag_item, on_item, ...); } +// Called if the mouse cursor enters hovering over an item. +public func OnMouseOverItem(object over_item, object dragged_item) +{ + ShowProductInfo(over_item); + + return _inherited(over_item, dragged_item, ...); +} + +// Called if the mouse cursor exits hovering over an item. +public func OnMouseOutItem(object out_item, object dragged_item) +{ + HideProductInfo(); + + return _inherited(out_item, dragged_item, ...); +} + From 1963fa61baf7a95a761b327541e04102f90ae96e Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 26 Feb 2012 15:54:09 +0100 Subject: [PATCH 51/70] fixed dropping of stuff --- planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 577138d57..9542cecbd 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -770,10 +770,10 @@ public func ObjectCommand(string command, object target, int tx, int ty, object { // special control for throw and jump // but only with controls, not with general commands - if (command == "Throw") this->~ControlThrow(target,tx,ty); - else if (command == "Jump") this->~ControlJump(); + if (command == "Throw") return this->~ControlThrow(target,tx,ty); + else if (command == "Jump") return this->~ControlJump(); // else standard command - else SetCommand(command,target,tx,ty,target2); + else return SetCommand(command,target,tx,ty,target2); // this function might be obsolete: a normal SetCommand does make a callback to // script before it is executed: ControlCommand(szCommand, pTarget, iTx, iTy) From 3fddad2aad43103c7eac26ce77812b8e652702d0 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Sun, 26 Feb 2012 21:12:07 +0100 Subject: [PATCH 52/70] Hovered Items in Menus are enlarged by 10% now --- planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c index 58910c090..ebe5a438c 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/MenuItem.ocd/Script.c @@ -95,6 +95,10 @@ public func OnMouseOver(int plr, object dragged) { if (plr != GetOwner()) return; + // make it appear bigger + SetObjDrawTransform(1100, 0, 0, 0, 1100, 0, 1); + + // Forward command to menu. return item_menu->OnMouseOverItem(this, dragged); } @@ -104,6 +108,9 @@ public func OnMouseOut(int plr, object dragged) { if (plr != GetOwner()) return; + // standard size again + SetObjDrawTransform(1000, 0, 0, 0, 1000, 0, 1); + // Forward command to menu. return item_menu->OnMouseOutItem(this, dragged); } From fea620936528da535ddd14e3b01a65648a936637 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 26 Feb 2012 21:09:42 +0100 Subject: [PATCH 53/70] Fix drawing of non-default graphics in picture overlays This was broken by 427cf61d729a. --- .../Icons.ocd/SlimNumber.ocd/DefCore.txt | 2 +- src/game/object/C4Def.cpp | 58 +--------------- src/game/object/C4DefGraphics.cpp | 66 +++++++++++++++++-- src/game/object/C4DefGraphics.h | 2 + 4 files changed, 67 insertions(+), 61 deletions(-) diff --git a/planet/Objects.ocd/Icons.ocd/SlimNumber.ocd/DefCore.txt b/planet/Objects.ocd/Icons.ocd/SlimNumber.ocd/DefCore.txt index 1b51df48e..ff2ffa64d 100644 --- a/planet/Objects.ocd/Icons.ocd/SlimNumber.ocd/DefCore.txt +++ b/planet/Objects.ocd/Icons.ocd/SlimNumber.ocd/DefCore.txt @@ -2,7 +2,7 @@ id=Icon_SlimNumber Version=5,2,0,1 Category=C4D_StaticBack -Picture=0,0,64,64 +Picture=0,0,32,64 Width=32 Height=64 Offset=-16,-32 diff --git a/src/game/object/C4Def.cpp b/src/game/object/C4Def.cpp index b0547478b..2d3561825 100644 --- a/src/game/object/C4Def.cpp +++ b/src/game/object/C4Def.cpp @@ -533,65 +533,11 @@ bool C4Def::Load(C4Group &hGroup, void C4Def::Draw(C4Facet &cgo, bool fSelected, DWORD iColor, C4Object *pObj, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform* trans) { - - // default: def picture rect - C4Rect fctPicRect = PictureRect; - C4Facet fctPicture; - - // if assigned: use object specific rect and graphics - if (pObj) if (pObj->PictureRect.Wdt) fctPicRect = pObj->PictureRect; - - if (fSelected) + if(fSelected) pDraw->DrawBoxDw(cgo.Surface, cgo.X, cgo.Y, cgo.X + cgo.Wdt - 1, cgo.Y + cgo.Hgt - 1, C4RGB(0xca, 0, 0)); C4DefGraphics* graphics = pObj ? pObj->GetGraphics() : &Graphics; - - // specific object color? - if (pObj) pObj->PrepareDrawing(); - - switch (graphics->Type) - { - case C4DefGraphics::TYPE_Bitmap: - fctPicture.Set(graphics->GetBitmap(iColor),fctPicRect.x,fctPicRect.y,fctPicRect.Wdt,fctPicRect.Hgt); - fctPicture.DrawTUnscaled(cgo,true,iPhaseX,iPhaseY,trans); - break; - case C4DefGraphics::TYPE_Mesh: - // TODO: Allow rendering of a mesh directly, without instance (to render pose; no animation) - std::auto_ptr dummy; - StdMeshInstance* instance; - - C4Value value; - if (pObj) - { - instance = pObj->pMeshInstance; - pObj->GetProperty(P_PictureTransformation, &value); - } - else - { - dummy.reset(new StdMeshInstance(*graphics->Mesh, 1.0f)); - instance = dummy.get(); - GetProperty(P_PictureTransformation, &value); - } - - StdMeshMatrix matrix; - if (C4ValueToMatrix(value, &matrix)) - pDraw->SetMeshTransform(&matrix); - - pDraw->SetPerspective(true); - pDraw->RenderMesh(*instance, cgo.Surface, cgo.X,cgo.Y, cgo.Wdt, cgo.Hgt, pObj ? pObj->Color : iColor, trans); - pDraw->SetPerspective(false); - pDraw->SetMeshTransform(NULL); - - break; - } - - if (pObj) pObj->FinishedDrawing(); - - // draw overlays - if (pObj && pObj->pGfxOverlay) - for (C4GraphicsOverlay *pGfxOvrl = pObj->pGfxOverlay; pGfxOvrl; pGfxOvrl = pGfxOvrl->GetNext()) - if (pGfxOvrl->IsPicture()) - pGfxOvrl->DrawPicture(cgo, pObj, trans); + graphics->Draw(cgo, iColor, pObj, iPhaseX, iPhaseY, trans); } int32_t C4Def::GetValue(C4Object *pInBase, int32_t iBuyPlayer) diff --git a/src/game/object/C4DefGraphics.cpp b/src/game/object/C4DefGraphics.cpp index 431345507..d72697476 100644 --- a/src/game/object/C4DefGraphics.cpp +++ b/src/game/object/C4DefGraphics.cpp @@ -294,6 +294,63 @@ bool C4DefGraphics::CopyGraphicsFrom(C4DefGraphics &rSource) return true; } +void C4DefGraphics::Draw(C4Facet &cgo, DWORD iColor, C4Object *pObj, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform* trans) +{ + // default: def picture rect + C4Rect fctPicRect = pDef->PictureRect; + C4Facet fctPicture; + + // if assigned: use object specific rect and graphics + if (pObj) if (pObj->PictureRect.Wdt) fctPicRect = pObj->PictureRect; + + // specific object color? + if (pObj) pObj->PrepareDrawing(); + + switch(Type) + { + case C4DefGraphics::TYPE_Bitmap: + fctPicture.Set(GetBitmap(iColor),fctPicRect.x,fctPicRect.y,fctPicRect.Wdt,fctPicRect.Hgt); + fctPicture.DrawTUnscaled(cgo,true,iPhaseX,iPhaseY,trans); + break; + case C4DefGraphics::TYPE_Mesh: + // TODO: Allow rendering of a mesh directly, without instance (to render pose; no animation) + std::auto_ptr dummy; + StdMeshInstance* instance; + + C4Value value; + if (pObj) + { + instance = pObj->pMeshInstance; + pObj->GetProperty(P_PictureTransformation, &value); + } + else + { + dummy.reset(new StdMeshInstance(*Mesh, 1.0f)); + instance = dummy.get(); + pDef->GetProperty(P_PictureTransformation, &value); + } + + StdMeshMatrix matrix; + if (C4ValueToMatrix(value, &matrix)) + pDraw->SetMeshTransform(&matrix); + + pDraw->SetPerspective(true); + pDraw->RenderMesh(*instance, cgo.Surface, cgo.X,cgo.Y, cgo.Wdt, cgo.Hgt, pObj ? pObj->Color : iColor, trans); + pDraw->SetPerspective(false); + pDraw->SetMeshTransform(NULL); + + break; + } + + if (pObj) pObj->FinishedDrawing(); + + // draw overlays + if (pObj && pObj->pGfxOverlay) + for (C4GraphicsOverlay *pGfxOvrl = pObj->pGfxOverlay; pGfxOvrl; pGfxOvrl = pGfxOvrl->GetNext()) + if (pGfxOvrl->IsPicture()) + pGfxOvrl->DrawPicture(cgo, pObj, trans); +} + void C4DefGraphics::DrawClr(C4Facet &cgo, bool fAspect, DWORD dwClr) { if (Type != TYPE_Bitmap) return; // TODO @@ -920,7 +977,6 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP } else if(eMode == MODE_Picture || eMode == MODE_IngamePicture) { - C4Def *pDef = pSourceGfx->pDef; float twdt, thgt; if (fZoomToShape) { @@ -929,14 +985,16 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP } else { - twdt = pDef->Shape.Wdt; - thgt = pDef->Shape.Hgt; + twdt = pSourceGfx->pDef->Shape.Wdt; + thgt = pSourceGfx->pDef->Shape.Hgt; } C4TargetFacet ccgo; ccgo.Set(cgo.Surface, offX-twdt/2, offY-thgt/2, twdt, thgt, cgo.TargetX, cgo.TargetY); C4DrawTransform trf(Transform, offX, offY); - pDef->Draw(ccgo, false, pForObj->Color, NULL, iPhase, 0, &trf); + + // Don't set pForObj because we don't draw the picture of pForObj, but the picture of another definition on top of pForObj: + pSourceGfx->Draw(ccgo, pForObj->Color, NULL, iPhase, 0, &trf); } else { diff --git a/src/game/object/C4DefGraphics.h b/src/game/object/C4DefGraphics.h index 7f597c520..655a158dd 100644 --- a/src/game/object/C4DefGraphics.h +++ b/src/game/object/C4DefGraphics.h @@ -81,6 +81,8 @@ public: { return Type == TYPE_Mesh || !!Bmp.BitmapClr; } // Mesh can always apply PlayerColor (if used in its material) bool CopyGraphicsFrom(C4DefGraphics &rSource); // copy bitmaps from source graphics + void Draw(C4Facet &cgo, DWORD iColor, C4Object *pObj, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform* trans); + virtual const char *GetName() { return NULL; } // return name to be stored in safe game files C4AdditionalDefGraphics *GetNext() { return pNext; } From 893fb4bbed0e48228e064d805b2523948a5282a3 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sun, 26 Feb 2012 21:44:00 +0100 Subject: [PATCH 54/70] Make overlays on picture graphics work again This was partly broken by 427cf61d729a. However, already before that, the size of the overlay was depending on the ingame size of the object on whose picture the overlay was being drawn. This didn't make much sense and now the size of the overlay is equal to the area on which the picture is drawn in the first place. --- src/game/object/C4DefGraphics.cpp | 42 ++++++++----------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/src/game/object/C4DefGraphics.cpp b/src/game/object/C4DefGraphics.cpp index d72697476..97fc2ad59 100644 --- a/src/game/object/C4DefGraphics.cpp +++ b/src/game/object/C4DefGraphics.cpp @@ -936,6 +936,8 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP // drawing specific object? else if (OverlayObj) { + // TODO: Shouldn't have called PrepareDrawing/set ClrModulation here, since + // OverlayObj drawing will do it on its own. if (eMode == MODE_ObjectPicture) { C4Facet fctTarget; @@ -1071,8 +1073,7 @@ void C4GraphicsOverlay::DrawRankSymbol(C4Facet &cgo, C4Object *rank_obj) void C4GraphicsOverlay::DrawPicture(C4Facet &cgo, C4Object *pForObj, C4DrawTransform* trans) { assert(IsPicture()); - // update object color - if (pForObj && fctBlit.Surface) fctBlit.Surface->SetClr(pForObj->Color); + // special blit mode if (dwBlitMode == C4GFXBLIT_PARENT) { @@ -1086,38 +1087,16 @@ void C4GraphicsOverlay::DrawPicture(C4Facet &cgo, C4Object *pForObj, C4DrawTrans if (pMeshInstance) pMeshInstance->SetFaceOrderingForClrModulation(dwClrModulation); } - // draw at given rect - if (!pMeshInstance) - { - // the picture we are rendering is the one with trans applied, and the overlay transformation - // is applied to the picture we are rendering, so apply it afterwards. Note that - // C4BltTransform::operator*= does this = other * this. - C4DrawTransform trf(Transform, cgo.X+float(cgo.Wdt)/2, cgo.Y+float(cgo.Hgt)/2); - if(trans) trf *= *trans; - fctBlit.DrawT(cgo, true, iPhase, 0, &trf); - } - else - { - C4Def *pDef = pSourceGfx->pDef; + // the picture we are rendering is the one with trans applied, and the overlay transformation + // is applied to the picture we are rendering, so apply it afterwards. Note that + // C4BltTransform::operator*= does this = other * this. + C4DrawTransform trf(Transform, cgo.X + cgo.Wdt/2.0f, cgo.Y + cgo.Hgt/2.0f); + if(trans) trf *= *trans; - C4Value value; - pDef->GetProperty(P_PictureTransformation, &value); - StdMeshMatrix matrix; - if (C4ValueToMatrix(value, &matrix)) - pDraw->SetMeshTransform(&matrix); + // Don't set pForObj because we don't draw the picture of pForObj, but the picture of another definition on top of pForObj: + pSourceGfx->Draw(cgo, pForObj->Color, NULL, iPhase, 0, &trf); - // the picture we are rendering is the one with trans applied, and the overlay transformation - // is applied to the picture we are rendering, so apply it afterwards. Note that - // C4BltTransform::operator*= does this = other * this. - C4DrawTransform trf(Transform, cgo.X+float(pForObj->Shape.Wdt)/2, cgo.Y+float(pForObj->Shape.Hgt)/2); - if(trans) trf *= *trans; - - pDraw->SetPerspective(true); - pDraw->RenderMesh(*pMeshInstance, cgo.Surface, cgo.X, cgo.Y, pForObj->Shape.Wdt, pForObj->Shape.Hgt, pForObj->Color, &trf); - pDraw->SetPerspective(false); - pDraw->SetMeshTransform(NULL); - } // cleanup if (dwBlitMode == C4GFXBLIT_PARENT) { @@ -1130,7 +1109,6 @@ void C4GraphicsOverlay::DrawPicture(C4Facet &cgo, C4Object *pForObj, C4DrawTrans } } - bool C4GraphicsOverlay::operator == (const C4GraphicsOverlay &rCmp) const { // compare relevant fields From 44336f23d70bcf8e231de69669a1397d9d0bd636 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Mon, 27 Feb 2012 20:44:12 +0100 Subject: [PATCH 55/70] The Content-Menu now displays nearby crewmembers to the left for trading. --- .../ContentsMenuController.ocd/Script.c | 75 +++++++++++++++---- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c index d179abd28..5d8c185a2 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c @@ -4,9 +4,15 @@ @author Newton, Maikel */ +// this array contains all the menus +// index 0 = calling object +// index >0 = first crew, then containers local circ_menus; local menu_object; +local crew_count; +local container_count; + /** Creates a content menu for the calling object. This is supposed to be a crew member, controlled by a player. @return a pointer to the created menu, or \c nil if failed. @@ -23,10 +29,21 @@ global func CreateContentsMenus() controller->SetMenuObject(this); this->SetMenu(controller); + var index = 0; + + // add the clonk itself + controller->AddContentMenu(this, index, true); + + // add all nearby crewmembers + var teammates = FindObjects(Find_Distance(20), Find_OCF(OCF_CrewMember), Find_Owner(GetOwner()), Find_Exclude(this)); + index = 1; + for(var t in teammates) + controller->AddContentMenu(t, index++, true); + // Add content menus for all containers at the position of the caller. - var containers = FindObjects(Find_Or(Find_Not(Find_Exclude(this)), Find_And(Find_AtPoint(), Find_NoContainer(), Find_Func("IsContainer"))), Sort_Func("SortInventoryObjs")); - for(var index = 0; index < GetLength(containers); index++) - controller->AddContentMenu(containers[index], index, GetLength(containers)); + var containers = FindObjects(Find_AtPoint(), Find_NoContainer(), Find_Func("IsContainer"), Sort_Func("SortInventoryObjs")); + for(var c in containers) + controller->AddContentMenu(c, index++, false); // Show and return content menu. controller->Show(); @@ -81,7 +98,7 @@ func Hide() prop.Menu->Hide(); } -func AddContentMenu(object container, int pos, int length) +func AddContentMenu(object container, int pos, bool isCrew) { var menu = CreateObject(GUI_Menu, 0, 0, GetOwner()); @@ -91,7 +108,12 @@ func AddContentMenu(object container, int pos, int length) menu->SetDragDropMenu(true); PutContentsIntoMenu(menu, container); - circ_menus[pos] = {Object = container, Menu = menu}; + circ_menus[pos] = {Object = container, Menu = menu, IsCrew = isCrew}; + + if(isCrew) + crew_count++; + else + container_count++; // Track external changes in containers. AddEffect("ContainerTracker", container, 100, 1, this, nil, menu); @@ -103,18 +125,41 @@ func AddContentMenu(object container, int pos, int length) // Draws the contents menus to the right positions. private func UpdateContentMenus() { - var menu_count = GetLength(circ_menus); - for (var index = 0; index < menu_count; index++) + // for positioning to the left + var index_crew = 0; + // for positioning to the right + var index_containers = 1; // containers start with an offset of 1 + + // calculate left edge + var r = 160; + var d = 2*r/3; + var dx = Sqrt(r**2 - d**2); + var x_base = 800 - dx*(container_count-1); + var y_base = 320; + + for(var prop in circ_menus) { - var menu = circ_menus[index].Menu; - var r = 160; - var d = 2*r/3; - var dx = Sqrt(r**2 - d**2); + var menu = prop.Menu; - // Determine x-position. - var x = 800 + dx * (2*index - menu_count + 1); - // Alternate y-position. - var y = 320 + (-1)**index * d; + var x,y; + + if(prop.IsCrew) + { + x = x_base - dx * (2*index_crew); + y = y_base + 2*d - (-1)**index_crew * d; + + index_crew++; + } + else + { + // Determine x-position. + //x = 800 + dx * (2*index_containers - container_count + 1); + x = x_base + dx*(2*index_containers); + // Alternate y-position. + y = y_base + (-1)**(index_containers) * d; + + index_containers++; + } // TODO: reduce size of menus to fit more into screen. menu->SetPosition(x, y); } From 1be03954423c79d2998a39976ada05547e544c61 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Mon, 27 Feb 2012 21:00:29 +0100 Subject: [PATCH 56/70] Fixed Menu-Movement when transferring stuff --- .../HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c index 5d8c185a2..84d6c77d0 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c @@ -323,7 +323,12 @@ public func OnExternalContentChange(object menu, object container) } // Reopen the changed menu. - AddContentMenu(container, index, length); + var isCrew = container->GetOCF() & OCF_CrewMember; + if(isCrew) + crew_count--; + else + container_count--; + AddContentMenu(container, index, isCrew); Show(); return; } From 9480a701c43e6c6b216133b191848241d0309cb3 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Mon, 27 Feb 2012 21:17:23 +0100 Subject: [PATCH 57/70] ContentsMenu takes order in clonk-inventory into account --- .../HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c | 7 ++++++- .../Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c index 84d6c77d0..750e6aba5 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c @@ -170,7 +170,12 @@ private func PutContentsIntoMenu(object menu, object container) { if (container->~ NoStackedContentMenu()) { - var contents = FindObjects(Find_Container(container)); + var contents; + // get contents in special order if possible + if(!(contents = (container->~GetItems()))) + // else just take everything we find. + contents = FindObjects(Find_Container(container)); + for (var content in contents) if (!AddContentsMenuItem(content, menu)) return; diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 9542cecbd..d397c282f 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -61,6 +61,14 @@ public func GetItem(int i) return inventory[i]; } +/* returns all items in the inventory */ +public func GetItems() +{ + var inv = inventory[:]; + RemoveHoles(inv); + return inv; +} + // For the HUD: this object shows its items in the HUD (i.e. has the GetItem function) public func HUDShowItems() { return true; } From a698b0e662fca85f9ed3e07a0c147ca4bf7c7387 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Mon, 27 Feb 2012 21:34:59 +0100 Subject: [PATCH 58/70] Fixed menus beeing built counter-clockwise instead of clockwise The middle now is the 8th menu entry instead of the 1st --- planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c index 16919edd4..8bfae2a3a 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/Script.c @@ -165,12 +165,12 @@ private func GetItemPosition(int n, int total) // Packing 7 or less circles. if (total <= 7) { - if (n == 1) + if (n == 7) return [0, 0]; else { - var x = Cos(60 * (n-1), 2 * MENU_Radius / 3); - var y = -Sin(60 * (n-1), 2 * MENU_Radius / 3); + var x = -Cos(60 * (n+1), 2 * MENU_Radius / 3); + var y = -Sin(60 * (n+1), 2 * MENU_Radius / 3); return [x, y]; } } @@ -178,18 +178,18 @@ private func GetItemPosition(int n, int total) // Packing 19 or less circles. if (total <= 19) { - if (n == 1) + if (n == 7) return [0, 0]; - else if (n <= 7) + else if (n < 7) { - var x = Cos(60 * (n-1), 2 * MENU_Radius / 5); - var y = -Sin(60 * (n-1), 2 * MENU_Radius / 5); + var x = -Cos(60 * (n+1), 2 * MENU_Radius / 5); + var y = -Sin(60 * (n+1), 2 * MENU_Radius / 5); return [x, y]; } else { - var x = Cos(30 * (n-7) + 15, 31 * MENU_Radius / 40); - var y = -Sin(30 * (n-7) + 15, 31 * MENU_Radius / 40); + var x = -Cos(30 * (n-5) + 15, 31 * MENU_Radius / 40); + var y = -Sin(30 * (n-5) + 15, 31 * MENU_Radius / 40); return [x, y]; } } @@ -197,24 +197,24 @@ private func GetItemPosition(int n, int total) // Packing 37 or less circles. if (total <= 37) { - if (n == 1) + if (n == 7) return [0, 0]; - else if (n <= 7) + else if (n < 7) { - var x = Cos(60 * (n-1), 2 * MENU_Radius / 7); - var y = -Sin(60 * (n-1), 2 * MENU_Radius / 7); + var x = -Cos(60 * (n+1), 2 * MENU_Radius / 7); + var y = -Sin(60 * (n+1), 2 * MENU_Radius / 7); return [x, y]; } else if (n <= 19) { - var x = Cos(30 * (n-7) + 15, 31 * MENU_Radius / 56); - var y = -Sin(30 * (n-7) + 15, 31 * MENU_Radius / 56); + var x = -Cos(30 * (n-5) + 15, 31 * MENU_Radius / 56); + var y = -Sin(30 * (n-5) + 15, 31 * MENU_Radius / 56); return [x, y]; } else { - var x = Cos(30 * (n-19), 61 * MENU_Radius / 72); - var y = -Sin(30 * (n-19), 61 * MENU_Radius / 72); + var x = -Cos(30 * (n-17), 61 * MENU_Radius / 72); + var y = -Sin(30 * (n-17), 61 * MENU_Radius / 72); return [x, y]; } } From 7251865981e1f697159cd78b5e9c1d93f3db1de1 Mon Sep 17 00:00:00 2001 From: Bernhard Bonigl Date: Tue, 28 Feb 2012 22:55:40 +0100 Subject: [PATCH 59/70] ContentsMenu now only shows fully built containers --- .../HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c index 750e6aba5..ab8c4c2a3 100644 --- a/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/Menu.ocd/ContentsMenuController.ocd/Script.c @@ -41,7 +41,7 @@ global func CreateContentsMenus() controller->AddContentMenu(t, index++, true); // Add content menus for all containers at the position of the caller. - var containers = FindObjects(Find_AtPoint(), Find_NoContainer(), Find_Func("IsContainer"), Sort_Func("SortInventoryObjs")); + var containers = FindObjects(Find_AtPoint(), Find_NoContainer(), Find_OCF(OCF_Fullcon), Find_Func("IsContainer"), Sort_Func("SortInventoryObjs")); for(var c in containers) controller->AddContentMenu(c, index++, false); From cb6eb060cc976b52c9f1eb421b1a751ecdf8590a Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Tue, 28 Feb 2012 18:28:16 +0100 Subject: [PATCH 60/70] Add a dialogue for windows which can be displayed when the graphics engine initialisation failed The dialogue has fields for resolution and a checkbox for fullscreen mode --- CMakeLists.txt | 14 +-- planet/System.ocg/LanguageDE.txt | 4 + planet/System.ocg/LanguageUS.txt | 4 + src/C4Application.cpp | 4 +- src/gui/C4GfxErrorDlg.cpp | 153 +++++++++++++++++++++++++++++++ src/gui/C4GfxErrorDlg.h | 11 +++ src/res/engine.rc | 20 +++- src/res/resource.h | 9 ++ 8 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 src/gui/C4GfxErrorDlg.cpp create mode 100644 src/gui/C4GfxErrorDlg.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 48e348788..033304df3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ separate_arguments(OC_EXE_LINKER_FLAGS_DEBUG) ############################################################################ # User selectable options ############################################################################ -option(PROJECT_FOLDERS "Put source files into subfolders in project file" ON) +option(PROJECT_FOLDERS "Put source files into subfolders in project file" ON) option(USE_GL "Enable OpenGL support" ON) SET(INITIAL_USE_SDL_MAINLOOP_VALUE OFF) SET(INITIAL_USE_OPEN_AL OFF) @@ -56,7 +56,7 @@ if(WIN32 AND FALSE) # disable DX option while it doesn't work anyway list(APPEND CMAKE_LIBRARY_PATH $ENV{DXSDK_DIR}/Lib/x86) endif() else() - + endif() else() SET(USE_DIRECTX OFF) @@ -324,6 +324,8 @@ set(OC_CLONK_SOURCES src/gui/C4GameOptions.h src/gui/C4GameOverDlg.cpp src/gui/C4GameOverDlg.h + src/gui/C4GfxErrorDlg.cpp + src/gui/C4GfxErrorDlg.h src/gui/C4GuiButton.cpp src/gui/C4GuiCheckBox.cpp src/gui/C4GuiComboBox.cpp @@ -873,14 +875,14 @@ if(APPLE) src/res/Ift_Trans.png src/res/NoIft_Trans.png ) - + # Add icon resources set_source_files_properties( ${OC_BUNDLE_RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) list(APPEND OC_SYSTEM_SOURCES ${OC_BUNDLE_RESOURCES}) - + endif() ############################################################################ @@ -987,7 +989,7 @@ if(HAVE_PTHREAD) pthread ) target_link_libraries(c4script - pthread + pthread ) endif() if(USE_CONSOLE) @@ -1017,7 +1019,7 @@ if (APPLE) SET_TARGET_PROPERTIES(c4group PROPERTIES XCODE_ATTRIBUTE_GCC_PFE_FILE_C_DIALECTS "c++ objective-c++") endif() -# This expands some variables in Info.plist as a side-effect. XCode might then +# This expands some variables in Info.plist as a side-effect. XCode might then # expand a second time, using the same syntax. Try not to get confused by this! set_target_properties(clonk PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/src/res/Info.plist") diff --git a/planet/System.ocg/LanguageDE.txt b/planet/System.ocg/LanguageDE.txt index a859e74b6..0d3337af9 100644 --- a/planet/System.ocg/LanguageDE.txt +++ b/planet/System.ocg/LanguageDE.txt @@ -38,6 +38,7 @@ IDS_BTN_RELOAD=&Aktualisieren IDS_BTN_RENAME=Umbenennen IDS_BTN_RESETCONFIG=Konfiguration zurücksetzen IDS_BTN_RESETKEYBOARD=Alle zurücksetzen +IDS_BTN_RESTART=Neu &Starten IDS_BTN_RETRY=Wiederholen IDS_BTN_SIMPLE=<- Einfach IDS_BTN_START=Starten @@ -784,6 +785,9 @@ IDS_MSG_FREEVIEW=Freie Sicht IDS_MSG_FULLSCREEN=Vollbild IDS_MSG_FULLSCREEN_DESC=Vollbildmodus aktivieren. IDS_MSG_GFXENGINE_DESC=Gibt an, welcher Grafikmodus benutzt wird. Änderungen greifen erst beim nächsten Programmstart. +IDS_MSG_GFXERR_RESINVAL=Ungültige Auflösung! +IDS_MSG_GFXERR_RESNOTFOUND=Die gewählte Auflösung wird vom System anscheinend nicht unterstützt. +IDS_MSG_GFXERR_TXT=OpenClonk konnte OpenGL nicht laden. Prüfen Sie, ob Ihr Grafiktreiber aktuell ist und OpenGL 1.3 unterstützt. IDS_MSG_HASDISCONNECTED=%s hat die Verbindung beendet (%s). IDS_MSG_HASJOINEDTHECHANNEL=%s ist dem Chat-Kanal beigetreten. IDS_MSG_HASLEFTTHECHANNEL=%s hat den Chat-Kanal verlassen (%s) diff --git a/planet/System.ocg/LanguageUS.txt b/planet/System.ocg/LanguageUS.txt index 78bc2e008..8d7a640b3 100644 --- a/planet/System.ocg/LanguageUS.txt +++ b/planet/System.ocg/LanguageUS.txt @@ -38,6 +38,7 @@ IDS_BTN_RELOAD=Reloa&d IDS_BTN_RENAME=Rename IDS_BTN_RESETCONFIG=Reset configuration IDS_BTN_RESETKEYBOARD=Reset all +IDS_BTN_RESTART=Restart IDS_BTN_RETRY=Retry IDS_BTN_SIMPLE=<- Basic IDS_BTN_START=Start @@ -783,6 +784,9 @@ IDS_MSG_FREEVIEW=free view IDS_MSG_FULLSCREEN=Fullscreen IDS_MSG_FULLSCREEN_DESC=Use fullscreen mode. IDS_MSG_GFXENGINE_DESC=Determines the rendering engine. Changes take effect when the game is restarted. +IDS_MSG_GFXERR_RESINVAL=Invalid resolution! +IDS_MSG_GFXERR_RESNOTFOUND=This resolution is probably not supportet by your system. +IDS_MSG_GFXERR_TXT=OpenClonk could not load OpenGL. Please check if your graphics card driver is up-to-date and supports OpenGL 1.3. IDS_MSG_HASDISCONNECTED=%s has disconnected (%s). IDS_MSG_HASJOINEDTHECHANNEL=%s has joined the channel. IDS_MSG_HASLEFTTHECHANNEL=%s has left the channel (%s) diff --git a/src/C4Application.cpp b/src/C4Application.cpp index 120e25298..0af847502 100644 --- a/src/C4Application.cpp +++ b/src/C4Application.cpp @@ -52,6 +52,8 @@ #include +#include + static C4Network2IRCClient ApplicationIRCClient; C4Application::C4Application(): @@ -161,7 +163,7 @@ bool C4Application::DoInit(int argc, char * argv[]) if (!isEditor) { if (!(pWindow = FullScreen.Init(this))) - { Clear(); return false; } + { Clear(); ShowGfxErrorDialog(); return false; } } else { diff --git a/src/gui/C4GfxErrorDlg.cpp b/src/gui/C4GfxErrorDlg.cpp new file mode 100644 index 000000000..1a791ae46 --- /dev/null +++ b/src/gui/C4GfxErrorDlg.cpp @@ -0,0 +1,153 @@ +/* + * OpenClonk, http://www.openclonk.org + * + * Copyright (c) 2012, Julius Michaelis + * + * Portions might be copyrighted by other authors who have contributed + * to OpenClonk. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * See isc_license.txt for full license and disclaimer. + * + * "Clonk" is a registered trademark of Matthes Bender. + * See clonk_trademark_license.txt for full license. + */ + +/* Functions for displaying a settings dialogue to users when the graphics system failed */ + + +#ifdef _WIN32 + +#include +#include +#include +#include +#include +#include + +static int edittext_toi(HWND hWnd, int field) +{ + WCHAR buf[512]; buf[511] = 0; + GetDlgItemTextW(hWnd,field,buf,509); + StdStrBuf data(buf); + const char* bufp = data.getData(); + while(*bufp == ' ') ++bufp; + int res = strtol(bufp, NULL, 0); + if(errno != ERANGE) + return res; + return -1; +} + +static INT_PTR CALLBACK GfxErrProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + switch(Msg) + { + case WM_INITDIALOG: + // Set Icon, Caption and static Texts + SendMessage(hWnd,WM_SETICON,ICON_BIG,(LPARAM)LoadIcon(Application.GetInstance(),MAKEINTRESOURCE(IDI_00_C4X))); + SendMessage(hWnd,WM_SETICON,ICON_SMALL,(LPARAM)LoadIcon(Application.GetInstance(),MAKEINTRESOURCE(IDI_00_C4X))); + SetWindowTextW(hWnd, GetWideChar(C4ENGINECAPTION)); + SetDlgItemTextW(hWnd,IDC_GFXERR_MSG ,GetWideChar(LoadResStr("IDS_MSG_GFXERR_TXT"))); + SetDlgItemTextW(hWnd,IDC_GFXERR_RES ,GetWideChar(LoadResStr("IDS_CTL_RESOLUTION"))); + SetDlgItemTextW(hWnd,IDC_GFXERR_FSCRN,GetWideChar(LoadResStr("IDS_MSG_FULLSCREEN"))); + SetDlgItemTextW(hWnd,IDCANCEL ,GetWideChar(LoadResStr("IDS_DLG_EXIT"))); + SetDlgItemTextW(hWnd,IDOK ,GetWideChar(LoadResStr("IDS_BTN_RESTART"))); + // Set Options + SendMessage(GetDlgItem(hWnd, IDC_GFXERR_FSCRN), BM_SETCHECK, Config.Graphics.Windowed?0:1, 0); + SetDlgItemTextW(hWnd,IDC_GFXERR_XINP ,FormatString("%d",Config.Graphics.ResX).GetWideChar()); + SetDlgItemTextW(hWnd,IDC_GFXERR_YINP ,FormatString("%d",Config.Graphics.ResY).GetWideChar()); + return TRUE; + + case WM_DESTROY: + EndDialog(hWnd,1); + return TRUE; + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hWnd,1); + return TRUE; + case IDC_GFXERR_FSCRN: + case IDC_GFXERR_XINP: + case IDC_GFXERR_YINP: + { // Handle Resolution values + if(SendMessage(GetDlgItem(hWnd, IDC_GFXERR_FSCRN),BM_GETCHECK,0,0) == BST_CHECKED) + { + int resx = edittext_toi(hWnd,IDC_GFXERR_XINP); + int resy = edittext_toi(hWnd,IDC_GFXERR_YINP); + if(resx < 1 || resy < 1) // res. will be 0 if the user supplies an invalid value + SetDlgItemTextW(hWnd,IDC_GFXERR_INVAL,GetWideChar(LoadResStr("IDS_MSG_GFXERR_RESINVAL"))); + else + { + // Check if res is in list of supportet + bool found = false; + int32_t idx = 0, iXRes, iYRes, iBitDepth; + while (Application.GetIndexedDisplayMode(idx++, &iXRes, &iYRes, &iBitDepth, NULL, Config.Graphics.Monitor)) + if (iBitDepth == Config.Graphics.BitDepth) + if(iXRes == resx && iYRes == resy) + { + found = true; + break; + } + SetDlgItemTextW(hWnd,IDC_GFXERR_INVAL,found?L"":GetWideChar(LoadResStr("IDS_MSG_GFXERR_RESNOTFOUND"))); + } + } + else + SetDlgItemTextW(hWnd,IDC_GFXERR_INVAL,L""); + return TRUE; + } + case IDOK: + { + int resx = edittext_toi(hWnd,IDC_GFXERR_XINP); + int resy = edittext_toi(hWnd,IDC_GFXERR_YINP); + if(resx < 1 || resy < 1) break; + Config.Graphics.Windowed = !(SendMessage(GetDlgItem(hWnd, IDC_GFXERR_FSCRN),BM_GETCHECK,0,0) == BST_CHECKED); + Config.Graphics.ResX = resx; + Config.Graphics.ResY = resy; + Config.Save(); + TCHAR selfpath[4096]; + GetModuleFileName(NULL, selfpath, 4096); + STARTUPINFOW siStartupInfo; + PROCESS_INFORMATION piProcessInfo; + memset(&siStartupInfo, 0, sizeof(siStartupInfo)); + memset(&piProcessInfo, 0, sizeof(piProcessInfo)); + siStartupInfo.cb = sizeof(siStartupInfo); + CreateProcessW(selfpath, L"", + NULL, NULL, FALSE, 0, NULL, Config.General.ExePath.GetWideChar(), &siStartupInfo, &piProcessInfo); + EndDialog(hWnd,2); + return TRUE; + } + } + } + } + return FALSE; +} + +void ShowGfxErrorDialog() +{ + int ret = DialogBox(Application.GetInstance(), MAKEINTRESOURCE(IDD_GFXERROR), NULL, GfxErrProcedure); + if (ret == 0 || ret == -1) + { + LPVOID lpMsgBuf; + DWORD err = GetLastError(); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + LogF("Error in GfxErrorDlg: %d - %s", err, StdStrBuf((wchar_t*)lpMsgBuf).getData()); + LocalFree(lpMsgBuf); + } +} + +#else +void ShowGfxErrorDialog(){} // To be implemented? It's mainly a windows (users') problem. +#endif diff --git a/src/gui/C4GfxErrorDlg.h b/src/gui/C4GfxErrorDlg.h new file mode 100644 index 000000000..2c43d7f43 --- /dev/null +++ b/src/gui/C4GfxErrorDlg.h @@ -0,0 +1,11 @@ +/* + * OpenClonk, http://www.openclonk.org + * + * This file is ineligible for copyright and therefore in the public domain, + * because it does not reach the required threshold of originality. + * + * "Clonk" is a registered trademark of Matthes Bender. + * See clonk_trademark_license.txt for full license. + */ + +void ShowGfxErrorDialog(); diff --git a/src/res/engine.rc b/src/res/engine.rc index 8bfa48c22..14efb4493 100644 --- a/src/res/engine.rc +++ b/src/res/engine.rc @@ -18,7 +18,7 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_00_C4X ICON DISCARDABLE "oc.ico" +IDI_00_C4X ICON DISCARDABLE "oc.ico" IDI_01_OCS ICON DISCARDABLE "ocs.ico" IDI_02_OCG ICON DISCARDABLE "ocg.ico" IDI_03_OCF ICON DISCARDABLE "ocf.ico" @@ -167,6 +167,24 @@ BEGIN ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL END +IDD_GFXERROR DIALOGEX 200, 200, 300, 200 +STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU | DS_CENTER +CAPTION "OCOGLERR" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "ERRORMSGGFX",IDC_GFXERR_MSG,6,20,294,33 + LTEXT "RES",IDC_GFXERR_RES,40,72,100,11 + LTEXT "X:",IDC_GFXERR_X,100,86,20,11 + EDITTEXT IDC_GFXERR_XINP,120,85,35,13, ES_RIGHT | WS_TABSTOP + LTEXT "Y:",IDC_GFXERR_Y,100,100,20,11 + EDITTEXT IDC_GFXERR_YINP,120,99,35,13, ES_RIGHT | WS_TABSTOP + LTEXT "INVAL",IDC_GFXERR_INVAL,170,86,110,33 + AUTOCHECKBOX "FULLSCREEN",IDC_GFXERR_FSCRN, 40, 135, 100, 11, WS_TABSTOP + DEFPUSHBUTTON "RESTART",IDOK, 180,174,60,14, WS_TABSTOP + PUSHBUTTON "CANCEL",IDCANCEL,60,174,60,14, WS_TABSTOP +END + ///////////////////////////////////////////////////////////////////////////// // // Bitmap diff --git a/src/res/resource.h b/src/res/resource.h index 06b77fc48..26c18b92c 100644 --- a/src/res/resource.h +++ b/src/res/resource.h @@ -54,10 +54,19 @@ #define IDC_STATICSCRIPT 2026 #define IDC_STATICTEXTURE 2027 #define IDC_STATICTIME 2028 +#define IDC_GFXERR_MSG 2029 +#define IDC_GFXERR_RES 2030 +#define IDC_GFXERR_X 2031 +#define IDC_GFXERR_XINP 2032 +#define IDC_GFXERR_Y 2033 +#define IDC_GFXERR_YINP 2034 +#define IDC_GFXERR_FSCRN 2035 +#define IDC_GFXERR_INVAL 2036 #define IDD_COMPONENT 3000 #define IDD_CONSOLE 3001 #define IDD_PROPERTIES 3002 #define IDD_TOOLS 3003 +#define IDD_GFXERROR 3004 #define IDI_00_C4X 4000 #define IDI_01_OCS 4001 #define IDI_02_OCG 4002 From d1b80573820dd55b854026ae5359557495884411 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Fri, 2 Mar 2012 22:48:25 +0100 Subject: [PATCH 61/70] Fix build for 8ac3339bf901 --- src/gui/C4GfxErrorDlg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/C4GfxErrorDlg.cpp b/src/gui/C4GfxErrorDlg.cpp index 1a791ae46..f3e250d68 100644 --- a/src/gui/C4GfxErrorDlg.cpp +++ b/src/gui/C4GfxErrorDlg.cpp @@ -17,10 +17,10 @@ /* Functions for displaying a settings dialogue to users when the graphics system failed */ +#include #ifdef _WIN32 -#include #include #include #include From 853bcb3608b654c92d6fda264d8b95dc4b13a263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Brammer?= Date: Fri, 2 Mar 2012 23:58:41 +0100 Subject: [PATCH 62/70] autotools: add missing files --- Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile.am b/Makefile.am index c676ffcf4..68cfc4d60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -149,6 +149,7 @@ src/platform/StdRegistry.h \ src/platform/StdScheduler.cpp \ src/platform/StdScheduler.h \ src/zlib/gzio.c \ +src/zlib/gzio.h \ src/zlib/zutil.h clonk_SOURCES = \ @@ -318,6 +319,8 @@ src/gui/C4GameOptions.cpp \ src/gui/C4GameOptions.h \ src/gui/C4GameOverDlg.cpp \ src/gui/C4GameOverDlg.h \ +src/gui/C4GfxErrorDlg.cpp \ +src/gui/C4GfxErrorDlg.h \ src/gui/C4GuiButton.cpp \ src/gui/C4GuiCheckBox.cpp \ src/gui/C4GuiComboBox.cpp \ @@ -533,6 +536,7 @@ src/script/C4Value.cpp \ src/script/C4Value.h \ src/script/C4ValueMap.cpp \ src/script/C4ValueMap.h \ +thirdparty/timsort/sort.h \ thirdparty/tinyxml/tinystr.cpp \ thirdparty/tinyxml/tinystr.h \ thirdparty/tinyxml/tinyxml.cpp \ From fa7e922321df6a51e62f095ee0795bffca92b5e7 Mon Sep 17 00:00:00 2001 From: Armin Burgmeier Date: Sat, 3 Mar 2012 01:45:46 +0100 Subject: [PATCH 63/70] Fix rendering of mesh pictures to non-square target rectangles This is still not perfect yet, but I suppose to get better we'd need to compute the bounding box of the transformed mesh. --- src/platform/StdGL.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/platform/StdGL.cpp b/src/platform/StdGL.cpp index 852ca9dc7..5e04741cd 100644 --- a/src/platform/StdGL.cpp +++ b/src/platform/StdGL.cpp @@ -1238,6 +1238,11 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw glMatrixMode(GL_PROJECTION); glPushMatrix(); + // Mesh extents + const float b = fabs(v2.x - v1.x)/2.0f; + const float h = fabs(v2.y - v1.y)/2.0f; + const float l = fabs(v2.z - v1.z)/2.0f; + if (!fUsePerspective) { // Orthographic projection. The orthographic projection matrix @@ -1313,6 +1318,14 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw glScalef(iWdt/2.0, -iHgt/2.0, 1.0f); glTranslatef(1.0f, -1.0f, 0.0f); + // Fix for the case when we have a non-square target + const float ta = twdt / thgt; + const float ma = b / h; + if(ta <= 1 && ta/ma <= 1) + glScalef(std::max(ta, ta/ma), std::max(ta, ta/ma), 1.0f); + else if(ta >= 1 && ta/ma >= 1) + glScalef(std::max(1.0f/ta, ma/ta), std::max(1.0f/ta, ma/ta), 1.0f); + // Apply perspective projection. After this, x and y range from // -1 to 1, and this is mapped into tx/ty/twdt/thgt by the above code. // Aspect is 1.0f which is accounted for above. @@ -1333,19 +1346,9 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw } else { - // Mesh extents - const float b = fabs(v2.x - v1.x)/2.0f; - const float h = fabs(v2.y - v1.y)/2.0f; - const float l = fabs(v2.z - v1.z)/2.0f; - // Setup camera position so that the mesh with uniform transformation - // fits well into the rectangle twdt/thgt (without distortion). - float EyeR; - if (thgt < twdt) - EyeR = l + std::max(b/TAN_FOV, h/TAN_FOV * twdt/thgt); - else - EyeR = l + std::max(b/TAN_FOV * thgt/twdt, h/TAN_FOV); - + // fits well into a square target (without distortion). + const float EyeR = l + std::max(b/TAN_FOV, h/TAN_FOV); const float EyeX = MeshCenter.x; const float EyeY = MeshCenter.y; const float EyeZ = MeshCenter.z + EyeR; From a977aebac5e71a9c0facfce75a941b331d7aaf63 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 4 Mar 2012 10:44:53 +0100 Subject: [PATCH 64/70] Cloud: clean up and fixed lightning strikes This should in the end all depend on scenario settings, but it's okay for now I guess --- .../IronPeak.ocs/Scenario.txt | 1 + .../Clouds.ocd/AcidRain.ocd/DefCore.txt | 9 - .../Clouds.ocd/AcidRain.ocd/Graphics.png | Bin 2253 -> 0 bytes .../Clouds.ocd/AcidRain.ocd/Script.c | 1 - .../Clouds.ocd/AcidRain.ocd/StringTblDE.txt | 1 - .../Clouds.ocd/AcidRain.ocd/StringTblUS.txt | 1 - .../Clouds.ocd/Cloud.ocd/DefCore.txt | 4 +- .../Clouds.ocd/Cloud.ocd/Script.c | 373 +++++++++++------- 8 files changed, 242 insertions(+), 148 deletions(-) delete mode 100644 planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/DefCore.txt delete mode 100644 planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Graphics.png delete mode 100644 planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Script.c delete mode 100644 planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblDE.txt delete mode 100644 planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblUS.txt diff --git a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt index 6e07ec99c..788907758 100644 --- a/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt +++ b/planet/BeyondTheRocks.ocf/IronPeak.ocs/Scenario.txt @@ -47,4 +47,5 @@ BottomOpen=1 Climate=100 YearSpeed=0 Wind=1,100,-100,100 +Rain=40 diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/DefCore.txt b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/DefCore.txt deleted file mode 100644 index 6540a67a3..000000000 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/DefCore.txt +++ /dev/null @@ -1,9 +0,0 @@ -[DefCore] -id=Environment_AcidRain -Version=5,2,0,1 -Category=C4D_StaticBack|C4D_Environment -Width=1 -Height=1 -Value=1 -Picture=0,0,64,64 - diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Graphics.png b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Graphics.png deleted file mode 100644 index e90c5d293b4b698716686e7602049908c4c856e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2253 zcmV;;2r~DHP)Px#24YJ`L;yno{{Ta`UA-Xy000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXc9 z04XU2XV}dE000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000OmNkl)Rd!K!(PMzwmzRmOubk7VUGXo67LBk*jjL`_f0FoGDA_Nk^MB$Mb z62upYioO^U1NguL27MtRMl@a$K#e8@UsR9*q(RKgFg@K(U#d>k*_Y)*0q@;aSjAA^ z5BSd7-~QHKmjjG2!U!XbFv18Uj4(o9Fnjy#%Aw~E-TP6Am-|f^J8|5v_~c_NKv)k* zwkQAj*a{#~(0Z*k{b2;F$Mx@rKLy$mZpo$n=4~8l+@*5055P6U?Eohz-zjy!c`2cz z)pM(j>VfL)PzwMC+6(PZ_np@AoElTrSjIbtS^zc-x8yGEYwnNf+a$<&h+sQw_YbWA z`+vIsW|b?Drpa_Zy{3;*-jZFAY2DDU+ijh5{@PFqaQauLzd?o|QToYz&)DT-SLz83 zJ7-ZYmZYq@bSMP~&2R-6Km^>fQ~luFe#`dnj$b~mVj1C=J<|Dm=S4!2@B|{}Z<4EKCqzP~UJh0=g9g}@% ze2%hWwmU7tT7VwYsP3(zbD~3`8NNJJ0+grA8=-*U10)KTo>}@W`aT>Hz~bAHWB=X3|~fZy=Y4NdL;w$VA> z`FmeVY~MOHOWQ~YzU3hhsJimKau)wCu3P`x`k(xYzbqCJmGdgpUT8>@kSa_mWayw_As_dzJCWhE@C)^*4*NfZxc5(e6 zN%y6{Oy|?1x~>sJgi;EeFk&Y@zxdSRRl__E_ay~XrjDviK~)q81ZfLG5hQGcE6@0S zKz?cd2xkmZ-IrRNz^{2oDKVK$Fm=P!lV|oqMB(enbkfcHOo3AdBEVH0$4z$3Mx}jRuLiu3djy-zZq5mdg|A8T|c68y^AXhRaHpF6JgDy zQ;pyPVkeT6g3ty^IYXU_D{?+Qq z1#|b!-Lv}V)fWcpfVunT?iQBM>M;#fQA~!Qsw!~800E>4I@jIG5CyufVP*`7=}Wx^ z?AH1-X7?n(#y>Y6P9_qlsuBRuH4T-j=$!`{`oN}KVQ|XuO)rRmTX9$SYJYdyWdjvJ zfZji(kdVm@bgsc^w><$YvZMHVawQ;^gsSQ*B zaqWR5$-Y05L(Qy4w$Ufpi3+2+?nNNEA>)n{Q_{jsVChp`?02 zb=%;oKuw*ZNMOUDquLAG*6iCqM#-7sPg?&u4_OrmwhVx_CN#}J2dt?5s~O3+?s>51;X9EI-tNG!cyg-_?Kj(?lz#HogKs^!sp?nL`}LSs>7Ep3!cZ)tB-;|0X+xCKCkM6< zSo-zSZ)a|rv2Mxj6NrwjsAD@KtOodZJ;HiGSPzhnz^`}!cJDZAbN;`n37f3_uyYPLGlAWc**mSDpOoj?*KN+FtsXL?%e_56$qn$K3A zeHy^iAIi>7aRCPWy6?8x6(TCA+hMYZcp30o{6j{h_=a0{Ql2a!ED}Q$x99``B&C#* z%B#r1} diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Script.c deleted file mode 100644 index 5d5c87e08..000000000 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/Script.c +++ /dev/null @@ -1 +0,0 @@ -local Name = "$Name$"; diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblDE.txt b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblDE.txt deleted file mode 100644 index ec659f1a9..000000000 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblDE.txt +++ /dev/null @@ -1 +0,0 @@ -Name=Säureregen diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblUS.txt b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblUS.txt deleted file mode 100644 index a22dce521..000000000 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/AcidRain.ocd/StringTblUS.txt +++ /dev/null @@ -1 +0,0 @@ -Name=Acid Rain diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/DefCore.txt b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/DefCore.txt index 669dfbd6e..1723d0485 100644 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/DefCore.txt +++ b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/DefCore.txt @@ -1,9 +1,7 @@ [DefCore] id=Cloud Version=5,2,0,1 -Category=C4D_Vehicle|C4D_Background -Timer=25 -TimerCall=TimedEvents +Category=C4D_Vehicle | C4D_Background Width=512 Height=350 Offset=-256,-175 diff --git a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c index 90ba7b885..53b0e44ab 100644 --- a/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c +++ b/planet/Objects.ocd/Environment.ocd/Clouds.ocd/Cloud.ocd/Script.c @@ -1,20 +1,43 @@ -/*--- Cloud ---*/ +/** + Cloud + Generic cloud, features: rain (water, acid) and thunder. + The clouds have periods of condensing, idle and raining. + Different types of rain (water, acid) are hardcoded. + + TODO: Make dependent on scenario setting. + TODO: Make for all material types. + + @authors Ringwaul, Maikel +*/ + + +// Cloud modes: idle, raining, condensing. +static const CLOUD_ModeIdle = 0; +static const CLOUD_ModeRaining = 1; +static const CLOUD_ModeCondensing = 2; +local mode; +// The time a cloud is in this mode. +local mode_time; + +local water; // number of water pixels the cloud contains. +local acid; // number of acid pixels the cloud contains. +local lightning_chance; // chance of lightning strikes 0-100. +local evap_x; // x coordinate for evaporation -local szMat, iSize, iCondensing; -local iSearchY; -local iWaitTime; -local iAcidity; -local iStrikeChance; protected func Initialize() { - //Cloud defaults and modifiers - iCondensing = 0; - iSize = RandomX(300,500); - SetClrModulation(RGB(255,255,255)); - iSearchY = 0; - iAcidity=0; - iWaitTime = RandomX(130,190); + // Clouds start idle. + mode = CLOUD_ModeIdle; + mode_time = 360 + RandomX(-60, 60); + + // Default values for rain. + water = RandomX(200, 300); + acid = 0; + + // Cloud defaults + lightning_chance = 0; + evap_x = 0; DoCon(Random(75)); @@ -30,142 +53,226 @@ protected func Initialize() //Failsafe for stupid grounded clouds if(GetMaterial(0,30)!=Material("Sky")) SetPosition(GetX(), GetY()-180); - -} - -public func Precipitation() -{ - if (GetTemperature() < 0 && iAcidity == 0) szMat = "Snow"; - if (GetTemperature() >= 1 && iAcidity == 0) szMat = "Water"; - if (iAcidity >= 1) szMat="Acid"; - - //Reroute function to Evaporation if cloud is growing - if(iCondensing == 1) return(Evaporation()); - if(iSize <= 50 && iAcidity==0) iCondensing = 1; - - //water-snow precipitation - if(iWaitTime == 0 && szMat != "Acid") - { - RainDrop(); - iSize = --iSize; - } - - //acid precipitation - if(iWaitTime == 0 && szMat == "Acid") - { - RainDrop(); - iAcidity = --iAcidity; - } - //Lightning Strike; only during rain - if(iWaitTime <= 0 && iSize >= 650 && Random(100) >= 100-(iStrikeChance/16) && szMat=="Water") LaunchLightning(GetX(), GetY(), RandomX(60, 100), 0, 100, 100, 10, true); -} - -public func TimedEvents() -{ - var iRight = LandscapeWidth() - 10; - - if(iWaitTime != 0) (iWaitTime = --iWaitTime); - if(iWaitTime == 0) Precipitation(); - WindDirection(); - CloudShade(); - //Makes clouds loop around map; - if(GetX() >= iRight) SetPosition(12, GetY()); - if(GetX() <= 10) SetPosition(LandscapeWidth()-12, GetY()); - if(GetY() <= 5) SetPosition(0,6); - if(GetYDir()!=0) SetYDir(0); - - while(Stuck()) SetPosition(GetX(),GetY()-5); -} - -protected func Evaporation() //Creates a search line every x-amount(currently five) of pixels to check for water beneath the cloud -{ - var iPrecision = 5; - if(iSize >= 700 || iAcidity >= 100) - { - iCondensing = 0; - iSearchY = 0; - iWaitTime = RandomX(130,190); - } - //line below prevents clouds evaporating through solids - if(GetMaterial(0, iSearchY) != Material("Water") && GetMaterial(0, iSearchY) != Material("Acid") && GetMaterial(0, iSearchY) != Material("Sky")) return(iSearchY=0); - if(GetMaterial(0, iSearchY) == Material("Water")) - { - ExtractMaterialAmount(0, iSearchY,Material("Water"), 3); - iSize = iSize+3; - } - if(ObjectCount(Find_ID(Environment_AcidRain))>=1 && GetMaterial(0, iSearchY) == Material("Acid")) { - ExtractMaterialAmount(0, iSearchY,Material("Acid"), 3); - iAcidity = iAcidity+3; - } - //advance search point - if(GetMaterial(0, iSearchY) != Material("Water") && GetMaterial(0, iSearchY) != Material("Acid")) - iSearchY += iPrecision; - - if(iSearchY + GetY() >= LandscapeHeight()) (iSearchY = 0); + // Add effect to process all cloud features. + AddEffect("ProcessCloud", this, 100, 5, this); + return; } -private func CloudShade() +protected func FxProcessCloudStart(object target, proplist effect, int temporary) { -//Shades the clouds based on iSize: the water density value of the cloud. - var iShade = iSize*425/1000; - var iShade2 = iSize-600; - var iShade3 = (iAcidity*255/100)/2; - - if(iSize <= 600) SetObjAlpha(iShade); - if(iSize > 600) SetObjAlpha(255); - if(iSize > 600 && szMat=="Water") SetClrModulation(RGBa(255-iShade2,255-iShade2,255-iShade2, 255)); - if(iAcidity >= 1) SetClrModulation(RGBa(255-iShade3,255,255-iShade3, 255-iShade)); + // Make sure the effect interval is 5. + if (!temporary) + effect.Interval = 5; + return 1; } -public func RainDrop() +protected func FxProcessCloudTimer() { - var angle = RandomX(0,359); + // Move clouds. + MoveCloud(); + // Update mode time. + mode_time--; + if (mode_time <= 0) + { + // Change mode, reset timer. + mode = (mode + 1) % 3; + mode_time = 360 + RandomX(-60, 60); + } + // Process modes. + if (mode == CLOUD_ModeIdle) + { + /* Empty */ + } + else if (mode == CLOUD_ModeRaining) + { + Precipitation(); + ThunderStrike(); + } + else if (mode == CLOUD_ModeCondensing) + { + Evaporation(); + } + // Update cloud appearance. + ShadeCloud(); + + return 1; +} + +private func MoveCloud() +{ + // Move according to wind. + var wind = GetWind(); + if (wind >= 7) + SetXDir(Random(355), 1000); + else if (wind <= -7) + SetXDir(-Random(355), 1000); + else + SetXDir(); + // Loop clouds around the map. + if (GetX() >= LandscapeWidth() - 10) + SetPosition(12, GetY()); + if (GetX() <= 10) + SetPosition(LandscapeWidth()-12, GetY()); + // Some other safety. + if (GetY() <= 5) + SetPosition(0, 6); + if (GetYDir()!=0) + SetYDir(0); + while (Stuck()) + SetPosition(GetX(), GetY() - 5); + return; +} + +private func Precipitation() +{ + // Precipitaion: water or snow. + if (water > 0) + { + if (GetTemperature() > 0) + RainDrop("Water"); + else + RainDrop("Snow"); + water--; + } + + // Precipitation: acid. + if (acid > 0) + { + RainDrop("Acid"); + acid--; + } + // If out of liquids, skip mode. + if (water == 0 && acid == 0) + mode_time = 0; + + return; +} + +// Raindrop somewhere from the cloud. +private func RainDrop(string mat) +{ + var angle = RandomX(0, 359); var dist = Random(51); - CastPXS(szMat, 1, 1, Sin(angle,dist),Cos(angle,dist)); + CastPXS(mat, 1, 1, Sin(angle,dist),Cos(angle,dist)); +} + +// Launches possibly one thunder strike from the cloud. +private func ThunderStrike() +{ + // Determine whether to launch a strike. + if (water < 100) + return; + if (Random(100) >= lightning_chance || Random(5)) + return; + + // Find random position in the cloud. + var con = GetCon(); + var wdt = GetDefWidth() * con / 250; + var hgt = GetDefHeight() * con / 350; + var x = GetX() + RandomX(-wdt, wdt); + var y = GetY() + RandomX(-hgt, hgt); + var str = con + RandomX(-20, 20); + // Launch lightning. + return LaunchLightning(x, y, str, 0, str / 5, str / 10, str / 10, true); +} + +// Tries to evaporate liquids from the surface. +protected func Evaporation() +{ + var prec = 5; + + // Found enough water/acid, skip condensing phase. + if (water >= 700 || acid >= 100) + { + mode_time = 0; + return; + } + + // determine new x coordinate from the cloud to test for liquids. + var wdt = GetDefWidth() * GetCon() * 3 / 4; + evap_x += prec; + if (evap_x > wdt) + evap_x = - wdt; + + // Test the line downwards from this coordinate. + var y = 0; + while (!GBackSemiSolid(evap_x, y) && y < LandscapeHeight()) + y += prec; + + // Try to extract water. + if(GetMaterial(evap_x, y) == Material("Water")) + { + ExtractMaterialAmount(evap_x, y, Material("Water"), 3); + water += 3; + } + + // Try to extract acid. + if(GetMaterial(evap_x, y) == Material("Acid")) + { + ExtractMaterialAmount(evap_x, y, Material("Acid"), 3); + acid += 3; + } + + // Also add some rain by scenario value. + var mat = GetScenarioVal("Precipitation"); + if (Random(100) < GetScenarioVal("Rain")) + { + if (mat == "Water") + water++; + if (mat == "Acid") + acid++; + } + + return; +} + +//Shades the clouds based on iSize: the water density value of the cloud. +private func ShadeCloud() +{ + var shade = Min(water*425/1000, 255); + var shade2 = Min(water-600, 255); + var shade3 = (acid*255/100)/2; + + if (water <= 600) + SetObjAlpha(shade); + if (water > 600) + SetClrModulation(RGBa(255-shade2, 255-shade2, 255-shade2, 255)); + if (acid > 0) + SetClrModulation(RGBa(255-shade3, 255, 255-shade3, 255-shade)); + return; } //For use as scenario setting. Can work after initialize, if you really want to. -global func AdjustLightningFrequency(int iFreq) +global func AdjustLightningFrequency(int freq) { - for(var Cloud in FindObjects(Find_ID(Cloud))) - Cloud->SetLightningFrequency(iFreq); - return(iFreq); + for (var cloud in FindObjects(Find_ID(Cloud))) + cloud->SetLightningFrequency(freq); + return; } //Routes the global adjust function's variable to the clouds. -public func SetLightningFrequency(int iFreq) +public func SetLightningFrequency(int freq) { - iStrikeChance=iFreq; + lightning_chance = freq; } -private func WindDirection() -{ - var iWind = GetWind(); - - if(iWind >= 7) SetXDir(Random(355),1000); - if(iWind <= -7) SetXDir(-Random(355),1000); - if(iWind < 6 && iWind > -6) SetXDir(); -} - -func Definition(def) { - SetProperty("ActMap", { -Fly = { - Prototype = Action, - Name = "Fly", - Procedure = DFA_FLOAT, - Speed = 20, - Accel = 16, - Decel = 16, - X = 0, - Y = 0, - Wdt = 512, - Hgt = 350, - Length = 16, - Delay = 0, - NextAction = "Fly", - TurnAction = "Turn", -}, -}, def); -} +local ActMap = { + Fly = { + Prototype = Action, + Name = "Fly", + Procedure = DFA_FLOAT, + Speed = 20, + Accel = 16, + Decel = 16, + X = 0, + Y = 0, + Wdt = 512, + Hgt = 350, + Length = 16, + Delay = 0, + NextAction = "Fly", + TurnAction = "Turn", + }, +}; local Name = "Cloud"; From 9543c10cadb1c90bf794b765c58c6d321eb3a688 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 4 Mar 2012 17:12:39 +0100 Subject: [PATCH 65/70] Sawmill is not be accessible as a container. If one takes wood from the sawmill during production this triggers the infinite sawing loop. --- .../Libraries.ocd/Producer.ocd/Script.c | 20 ++++++++++--------- .../Structures.ocd/Sawmill.ocd/Script.c | 3 +++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c index cd1a6e11d..8bd5bb3a6 100644 --- a/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Producer.ocd/Script.c @@ -480,31 +480,36 @@ protected func FxProcessProductionStart(object target, proplist effect, int temp return 1; } -func OnNotEnoughPower() +public func OnNotEnoughPower() { var effect = GetEffect("ProcessProduction", this); if(effect) { effect.Active = false; this->~OnProductionHold(effect.Product, effect.Duration); - } else FatalError("Producer effect removed when power still active!"); + } + else + FatalError("Producer effect removed when power still active!"); return _inherited(...); } -func OnEnoughPower() +public func OnEnoughPower() { var effect = GetEffect("ProcessProduction", this); if(effect) { effect.Active = true; this->~OnProductionContinued(effect.Product, effect.Duration); - } else FatalError("Producer effect removed when power still active!"); + } + else + FatalError("Producer effect removed when power still active!"); return _inherited(...); } protected func FxProcessProductionTimer(object target, proplist effect, int time) { - if(!effect.Active) return 1; + if (!effect.Active) + return 1; // Add effect interval to production duration. effect.Duration += effect.Interval; @@ -525,12 +530,9 @@ protected func FxProcessProductionStop(object target, proplist effect, int reaso // no need to consume power anymore MakePowerConsumer(0); - if (reason != 0) return 1; - - - + // Callback to the producer. //Log("Production finished on %i after %d frames", effect.Product, effect.Duration); this->~OnProductionFinish(effect.Product); diff --git a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c index 83996c166..645c59632 100644 --- a/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Sawmill.ocd/Script.c @@ -23,6 +23,9 @@ public func Initialize() /*-- Interaction --*/ +// Sawmill can't be accessed as a container. +public func IsContainer() { return false; } + // Automatically search for trees in front of sawmill // Temporary solution? protected func FindTrees() From 71e108f16a26183e348f5d42d8f92fa152d2f759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Brammer?= Date: Sun, 4 Mar 2012 21:23:11 +0100 Subject: [PATCH 66/70] Start of a C4Script API third party programs could use This is very experimental, subject to change, and the single function not at all useful yet. --- CMakeLists.txt | 2 + Makefile.am | 2 + include/c4script/c4script.h | 32 ++++++++ src/C4Include.h | 7 +- src/script/C4ScriptStandalone.cpp | 127 ++++++++++++++++++++++++++++++ src/script/shell.cpp | 109 ++----------------------- 6 files changed, 174 insertions(+), 105 deletions(-) create mode 100644 include/c4script/c4script.h create mode 100644 src/script/C4ScriptStandalone.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 033304df3..1117b291e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -926,6 +926,7 @@ add_executable(netpuncher EXCLUDE_FROM_ALL ) add_executable(c4script + include/c4script/c4script.h src/c4group/C4Group.cpp src/c4group/C4Group.h src/c4group/CStdFile.cpp @@ -956,6 +957,7 @@ add_executable(c4script src/script/C4StringTable.cpp src/script/C4PropList.cpp src/script/C4ScriptHost.cpp + src/script/C4ScriptStandalone.cpp src/script/C4ValueArray.cpp src/script/C4Value.cpp src/script/C4ValueMap.cpp diff --git a/Makefile.am b/Makefile.am index 68cfc4d60..a3ac3be79 100644 --- a/Makefile.am +++ b/Makefile.am @@ -690,6 +690,7 @@ endif ## c4script shell c4script_SOURCES = \ +include/c4script/c4script.h \ src/lib/C4SimpleLog.cpp \ src/lib/C4Real.cpp \ src/lib/C4Random.cpp \ @@ -701,6 +702,7 @@ src/script/C4AulParse.cpp \ src/script/C4StringTable.cpp \ src/script/C4PropList.cpp \ src/script/C4ScriptHost.cpp \ +src/script/C4ScriptStandalone.cpp \ src/script/C4ValueArray.cpp \ src/script/C4Value.cpp \ src/script/C4ValueMap.cpp \ diff --git a/include/c4script/c4script.h b/include/c4script/c4script.h new file mode 100644 index 000000000..5ad4f8a03 --- /dev/null +++ b/include/c4script/c4script.h @@ -0,0 +1,32 @@ +/* + * OpenClonk, http://www.openclonk.org + * + * Copyright (c) 2012 Günther Brammer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef C4SCRIPTSTANDALONE_H +#define C4SCRIPTSTANDALONE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int c4s_runscript(const char * filename); + +#ifdef __cplusplus +} +#endif + +#endif // C4SCRIPTSTANDALONE_H diff --git a/src/C4Include.h b/src/C4Include.h index eadc99376..b4b21bd92 100644 --- a/src/C4Include.h +++ b/src/C4Include.h @@ -20,7 +20,12 @@ * See clonk_trademark_license.txt for full license. */ -/* Main header to include all others */ +/* This header is included first from every source file. It serves three purposes: + - PlatformAbstraction.h + - Common utility functionality that's used everywhere + - Speeding up the compilation by precompiling this header +All of our headers are designed to be used with C4Include.h included before and +don't need to include this file or any of the files it includes. */ #ifndef INC_C4Include #define INC_C4Include diff --git a/src/script/C4ScriptStandalone.cpp b/src/script/C4ScriptStandalone.cpp new file mode 100644 index 000000000..a09482add --- /dev/null +++ b/src/script/C4ScriptStandalone.cpp @@ -0,0 +1,127 @@ +/* + * OpenClonk, http://www.openclonk.org + * + * Copyright (c) 2011-2012 Günther Brammer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "../../include/c4script/c4script.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +C4Config Config; +C4Config::C4Config() {} +C4Config::~C4Config() {} +const char * C4Config::AtRelativePath(char const*s) {return s;} + +C4DefList Definitions; +C4DefList::C4DefList() {} +C4DefList::~C4DefList() {} +C4Def* C4DefList::ID2Def(C4ID id) {return NULL;} +C4Def * C4DefList::GetDef(int) {return 0;} +int C4DefList::GetDefCount() {return 0;} +void C4DefList::CallEveryDefinition() {} +void C4DefList::ResetIncludeDependencies() {} +bool C4DefList::DrawFontImage(const char* szImageTag, C4Facet& rTarget, C4DrawTransform* pTransform) { return false; } +float C4DefList::GetFontImageAspect(const char* szImageTag) { return -1.0f; } + +C4MaterialMap MaterialMap; +C4MaterialMap::C4MaterialMap() {} +C4MaterialMap::~C4MaterialMap() {} +void C4MaterialMap::UpdateScriptPointers() {} + +C4AulDebug *C4AulDebug::pDebug; +void C4AulDebug::DebugStepIn(C4AulBCC*) {} +void C4AulDebug::DebugStepOut(C4AulBCC*, C4AulScriptContext*, C4Value*) {} +void C4AulDebug::DebugStep(C4AulBCC*) {} + +C4GameObjects Objects; +C4GameObjects::C4GameObjects() {} +C4GameObjects::~C4GameObjects() {} +void C4GameObjects::UpdateScriptPointers() {} +void C4GameObjects::Clear(bool) {} +void C4GameObjects::Default() {} +bool C4GameObjects::Remove(C4Object*) {return 0;} +bool C4GameObjects::AssignInfo() {return 0;} +bool C4GameObjects::ValidateOwners() {return 0;} +C4Value C4GameObjects::GRBroadcast(char const*, C4AulParSet*, bool, bool) {return C4Value();} +C4Object * C4GameObjects::ObjectPointer(int) {return 0;} + +C4ObjectList::C4ObjectList() {} +C4ObjectList::~C4ObjectList() {} +void C4ObjectList::Default() {} +void C4ObjectList::Clear() {} +void C4ObjectList::InsertLinkBefore(C4ObjectLink*, C4ObjectLink*) {} +void C4ObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {} +void C4ObjectList::RemoveLink(C4ObjectLink*) {} +bool C4ObjectList::Add(C4Object*, C4ObjectList::SortType, C4ObjectList*) {return 0;} +bool C4ObjectList::Remove(C4Object*) {return 0;} +bool C4ObjectList::AssignInfo() {return 0;} +bool C4ObjectList::ValidateOwners() {return 0;} + +void C4NotifyingObjectList::InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore) {} +void C4NotifyingObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {} +void C4NotifyingObjectList::RemoveLink(C4ObjectLink*) {} + +C4Reloc Reloc; +bool C4Reloc::Open(C4Group&, char const*) const {return false;} + +void C4LSector::Clear() {} +void C4Def::IncludeDefinition(C4Def*) {} +bool EraseItemSafe(const char *szFilename) {return false;} +void AddDbgRec(C4RecordChunkType, const void *, int) {} + +int c4s_runscript(const char * filename) +{ + InitCoreFunctionMap(&ScriptEngine); + + C4Group File; + if (!File.Open(GetWorkingDirectory())) + { + fprintf(stderr, "Open failed: %s\n", File.GetError()); + return 1; + } + + // get scripts + StdStrBuf fn; + File.ResetSearch(); + if (!File.FindNextEntry(filename, &fn)) + { + fprintf(stderr, "FindNextEntry failed: %s\n", File.GetError()); + return 1; + } + // host will be destroyed by script engine, so drop the references + GameScript.Reg2List(&ScriptEngine, &ScriptEngine); + GameScript.Load(File, fn.getData(), NULL, NULL, NULL); + + // Link script engine (resolve includes/appends, generate code) + ScriptEngine.Link(&::Definitions); + + // Set name list for globals + ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames); + GameScript.Call("Main"); + GameScript.Clear(); + return 0; +} diff --git a/src/script/shell.cpp b/src/script/shell.cpp index 0326591e4..63138d2ec 100644 --- a/src/script/shell.cpp +++ b/src/script/shell.cpp @@ -1,7 +1,7 @@ /* * OpenClonk, http://www.openclonk.org * - * Copyright (c) 2011 Günther Brammer + * Copyright (c) 2012 Günther Brammer * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,110 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -C4Config Config; -C4Config::C4Config() {} -C4Config::~C4Config() {} -const char * C4Config::AtRelativePath(char const*s) {return s;} - -C4DefList Definitions; -C4DefList::C4DefList() {} -C4DefList::~C4DefList() {} -C4Def* C4DefList::ID2Def(C4ID id) {return NULL;} -C4Def * C4DefList::GetDef(int) {return 0;} -int C4DefList::GetDefCount() {return 0;} -void C4DefList::CallEveryDefinition() {} -void C4DefList::ResetIncludeDependencies() {} -bool C4DefList::DrawFontImage(const char* szImageTag, C4Facet& rTarget, C4DrawTransform* pTransform) { return false; } -float C4DefList::GetFontImageAspect(const char* szImageTag) { return -1.0f; } - -C4MaterialMap MaterialMap; -C4MaterialMap::C4MaterialMap() {} -C4MaterialMap::~C4MaterialMap() {} -void C4MaterialMap::UpdateScriptPointers() {} - -C4AulDebug *C4AulDebug::pDebug; -void C4AulDebug::DebugStepIn(C4AulBCC*) {} -void C4AulDebug::DebugStepOut(C4AulBCC*, C4AulScriptContext*, C4Value*) {} -void C4AulDebug::DebugStep(C4AulBCC*) {} - -C4GameObjects Objects; -C4GameObjects::C4GameObjects() {} -C4GameObjects::~C4GameObjects() {} -void C4GameObjects::UpdateScriptPointers() {} -void C4GameObjects::Clear(bool) {} -void C4GameObjects::Default() {} -bool C4GameObjects::Remove(C4Object*) {return 0;} -bool C4GameObjects::AssignInfo() {return 0;} -bool C4GameObjects::ValidateOwners() {return 0;} -C4Value C4GameObjects::GRBroadcast(char const*, C4AulParSet*, bool, bool) {return C4Value();} -C4Object * C4GameObjects::ObjectPointer(int) {return 0;} - -C4ObjectList::C4ObjectList() {} -C4ObjectList::~C4ObjectList() {} -void C4ObjectList::Default() {} -void C4ObjectList::Clear() {} -void C4ObjectList::InsertLinkBefore(C4ObjectLink*, C4ObjectLink*) {} -void C4ObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {} -void C4ObjectList::RemoveLink(C4ObjectLink*) {} -bool C4ObjectList::Add(C4Object*, C4ObjectList::SortType, C4ObjectList*) {return 0;} -bool C4ObjectList::Remove(C4Object*) {return 0;} -bool C4ObjectList::AssignInfo() {return 0;} -bool C4ObjectList::ValidateOwners() {return 0;} - -void C4NotifyingObjectList::InsertLinkBefore(C4ObjectLink *pLink, C4ObjectLink *pBefore) {} -void C4NotifyingObjectList::InsertLink(C4ObjectLink*, C4ObjectLink*) {} -void C4NotifyingObjectList::RemoveLink(C4ObjectLink*) {} - -C4Reloc Reloc; -bool C4Reloc::Open(C4Group&, char const*) const {return false;} - -void C4LSector::Clear() {} -void C4Def::IncludeDefinition(C4Def*) {} -bool EraseItemSafe(const char *szFilename) {return false;} -void AddDbgRec(C4RecordChunkType, const void *, int) {} +// Do not include C4Include.h - this file tests whether +// c4script.h is useable without that. +#include "../../include/c4script/c4script.h" int main(int argc, const char * argv[]) { - InitCoreFunctionMap(&ScriptEngine); - - C4Group File; - if (!File.Open(GetWorkingDirectory())) - { - fprintf(stderr, "Open failed: %s\n", File.GetError()); - return 1; - } - - // get scripts - StdStrBuf fn; - File.ResetSearch(); - if (!File.FindNextEntry(argv[1], &fn)) - { - fprintf(stderr, "FindNextEntry failed: %s\n", File.GetError()); - return 1; - } - // host will be destroyed by script engine, so drop the references - GameScript.Reg2List(&ScriptEngine, &ScriptEngine); - GameScript.Load(File, fn.getData(), NULL, NULL, NULL); - - // Link script engine (resolve includes/appends, generate code) - ScriptEngine.Link(&::Definitions); - - // Set name list for globals - ScriptEngine.GlobalNamed.SetNameList(&ScriptEngine.GlobalNamedNames); - GameScript.Call("Main"); - GameScript.Clear(); - return 0; + return c4s_runscript(argv[1]); } From 51889abb047dc35e18bd418772d49cc183b50104 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 4 Mar 2012 21:45:55 +0100 Subject: [PATCH 67/70] Goldrush has more firestones in the earth This to make sure players can mine enough resources from the start, also symmetrize wind and introduced topsoil and midsoil earth. --- planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt | 5 +++++ planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt index 5993056d2..e31f0fe01 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Landscape.txt @@ -62,6 +62,8 @@ map Goldmine { }; RandomMat & overlay { mat=Earth; tex=earth_rough; }; RandomMat & overlay { mat=Earth; tex=earth_dry; }; + RandomSpots & overlay { mat=Earth; tex=earth_topsoil; }; + RandomSpots & overlay { mat=Earth; tex=earth_midsoil; }; RandomSpots & overlay { mat=Coal; tex=coal; }; RandomSpots & overlay { mat=Sulphur; tex=sulphur; }; RandomSpots & overlay { mat=Ore; tex=Ore; }; @@ -71,6 +73,7 @@ map Goldmine { x=0; y=58; wdt=100; hgt=12; turbulence=10; lambda=3; loosebounds=1; mask=1; + RandomMat & overlay { mat=Earth; tex=earth_topsoil; }; RandomMat & overlay { mat=Coal; tex=coal; }; RandomMat & overlay { mat=Sulphur; tex=sulphur; }; }; @@ -79,11 +82,13 @@ map Goldmine { x=0; y=72; wdt=100; hgt=12; turbulence=10; lambda=3; loosebounds=1; mask=1; + RandomMat & overlay { mat=Earth; tex=earth_midsoil; }; RandomMat & overlay { mat=Rock; tex=rock; }; RandomMat & overlay { mat=Ore; tex=ore; }; RandomSpots & overlay { mat=Rock; tex=rock_cracked; }; RandomSpots & overlay { mat=Rock; tex=rock_cracked; }; RandomSpots & overlay { mat=Rock; tex=rock_cracked; }; + RandomSpots & overlay { mat=Rock; tex=rock_cracked; }; }; // Bottom layer with gold. overlay { diff --git a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt index cc17ac872..12a8345f5 100644 --- a/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt +++ b/planet/BeyondTheRocks.ocf/GoldRush.ocs/Scenario.txt @@ -37,7 +37,7 @@ HomeBaseMaterial=Shovel=2;Pickaxe=2;Axe=2;Hammer=2;Dynamite=10;Loam=10;Wood=20;M [Landscape] InEarth=Rock=1;Firestone=3;Loam=2 -InEarthLevel=30,0,0,100 +InEarthLevel=40 Sky=Clouds2 MapWidth=100 MapHeight=75 @@ -45,5 +45,5 @@ MapHeight=75 [Weather] Climate=0 YearSpeed=0 -Wind=1,100,-100,100 +Wind=0,100,-100,100 From 7d8e1428c47db48388953001c70c396cb6972230 Mon Sep 17 00:00:00 2001 From: Sven-Hendrik Haase Date: Tue, 6 Mar 2012 10:06:59 +0100 Subject: [PATCH 68/70] Enable support for DESTDIR (important for Linux packagers) --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1117b291e..ee0e8c4ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1277,11 +1277,11 @@ ENDIF() # TODO: Check for convert at configure step? install(DIRECTORY DESTINATION share/icons/hicolor/48x48/apps) install(CODE " -EXECUTE_PROCESS(COMMAND \"convert\" \"${CMAKE_CURRENT_SOURCE_DIR}/src/res/oc.ico[2]\" \"${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps/clonk.png\" RESULT_VARIABLE CONVERT_RESULT) +EXECUTE_PROCESS(COMMAND \"convert\" \"${CMAKE_CURRENT_SOURCE_DIR}/src/res/oc.ico[2]\" \"$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps/clonk.png\" RESULT_VARIABLE CONVERT_RESULT) IF(NOT \${CONVERT_RESULT} EQUAL 0) MESSAGE(SEND_ERROR \"Creating icon failed\") ENDIF() -FILE(MAKE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/share/openclonk) +FILE(MAKE_DIRECTORY $ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/share/openclonk) ") set(OC_C4GROUPS @@ -1308,7 +1308,7 @@ foreach(group ${OC_C4GROUPS}) else() INSTALL(CODE " MESSAGE(\"Packing and installing ${group}...\") - EXECUTE_PROCESS(COMMAND \"${CMAKE_CURRENT_BINARY_DIR}/c4group\" \"${CMAKE_CURRENT_SOURCE_DIR}/planet/${group}\" -t \"${CMAKE_INSTALL_PREFIX}/share/openclonk/${group}\" RESULT_VARIABLE PACK_RESULT) + EXECUTE_PROCESS(COMMAND \"${CMAKE_CURRENT_BINARY_DIR}/c4group\" \"${CMAKE_CURRENT_SOURCE_DIR}/planet/${group}\" -t \"$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/share/openclonk/${group}\" RESULT_VARIABLE PACK_RESULT) IF(NOT \${PACK_RESULT} EQUAL 0) MESSAGE(SEND_ERROR \"Packing ${group} failed\") ENDIF() From ed5d615aab4d249a8fafe94e205f9dba8b821dab Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Sat, 3 Mar 2012 23:25:50 +0100 Subject: [PATCH 69/70] Check for OpenGL Version 1.2 and two functions from 1.3 instead of requiring full 1.3 (#692) --- src/C4Application.cpp | 2 +- src/platform/StdGL.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/C4Application.cpp b/src/C4Application.cpp index 0af847502..a42607c28 100644 --- a/src/C4Application.cpp +++ b/src/C4Application.cpp @@ -180,7 +180,7 @@ bool C4Application::DoInit(int argc, char * argv[]) // Initialize D3D/OpenGL bool success = DDrawInit(this, isEditor, false, Config.Graphics.ResX, Config.Graphics.ResY, Config.Graphics.BitDepth, Config.Graphics.Engine, Config.Graphics.Monitor); - if (!success) { LogFatal(LoadResStr("IDS_ERR_DDRAW")); Clear(); return false; } + if (!success) { LogFatal(LoadResStr("IDS_ERR_DDRAW")); Clear(); ShowGfxErrorDialog(); return false; } if (!isEditor) { diff --git a/src/platform/StdGL.cpp b/src/platform/StdGL.cpp index 5e04741cd..eddb70181 100644 --- a/src/platform/StdGL.cpp +++ b/src/platform/StdGL.cpp @@ -1884,8 +1884,11 @@ bool CStdGL::RestoreDeviceObjects() RenderTarget = pApp->pWindow->pSurface; // BGRA Pixel Formats, Multitexturing, Texture Combine Environment Modes - if (!GLEW_VERSION_1_3) - { + // Check for GL 1.2 and two functions from 1.3 we need. + if( !GLEW_VERSION_1_2 || + glActiveTexture == NULL || + glClientActiveTexture == NULL + ) { return Error(" gl: OpenGL Version 1.3 or higher required. A better graphics driver will probably help."); } From 5716bb1e478c78cd4eecd269e1e541836b0d1bfc Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Fri, 9 Mar 2012 11:45:25 +0100 Subject: [PATCH 70/70] C4AulScript::DirectExec: Throw on parsing errors, too, when fPassErrors is set. --- src/script/C4AulExec.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index a08e31bb0..7a24b1a12 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -1142,10 +1142,12 @@ C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char } catch (C4AulError *ex) { - ex->show(); - delete ex; delete pFunc; delete pScript; + ex->show(); + if(fPassErrors) + throw; + delete ex; return C4VNull; } pFunc->CodePos = 1;