~qcumber-some/widelands/spice-up-cmake

« back to all changes in this revision

Viewing changes to src/logic/worker.cc

  • Committer: Jens Beyer (Qcumber-some)
  • Date: 2010-05-28 14:51:37 UTC
  • mfrom: (5149.1.226 trunk)
  • Revision ID: qcumber-some@buerotiger.de-20100528145137-0pyil9qw7szyztsw
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
#include "graphic/graphic.h"
36
36
#include "graphic/rendertarget.h"
37
37
#include "helper.h"
 
38
#include "map_io/widelands_map_map_object_loader.h"
 
39
#include "map_io/widelands_map_map_object_saver.h"
38
40
#include "mapfringeregion.h"
39
41
#include "message_queue.h"
40
42
#include "player.h"
925
927
        Bob          (worker_descr),
926
928
        m_economy    (0),
927
929
        m_supply     (0),
928
 
        m_needed_exp (0),
 
930
        m_transfer   (0),
929
931
        m_current_exp(0)
930
 
{}
 
932
{
 
933
}
931
934
 
932
935
Worker::~Worker()
933
936
{
934
937
        assert(!m_location.is_set());
 
938
        assert(!m_transfer);
935
939
}
936
940
 
937
941
 
947
951
        }
948
952
 
949
953
        molog("Economy: %p\n", m_economy);
 
954
        molog("transfer: %p\n",  m_transfer);
950
955
 
951
956
        if (upcast(WareInstance, ware, m_carried_item.get(egbase))) {
952
957
                molog
955
960
                molog("* m_carried_item->get_economy() (): %p\n", ware->get_economy());
956
961
        }
957
962
 
958
 
        molog("m_needed_exp: %i\n", m_needed_exp);
959
 
        molog("m_current_exp: %i\n", m_current_exp);
 
963
        molog("m_current_exp: %i / %i\n", m_current_exp, descr().get_level_experience());
960
964
 
961
965
        molog("m_supply: %p\n", m_supply);
962
966
}
1146
1150
 */
1147
1151
void Worker::create_needed_experience(Game & game)
1148
1152
{
1149
 
        if (descr().get_min_exp() == -1 && descr().get_max_exp() == -1) {
1150
 
                m_needed_exp = m_current_exp = -1;
 
1153
        if (descr().get_level_experience() == -1) {
 
1154
                m_current_exp = -1;
1151
1155
                return;
1152
1156
        }
1153
1157
 
1154
 
        assert(descr().get_min_exp() <= descr().get_max_exp());
1155
 
        m_needed_exp =
1156
 
                descr().get_min_exp()
1157
 
                +
1158
 
                game.logic_rand() % (1 + descr().get_max_exp() - descr().get_min_exp());
1159
1158
        m_current_exp = 0;
1160
1159
}
1161
1160
 
1169
1168
 */
1170
1169
Ware_Index Worker::gain_experience(Game & game) {
1171
1170
        return
1172
 
                m_needed_exp == -1 or ++m_current_exp < m_needed_exp ?
 
1171
                descr().get_level_experience() == -1 || ++m_current_exp < descr().get_level_experience() ?
1173
1172
                Ware_Index::Null() : level(game);
1174
1173
}
1175
1174
 
1206
1205
 * Set a fallback task.
1207
1206
 */
1208
1207
void Worker::init_auto_task(Game & game) {
1209
 
        if (get_location(game)) {
1210
 
                if (get_economy()->warehouses().size())
 
1208
        if (PlayerImmovable * location = get_location(game)) {
 
1209
                if (get_economy()->warehouses().size() || location->get_type() == BUILDING)
1211
1210
                        return start_task_gowarehouse(game);
1212
1211
 
1213
1212
                set_location(0);
1227
1226
const Bob::Task Worker::taskTransfer = {
1228
1227
        "transfer",
1229
1228
        static_cast<Bob::Ptr>(&Worker::transfer_update),
1230
 
        static_cast<Bob::PtrSignal>(&Worker::transfer_signalimmediate),
1231
1229
        0,
 
1230
        static_cast<Bob::Ptr>(&Worker::transfer_pop),
1232
1231
        false
1233
1232
};
1234
1233
 
1238
1237
 */
1239
1238
void Worker::start_task_transfer(Game & game, Transfer * t)
1240
1239
{
1241
 
        // hackish override for gowarehouse
1242
 
        if (State * const state = get_state(taskGowarehouse)) {
1243
 
                assert(!state->transfer);
 
1240
        // Hackish override for receiving transfers during gowarehouse,
 
1241
        // and to correctly handle the stack during loading of games
 
1242
        // (in that case, the transfer task already exists on the stack
 
1243
        // when this is called).
 
1244
        if (get_state(taskGowarehouse) || get_state(taskTransfer)) {
 
1245
                assert(!m_transfer);
1244
1246
 
1245
 
                state->transfer = t;
 
1247
                m_transfer = t;
1246
1248
                send_signal(game, "transfer");
1247
1249
        } else { //  just start a normal transfer
1248
1250
                push_task(game, taskTransfer);
1249
 
                top_state().transfer = t;
 
1251
                m_transfer = t;
1250
1252
        }
1251
1253
}
1252
1254
 
 
1255
void Worker::transfer_pop(Game & game, State & state)
 
1256
{
 
1257
        if (m_transfer) {
 
1258
                m_transfer->has_failed();
 
1259
                m_transfer = 0;
 
1260
        }
 
1261
}
1253
1262
 
1254
1263
void Worker::transfer_update(Game & game, State & state) {
1255
1264
        Map & map = game.map();
1263
1272
        }
1264
1273
 
1265
1274
        // The request is no longer valid, the task has failed
1266
 
        if (!state.transfer) {
 
1275
        if (!m_transfer) {
1267
1276
                molog("[transfer]: Fail (without transfer)\n");
1268
1277
 
1269
1278
                send_signal(game, "fail");
1277
1286
                // The caller requested a route update, or the previously calulcated route
1278
1287
                // failed.
1279
1288
                // We will recalculate the route on the next update().
1280
 
                if (signal == "road" || signal == "fail") {
 
1289
                if (signal == "road" || signal == "fail" || signal == "transfer") {
1281
1290
                        molog("[transfer]: Got signal '%s' -> recalculate\n", signal.c_str());
1282
1291
 
1283
1292
                        signal_handled();
 
1293
                } else if (signal == "blocked") {
 
1294
                        molog("[transfer]: Blocked by a battle\n");
 
1295
 
 
1296
                        signal_handled();
 
1297
                        return start_task_idle(game, get_animation("idle"), 500);
1284
1298
                } else {
1285
1299
                        molog("[transfer]: Cancel due to signal '%s'\n", signal.c_str());
1286
1300
                        return pop_task(game);
1319
1333
        // Figure out where to go
1320
1334
        bool success;
1321
1335
        PlayerImmovable * const nextstep =
1322
 
                state.transfer->get_next_step(location, success);
 
1336
                m_transfer->get_next_step(location, success);
1323
1337
 
1324
1338
        if (!nextstep) {
1325
 
                Transfer * const t = state.transfer;
 
1339
                Transfer * const t = m_transfer;
1326
1340
 
1327
 
                state.transfer = 0;
 
1341
                m_transfer = 0;
1328
1342
 
1329
1343
                if (success) {
1330
1344
                        pop_task(game);
1434
1448
}
1435
1449
 
1436
1450
 
1437
 
void Worker::transfer_signalimmediate
1438
 
        (Game &, State & state, std::string const & signal)
1439
 
{
1440
 
        if (signal == "cancel")
1441
 
                state.transfer = 0; //  do not call transfer_fail/finish when cancelled
1442
 
}
1443
 
 
1444
 
 
1445
1451
/**
1446
1452
 * Called by transport code when the transfer has been cancelled & destroyed.
1447
1453
 */
1448
1454
void Worker::cancel_task_transfer(Game & game)
1449
1455
{
 
1456
        m_transfer = 0;
1450
1457
        send_signal(game, "cancel");
1451
1458
}
1452
1459
 
1755
1762
 
1756
1763
        if (signal.size()) {
1757
1764
                // if routing has failed, try a different warehouse/route on next update()
1758
 
                if (signal == "fail") {
1759
 
                        molog("[gowarehouse]: caught 'fail'\n");
 
1765
                if (signal == "fail" || signal == "cancel") {
 
1766
                        molog("[gowarehouse]: caught '%s'\n", signal.c_str());
1760
1767
                        signal_handled();
1761
1768
                } else if (signal == "transfer") {
1762
1769
                        signal_handled();
1775
1782
        }
1776
1783
 
1777
1784
        // If we got a transfer, use it
1778
 
        if (state.transfer) {
1779
 
                Transfer * const t = state.transfer;
1780
 
 
1781
 
                state.transfer = 0;
 
1785
        if (m_transfer) {
 
1786
                Transfer * const t = m_transfer;
 
1787
                m_transfer = 0;
 
1788
 
 
1789
                molog("[gowarehouse]: Got transfer\n");
 
1790
 
1782
1791
                pop_task(game);
1783
1792
                return start_task_transfer(game, t);
1784
1793
        }
1785
1794
 
 
1795
        // Always leave buildings in an orderly manner,
 
1796
        // even when no warehouses are left to return to
 
1797
        if (location->get_type() == BUILDING && get_position() == static_cast<Building*>(location)->get_position())
 
1798
                return start_task_leavebuilding(game, true);
 
1799
 
1786
1800
        if (!get_economy()->warehouses().size()) {
1787
1801
                molog("[gowarehouse]: No warehouse left in Economy\n");
1788
1802
                return pop_task(game);
1795
1809
        // flag is removed or a warehouse connects to the Economy).
1796
1810
        if (!m_supply)
1797
1811
                m_supply = new IdleWorkerSupply(*this);
1798
 
        if (name() == "donkey")
1799
 
                molog
1800
 
                        ("Worker::gowarehouse_update: donkey at (%i, %i): nothing to do, "
1801
 
                         "starting task idle\n", get_position().x, get_position().y);
 
1812
 
1802
1813
        return start_task_idle(game, get_animation("idle"), 1000);
1803
1814
}
1804
1815
 
1805
1816
void Worker::gowarehouse_signalimmediate
1806
 
        (Game &, State &, std::string const & signal)
 
1817
        (Game &, State & state, std::string const & signal)
1807
1818
{
1808
1819
        if (signal == "transfer") {
1809
1820
                // We are assigned a transfer, make sure our supply disappears immediately
1817
1828
{
1818
1829
        delete m_supply;
1819
1830
        m_supply = 0;
 
1831
 
 
1832
        if (m_transfer) {
 
1833
                m_transfer->has_failed();
 
1834
                m_transfer = 0;
 
1835
        }
1820
1836
}
1821
1837
 
1822
1838
 
2254
2270
                }
2255
2271
        }
2256
2272
 
2257
 
        //  try to find a flag connected to a warehouse that we can return to
 
2273
        // Try to find a flag connected to a warehouse that we can return to
 
2274
        //
 
2275
        // We always have a high probability to see flags within our vision range,
 
2276
        // but with some luck we see flags that are even further away.
2258
2277
        std::vector<ImmovableFound> flags;
 
2278
        int32_t vision = vision_range();
 
2279
        int32_t maxdist = 4*vision;
2259
2280
        if
2260
2281
                (map.find_immovables
2261
 
                        (Area<FCoords>(map.get_fcoords(get_position()), vision_range()),
 
2282
                        (Area<FCoords>(map.get_fcoords(get_position()), maxdist),
2262
2283
                         &flags, FindFlagWithPlayersWarehouse(*get_owner())))
2263
2284
        {
2264
2285
                int32_t bestdist = -1;
2269
2290
                container_iterate_const(std::vector<ImmovableFound>, flags, i) {
2270
2291
                        Flag & flag = ref_cast<Flag, BaseImmovable>(*i.current->object);
2271
2292
 
 
2293
                        if (game.logic_rand() % 2 == 0)
 
2294
                                continue;
 
2295
 
2272
2296
                        int32_t const dist =
2273
2297
                                map.calc_distance(get_position(), i.current->coords);
2274
2298
 
2275
 
                        if (!best || dist < bestdist) {
 
2299
                        if (!best || bestdist > dist) {
2276
2300
                                best = &flag;
2277
2301
                                bestdist = dist;
2278
2302
                        }
2279
2303
                }
2280
2304
 
2281
 
                if
2282
 
                        (best and
2283
 
                         static_cast<int32_t>(game.logic_rand() % 30) <= 30 - bestdist)
2284
 
                {
 
2305
                if (best && bestdist > vision) {
 
2306
                        uint32_t chance = maxdist - (bestdist - vision);
 
2307
                        if (game.logic_rand() % maxdist >= chance)
 
2308
                                best = 0;
 
2309
                }
 
2310
 
 
2311
                if (best) {
2285
2312
                        molog("[fugitive]: try to move to flag\n");
2286
2313
 
2287
 
                        //  \todo FIXME ??? \todo
2288
 
                        //  warehouse could be on a different island, so check for failure
 
2314
                        // Warehouse could be on a different island, so check for failure
 
2315
                        // Also, move only a few number of steps in the right direction,
 
2316
                        // so that we could theoretically lose the flag again, but also
 
2317
                        // perhaps find a closer flag.
2289
2318
                        if
2290
2319
                                (start_task_movepath
2291
2320
                                        (game,
2292
2321
                                         best->get_position(),
2293
2322
                                         0,
2294
 
                                         descr().get_right_walk_anims(does_carry_ware())))
 
2323
                                         descr().get_right_walk_anims(does_carry_ware()),
 
2324
                                         false,
 
2325
                                         4))
2295
2326
                                return;
2296
2327
                }
2297
2328
        }
2653
2684
                draw_inner(game, dst, calc_drawpos(game, pos));
2654
2685
}
2655
2686
 
 
2687
/*
 
2688
==============================
 
2689
 
 
2690
Load/save support
 
2691
 
 
2692
==============================
 
2693
*/
 
2694
 
 
2695
#define WORKER_SAVEGAME_VERSION 2
 
2696
 
 
2697
Worker::Loader::Loader()
 
2698
{
 
2699
}
 
2700
 
 
2701
void Worker::Loader::load(FileRead& fr)
 
2702
{
 
2703
        Bob::Loader::load(fr);
 
2704
 
 
2705
        uint8_t version = fr.Unsigned8();
 
2706
        if (!(1 <= version && version <= WORKER_SAVEGAME_VERSION))
 
2707
                throw game_data_error("unknown/unhandled version %u", version);
 
2708
 
 
2709
        Worker& worker = get<Worker>();
 
2710
        m_location = fr.Unsigned32();
 
2711
        m_carried_item = fr.Unsigned32();
 
2712
        worker.m_current_exp = fr.Signed32();
 
2713
 
 
2714
        if (version >= 2) {
 
2715
                if (fr.Unsigned8()) {
 
2716
                        worker.m_transfer = new Transfer(ref_cast<Game, Editor_Game_Base>(egbase()), worker);
 
2717
                        worker.m_transfer->read(fr, m_transfer);
 
2718
                }
 
2719
        }
 
2720
}
 
2721
 
 
2722
void Worker::Loader::load_pointers()
 
2723
{
 
2724
        Bob::Loader::load_pointers();
 
2725
 
 
2726
        Worker& worker = get<Worker>();
 
2727
 
 
2728
        if (m_location)
 
2729
                worker.set_location(&mol().get<PlayerImmovable>(m_location));
 
2730
        if (m_carried_item)
 
2731
                worker.m_carried_item = &mol().get<WareInstance>(m_carried_item);
 
2732
        if (worker.m_transfer)
 
2733
                worker.m_transfer->read_pointers(mol(), m_transfer);
 
2734
}
 
2735
 
 
2736
void Worker::Loader::load_finish()
 
2737
{
 
2738
        Bob::Loader::load_finish();
 
2739
 
 
2740
        // it's not entirely clear whether this is the best place to put this code,
 
2741
        // keep an open mind once player immovables are also handled via the new save code
 
2742
        Worker& worker = get<Worker>();
 
2743
        Economy * economy = 0;
 
2744
        if (PlayerImmovable * const location = worker.m_location.get(egbase()))
 
2745
                economy = location->get_economy();
 
2746
        worker.set_economy(economy);
 
2747
        if (WareInstance * const carried_item = worker.m_carried_item.get(egbase()))
 
2748
                carried_item->set_economy(economy);
 
2749
}
 
2750
 
 
2751
const Bob::Task* Worker::Loader::get_task(const std::string& name)
 
2752
{
 
2753
        if (name == "program") return &taskProgram;
 
2754
        if (name == "transfer") return &taskTransfer;
 
2755
        if (name == "buildingwork") return &taskBuildingwork;
 
2756
        if (name == "return") return &taskReturn;
 
2757
        if (name == "gowarehouse") return &taskGowarehouse;
 
2758
        if (name == "dropoff") return &taskDropoff;
 
2759
        if (name == "releaserecruit") return &taskReleaserecruit;
 
2760
        if (name == "fetchfromflag") return &taskFetchfromflag;
 
2761
        if (name == "waitforcapacity") return &taskWaitforcapacity;
 
2762
        if (name == "leavebuilding") return &taskLeavebuilding;
 
2763
        if (name == "fugitive") return &taskFugitive;
 
2764
        if (name == "geologist") return &taskGeologist;
 
2765
        if (name == "scout") return &taskScout;
 
2766
        return Bob::Loader::get_task(name);
 
2767
}
 
2768
 
 
2769
const BobProgramBase* Worker::Loader::get_program(const std::string& name)
 
2770
{
 
2771
        Worker& worker = get<Worker>();
 
2772
        return worker.descr().get_program(name);
 
2773
}
 
2774
 
 
2775
Worker::Loader* Worker::create_loader()
 
2776
{
 
2777
        return new Loader;
 
2778
}
 
2779
 
 
2780
/**
 
2781
 * Load function for all classes derived from \ref Worker
 
2782
 *
 
2783
 * Derived classes must override \ref create_loader to make sure
 
2784
 * the appropriate actual load functions are called.
 
2785
 */
 
2786
Map_Object::Loader* Worker::load(Editor_Game_Base& egbase, Map_Map_Object_Loader& mol, FileRead& fr)
 
2787
{
 
2788
        try {
 
2789
                // header has already been read by caller
 
2790
                std::string tribename = fr.CString();
 
2791
                std::string name = fr.CString();
 
2792
 
 
2793
                egbase.manually_load_tribe(tribename);
 
2794
 
 
2795
                const Tribe_Descr * tribe = egbase.get_tribe(tribename);
 
2796
                if (!tribe)
 
2797
                        throw game_data_error("unknown tribe '%s'", tribename.c_str());
 
2798
 
 
2799
                const Worker_Descr * descr = tribe->get_worker_descr(tribe->safe_worker_index(name));
 
2800
 
 
2801
                Worker * worker = static_cast<Worker*>(&descr->create_object());
 
2802
                std::auto_ptr<Loader> loader(worker->create_loader());
 
2803
                loader->init(egbase, mol, *worker);
 
2804
                loader->load(fr);
 
2805
                return loader.release();
 
2806
        } catch (const std::exception & e) {
 
2807
                throw wexception(_("loading worker: %s"), e.what());
 
2808
        }
 
2809
}
 
2810
 
 
2811
/**
 
2812
 * Save the \ref Worker specific header and version info.
 
2813
 *
 
2814
 * \warning Do not override this function, override \ref do_save instead.
 
2815
 */
 
2816
void Worker::save(Editor_Game_Base& egbase, Map_Map_Object_Saver& mos, FileWrite& fw)
 
2817
{
 
2818
        fw.Unsigned8(header_Worker);
 
2819
        fw.CString(tribe().name());
 
2820
        fw.CString(descr().name());
 
2821
 
 
2822
        do_save(egbase, mos, fw);
 
2823
}
 
2824
 
 
2825
/**
 
2826
 * Save the data fields of this worker.
 
2827
 *
 
2828
 * This is separate from \ref save because of the way data headers are treated.
 
2829
 *
 
2830
 * Override this function in derived classes.
 
2831
 */
 
2832
void Worker::do_save(Editor_Game_Base& egbase, Map_Map_Object_Saver& mos, FileWrite& fw)
 
2833
{
 
2834
        Bob::save(egbase, mos, fw);
 
2835
 
 
2836
        fw.Unsigned8(WORKER_SAVEGAME_VERSION);
 
2837
        fw.Unsigned32(mos.get_object_file_index_or_zero(m_location.get(egbase)));
 
2838
        fw.Unsigned32(mos.get_object_file_index_or_zero(m_carried_item.get(egbase)));
 
2839
        fw.Signed32(m_current_exp);
 
2840
 
 
2841
        if (m_transfer) {
 
2842
                fw.Unsigned8(1);
 
2843
                m_transfer->write(mos, fw);
 
2844
        } else {
 
2845
                fw.Unsigned8(0);
 
2846
        }
 
2847
}
 
2848
 
2656
2849
}