Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

override my anus

Name: Anonymous 2011-10-28 11:28

How do I override functions used in structs in c?

Function pointers?

Name: Anonymous 2011-10-29 0:46

here's a way kinda like seeples.




Interface EntityAble {
  int getHealth();
  void recieveDamage(int damage);
  void attack(EntityAble target);
};


struct entity_interface {
  int (*get_health)(struct entity_interface** self);
  void (*recieve_damage)(struct entity_interface** self, int damage);
  void (*attack)(struct entity_interface** self, entity_interface* target);
  void (*rest)(struct entity_interface** self);
};

struct entity_base {
  struct entity_interface* v_table;
  int health;
};

int entity_base_get_health(struct entity_interface** self) {
  return ((struct entity_base_class*)self)->health;
}

void entity_base_recieve_damage(struct entity_interface** self, int damage) {
  ((struct entity_base_class*)self)->health -= damage;
}

struct wizard {
  struct entity_base;
  int mana;
  double magic_damage_multiplyer;
};

int wizard_calculate_amount_of_mana_to_use(struct wizard* self, struct entity_interface** target) {
  int other_health = target->get_health(target);
  int ideal_amount_of_mana = (int)((double)other_health/self->magic_damage_multiplyer);
  int maximum_amount_of_mana_to_use = self->mana/2;
  int mana_to_use = ideal_amount_of_mana > maximum_amount_of_mana ? maximum_amount_of_mana : ideal_amount_of_mana;
  return mana_to_use;
}

void wizard_attack(struct entity_interface** self, struct entity_interface** target) {
  struct wizard* self_wizard = (struct wizard*)self;
  int mana_to_use = wizard_calculate_amount_of_mana_to_use(self, target);
  int damage_to_deal = (int)((double)mana_to_use*self_wizard->magic_damage_multiplyer);
  self_wizard->mana -= mana_to_use;
  target->recieve_damage(target, damage_to_deal);
}

void wizard_rest(struct entity_interface** self) {
  struct wizard* self_wizard = (struct wizard*)self;
  self_wizard->entity_base.health++;
  self_wizard->mana += 7;
}

struct wolf_class {
  struct entity_interface super;
  int bite_cost;  // bite_cost > scratch_cost
  int scratch_cost;
};

struct wolf {
  struct entity_base_class entity_base_class;
  int stamina;
  int bite_damage;
  int scratch_damage;
  double stamina_damage_absorbtion_factor;
};

void wolf_recieve_damage(struct entity_interface** self, int damage) {
  struct wolf* self_wolf = (struct wolf*)self;
  int stamina_reduction = (int)((double)damage*stamina_damage_absorbtion_factor);
  int health_reduction = damage - stamina_reduction;
  self_wolf->stamina -= stamina_reduction;
  entity_base_recieve_damage(self, health_reduction);
}

void wolf_attack(struct entity_interface** self, struct entity_interface** other) {
  struct wolf* self_wolf = (struct wolf*)self;
  int attack_damage;
  int attack_cost;
  int other_health = (*other)->get_health(other);
  if(self_wolf->stamina < (struct wolf_class*)(self_wolf->entity_base.v_table)->scratch_cost) {
    // You don't have enough stamina to do an attack.
    return;
  }
  if(other_health < self_wolf->scratch_damage ||
     self_wolf->stamina < (struct wolf_class*)(self_wolf->entity_base.v_table)->bite_cost  ||
     (random() % 6 == 0)) {
    attack_damage = self->wolf->scratch_damage;
    attack_cost = (struct wolf_class*)(self->entity_base.v_table)->scratch_cost;
  } else {
    attack_damage = self->wolf->bite_damage;
    attack_cost = (struct wolf_class*)(self->entity_base.v_table)->bite_cost;
  }
  self_wolf->stamina -= attack_cost;
  (*other)->recieve_damage(other, attack_damage);
}

void wolf_rest(struct entity_interface** self) {
  struct wolf* self_wolf = (struct wolf*)self;
  self_wolf->entity_base.health += 4;
  self_wolf->stamina += 11;
}

static struct entity_interface wizard_class = {
  entity_base_get_health,
  entity_base_recieve_damage,
  wizard_attack,
  wizard_rest
};

static struct wolf_class wolf_class {
  {entity_base_get_health,
   wolf_recieve_damage,
   wolf_attack},
  10, // scratch cost
  20  // bite cost
};

void wizard_init(struct wizard* self, int health, int mana, double magic_damage_multiplyer) {
  self->entity_base.v_table = &wizard_class;
  self->entity_base.health = health;
  self->mana = mana;
  self->magic_damage_multiplyer = magic_damage_multiplyer;
}

void wolf_init(struct wolf* self, int health, int stamina, int scratch_damage, int bite_damage) {
  self->entity_base.v_table = (struct entity_interface*)&wolf_class;
  self->entity_base.health = health;
  self->stamina = stamina;
  self->scratch_damage = scratch_damage;
  self->bite_damage = bite_damage;
}

// A generic function taking an argument that implements
// the interface..
int is_alive(struct entity_interface** self) {
  return (*self)->get_health(self) > 0;
}

void main() {
  struct wizard wizard;
  struct wolf wolf;
  wizard_init(&wizard, 100, 50, .7);
  wolf_init(&wolf, 100, 200, 10, 18);
  for(;;) {
    if(!is_alive((struct entity_interface**)&wizard)) {
      printf("the wizard died.\n");
      break;
    }
//    wizard_attack(&wizard, &wolf); // This call would avoid the v table look up overhead.
    (*((struct entity_interface**)&wizard))->attack(&wizard, &wolf); // Using the v table.
    if(!is_alive((struct entity_interface**)&wolf)) {
      printf("the wolf died.\n");
      break;
    }
    (*((struct entity_interface**)&wolf))->attack((struct entity_interface**)&wolf, (struct entity_interface**)&wizard);
  }
}


If you have a compiler that is old and doesn't do type checking on pointers, like the enterprise borland compiler, then you can omit all of those casts, or perhaps make macros for them.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List