~widelands-dev/widelands/trunk

« back to all changes in this revision

Viewing changes to src/logic/production_program.cc

  • Committer: sigra
  • Date: 2010-01-04 03:32:50 UTC
  • Revision ID: git-v1:82d9f24adcbde7d19f90434aac5f96c7df58aa10
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.

Before the game is set up, the tribes are preloaded, which means that it is checked which tribes exist and which initializations each tribe has, so that each player can select a tribe and an initialization. The selected initialization is saved as an index. When the game is finally started, the tribes are fully read. Then a player is initialized with the initialization with the stored index.

But if for example a player has selected the initialization with index 1, then the tribe is edited so that there is no initialization with that index (such as only the initialization with index 0 remains), then the game i started, the tribe fully read, the player initialized with initialization 1, an assertion will fail in debug builds (and an out-of-range access will be done in release builds.

Now throw game_data_error when this happens. Of course it may still behave a bit unexpected if a player selects initialization a with index 0 and then initializaion a is removed and initialization b has index 0, but at least a crash is fixed.

Also make donkey breeding less broken.

git-svn-id: https://widelands.svn.sourceforge.net/svnroot/widelands/trunk@4870 37b2a8de-5219-0410-9f54-a31bc463ab9c

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2002-2004, 2006-2009 by the Widelands Development Team
 
2
 * Copyright (C) 2002-2004, 2006-2010 by the Widelands Development Team
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU General Public License
134
134
}
135
135
 
136
136
 
137
 
ProductionProgram::ActReturn::Economy_Needs::Economy_Needs
138
 
        (char * & parameters, Tribe_Descr const & tribe)
139
 
{
140
 
        try {
141
 
                bool reached_end;
142
 
                ware_type = tribe.safe_ware_index(match(parameters, reached_end));
143
 
                tribe.set_ware_type_has_demand_check(ware_type);
144
 
        } catch (_wexception const & e) {
145
 
                throw game_data_error("needs: %s", e.what());
146
 
        }
147
 
}
148
 
bool ProductionProgram::ActReturn::Economy_Needs::evaluate
 
137
bool ProductionProgram::ActReturn::Economy_Needs_Ware::evaluate
149
138
        (ProductionSite const & ps) const
150
139
{
151
140
#if 0
152
141
        log
153
 
                ("ActReturn::Economy_Needs::evaluate(%s): (called from %s:%u) "
 
142
                ("ActReturn::Economy_Needs_Ware::evaluate(%s): (called from %s:%u) "
154
143
                 "economy_needs(%s) = %u\n",
155
144
                 ps.descname().c_str(),
156
145
                 const_cast<ProductionSite &>(ps).top_state().program->get_name().c_str(),
160
149
#endif
161
150
        return ps.get_economy()->needs_ware(ware_type);
162
151
}
163
 
std::string ProductionProgram::ActReturn::Economy_Needs::description
 
152
std::string ProductionProgram::ActReturn::Economy_Needs_Ware::description
164
153
        (Tribe_Descr const & tribe) const
165
154
{
166
155
        return _("economy needs ") + tribe.get_ware_descr(ware_type)->descname();
167
156
}
168
157
 
 
158
bool ProductionProgram::ActReturn::Economy_Needs_Worker::evaluate
 
159
        (ProductionSite const & ps) const
 
160
{
 
161
#if 0
 
162
        log
 
163
                ("ActReturn::Economy_Needs_Worker::evaluate(%s): (called from %s:%u) "
 
164
                 "economy_needs(%s) = %u\n",
 
165
                 ps.descname().c_str(),
 
166
                 const_cast<ProductionSite &>(ps).top_state().program->get_name().c_str(),
 
167
                 const_cast<ProductionSite &>(ps).top_state().ip,
 
168
                 ps.descr().tribe().get_worker_descr(worker_type)->descname().c_str(),
 
169
                 ps.get_economy()->needs_worker(worker_type));
 
170
#endif
 
171
        return ps.get_economy()->needs_worker(worker_type);
 
172
}
 
173
std::string ProductionProgram::ActReturn::Economy_Needs_Worker::description
 
174
        (Tribe_Descr const & tribe) const
 
175
{
 
176
        return _("economy needs ") + tribe.get_ware_descr(worker_type)->descname();
 
177
}
 
178
 
169
179
ProductionProgram::ActReturn::Site_Has::Site_Has
170
180
        (char * & parameters, ProductionSite_Descr const & descr)
171
181
{
227
237
{
228
238
        try {
229
239
                if (match_force_skip(parameters, "needs"))
230
 
                        return
231
 
                                new ProductionProgram::ActReturn::Economy_Needs(parameters, tribe);
 
240
                        try {
 
241
                                bool reached_end;
 
242
                                char const * const type_name = match(parameters, reached_end);
 
243
                                if (Ware_Index index = tribe.ware_index(type_name)) {
 
244
                                        tribe.set_ware_type_has_demand_check(index);
 
245
                                        return
 
246
                                                new ProductionProgram::ActReturn::Economy_Needs_Ware
 
247
                                                        (index);
 
248
                                } else if ((index = tribe.worker_index(type_name))) {
 
249
                                        tribe.set_worker_type_has_demand_check(index);
 
250
                                        return
 
251
                                                new ProductionProgram::ActReturn::Economy_Needs_Worker
 
252
                                                        (index);
 
253
                                } else
 
254
                                        throw game_data_error
 
255
                                                (_("expected %s but found \"%s\""),
 
256
                                                 _("ware type or worker type"), type_name);
 
257
                        } catch (_wexception const & e) {
 
258
                                throw game_data_error("needs: %s", e.what());
 
259
                        }
232
260
                else
233
261
                        throw game_data_error
234
262
                                (_("expected %s but found \"%s\""), "\"needs\"", parameters);
846
874
}
847
875
 
848
876
 
 
877
ProductionProgram::ActRecruit::ActRecruit
 
878
        (char * parameters, ProductionSite_Descr const & descr)
 
879
{
 
880
        try {
 
881
                Tribe_Descr const & tribe = descr.tribe();
 
882
                for (bool more = true; more; ++parameters) {
 
883
                        m_items.resize(m_items.size() + 1);
 
884
                        std::pair<Ware_Index, uint8_t> & item = *m_items.rbegin();
 
885
                        skip(parameters);
 
886
                        char const * worker = parameters;
 
887
                        for (;; ++parameters)
 
888
                                switch (*parameters) {
 
889
                                case '\0':
 
890
                                case ' ':
 
891
                                        item.second = 1;
 
892
                                        goto item_end;
 
893
                                case ':': {
 
894
                                        *parameters = '\0';
 
895
                                        ++parameters;
 
896
                                        char * endp;
 
897
                                        unsigned long long int const value =
 
898
                                                strtoull(parameters, &endp, 0);
 
899
                                        item.second = value;
 
900
                                        if
 
901
                                                ((*endp and *endp != ' ')
 
902
                                                 or
 
903
                                                 value < 1 or item.second != value)
 
904
                                                throw game_data_error
 
905
                                                        (_("expected %s but found \"%s\""),
 
906
                                                         _("count"), parameters);
 
907
                                        parameters = endp;
 
908
                                        goto item_end;
 
909
                                }
 
910
                                }
 
911
                item_end:
 
912
                        more = *parameters != '\0';
 
913
                        *parameters = '\0';
 
914
                        item.first = tribe.safe_worker_index(worker);
 
915
                }
 
916
        } catch (_wexception const & e) {
 
917
                throw game_data_error("recruit: %s", e.what());
 
918
        }
 
919
}
 
920
 
 
921
void ProductionProgram::ActRecruit::execute
 
922
        (Game & game, ProductionSite & ps) const
 
923
{
 
924
        assert(ps.m_recruited_workers.empty());
 
925
        ps.m_recruited_workers = m_items;
 
926
        ps.m_working_positions[0].worker->update_task_buildingwork(game);
 
927
 
 
928
        Tribe_Descr const & tribe = ps.owner().tribe();
 
929
        std::string result_string = _("Recruited ");
 
930
        assert(m_items.size());
 
931
        for
 
932
                (struct {Items::const_iterator current; Items::const_iterator const end;}
 
933
                 i = {m_items.begin(), m_items.end()};;)
 
934
        {
 
935
                {
 
936
                        uint8_t const count = i.current->second;
 
937
                        if (1 < count) {
 
938
                                char buffer[5];
 
939
                                sprintf(buffer, _("%u "), count);
 
940
                                result_string += buffer;
 
941
                        }
 
942
                }
 
943
                result_string += tribe.get_worker_descr(i.current->first)->descname();
 
944
                if (++i.current == i.end)
 
945
                        break;
 
946
                result_string += _(", ");
 
947
        }
 
948
        snprintf
 
949
                (ps.m_result_buffer, sizeof(ps.m_result_buffer),
 
950
                 "%s", result_string.c_str());
 
951
}
 
952
 
 
953
 
849
954
ProductionProgram::ActMine::ActMine
850
955
        (char * parameters, ProductionSite_Descr & descr,
851
956
         const std::string & production_program_name)
1034
1139
 
1035
1140
                        MessageQueue::add
1036
1141
                                (ps.owner().player_number(),
1037
 
                                Message
1038
 
                                        (MSG_MINE,
1039
 
                                        game.get_gametime(),
1040
 
                                        _("Mine empty"),
1041
 
                                        ps.get_position(),
1042
 
                                        message.c_str()));
 
1142
                                 Message
 
1143
                                        (MSG_MINE,
 
1144
                                         game.get_gametime(),
 
1145
                                         _("Mine empty"),
 
1146
                                         ps.get_position(),
 
1147
                                         message.c_str()));
1043
1148
                        break;
1044
1149
                } else if
1045
1150
                        (i.current->sender() == MSG_MINE and
1275
1380
                        action = new ActConsume(v->get_string(), *building);
1276
1381
                else if (not strcmp(v->get_name(), "produce"))
1277
1382
                        action = new ActProduce(v->get_string(), *building);
 
1383
                else if (not strcmp(v->get_name(), "recruit"))
 
1384
                        action = new ActRecruit(v->get_string(), *building);
1278
1385
                else if (not strcmp(v->get_name(), "worker"))
1279
1386
                        action = new ActWorker (v->get_string(), *building, _name);
1280
1387
                else if (not strcmp(v->get_name(), "mine"))