Merge branch 'master' of git://github.com/peterix/dfhack
						commit
						0cf3ee3dc6
					
				@ -1,96 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
https://github.com/peterix/dfhack
 | 
			
		||||
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
 | 
			
		||||
 | 
			
		||||
This software is provided 'as-is', without any express or implied
 | 
			
		||||
warranty. In no event will the authors be held liable for any
 | 
			
		||||
damages arising from the use of this software.
 | 
			
		||||
 | 
			
		||||
Permission is granted to anyone to use this software for any
 | 
			
		||||
purpose, including commercial applications, and to alter it and
 | 
			
		||||
redistribute it freely, subject to the following restrictions:
 | 
			
		||||
 | 
			
		||||
1. The origin of this software must not be misrepresented; you must
 | 
			
		||||
not claim that you wrote the original software. If you use this
 | 
			
		||||
software in a product, an acknowledgment in the product documentation
 | 
			
		||||
would be appreciated but is not required.
 | 
			
		||||
 | 
			
		||||
2. Altered source versions must be plainly marked as such, and
 | 
			
		||||
must not be misrepresented as being the original software.
 | 
			
		||||
 | 
			
		||||
3. This notice may not be removed or altered from any source
 | 
			
		||||
distribution.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#ifndef DFVECTOR_H_INCLUDED
 | 
			
		||||
#define DFVECTOR_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include "Pragma.h"
 | 
			
		||||
#include "Export.h"
 | 
			
		||||
#include "VersionInfo.h"
 | 
			
		||||
#include "MemAccess.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace DFHack
 | 
			
		||||
{
 | 
			
		||||
    template <class T>
 | 
			
		||||
    class DFHACK_EXPORT DfVector
 | 
			
		||||
    {
 | 
			
		||||
        private:
 | 
			
		||||
            std::vector<T> * real_vec;
 | 
			
		||||
        public:
 | 
			
		||||
            DfVector(uint32_t address)
 | 
			
		||||
            {
 | 
			
		||||
                real_vec = (std::vector<T> *) address;
 | 
			
		||||
            };
 | 
			
		||||
            ~DfVector()
 | 
			
		||||
            {
 | 
			
		||||
            };
 | 
			
		||||
            // get offset of the specified index
 | 
			
		||||
            inline const T& operator[] (uint32_t index)
 | 
			
		||||
            {
 | 
			
		||||
                // FIXME: vector out of bounds exception
 | 
			
		||||
                //assert(index < size);
 | 
			
		||||
                return real_vec->at(index);
 | 
			
		||||
            };
 | 
			
		||||
            // get offset of the specified index
 | 
			
		||||
            inline const T& at (uint32_t index)
 | 
			
		||||
            {
 | 
			
		||||
                //assert(index < size);
 | 
			
		||||
                return real_vec->at(index);
 | 
			
		||||
            };
 | 
			
		||||
            // update value at index
 | 
			
		||||
            bool set(uint32_t index, T value)
 | 
			
		||||
            {
 | 
			
		||||
                if (index >= real_vec->size())
 | 
			
		||||
                    return false;
 | 
			
		||||
                real_vec->at(index) = value;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            // remove value
 | 
			
		||||
            bool remove(uint32_t index)
 | 
			
		||||
            {
 | 
			
		||||
                if (index >= real_vec->size())
 | 
			
		||||
                    return false;
 | 
			
		||||
                // Remove the item
 | 
			
		||||
                real_vec->erase(real_vec->begin() + index);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            // get vector size
 | 
			
		||||
            inline uint32_t size ()
 | 
			
		||||
            {
 | 
			
		||||
                return real_vec->size();
 | 
			
		||||
            };
 | 
			
		||||
            // get vector start
 | 
			
		||||
            inline const T * start ()
 | 
			
		||||
            {
 | 
			
		||||
                return real_vec->data();
 | 
			
		||||
            };
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
#endif // DFVECTOR_H_INCLUDED
 | 
			
		||||
@ -1,3 +1,3 @@
 | 
			
		||||
*.h
 | 
			
		||||
*.inc
 | 
			
		||||
static*.inc
 | 
			
		||||
*.xml
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
coord(const coord2d &c, uint16_t _z) : x(c.x), y(c.y), z(_z) {}
 | 
			
		||||
coord(uint16_t _x, uint16_t _y, uint16_t _z) : x(_x), y(_y), z(_z) {}
 | 
			
		||||
 | 
			
		||||
operator coord2d() const { return coord2d(x,y); }
 | 
			
		||||
 | 
			
		||||
bool isValid() const { return x != -30000; }
 | 
			
		||||
void clear() { x = y = z = -30000; }
 | 
			
		||||
 | 
			
		||||
bool operator==(const coord &other) const
 | 
			
		||||
{
 | 
			
		||||
    return (x == other.x) && (y == other.y) && (z == other.z);
 | 
			
		||||
}
 | 
			
		||||
bool operator!=(const coord &other) const
 | 
			
		||||
{
 | 
			
		||||
    return (x != other.x) || (y != other.y) || (z != other.z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool operator<(const coord &other) const
 | 
			
		||||
{
 | 
			
		||||
    if (x != other.x) return (x < other.x);
 | 
			
		||||
    if (y != other.y) return (y < other.y);
 | 
			
		||||
    return z < other.z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
coord operator/(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord(x/number, y/number, z);
 | 
			
		||||
}
 | 
			
		||||
coord operator*(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord(x*number, y*number, z);
 | 
			
		||||
}
 | 
			
		||||
coord operator%(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord(x%number, y%number, z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
coord operator-(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord(x,y,z-number);
 | 
			
		||||
}
 | 
			
		||||
coord operator+(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord(x,y,z+number);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
coord2d(uint16_t _x, uint16_t _y) : x(_x), y(_y) {}
 | 
			
		||||
 | 
			
		||||
bool isValid() const { return x != -30000; }
 | 
			
		||||
void clear() { x = y = -30000; }
 | 
			
		||||
 | 
			
		||||
bool operator==(const coord2d &other) const
 | 
			
		||||
{
 | 
			
		||||
    return (x == other.x) && (y == other.y);
 | 
			
		||||
}
 | 
			
		||||
bool operator!=(const coord2d &other) const
 | 
			
		||||
{
 | 
			
		||||
    return (x != other.x) || (y != other.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool operator<(const coord2d &other) const
 | 
			
		||||
{
 | 
			
		||||
    if (x != other.x) return (x < other.x);
 | 
			
		||||
    return y < other.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
coord2d operator/(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord2d(x/number, y/number);
 | 
			
		||||
}
 | 
			
		||||
coord2d operator*(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord2d(x*number, y*number);
 | 
			
		||||
}
 | 
			
		||||
coord2d operator%(int number) const
 | 
			
		||||
{
 | 
			
		||||
    return coord2d(x%number, y%number);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
unsigned size() const { return x.size(); }
 | 
			
		||||
 | 
			
		||||
coord operator[] (unsigned idx) const {
 | 
			
		||||
    if (idx >= x.size() || idx >= y.size() || idx >= z.size())
 | 
			
		||||
        return coord();
 | 
			
		||||
    else
 | 
			
		||||
        return coord(x[idx], y[idx], z[idx]);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
https://github.com/peterix/dfhack
 | 
			
		||||
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
 | 
			
		||||
 | 
			
		||||
This software is provided 'as-is', without any express or implied
 | 
			
		||||
warranty. In no event will the authors be held liable for any
 | 
			
		||||
damages arising from the use of this software.
 | 
			
		||||
 | 
			
		||||
Permission is granted to anyone to use this software for any
 | 
			
		||||
purpose, including commercial applications, and to alter it and
 | 
			
		||||
redistribute it freely, subject to the following restrictions:
 | 
			
		||||
 | 
			
		||||
1. The origin of this software must not be misrepresented; you must
 | 
			
		||||
not claim that you wrote the original software. If you use this
 | 
			
		||||
software in a product, an acknowledgment in the product documentation
 | 
			
		||||
would be appreciated but is not required.
 | 
			
		||||
 | 
			
		||||
2. Altered source versions must be plainly marked as such, and
 | 
			
		||||
must not be misrepresented as being the original software.
 | 
			
		||||
 | 
			
		||||
3. This notice may not be removed or altered from any source
 | 
			
		||||
distribution.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef CL_MOD_JOB
 | 
			
		||||
#define CL_MOD_JOB
 | 
			
		||||
 | 
			
		||||
#include "Export.h"
 | 
			
		||||
#include "Module.h"
 | 
			
		||||
#include <ostream>
 | 
			
		||||
 | 
			
		||||
namespace df
 | 
			
		||||
{
 | 
			
		||||
    struct job;
 | 
			
		||||
    struct job_item;
 | 
			
		||||
    struct job_item_filter;
 | 
			
		||||
    struct building;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace DFHack
 | 
			
		||||
{
 | 
			
		||||
    // Duplicate the job structure. It is not linked into any DF lists.
 | 
			
		||||
    DFHACK_EXPORT df::job *cloneJobStruct(df::job *job);
 | 
			
		||||
 | 
			
		||||
    // Delete a cloned structure.
 | 
			
		||||
    DFHACK_EXPORT void deleteJobStruct(df::job *job);
 | 
			
		||||
 | 
			
		||||
    DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);
 | 
			
		||||
    DFHACK_EXPORT bool operator== (const df::job &a, const df::job &b);
 | 
			
		||||
 | 
			
		||||
    DFHACK_EXPORT void printJobDetails(Core *c, df::job *job);
 | 
			
		||||
 | 
			
		||||
    DFHACK_EXPORT df::building *getJobHolder(df::job *job);
 | 
			
		||||
 | 
			
		||||
    DFHACK_EXPORT bool linkJobIntoWorld(df::job *job, bool new_id = true);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,86 +1,38 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#ifndef CL_MOD_VERMIN
 | 
			
		||||
#define CL_MOD_VERMIN
 | 
			
		||||
/**
 | 
			
		||||
 * \defgroup grp_vermin Wild vermin (ants, bees, etc)
 | 
			
		||||
 * @ingroup grp_vermin
 | 
			
		||||
 */
 | 
			
		||||
#include "Export.h"
 | 
			
		||||
#include "Module.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
namespace DFHack
 | 
			
		||||
namespace DFHack { namespace Simple { namespace Vermin
 | 
			
		||||
{
 | 
			
		||||
#endif
 | 
			
		||||
    /**
 | 
			
		||||
     * Structure for holding a read DF vermin spawn point object
 | 
			
		||||
     * \ingroup grp_vermin
 | 
			
		||||
     */
 | 
			
		||||
    struct t_spawnPoint
 | 
			
		||||
    struct t_vermin
 | 
			
		||||
    {
 | 
			
		||||
        uint32_t origin;
 | 
			
		||||
        void * origin;
 | 
			
		||||
        int16_t race;
 | 
			
		||||
        uint16_t type;
 | 
			
		||||
        int16_t caste;
 | 
			
		||||
        uint16_t x;
 | 
			
		||||
        uint16_t y;
 | 
			
		||||
        uint16_t z;
 | 
			
		||||
        bool     in_use;
 | 
			
		||||
        uint8_t  unknown;
 | 
			
		||||
        uint32_t countdown;
 | 
			
		||||
        bool visible:1;
 | 
			
		||||
        bool is_colony:1; /// Is vermin object a colony?
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
    class DFContextShared;
 | 
			
		||||
    class SpawnPoints;
 | 
			
		||||
 | 
			
		||||
    static const uint16_t TYPE_WILD_COLONY = 0xFFFF;
 | 
			
		||||
    /**
 | 
			
		||||
     * The Vermin module - allows reading DF vermin
 | 
			
		||||
     * \ingroup grp_modules
 | 
			
		||||
     * \ingroup grp_vermin
 | 
			
		||||
     * Get number of vermin objects
 | 
			
		||||
     */
 | 
			
		||||
    class DFHACK_EXPORT Vermin : public Module
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
        Vermin();
 | 
			
		||||
        ~Vermin();
 | 
			
		||||
 | 
			
		||||
        bool Finish();
 | 
			
		||||
 | 
			
		||||
        // NOTE: caller must call delete on result when done.
 | 
			
		||||
        SpawnPoints* getSpawnPoints();
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
        struct Private;
 | 
			
		||||
        Private *d;
 | 
			
		||||
 | 
			
		||||
        friend class SpawnPoints;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class DFHACK_EXPORT SpawnPoints
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        static const uint16_t TYPE_WILD_COLONY = 0xFFFF;
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        SpawnPoints(Vermin * v);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        ~SpawnPoints();
 | 
			
		||||
 | 
			
		||||
        size_t size();
 | 
			
		||||
        bool   Read (const uint32_t index, t_spawnPoint & point);
 | 
			
		||||
        bool   Write (const uint32_t index, t_spawnPoint & point);
 | 
			
		||||
        bool   isValid();
 | 
			
		||||
 | 
			
		||||
        static bool isWildColony(t_spawnPoint & point);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        Vermin* v;
 | 
			
		||||
        std::vector <void*> * p_sp;
 | 
			
		||||
 | 
			
		||||
        friend class Vermin;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
#endif // __cplusplus
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
    DFHACK_EXPORT uint32_t getNumVermin();
 | 
			
		||||
    /**
 | 
			
		||||
     * Read from vermin object
 | 
			
		||||
     */
 | 
			
		||||
    DFHACK_EXPORT bool Read (const uint32_t index, t_vermin & point);
 | 
			
		||||
    /**
 | 
			
		||||
     * Write into vermin object
 | 
			
		||||
     */
 | 
			
		||||
    DFHACK_EXPORT bool Write (const uint32_t index, t_vermin & point);
 | 
			
		||||
} } } // end DFHack::Simple::Vermin
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 7a730830c515fea701ff73b33cb604f48a4531fc
 | 
			
		||||
Subproject commit d5abec61f72f113e023219fed19c4022363de953
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 355674a508d72349983455f04791b4481b6c1515
 | 
			
		||||
Subproject commit c114ec5f995aec69631187212254309464f82775
 | 
			
		||||
@ -0,0 +1,416 @@
 | 
			
		||||
#include "Core.h"
 | 
			
		||||
#include "Console.h"
 | 
			
		||||
#include "Export.h"
 | 
			
		||||
#include "PluginManager.h"
 | 
			
		||||
#include "MiscUtils.h"
 | 
			
		||||
 | 
			
		||||
#include "modules/Materials.h"
 | 
			
		||||
#include "modules/Items.h"
 | 
			
		||||
#include "modules/Gui.h"
 | 
			
		||||
#include "modules/Job.h"
 | 
			
		||||
 | 
			
		||||
#include "DataDefs.h"
 | 
			
		||||
#include "df/world.h"
 | 
			
		||||
#include "df/ui.h"
 | 
			
		||||
#include "df/ui_build_selector.h"
 | 
			
		||||
#include "df/ui_build_item_req.h"
 | 
			
		||||
#include "df/build_req_choice_genst.h"
 | 
			
		||||
#include "df/build_req_choice_specst.h"
 | 
			
		||||
#include "df/building_workshopst.h"
 | 
			
		||||
#include "df/building_furnacest.h"
 | 
			
		||||
#include "df/job.h"
 | 
			
		||||
#include "df/job_item.h"
 | 
			
		||||
#include "df/job_list_link.h"
 | 
			
		||||
#include "df/item.h"
 | 
			
		||||
#include "df/tool_uses.h"
 | 
			
		||||
#include "df/general_ref.h"
 | 
			
		||||
 | 
			
		||||
using std::vector;
 | 
			
		||||
using std::string;
 | 
			
		||||
using std::endl;
 | 
			
		||||
using namespace DFHack;
 | 
			
		||||
using namespace df::enums;
 | 
			
		||||
 | 
			
		||||
using df::global::world;
 | 
			
		||||
using df::global::ui;
 | 
			
		||||
using df::global::ui_build_selector;
 | 
			
		||||
using df::global::ui_workshop_job_cursor;
 | 
			
		||||
using df::global::job_next_id;
 | 
			
		||||
 | 
			
		||||
/* Plugin registration */
 | 
			
		||||
 | 
			
		||||
static bool job_material_hotkey(Core *c, df::viewscreen *top);
 | 
			
		||||
 | 
			
		||||
static command_result job_material(Core *c, vector <string> & parameters);
 | 
			
		||||
static command_result job_duplicate(Core *c, vector <string> & parameters);
 | 
			
		||||
static command_result job_cmd(Core *c, vector <string> & parameters);
 | 
			
		||||
 | 
			
		||||
DFhackCExport const char * plugin_name ( void )
 | 
			
		||||
{
 | 
			
		||||
    return "jobutils";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &commands)
 | 
			
		||||
{
 | 
			
		||||
    commands.clear();
 | 
			
		||||
    if (!world || !ui)
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
 | 
			
		||||
    commands.push_back(
 | 
			
		||||
        PluginCommand(
 | 
			
		||||
            "job", "General job query and manipulation.",
 | 
			
		||||
            job_cmd, false,
 | 
			
		||||
            "  job [query]\n"
 | 
			
		||||
            "    Print details of the current job.\n"
 | 
			
		||||
            "  job list\n"
 | 
			
		||||
            "    Print details of all jobs in the workshop.\n"
 | 
			
		||||
            "  job item-material <item-idx> <material[:subtoken]>\n"
 | 
			
		||||
            "    Replace the exact material id in the job item.\n"
 | 
			
		||||
            "  job item-type <item-idx> <type[:subtype]>\n"
 | 
			
		||||
            "    Replace the exact item type id in the job item.\n"
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (ui_workshop_job_cursor || ui_build_selector) {
 | 
			
		||||
        commands.push_back(
 | 
			
		||||
            PluginCommand(
 | 
			
		||||
                "job-material", "Alter the material of the selected job.",
 | 
			
		||||
                job_material, job_material_hotkey,
 | 
			
		||||
                "  job-material <inorganic-token>\n"
 | 
			
		||||
                "Intended to be used as a keybinding:\n"
 | 
			
		||||
                "  - In 'q' mode, when a job is highlighted within a workshop\n"
 | 
			
		||||
                "    or furnace, changes the material of the job.\n"
 | 
			
		||||
                "  - In 'b' mode, during selection of building components\n"
 | 
			
		||||
                "    positions the cursor over the first available choice\n"
 | 
			
		||||
                "    with the matching material.\n"
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ui_workshop_job_cursor && job_next_id) {
 | 
			
		||||
        commands.push_back(
 | 
			
		||||
            PluginCommand(
 | 
			
		||||
                "job-duplicate", "Duplicate the selected job in a workshop.",
 | 
			
		||||
                job_duplicate, workshop_job_hotkey,
 | 
			
		||||
                "  - In 'q' mode, when a job is highlighted within a workshop\n"
 | 
			
		||||
                "    or furnace building, instantly duplicates the job.\n"
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_shutdown ( Core * c )
 | 
			
		||||
{
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* UI state guards */
 | 
			
		||||
 | 
			
		||||
static bool job_material_hotkey(Core *c, df::viewscreen *top)
 | 
			
		||||
{
 | 
			
		||||
    return workshop_job_hotkey(c, top) ||
 | 
			
		||||
           build_selector_hotkey(c, top);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* job-material implementation */
 | 
			
		||||
 | 
			
		||||
static command_result job_material_in_job(Core *c, MaterialInfo &new_mat)
 | 
			
		||||
{
 | 
			
		||||
    df::job *job = getSelectedWorkshopJob(c);
 | 
			
		||||
    if (!job)
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
 | 
			
		||||
    if (!new_mat.isValid() || new_mat.type != 0)
 | 
			
		||||
    {
 | 
			
		||||
        c->con.printerr("New job material isn't inorganic: %s\n",
 | 
			
		||||
                        new_mat.toString().c_str());
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MaterialInfo cur_mat(job);
 | 
			
		||||
 | 
			
		||||
    if (!cur_mat.isValid() || cur_mat.type != 0)
 | 
			
		||||
    {
 | 
			
		||||
        c->con.printerr("Current job material isn't inorganic: %s\n",
 | 
			
		||||
                        cur_mat.toString().c_str());
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    df::craft_material_class old_class = cur_mat.getCraftClass();
 | 
			
		||||
    if (old_class == craft_material_class::None)
 | 
			
		||||
    {
 | 
			
		||||
        c->con.printerr("Unexpected current material type: %s\n",
 | 
			
		||||
                        cur_mat.toString().c_str());
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
    if (new_mat.getCraftClass() != old_class)
 | 
			
		||||
    {
 | 
			
		||||
        c->con.printerr("New material %s does not satisfy requirement: %s\n",
 | 
			
		||||
                        new_mat.toString().c_str(), ENUM_KEY_STR(craft_material_class, old_class));
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (unsigned i = 0; i < job->job_items.size(); i++)
 | 
			
		||||
    {
 | 
			
		||||
        df::job_item *item = job->job_items[i];
 | 
			
		||||
        MaterialInfo item_mat(item);
 | 
			
		||||
 | 
			
		||||
        if (item_mat != cur_mat)
 | 
			
		||||
        {
 | 
			
		||||
            c->con.printerr("Job item %d has different material: %s\n",
 | 
			
		||||
                            i, item_mat.toString().c_str());
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!new_mat.matches(*item))
 | 
			
		||||
        {
 | 
			
		||||
            c->con.printerr("Job item %d requirements not satisfied by %s.\n",
 | 
			
		||||
                            i, new_mat.toString().c_str());
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Apply the substitution
 | 
			
		||||
    job->mat_type = new_mat.type;
 | 
			
		||||
    job->mat_index = new_mat.index;
 | 
			
		||||
 | 
			
		||||
    for (unsigned i = 0; i < job->job_items.size(); i++)
 | 
			
		||||
    {
 | 
			
		||||
        df::job_item *item = job->job_items[i];
 | 
			
		||||
        item->mat_type = new_mat.type;
 | 
			
		||||
        item->mat_index = new_mat.index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c->con << "Applied material '" << new_mat.toString()
 | 
			
		||||
           << "' to job " << ENUM_KEY_STR(job_type,job->job_type) << endl;
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choicest *choice,
 | 
			
		||||
                                 MaterialInfo &new_mat, bool ignore_select)
 | 
			
		||||
{
 | 
			
		||||
    if (VIRTUAL_CAST_VAR(gen, df::build_req_choice_genst, choice))
 | 
			
		||||
    {
 | 
			
		||||
        if (gen->mat_type == new_mat.type &&
 | 
			
		||||
            gen->mat_index == new_mat.index &&
 | 
			
		||||
            (ignore_select || gen->used_count < gen->candidates.size()))
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (VIRTUAL_CAST_VAR(spec, df::build_req_choice_specst, choice))
 | 
			
		||||
    {
 | 
			
		||||
        if (spec->candidate &&
 | 
			
		||||
            spec->candidate->getActualMaterial() == new_mat.type &&
 | 
			
		||||
            spec->candidate->getActualMaterialIndex() == new_mat.index &&
 | 
			
		||||
            (ignore_select || !req->candidate_selected[spec->candidate_id]))
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static command_result job_material_in_build(Core *c, MaterialInfo &new_mat)
 | 
			
		||||
{
 | 
			
		||||
    df::ui_build_selector *sel = ui_build_selector;
 | 
			
		||||
    df::ui_build_item_req *req = sel->requirements[ui_build_selector->req_index];
 | 
			
		||||
 | 
			
		||||
    // Loop through matching choices
 | 
			
		||||
    bool matches = build_choice_matches(req, sel->choices[sel->sel_index], new_mat, true);
 | 
			
		||||
 | 
			
		||||
    int size = sel->choices.size();
 | 
			
		||||
    int base = (matches ? sel->sel_index + 1 : 0);
 | 
			
		||||
 | 
			
		||||
    for (unsigned i = 0; i < size; i++)
 | 
			
		||||
    {
 | 
			
		||||
        int idx = (base + i) % size;
 | 
			
		||||
 | 
			
		||||
        if (build_choice_matches(req, sel->choices[idx], new_mat, false))
 | 
			
		||||
        {
 | 
			
		||||
            sel->sel_index = idx;
 | 
			
		||||
            return CR_OK;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c->con.printerr("Could not find material in list: %s\n", new_mat.toString().c_str());
 | 
			
		||||
    return CR_FAILURE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static command_result job_material(Core * c, vector <string> & parameters)
 | 
			
		||||
{
 | 
			
		||||
    // HOTKEY COMMAND: CORE ALREADY SUSPENDED
 | 
			
		||||
 | 
			
		||||
    MaterialInfo new_mat;
 | 
			
		||||
    if (parameters.size() == 1)
 | 
			
		||||
    {
 | 
			
		||||
        if (!new_mat.find(parameters[0])) {
 | 
			
		||||
            c->con.printerr("Could not find material: %s\n", parameters[0].c_str());
 | 
			
		||||
            return CR_WRONG_USAGE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
    if (ui->main.mode == ui_sidebar_mode::QueryBuilding)
 | 
			
		||||
        return job_material_in_job(c, new_mat);
 | 
			
		||||
    if (ui->main.mode == ui_sidebar_mode::Build)
 | 
			
		||||
        return job_material_in_build(c, new_mat);
 | 
			
		||||
 | 
			
		||||
    return CR_WRONG_USAGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* job-duplicate implementation */
 | 
			
		||||
 | 
			
		||||
static command_result job_duplicate(Core * c, vector <string> & parameters)
 | 
			
		||||
{
 | 
			
		||||
    if (!parameters.empty())
 | 
			
		||||
        return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
    df::job *job = getSelectedWorkshopJob(c);
 | 
			
		||||
    if (!job)
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
 | 
			
		||||
    if (!job->misc_links.empty() ||
 | 
			
		||||
        (job->job_items.empty() &&
 | 
			
		||||
         job->job_type != job_type::CollectSand &&
 | 
			
		||||
         job->job_type != job_type::CollectClay))
 | 
			
		||||
    {
 | 
			
		||||
        c->con.printerr("Cannot duplicate job %s\n", ENUM_KEY_STR(job_type,job->job_type));
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    df::building *building = world->selected_building;
 | 
			
		||||
    if (building->jobs.size() >= 10)
 | 
			
		||||
    {
 | 
			
		||||
        c->con.printerr("Job list is already full.\n");
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Actually clone
 | 
			
		||||
    df::job *pnew = cloneJobStruct(job);
 | 
			
		||||
 | 
			
		||||
    linkJobIntoWorld(pnew);
 | 
			
		||||
    vector_insert_at(building->jobs, ++*ui_workshop_job_cursor, pnew);
 | 
			
		||||
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Main job command implementation */
 | 
			
		||||
 | 
			
		||||
static df::job_item *getJobItem(Core *c, df::job *job, std::string idx)
 | 
			
		||||
{
 | 
			
		||||
    if (!job)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    int v = atoi(idx.c_str());
 | 
			
		||||
    if (v < 1 || v > job->job_items.size()) {
 | 
			
		||||
        c->con.printerr("Invalid item index.\n");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return job->job_items[v-1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static command_result job_cmd(Core * c, vector <string> & parameters)
 | 
			
		||||
{
 | 
			
		||||
    CoreSuspender suspend(c);
 | 
			
		||||
 | 
			
		||||
    std::string cmd = (parameters.empty() ? "query" : parameters[0]);
 | 
			
		||||
    if (cmd == "query" || cmd == "list")
 | 
			
		||||
    {
 | 
			
		||||
        df::job *job = getSelectedWorkshopJob(c);
 | 
			
		||||
        if (!job)
 | 
			
		||||
            return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
        if (cmd == "query") {
 | 
			
		||||
            printJobDetails(c, job);
 | 
			
		||||
        } else {
 | 
			
		||||
            df::building *selected = world->selected_building;
 | 
			
		||||
            for (unsigned i = 0; i < selected->jobs.size(); i++)
 | 
			
		||||
                printJobDetails(c, selected->jobs[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (cmd == "item-material")
 | 
			
		||||
    {
 | 
			
		||||
        if (parameters.size() != 3)
 | 
			
		||||
            return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
        df::job *job = getSelectedWorkshopJob(c);
 | 
			
		||||
        df::job_item *item = getJobItem(c, job, parameters[1]);
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
        ItemTypeInfo iinfo(item);
 | 
			
		||||
        MaterialInfo minfo;
 | 
			
		||||
 | 
			
		||||
        if (!minfo.find(parameters[2])) {
 | 
			
		||||
            c->con.printerr("Could not find the specified material.\n");
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (minfo.isValid() && !iinfo.matches(*item, &minfo)) {
 | 
			
		||||
            c->con.printerr("Material does not match the requirements.\n");
 | 
			
		||||
            printJobDetails(c, job);
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (job->mat_type != -1 &&
 | 
			
		||||
            job->mat_type == item->mat_type &&
 | 
			
		||||
            job->mat_index == item->mat_index)
 | 
			
		||||
        {
 | 
			
		||||
            job->mat_type = minfo.type;
 | 
			
		||||
            job->mat_index = minfo.index;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item->mat_type = minfo.type;
 | 
			
		||||
        item->mat_index = minfo.index;
 | 
			
		||||
 | 
			
		||||
        c->con << "Job item updated." << endl;
 | 
			
		||||
 | 
			
		||||
        if (item->item_type < 0 && minfo.isValid())
 | 
			
		||||
            c->con.printerr("WARNING: Due to a probable bug, creature & plant material subtype\n"
 | 
			
		||||
                            "         is ignored unless the item type is also specified.\n");
 | 
			
		||||
 | 
			
		||||
        printJobDetails(c, job);
 | 
			
		||||
        return CR_OK;
 | 
			
		||||
    }
 | 
			
		||||
    else if (cmd == "item-type")
 | 
			
		||||
    {
 | 
			
		||||
        if (parameters.size() != 3)
 | 
			
		||||
            return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
        df::job *job = getSelectedWorkshopJob(c);
 | 
			
		||||
        df::job_item *item = getJobItem(c, job, parameters[1]);
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
        ItemTypeInfo iinfo;
 | 
			
		||||
        MaterialInfo minfo(item);
 | 
			
		||||
 | 
			
		||||
        if (!iinfo.find(parameters[2])) {
 | 
			
		||||
            c->con.printerr("Could not find the specified item type.\n");
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (iinfo.isValid() && !iinfo.matches(*item, &minfo)) {
 | 
			
		||||
            c->con.printerr("Item type does not match the requirements.\n");
 | 
			
		||||
            printJobDetails(c, job);
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item->item_type = iinfo.type;
 | 
			
		||||
        item->item_subtype = iinfo.subtype;
 | 
			
		||||
 | 
			
		||||
        c->con << "Job item updated." << endl;
 | 
			
		||||
        printJobDetails(c, job);
 | 
			
		||||
        return CR_OK;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,82 @@
 | 
			
		||||
// All above-ground soil not covered by buildings will be covered with grass.
 | 
			
		||||
// Necessary for worlds generated prior to version 0.31.19 - otherwise, outdoor shrubs and trees no longer grow.
 | 
			
		||||
 | 
			
		||||
#include "Core.h"
 | 
			
		||||
#include "Console.h"
 | 
			
		||||
#include "Export.h"
 | 
			
		||||
#include "PluginManager.h"
 | 
			
		||||
 | 
			
		||||
#include "DataDefs.h"
 | 
			
		||||
#include "df/world.h"
 | 
			
		||||
#include "df/map_block.h"
 | 
			
		||||
#include "TileTypes.h"
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
using std::vector;
 | 
			
		||||
using namespace DFHack;
 | 
			
		||||
 | 
			
		||||
using df::global::world;
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result df_regrass (Core * c, vector <string> & parameters)
 | 
			
		||||
{
 | 
			
		||||
	if (!parameters.empty())
 | 
			
		||||
		return CR_WRONG_USAGE;
 | 
			
		||||
 | 
			
		||||
        CoreSuspender suspend(c);
 | 
			
		||||
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	for (int i = 0; i < world->map.map_blocks.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		df::map_block *cur = world->map.map_blocks[i];
 | 
			
		||||
		for (int x = 0; x < 16; x++)
 | 
			
		||||
		{
 | 
			
		||||
			for (int y = 0; y < 16; y++)
 | 
			
		||||
			{
 | 
			
		||||
				if (DFHack::tileShape(cur->tiletype[x][y]) != DFHack::FLOOR)
 | 
			
		||||
					continue;
 | 
			
		||||
				if (DFHack::tileMaterial(cur->tiletype[x][y]) != DFHack::SOIL)
 | 
			
		||||
					continue;
 | 
			
		||||
				if (cur->designation[x][y].bits.subterranean)
 | 
			
		||||
					continue;
 | 
			
		||||
				if (cur->occupancy[x][y].bits.building)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				switch (rand() % 8)
 | 
			
		||||
				{
 | 
			
		||||
				// light grass
 | 
			
		||||
				case 0:	cur->tiletype[x][y] = 0x015C;	break;
 | 
			
		||||
				case 1:	cur->tiletype[x][y] = 0x015D;	break;
 | 
			
		||||
				case 2:	cur->tiletype[x][y] = 0x015E;	break;
 | 
			
		||||
				case 3:	cur->tiletype[x][y] = 0x015F;	break;
 | 
			
		||||
				// dark grass
 | 
			
		||||
				case 4:	cur->tiletype[x][y] = 0x018E;	break;
 | 
			
		||||
				case 5:	cur->tiletype[x][y] = 0x018F;	break;
 | 
			
		||||
				case 6:	cur->tiletype[x][y] = 0x0190;	break;
 | 
			
		||||
				case 7:	cur->tiletype[x][y] = 0x0191;	break;
 | 
			
		||||
				}
 | 
			
		||||
				count++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (count)
 | 
			
		||||
		c->con.print("Regrew %d tiles of grass.\n", count);
 | 
			
		||||
	return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DFhackCExport const char *plugin_name ( void )
 | 
			
		||||
{
 | 
			
		||||
	return "regrass";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_init (Core *c, std::vector<PluginCommand> &commands)
 | 
			
		||||
{
 | 
			
		||||
	commands.clear();
 | 
			
		||||
	commands.push_back(PluginCommand("regrass", "Regrows all surface grass, restoring outdoor plant growth for pre-0.31.19 worlds.", df_regrass));
 | 
			
		||||
	return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_shutdown ( Core * c )
 | 
			
		||||
{
 | 
			
		||||
	return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 1b28039e2c93daa3c2f69f5e2a000ff8c96ee1f8
 | 
			
		||||
Subproject commit 92627e39cb3502812cd5a131716d3d1da8ef625a
 | 
			
		||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								
		Loading…
	
		Reference in New Issue