/* sand falls down and applies pressure to water */ void move_sand(void) { int x, y; for(x = map.w - 1; x >= 0 ; x--) { for(y = map.h - 1; y >= 0; y--) { if((y + 1 <= map.h) && (x + 1 <= map.w)) { if(sand_tile(x, y) && air_tile(x, y+1)) { map.tiles[x][y] = AIR; map.tiles[x][y+1] = SAND; } /* current is sand and below is water*/ if(sand_tile(x, y) && water_tile(x, y+1)) { /* left of bottom tile is water or air, flow left*/ if((x > 0) && (water_tile(x-1, y+1) || air_tile(x-1, y+1))) { map.new_water_mass[x-1][y+1] += map.new_water_mass[x][y+1]; map.new_water_mass[x][y+1] = 0; map.tiles[x][y] = AIR; map.new_water_mass[x][y] = 0; map.tiles[x][y+1] = SAND; } /* right of bottom tile is water or air, flow rightt*/ else if(water_tile(x+1, y+1) || air_tile(x+1, y+1)) { map.new_water_mass[x+1][y+1] += map.new_water_mass[x][y+1]; map.new_water_mass[x][y+1] = 0; map.tiles[x][y] = AIR; map.new_water_mass[x][y] = 0; map.tiles[x][y+1] = SAND; } /* can't flow left or right, move to top of tile */ else { map.tiles[x][y] = map.tiles[x][y+1]; // move below tile one up map.new_water_mass[x][y] = map.new_water_mass[x][y+1]; // set mass to mass of below tile map.tiles[x][y+1] = SAND; // move sand tile one down map.new_water_mass[x][y+1] = 0; // reset sand mass } } } } } }
void simulate_water(void) { float flow = 0; float remaining_mass; int x, y; for(x = 0; x < map.w; x++) { for(y = 0; y < map.h; y++) { /* skip non water blocks */ if(!air_tile(x, y) && !water_tile(x, y)) { continue; } flow = 0; remaining_mass = map.water_mass[x][y]; if(remaining_mass <= 0) { continue; } /* the block below this one */ if(y+1 < map.h) { if(air_tile(x, y+1) || water_tile(x, y+1)) { flow = get_stable_state_below(remaining_mass + map.water_mass[x][y+1]) - map.water_mass[x][y+1]; if(flow > MIN_FLOW) { flow *= 0.5; /* leads to smoother flow */ } flow = constrain(flow, 0, min(MAX_SPEED, remaining_mass)); map.new_water_mass[x][y] -= flow; map.new_water_mass[x][y+1] += flow; remaining_mass -= flow; } } if(remaining_mass <= 0) { continue; } /* block left of this one */ if(x-1 >= 0) { if(air_tile(x-1, y) || water_tile(x-1, y)) { /* equalize the amount of water in this block and it's neighbour */ flow = (map.water_mass[x][y] - map.water_mass[x-1][y]) / 4; if(flow > MIN_FLOW) { flow *= 0.5; } flow = constrain(flow, 0, remaining_mass); map.new_water_mass[x][y] -= flow; map.new_water_mass[x-1][y] += flow; remaining_mass -= flow; } } if(remaining_mass <= 0) { continue; } /* block right of this one */ if(x + 1 < map.w) { if(air_tile(x+1, y) || water_tile(x+1, y)) { /* equalize the amount of water in this block and it's neighbour */ flow = (map.water_mass[x][y] - map.water_mass[x+1][y]) / 4; if(flow > MIN_FLOW) { flow *= 0.5; } flow = constrain(flow, 0, remaining_mass); map.new_water_mass[x][y] -= flow; map.new_water_mass[x+1][y] += flow; remaining_mass -= flow; } } if(remaining_mass <= 0) { continue; } /* up. only compressed water flows upwards */ if(y-1 >= 0) { if(air_tile(x, y-1) || water_tile(x, y-1)) { flow = remaining_mass - get_stable_state_below(remaining_mass + map.water_mass[x][y-1]); if(flow > MIN_FLOW) { flow *= 0.5; } flow = constrain(flow, 0, min(MAX_SPEED, remaining_mass)); map.new_water_mass[x][y] -= flow; map.new_water_mass[x][y-1] += flow; remaining_mass -= flow; } } } } /* copy the new mass values to the mass array */ for(x = 0; x < map.w; x++) { for(y = 0; y < map.h; y++) { map.water_mass[x][y] = map.new_water_mass[x][y]; } } for(x = 0; x < map.w; x++) { for(y = 0; y < map.h; y++) { /* skip ground blocks */ if(!air_tile(x, y) && !water_tile(x, y)) { continue; } /* Flag/unflag water blocks */ if ((map.water_mass[x][y] >= MIN_MASS) && (map.water_mass[x][y] < water2_mass)) { map.tiles[x][y] = WATER1; } else if ((map.water_mass[x][y] >= water2_mass) && (map.water_mass[x][y] < water3_mass)) { map.tiles[x][y] = WATER2; } else if ((map.water_mass[x][y] >= water3_mass) && (map.water_mass[x][y] < water4_mass)) { map.tiles[x][y] = WATER3; } else if ((map.water_mass[x][y] >= water4_mass) && (map.water_mass[x][y] < water5_mass)) { map.tiles[x][y] = WATER4; } else if (map.water_mass[x][y] >= water5_mass) { map.tiles[x][y] = WATER5; } else { map.tiles[x][y] = AIR; } } } }
int liquid_tile(int x, int y) { return (water_tile(x, y) || oil_tile(x, y)); }
void player_act() { switch(get_last_action()) { case ACTION_TILL: till(x, y, current_map); break; case ACTION_PICKUP: { item* it = get_item(items_at(x, y, current_map), item_count_at(x, y, current_map), PURPOSE_PICKUP, true); if(!it) break; printf_message(COLOR_DEFAULT, "Picked up %d %s", it->count, it->name); callback("picked_up", it->script_state); take_item(x, y, it, current_map); add_item(it); } break; case ACTION_DROP: { item* it = get_item(inventory, item_count, PURPOSE_DROP, false); if(!it) break; if(it->can_equip && equipment[it->slot] == it) { equipment[it->slot] = 0; printf_message(COLOR_DEFAULT, "You unequip the %s, and drop it on the ground.", it->name); callback("removed", it->script_state); } item* clone = clone_item(it); callback("dropped", clone->script_state); place_item(x, y, clone, current_map); remove_item(it, -1); } break; case ACTION_APPLY: { item* it = get_item(inventory, item_count, PURPOSE_APPLY, false); if(!it) break; callback("apply", it->script_state); remove_item(it, 1); } break; case ACTION_EQUIP: { item* it = get_item(inventory, item_count, PURPOSE_EQUIP, false); if(!it || it->slot == SLOT_INVALID) break; callback("equip", it->script_state); printf_message(COLOR_DEFAULT, "You equip the %s.", it->name); equipment[it->slot] = it; break; } case ACTION_REMOVE: { item* it = get_item(equipment, 3, PURPOSE_REMOVE, false); if(!it) break; callback("remove", it->script_state); equipment[it->slot] = 0; printf_message(COLOR_DEFAULT, "You unequip the %s.", it->name); break; } case ACTION_PLANT: { if(!can_plant(x, y, current_map, true)) break; item* it = get_item(inventory, item_count, PURPOSE_PLANT, false); if(!it) break; if(spawn_plant(x, y, it->plant_id, current_map)) { printf_message(COLOR_DEFAULT, "You plant the %s in the tilled soil.", it->name); remove_item(it, 1); } break; } case ACTION_HARVEST: { add_item(harvest_plant(x, y, current_map)); break; } case ACTION_HELP: show_controls(); break; case ACTION_INVENTORY: get_item(inventory, item_count, PURPOSE_NONE, false); break; case ACTION_WATER: water_tile(x, y, current_map); break; case ACTION_EXAMINE: { int mx, my; get_last_mouse_position(&mx, &my); int xdiff = mx - pres_x; int ydiff = my - pres_y; if(mx < 1 || my < 1 || mx > 78 || my > 78) break; examine(x + xdiff, y +ydiff, current_map); } break; } if(ep_current <= 0) add_message(COLOR_EP_CRIT, "Out of energy, you fall to the ground."); }