glx@9732: /* $Id$ */ glx@9732: rubidium@10455: /** @file newgrf_generic.cpp Handling of generic feature callbacks. */ rubidium@10455: glx@9732: #include "stdafx.h" glx@9732: #include "openttd.h" glx@9732: #include "variables.h" glx@9732: #include "landscape.h" glx@9732: #include "debug.h" glx@9732: #include "newgrf.h" glx@9732: #include "newgrf_callbacks.h" glx@9732: #include "newgrf_commons.h" glx@9732: #include "newgrf_spritegroup.h" glx@9732: #include "newgrf_generic.h" glx@9732: #include "tile_map.h" glx@9732: #include glx@9732: glx@9732: glx@9732: struct GenericCallback { glx@9732: const GRFFile *file; glx@9732: const SpriteGroup *group; glx@9732: glx@9732: GenericCallback(const GRFFile *file, const SpriteGroup *group) : glx@9732: file(file), glx@9732: group(group) glx@9732: { } glx@9732: }; glx@9732: glx@9732: typedef std::list GenericCallbackList; glx@9732: glx@9732: static GenericCallbackList _gcl[GSF_END]; glx@9732: glx@9732: glx@9732: /** glx@9732: * Reset all generic feature callback sprite groups. glx@9732: */ glx@9732: void ResetGenericCallbacks() glx@9732: { glx@9732: for (uint8 feature = 0; feature < lengthof(_gcl); feature++) { glx@9732: _gcl[feature].clear(); glx@9732: } glx@9732: } glx@9732: glx@9732: glx@9732: /** glx@9732: * Add a generic feature callback sprite group to the appropriate feature list. glx@9732: * @param feature glx@9732: * @param file glx@9732: * @param group glx@9732: */ glx@9732: void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *group) glx@9732: { glx@9732: if (feature >= lengthof(_gcl)) { glx@9732: grfmsg(5, "AddGenericCallback: Unsupported feature 0x%02X", feature); glx@9732: return; glx@9732: } glx@9732: glx@9732: /* Generic feature callbacks are evaluated in reverse (i.e. the last group glx@9732: * to be added is evaluated first, etc) thus we push the group to the glx@9732: * beginning of the list so a standard iterator will do the right thing. */ glx@9732: _gcl[feature].push_front(GenericCallback(file, group)); glx@9732: } glx@9732: glx@9732: glx@9732: static uint32 GenericCallbackGetRandomBits(const ResolverObject *object) glx@9732: { glx@9732: return 0; glx@9732: } glx@9732: glx@9732: glx@9732: static uint32 GenericCallbackGetTriggers(const ResolverObject *object) glx@9732: { glx@9732: return 0; glx@9732: } glx@9732: glx@9732: glx@9732: static void GenericCallbackSetTriggers(const ResolverObject *object, int triggers) glx@9732: { glx@9732: return; glx@9732: } glx@9732: glx@9732: glx@9732: static uint32 GenericCallbackGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) glx@9732: { glx@9732: switch (variable) { glx@9732: case 0x40: return object->u.generic.cargo_type; glx@9732: glx@9732: case 0x80: return object->u.generic.cargo_type; glx@9732: case 0x81: return object->u.generic.cargo_type; glx@9732: case 0x82: return object->u.generic.default_selection; glx@9732: case 0x83: return object->u.generic.src_industry; glx@9732: case 0x84: return object->u.generic.dst_industry; glx@9732: case 0x85: return object->u.generic.distance; glx@9732: case 0x86: return object->u.generic.event; glx@9732: case 0x87: return object->u.generic.count; glx@9732: case 0x88: return object->u.generic.station_size; glx@9732: glx@9732: default: break; glx@9732: } glx@9732: glx@9732: DEBUG(grf, 1, "Unhandled generic feature property 0x%02X", variable); glx@9732: glx@9732: *available = false; glx@9732: return 0; glx@9732: } glx@9732: glx@9732: glx@9732: static const SpriteGroup *GenericCallbackResolveReal(const ResolverObject *object, const SpriteGroup *group) glx@9732: { glx@9732: if (group->g.real.num_loaded == 0) return NULL; glx@9732: glx@9732: return group->g.real.loaded[0]; glx@9732: } glx@9732: glx@9732: glx@9732: static inline void NewGenericResolver(ResolverObject *res) glx@9732: { glx@9732: res->GetRandomBits = &GenericCallbackGetRandomBits; glx@9732: res->GetTriggers = &GenericCallbackGetTriggers; glx@9732: res->SetTriggers = &GenericCallbackSetTriggers; glx@9732: res->GetVariable = &GenericCallbackGetVariable; glx@9732: res->ResolveReal = &GenericCallbackResolveReal; glx@9732: glx@9732: res->callback = CBID_NO_CALLBACK; glx@9732: res->callback_param1 = 0; glx@9732: res->callback_param2 = 0; glx@9732: res->last_value = 0; glx@9732: res->trigger = 0; glx@9732: res->reseed = 0; rubidium@9826: res->count = 0; glx@9732: } glx@9732: glx@9732: glx@9732: /** Follow a generic feature callback list and return the first successful glx@9732: * answer glx@9732: * @param feature GRF Feature of callback glx@9732: * @param object pre-populated resolver object glx@9732: * @param file address of GRFFile object if file reference is needed, NULL is valid glx@9732: * @return callback value if successful or CALLBACK_FAILED glx@9732: */ glx@9732: static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject *object, const GRFFile **file) glx@9732: { glx@9732: assert(feature < lengthof(_gcl)); glx@9732: glx@9732: /* Test each feature callback sprite group. */ glx@9732: for (GenericCallbackList::const_iterator it = _gcl[feature].begin(); it != _gcl[feature].end(); ++it) { glx@9732: const SpriteGroup *group = it->group; glx@9732: group = Resolve(group, object); glx@9732: if (group == NULL || group->type != SGT_CALLBACK) continue; glx@9732: glx@9732: /* Return NewGRF file if necessary */ glx@9732: if (file != NULL) *file = it->file; glx@9732: glx@9732: return group->g.callback.result; glx@9732: } glx@9732: glx@9732: /* No callback returned a valid result, so we've failed. */ glx@9732: return CALLBACK_FAILED; glx@9732: } glx@9732: glx@9732: glx@9732: /** glx@9732: * 'Execute' an AI purchase selection callback glx@9732: */ glx@9732: uint16 GetAiPurchaseCallbackResult(uint8 feature, CargoID cargo_type, uint8 default_selection, IndustryType src_industry, IndustryType dst_industry, uint8 distance, AIConstructionEvent event, uint8 count, uint8 station_size, const GRFFile **file) glx@9732: { glx@9732: ResolverObject object; glx@9732: glx@9732: NewGenericResolver(&object); glx@9732: glx@9732: object.callback = CBID_GENERIC_AI_PURCHASE_SELECTION; glx@9732: object.u.generic.cargo_type = cargo_type; glx@9732: object.u.generic.default_selection = default_selection; glx@9732: object.u.generic.src_industry = src_industry; glx@9732: object.u.generic.dst_industry = dst_industry; glx@9732: object.u.generic.distance = distance; glx@9732: object.u.generic.event = event; glx@9732: object.u.generic.count = count; glx@9732: object.u.generic.station_size = station_size; glx@9732: glx@10294: uint16 callback = GetGenericCallbackResult(feature, &object, file); glx@10294: if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8); glx@10294: return callback; glx@9732: }