// What are the specified player's next possible moves LocationID *whereCanTheyGo(DracView currentView, int *numLocations, PlayerID player, int road, int rail, int sea) { // This will get ALL the connected locations. LocationID *arrConnected = connectedLocations(currentView->g, numLocations, getLocation(currentView->g, player), player, getRound(currentView->g), road, rail, sea); // The only trick is that Dracula must remove his trail. if (player == PLAYER_DRACULA) { Set setConnected = copyArrayToSet(arrConnected, *numLocations); LocationID pastSix[TRAIL_SIZE] = {0}; giveMeTheTrail(currentView, player, pastSix); for (int i = 0; i < TRAIL_SIZE; i++) { if (isElem(setConnected, pastSix[i])) { setRemove(setConnected, pastSix[i]); *numLocations -= 1; } } free(arrConnected); arrConnected = copySetToArray(setConnected); } return arrConnected; }
static GSList * parseForecastXml (const char *buff, GWeatherInfo *master_info) { GSList *res = NULL; xmlDocPtr doc; xmlNode *root, *node; g_return_val_if_fail (master_info != NULL, NULL); if (!buff || !*buff) return NULL; #define XC (const xmlChar *) #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name) doc = xmlParseMemory (buff, strlen (buff)); if (!doc) return NULL; /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */ root = xmlDocGetRootElement (doc); for (node = root->xmlChildrenNode; node; node = node->next) { if (node->name == NULL || node->type != XML_ELEMENT_NODE) continue; if (isElem (node, "data")) { xmlNode *n; char *time_layout = NULL; time_t update_times[7] = {0}; for (n = node->children; n; n = n->next) { if (!n->name) continue; if (isElem (n, "time-layout")) { if (!time_layout && hasAttr (n, "summarization", "24hourly")) { xmlNode *c; int count = 0; for (c = n->children; c && (count < 7 || !time_layout); c = c->next) { if (c->name && !time_layout && isElem (c, "layout-key")) { xmlChar *val = xmlNodeGetContent (c); if (val) { time_layout = g_strdup ((const char *)val); xmlFree (val); } } else if (c->name && isElem (c, "start-valid-time")) { xmlChar *val = xmlNodeGetContent (c); if (val) { GTimeVal tv; if (g_time_val_from_iso8601 ((const char *)val, &tv)) { update_times[count] = tv.tv_sec; } else { update_times[count] = 0; } count++; xmlFree (val); } } } if (count != 7) { /* There can be more than one time-layout element, the other with only few children, which is not the one to use. */ g_free (time_layout); time_layout = NULL; } } } else if (isElem (n, "parameters")) { xmlNode *p; /* time-layout should be always before parameters */ if (!time_layout) break; if (!res) { int i; for (i = 0; i < 7; i++) { GWeatherInfo *nfo = _gweather_info_new_clone (master_info); nfo->priv->current_time = nfo->priv->update = update_times[i]; if (nfo) res = g_slist_append (res, nfo); } } for (p = n->children; p; p = p->next) { if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) { xmlNode *c; GSList *at = res; gboolean is_max = hasAttr (p, "type", "maximum"); if (!is_max && !hasAttr (p, "type", "minimum")) break; for (c = p->children; c && at; c = c->next) { if (isElem (c, "value")) { GWeatherInfo *nfo = (GWeatherInfo *)at->data; GWeatherInfoPrivate *priv = nfo->priv; xmlChar *val = xmlNodeGetContent (c); /* can pass some values as <value xsi:nil="true"/> */ if (!val || !*val) { if (is_max) priv->temp_max = priv->temp_min; else priv->temp_min = priv->temp_max; } else { if (is_max) priv->temp_max = atof ((const char *)val); else priv->temp_min = atof ((const char *)val); } if (val) xmlFree (val); priv->tempMinMaxValid = priv->tempMinMaxValid || (priv->temp_max > -999.0 && priv->temp_min > -999.0); priv->valid = priv->tempMinMaxValid; at = at->next; } } } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) { xmlNode *c; GSList *at = res; for (c = p->children; c && at; c = c->next) { if (c->name && isElem (c, "weather-conditions")) { GWeatherInfo *nfo = at->data; GWeatherInfoPrivate *priv = nfo->priv; xmlChar *val = xmlGetProp (c, XC "weather-summary"); if (val && nfo) { /* Checking from top to bottom, if 'value' contains 'name', then that win, thus put longer (more precise) values to the top. */ int i; struct _ph_list { const char *name; GWeatherConditionPhenomenon ph; } ph_list[] = { { "Ice Crystals", GWEATHER_PHENOMENON_ICE_CRYSTALS } , { "Volcanic Ash", GWEATHER_PHENOMENON_VOLCANIC_ASH } , { "Blowing Sand", GWEATHER_PHENOMENON_SANDSTORM } , { "Blowing Dust", GWEATHER_PHENOMENON_DUSTSTORM } , { "Blowing Snow", GWEATHER_PHENOMENON_FUNNEL_CLOUD } , { "Drizzle", GWEATHER_PHENOMENON_DRIZZLE } , { "Rain", GWEATHER_PHENOMENON_RAIN } , { "Snow", GWEATHER_PHENOMENON_SNOW } , { "Fog", GWEATHER_PHENOMENON_FOG } , { "Smoke", GWEATHER_PHENOMENON_SMOKE } , { "Sand", GWEATHER_PHENOMENON_SAND } , { "Haze", GWEATHER_PHENOMENON_HAZE } , { "Dust", GWEATHER_PHENOMENON_DUST } /*, { "", GWEATHER_PHENOMENON_SNOW_GRAINS } , { "", GWEATHER_PHENOMENON_ICE_PELLETS } , { "", GWEATHER_PHENOMENON_HAIL } , { "", GWEATHER_PHENOMENON_SMALL_HAIL } , { "", GWEATHER_PHENOMENON_UNKNOWN_PRECIPITATION } , { "", GWEATHER_PHENOMENON_MIST } , { "", GWEATHER_PHENOMENON_SPRAY } , { "", GWEATHER_PHENOMENON_SQUALL } , { "", GWEATHER_PHENOMENON_TORNADO } , { "", GWEATHER_PHENOMENON_DUST_WHIRLS } */ }; struct _sky_list { const char *name; GWeatherSky sky; } sky_list[] = { { "Mostly Sunny", GWEATHER_SKY_BROKEN } , { "Mostly Clear", GWEATHER_SKY_BROKEN } , { "Partly Cloudy", GWEATHER_SKY_SCATTERED } , { "Mostly Cloudy", GWEATHER_SKY_FEW } , { "Sunny", GWEATHER_SKY_CLEAR } , { "Clear", GWEATHER_SKY_CLEAR } , { "Cloudy", GWEATHER_SKY_OVERCAST } , { "Clouds", GWEATHER_SKY_SCATTERED } , { "Rain", GWEATHER_SKY_SCATTERED } , { "Snow", GWEATHER_SKY_SCATTERED } }; priv->valid = TRUE; for (i = 0; i < G_N_ELEMENTS (ph_list); i++) { if (strstr ((const char *)val, ph_list [i].name)) { priv->cond.significant = TRUE; priv->cond.phenomenon = ph_list [i].ph; break; } } for (i = 0; i < G_N_ELEMENTS (sky_list); i++) { if (strstr ((const char *)val, sky_list [i].name)) { priv->sky = sky_list [i].sky; break; } } } if (val) xmlFree (val); at = at->next; } } } } if (res) { gboolean have_any = FALSE; GSList *r; /* Remove invalid forecast data from the list. They should be all valid or all invalid. */ for (r = res; r; r = r->next) { GWeatherInfo *nfo = r->data; GWeatherInfoPrivate *priv = nfo->priv; if (!nfo || !priv->valid) { if (r->data) g_object_unref (r->data); r->data = NULL; } else { have_any = TRUE; if (priv->tempMinMaxValid) priv->temp = (priv->temp_min + priv->temp_max) / 2.0; } } if (!have_any) { /* data members are freed already */ g_slist_free (res); res = NULL; } } break; } } g_free (time_layout); /* stop seeking XML */ break; } } xmlFreeDoc (doc); #undef XC #undef isElem return res; }